]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
Merge tag 'regmap-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Dec 2018 22:48:06 +0000 (14:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Dec 2018 22:48:06 +0000 (14:48 -0800)
Pull regmap updates from Mark Brown:
 "This has been a busy release for the regmap-irq code, there's several
  new features been added, including an API cleanup for how we specify
  types that affected one existing driver (gpio-max77620):

   - Support for hardware that flags rising and falling edges on
     separate status bits from Bartosz Golaszewski.

   - Support for explicitly clearing interrupts before unmasking from
     Bartosz Golaszewski.

   - Support for level triggered IRQs from Matti Vaittinen"

* tag 'regmap-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: irq: add an option to clear status registers on unmask
  regmap: regmap-irq/gpio-max77620: add level-irq support
  regmap: regmap-irq: Remove default irq type setting from core
  regmap: debugfs: convert to DEFINE_SHOW_ATTRIBUTE
  regmap: rbtree: convert to DEFINE_SHOW_ATTRIBUTE
  regmap: irq: handle HW using separate rising/falling edge interrupts
  regmap: add a new macro:REGMAP_IRQ_REG_LINE(_id, _reg_bits)

2718 files changed:
.mailmap
Documentation/ABI/stable/sysfs-driver-mlxreg-io
Documentation/ABI/testing/sysfs-bus-i3c [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/pm/cpuidle.rst [new file with mode: 0644]
Documentation/admin-guide/pm/intel_pstate.rst
Documentation/admin-guide/pm/working-state.rst
Documentation/cpuidle/core.txt [deleted file]
Documentation/cpuidle/sysfs.txt [deleted file]
Documentation/devicetree/bindings/bus/sun50i-de2-bus.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
Documentation/devicetree/bindings/display/himax,hx8357d.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/dsi.txt
Documentation/devicetree/bindings/display/msm/gpu.txt
Documentation/devicetree/bindings/display/msm/mdp4.txt
Documentation/devicetree/bindings/display/panel/auo,g101evn010 [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/cdtech,s070wv95-ct16.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/dlc,dlc1010gig.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/samsung,s6d16d0.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt
Documentation/devicetree/bindings/display/renesas,du.txt
Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
Documentation/devicetree/bindings/display/truly,nt35597.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i3c/i3c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/aspeed-video.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/cedrus.txt
Documentation/devicetree/bindings/media/i2c/mt9m111.txt
Documentation/devicetree/bindings/media/i2c/sony,imx214.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,venus.txt
Documentation/devicetree/bindings/media/rcar_vin.txt
Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
Documentation/devicetree/bindings/media/rockchip-vpu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
Documentation/devicetree/bindings/media/sun6i-csi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/synopsys.txt
Documentation/devicetree/bindings/mfd/axp20x.txt
Documentation/devicetree/bindings/mtd/atmel-quadspi.txt [deleted file]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt
Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
Documentation/devicetree/bindings/regulator/act8945a-regulator.txt
Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/regulator.txt
Documentation/devicetree/bindings/sound/ak4104.txt
Documentation/devicetree/bindings/sound/ak4118.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
Documentation/devicetree/bindings/sound/cs4270.txt
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
Documentation/devicetree/bindings/sound/dmic.txt
Documentation/devicetree/bindings/sound/fsl-sai.txt
Documentation/devicetree/bindings/sound/omap-mcpdm.txt
Documentation/devicetree/bindings/sound/pcm3060.txt
Documentation/devicetree/bindings/sound/qcom,q6asm.txt
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/rt5631.txt
Documentation/devicetree/bindings/sound/rt5663.txt
Documentation/devicetree/bindings/sound/simple-amplifier.txt
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/simple-scu-card.txt
Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt
Documentation/devicetree/bindings/sound/xlnx,i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/atmel-quadspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/omap-spi.txt
Documentation/devicetree/bindings/spi/sh-msiof.txt
Documentation/devicetree/bindings/spi/spi-fsl-lpspi.txt
Documentation/devicetree/bindings/spi/spi-mt65xx.txt
Documentation/devicetree/bindings/spi/spi-mxic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-pxa2xx.txt
Documentation/devicetree/bindings/spi/spi-rspi.txt
Documentation/devicetree/bindings/spi/spi-uniphier.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/driver-api/i3c/device-driver-api.rst [new file with mode: 0644]
Documentation/driver-api/i3c/index.rst [new file with mode: 0644]
Documentation/driver-api/i3c/master-driver-api.rst [new file with mode: 0644]
Documentation/driver-api/i3c/protocol.rst [new file with mode: 0644]
Documentation/driver-api/index.rst
Documentation/driver-model/devres.txt
Documentation/gpu/amdgpu-dc.rst [new file with mode: 0644]
Documentation/gpu/drivers.rst
Documentation/gpu/drm-kms-helpers.rst
Documentation/gpu/drm-kms.rst
Documentation/gpu/drm-mm.rst
Documentation/gpu/drm-uapi.rst
Documentation/gpu/todo.rst
Documentation/gpu/vkms.rst
Documentation/media/.gitignore
Documentation/media/Makefile
Documentation/media/audio.h.rst.exceptions
Documentation/media/ca.h.rst.exceptions
Documentation/media/cec-drivers/index.rst
Documentation/media/cec-drivers/pulse8-cec.rst
Documentation/media/cec.h.rst.exceptions
Documentation/media/conf.py
Documentation/media/conf_nitpick.py
Documentation/media/dmx.h.rst.exceptions
Documentation/media/dvb-drivers/avermedia.rst
Documentation/media/dvb-drivers/bt8xx.rst
Documentation/media/dvb-drivers/cards.rst
Documentation/media/dvb-drivers/ci.rst
Documentation/media/dvb-drivers/contributors.rst
Documentation/media/dvb-drivers/dvb-usb.rst
Documentation/media/dvb-drivers/faq.rst
Documentation/media/dvb-drivers/frontends.rst
Documentation/media/dvb-drivers/index.rst
Documentation/media/dvb-drivers/intro.rst
Documentation/media/dvb-drivers/lmedm04.rst
Documentation/media/dvb-drivers/opera-firmware.rst
Documentation/media/dvb-drivers/technisat.rst
Documentation/media/dvb-drivers/ttusb-dec.rst
Documentation/media/dvb-drivers/udev.rst
Documentation/media/frontend.h.rst.exceptions
Documentation/media/index.rst
Documentation/media/intro.rst
Documentation/media/kapi/cec-core.rst
Documentation/media/kapi/csi2.rst
Documentation/media/kapi/dtv-ca.rst
Documentation/media/kapi/dtv-common.rst
Documentation/media/kapi/dtv-core.rst
Documentation/media/kapi/dtv-demux.rst
Documentation/media/kapi/dtv-frontend.rst
Documentation/media/kapi/dtv-net.rst
Documentation/media/kapi/mc-core.rst
Documentation/media/kapi/rc-core.rst
Documentation/media/kapi/v4l2-async.rst
Documentation/media/kapi/v4l2-clocks.rst
Documentation/media/kapi/v4l2-common.rst
Documentation/media/kapi/v4l2-controls.rst
Documentation/media/kapi/v4l2-core.rst
Documentation/media/kapi/v4l2-dev.rst
Documentation/media/kapi/v4l2-device.rst
Documentation/media/kapi/v4l2-dv-timings.rst
Documentation/media/kapi/v4l2-event.rst
Documentation/media/kapi/v4l2-fh.rst
Documentation/media/kapi/v4l2-flash-led-class.rst
Documentation/media/kapi/v4l2-fwnode.rst
Documentation/media/kapi/v4l2-intro.rst
Documentation/media/kapi/v4l2-mc.rst
Documentation/media/kapi/v4l2-mediabus.rst
Documentation/media/kapi/v4l2-mem2mem.rst
Documentation/media/kapi/v4l2-rect.rst
Documentation/media/kapi/v4l2-subdev.rst
Documentation/media/kapi/v4l2-tuner.rst
Documentation/media/kapi/v4l2-tveeprom.rst
Documentation/media/kapi/v4l2-videobuf.rst
Documentation/media/kapi/v4l2-videobuf2.rst
Documentation/media/lirc.h.rst.exceptions
Documentation/media/media.h.rst.exceptions
Documentation/media/media_kapi.rst
Documentation/media/media_uapi.rst
Documentation/media/net.h.rst.exceptions
Documentation/media/typical_media_device.svg
Documentation/media/uapi/cec/cec-api.rst
Documentation/media/uapi/cec/cec-func-close.rst
Documentation/media/uapi/cec/cec-func-ioctl.rst
Documentation/media/uapi/cec/cec-func-open.rst
Documentation/media/uapi/cec/cec-func-poll.rst
Documentation/media/uapi/cec/cec-funcs.rst
Documentation/media/uapi/cec/cec-header.rst
Documentation/media/uapi/cec/cec-intro.rst
Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst
Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst
Documentation/media/uapi/cec/cec-ioc-adap-g-phys-addr.rst
Documentation/media/uapi/cec/cec-ioc-dqevent.rst
Documentation/media/uapi/cec/cec-ioc-g-mode.rst
Documentation/media/uapi/cec/cec-ioc-receive.rst
Documentation/media/uapi/cec/cec-pin-error-inj.rst
Documentation/media/uapi/dvb/audio-bilingual-channel-select.rst
Documentation/media/uapi/dvb/audio-channel-select.rst
Documentation/media/uapi/dvb/audio-clear-buffer.rst
Documentation/media/uapi/dvb/audio-continue.rst
Documentation/media/uapi/dvb/audio-fclose.rst
Documentation/media/uapi/dvb/audio-fopen.rst
Documentation/media/uapi/dvb/audio-fwrite.rst
Documentation/media/uapi/dvb/audio-get-capabilities.rst
Documentation/media/uapi/dvb/audio-get-status.rst
Documentation/media/uapi/dvb/audio-pause.rst
Documentation/media/uapi/dvb/audio-play.rst
Documentation/media/uapi/dvb/audio-select-source.rst
Documentation/media/uapi/dvb/audio-set-av-sync.rst
Documentation/media/uapi/dvb/audio-set-bypass-mode.rst
Documentation/media/uapi/dvb/audio-set-id.rst
Documentation/media/uapi/dvb/audio-set-mixer.rst
Documentation/media/uapi/dvb/audio-set-mute.rst
Documentation/media/uapi/dvb/audio-set-streamtype.rst
Documentation/media/uapi/dvb/audio-stop.rst
Documentation/media/uapi/dvb/audio.rst
Documentation/media/uapi/dvb/audio_data_types.rst
Documentation/media/uapi/dvb/audio_function_calls.rst
Documentation/media/uapi/dvb/ca-fclose.rst
Documentation/media/uapi/dvb/ca-fopen.rst
Documentation/media/uapi/dvb/ca-get-cap.rst
Documentation/media/uapi/dvb/ca-get-descr-info.rst
Documentation/media/uapi/dvb/ca-get-msg.rst
Documentation/media/uapi/dvb/ca-get-slot-info.rst
Documentation/media/uapi/dvb/ca-reset.rst
Documentation/media/uapi/dvb/ca-send-msg.rst
Documentation/media/uapi/dvb/ca-set-descr.rst
Documentation/media/uapi/dvb/ca.rst
Documentation/media/uapi/dvb/ca_data_types.rst
Documentation/media/uapi/dvb/ca_function_calls.rst
Documentation/media/uapi/dvb/demux.rst
Documentation/media/uapi/dvb/dmx-add-pid.rst
Documentation/media/uapi/dvb/dmx-expbuf.rst
Documentation/media/uapi/dvb/dmx-fclose.rst
Documentation/media/uapi/dvb/dmx-fopen.rst
Documentation/media/uapi/dvb/dmx-fread.rst
Documentation/media/uapi/dvb/dmx-fwrite.rst
Documentation/media/uapi/dvb/dmx-get-pes-pids.rst
Documentation/media/uapi/dvb/dmx-get-stc.rst
Documentation/media/uapi/dvb/dmx-mmap.rst
Documentation/media/uapi/dvb/dmx-munmap.rst
Documentation/media/uapi/dvb/dmx-qbuf.rst
Documentation/media/uapi/dvb/dmx-querybuf.rst
Documentation/media/uapi/dvb/dmx-remove-pid.rst
Documentation/media/uapi/dvb/dmx-reqbufs.rst
Documentation/media/uapi/dvb/dmx-set-buffer-size.rst
Documentation/media/uapi/dvb/dmx-set-filter.rst
Documentation/media/uapi/dvb/dmx-set-pes-filter.rst
Documentation/media/uapi/dvb/dmx-start.rst
Documentation/media/uapi/dvb/dmx-stop.rst
Documentation/media/uapi/dvb/dmx_fcalls.rst
Documentation/media/uapi/dvb/dmx_types.rst
Documentation/media/uapi/dvb/dvb-fe-read-status.rst
Documentation/media/uapi/dvb/dvb-frontend-event.rst
Documentation/media/uapi/dvb/dvb-frontend-parameters.rst
Documentation/media/uapi/dvb/dvbapi.rst
Documentation/media/uapi/dvb/dvbproperty.rst
Documentation/media/uapi/dvb/dvbstb.svg
Documentation/media/uapi/dvb/examples.rst
Documentation/media/uapi/dvb/fe-bandwidth-t.rst
Documentation/media/uapi/dvb/fe-diseqc-recv-slave-reply.rst
Documentation/media/uapi/dvb/fe-diseqc-reset-overload.rst
Documentation/media/uapi/dvb/fe-diseqc-send-burst.rst
Documentation/media/uapi/dvb/fe-diseqc-send-master-cmd.rst
Documentation/media/uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst
Documentation/media/uapi/dvb/fe-enable-high-lnb-voltage.rst
Documentation/media/uapi/dvb/fe-get-event.rst
Documentation/media/uapi/dvb/fe-get-frontend.rst
Documentation/media/uapi/dvb/fe-get-info.rst
Documentation/media/uapi/dvb/fe-get-property.rst
Documentation/media/uapi/dvb/fe-read-ber.rst
Documentation/media/uapi/dvb/fe-read-signal-strength.rst
Documentation/media/uapi/dvb/fe-read-snr.rst
Documentation/media/uapi/dvb/fe-read-status.rst
Documentation/media/uapi/dvb/fe-read-uncorrected-blocks.rst
Documentation/media/uapi/dvb/fe-set-frontend-tune-mode.rst
Documentation/media/uapi/dvb/fe-set-frontend.rst
Documentation/media/uapi/dvb/fe-set-tone.rst
Documentation/media/uapi/dvb/fe-set-voltage.rst
Documentation/media/uapi/dvb/fe-type-t.rst
Documentation/media/uapi/dvb/fe_property_parameters.rst
Documentation/media/uapi/dvb/frontend-header.rst
Documentation/media/uapi/dvb/frontend-property-cable-systems.rst
Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst
Documentation/media/uapi/dvb/frontend-property-terrestrial-systems.rst
Documentation/media/uapi/dvb/frontend-stat-properties.rst
Documentation/media/uapi/dvb/frontend.rst
Documentation/media/uapi/dvb/frontend_f_close.rst
Documentation/media/uapi/dvb/frontend_f_open.rst
Documentation/media/uapi/dvb/frontend_fcalls.rst
Documentation/media/uapi/dvb/frontend_legacy_api.rst
Documentation/media/uapi/dvb/frontend_legacy_dvbv3_api.rst
Documentation/media/uapi/dvb/headers.rst
Documentation/media/uapi/dvb/intro.rst
Documentation/media/uapi/dvb/legacy_dvb_apis.rst
Documentation/media/uapi/dvb/net-add-if.rst
Documentation/media/uapi/dvb/net-get-if.rst
Documentation/media/uapi/dvb/net-remove-if.rst
Documentation/media/uapi/dvb/net-types.rst
Documentation/media/uapi/dvb/net.rst
Documentation/media/uapi/dvb/query-dvb-frontend-info.rst
Documentation/media/uapi/dvb/video-clear-buffer.rst
Documentation/media/uapi/dvb/video-command.rst
Documentation/media/uapi/dvb/video-continue.rst
Documentation/media/uapi/dvb/video-fast-forward.rst
Documentation/media/uapi/dvb/video-fclose.rst
Documentation/media/uapi/dvb/video-fopen.rst
Documentation/media/uapi/dvb/video-freeze.rst
Documentation/media/uapi/dvb/video-fwrite.rst
Documentation/media/uapi/dvb/video-get-capabilities.rst
Documentation/media/uapi/dvb/video-get-event.rst
Documentation/media/uapi/dvb/video-get-frame-count.rst
Documentation/media/uapi/dvb/video-get-pts.rst
Documentation/media/uapi/dvb/video-get-size.rst
Documentation/media/uapi/dvb/video-get-status.rst
Documentation/media/uapi/dvb/video-play.rst
Documentation/media/uapi/dvb/video-select-source.rst
Documentation/media/uapi/dvb/video-set-blank.rst
Documentation/media/uapi/dvb/video-set-display-format.rst
Documentation/media/uapi/dvb/video-set-format.rst
Documentation/media/uapi/dvb/video-set-streamtype.rst
Documentation/media/uapi/dvb/video-slowmotion.rst
Documentation/media/uapi/dvb/video-stillpicture.rst
Documentation/media/uapi/dvb/video-stop.rst
Documentation/media/uapi/dvb/video-try-command.rst
Documentation/media/uapi/dvb/video.rst
Documentation/media/uapi/dvb/video_function_calls.rst
Documentation/media/uapi/dvb/video_types.rst
Documentation/media/uapi/fdl-appendix.rst
Documentation/media/uapi/gen-errors.rst
Documentation/media/uapi/mediactl/media-controller-intro.rst
Documentation/media/uapi/mediactl/media-controller-model.rst
Documentation/media/uapi/mediactl/media-controller.rst
Documentation/media/uapi/mediactl/media-func-close.rst
Documentation/media/uapi/mediactl/media-func-ioctl.rst
Documentation/media/uapi/mediactl/media-func-open.rst
Documentation/media/uapi/mediactl/media-funcs.rst
Documentation/media/uapi/mediactl/media-header.rst
Documentation/media/uapi/mediactl/media-ioc-device-info.rst
Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst
Documentation/media/uapi/mediactl/media-ioc-enum-links.rst
Documentation/media/uapi/mediactl/media-ioc-g-topology.rst
Documentation/media/uapi/mediactl/media-ioc-request-alloc.rst
Documentation/media/uapi/mediactl/media-ioc-setup-link.rst
Documentation/media/uapi/mediactl/media-request-ioc-queue.rst
Documentation/media/uapi/mediactl/media-request-ioc-reinit.rst
Documentation/media/uapi/mediactl/media-types.rst
Documentation/media/uapi/mediactl/request-api.rst
Documentation/media/uapi/mediactl/request-func-close.rst
Documentation/media/uapi/mediactl/request-func-ioctl.rst
Documentation/media/uapi/mediactl/request-func-poll.rst
Documentation/media/uapi/rc/keytable.c.rst
Documentation/media/uapi/rc/lirc-dev-intro.rst
Documentation/media/uapi/rc/lirc-dev.rst
Documentation/media/uapi/rc/lirc-func.rst
Documentation/media/uapi/rc/lirc-get-features.rst
Documentation/media/uapi/rc/lirc-get-rec-mode.rst
Documentation/media/uapi/rc/lirc-get-rec-resolution.rst
Documentation/media/uapi/rc/lirc-get-send-mode.rst
Documentation/media/uapi/rc/lirc-get-timeout.rst
Documentation/media/uapi/rc/lirc-header.rst
Documentation/media/uapi/rc/lirc-read.rst
Documentation/media/uapi/rc/lirc-set-measure-carrier-mode.rst
Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst
Documentation/media/uapi/rc/lirc-set-rec-carrier.rst
Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst
Documentation/media/uapi/rc/lirc-set-rec-timeout.rst
Documentation/media/uapi/rc/lirc-set-send-carrier.rst
Documentation/media/uapi/rc/lirc-set-send-duty-cycle.rst
Documentation/media/uapi/rc/lirc-set-transmitter-mask.rst
Documentation/media/uapi/rc/lirc-set-wideband-receiver.rst
Documentation/media/uapi/rc/lirc-write.rst
Documentation/media/uapi/rc/rc-intro.rst
Documentation/media/uapi/rc/rc-sysfs-nodes.rst
Documentation/media/uapi/rc/rc-table-change.rst
Documentation/media/uapi/rc/rc-tables.rst
Documentation/media/uapi/rc/remote_controllers.rst
Documentation/media/uapi/v4l/app-pri.rst
Documentation/media/uapi/v4l/async.rst
Documentation/media/uapi/v4l/audio.rst
Documentation/media/uapi/v4l/bayer.svg
Documentation/media/uapi/v4l/biblio.rst
Documentation/media/uapi/v4l/buffer.rst
Documentation/media/uapi/v4l/capture-example.rst
Documentation/media/uapi/v4l/capture.c.rst
Documentation/media/uapi/v4l/colorspaces-defs.rst
Documentation/media/uapi/v4l/colorspaces-details.rst
Documentation/media/uapi/v4l/colorspaces.rst
Documentation/media/uapi/v4l/common-defs.rst
Documentation/media/uapi/v4l/common.rst
Documentation/media/uapi/v4l/compat.rst
Documentation/media/uapi/v4l/constraints.svg
Documentation/media/uapi/v4l/control.rst
Documentation/media/uapi/v4l/crop.rst
Documentation/media/uapi/v4l/crop.svg
Documentation/media/uapi/v4l/depth-formats.rst
Documentation/media/uapi/v4l/dev-capture.rst
Documentation/media/uapi/v4l/dev-codec.rst
Documentation/media/uapi/v4l/dev-effect.rst
Documentation/media/uapi/v4l/dev-event.rst
Documentation/media/uapi/v4l/dev-meta.rst
Documentation/media/uapi/v4l/dev-osd.rst
Documentation/media/uapi/v4l/dev-output.rst
Documentation/media/uapi/v4l/dev-overlay.rst
Documentation/media/uapi/v4l/dev-radio.rst
Documentation/media/uapi/v4l/dev-raw-vbi.rst
Documentation/media/uapi/v4l/dev-rds.rst
Documentation/media/uapi/v4l/dev-sdr.rst
Documentation/media/uapi/v4l/dev-sliced-vbi.rst
Documentation/media/uapi/v4l/dev-subdev.rst
Documentation/media/uapi/v4l/dev-teletext.rst
Documentation/media/uapi/v4l/dev-touch.rst
Documentation/media/uapi/v4l/devices.rst
Documentation/media/uapi/v4l/diff-v4l.rst
Documentation/media/uapi/v4l/dmabuf.rst
Documentation/media/uapi/v4l/dv-timings.rst
Documentation/media/uapi/v4l/extended-controls.rst
Documentation/media/uapi/v4l/field-order.rst
Documentation/media/uapi/v4l/fieldseq_bt.svg
Documentation/media/uapi/v4l/fieldseq_tb.svg
Documentation/media/uapi/v4l/format.rst
Documentation/media/uapi/v4l/func-close.rst
Documentation/media/uapi/v4l/func-ioctl.rst
Documentation/media/uapi/v4l/func-mmap.rst
Documentation/media/uapi/v4l/func-munmap.rst
Documentation/media/uapi/v4l/func-open.rst
Documentation/media/uapi/v4l/func-poll.rst
Documentation/media/uapi/v4l/func-read.rst
Documentation/media/uapi/v4l/func-select.rst
Documentation/media/uapi/v4l/func-write.rst
Documentation/media/uapi/v4l/hist-v4l2.rst
Documentation/media/uapi/v4l/hsv-formats.rst
Documentation/media/uapi/v4l/io.rst
Documentation/media/uapi/v4l/libv4l-introduction.rst
Documentation/media/uapi/v4l/libv4l.rst
Documentation/media/uapi/v4l/meta-formats.rst
Documentation/media/uapi/v4l/mmap.rst
Documentation/media/uapi/v4l/nv12mt.svg
Documentation/media/uapi/v4l/nv12mt_example.svg
Documentation/media/uapi/v4l/open.rst
Documentation/media/uapi/v4l/pipeline.dot
Documentation/media/uapi/v4l/pixfmt-cnf4.rst [new file with mode: 0644]
Documentation/media/uapi/v4l/pixfmt-compressed.rst
Documentation/media/uapi/v4l/pixfmt-grey.rst
Documentation/media/uapi/v4l/pixfmt-indexed.rst
Documentation/media/uapi/v4l/pixfmt-intro.rst
Documentation/media/uapi/v4l/pixfmt-inzi.rst
Documentation/media/uapi/v4l/pixfmt-m420.rst
Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst
Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst [new file with mode: 0644]
Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst
Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgo.rst
Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst
Documentation/media/uapi/v4l/pixfmt-nv12.rst
Documentation/media/uapi/v4l/pixfmt-nv12m.rst
Documentation/media/uapi/v4l/pixfmt-nv12mt.rst
Documentation/media/uapi/v4l/pixfmt-nv16.rst
Documentation/media/uapi/v4l/pixfmt-nv16m.rst
Documentation/media/uapi/v4l/pixfmt-nv24.rst
Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst
Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst
Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst
Documentation/media/uapi/v4l/pixfmt-reserved.rst
Documentation/media/uapi/v4l/pixfmt-rgb.rst
Documentation/media/uapi/v4l/pixfmt-sdr-cs08.rst
Documentation/media/uapi/v4l/pixfmt-sdr-cs14le.rst
Documentation/media/uapi/v4l/pixfmt-sdr-cu08.rst
Documentation/media/uapi/v4l/pixfmt-sdr-cu16le.rst
Documentation/media/uapi/v4l/pixfmt-sdr-pcu16be.rst
Documentation/media/uapi/v4l/pixfmt-sdr-pcu18be.rst
Documentation/media/uapi/v4l/pixfmt-sdr-pcu20be.rst
Documentation/media/uapi/v4l/pixfmt-sdr-ru12le.rst
Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst
Documentation/media/uapi/v4l/pixfmt-srggb10.rst
Documentation/media/uapi/v4l/pixfmt-srggb10alaw8.rst
Documentation/media/uapi/v4l/pixfmt-srggb10dpcm8.rst
Documentation/media/uapi/v4l/pixfmt-srggb10p.rst
Documentation/media/uapi/v4l/pixfmt-srggb12.rst
Documentation/media/uapi/v4l/pixfmt-srggb12p.rst
Documentation/media/uapi/v4l/pixfmt-srggb14p.rst
Documentation/media/uapi/v4l/pixfmt-srggb16.rst
Documentation/media/uapi/v4l/pixfmt-srggb8.rst
Documentation/media/uapi/v4l/pixfmt-tch-td08.rst
Documentation/media/uapi/v4l/pixfmt-tch-td16.rst
Documentation/media/uapi/v4l/pixfmt-tch-tu08.rst
Documentation/media/uapi/v4l/pixfmt-tch-tu16.rst
Documentation/media/uapi/v4l/pixfmt-uv8.rst
Documentation/media/uapi/v4l/pixfmt-uyvy.rst
Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst
Documentation/media/uapi/v4l/pixfmt-v4l2.rst
Documentation/media/uapi/v4l/pixfmt-vyuy.rst
Documentation/media/uapi/v4l/pixfmt-y10.rst
Documentation/media/uapi/v4l/pixfmt-y10b.rst
Documentation/media/uapi/v4l/pixfmt-y10p.rst
Documentation/media/uapi/v4l/pixfmt-y12.rst
Documentation/media/uapi/v4l/pixfmt-y12i.rst
Documentation/media/uapi/v4l/pixfmt-y16-be.rst
Documentation/media/uapi/v4l/pixfmt-y16.rst
Documentation/media/uapi/v4l/pixfmt-y41p.rst
Documentation/media/uapi/v4l/pixfmt-y8i.rst
Documentation/media/uapi/v4l/pixfmt-yuv410.rst
Documentation/media/uapi/v4l/pixfmt-yuv411p.rst
Documentation/media/uapi/v4l/pixfmt-yuv420.rst
Documentation/media/uapi/v4l/pixfmt-yuv420m.rst
Documentation/media/uapi/v4l/pixfmt-yuv422m.rst
Documentation/media/uapi/v4l/pixfmt-yuv422p.rst
Documentation/media/uapi/v4l/pixfmt-yuv444m.rst
Documentation/media/uapi/v4l/pixfmt-yuyv.rst
Documentation/media/uapi/v4l/pixfmt-yvyu.rst
Documentation/media/uapi/v4l/pixfmt-z16.rst
Documentation/media/uapi/v4l/pixfmt.rst
Documentation/media/uapi/v4l/planar-apis.rst
Documentation/media/uapi/v4l/querycap.rst
Documentation/media/uapi/v4l/rw.rst
Documentation/media/uapi/v4l/sdr-formats.rst
Documentation/media/uapi/v4l/selection-api-configuration.rst
Documentation/media/uapi/v4l/selection-api-examples.rst
Documentation/media/uapi/v4l/selection-api-intro.rst
Documentation/media/uapi/v4l/selection-api-targets.rst
Documentation/media/uapi/v4l/selection-api-vs-crop-api.rst
Documentation/media/uapi/v4l/selection-api.rst
Documentation/media/uapi/v4l/selection.svg
Documentation/media/uapi/v4l/selections-common.rst
Documentation/media/uapi/v4l/standard.rst
Documentation/media/uapi/v4l/streaming-par.rst
Documentation/media/uapi/v4l/subdev-formats.rst
Documentation/media/uapi/v4l/subdev-image-processing-crop.svg
Documentation/media/uapi/v4l/subdev-image-processing-full.svg
Documentation/media/uapi/v4l/subdev-image-processing-scaling-multi-source.svg
Documentation/media/uapi/v4l/tch-formats.rst
Documentation/media/uapi/v4l/tuner.rst
Documentation/media/uapi/v4l/user-func.rst
Documentation/media/uapi/v4l/userp.rst
Documentation/media/uapi/v4l/v4l2-selection-flags.rst
Documentation/media/uapi/v4l/v4l2-selection-targets.rst
Documentation/media/uapi/v4l/v4l2.rst
Documentation/media/uapi/v4l/v4l2grab-example.rst
Documentation/media/uapi/v4l/v4l2grab.c.rst
Documentation/media/uapi/v4l/vbi_525.svg
Documentation/media/uapi/v4l/vbi_625.svg
Documentation/media/uapi/v4l/vbi_hsync.svg
Documentation/media/uapi/v4l/video.rst
Documentation/media/uapi/v4l/videodev.rst
Documentation/media/uapi/v4l/vidioc-create-bufs.rst
Documentation/media/uapi/v4l/vidioc-cropcap.rst
Documentation/media/uapi/v4l/vidioc-dbg-g-chip-info.rst
Documentation/media/uapi/v4l/vidioc-dbg-g-register.rst
Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst
Documentation/media/uapi/v4l/vidioc-dqevent.rst
Documentation/media/uapi/v4l/vidioc-dv-timings-cap.rst
Documentation/media/uapi/v4l/vidioc-encoder-cmd.rst
Documentation/media/uapi/v4l/vidioc-enum-dv-timings.rst
Documentation/media/uapi/v4l/vidioc-enum-fmt.rst
Documentation/media/uapi/v4l/vidioc-enum-frameintervals.rst
Documentation/media/uapi/v4l/vidioc-enum-framesizes.rst
Documentation/media/uapi/v4l/vidioc-enum-freq-bands.rst
Documentation/media/uapi/v4l/vidioc-enumaudio.rst
Documentation/media/uapi/v4l/vidioc-enumaudioout.rst
Documentation/media/uapi/v4l/vidioc-enuminput.rst
Documentation/media/uapi/v4l/vidioc-enumoutput.rst
Documentation/media/uapi/v4l/vidioc-enumstd.rst
Documentation/media/uapi/v4l/vidioc-expbuf.rst
Documentation/media/uapi/v4l/vidioc-g-audio.rst
Documentation/media/uapi/v4l/vidioc-g-audioout.rst
Documentation/media/uapi/v4l/vidioc-g-crop.rst
Documentation/media/uapi/v4l/vidioc-g-ctrl.rst
Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst
Documentation/media/uapi/v4l/vidioc-g-edid.rst
Documentation/media/uapi/v4l/vidioc-g-enc-index.rst
Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst
Documentation/media/uapi/v4l/vidioc-g-fbuf.rst
Documentation/media/uapi/v4l/vidioc-g-fmt.rst
Documentation/media/uapi/v4l/vidioc-g-frequency.rst
Documentation/media/uapi/v4l/vidioc-g-input.rst
Documentation/media/uapi/v4l/vidioc-g-jpegcomp.rst
Documentation/media/uapi/v4l/vidioc-g-modulator.rst
Documentation/media/uapi/v4l/vidioc-g-output.rst
Documentation/media/uapi/v4l/vidioc-g-parm.rst
Documentation/media/uapi/v4l/vidioc-g-priority.rst
Documentation/media/uapi/v4l/vidioc-g-selection.rst
Documentation/media/uapi/v4l/vidioc-g-sliced-vbi-cap.rst
Documentation/media/uapi/v4l/vidioc-g-std.rst
Documentation/media/uapi/v4l/vidioc-g-tuner.rst
Documentation/media/uapi/v4l/vidioc-log-status.rst
Documentation/media/uapi/v4l/vidioc-overlay.rst
Documentation/media/uapi/v4l/vidioc-prepare-buf.rst
Documentation/media/uapi/v4l/vidioc-qbuf.rst
Documentation/media/uapi/v4l/vidioc-query-dv-timings.rst
Documentation/media/uapi/v4l/vidioc-querybuf.rst
Documentation/media/uapi/v4l/vidioc-querycap.rst
Documentation/media/uapi/v4l/vidioc-queryctrl.rst
Documentation/media/uapi/v4l/vidioc-querystd.rst
Documentation/media/uapi/v4l/vidioc-reqbufs.rst
Documentation/media/uapi/v4l/vidioc-s-hw-freq-seek.rst
Documentation/media/uapi/v4l/vidioc-streamon.rst
Documentation/media/uapi/v4l/vidioc-subdev-enum-frame-interval.rst
Documentation/media/uapi/v4l/vidioc-subdev-enum-frame-size.rst
Documentation/media/uapi/v4l/vidioc-subdev-enum-mbus-code.rst
Documentation/media/uapi/v4l/vidioc-subdev-g-crop.rst
Documentation/media/uapi/v4l/vidioc-subdev-g-fmt.rst
Documentation/media/uapi/v4l/vidioc-subdev-g-frame-interval.rst
Documentation/media/uapi/v4l/vidioc-subdev-g-selection.rst
Documentation/media/uapi/v4l/vidioc-subscribe-event.rst
Documentation/media/uapi/v4l/yuv-formats.rst
Documentation/media/v4l-drivers/au0828-cardlist.rst
Documentation/media/v4l-drivers/bttv-cardlist.rst
Documentation/media/v4l-drivers/bttv.rst
Documentation/media/v4l-drivers/cafe_ccic.rst
Documentation/media/v4l-drivers/cardlist.rst
Documentation/media/v4l-drivers/cpia2.rst
Documentation/media/v4l-drivers/cx18.rst
Documentation/media/v4l-drivers/cx2341x.rst
Documentation/media/v4l-drivers/cx23885-cardlist.rst
Documentation/media/v4l-drivers/cx88-cardlist.rst
Documentation/media/v4l-drivers/cx88.rst
Documentation/media/v4l-drivers/davinci-vpbe.rst
Documentation/media/v4l-drivers/em28xx-cardlist.rst
Documentation/media/v4l-drivers/fimc.rst
Documentation/media/v4l-drivers/fourcc.rst
Documentation/media/v4l-drivers/gspca-cardlist.rst
Documentation/media/v4l-drivers/imx.rst
Documentation/media/v4l-drivers/index.rst
Documentation/media/v4l-drivers/ipu3.rst [new file with mode: 0644]
Documentation/media/v4l-drivers/ivtv-cardlist.rst
Documentation/media/v4l-drivers/ivtv.rst
Documentation/media/v4l-drivers/max2175.rst
Documentation/media/v4l-drivers/meye.rst
Documentation/media/v4l-drivers/omap3isp.rst
Documentation/media/v4l-drivers/omap4_camera.rst
Documentation/media/v4l-drivers/philips.rst
Documentation/media/v4l-drivers/pvrusb2.rst
Documentation/media/v4l-drivers/pxa_camera.rst
Documentation/media/v4l-drivers/qcom_camss.rst
Documentation/media/v4l-drivers/qcom_camss_8x96_graph.dot
Documentation/media/v4l-drivers/qcom_camss_graph.dot
Documentation/media/v4l-drivers/radiotrack.rst
Documentation/media/v4l-drivers/rcar-fdp1.rst
Documentation/media/v4l-drivers/saa7134-cardlist.rst
Documentation/media/v4l-drivers/saa7134.rst
Documentation/media/v4l-drivers/saa7164-cardlist.rst
Documentation/media/v4l-drivers/sh_mobile_ceu_camera.rst
Documentation/media/v4l-drivers/si470x.rst
Documentation/media/v4l-drivers/si4713.rst
Documentation/media/v4l-drivers/si476x.rst
Documentation/media/v4l-drivers/soc-camera.rst
Documentation/media/v4l-drivers/tm6000-cardlist.rst
Documentation/media/v4l-drivers/tuner-cardlist.rst
Documentation/media/v4l-drivers/tuners.rst
Documentation/media/v4l-drivers/usbvision-cardlist.rst
Documentation/media/v4l-drivers/uvcvideo.rst
Documentation/media/v4l-drivers/v4l-with-ir.rst
Documentation/media/v4l-drivers/vivid.rst
Documentation/media/v4l-drivers/zoran.rst
Documentation/media/v4l-drivers/zr364xx.rst
Documentation/media/video.h.rst.exceptions
Documentation/media/videodev2.h.rst.exceptions
Documentation/vm/unevictable-lru.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/omap1_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-s3c64xx/mach-crag6410-module.c
arch/arm64/Kconfig
arch/m68k/kernel/setup_mm.c
arch/m68k/mm/motorola.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/setup_64.c
arch/sparc/vdso/Makefile
arch/x86/Makefile
arch/x86/entry/calling.h
arch/x86/entry/vdso/Makefile
arch/x86/include/asm/alternative-asm.h
arch/x86/include/asm/alternative.h
arch/x86/include/asm/asm.h
arch/x86/include/asm/bug.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/fsgsbase.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/pgtable_64_types.h
arch/x86/include/asm/refcount.h
arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
arch/x86/kernel/cpu/mtrr/if.c
arch/x86/kernel/macros.S [deleted file]
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/xen/mmu_pv.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_apd.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/dbxface.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dspkginit.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exserial.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psobject.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utosi.c
drivers/acpi/apei/einj.c
drivers/acpi/apei/ghes.c
drivers/acpi/arm64/iort.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/osi.c
drivers/acpi/osl.c
drivers/acpi/reboot.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/spcr.c
drivers/acpi/tables.c
drivers/auxdisplay/charlcd.c
drivers/base/power/domain.c
drivers/base/power/runtime.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq-nforce2.c
drivers/cpufreq/ia64-acpi-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/pmac64-cpufreq.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c [new file with mode: 0644]
drivers/cpufreq/s3c24xx-cpufreq-debugfs.c
drivers/cpuidle/cpuidle-big_little.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.h
drivers/cpuidle/governor.c
drivers/cpuidle/poll_state.c
drivers/cpuidle/sysfs.c
drivers/crypto/chelsio/chtls/chtls.h
drivers/crypto/chelsio/chtls/chtls_cm.c
drivers/crypto/chelsio/chtls/chtls_io.c
drivers/crypto/chelsio/chtls/chtls_main.c
drivers/devfreq/devfreq.c
drivers/dma-buf/dma-fence.c
drivers/dma-buf/reservation.c
drivers/edac/Kconfig
drivers/edac/e752x_edac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/fsl_ddr_edac.c
drivers/edac/fsl_ddr_edac.h
drivers/edac/i3000_edac.c
drivers/edac/i5000_edac.c
drivers/edac/i7core_edac.c
drivers/edac/i82975x_edac.c
drivers/edac/qcom_edac.c
drivers/edac/skx_edac.c
drivers/edac/synopsys_edac.c
drivers/gpio/gpio-max7301.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-devres.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/cik.c
drivers/gpu/drm/amd/amdgpu/cik.h
drivers/gpu/drm/amd/amdgpu/cik_ih.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cz_ih.c
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/iceland_ih.c
drivers/gpu/drm/amd/amdgpu/kv_dpm.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h
drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c
drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
drivers/gpu/drm/amd/amdgpu/si_dma.c
drivers/gpu/drm/amd/amdgpu/si_ih.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/soc15.h
drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/tonga_ih.c
drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
drivers/gpu/drm/amd/amdgpu/vega10_ih.c
drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c
drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdgpu/vi.h
drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
drivers/gpu/drm/amd/amdkfd/cik_regs.h
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_crat.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_device_queue_manager_vi.c
drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_pasid.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/display/Makefile
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_debug.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drivers/gpu/drm/amd/display/dc/core/dc_surface.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_bios_types.h
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dce/Makefile
drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c [deleted file]
drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h [deleted file]
drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h
drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
drivers/gpu/drm/amd/display/dc/dcn10/Makefile
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dm_event_log.h
drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
drivers/gpu/drm/amd/display/dc/dm_services.h
drivers/gpu/drm/amd/display/dc/dm_services_types.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h
drivers/gpu/drm/amd/display/dc/inc/compressor.h
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h [deleted file]
drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/inc/resource.h
drivers/gpu/drm/amd/display/modules/color/color_gamma.c
drivers/gpu/drm/amd/display/modules/color/color_gamma.h
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
drivers/gpu/drm/amd/display/modules/inc/mod_shared.h
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
drivers/gpu/drm/amd/display/modules/power/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/modules/power/power_helpers.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/modules/power/power_helpers.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/amd_acpi.h
drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/amd/include/kgd_pp_interface.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
drivers/gpu/drm/amd/powerplay/inc/smu7_common.h
drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c
drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
drivers/gpu/drm/arc/arcpgu.h
drivers/gpu/drm/arc/arcpgu_crtc.c
drivers/gpu/drm/arc/arcpgu_drv.c
drivers/gpu/drm/arm/malidp_hw.c
drivers/gpu/drm/arm/malidp_planes.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/bochs/bochs.h
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/sii902x.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
drivers/gpu/drm/bridge/tc358764.c
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_atomic_state_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_atomic_uapi.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_client.c
drivers/gpu/drm/drm_color_mgmt.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_damage_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_dp_cec.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_dsc.c [new file with mode: 0644]
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fourcc.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_gem_framebuffer_helper.c
drivers/gpu/drm/drm_global.c [deleted file]
drivers/gpu/drm/drm_info.c [deleted file]
drivers/gpu/drm/drm_internal.h
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_lease.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_mode_config.c
drivers/gpu/drm/drm_mode_object.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_modeset_helper.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/drm_simple_kms_helper.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/etnaviv/etnaviv_drv.c
drivers/gpu/drm/etnaviv/etnaviv_dump.c
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
drivers/gpu/drm/etnaviv/etnaviv_sched.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/Makefile
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_dma.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_iommu.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_iommu.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_scaler.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/exynos/regs-decon5433.h
drivers/gpu/drm/exynos/regs-mixer.h
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_fixed.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem.h
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_context.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_gpu_error.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_oa_bdw.c
drivers/gpu/drm/i915/i915_oa_bdw.h
drivers/gpu/drm/i915/i915_oa_bxt.c
drivers/gpu/drm/i915/i915_oa_bxt.h
drivers/gpu/drm/i915/i915_oa_cflgt2.c
drivers/gpu/drm/i915/i915_oa_cflgt2.h
drivers/gpu/drm/i915/i915_oa_cflgt3.c
drivers/gpu/drm/i915/i915_oa_cflgt3.h
drivers/gpu/drm/i915/i915_oa_chv.c
drivers/gpu/drm/i915/i915_oa_chv.h
drivers/gpu/drm/i915/i915_oa_cnl.c
drivers/gpu/drm/i915/i915_oa_cnl.h
drivers/gpu/drm/i915/i915_oa_glk.c
drivers/gpu/drm/i915/i915_oa_glk.h
drivers/gpu/drm/i915/i915_oa_hsw.c
drivers/gpu/drm/i915/i915_oa_hsw.h
drivers/gpu/drm/i915/i915_oa_icl.c
drivers/gpu/drm/i915/i915_oa_icl.h
drivers/gpu/drm/i915/i915_oa_kblgt2.c
drivers/gpu/drm/i915/i915_oa_kblgt2.h
drivers/gpu/drm/i915/i915_oa_kblgt3.c
drivers/gpu/drm/i915/i915_oa_kblgt3.h
drivers/gpu/drm/i915/i915_oa_sklgt2.c
drivers/gpu/drm/i915/i915_oa_sklgt2.h
drivers/gpu/drm/i915/i915_oa_sklgt3.c
drivers/gpu/drm/i915/i915_oa_sklgt3.h
drivers/gpu/drm/i915/i915_oa_sklgt4.c
drivers/gpu/drm/i915/i915_oa_sklgt4.h
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_params.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_query.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/i915_scheduler.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_scheduler.h
drivers/gpu/drm/i915/i915_sw_fence.c
drivers/gpu/drm/i915/i915_sw_fence.h
drivers/gpu/drm/i915/i915_syncmap.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_timeline.h
drivers/gpu/drm/i915/i915_utils.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/icl_dsi.c
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_atomic_plane.c
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_cdclk.c
drivers/gpu/drm/i915/intel_color.c
drivers/gpu/drm/i915/intel_combo_phy.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_connector.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_csr.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/i915/intel_device_info.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_display.h
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_dpio_phy.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dsi.h
drivers/gpu/drm/i915/intel_dsi_vbt.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_guc.c
drivers/gpu/drm/i915/intel_guc.h
drivers/gpu/drm/i915/intel_guc_fw.c
drivers/gpu/drm/i915/intel_guc_fwif.h
drivers/gpu/drm/i915/intel_guc_reg.h
drivers/gpu/drm/i915/intel_guc_submission.c
drivers/gpu/drm/i915/intel_hdcp.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_hotplug.c
drivers/gpu/drm/i915/intel_huc.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lspcon.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c [deleted file]
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_opregion.h
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_quirks.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uc.c
drivers/gpu/drm/i915/intel_uc_fw.h
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/i915/intel_vbt_defs.h
drivers/gpu/drm/i915/intel_vdsc.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_workarounds.c
drivers/gpu/drm/i915/intel_workarounds.h
drivers/gpu/drm/i915/selftests/huge_pages.c
drivers/gpu/drm/i915/selftests/i915_gem_context.c
drivers/gpu/drm/i915/selftests/i915_gem_evict.c
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/igt_reset.c [new file with mode: 0644]
drivers/gpu/drm/i915/selftests/igt_reset.h [new file with mode: 0644]
drivers/gpu/drm/i915/selftests/igt_spinner.c [new file with mode: 0644]
drivers/gpu/drm/i915/selftests/igt_spinner.h [new file with mode: 0644]
drivers/gpu/drm/i915/selftests/intel_guc.c
drivers/gpu/drm/i915/selftests/intel_hangcheck.c
drivers/gpu/drm/i915/selftests/intel_lrc.c
drivers/gpu/drm/i915/selftests/intel_workarounds.c
drivers/gpu/drm/i915/selftests/mock_engine.c
drivers/gpu/drm/i915/vlv_dsi.c
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/imx/imx-drm-core.c
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/parallel-display.c
drivers/gpu/drm/meson/Kconfig
drivers/gpu/drm/meson/Makefile
drivers/gpu/drm/meson/meson_canvas.c
drivers/gpu/drm/meson/meson_canvas.h
drivers/gpu/drm/meson/meson_crtc.c
drivers/gpu/drm/meson/meson_drv.c
drivers/gpu/drm/meson/meson_drv.h
drivers/gpu/drm/meson/meson_dw_hdmi.c
drivers/gpu/drm/meson/meson_overlay.c [new file with mode: 0644]
drivers/gpu/drm/meson/meson_overlay.h [new file with mode: 0644]
drivers/gpu/drm/meson/meson_plane.c
drivers/gpu/drm/meson/meson_registers.h
drivers/gpu/drm/meson/meson_vclk.c
drivers/gpu/drm/meson/meson_vclk.h
drivers/gpu/drm/meson/meson_venc.c
drivers/gpu/drm/meson/meson_viu.c
drivers/gpu/drm/meson/meson_viu.h
drivers/gpu/drm/meson/meson_vpp.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a2xx.xml.h
drivers/gpu/drm/msm/adreno/a2xx_gpu.c [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a2xx_gpu.h [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a3xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/a4xx.xml.h
drivers/gpu/drm/msm/adreno/a4xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx.xml.h
drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx_power.c
drivers/gpu/drm/msm/adreno/a5xx_preempt.c
drivers/gpu/drm/msm/adreno/a6xx.xml.h
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
drivers/gpu/drm/msm/adreno/a6xx_gmu.xml.h
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.h
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a6xx_hfi.c
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c
drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c
drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h [deleted file]
drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h
drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h
drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
drivers/gpu/drm/msm/edp/edp.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c
drivers/gpu/drm/msm/hdmi/hdmi_phy.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c
drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_debugfs.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fb.c
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gem_vma.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_gpu_trace.h [new file with mode: 0644]
drivers/gpu/drm/msm/msm_gpu_tracepoints.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_gpummu.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/msm/msm_kms.h
drivers/gpu/drm/msm/msm_mmu.h
drivers/gpu/drm/msm/msm_rd.c
drivers/gpu/drm/msm/msm_ringbuffer.c
drivers/gpu/drm/msm/msm_ringbuffer.h
drivers/gpu/drm/mxsfb/mxsfb_drv.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv50/Kbuild
drivers/gpu/drm/nouveau/dispnv50/atom.h
drivers/gpu/drm/nouveau/dispnv50/base907c.c
drivers/gpu/drm/nouveau/dispnv50/core.c
drivers/gpu/drm/nouveau/dispnv50/core.h
drivers/gpu/drm/nouveau/dispnv50/corec37d.c
drivers/gpu/drm/nouveau/dispnv50/corec57d.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv50/curs.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/dispnv50/disp.h
drivers/gpu/drm/nouveau/dispnv50/head.c
drivers/gpu/drm/nouveau/dispnv50/head.h
drivers/gpu/drm/nouveau/dispnv50/head507d.c
drivers/gpu/drm/nouveau/dispnv50/head907d.c
drivers/gpu/drm/nouveau/dispnv50/headc37d.c
drivers/gpu/drm/nouveau/dispnv50/headc57d.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv50/lut.c
drivers/gpu/drm/nouveau/dispnv50/lut.h
drivers/gpu/drm/nouveau/dispnv50/wimm.c
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/dispnv50/wndw.h
drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/include/nvif/cl0080.h
drivers/gpu/drm/nouveau/include/nvif/cla06f.h
drivers/gpu/drm/nouveau/include/nvif/class.h
drivers/gpu/drm/nouveau/include/nvif/clc36f.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/include/nvkm/core/device.h
drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_chan.h
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_debugfs.c
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nouveau_vmm.h
drivers/gpu/drm/nouveau/nvif/disp.c
drivers/gpu/drm/nouveau/nvkm/core/subdev.c
drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgv100.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/disp/wndwgv100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
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/gk110.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/fifo/user.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/falcon/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp102.c
drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-innolux-p079zca.c
drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-samsung-s6d16d0.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/panel/panel-truly-nt35597.c [new file with mode: 0644]
drivers/gpu/drm/pl111/pl111_vexpress.c
drivers/gpu/drm/qxl/qxl_cmd.c
drivers/gpu/drm/qxl/qxl_debugfs.c
drivers/gpu/drm/qxl/qxl_dev.h
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_draw.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_dumb.c
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_image.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_kms.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_object.h
drivers/gpu/drm/qxl/qxl_prime.c
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_legacy_tv.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_vm.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_drv.h
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/rockchip/Kconfig
drivers/gpu/drm/rockchip/Makefile
drivers/gpu/drm/rockchip/cdn-dp-reg.c
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c [new file with mode: 0644]
drivers/gpu/drm/rockchip/dw-mipi-dsi.c [deleted file]
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_psr.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
drivers/gpu/drm/scheduler/sched_entity.c
drivers/gpu/drm/scheduler/sched_main.c
drivers/gpu/drm/selftests/Makefile
drivers/gpu/drm/selftests/drm_helper_selftests.h [deleted file]
drivers/gpu/drm/selftests/drm_modeset_selftests.h [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm-helper.c [deleted file]
drivers/gpu/drm/selftests/test-drm_damage_helper.c [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_format.c [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_framebuffer.c [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_modeset_common.c [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_modeset_common.h [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_plane_helper.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_drv.c
drivers/gpu/drm/sti/sti_crtc.c
drivers/gpu/drm/sti/sti_cursor.c
drivers/gpu/drm/sti/sti_drv.c
drivers/gpu/drm/sti/sti_gdp.c
drivers/gpu/drm/sti/sti_hqvdp.c
drivers/gpu/drm/stm/drv.c
drivers/gpu/drm/stm/ltdc.c
drivers/gpu/drm/stm/ltdc.h
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_backend.h
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_framebuffer.c
drivers/gpu/drm/sun4i/sun4i_framebuffer.h
drivers/gpu/drm/sun4i/sun4i_frontend.c
drivers/gpu/drm/sun4i/sun4i_frontend.h
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
drivers/gpu/drm/sun4i/sun4i_layer.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/sun4i/sun8i_csc.c
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
drivers/gpu/drm/sun4i/sun8i_mixer.c
drivers/gpu/drm/sun4i/sun8i_mixer.h
drivers/gpu/drm/sun4i/sun8i_tcon_top.c
drivers/gpu/drm/sun4i/sun8i_ui_layer.c
drivers/gpu/drm/sun4i/sun8i_ui_layer.h
drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
drivers/gpu/drm/sun4i/sun8i_vi_layer.c
drivers/gpu/drm/sun4i/sun8i_vi_layer.h
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/falcon.c
drivers/gpu/drm/tegra/hub.c
drivers/gpu/drm/tegra/hub.h
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/tegra/sor.h
drivers/gpu/drm/tegra/vic.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/tinydrm/Kconfig
drivers/gpu/drm/tinydrm/Makefile
drivers/gpu/drm/tinydrm/core/tinydrm-core.c
drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
drivers/gpu/drm/tinydrm/hx8357d.c [new file with mode: 0644]
drivers/gpu/drm/tinydrm/ili9225.c
drivers/gpu/drm/tinydrm/ili9341.c
drivers/gpu/drm/tinydrm/mi0283qt.c
drivers/gpu/drm/tinydrm/mipi-dbi.c
drivers/gpu/drm/tinydrm/repaper.c
drivers/gpu/drm/tinydrm/st7586.c
drivers/gpu/drm/tinydrm/st7735r.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_execbuf_util.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/gpu/drm/tve200/tve200_drv.c
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/v3d/v3d_bo.c
drivers/gpu/drm/v3d/v3d_debugfs.c
drivers/gpu/drm/v3d/v3d_drv.c
drivers/gpu/drm/v3d/v3d_drv.h
drivers/gpu/drm/v3d/v3d_fence.c
drivers/gpu/drm/v3d/v3d_gem.c
drivers/gpu/drm/v3d/v3d_irq.c
drivers/gpu/drm/v3d/v3d_regs.h
drivers/gpu/drm/v3d/v3d_sched.c
drivers/gpu/drm/v3d/v3d_trace.h
drivers/gpu/drm/vc4/vc4_drv.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_gem.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/vc4/vc4_regs.h
drivers/gpu/drm/vgem/vgem_drv.c
drivers/gpu/drm/vgem/vgem_fence.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/virtio/virtgpu_drm_bus.c
drivers/gpu/drm/virtio/virtgpu_drv.c
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_fb.c
drivers/gpu/drm/virtio/virtgpu_fence.c
drivers/gpu/drm/virtio/virtgpu_gem.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/virtio/virtgpu_kms.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/gpu/drm/virtio/virtgpu_plane.c
drivers/gpu/drm/virtio/virtgpu_ttm.c
drivers/gpu/drm/virtio/virtgpu_vq.c
drivers/gpu/drm/vkms/vkms_drv.c
drivers/gpu/drm/vkms/vkms_drv.h
drivers/gpu/drm/vkms/vkms_gem.c
drivers/gpu/drm/vkms/vkms_plane.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
drivers/gpu/drm/zte/zx_drm_drv.c
drivers/gpu/drm/zte/zx_plane.c
drivers/gpu/host1x/Makefile
drivers/gpu/host1x/dev.c
drivers/gpu/host1x/hw/channel_hw.c
drivers/gpu/host1x/hw/debug_hw_1x06.c
drivers/gpu/host1x/hw/host1x07.c [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x07.h [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x07_hardware.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x06_uclass.h
drivers/gpu/host1x/hw/hw_host1x07_hypervisor.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x07_uclass.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x07_vm.h [new file with mode: 0644]
drivers/gpu/host1x/hw/syncpt_hw.c
drivers/gpu/ipu-v3/ipu-cpmem.c
drivers/gpu/ipu-v3/ipu-ic.c
drivers/gpu/ipu-v3/ipu-image-convert.c
drivers/gpu/vga/vgaarb.c
drivers/hv/Kconfig
drivers/hv/vmbus_drv.c
drivers/i2c/busses/i2c-nvidia-gpu.c
drivers/i2c/i2c-core-acpi.c
drivers/i3c/Kconfig [new file with mode: 0644]
drivers/i3c/Makefile [new file with mode: 0644]
drivers/i3c/device.c [new file with mode: 0644]
drivers/i3c/internals.h [new file with mode: 0644]
drivers/i3c/master.c [new file with mode: 0644]
drivers/i3c/master/Kconfig [new file with mode: 0644]
drivers/i3c/master/Makefile [new file with mode: 0644]
drivers/i3c/master/dw-i3c-master.c [new file with mode: 0644]
drivers/i3c/master/i3c-master-cdns.c [new file with mode: 0644]
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/leds/trigger/Kconfig
drivers/leds/trigger/Makefile
drivers/leds/trigger/ledtrig-audio.c [new file with mode: 0644]
drivers/media/cec/cec-adap.c
drivers/media/cec/cec-core.c
drivers/media/cec/cec-pin.c
drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-frontends/af9033.c
drivers/media/dvb-frontends/dib0090.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/lgdt3306a.c
drivers/media/dvb-frontends/mxl5xx.c
drivers/media/dvb-frontends/tda18271c2dd.c
drivers/media/firewire/firedtv-avc.c
drivers/media/firewire/firedtv.h
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7511.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/imx214.c [new file with mode: 0644]
drivers/media/i2c/imx258.c
drivers/media/i2c/imx274.c
drivers/media/i2c/imx319.c
drivers/media/i2c/imx355.c
drivers/media/i2c/mt9m111.c
drivers/media/i2c/ov13858.c
drivers/media/i2c/ov2640.c
drivers/media/i2c/ov2680.c
drivers/media/i2c/ov5640.c
drivers/media/i2c/ov5645.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/ov772x.c
drivers/media/i2c/ov7740.c
drivers/media/i2c/tc358743.c
drivers/media/i2c/tda1997x.c
drivers/media/i2c/tda7432.c
drivers/media/i2c/ths8200.c
drivers/media/i2c/tvp5150.c
drivers/media/i2c/video-i2c.c
drivers/media/pci/b2c2/flexcop-dma.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/cobalt/cobalt-v4l2.c
drivers/media/pci/cx18/cx18-ioctl.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-i2c.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885.h
drivers/media/pci/ddbridge/ddbridge.h
drivers/media/pci/intel/ipu3/ipu3-cio2.h
drivers/media/pci/ivtv/ivtv-ioctl.c
drivers/media/pci/mantis/mantis_cards.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-input.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/aspeed-video.c [new file with mode: 0644]
drivers/media/platform/coda/coda-bit.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/coda/coda.h
drivers/media/platform/coda/coda_regs.h
drivers/media/platform/coda/trace.h
drivers/media/platform/davinci/vpbe.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-core.h
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/fimc-core.h
drivers/media/platform/exynos4-is/fimc-is-errno.c
drivers/media/platform/exynos4-is/fimc-is-errno.h
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/imx-pxp.c
drivers/media/platform/marvell-ccic/cafe-driver.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
drivers/media/platform/mtk-vcodec/venc_drv_if.h
drivers/media/platform/qcom/camss/camss-vfe.c
drivers/media/platform/qcom/camss/camss.c
drivers/media/platform/qcom/camss/camss.h
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/firmware.c
drivers/media/platform/qcom/venus/firmware.h
drivers/media/platform/qcom/venus/hfi_cmds.c
drivers/media/platform/qcom/venus/hfi_venus.c
drivers/media/platform/qcom/venus/hfi_venus_io.h
drivers/media/platform/qcom/venus/vdec.c
drivers/media/platform/qcom/venus/venc.c
drivers/media/platform/qcom/venus/venc_ctrls.c
drivers/media/platform/rcar-vin/rcar-core.c
drivers/media/platform/rcar-vin/rcar-csi2.c
drivers/media/platform/rcar-vin/rcar-v4l2.c
drivers/media/platform/rockchip/rga/rga.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/seco-cec/Makefile [new file with mode: 0644]
drivers/media/platform/seco-cec/seco-cec.c [new file with mode: 0644]
drivers/media/platform/seco-cec/seco-cec.h [new file with mode: 0644]
drivers/media/platform/sh_vou.c
drivers/media/platform/sti/bdisp/bdisp-hw.c
drivers/media/platform/sunxi/sun6i-csi/Kconfig [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/Makefile [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/cal.c
drivers/media/platform/vicodec/codec-fwht.c
drivers/media/platform/vicodec/codec-fwht.h
drivers/media/platform/vicodec/codec-v4l2-fwht.c
drivers/media/platform/vicodec/codec-v4l2-fwht.h
drivers/media/platform/vicodec/vicodec-core.c
drivers/media/platform/vim2m.c
drivers/media/platform/vimc/vimc-common.c
drivers/media/platform/vimc/vimc-sensor.c
drivers/media/platform/vivid/vivid-core.c
drivers/media/platform/vivid/vivid-core.h
drivers/media/platform/vivid/vivid-ctrls.c
drivers/media/platform/vivid/vivid-kthread-cap.c
drivers/media/platform/vivid/vivid-kthread-out.c
drivers/media/platform/vivid/vivid-vbi-cap.c
drivers/media/platform/vivid/vivid-vid-cap.c
drivers/media/platform/vivid/vivid-vid-cap.h
drivers/media/platform/vivid/vivid-vid-common.c
drivers/media/platform/vivid/vivid-vid-out.c
drivers/media/platform/vivid/vivid-vid-out.h
drivers/media/platform/xilinx/Kconfig
drivers/media/platform/xilinx/Makefile
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-dma.h
drivers/media/platform/xilinx/xilinx-tpg.c
drivers/media/platform/xilinx/xilinx-vip.c
drivers/media/platform/xilinx/xilinx-vip.h
drivers/media/platform/xilinx/xilinx-vipp.c
drivers/media/platform/xilinx/xilinx-vipp.h
drivers/media/platform/xilinx/xilinx-vtc.c
drivers/media/platform/xilinx/xilinx-vtc.h
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/imon.c
drivers/media/rc/imon_raw.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-xbox-dvd.c [new file with mode: 0644]
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/rc/xbox_remote.c [new file with mode: 0644]
drivers/media/spi/cxd2880-spi.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/cpia2/cpia2_v4l.c
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb-v2/gl861.c
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.h
drivers/media/usb/dvb-usb-v2/usb_urb.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/friio-fe.c [deleted file]
drivers/media/usb/dvb-usb/friio.c [deleted file]
drivers/media/usb/dvb-usb/friio.h [deleted file]
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/pulse8-cec/pulse8-cec.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/usb/siano/smsusb.c
drivers/media/usb/stkwebcam/stk-webcam.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_isight.c
drivers/media/usb/uvc/uvc_queue.c
drivers/media/usb/uvc/uvc_status.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/v4l2-async.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-device.c
drivers/media/v4l2-core/v4l2-fwnode.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/mfd/axp20x.c
drivers/mfd/wm8994-core.c
drivers/mmc/core/mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/docg3.h
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/gpio-addr-flash.c [deleted file]
drivers/mtd/maps/latch-addr-flash.c [deleted file]
drivers/mtd/maps/physmap-core.c [new file with mode: 0644]
drivers/mtd/maps/physmap-gemini.c [new file with mode: 0644]
drivers/mtd/maps/physmap-gemini.h [new file with mode: 0644]
drivers/mtd/maps/physmap-versatile.c [new file with mode: 0644]
drivers/mtd/maps/physmap-versatile.h [new file with mode: 0644]
drivers/mtd/maps/physmap.c [deleted file]
drivers/mtd/maps/physmap_of_core.c [deleted file]
drivers/mtd/maps/physmap_of_gemini.c [deleted file]
drivers/mtd/maps/physmap_of_gemini.h [deleted file]
drivers/mtd/maps/physmap_of_versatile.c [deleted file]
drivers/mtd/maps/physmap_of_versatile.h [deleted file]
drivers/mtd/mtdblock.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/mtdswap.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/ams-delta.c
drivers/mtd/nand/raw/atmel/nand-controller.c
drivers/mtd/nand/raw/au1550nd.c
drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/davinci_nand.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/denali.h
drivers/mtd/nand/raw/diskonchip.c
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsl_upm.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/hisi504_nand.c
drivers/mtd/nand/raw/internals.h
drivers/mtd/nand/raw/jz4740_nand.c
drivers/mtd/nand/raw/jz4780_bch.c
drivers/mtd/nand/raw/jz4780_nand.c
drivers/mtd/nand/raw/lpc32xx_mlc.c
drivers/mtd/nand/raw/lpc32xx_slc.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/mpc5121_nfc.c
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/mxc_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/nand_hynix.c
drivers/mtd/nand/raw/nand_jedec.c
drivers/mtd/nand/raw/nand_legacy.c
drivers/mtd/nand/raw/nand_macronix.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/raw/plat_nand.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/raw/r852.c
drivers/mtd/nand/raw/s3c2410.c
drivers/mtd/nand/raw/sh_flctl.c
drivers/mtd/nand/raw/sm_common.c
drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/tango_nand.c
drivers/mtd/nand/raw/tegra_nand.c
drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/raw/xway_nand.c
drivers/mtd/nand/spi/Makefile
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/gigadevice.c [new file with mode: 0644]
drivers/mtd/nand/spi/toshiba.c [new file with mode: 0644]
drivers/mtd/nand/spi/winbond.c
drivers/mtd/nftlmount.c
drivers/mtd/parsers/Kconfig
drivers/mtd/parsers/Makefile
drivers/mtd/parsers/redboot.c [new file with mode: 0644]
drivers/mtd/redboot.c [deleted file]
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/Makefile
drivers/mtd/spi-nor/atmel-quadspi.c [deleted file]
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/kapi.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/cadence/macb_ptp.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
drivers/net/ethernet/hisilicon/hns/hns_enet.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
drivers/net/ethernet/intel/i40e/i40e_xsk.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
drivers/net/ethernet/mellanox/mlxsw/trap.h
drivers/net/ethernet/microchip/lan743x_main.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/neterion/vxge/vxge-config.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/nuvoton/w90p910_ether.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_ll2.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ieee802154/ca8210.c
drivers/net/ieee802154/mac802154_hwsim.c
drivers/net/phy/phy_device.c
drivers/net/usb/hso.c
drivers/net/usb/lan78xx.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/thermal.c
drivers/net/wireless/ath/ath10k/wmi-tlv.h
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/marvell/mwifiex/11n.c
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
drivers/net/wireless/marvell/mwifiex/uap_txrx.c
drivers/net/wireless/mediatek/mt76/tx.c
drivers/net/wireless/realtek/rtlwifi/base.c
drivers/net/xen-netfront.c
drivers/opp/core.c
drivers/opp/of.c
drivers/opp/opp.h
drivers/pci/Makefile
drivers/pci/pcie/aer.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/huawei-wmi.c [new file with mode: 0644]
drivers/platform/x86/i2c-multi-instantiate.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_atomisp2_pm.c
drivers/platform/x86/intel_cht_int33fe.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_pmc_core.c
drivers/platform/x86/intel_pmc_core.h
drivers/platform/x86/intel_telemetry_debugfs.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/power/avs/smartreflex.c
drivers/pwm/Kconfig
drivers/pwm/pwm-bcm2835.c
drivers/pwm/pwm-clps711x.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-lpc18xx-sct.c
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/act8945a-regulator.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/as3711-regulator.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/bd718x7-regulator.c
drivers/regulator/bd9571mwv-regulator.c
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9210-regulator.c
drivers/regulator/da9211-regulator.c
drivers/regulator/dbx500-prcmu.c
drivers/regulator/fixed.c
drivers/regulator/internal.h
drivers/regulator/lm363x-regulator.c
drivers/regulator/lochnagar-regulator.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686-regulator.c
drivers/regulator/max8952.c
drivers/regulator/max8973-regulator.c
drivers/regulator/max8997-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/mcp16502.c [new file with mode: 0644]
drivers/regulator/of_regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/stpmic1_regulator.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8994-regulator.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/sd.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel-quadspi.c [new file with mode: 0644]
drivers/spi/spi-at91-usart.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-geni-qcom.c
drivers/spi/spi-gpio.c
drivers/spi/spi-imx.c
drivers/spi/spi-mem.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-mxic.c [new file with mode: 0644]
drivers/spi/spi-npcm-pspi.c [new file with mode: 0644]
drivers/spi/spi-pl022.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.h
drivers/spi/spi-qcom-qspi.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-rspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/bcm2048/radio-bcm2048.c
drivers/staging/media/imx/imx-media-of.c
drivers/staging/media/ipu3/Kconfig [new file with mode: 0644]
drivers/staging/media/ipu3/Makefile [new file with mode: 0644]
drivers/staging/media/ipu3/TODO [new file with mode: 0644]
drivers/staging/media/ipu3/include/intel-ipu3.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-abi.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-fw.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-fw.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-params.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-params.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-pool.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css-pool.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-css.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-dmamap.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-dmamap.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-mmu.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-mmu.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-tables.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-tables.h [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3-v4l2.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3.c [new file with mode: 0644]
drivers/staging/media/ipu3/ipu3.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/Kconfig [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/Makefile [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/TODO [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c [new file with mode: 0644]
drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h [new file with mode: 0644]
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus.h
drivers/staging/media/sunxi/cedrus/cedrus_dec.c
drivers/staging/media/sunxi/cedrus/cedrus_hw.c
drivers/staging/media/sunxi/cedrus/cedrus_video.c
drivers/staging/media/tegra-vde/tegra-vde.c
drivers/staging/media/tegra-vde/trace.h [new file with mode: 0644]
drivers/staging/mt29f_spinand/Kconfig [deleted file]
drivers/staging/mt29f_spinand/Makefile [deleted file]
drivers/staging/mt29f_spinand/TODO [deleted file]
drivers/staging/mt29f_spinand/mt29f_spinand.c [deleted file]
drivers/staging/mt29f_spinand/mt29f_spinand.h [deleted file]
drivers/staging/vboxvideo/vbox_drv.c
drivers/staging/vboxvideo/vbox_drv.h
drivers/staging/vboxvideo/vbox_ttm.c
drivers/target/iscsi/cxgbit/cxgbit_cm.c
drivers/target/iscsi/cxgbit/cxgbit_main.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/sunsu.c
drivers/uio/uio_hv_generic.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci.h
drivers/usb/serial/option.c
drivers/usb/typec/tps6598x.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/video/hdmi.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2proto.h
fs/iomap.c
fs/jffs2/super.c
fs/namei.c
fs/proc/proc_sysctl.c
fs/sysfs/file.c
fs/ubifs/Kconfig
fs/ubifs/lpt.c
fs/ubifs/replay.c
fs/ubifs/sb.c
include/acpi/acoutput.h
include/acpi/acpi_drivers.h
include/acpi/acpixf.h
include/acpi/actbl.h
include/acpi/actbl3.h
include/acpi/actypes.h
include/acpi/platform/aclinux.h
include/asm-generic/bug.h
include/drm/bridge/dw_hdmi.h
include/drm/bridge/dw_mipi_dsi.h
include/drm/drmP.h
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_atomic_state_helper.h [new file with mode: 0644]
include/drm/drm_connector.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_damage_helper.h [new file with mode: 0644]
include/drm/drm_dp_helper.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_drv.h
include/drm/drm_dsc.h [new file with mode: 0644]
include/drm/drm_fb_cma_helper.h
include/drm/drm_file.h
include/drm/drm_fourcc.h
include/drm/drm_framebuffer.h
include/drm/drm_gem.h
include/drm/drm_gem_cma_helper.h
include/drm/drm_global.h [deleted file]
include/drm/drm_hdcp.h
include/drm/drm_mipi_dsi.h
include/drm/drm_mode_config.h
include/drm/drm_modeset_lock.h
include/drm/drm_plane.h
include/drm/drm_plane_helper.h
include/drm/drm_prime.h
include/drm/drm_property.h
include/drm/drm_syncobj.h
include/drm/drm_vblank.h
include/drm/gpu_scheduler.h
include/drm/i915_pciids.h
include/drm/tinydrm/tinydrm.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_execbuf_util.h
include/drm/ttm/ttm_memory.h
include/dt-bindings/media/xilinx-vip.h
include/dt-bindings/regulator/active-semi,8945a-regulator.h [new file with mode: 0644]
include/dt-bindings/sound/qcom,q6afe.h
include/linux/acpi.h
include/linux/adxl.h
include/linux/compiler.h
include/linux/compiler_types.h
include/linux/cpuidle.h
include/linux/dell-led.h [deleted file]
include/linux/devfreq.h
include/linux/dma-fence.h
include/linux/dma-mapping.h
include/linux/edac.h
include/linux/filter.h
include/linux/gpio/consumer.h
include/linux/hdmi.h
include/linux/i3c/ccc.h [new file with mode: 0644]
include/linux/i3c/device.h [new file with mode: 0644]
include/linux/i3c/master.h [new file with mode: 0644]
include/linux/leds.h
include/linux/mfd/axp20x.h
include/linux/mfd/wm8994/pdata.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mod_devicetable.h
include/linux/mtd/cfi.h
include/linux/mtd/mtd.h
include/linux/mtd/rawnand.h
include/linux/mtd/sh_flctl.h
include/linux/mtd/spi-nor.h
include/linux/mtd/spinand.h
include/linux/netfilter/nfnetlink.h
include/linux/pci.h
include/linux/platform_data/davinci_asp.h
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pm_opp.h
include/linux/pm_runtime.h
include/linux/power/smartreflex.h
include/linux/pwm.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/regulator/pfuze100.h
include/linux/reservation.h
include/linux/spi/pxa2xx_spi.h
include/linux/spi/spi-mem.h
include/linux/spi/spi.h
include/linux/swap.h
include/linux/sysfs.h
include/linux/t10-pi.h
include/linux/thinkpad_acpi.h [deleted file]
include/media/cec.h
include/media/davinci/vpbe.h
include/media/rc-map.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h
include/media/v4l2-subdev.h
include/net/ip_tunnels.h
include/net/sock.h
include/net/tls.h
include/net/xfrm.h
include/sound/compress_driver.h
include/sound/hda_codec.h
include/sound/hda_component.h
include/sound/hdaudio.h
include/sound/simple_card_utils.h
include/sound/soc-acpi-intel-match.h
include/sound/soc-acpi.h
include/sound/soc.h
include/uapi/asm-generic/Kbuild.asm
include/uapi/drm/amdgpu_drm.h
include/uapi/drm/drm_fourcc.h
include/uapi/drm/drm_mode.h
include/uapi/drm/i915_drm.h
include/uapi/drm/msm_drm.h
include/uapi/drm/v3d_drm.h
include/uapi/drm/virtgpu_drm.h
include/uapi/linux/blkzoned.h
include/uapi/linux/if_tunnel.h
include/uapi/linux/in.h
include/uapi/linux/kfd_ioctl.h
include/uapi/linux/net_tstamp.h
include/uapi/linux/netlink.h
include/uapi/linux/v4l2-common.h
include/uapi/linux/videodev2.h
include/uapi/linux/virtio_gpu.h
include/uapi/sound/firewire.h
include/video/imx-ipu-v3.h
kernel/bpf/core.c
kernel/bpf/verifier.c
kernel/dma/direct.c
kernel/fork.c
kernel/futex.c
kernel/power/main.c
kernel/power/qos.c
kernel/sched/cpufreq.c
kernel/sched/cpufreq_schedutil.c
kernel/time/posix-timers.c
mm/huge_memory.c
mm/page_alloc.c
mm/shmem.c
mm/vmscan.c
net/can/raw.c
net/core/flow_dissector.c
net/core/gro_cells.c
net/core/neighbour.c
net/core/skmsg.c
net/core/sysctl_net_core.c
net/ipv4/devinet.c
net/ipv4/inet_diag.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/raw.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_udp_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ip6mr.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/status.c
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conncount.c
net/netfilter/nf_conntrack_seqadj.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/rds/message.c
net/rds/rdma.c
net/rds/rds.h
net/rds/send.c
net/sched/cls_flower.c
net/sctp/ipv6.c
net/smc/af_smc.c
net/smc/smc.h
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
net/tipc/socket.c
net/tipc/udp_media.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/vmw_vsock/af_vsock.c
net/vmw_vsock/vmci_transport.c
net/wireless/nl80211.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
samples/v4l/v4l2-pci-skeleton.c
scripts/Kbuild.include
scripts/coccinelle/api/drm-get-put.cocci [deleted file]
scripts/mod/Makefile
security/integrity/ima/ima_policy.c
security/keys/keyctl_pkey.c
security/keys/trusted.c
sound/aoa/fabrics/layout.c
sound/aoa/soundbus/core.c
sound/aoa/soundbus/i2sbus/core.c
sound/aoa/soundbus/sysfs.c
sound/core/compress_offload.c
sound/core/control.c
sound/core/pcm.c
sound/firewire/Kconfig
sound/firewire/amdtp-stream-trace.h
sound/firewire/amdtp-stream.c
sound/firewire/bebob/bebob.c
sound/firewire/fireface/Makefile
sound/firewire/fireface/ff-pcm.c
sound/firewire/fireface/ff-proc.c
sound/firewire/fireface/ff-protocol-ff400.c
sound/firewire/fireface/ff-protocol-ff800.c [new file with mode: 0644]
sound/firewire/fireface/ff-stream.c
sound/firewire/fireface/ff-transaction.c
sound/firewire/fireface/ff.c
sound/firewire/fireface/ff.h
sound/firewire/oxfw/oxfw.c
sound/firewire/tascam/amdtp-tascam.c
sound/firewire/tascam/tascam-hwdep.c
sound/firewire/tascam/tascam.h
sound/hda/hdac_bus.c
sound/hda/hdac_component.c
sound/hda/hdac_device.c
sound/pci/asihpi/asihpi.c
sound/pci/emu10k1/emufx.c
sound/pci/hda/Kconfig
sound/pci/hda/dell_wmi_helper.c [deleted file]
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/hda_tegra.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/thinkpad_helper.c
sound/pci/rme9652/hdsp.c
sound/ppc/pmac.c
sound/ppc/tumbler.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/amd/Kconfig
sound/soc/amd/Makefile
sound/soc/amd/acp-da7219-max98357a.c
sound/soc/amd/acp-pcm-dma.c
sound/soc/amd/acp.h
sound/soc/amd/raven/Makefile [new file with mode: 0644]
sound/soc/amd/raven/acp3x-pcm-dma.c [new file with mode: 0644]
sound/soc/amd/raven/acp3x.h [new file with mode: 0644]
sound/soc/amd/raven/chip_offset_byte.h [new file with mode: 0644]
sound/soc/amd/raven/pci-acp3x.c [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4118.c [new file with mode: 0644]
sound/soc/codecs/ak4458.c
sound/soc/codecs/ak5558.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/dmic.c
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/max98373.c
sound/soc/codecs/max9867.c
sound/soc/codecs/max9867.h
sound/soc/codecs/nau8540.c
sound/soc/codecs/nau8822.c
sound/soc/codecs/nau8822.h
sound/soc/codecs/nau8825.c
sound/soc/codecs/pcm3060.c
sound/soc/codecs/pcm3060.h
sound/soc/codecs/pcm3168a.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/pcm512x.h
sound/soc/codecs/rt5660.c
sound/soc/codecs/rt5663.c
sound/soc/codecs/simple-amplifier.c
sound/soc/codecs/tas6424.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/davinci/Kconfig [deleted file]
sound/soc/davinci/Makefile [deleted file]
sound/soc/davinci/davinci-evm.c [deleted file]
sound/soc/davinci/davinci-i2s.c [deleted file]
sound/soc/davinci/davinci-i2s.h [deleted file]
sound/soc/davinci/davinci-mcasp.c [deleted file]
sound/soc/davinci/davinci-mcasp.h [deleted file]
sound/soc/davinci/davinci-vcif.c [deleted file]
sound/soc/davinci/edma-pcm.c [deleted file]
sound/soc/davinci/edma-pcm.h [deleted file]
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_ssi_dbg.c
sound/soc/generic/Kconfig
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-scu-card.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/generic/simple-scu-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_loader.c
sound/soc/intel/atom/sst/sst_pvt.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/glk_rt5682_max98357a.c
sound/soc/intel/boards/kbl_da7219_max98927.c
sound/soc/intel/boards/kbl_rt5660.c [new file with mode: 0644]
sound/soc/intel/boards/kbl_rt5663_max98927.c
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
sound/soc/intel/boards/skl_hda_dsp_generic.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/soc-acpi-intel-bxt-match.c
sound/soc/intel/common/soc-acpi-intel-icl-match.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-kbl-match.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
sound/soc/meson/Kconfig
sound/soc/meson/Makefile
sound/soc/meson/axg-fifo.h
sound/soc/meson/axg-spdifin.c [new file with mode: 0644]
sound/soc/meson/axg-toddr.c
sound/soc/omap/Kconfig [deleted file]
sound/soc/omap/Makefile [deleted file]
sound/soc/omap/am3517evm.c [deleted file]
sound/soc/omap/ams-delta.c [deleted file]
sound/soc/omap/mcbsp.c [deleted file]
sound/soc/omap/mcbsp.h [deleted file]
sound/soc/omap/n810.c [deleted file]
sound/soc/omap/omap-abe-twl6040.c [deleted file]
sound/soc/omap/omap-dmic.c [deleted file]
sound/soc/omap/omap-dmic.h [deleted file]
sound/soc/omap/omap-hdmi-audio.c [deleted file]
sound/soc/omap/omap-mcbsp.c [deleted file]
sound/soc/omap/omap-mcbsp.h [deleted file]
sound/soc/omap/omap-mcpdm.c [deleted file]
sound/soc/omap/omap-mcpdm.h [deleted file]
sound/soc/omap/omap-twl4030.c [deleted file]
sound/soc/omap/omap3pandora.c [deleted file]
sound/soc/omap/osk5912.c [deleted file]
sound/soc/omap/rx51.c [deleted file]
sound/soc/omap/sdma-pcm.c [deleted file]
sound/soc/omap/sdma-pcm.h [deleted file]
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/raumfeld.c [deleted file]
sound/soc/qcom/Kconfig
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/qdsp6/q6afe-dai.c
sound/soc/qcom/qdsp6/q6afe.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6asm.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/qcom/sdm845.c
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/cmd.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c
sound/soc/soc-core.c
sound/soc/stm/stm32_sai.c
sound/soc/stm/stm32_sai_sub.c
sound/soc/sunxi/sun50i-codec-analog.c
sound/soc/ti/Kconfig [new file with mode: 0644]
sound/soc/ti/Makefile [new file with mode: 0644]
sound/soc/ti/ams-delta.c [new file with mode: 0644]
sound/soc/ti/davinci-evm.c [new file with mode: 0644]
sound/soc/ti/davinci-i2s.c [new file with mode: 0644]
sound/soc/ti/davinci-i2s.h [new file with mode: 0644]
sound/soc/ti/davinci-mcasp.c [new file with mode: 0644]
sound/soc/ti/davinci-mcasp.h [new file with mode: 0644]
sound/soc/ti/davinci-vcif.c [new file with mode: 0644]
sound/soc/ti/edma-pcm.c [new file with mode: 0644]
sound/soc/ti/edma-pcm.h [new file with mode: 0644]
sound/soc/ti/n810.c [new file with mode: 0644]
sound/soc/ti/omap-abe-twl6040.c [new file with mode: 0644]
sound/soc/ti/omap-dmic.c [new file with mode: 0644]
sound/soc/ti/omap-dmic.h [new file with mode: 0644]
sound/soc/ti/omap-hdmi.c [new file with mode: 0644]
sound/soc/ti/omap-mcbsp-priv.h [new file with mode: 0644]
sound/soc/ti/omap-mcbsp-st.c [new file with mode: 0644]
sound/soc/ti/omap-mcbsp.c [new file with mode: 0644]
sound/soc/ti/omap-mcbsp.h [new file with mode: 0644]
sound/soc/ti/omap-mcpdm.c [new file with mode: 0644]
sound/soc/ti/omap-mcpdm.h [new file with mode: 0644]
sound/soc/ti/omap-twl4030.c [new file with mode: 0644]
sound/soc/ti/omap3pandora.c [new file with mode: 0644]
sound/soc/ti/osk5912.c [new file with mode: 0644]
sound/soc/ti/rx51.c [new file with mode: 0644]
sound/soc/ti/sdma-pcm.c [new file with mode: 0644]
sound/soc/ti/sdma-pcm.h [new file with mode: 0644]
sound/soc/xilinx/Kconfig [new file with mode: 0644]
sound/soc/xilinx/Makefile [new file with mode: 0644]
sound/soc/xilinx/xlnx_i2s.c [new file with mode: 0644]
sound/synth/emux/emux_hwdep.c
sound/usb/quirks.c
sound/x86/intel_hdmi_audio.c
tools/include/uapi/linux/netlink.h
tools/power/acpi/tools/acpidump/apmain.c
tools/power/cpupower/Makefile
tools/power/cpupower/cpupower-completion.sh [new file with mode: 0644]
tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
tools/power/x86/turbostat/turbostat.c
tools/testing/selftests/bpf/bpf_flow.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/test_vxlan_fdb_changelink.sh [new file with mode: 0755]
tools/virtio/linux/kernel.h
virt/kvm/coalesced_mmio.c

index 28fecafa65069c1af077453a4159a6a290949982..b4b0b0b768dd0df953123a8c76ee1b4a02a74f4c 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -36,9 +36,10 @@ Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
-Boris Brezillon <boris.brezillon@bootlin.com> <boris.brezillon@free-electrons.com>
-Boris Brezillon <boris.brezillon@bootlin.com> <b.brezillon.dev@gmail.com>
-Boris Brezillon <boris.brezillon@bootlin.com> <b.brezillon@overkiz.com>
+Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
+Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
+Boris Brezillon <bbrezillon@kernel.org> <b.brezillon.dev@gmail.com>
+Boris Brezillon <bbrezillon@kernel.org> <b.brezillon@overkiz.com>
 Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
 Christoph Hellwig <hch@lst.de>
index d9d117d457e16b239bf5c764a3aebe1732ba9c82..9b642669cb160c6e1535022c31628818faa37fdb 100644 (file)
@@ -12,7 +12,6 @@ Description:  This file shows ASIC health status. The possible values are:
 What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
                                                        cpld1_version
                                                        cpld2_version
-
 Date:          June 2018
 KernelVersion: 4.19
 Contact:       Vadim Pasternak <vadimpmellanox.com>
@@ -21,6 +20,28 @@ Description: These files show with which CPLD versions have been burned
 
                The files are read only.
 
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+                                                       cpld3_version
+
+Date:          November 2018
+KernelVersion: 4.21
+Contact:       Vadim Pasternak <vadimpmellanox.com>
+Description:   These files show with which CPLD versions have been burned
+               on LED board.
+
+               The files are read only.
+
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+                                                       jtag_enable
+
+Date:          November 2018
+KernelVersion: 4.21
+Contact:       Vadim Pasternak <vadimpmellanox.com>
+Description:   These files enable and disable the access to the JTAG domain.
+               By default access to the JTAG domain is disabled.
+
+               The file is read/write.
+
 What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/select_iio
 Date:          June 2018
 KernelVersion: 4.19
@@ -76,3 +97,21 @@ Description: These files show the system reset cause, as following: power
                reset cause.
 
                The files are read only.
+
+What:          /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+                                               reset_comex_pwr_fail
+                                               reset_from_comex
+                                               reset_system
+                                               reset_voltmon_upgrade_fail
+
+Date:          November 2018
+KernelVersion: 4.21
+Contact:       Vadim Pasternak <vadimpmellanox.com>
+Description:   These files show the system reset cause, as following: ComEx
+               power fail, reset from ComEx, system platform reset, reset
+               due to voltage monitor devices upgrade failure,
+               Value 1 in file means this is reset cause, 0 - otherwise.
+               Only one bit could be 1 at the same time, representing only
+               the last reset cause.
+
+               The files are read only.
diff --git a/Documentation/ABI/testing/sysfs-bus-i3c b/Documentation/ABI/testing/sysfs-bus-i3c
new file mode 100644 (file)
index 0000000..2f332ec
--- /dev/null
@@ -0,0 +1,146 @@
+What:          /sys/bus/i3c/devices/i3c-<bus-id>
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               An I3C bus. This directory will contain one sub-directory per
+               I3C device present on the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/current_master
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Expose the master that owns the bus (<bus-id>-<master-pid>) at
+               the time this file is read. Note that bus ownership can change
+               overtime, so there's no guarantee that when the read() call
+               returns, the value returned is still valid.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/mode
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               I3C bus mode. Can be "pure", "mixed-fast" or "mixed-slow". See
+               the I3C specification for a detailed description of what each
+               of these modes implies.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/i3c_scl_frequency
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               The frequency (expressed in Hz) of the SCL signal when
+               operating in I3C SDR mode.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/i2c_scl_frequency
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               The frequency (expressed in Hz) of the SCL signal when
+               operating in I2C mode.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/dynamic_address
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Dynamic address assigned to the master controller. This
+               address may change if the bus is re-initialized.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/bcr
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               BCR stands for Bus Characteristics Register and express the
+               device capabilities in term of speed, maximum read/write
+               length, etc. See the I3C specification for more details.
+               This entry describes the BCR of the master controller driving
+               the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/dcr
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               DCR stands for Device Characteristics Register and express the
+               device capabilities in term of exposed features. See the I3C
+               specification for more details.
+               This entry describes the DCR of the master controller driving
+               the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/pid
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               PID stands for Provisional ID and is used to uniquely identify
+               a device on a bus. This PID contains information about the
+               vendor, the part and an instance ID so that several devices of
+               the same type can be connected on the same bus.
+               See the I3C specification for more details.
+               This entry describes the PID of the master controller driving
+               the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/hdrcap
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Expose the HDR (High Data Rate) capabilities of a device.
+               Returns a list of supported HDR mode, each element is separated
+               by space. Modes can be "hdr-ddr", "hdr-tsp" and "hdr-tsl".
+               See the I3C specification for more details about these HDR
+               modes.
+               This entry describes the HDRCAP of the master controller
+               driving the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               An I3C device present on I3C bus identified by <bus-id>. Note
+               that all devices are represented including the master driving
+               the bus.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/dynamic_address
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Dynamic address assigned to device <bus-id>-<device-pid>. This
+               address may change if the bus is re-initialized.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/bcr
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               BCR stands for Bus Characteristics Register and express the
+               device capabilities in term of speed, maximum read/write
+               length, etc. See the I3C specification for more details.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/dcr
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               DCR stands for Device Characteristics Register and express the
+               device capabilities in term of exposed features. See the I3C
+               specification for more details.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/pid
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               PID stands for Provisional ID and is used to uniquely identify
+               a device on a bus. This PID contains information about the
+               vendor, the part and an instance ID so that several devices of
+               the same type can be connected on the same bus.
+               See the I3C specification for more details.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/hdrcap
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Expose the HDR (High Data Rate) capabilities of a device.
+               Returns a list of supported HDR mode, each element is separated
+               by space. Modes can be "hdr-ddr", "hdr-tsp" and "hdr-tsl".
+               See the I3C specification for more details about these HDR
+               modes.
+
+What:          /sys/bus/i3c/devices/<bus-id>-<device-pid>
+KernelVersion:  5.0
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               These directories are just symbolic links to
+               /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>.
index 73318225a3681b3473abe87d0fe1bb4c3447e7ed..9605dbd4b5b59ecc251913b1b327e6031cfb875f 100644 (file)
@@ -145,6 +145,8 @@ What:               /sys/devices/system/cpu/cpuX/cpuidle/stateN/name
                /sys/devices/system/cpu/cpuX/cpuidle/stateN/power
                /sys/devices/system/cpu/cpuX/cpuidle/stateN/time
                /sys/devices/system/cpu/cpuX/cpuidle/stateN/usage
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/above
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/below
 Date:          September 2007
 KernelVersion: v2.6.24
 Contact:       Linux power management list <linux-pm@vger.kernel.org>
@@ -166,6 +168,11 @@ Description:
 
                usage: (RO) Number of times this state was entered (a count).
 
+               above: (RO) Number of times this state was entered, but the
+                      observed CPU idle duration was too short for it (a count).
+
+               below: (RO) Number of times this state was entered, but the
+                      observed CPU idle duration was too long for it (a count).
 
 What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/desc
 Date:          February 2008
index aefd358a5ca36b14963442a689fc76abde6a8f31..362a18cd68e1a7298fd2108a4ec35a5f1e1fa87f 100644 (file)
        cpuidle.off=1   [CPU_IDLE]
                        disable the cpuidle sub-system
 
+       cpuidle.governor=
+                       [CPU_IDLE] Name of the cpuidle governor to use.
+
        cpufreq.off=1   [CPU_FREQ]
                        disable the cpufreq sub-system
 
diff --git a/Documentation/admin-guide/pm/cpuidle.rst b/Documentation/admin-guide/pm/cpuidle.rst
new file mode 100644 (file)
index 0000000..106379e
--- /dev/null
@@ -0,0 +1,631 @@
+.. |struct cpuidle_state| replace:: :c:type:`struct cpuidle_state <cpuidle_state>`
+.. |cpufreq| replace:: :doc:`CPU Performance Scaling <cpufreq>`
+
+========================
+CPU Idle Time Management
+========================
+
+::
+
+ Copyright (c) 2018 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+Concepts
+========
+
+Modern processors are generally able to enter states in which the execution of
+a program is suspended and instructions belonging to it are not fetched from
+memory or executed.  Those states are the *idle* states of the processor.
+
+Since part of the processor hardware is not used in idle states, entering them
+generally allows power drawn by the processor to be reduced and, in consequence,
+it is an opportunity to save energy.
+
+CPU idle time management is an energy-efficiency feature concerned about using
+the idle states of processors for this purpose.
+
+Logical CPUs
+------------
+
+CPU idle time management operates on CPUs as seen by the *CPU scheduler* (that
+is the part of the kernel responsible for the distribution of computational
+work in the system).  In its view, CPUs are *logical* units.  That is, they need
+not be separate physical entities and may just be interfaces appearing to
+software as individual single-core processors.  In other words, a CPU is an
+entity which appears to be fetching instructions that belong to one sequence
+(program) from memory and executing them, but it need not work this way
+physically.  Generally, three different cases can be consider here.
+
+First, if the whole processor can only follow one sequence of instructions (one
+program) at a time, it is a CPU.  In that case, if the hardware is asked to
+enter an idle state, that applies to the processor as a whole.
+
+Second, if the processor is multi-core, each core in it is able to follow at
+least one program at a time.  The cores need not be entirely independent of each
+other (for example, they may share caches), but still most of the time they
+work physically in parallel with each other, so if each of them executes only
+one program, those programs run mostly independently of each other at the same
+time.  The entire cores are CPUs in that case and if the hardware is asked to
+enter an idle state, that applies to the core that asked for it in the first
+place, but it also may apply to a larger unit (say a "package" or a "cluster")
+that the core belongs to (in fact, it may apply to an entire hierarchy of larger
+units containing the core).  Namely, if all of the cores in the larger unit
+except for one have been put into idle states at the "core level" and the
+remaining core asks the processor to enter an idle state, that may trigger it
+to put the whole larger unit into an idle state which also will affect the
+other cores in that unit.
+
+Finally, each core in a multi-core processor may be able to follow more than one
+program in the same time frame (that is, each core may be able to fetch
+instructions from multiple locations in memory and execute them in the same time
+frame, but not necessarily entirely in parallel with each other).  In that case
+the cores present themselves to software as "bundles" each consisting of
+multiple individual single-core "processors", referred to as *hardware threads*
+(or hyper-threads specifically on Intel hardware), that each can follow one
+sequence of instructions.  Then, the hardware threads are CPUs from the CPU idle
+time management perspective and if the processor is asked to enter an idle state
+by one of them, the hardware thread (or CPU) that asked for it is stopped, but
+nothing more happens, unless all of the other hardware threads within the same
+core also have asked the processor to enter an idle state.  In that situation,
+the core may be put into an idle state individually or a larger unit containing
+it may be put into an idle state as a whole (if the other cores within the
+larger unit are in idle states already).
+
+Idle CPUs
+---------
+
+Logical CPUs, simply referred to as "CPUs" in what follows, are regarded as
+*idle* by the Linux kernel when there are no tasks to run on them except for the
+special "idle" task.
+
+Tasks are the CPU scheduler's representation of work.  Each task consists of a
+sequence of instructions to execute, or code, data to be manipulated while
+running that code, and some context information that needs to be loaded into the
+processor every time the task's code is run by a CPU.  The CPU scheduler
+distributes work by assigning tasks to run to the CPUs present in the system.
+
+Tasks can be in various states.  In particular, they are *runnable* if there are
+no specific conditions preventing their code from being run by a CPU as long as
+there is a CPU available for that (for example, they are not waiting for any
+events to occur or similar).  When a task becomes runnable, the CPU scheduler
+assigns it to one of the available CPUs to run and if there are no more runnable
+tasks assigned to it, the CPU will load the given task's context and run its
+code (from the instruction following the last one executed so far, possibly by
+another CPU).  [If there are multiple runnable tasks assigned to one CPU
+simultaneously, they will be subject to prioritization and time sharing in order
+to allow them to make some progress over time.]
+
+The special "idle" task becomes runnable if there are no other runnable tasks
+assigned to the given CPU and the CPU is then regarded as idle.  In other words,
+in Linux idle CPUs run the code of the "idle" task called *the idle loop*.  That
+code may cause the processor to be put into one of its idle states, if they are
+supported, in order to save energy, but if the processor does not support any
+idle states, or there is not enough time to spend in an idle state before the
+next wakeup event, or there are strict latency constraints preventing any of the
+available idle states from being used, the CPU will simply execute more or less
+useless instructions in a loop until it is assigned a new task to run.
+
+
+.. _idle-loop:
+
+The Idle Loop
+=============
+
+The idle loop code takes two major steps in every iteration of it.  First, it
+calls into a code module referred to as the *governor* that belongs to the CPU
+idle time management subsystem called ``CPUIdle`` to select an idle state for
+the CPU to ask the hardware to enter.  Second, it invokes another code module
+from the ``CPUIdle`` subsystem, called the *driver*, to actually ask the
+processor hardware to enter the idle state selected by the governor.
+
+The role of the governor is to find an idle state most suitable for the
+conditions at hand.  For this purpose, idle states that the hardware can be
+asked to enter by logical CPUs are represented in an abstract way independent of
+the platform or the processor architecture and organized in a one-dimensional
+(linear) array.  That array has to be prepared and supplied by the ``CPUIdle``
+driver matching the platform the kernel is running on at the initialization
+time.  This allows ``CPUIdle`` governors to be independent of the underlying
+hardware and to work with any platforms that the Linux kernel can run on.
+
+Each idle state present in that array is characterized by two parameters to be
+taken into account by the governor, the *target residency* and the (worst-case)
+*exit latency*.  The target residency is the minimum time the hardware must
+spend in the given state, including the time needed to enter it (which may be
+substantial), in order to save more energy than it would save by entering one of
+the shallower idle states instead.  [The "depth" of an idle state roughly
+corresponds to the power drawn by the processor in that state.]  The exit
+latency, in turn, is the maximum time it will take a CPU asking the processor
+hardware to enter an idle state to start executing the first instruction after a
+wakeup from that state.  Note that in general the exit latency also must cover
+the time needed to enter the given state in case the wakeup occurs when the
+hardware is entering it and it must be entered completely to be exited in an
+ordered manner.
+
+There are two types of information that can influence the governor's decisions.
+First of all, the governor knows the time until the closest timer event.  That
+time is known exactly, because the kernel programs timers and it knows exactly
+when they will trigger, and it is the maximum time the hardware that the given
+CPU depends on can spend in an idle state, including the time necessary to enter
+and exit it.  However, the CPU may be woken up by a non-timer event at any time
+(in particular, before the closest timer triggers) and it generally is not known
+when that may happen.  The governor can only see how much time the CPU actually
+was idle after it has been woken up (that time will be referred to as the *idle
+duration* from now on) and it can use that information somehow along with the
+time until the closest timer to estimate the idle duration in future.  How the
+governor uses that information depends on what algorithm is implemented by it
+and that is the primary reason for having more than one governor in the
+``CPUIdle`` subsystem.
+
+There are two ``CPUIdle`` governors available, ``menu`` and ``ladder``.  Which
+of them is used depends on the configuration of the kernel and in particular on
+whether or not the scheduler tick can be `stopped by the idle
+loop <idle-cpus-and-tick_>`_.  It is possible to change the governor at run time
+if the ``cpuidle_sysfs_switch`` command line parameter has been passed to the
+kernel, but that is not safe in general, so it should not be done on production
+systems (that may change in the future, though).  The name of the ``CPUIdle``
+governor currently used by the kernel can be read from the
+:file:`current_governor_ro` (or :file:`current_governor` if
+``cpuidle_sysfs_switch`` is present in the kernel command line) file under
+:file:`/sys/devices/system/cpu/cpuidle/` in ``sysfs``.
+
+Which ``CPUIdle`` driver is used, on the other hand, usually depends on the
+platform the kernel is running on, but there are platforms with more than one
+matching driver.  For example, there are two drivers that can work with the
+majority of Intel platforms, ``intel_idle`` and ``acpi_idle``, one with
+hardcoded idle states information and the other able to read that information
+from the system's ACPI tables, respectively.  Still, even in those cases, the
+driver chosen at the system initialization time cannot be replaced later, so the
+decision on which one of them to use has to be made early (on Intel platforms
+the ``acpi_idle`` driver will be used if ``intel_idle`` is disabled for some
+reason or if it does not recognize the processor).  The name of the ``CPUIdle``
+driver currently used by the kernel can be read from the :file:`current_driver`
+file under :file:`/sys/devices/system/cpu/cpuidle/` in ``sysfs``.
+
+
+.. _idle-cpus-and-tick:
+
+Idle CPUs and The Scheduler Tick
+================================
+
+The scheduler tick is a timer that triggers periodically in order to implement
+the time sharing strategy of the CPU scheduler.  Of course, if there are
+multiple runnable tasks assigned to one CPU at the same time, the only way to
+allow them to make reasonable progress in a given time frame is to make them
+share the available CPU time.  Namely, in rough approximation, each task is
+given a slice of the CPU time to run its code, subject to the scheduling class,
+prioritization and so on and when that time slice is used up, the CPU should be
+switched over to running (the code of) another task.  The currently running task
+may not want to give the CPU away voluntarily, however, and the scheduler tick
+is there to make the switch happen regardless.  That is not the only role of the
+tick, but it is the primary reason for using it.
+
+The scheduler tick is problematic from the CPU idle time management perspective,
+because it triggers periodically and relatively often (depending on the kernel
+configuration, the length of the tick period is between 1 ms and 10 ms).
+Thus, if the tick is allowed to trigger on idle CPUs, it will not make sense
+for them to ask the hardware to enter idle states with target residencies above
+the tick period length.  Moreover, in that case the idle duration of any CPU
+will never exceed the tick period length and the energy used for entering and
+exiting idle states due to the tick wakeups on idle CPUs will be wasted.
+
+Fortunately, it is not really necessary to allow the tick to trigger on idle
+CPUs, because (by definition) they have no tasks to run except for the special
+"idle" one.  In other words, from the CPU scheduler perspective, the only user
+of the CPU time on them is the idle loop.  Since the time of an idle CPU need
+not be shared between multiple runnable tasks, the primary reason for using the
+tick goes away if the given CPU is idle.  Consequently, it is possible to stop
+the scheduler tick entirely on idle CPUs in principle, even though that may not
+always be worth the effort.
+
+Whether or not it makes sense to stop the scheduler tick in the idle loop
+depends on what is expected by the governor.  First, if there is another
+(non-tick) timer due to trigger within the tick range, stopping the tick clearly
+would be a waste of time, even though the timer hardware may not need to be
+reprogrammed in that case.  Second, if the governor is expecting a non-timer
+wakeup within the tick range, stopping the tick is not necessary and it may even
+be harmful.  Namely, in that case the governor will select an idle state with
+the target residency within the time until the expected wakeup, so that state is
+going to be relatively shallow.  The governor really cannot select a deep idle
+state then, as that would contradict its own expectation of a wakeup in short
+order.  Now, if the wakeup really occurs shortly, stopping the tick would be a
+waste of time and in this case the timer hardware would need to be reprogrammed,
+which is expensive.  On the other hand, if the tick is stopped and the wakeup
+does not occur any time soon, the hardware may spend indefinite amount of time
+in the shallow idle state selected by the governor, which will be a waste of
+energy.  Hence, if the governor is expecting a wakeup of any kind within the
+tick range, it is better to allow the tick trigger.  Otherwise, however, the
+governor will select a relatively deep idle state, so the tick should be stopped
+so that it does not wake up the CPU too early.
+
+In any case, the governor knows what it is expecting and the decision on whether
+or not to stop the scheduler tick belongs to it.  Still, if the tick has been
+stopped already (in one of the previous iterations of the loop), it is better
+to leave it as is and the governor needs to take that into account.
+
+The kernel can be configured to disable stopping the scheduler tick in the idle
+loop altogether.  That can be done through the build-time configuration of it
+(by unsetting the ``CONFIG_NO_HZ_IDLE`` configuration option) or by passing
+``nohz=off`` to it in the command line.  In both cases, as the stopping of the
+scheduler tick is disabled, the governor's decisions regarding it are simply
+ignored by the idle loop code and the tick is never stopped.
+
+The systems that run kernels configured to allow the scheduler tick to be
+stopped on idle CPUs are referred to as *tickless* systems and they are
+generally regarded as more energy-efficient than the systems running kernels in
+which the tick cannot be stopped.  If the given system is tickless, it will use
+the ``menu`` governor by default and if it is not tickless, the default
+``CPUIdle`` governor on it will be ``ladder``.
+
+
+The ``menu`` Governor
+=====================
+
+The ``menu`` governor is the default ``CPUIdle`` governor for tickless systems.
+It is quite complex, but the basic principle of its design is straightforward.
+Namely, when invoked to select an idle state for a CPU (i.e. an idle state that
+the CPU will ask the processor hardware to enter), it attempts to predict the
+idle duration and uses the predicted value for idle state selection.
+
+It first obtains the time until the closest timer event with the assumption
+that the scheduler tick will be stopped.  That time, referred to as the *sleep
+length* in what follows, is the upper bound on the time before the next CPU
+wakeup.  It is used to determine the sleep length range, which in turn is needed
+to get the sleep length correction factor.
+
+The ``menu`` governor maintains two arrays of sleep length correction factors.
+One of them is used when tasks previously running on the given CPU are waiting
+for some I/O operations to complete and the other one is used when that is not
+the case.  Each array contains several correction factor values that correspond
+to different sleep length ranges organized so that each range represented in the
+array is approximately 10 times wider than the previous one.
+
+The correction factor for the given sleep length range (determined before
+selecting the idle state for the CPU) is updated after the CPU has been woken
+up and the closer the sleep length is to the observed idle duration, the closer
+to 1 the correction factor becomes (it must fall between 0 and 1 inclusive).
+The sleep length is multiplied by the correction factor for the range that it
+falls into to obtain the first approximation of the predicted idle duration.
+
+Next, the governor uses a simple pattern recognition algorithm to refine its
+idle duration prediction.  Namely, it saves the last 8 observed idle duration
+values and, when predicting the idle duration next time, it computes the average
+and variance of them.  If the variance is small (smaller than 400 square
+milliseconds) or it is small relative to the average (the average is greater
+that 6 times the standard deviation), the average is regarded as the "typical
+interval" value.  Otherwise, the longest of the saved observed idle duration
+values is discarded and the computation is repeated for the remaining ones.
+Again, if the variance of them is small (in the above sense), the average is
+taken as the "typical interval" value and so on, until either the "typical
+interval" is determined or too many data points are disregarded, in which case
+the "typical interval" is assumed to equal "infinity" (the maximum unsigned
+integer value).  The "typical interval" computed this way is compared with the
+sleep length multiplied by the correction factor and the minimum of the two is
+taken as the predicted idle duration.
+
+Then, the governor computes an extra latency limit to help "interactive"
+workloads.  It uses the observation that if the exit latency of the selected
+idle state is comparable with the predicted idle duration, the total time spent
+in that state probably will be very short and the amount of energy to save by
+entering it will be relatively small, so likely it is better to avoid the
+overhead related to entering that state and exiting it.  Thus selecting a
+shallower state is likely to be a better option then.   The first approximation
+of the extra latency limit is the predicted idle duration itself which
+additionally is divided by a value depending on the number of tasks that
+previously ran on the given CPU and now they are waiting for I/O operations to
+complete.  The result of that division is compared with the latency limit coming
+from the power management quality of service, or `PM QoS <cpu-pm-qos_>`_,
+framework and the minimum of the two is taken as the limit for the idle states'
+exit latency.
+
+Now, the governor is ready to walk the list of idle states and choose one of
+them.  For this purpose, it compares the target residency of each state with
+the predicted idle duration and the exit latency of it with the computed latency
+limit.  It selects the state with the target residency closest to the predicted
+idle duration, but still below it, and exit latency that does not exceed the
+limit.
+
+In the final step the governor may still need to refine the idle state selection
+if it has not decided to `stop the scheduler tick <idle-cpus-and-tick_>`_.  That
+happens if the idle duration predicted by it is less than the tick period and
+the tick has not been stopped already (in a previous iteration of the idle
+loop).  Then, the sleep length used in the previous computations may not reflect
+the real time until the closest timer event and if it really is greater than
+that time, the governor may need to select a shallower state with a suitable
+target residency.
+
+
+.. _idle-states-representation:
+
+Representation of Idle States
+=============================
+
+For the CPU idle time management purposes all of the physical idle states
+supported by the processor have to be represented as a one-dimensional array of
+|struct cpuidle_state| objects each allowing an individual (logical) CPU to ask
+the processor hardware to enter an idle state of certain properties.  If there
+is a hierarchy of units in the processor, one |struct cpuidle_state| object can
+cover a combination of idle states supported by the units at different levels of
+the hierarchy.  In that case, the `target residency and exit latency parameters
+of it <idle-loop_>`_, must reflect the properties of the idle state at the
+deepest level (i.e. the idle state of the unit containing all of the other
+units).
+
+For example, take a processor with two cores in a larger unit referred to as
+a "module" and suppose that asking the hardware to enter a specific idle state
+(say "X") at the "core" level by one core will trigger the module to try to
+enter a specific idle state of its own (say "MX") if the other core is in idle
+state "X" already.  In other words, asking for idle state "X" at the "core"
+level gives the hardware a license to go as deep as to idle state "MX" at the
+"module" level, but there is no guarantee that this is going to happen (the core
+asking for idle state "X" may just end up in that state by itself instead).
+Then, the target residency of the |struct cpuidle_state| object representing
+idle state "X" must reflect the minimum time to spend in idle state "MX" of
+the module (including the time needed to enter it), because that is the minimum
+time the CPU needs to be idle to save any energy in case the hardware enters
+that state.  Analogously, the exit latency parameter of that object must cover
+the exit time of idle state "MX" of the module (and usually its entry time too),
+because that is the maximum delay between a wakeup signal and the time the CPU
+will start to execute the first new instruction (assuming that both cores in the
+module will always be ready to execute instructions as soon as the module
+becomes operational as a whole).
+
+There are processors without direct coordination between different levels of the
+hierarchy of units inside them, however.  In those cases asking for an idle
+state at the "core" level does not automatically affect the "module" level, for
+example, in any way and the ``CPUIdle`` driver is responsible for the entire
+handling of the hierarchy.  Then, the definition of the idle state objects is
+entirely up to the driver, but still the physical properties of the idle state
+that the processor hardware finally goes into must always follow the parameters
+used by the governor for idle state selection (for instance, the actual exit
+latency of that idle state must not exceed the exit latency parameter of the
+idle state object selected by the governor).
+
+In addition to the target residency and exit latency idle state parameters
+discussed above, the objects representing idle states each contain a few other
+parameters describing the idle state and a pointer to the function to run in
+order to ask the hardware to enter that state.  Also, for each
+|struct cpuidle_state| object, there is a corresponding
+:c:type:`struct cpuidle_state_usage <cpuidle_state_usage>` one containing usage
+statistics of the given idle state.  That information is exposed by the kernel
+via ``sysfs``.
+
+For each CPU in the system, there is a :file:`/sys/devices/system/cpu<N>/cpuidle/`
+directory in ``sysfs``, where the number ``<N>`` is assigned to the given
+CPU at the initialization time.  That directory contains a set of subdirectories
+called :file:`state0`, :file:`state1` and so on, up to the number of idle state
+objects defined for the given CPU minus one.  Each of these directories
+corresponds to one idle state object and the larger the number in its name, the
+deeper the (effective) idle state represented by it.  Each of them contains
+a number of files (attributes) representing the properties of the idle state
+object corresponding to it, as follows:
+
+``above``
+       Total number of times this idle state had been asked for, but the
+       observed idle duration was certainly too short to match its target
+       residency.
+
+``below``
+       Total number of times this idle state had been asked for, but cerainly
+       a deeper idle state would have been a better match for the observed idle
+       duration.
+
+``desc``
+       Description of the idle state.
+
+``disable``
+       Whether or not this idle state is disabled.
+
+``latency``
+       Exit latency of the idle state in microseconds.
+
+``name``
+       Name of the idle state.
+
+``power``
+       Power drawn by hardware in this idle state in milliwatts (if specified,
+       0 otherwise).
+
+``residency``
+       Target residency of the idle state in microseconds.
+
+``time``
+       Total time spent in this idle state by the given CPU (as measured by the
+       kernel) in microseconds.
+
+``usage``
+       Total number of times the hardware has been asked by the given CPU to
+       enter this idle state.
+
+The :file:`desc` and :file:`name` files both contain strings.  The difference
+between them is that the name is expected to be more concise, while the
+description may be longer and it may contain white space or special characters.
+The other files listed above contain integer numbers.
+
+The :file:`disable` attribute is the only writeable one.  If it contains 1, the
+given idle state is disabled for this particular CPU, which means that the
+governor will never select it for this particular CPU and the ``CPUIdle``
+driver will never ask the hardware to enter it for that CPU as a result.
+However, disabling an idle state for one CPU does not prevent it from being
+asked for by the other CPUs, so it must be disabled for all of them in order to
+never be asked for by any of them.  [Note that, due to the way the ``ladder``
+governor is implemented, disabling an idle state prevents that governor from
+selecting any idle states deeper than the disabled one too.]
+
+If the :file:`disable` attribute contains 0, the given idle state is enabled for
+this particular CPU, but it still may be disabled for some or all of the other
+CPUs in the system at the same time.  Writing 1 to it causes the idle state to
+be disabled for this particular CPU and writing 0 to it allows the governor to
+take it into consideration for the given CPU and the driver to ask for it,
+unless that state was disabled globally in the driver (in which case it cannot
+be used at all).
+
+The :file:`power` attribute is not defined very well, especially for idle state
+objects representing combinations of idle states at different levels of the
+hierarchy of units in the processor, and it generally is hard to obtain idle
+state power numbers for complex hardware, so :file:`power` often contains 0 (not
+available) and if it contains a nonzero number, that number may not be very
+accurate and it should not be relied on for anything meaningful.
+
+The number in the :file:`time` file generally may be greater than the total time
+really spent by the given CPU in the given idle state, because it is measured by
+the kernel and it may not cover the cases in which the hardware refused to enter
+this idle state and entered a shallower one instead of it (or even it did not
+enter any idle state at all).  The kernel can only measure the time span between
+asking the hardware to enter an idle state and the subsequent wakeup of the CPU
+and it cannot say what really happened in the meantime at the hardware level.
+Moreover, if the idle state object in question represents a combination of idle
+states at different levels of the hierarchy of units in the processor,
+the kernel can never say how deep the hardware went down the hierarchy in any
+particular case.  For these reasons, the only reliable way to find out how
+much time has been spent by the hardware in different idle states supported by
+it is to use idle state residency counters in the hardware, if available.
+
+
+.. _cpu-pm-qos:
+
+Power Management Quality of Service for CPUs
+============================================
+
+The power management quality of service (PM QoS) framework in the Linux kernel
+allows kernel code and user space processes to set constraints on various
+energy-efficiency features of the kernel to prevent performance from dropping
+below a required level.  The PM QoS constraints can be set globally, in
+predefined categories referred to as PM QoS classes, or against individual
+devices.
+
+CPU idle time management can be affected by PM QoS in two ways, through the
+global constraint in the ``PM_QOS_CPU_DMA_LATENCY`` class and through the
+resume latency constraints for individual CPUs.  Kernel code (e.g. device
+drivers) can set both of them with the help of special internal interfaces
+provided by the PM QoS framework.  User space can modify the former by opening
+the :file:`cpu_dma_latency` special device file under :file:`/dev/` and writing
+a binary value (interpreted as a signed 32-bit integer) to it.  In turn, the
+resume latency constraint for a CPU can be modified by user space by writing a
+string (representing a signed 32-bit integer) to the
+:file:`power/pm_qos_resume_latency_us` file under
+:file:`/sys/devices/system/cpu/cpu<N>/` in ``sysfs``, where the CPU number
+``<N>`` is allocated at the system initialization time.  Negative values
+will be rejected in both cases and, also in both cases, the written integer
+number will be interpreted as a requested PM QoS constraint in microseconds.
+
+The requested value is not automatically applied as a new constraint, however,
+as it may be less restrictive (greater in this particular case) than another
+constraint previously requested by someone else.  For this reason, the PM QoS
+framework maintains a list of requests that have been made so far in each
+global class and for each device, aggregates them and applies the effective
+(minimum in this particular case) value as the new constraint.
+
+In fact, opening the :file:`cpu_dma_latency` special device file causes a new
+PM QoS request to be created and added to the priority list of requests in the
+``PM_QOS_CPU_DMA_LATENCY`` class and the file descriptor coming from the
+"open" operation represents that request.  If that file descriptor is then
+used for writing, the number written to it will be associated with the PM QoS
+request represented by it as a new requested constraint value.  Next, the
+priority list mechanism will be used to determine the new effective value of
+the entire list of requests and that effective value will be set as a new
+constraint.  Thus setting a new requested constraint value will only change the
+real constraint if the effective "list" value is affected by it.  In particular,
+for the ``PM_QOS_CPU_DMA_LATENCY`` class it only affects the real constraint if
+it is the minimum of the requested constraints in the list.  The process holding
+a file descriptor obtained by opening the :file:`cpu_dma_latency` special device
+file controls the PM QoS request associated with that file descriptor, but it
+controls this particular PM QoS request only.
+
+Closing the :file:`cpu_dma_latency` special device file or, more precisely, the
+file descriptor obtained while opening it, causes the PM QoS request associated
+with that file descriptor to be removed from the ``PM_QOS_CPU_DMA_LATENCY``
+class priority list and destroyed.  If that happens, the priority list mechanism
+will be used, again, to determine the new effective value for the whole list
+and that value will become the new real constraint.
+
+In turn, for each CPU there is only one resume latency PM QoS request
+associated with the :file:`power/pm_qos_resume_latency_us` file under
+:file:`/sys/devices/system/cpu/cpu<N>/` in ``sysfs`` and writing to it causes
+this single PM QoS request to be updated regardless of which user space
+process does that.  In other words, this PM QoS request is shared by the entire
+user space, so access to the file associated with it needs to be arbitrated
+to avoid confusion.  [Arguably, the only legitimate use of this mechanism in
+practice is to pin a process to the CPU in question and let it use the
+``sysfs`` interface to control the resume latency constraint for it.]  It
+still only is a request, however.  It is a member of a priority list used to
+determine the effective value to be set as the resume latency constraint for the
+CPU in question every time the list of requests is updated this way or another
+(there may be other requests coming from kernel code in that list).
+
+CPU idle time governors are expected to regard the minimum of the global
+effective ``PM_QOS_CPU_DMA_LATENCY`` class constraint and the effective
+resume latency constraint for the given CPU as the upper limit for the exit
+latency of the idle states they can select for that CPU.  They should never
+select any idle states with exit latency beyond that limit.
+
+
+Idle States Control Via Kernel Command Line
+===========================================
+
+In addition to the ``sysfs`` interface allowing individual idle states to be
+`disabled for individual CPUs <idle-states-representation_>`_, there are kernel
+command line parameters affecting CPU idle time management.
+
+The ``cpuidle.off=1`` kernel command line option can be used to disable the
+CPU idle time management entirely.  It does not prevent the idle loop from
+running on idle CPUs, but it prevents the CPU idle time governors and drivers
+from being invoked.  If it is added to the kernel command line, the idle loop
+will ask the hardware to enter idle states on idle CPUs via the CPU architecture
+support code that is expected to provide a default mechanism for this purpose.
+That default mechanism usually is the least common denominator for all of the
+processors implementing the architecture (i.e. CPU instruction set) in question,
+however, so it is rather crude and not very energy-efficient.  For this reason,
+it is not recommended for production use.
+
+The ``cpuidle.governor=`` kernel command line switch allows the ``CPUIdle``
+governor to use to be specified.  It has to be appended with a string matching
+the name of an available governor (e.g. ``cpuidle.governor=menu``) and that
+governor will be used instead of the default one.  It is possible to force
+the ``menu`` governor to be used on the systems that use the ``ladder`` governor
+by default this way, for example.
+
+The other kernel command line parameters controlling CPU idle time management
+described below are only relevant for the *x86* architecture and some of
+them affect Intel processors only.
+
+The *x86* architecture support code recognizes three kernel command line
+options related to CPU idle time management: ``idle=poll``, ``idle=halt``,
+and ``idle=nomwait``.  The first two of them disable the ``acpi_idle`` and
+``intel_idle`` drivers altogether, which effectively causes the entire
+``CPUIdle`` subsystem to be disabled and makes the idle loop invoke the
+architecture support code to deal with idle CPUs.  How it does that depends on
+which of the two parameters is added to the kernel command line.  In the
+``idle=halt`` case, the architecture support code will use the ``HLT``
+instruction of the CPUs (which, as a rule, suspends the execution of the program
+and causes the hardware to attempt to enter the shallowest available idle state)
+for this purpose, and if ``idle=poll`` is used, idle CPUs will execute a
+more or less ``lightweight'' sequence of instructions in a tight loop.  [Note
+that using ``idle=poll`` is somewhat drastic in many cases, as preventing idle
+CPUs from saving almost any energy at all may not be the only effect of it.
+For example, on Intel hardware it effectively prevents CPUs from using
+P-states (see |cpufreq|) that require any number of CPUs in a package to be
+idle, so it very well may hurt single-thread computations performance as well as
+energy-efficiency.  Thus using it for performance reasons may not be a good idea
+at all.]
+
+The ``idle=nomwait`` option disables the ``intel_idle`` driver and causes
+``acpi_idle`` to be used (as long as all of the information needed by it is
+there in the system's ACPI tables), but it is not allowed to use the
+``MWAIT`` instruction of the CPUs to ask the hardware to enter idle states.
+
+In addition to the architecture-level kernel command line options affecting CPU
+idle time management, there are parameters affecting individual ``CPUIdle``
+drivers that can be passed to them via the kernel command line.  Specifically,
+the ``intel_idle.max_cstate=<n>`` and ``processor.max_cstate=<n>`` parameters,
+where ``<n>`` is an idle state index also used in the name of the given
+state's directory in ``sysfs`` (see
+`Representation of Idle States <idle-states-representation_>`_), causes the
+``intel_idle`` and ``acpi_idle`` drivers, respectively, to discard all of the
+idle states deeper than idle state ``<n>``.  In that case, they will never ask
+for any of those idle states or expose them to the governor.  [The behavior of
+the two drivers is different for ``<n>`` equal to ``0``.  Adding
+``intel_idle.max_cstate=0`` to the kernel command line disables the
+``intel_idle`` driver and allows ``acpi_idle`` to be used, whereas
+``processor.max_cstate=0`` is equivalent to ``processor.max_cstate=1``.
+Also, the ``acpi_idle`` driver is part of the ``processor`` kernel module that
+can be loaded separately and ``max_cstate=<n>`` can be passed to it as a module
+parameter when it is loaded.]
index ac6f5c597a5612830c2acf5d044194b9d6de1cb4..ec0f7c111f65b14c4328d7a9e0cd3314a8fba36f 100644 (file)
@@ -495,7 +495,15 @@ on the following rules, regardless of the current operation mode of the driver:
 
  2. Each individual CPU is affected by its own per-policy limits (that is, it
     cannot be requested to run faster than its own per-policy maximum and it
-    cannot be requested to run slower than its own per-policy minimum).
+    cannot be requested to run slower than its own per-policy minimum). The
+    effective performance depends on whether the platform supports per core
+    P-states, hyper-threading is enabled and on current performance requests
+    from other CPUs. When platform doesn't support per core P-states, the
+    effective performance can be more than the policy limits set on a CPU, if
+    other CPUs are requesting higher performance at that moment. Even with per
+    core P-states support, when hyper-threading is enabled, if the sibling CPU
+    is requesting higher performance, the other siblings will get higher
+    performance than their policy limits.
 
  3. The global and per-policy limits can be set independently.
 
index fa01bf083dfe67877b43bfa3a94e2f7b78d48cec..b6cef9b5e961e6bdec653707e1457e0ddb87e013 100644 (file)
@@ -5,5 +5,6 @@ Working-State Power Management
 .. toctree::
    :maxdepth: 2
 
+   cpuidle
    cpufreq
    intel_pstate
diff --git a/Documentation/cpuidle/core.txt b/Documentation/cpuidle/core.txt
deleted file mode 100644 (file)
index 63ecc5d..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-               Supporting multiple CPU idle levels in kernel
-
-                               cpuidle
-
-General Information:
-
-Various CPUs today support multiple idle levels that are differentiated
-by varying exit latencies and power consumption during idle.
-cpuidle is a generic in-kernel infrastructure that separates
-idle policy (governor) from idle mechanism (driver) and provides a
-standardized infrastructure to support independent development of
-governors and drivers.
-
-cpuidle resides under drivers/cpuidle.
-
-Boot options:
-"cpuidle_sysfs_switch"
-enables current_governor interface in /sys/devices/system/cpu/cpuidle/,
-which can be used to switch governors at run time. This boot option
-is meant for developer testing only. In normal usage, kernel picks the
-best governor based on governor ratings.
-SEE ALSO: sysfs.txt in this directory.
diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt
deleted file mode 100644 (file)
index d1587f4..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-               Supporting multiple CPU idle levels in kernel
-
-                               cpuidle sysfs
-
-System global cpuidle related information and tunables are under
-/sys/devices/system/cpu/cpuidle
-
-The current interfaces in this directory has self-explanatory names:
-* current_driver
-* current_governor_ro
-
-With cpuidle_sysfs_switch boot option (meant for developer testing)
-following objects are visible instead.
-* current_driver
-* available_governors
-* current_governor
-In this case users can switch the governor at run time by writing
-to current_governor.
-
-
-Per logical CPU specific cpuidle information are under
-/sys/devices/system/cpu/cpuX/cpuidle
-for each online cpu X
-
---------------------------------------------------------------------------------
-# ls -lR /sys/devices/system/cpu/cpu0/cpuidle/
-/sys/devices/system/cpu/cpu0/cpuidle/:
-total 0
-drwxr-xr-x 2 root root 0 Feb  8 10:42 state0
-drwxr-xr-x 2 root root 0 Feb  8 10:42 state1
-drwxr-xr-x 2 root root 0 Feb  8 10:42 state2
-drwxr-xr-x 2 root root 0 Feb  8 10:42 state3
-
-/sys/devices/system/cpu/cpu0/cpuidle/state0:
-total 0
--r--r--r-- 1 root root 4096 Feb  8 10:42 desc
--rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
--r--r--r-- 1 root root 4096 Feb  8 10:42 latency
--r--r--r-- 1 root root 4096 Feb  8 10:42 name
--r--r--r-- 1 root root 4096 Feb  8 10:42 power
--r--r--r-- 1 root root 4096 Feb  8 10:42 residency
--r--r--r-- 1 root root 4096 Feb  8 10:42 time
--r--r--r-- 1 root root 4096 Feb  8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state1:
-total 0
--r--r--r-- 1 root root 4096 Feb  8 10:42 desc
--rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
--r--r--r-- 1 root root 4096 Feb  8 10:42 latency
--r--r--r-- 1 root root 4096 Feb  8 10:42 name
--r--r--r-- 1 root root 4096 Feb  8 10:42 power
--r--r--r-- 1 root root 4096 Feb  8 10:42 residency
--r--r--r-- 1 root root 4096 Feb  8 10:42 time
--r--r--r-- 1 root root 4096 Feb  8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state2:
-total 0
--r--r--r-- 1 root root 4096 Feb  8 10:42 desc
--rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
--r--r--r-- 1 root root 4096 Feb  8 10:42 latency
--r--r--r-- 1 root root 4096 Feb  8 10:42 name
--r--r--r-- 1 root root 4096 Feb  8 10:42 power
--r--r--r-- 1 root root 4096 Feb  8 10:42 residency
--r--r--r-- 1 root root 4096 Feb  8 10:42 time
--r--r--r-- 1 root root 4096 Feb  8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state3:
-total 0
--r--r--r-- 1 root root 4096 Feb  8 10:42 desc
--rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
--r--r--r-- 1 root root 4096 Feb  8 10:42 latency
--r--r--r-- 1 root root 4096 Feb  8 10:42 name
--r--r--r-- 1 root root 4096 Feb  8 10:42 power
--r--r--r-- 1 root root 4096 Feb  8 10:42 residency
--r--r--r-- 1 root root 4096 Feb  8 10:42 time
--r--r--r-- 1 root root 4096 Feb  8 10:42 usage
---------------------------------------------------------------------------------
-
-
-* desc : Small description about the idle state (string)
-* disable : Option to disable this idle state (bool) -> see note below
-* latency : Latency to exit out of this idle state (in microseconds)
-* residency : Time after which a state becomes more effecient than any
-  shallower state (in microseconds)
-* name : Name of the idle state (string)
-* power : Power consumed while in this idle state (in milliwatts)
-* time : Total time spent in this idle state (in microseconds)
-* usage : Number of times this state was entered (count)
-
-Note:
-The behavior and the effect of the disable variable depends on the
-implementation of a particular governor. In the ladder governor, for
-example, it is not coherent, i.e. if one is disabling a light state,
-then all deeper states are disabled as well, but the disable variable
-does not reflect it. Likewise, if one enables a deep state but a lighter
-state still is disabled, then this has no effect.
index 87dfb33fb3bebd12a075f4e8d6b366337f0255d3..b9d533717dffe62be1cf8359cee79b2bc61f4aca 100644 (file)
@@ -1,11 +1,14 @@
-Device tree bindings for Allwinner A64 DE2 bus
+Device tree bindings for Allwinner DE2/3 bus
 
 The Allwinner A64 DE2 is on a special bus, which needs a SRAM region (SRAM C)
-to be claimed for enabling the access.
+to be claimed for enabling the access. The DE3 on Allwinner H6 is at the same
+situation, and the binding also applies.
 
 Required properties:
 
- - compatible:         Should contain "allwinner,sun50i-a64-de2"
+ - compatible:         Should be one of:
+                               - "allwinner,sun50i-a64-de2"
+                               - "allwinner,sun50i-h6-de3", "allwinner,sun50i-a64-de2"
  - reg:                        A resource specifier for the register space
  - #address-cells:     Must be set to 1
  - #size-cells:                Must be set to 1
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt
new file mode 100644 (file)
index 0000000..3385694
--- /dev/null
@@ -0,0 +1,172 @@
+Qualcomm Technologies, Inc. CPUFREQ Bindings
+
+CPUFREQ HW is a hardware engine used by some Qualcomm Technologies, Inc. (QTI)
+SoCs to manage frequency in hardware. It is capable of controlling frequency
+for multiple clusters.
+
+Properties:
+- compatible
+       Usage:          required
+       Value type:     <string>
+       Definition:     must be "qcom,cpufreq-hw".
+
+- clocks
+       Usage:          required
+       Value type:     <phandle> From common clock binding.
+       Definition:     clock handle for XO clock and GPLL0 clock.
+
+- clock-names
+       Usage:          required
+       Value type:     <string> From common clock binding.
+       Definition:     must be "xo", "alternate".
+
+- reg
+       Usage:          required
+       Value type:     <prop-encoded-array>
+       Definition:     Addresses and sizes for the memory of the HW bases in
+                       each frequency domain.
+- reg-names
+       Usage:          Optional
+       Value type:     <string>
+       Definition:     Frequency domain name i.e.
+                       "freq-domain0", "freq-domain1".
+
+- #freq-domain-cells:
+       Usage:          required.
+       Definition:     Number of cells in a freqency domain specifier.
+
+* Property qcom,freq-domain
+Devices supporting freq-domain must set their "qcom,freq-domain" property with
+phandle to a cpufreq_hw followed by the Domain ID(0/1) in the CPU DT node.
+
+
+Example:
+
+Example 1: Dual-cluster, Quad-core per cluster. CPUs within a cluster switch
+DCVS state together.
+
+/ {
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               CPU0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x0>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_0>;
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       L2_0: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                               L3_0: l3-cache {
+                                     compatible = "cache";
+                               };
+                       };
+               };
+
+               CPU1: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x100>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_100>;
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       L2_100: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU2: cpu@200 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x200>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_200>;
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       L2_200: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU3: cpu@300 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x300>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_300>;
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       L2_300: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU4: cpu@400 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x400>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_400>;
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       L2_400: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU5: cpu@500 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x500>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_500>;
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       L2_500: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU6: cpu@600 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x600>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_600>;
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       L2_600: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU7: cpu@700 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo385";
+                       reg = <0x0 0x700>;
+                       enable-method = "psci";
+                       next-level-cache = <&L2_700>;
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       L2_700: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+       };
+
+ soc {
+       cpufreq_hw: cpufreq@17d43000 {
+               compatible = "qcom,cpufreq-hw";
+               reg = <0x17d43000 0x1400>, <0x17d45800 0x1400>;
+               reg-names = "freq-domain0", "freq-domain1";
+
+               clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
+               clock-names = "xo", "alternate";
+
+               #freq-domain-cells = <1>;
+       };
+}
index 057b81335775e7526805710324eb497fe7c04bcb..c65fd7a7467c09f1e7fa77ca3581de29f31653fd 100644 (file)
@@ -67,6 +67,8 @@ Required properties:
 Optional properties:
 - power-domains: Optional phandle to associated power domain as described in
        the file ../power/power_domain.txt
+- amlogic,canvas: phandle to canvas provider node as described in the file
+       ../soc/amlogic/amlogic,canvas.txt
 
 Required nodes:
 
index 3aeb0ec06fd02421bcb412fdfbca08747476b904..ba5469dd09f35393e339af8000d6ca776d1c2f31 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
   - "renesas,r8a7793-lvds" for R8A7793 (R-Car M2-N) compatible LVDS encoders
   - "renesas,r8a7795-lvds" for R8A7795 (R-Car H3) compatible LVDS encoders
   - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders
+  - "renesas,r8a77965-lvds" for R8A77965 (R-Car M3-N) compatible LVDS encoders
   - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders
   - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders
   - "renesas,r8a77990-lvds" for R8A77990 (R-Car E3) compatible LVDS encoders
diff --git a/Documentation/devicetree/bindings/display/himax,hx8357d.txt b/Documentation/devicetree/bindings/display/himax,hx8357d.txt
new file mode 100644 (file)
index 0000000..e641f66
--- /dev/null
@@ -0,0 +1,26 @@
+Himax HX8357D display panels
+
+This binding is for display panels using a Himax HX8357D controller in SPI
+mode, such as the Adafruit 3.5" TFT for Raspberry Pi.
+
+Required properties:
+- compatible:  "adafruit,yx350hv15", "himax,hx8357d"
+- dc-gpios:    D/C pin
+- reg:         address of the panel on the SPI bus
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in ../spi/spi-bus.txt must be specified.
+
+Optional properties:
+- rotation:    panel rotation in degrees counter clockwise (0,90,180,270)
+- backlight:   phandle of the backlight device attached to the panel
+
+Example:
+       display@0{
+               compatible = "adafruit,yx350hv15", "himax,hx8357d";
+               reg = <0>;
+               spi-max-frequency = <32000000>;
+               dc-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
+               rotation = <90>;
+               backlight = <&backlight>;
+       };
index dfc743219bd88e4ab858470fac7d77752ff261a3..9ae94694272071281285be6e1185d5ad720ef68f 100644 (file)
@@ -106,6 +106,7 @@ Required properties:
 - clocks: Phandles to device clocks. See [1] for details on clock bindings.
 - clock-names: the following clocks are required:
   * "iface"
+  * "ref" (only required for new DTS files/entries)
   For 28nm HPM/LP, 28nm 8960 PHYs:
 - vddio-supply: phandle to vdd-io regulator device node
   For 20nm PHY:
index 43fac0fe09bbaf69bfbc1539ffbf095a3078bba8..ac8df3b871f900a0672f266a5b05635a7aca01cf 100644 (file)
@@ -1,11 +1,13 @@
 Qualcomm adreno/snapdragon GPU
 
 Required properties:
-- compatible: "qcom,adreno-XYZ.W", "qcom,adreno"
+- compatible: "qcom,adreno-XYZ.W", "qcom,adreno" or
+             "amd,imageon-XYZ.W", "amd,imageon"
     for example: "qcom,adreno-306.0", "qcom,adreno"
   Note that you need to list the less specific "qcom,adreno" (since this
   is what the device is matched on), in addition to the more specific
   with the chip-id.
+  If "amd,imageon" is used, there should be no top level msm device.
 - reg: Physical base address and length of the controller's registers.
 - interrupts: The interrupt signal from the gpu.
 - clocks: device clocks
index 3c341a15ccdc6a51ad3bf313d2b0ec9566a0d5f9..b07eeb38f709829894a65ed66d74628e36f0c0bf 100644 (file)
@@ -38,6 +38,8 @@ Required properties:
 Optional properties:
 - clock-names: the following clocks are optional:
   * "lut_clk"
+- qcom,lcdc-align-lsb: Boolean value indicating that LSB alignment should be
+  used for LCDC. This is only valid for 18bpp panels.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 b/Documentation/devicetree/bindings/display/panel/auo,g101evn010
new file mode 100644 (file)
index 0000000..bc6a0c8
--- /dev/null
@@ -0,0 +1,12 @@
+AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,g101evn010"
+- power-supply: as specified in the base binding
+
+Optional properties:
+- backlight: as specified in the base binding
+- enable-gpios: as specified in the base binding
+
+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/display/panel/bananapi,s070wv20-ct16.txt b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
new file mode 100644 (file)
index 0000000..35bc0c8
--- /dev/null
@@ -0,0 +1,12 @@
+Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
+
+Required properties:
+- compatible: should be "bananapi,s070wv20-ct16"
+- power-supply: see ./panel-common.txt
+
+Optional properties:
+- enable-gpios: see ./simple-panel.txt
+- backlight: see ./simple-panel.txt
+
+This binding is compatible with the simple-panel binding, which is specified
+in ./simple-panel.txt.
diff --git a/Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt b/Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt
new file mode 100644 (file)
index 0000000..057f7f3
--- /dev/null
@@ -0,0 +1,12 @@
+CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel
+
+Required properties:
+- compatible: should be "cdtech,s043wq26h-ct7"
+- power-supply: as specified in the base binding
+
+Optional properties:
+- backlight: as specified in the base binding
+- enable-gpios: as specified in the base binding
+
+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/display/panel/cdtech,s070wv95-ct16.txt b/Documentation/devicetree/bindings/display/panel/cdtech,s070wv95-ct16.txt
new file mode 100644 (file)
index 0000000..505615d
--- /dev/null
@@ -0,0 +1,12 @@
+CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel
+
+Required properties:
+- compatible: should be "cdtech,s070wv95-ct16"
+- power-supply: as specified in the base binding
+
+Optional properties:
+- backlight: as specified in the base binding
+- enable-gpios: as specified in the base binding
+
+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/display/panel/dlc,dlc1010gig.txt b/Documentation/devicetree/bindings/display/panel/dlc,dlc1010gig.txt
new file mode 100644 (file)
index 0000000..fbf5dcd
--- /dev/null
@@ -0,0 +1,12 @@
+DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
+
+Required properties:
+- compatible: should be "dlc,dlc1010gig"
+- power-supply: See simple-panel.txt
+
+Optional properties:
+- enable-gpios: See simple-panel.txt
+- backlight: See simple-panel.txt
+
+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/display/panel/olimex,lcd-olinuxino.txt b/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt
new file mode 100644 (file)
index 0000000..a89f9c8
--- /dev/null
@@ -0,0 +1,42 @@
+Binding for Olimex Ltd. LCD-OLinuXino bridge panel.
+
+This device can be used as bridge between a host controller and LCD panels.
+Currently supported LCDs are:
+  - LCD-OLinuXino-4.3TS
+  - LCD-OLinuXino-5
+  - LCD-OLinuXino-7
+  - LCD-OLinuXino-10
+
+The panel itself contains:
+  - AT24C16C EEPROM holding panel identification and timing requirements
+  - AR1021 resistive touch screen controller (optional)
+  - FT5x6 capacitive touch screnn controller (optional)
+  - GT911/GT928 capacitive touch screen controller (optional)
+
+The above chips share same I2C bus. The EEPROM is factory preprogrammed with
+device information (id, serial, etc.) and timing requirements.
+
+Touchscreen bingings can be found in these files:
+  - input/touchscreen/goodix.txt
+  - input/touchscreen/edt-ft5x06.txt
+  - input/touchscreen/ar1021.txt
+
+Required properties:
+  - compatible: should be "olimex,lcd-olinuxino"
+  - reg: address of the configuration EEPROM, should be <0x50>
+  - power-supply: phandle of the regulator that provides the supply voltage
+
+Optional properties:
+  - enable-gpios: GPIO pin to enable or disable the panel
+  - backlight: phandle of the backlight device attacked to the panel
+
+Example:
+&i2c2 {
+       panel@50 {
+               compatible = "olimex,lcd-olinuxino";
+               reg = <0x50>;
+               power-supply = <&reg_vcc5v0>;
+               enable-gpios = <&pio 7 8 GPIO_ACTIVE_HIGH>;
+               backlight = <&backlight>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6d16d0.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6d16d0.txt
new file mode 100644 (file)
index 0000000..b94e366
--- /dev/null
@@ -0,0 +1,30 @@
+Samsung S6D16D0 4" 864x480 AMOLED panel
+
+Required properties:
+  - compatible: should be:
+    "samsung,s6d16d0",
+  - reg: the virtual channel number of a DSI peripheral
+  - vdd1-supply: I/O voltage supply
+  - reset-gpios: a GPIO spec for the reset pin (active low)
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in
+media/video-interfaces.txt. This node should describe panel's video bus.
+
+Example:
+&dsi {
+       ...
+
+       panel@0 {
+               compatible = "samsung,s6d16d0";
+               reg = <0>;
+               vdd1-supply = <&foo>;
+               reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&dsi_out>;
+                       };
+               };
+       };
+};
index f5e3c6f2095a502d420fec40af372c009e80e418..40f3d7c713bb13ccd4759bd2cef8f51c3b97253b 100644 (file)
@@ -1,47 +1,70 @@
 TPO TPG110 Panel
 ================
 
-This binding builds on the DPI bindings, adding a few properties
-as a superset of a DPI. See panel-dpi.txt for the required DPI
-bindings.
+This panel driver is a component that acts as an intermediary
+between an RGB output and a variety of panels. The panel
+driver is strapped up in electronics to the desired resolution
+and other properties, and has a control interface over 3WIRE
+SPI. By talking to the TPG110 over SPI, the strapped properties
+can be discovered and the hardware is therefore mostly
+self-describing.
+
+       +--------+
+SPI -> |  TPO   | -> physical display
+RGB -> | TPG110 |
+       +--------+
+
+If some electrical strap or alternate resolution is desired,
+this can be set up by taking software control of the display
+over the SPI interface. The interface can also adjust
+for properties of the display such as gamma correction and
+certain electrical driving levels.
+
+The TPG110 does not know the physical dimensions of the panel
+connected, so this needs to be specified in the device tree.
+
+It requires a GPIO line for control of its reset line.
+
+The serial protocol has line names that resemble I2C but the
+protocol is not I2C but 3WIRE SPI.
 
 Required properties:
-- compatible : "tpo,tpg110"
+- compatible : one of:
+  "ste,nomadik-nhk15-display", "tpo,tpg110"
+  "tpo,tpg110"
 - grestb-gpios : panel reset GPIO
-- scen-gpios : serial control enable GPIO
-- scl-gpios : serial control clock line GPIO
-- sda-gpios : serial control data line GPIO
+- width-mm : see display/panel/panel-common.txt
+- height-mm : see display/panel/panel-common.txt
+
+The device needs to be a child of an SPI bus, see
+spi/spi-bus.txt. The SPI child must set the following
+properties:
+- spi-3wire
+- spi-max-frequency = <3000000>;
+as these are characteristics of this device.
 
-Required nodes:
-- Video port for DPI input, see panel-dpi.txt
-- Panel timing for DPI setup, see panel-dpi.txt
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in
+media/video-interfaces.txt. This node should describe panel's video bus.
 
 Example
 -------
 
-panel {
-       compatible = "tpo,tpg110", "panel-dpi";
-       grestb-gpios = <&stmpe_gpio44 5 GPIO_ACTIVE_LOW>;
-       scen-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
-       scl-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
-       sda-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+panel: display@0 {
+       compatible = "tpo,tpg110";
+       reg = <0>;
+       spi-3wire;
+       /* 320 ns min period ~= 3 MHz */
+       spi-max-frequency = <3000000>;
+       /* Width and height from data sheet */
+       width-mm = <116>;
+       height-mm = <87>;
+       grestb-gpios = <&foo_gpio 5 GPIO_ACTIVE_LOW>;
        backlight = <&bl>;
 
        port {
                nomadik_clcd_panel: endpoint {
-                       remote-endpoint = <&nomadik_clcd_pads>;
+                       remote-endpoint = <&foo>;
                };
        };
-
-       panel-timing {
-               clock-frequency = <33200000>;
-               hactive = <800>;
-               hback-porch = <216>;
-               hfront-porch = <40>;
-               hsync-len = <1>;
-               vactive = <480>;
-               vback-porch = <35>;
-               vfront-porch = <10>;
-               vsync-len = <1>;
-       };
 };
index 9de67be632d1a7a42bbd765e5fa3cbd07b9a01f5..3c855d9f27193bcb03f365cc8c4a3a78a5d478a0 100644 (file)
@@ -4,7 +4,9 @@ Required Properties:
 
   - compatible: must be one of the following.
     - "renesas,du-r8a7743" for R8A7743 (RZ/G1M) compatible DU
+    - "renesas,du-r8a7744" for R8A7744 (RZ/G1N) compatible DU
     - "renesas,du-r8a7745" for R8A7745 (RZ/G1E) compatible DU
+    - "renesas,du-r8a77470" for R8A77470 (RZ/G1C) compatible DU
     - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
     - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
     - "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU
@@ -52,7 +54,9 @@ corresponding to each DU output.
                         Port0          Port1          Port2          Port3
 -----------------------------------------------------------------------------
  R8A7743 (RZ/G1M)       DPAD 0         LVDS 0         -              -
+ R8A7744 (RZ/G1N)       DPAD 0         LVDS 0         -              -
  R8A7745 (RZ/G1E)       DPAD 0         DPAD 1         -              -
+ R8A77470 (RZ/G1C)      DPAD 0         DPAD 1         LVDS 0         -
  R8A7779 (R-Car H1)     DPAD 0         DPAD 1         -              -
  R8A7790 (R-Car H2)     DPAD 0         LVDS 0         LVDS 1         -
  R8A7791 (R-Car M2-W)   DPAD 0         LVDS 0         -              -
index adc94fc3c9f88543862821bbc0ac6f506f6cfc1c..39143424a474064327701868e4625866cd91f257 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
 
 - compatible: should be one of the following:
                "rockchip,rk3288-dw-hdmi"
+               "rockchip,rk3328-dw-hdmi"
                "rockchip,rk3399-dw-hdmi"
 - reg: See dw_hdmi.txt.
 - reg-io-width: See dw_hdmi.txt. Shall be 4.
@@ -34,6 +35,8 @@ Optional properties
 - clock-names: May contain "cec" as defined in dw_hdmi.txt.
 - clock-names: May contain "grf", power for grf io.
 - clock-names: May contain "vpll", external clock for some hdmi phy.
+- phys: from general PHY binding: the phandle for the PHY device.
+- phy-names: Should be "hdmi" if phys references an external phy.
 
 Example:
 
index 7854fff4fc16687a1e136fda220c331ccdfb3ba9..f426bdb42f18ce8d2f153bbcead91f7b593ad13d 100644 (file)
@@ -79,6 +79,7 @@ Required properties:
   - compatible: value must be one of:
     * "allwinner,sun8i-a83t-dw-hdmi"
     * "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi"
+    * "allwinner,sun50i-h6-dw-hdmi"
   - reg: base address and size of memory-mapped region
   - reg-io-width: See dw_hdmi.txt. Shall be 1.
   - interrupts: HDMI interrupt number
@@ -86,9 +87,14 @@ Required properties:
     * iahb: the HDMI bus clock
     * isfr: the HDMI register clock
     * tmds: TMDS clock
+    * cec: HDMI CEC clock (H6 only)
+    * hdcp: HDCP clock (H6 only)
+    * hdcp-bus: HDCP bus clock (H6 only)
   - clock-names: the clock names mentioned above
-  - resets: phandle to the reset controller
-  - reset-names: must be "ctrl"
+  - resets:
+    * ctrl: HDMI controller reset
+    * hdcp: HDCP reset (H6 only)
+  - reset-names: reset names mentioned above
   - phys: phandle to the DWC HDMI PHY
   - phy-names: must be "phy"
 
@@ -109,6 +115,7 @@ Required properties:
     * allwinner,sun8i-h3-hdmi-phy
     * allwinner,sun8i-r40-hdmi-phy
     * allwinner,sun50i-a64-hdmi-phy
+    * allwinner,sun50i-h6-hdmi-phy
   - reg: base address and size of memory-mapped region
   - clocks: phandles to the clocks feeding the HDMI PHY
     * bus: the HDMI PHY interface clock
@@ -158,6 +165,7 @@ Required properties:
    * allwinner,sun9i-a80-tcon-tv
    * "allwinner,sun50i-a64-tcon-lcd", "allwinner,sun8i-a83t-tcon-lcd"
    * "allwinner,sun50i-a64-tcon-tv", "allwinner,sun8i-a83t-tcon-tv"
+   * allwinner,sun50i-h6-tcon-tv, allwinner,sun8i-r40-tcon-tv
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
  - clocks: phandles to the clocks feeding the TCON.
@@ -220,24 +228,26 @@ It allows display pipeline to be configured in very different ways:
                  \ [3] TCON-TV1 [1] - TVE1/RGB
 
 Note that both TCON TOP references same physical unit. Both mixers can be
-connected to any TCON.
+connected to any TCON. Not all TCON TOP variants support all features.
 
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun8i-r40-tcon-top
+    * allwinner,sun50i-h6-tcon-top
   - reg: base address and size of the memory-mapped region.
   - clocks: phandle to the clocks feeding the TCON TOP
     * bus: TCON TOP interface clock
     * tcon-tv0: TCON TV0 clock
-    * tve0: TVE0 clock
-    * tcon-tv1: TCON TV1 clock
-    * tve1: TVE0 clock
-    * dsi: MIPI DSI clock
+    * tve0: TVE0 clock (R40 only)
+    * tcon-tv1: TCON TV1 clock (R40 only)
+    * tve1: TVE0 clock (R40 only)
+    * dsi: MIPI DSI clock (R40 only)
   - clock-names: clock name mentioned above
   - resets: phandle to the reset line driving the TCON TOP
   - #clock-cells : must contain 1
   - clock-output-names: Names of clocks created for TCON TV0 channel clock,
-    TCON TV1 channel clock and DSI channel clock, in that order.
+    TCON TV1 channel clock (R40 only) and DSI channel clock (R40 only), in
+    that order.
 
 - ports: A ports node with endpoint definitions as defined in
     Documentation/devicetree/bindings/media/video-interfaces.txt. 6 ports should
@@ -381,6 +391,7 @@ Required properties:
     * allwinner,sun8i-v3s-de2-mixer
     * allwinner,sun50i-a64-de2-mixer-0
     * allwinner,sun50i-a64-de2-mixer-1
+    * allwinner,sun50i-h6-de3-mixer-0
   - reg: base address and size of the memory-mapped region.
   - clocks: phandles to the clocks feeding the mixer
     * bus: the mixer interface clock
@@ -415,9 +426,10 @@ Required properties:
     * allwinner,sun8i-v3s-display-engine
     * allwinner,sun9i-a80-display-engine
     * allwinner,sun50i-a64-display-engine
+    * allwinner,sun50i-h6-display-engine
 
   - allwinner,pipelines: list of phandle to the display engine
-    frontends (DE 1.0) or mixers (DE 2.0) available.
+    frontends (DE 1.0) or mixers (DE 2.0/3.0) available.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/display/truly,nt35597.txt b/Documentation/devicetree/bindings/display/truly,nt35597.txt
new file mode 100644 (file)
index 0000000..f39c77e
--- /dev/null
@@ -0,0 +1,59 @@
+Truly model NT35597 DSI display driver
+
+The Truly NT35597 is a generic display driver, currently only configured
+for use in the 2K display on the Qualcomm SDM845 MTP board.
+
+Required properties:
+- compatible: should be "truly,nt35597-2K-display"
+- vdda-supply: phandle of the regulator that provides the supply voltage
+  Power IC supply
+- vdispp-supply: phandle of the regulator that provides the supply voltage
+  for positive LCD bias
+- vdispn-supply: phandle of the regulator that provides the supply voltage
+  for negative LCD bias
+- reset-gpios: phandle of gpio for reset line
+  This should be 8mA, gpio can be configured using mux, pinctrl, pinctrl-names
+  (active low)
+- mode-gpios: phandle of the gpio for choosing the mode of the display
+  for single DSI or Dual DSI
+  This should be low for dual DSI and high for single DSI mode
+- ports: This device has two video ports driven by two DSIs. Their connections
+  are modeled using the OF graph bindings specified in
+  Documentation/devicetree/bindings/graph.txt.
+  - port@0: DSI input port driven by master DSI
+  - port@1: DSI input port driven by secondary DSI
+
+Example:
+
+       dsi@ae94000 {
+               panel@0 {
+                       compatible = "truly,nt35597-2K-display";
+                       reg = <0>;
+                       vdda-supply = <&pm8998_l14>;
+                       vdispp-supply = <&lab_regulator>;
+                       vdispn-supply = <&ibb_regulator>;
+                       pinctrl-names = "default", "suspend";
+                       pinctrl-0 = <&dpu_dsi_active>;
+                       pinctrl-1 = <&dpu_dsi_suspend>;
+
+                       reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;
+                       mode-gpios = <&tlmm 52 GPIO_ACTIVE_HIGH>;
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               port@0 {
+                                       reg = <0>;
+                                       panel0_in: endpoint {
+                                               remote-endpoint = <&dsi0_out>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       panel1_in: endpoint {
+                                               remote-endpoint = <&dsi1_out>;
+                                       };
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt b/Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt
new file mode 100644 (file)
index 0000000..69da211
--- /dev/null
@@ -0,0 +1,43 @@
+Bindings for cadence I3C master block
+=====================================
+
+Required properties:
+--------------------
+- compatible: shall be "cdns,i3c-master"
+- clocks: shall reference the pclk and sysclk
+- clock-names: shall contain "pclk" and "sysclk"
+- interrupts: the interrupt line connected to this I3C master
+- reg: I3C master registers
+
+Mandatory properties defined by the generic binding (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details):
+
+- #address-cells: shall be set to 1
+- #size-cells: shall be set to 0
+
+Optional properties defined by the generic binding (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details):
+
+- i2c-scl-hz
+- i3c-scl-hz
+
+I3C device connected on the bus follow the generic description (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details).
+
+Example:
+
+       i3c-master@0d040000 {
+               compatible = "cdns,i3c-master";
+               clocks = <&coreclock>, <&i3csysclock>;
+               clock-names = "pclk", "sysclk";
+               interrupts = <3 0>;
+               reg = <0x0d040000 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               i2c-scl-hz = <100000>;
+
+               nunchuk: nunchuk@52 {
+                       compatible = "nintendo,nunchuk";
+                       reg = <0x52 0x80000010 0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt
new file mode 100644 (file)
index 0000000..ab729a0
--- /dev/null
@@ -0,0 +1,138 @@
+Generic device tree bindings for I3C busses
+===========================================
+
+This document describes generic bindings that should be used to describe I3C
+busses in a device tree.
+
+Required properties
+-------------------
+
+- #address-cells  - should be <3>. Read more about addresses below.
+- #size-cells     - should be <0>.
+- compatible      - name of the I3C master controller driving the I3C bus
+
+For other required properties e.g. to describe register sets,
+clocks, etc. check the binding documentation of the specific driver.
+The node describing an I3C bus should be named i3c-master.
+
+Optional properties
+-------------------
+
+These properties may not be supported by all I3C master drivers. Each I3C
+master bindings should specify which of them are supported.
+
+- i3c-scl-hz: frequency of the SCL signal used for I3C transfers.
+             When undefined the core sets it to 12.5MHz.
+
+- i2c-scl-hz: frequency of the SCL signal used for I2C transfers.
+             When undefined, the core looks at LVR (Legacy Virtual Register)
+             values of I2C devices described in the device tree to determine
+             the maximum I2C frequency.
+
+I2C devices
+===========
+
+Each I2C device connected to the bus should be described in a subnode. All
+properties described in Documentation/devicetree/bindings/i2c/i2c.txt are
+valid here, but several new properties have been added.
+
+New constraint on existing properties:
+--------------------------------------
+- reg: contains 3 cells
+  + first cell : still encoding the I2C address
+
+  + second cell: shall be 0
+
+  + third cell: shall encode the I3C LVR (Legacy Virtual Register)
+       bit[31:8]: unused/ignored
+       bit[7:5]: I2C device index. Possible values
+       * 0: I2C device has a 50 ns spike filter
+       * 1: I2C device does not have a 50 ns spike filter but supports high
+            frequency on SCL
+       * 2: I2C device does not have a 50 ns spike filter and is not tolerant
+            to high frequencies
+       * 3-7: reserved
+
+       bit[4]: tell whether the device operates in FM (Fast Mode) or FM+ mode
+       * 0: FM+ mode
+       * 1: FM mode
+
+       bit[3:0]: device type
+       * 0-15: reserved
+
+The I2C node unit-address should always match the first cell of the reg
+property: <device-type>@<i2c-address>.
+
+I3C devices
+===========
+
+All I3C devices are supposed to support DAA (Dynamic Address Assignment), and
+are thus discoverable. So, by default, I3C devices do not have to be described
+in the device tree.
+This being said, one might want to attach extra resources to these devices,
+and those resources may have to be described in the device tree, which in turn
+means we have to describe I3C devices.
+
+Another use case for describing an I3C device in the device tree is when this
+I3C device has a static I2C address and we want to assign it a specific I3C
+dynamic address before the DAA takes place (so that other devices on the bus
+can't take this dynamic address).
+
+The I3C device should be names <device-type>@<static-i2c-address>,<i3c-pid>,
+where device-type is describing the type of device connected on the bus
+(gpio-controller, sensor, ...).
+
+Required properties
+-------------------
+- reg: contains 3 cells
+  + first cell : encodes the static I2C address. Should be 0 if the device does
+                not have one (0 is not a valid I2C address).
+
+  + second and third cells: should encode the ProvisionalID. The second cell
+                           contains the manufacturer ID left-shifted by 1.
+                           The third cell contains ORing of the part ID
+                           left-shifted by 16, the instance ID left-shifted
+                           by 12 and the extra information. This encoding is
+                           following the PID definition provided by the I3C
+                           specification.
+
+Optional properties
+-------------------
+- assigned-address: dynamic address to be assigned to this device. This
+                   property is only valid if the I3C device has a static
+                   address (first cell of the reg property != 0).
+
+
+Example:
+
+       i3c-master@d040000 {
+               compatible = "cdns,i3c-master";
+               clocks = <&coreclock>, <&i3csysclock>;
+               clock-names = "pclk", "sysclk";
+               interrupts = <3 0>;
+               reg = <0x0d040000 0x1000>;
+               #address-cells = <3>;
+               #size-cells = <0>;
+               i2c-scl-hz = <100000>;
+
+               /* I2C device. */
+               nunchuk: nunchuk@52 {
+                       compatible = "nintendo,nunchuk";
+                       reg = <0x52 0x0 0x10>;
+               };
+
+               /* I3C device with a static I2C address. */
+               thermal_sensor: sensor@68,39200144004 {
+                       reg = <0x68 0x392 0x144004>;
+                       assigned-address = <0xa>;
+               };
+
+               /*
+                * I3C device without a static I2C address but requiring
+                * resources described in the DT.
+                */
+               sensor@0,39200154004 {
+                       reg = <0x0 0x392 0x154004>;
+                       clocks = <&clock_provider 0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt b/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt
new file mode 100644 (file)
index 0000000..5020eb7
--- /dev/null
@@ -0,0 +1,41 @@
+Bindings for Synopsys DesignWare I3C master block
+=================================================
+
+Required properties:
+--------------------
+- compatible: shall be "snps,dw-i3c-master-1.00a"
+- clocks: shall reference the core_clk
+- interrupts: the interrupt line connected to this I3C master
+- reg: Offset and length of I3C master registers
+
+Mandatory properties defined by the generic binding (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details):
+
+- #address-cells: shall be set to 3
+- #size-cells: shall be set to 0
+
+Optional properties defined by the generic binding (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details):
+
+- i2c-scl-hz
+- i3c-scl-hz
+
+I3C device connected on the bus follow the generic description (see
+Documentation/devicetree/bindings/i3c/i3c.txt for more details).
+
+Example:
+
+       i3c-master@2000 {
+               compatible = "snps,dw-i3c-master-1.00a";
+               #address-cells = <3>;
+               #size-cells = <0>;
+               reg = <0x02000 0x1000>;
+               interrupts = <0>;
+               clocks = <&i3cclk>;
+
+               eeprom@57{
+                       compatible = "atmel,24c01";
+                       reg = <0x57 0x0 0x10>;
+                       pagesize = <0x8>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/media/aspeed-video.txt b/Documentation/devicetree/bindings/media/aspeed-video.txt
new file mode 100644 (file)
index 0000000..78b464a
--- /dev/null
@@ -0,0 +1,26 @@
+* Device tree bindings for Aspeed Video Engine
+
+The Video Engine (VE) embedded in the Aspeed AST2400 and AST2500 SOCs can
+capture and compress video data from digital or analog sources.
+
+Required properties:
+ - compatible:         "aspeed,ast2400-video-engine" or
+                       "aspeed,ast2500-video-engine"
+ - reg:                        contains the offset and length of the VE memory region
+ - clocks:             clock specifiers for the syscon clocks associated with
+                       the VE (ordering must match the clock-names property)
+ - clock-names:                "vclk" and "eclk"
+ - resets:             reset specifier for the syscon reset associated with
+                       the VE
+ - interrupts:         the interrupt associated with the VE on this platform
+
+Example:
+
+video-engine@1e700000 {
+    compatible = "aspeed,ast2500-video-engine";
+    reg = <0x1e700000 0x20000>;
+    clocks = <&syscon ASPEED_CLK_GATE_VCLK>, <&syscon ASPEED_CLK_GATE_ECLK>;
+    clock-names = "vclk", "eclk";
+    resets = <&syscon ASPEED_RESET_VIDEO>;
+    interrupts = <7>;
+};
index a089a0c1ff050534c1a0e01ccfe2df8b88718d18..b3c0635dcd0e22baef91586fd7fe88223c84d10a 100644 (file)
@@ -11,6 +11,8 @@ Required properties:
                        - "allwinner,sun7i-a20-video-engine"
                        - "allwinner,sun8i-a33-video-engine"
                        - "allwinner,sun8i-h3-video-engine"
+                       - "allwinner,sun50i-a64-video-engine"
+                       - "allwinner,sun50i-h5-video-engine"
 - reg                  : register base and length of VE;
 - clocks               : list of clock specifiers, corresponding to entries in
                          the clock-names property;
index 6b910036b57e9303df805e23f7389d1a86c44f19..d0bed6fa901a7aaf9b7b91ae651c006cf0bd11c2 100644 (file)
@@ -9,8 +9,14 @@ Required Properties:
 - clocks: reference to the master clock.
 - clock-names: shall be "mclk".
 
-For further reading on port node refer to
-Documentation/devicetree/bindings/media/video-interfaces.txt.
+The device node must contain one 'port' child node with one 'endpoint' child
+sub-node for its digital output video port, in accordance with the video
+interface bindings defined in:
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Optional endpoint properties:
+- pclk-sample: For information see ../video-interfaces.txt. The value is set to
+  0 if it isn't specified.
 
 Example:
 
@@ -21,11 +27,10 @@ Example:
                        clocks = <&mclk>;
                        clock-names = "mclk";
 
-                       remote = <&pxa_camera>;
                        port {
                                mt9m111_1: endpoint {
-                                       bus-width = <8>;
                                        remote-endpoint = <&pxa_camera>;
+                                       pclk-sample = <1>;
                                };
                        };
                };
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.txt b/Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
new file mode 100644 (file)
index 0000000..f11f28a
--- /dev/null
@@ -0,0 +1,53 @@
+* Sony 1/3.06-Inch 13.13Mp CMOS Digital Image Sensor
+
+The Sony imx214 is a 1/3.06-inch CMOS active pixel digital image sensor with
+an active array size of 4224H x 3200V. It is programmable through an I2C
+interface.
+Image data is sent through MIPI CSI-2, through 2 or 4 lanes at a maximum
+throughput of 1.2Gbps/lane.
+
+
+Required Properties:
+- compatible: Shall be "sony,imx214".
+- reg: I2C bus address of the device. Depending on how the sensor is wired,
+       it shall be <0x10> or <0x1a>;
+- enable-gpios: GPIO descriptor for the enable pin.
+- vdddo-supply: Chip digital IO regulator (1.8V).
+- vdda-supply: Chip analog regulator (2.7V).
+- vddd-supply: Chip digital core regulator (1.12V).
+- clocks: Reference to the xclk clock.
+- clock-frequency: Frequency of the xclk clock.
+
+Optional Properties:
+- flash-leds: See ../video-interfaces.txt
+- lens-focus: See ../video-interfaces.txt
+
+The imx214 device node shall contain one 'port' child node with
+an 'endpoint' subnode. For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Required Properties on endpoint:
+- data-lanes: check ../video-interfaces.txt
+- link-frequencies: check ../video-interfaces.txt
+- remote-endpoint: check ../video-interfaces.txt
+
+Example:
+
+       camera-sensor@1a {
+               compatible = "sony,imx214";
+               reg = <0x1a>;
+               vdddo-supply = <&pm8994_lvs1>;
+               vddd-supply = <&camera_vddd_1v12>;
+               vdda-supply = <&pm8994_l17>;
+               lens-focus = <&ad5820>;
+               enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>;
+               clocks = <&mmcc CAMSS_MCLK0_CLK>;
+               clock-frequency = <24000000>;
+               port {
+                       imx214_ep: endpoint {
+                               data-lanes = <1 2 3 4>;
+                               link-frequencies = /bits/ 64 <480000000>;
+                               remote-endpoint = <&csiphy0_ep>;
+                       };
+               };
+       };
index 00d0d1bf764748381a0d1f02be0b9a97314dde01..b602c4c025e70553f7c19a8d187b0637d125dc74 100644 (file)
@@ -53,7 +53,8 @@
 
 * Subnodes
 The Venus video-codec node must contain two subnodes representing
-video-decoder and video-encoder.
+video-decoder and video-encoder, and one optional firmware subnode.
+Firmware subnode is needed when the platform does not have TrustZone.
 
 Every of video-encoder or video-decoder subnode should have:
 
@@ -79,6 +80,13 @@ Every of video-encoder or video-decoder subnode should have:
                    power domain which is responsible for collapsing
                    and restoring power to the subcore.
 
+The firmware subnode must have:
+
+- iommus:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: A list of phandle and IOMMU specifier pairs.
+
 * An Example
        video-codec@1d00000 {
                compatible = "qcom,msm8916-venus";
@@ -105,4 +113,8 @@ Every of video-encoder or video-decoder subnode should have:
                        clock-names = "core";
                        power-domains = <&mmcc VENUS_CORE1_GDSC>;
                };
+
+               video-firmware {
+                       iommus = <&apps_iommu 0x10b2 0x0>;
+               };
        };
index d329a4e8ac58ed6d2d83c05330f6e3741c19eaf0..0dd84a183ca754bef588608f6c0f220ba00ed07a 100644 (file)
@@ -24,6 +24,8 @@ on Gen3 platforms to a CSI-2 receiver.
    - "renesas,vin-r8a7796" for the R8A7796 device
    - "renesas,vin-r8a77965" for the R8A77965 device
    - "renesas,vin-r8a77970" for the R8A77970 device
+   - "renesas,vin-r8a77980" for the R8A77980 device
+   - "renesas,vin-r8a77990" for the R8A77990 device
    - "renesas,vin-r8a77995" for the R8A77995 device
    - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 or RZ/G1 compatible
      device.
index 2d385b65b275bc584a0b7022c8f4ea8e2b8c6b99..541d936b62e8d735dbce94425e969a3b070aba06 100644 (file)
@@ -12,6 +12,8 @@ Mandatory properties
    - "renesas,r8a7796-csi2" for the R8A7796 device.
    - "renesas,r8a77965-csi2" for the R8A77965 device.
    - "renesas,r8a77970-csi2" for the R8A77970 device.
+   - "renesas,r8a77980-csi2" for the R8A77980 device.
+   - "renesas,r8a77990-csi2" for the R8A77990 device.
 
  - reg: the register base and size for the device registers
  - interrupts: the interrupt for the device
diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.txt b/Documentation/devicetree/bindings/media/rockchip-vpu.txt
new file mode 100644 (file)
index 0000000..35dc464
--- /dev/null
@@ -0,0 +1,29 @@
+device-tree bindings for rockchip VPU codec
+
+Rockchip (Video Processing Unit) present in various Rockchip platforms,
+such as RK3288 and RK3399.
+
+Required properties:
+- compatible: value should be one of the following
+               "rockchip,rk3288-vpu";
+               "rockchip,rk3399-vpu";
+- interrupts: encoding and decoding interrupt specifiers
+- interrupt-names: should be "vepu" and "vdpu"
+- clocks: phandle to VPU aclk, hclk clocks
+- clock-names: should be "aclk" and "hclk"
+- power-domains: phandle to power domain node
+- iommus: phandle to a iommu node
+
+Example:
+SoC-specific DT entry:
+       vpu: video-codec@ff9a0000 {
+               compatible = "rockchip,rk3288-vpu";
+               reg = <0x0 0xff9a0000 0x0 0x800>;
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "vepu", "vdpu";
+               clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>;
+               clock-names = "aclk", "hclk";
+               power-domains = <&power RK3288_PD_VIDEO>;
+               iommus = <&vpu_mmu>;
+       };
index fc5aa263abe53dfe6caffaa40dcb6d501523951a..98a72c0b3c6486ba881dd3f785120f5758cc5ba1 100644 (file)
@@ -5,6 +5,10 @@ Required properties:
 - reg: SPI chip select number for the device.
 - spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz).
 
+Optional properties:
+- vcc-supply: Optional phandle to the vcc regulator to power the adapter,
+  as described in the file ../regulator/regulator.txt
+
 Example:
 
 cxd2880@0 {
diff --git a/Documentation/devicetree/bindings/media/sun6i-csi.txt b/Documentation/devicetree/bindings/media/sun6i-csi.txt
new file mode 100644 (file)
index 0000000..d4ab34f
--- /dev/null
@@ -0,0 +1,59 @@
+Allwinner V3s Camera Sensor Interface
+-------------------------------------
+
+Allwinner V3s SoC features a CSI module(CSI1) with parallel interface.
+
+Required properties:
+  - compatible: value must be one of:
+    * "allwinner,sun6i-a31-csi"
+    * "allwinner,sun8i-h3-csi", "allwinner,sun6i-a31-csi"
+    * "allwinner,sun8i-v3s-csi"
+  - reg: base address and size of the memory-mapped region.
+  - interrupts: interrupt associated to this IP
+  - clocks: phandles to the clocks feeding the CSI
+    * bus: the CSI interface clock
+    * mod: the CSI module clock
+    * ram: the CSI DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset line driving the CSI
+
+The CSI node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Endpoint node properties for CSI
+---------------------------------
+See the video-interfaces.txt for a detailed description of these properties.
+- remote-endpoint      : (required) a phandle to the bus receiver's endpoint
+                          node
+- bus-width:           : (required) must be 8, 10, 12 or 16
+- pclk-sample          : (optional) (default: sample on falling edge)
+- hsync-active         : (required; parallel-only)
+- vsync-active         : (required; parallel-only)
+
+Example:
+
+csi1: csi@1cb4000 {
+       compatible = "allwinner,sun8i-v3s-csi";
+       reg = <0x01cb4000 0x1000>;
+       interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&ccu CLK_BUS_CSI>,
+                <&ccu CLK_CSI1_SCLK>,
+                <&ccu CLK_DRAM_CSI>;
+       clock-names = "bus", "mod", "ram";
+       resets = <&ccu RST_BUS_CSI>;
+
+       port {
+               /* Parallel bus endpoint */
+               csi1_ep: endpoint {
+                       remote-endpoint = <&adv7611_ep>;
+                       bus-width = <16>;
+
+                       /* If hsync-active/vsync-active are missing,
+                          embedded BT.656 sync is used */
+                       hsync-active = <0>; /* Active low */
+                       vsync-active = <0>; /* Active low */
+                       pclk-sample = <1>;  /* Rising */
+               };
+       };
+};
index a43d26d41e04b7f87586b6b825c4307e6ff9f3ba..9d32762c47e1ba6ef1e9465d635247b533fb3e28 100644 (file)
@@ -1,15 +1,32 @@
 Binding for Synopsys IntelliDDR Multi Protocol Memory Controller
 
-This controller has an optional ECC support in half-bus width (16-bit)
-configuration. The ECC controller corrects one bit error and detects
-two bit errors.
+The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit
+bus width configurations.
+
+The Zynq DDR ECC controller has an optional ECC support in half-bus width
+(16-bit) configuration.
+
+These both ECC controllers correct single bit ECC errors and detect double bit
+ECC errors.
 
 Required properties:
- - compatible: Should be 'xlnx,zynq-ddrc-a05'
- - reg: Base address and size of the controllers memory area
+ - compatible: One of:
+       - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller
+       - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller
+ - reg: Should contain DDR controller registers location and length.
+
+Required properties for "xlnx,zynqmp-ddrc-2.40a":
+ - interrupts: Property with a value describing the interrupt number.
 
 Example:
        memory-controller@f8006000 {
                compatible = "xlnx,zynq-ddrc-a05";
                reg = <0xf8006000 0x1000>;
        };
+
+       mc: memory-controller@fd070000 {
+               compatible = "xlnx,zynqmp-ddrc-2.40a";
+               reg = <0x0 0xfd070000 0x0 0x30000>;
+               interrupt-parent = <&gic>;
+               interrupts = <0 112 4>;
+       };
index 188f0373d441bcad97a78943d6d551601b89c4cc..2af4ff95d6bc7f7271b7e179a73235cba792124d 100644 (file)
@@ -32,6 +32,15 @@ Required properties:
 - interrupt-controller: The PMIC has its own internal IRQs
 - #interrupt-cells: Should be set to 1
 
+Supported common regulator properties, see ../regulator/regulator.txt for
+more information:
+- regulator-ramp-delay: sets the ramp up delay in uV/us
+                       AXP20x/DCDC2: 1600, 800
+                       AXP20x/LDO3:  1600, 800
+- regulator-soft-start:        enable the output at the lowest possible voltage and
+                       only then set the desired voltage
+                       AXP20x/LDO3: software-based implementation
+
 Optional properties:
 - x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
                      AXP152/20X: range:  750-1875, Default: 1.5 MHz
diff --git a/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
deleted file mode 100644 (file)
index b93c1e2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-* Atmel Quad Serial Peripheral Interface (QSPI)
-
-Required properties:
-- compatible:     Should be "atmel,sama5d2-qspi".
-- reg:            Should contain the locations and lengths of the base registers
-                  and the mapped memory.
-- reg-names:      Should contain the resource reg names:
-                  - qspi_base: configuration register address space
-                  - qspi_mmap: memory mapped address space
-- interrupts:     Should contain the interrupt for the device.
-- clocks:         The phandle of the clock needed by the QSPI controller.
-- #address-cells: Should be <1>.
-- #size-cells:    Should be <0>.
-
-Example:
-
-spi@f0020000 {
-       compatible = "atmel,sama5d2-qspi";
-       reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
-       reg-names = "qspi_base", "qspi_mmap";
-       interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
-       clocks = <&spi0_clk>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_spi0_default>;
-
-       m25p80@0 {
-               ...
-       };
-};
index 232fa12e90efa59082ad5cb3c66640fc148d9976..7df0dcaccb7d9691e00f741ece0b7fdf547fb6a4 100644 (file)
@@ -29,6 +29,8 @@ file systems on embedded devices.
  - use-advanced-sector-protection: boolean to enable support for the
    advanced sector protection (Spansion: PPB - Persistent Protection
    Bits) locking.
+ - addr-gpios : (optional) List of GPIO descriptors that will be used to
+   address the MSBs address lines. The order goes from LSB to MSB.
 
 For JEDEC compatible devices, the following additional properties
 are defined:
diff --git a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt
new file mode 100644 (file)
index 0000000..fd0ebe4
--- /dev/null
@@ -0,0 +1,27 @@
+RedBoot FLASH Image System (FIS) Partitions
+===========================================
+
+The FLASH Image System (FIS) directory is a flash description
+format closely associated with the RedBoot boot loader.
+
+It uses one single flash eraseblock in the flash to store an index of
+all images in the flash.
+
+This block size will vary depending on flash but is typically
+32 KB in size.
+
+Required properties:
+- compatible : (required) must be "redboot-fis"
+- fis-index-block : (required) a index to the eraseblock containing
+  the FIS directory on this device. On a flash memory with 32KB
+  eraseblocks, 0 means the first eraseblock at 0x00000000, 1 means the
+  second eraseblock at 0x00008000 and so on.
+
+Example:
+
+flash@0 {
+       partitions {
+               compatible = "redboot-fis";
+               fis-index-block = <0>;
+       };
+};
index 7f31fe7e209348ceb04a471e08be0f60b4fff65d..fbd6a4f943ced8f9067ab826e9bc17181c5c371e 100644 (file)
@@ -6,6 +6,7 @@ Required Properties:
  - "renesas,pwm-r8a7744": for RZ/G1N
  - "renesas,pwm-r8a7745": for RZ/G1E
  - "renesas,pwm-r8a774a1": for RZ/G2M
+ - "renesas,pwm-r8a774c0": for RZ/G2E
  - "renesas,pwm-r8a7778": for R-Car M1A
  - "renesas,pwm-r8a7779": for R-Car H1
  - "renesas,pwm-r8a7790": for R-Car H2
index ac955dea00d16c50a89a75922672030dde122cbe..4017527619ab2df4b81fd911b1e2366e0873f3a0 100644 (file)
@@ -15,11 +15,17 @@ Optional input supply properties:
   - inl67-supply: The input supply for REG_LDO3 and REG_LDO4
 
 Any standard regulator properties can be used to configure the single regulator.
+regulator-initial-mode, regulator-allowed-modes and regulator-mode could be
+specified using mode values from dt-bindings/regulator/active-semi,8945a-regulator.h
+file.
 
 The valid names for regulators are:
        REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4.
 
 Example:
+
+#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
+
        pmic@5b {
                compatible = "active-semi,act8945a";
                reg = <0x5b>;
@@ -32,6 +38,18 @@ Example:
                                regulator-min-microvolt = <1350000>;
                                regulator-max-microvolt = <1350000>;
                                regulator-always-on;
+
+                               regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
+                                                         <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                               regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-min-microvolt=<1400000>;
+                                       regulator-suspend-max-microvolt=<1400000>;
+                                       regulator-changeable-in-suspend;
+                                       regulator-mode=<ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                               };
                        };
 
                        vdd_1v2_reg: REG_DCDC2 {
@@ -39,6 +57,14 @@ Example:
                                regulator-min-microvolt = <1100000>;
                                regulator-max-microvolt = <1300000>;
                                regulator-always-on;
+
+                               regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
+                                                         <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                               regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        vdd_3v3_reg: REG_DCDC3 {
@@ -53,6 +79,14 @@ Example:
                                regulator-min-microvolt = <2500000>;
                                regulator-max-microvolt = <2500000>;
                                regulator-always-on;
+
+                               regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
+                                                         <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                               regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
                        };
 
                        vdd_3v3_lp_reg: REG_LDO2 {
diff --git a/Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
new file mode 100644 (file)
index 0000000..91974e6
--- /dev/null
@@ -0,0 +1,82 @@
+Cirrus Logic Lochnagar Audio Development Board
+
+Lochnagar is an evaluation and development board for Cirrus Logic
+Smart CODEC and Amp devices. It allows the connection of most Cirrus
+Logic devices on mini-cards, as well as allowing connection of
+various application processor systems to provide a full evaluation
+platform.  Audio system topology, clocking and power can all be
+controlled through the Lochnagar, allowing the device under test
+to be used in a variety of possible use cases.
+
+This binding document describes the binding for the regulator portion
+of the driver.
+
+Also see these documents for generic binding information:
+  [1] Regulator: ../regulator/regulator.txt
+
+This binding must be part of the Lochnagar MFD binding:
+  [2] ../mfd/cirrus,lochnagar.txt
+
+Optional sub-nodes:
+
+  - VDDCORE : Initialisation data for the VDDCORE regulator, which
+    supplies the CODECs digital core if it has no build regulator for that
+    purpose.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-vddcore"
+      - SYSVDD-supply: Primary power supply for the Lochnagar.
+
+  - MICVDD : Initialisation data for the MICVDD regulator, which
+    supplies the CODECs MICVDD.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-micvdd"
+      - SYSVDD-supply: Primary power supply for the Lochnagar.
+
+  - MIC1VDD, MIC2VDD : Initialisation data for the MICxVDD supplies.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-mic1vdd", "cirrus,lochnagar2-mic2vdd"
+      Optional Properties:
+      - cirrus,micbias-input : A property selecting which of the CODEC
+        minicard micbias outputs should be used, valid values are 1 - 4.
+      - MICBIAS1-supply, MICBIAS2-supply: Regulator supplies for the
+        MICxVDD outputs, supplying the digital microphones, normally
+        supplied from the attached CODEC.
+
+  - VDD1V8 : Recommended fixed regulator for the VDD1V8 regulator, which supplies the
+    CODECs analog and 1.8V digital supplies.
+      Required Properties:
+      - compatible : Should be set to "regulator-fixed"
+      - regulator-min-microvolt : Should be set to 1.8V
+      - regulator-max-microvolt : Should be set to 1.8V
+      - regulator-boot-on
+      - regulator-always-on
+      - vin-supply : Should be set to same supply as SYSVDD
+
+Example:
+
+lochnagar {
+       lochnagar-micvdd: MICVDD {
+               compatible = "cirrus,lochnagar2-micvdd";
+
+               SYSVDD-supply = <&wallvdd>;
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       lochnagar-vdd1v8: VDD1V8 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VDD1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+
+               vin-supply = <&wallvdd>;
+       };
+};
+
diff --git a/Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt b/Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
new file mode 100644 (file)
index 0000000..b8f843f
--- /dev/null
@@ -0,0 +1,143 @@
+MCP16502 PMIC
+
+Required properties:
+- compatible: "microchip,mcp16502"
+- reg: I2C slave address
+- lpm-gpios: GPIO for LPM pin. Note that this GPIO *must* remain high during
+            suspend-to-ram, keeping the PMIC into HIBERNATE mode.
+- regulators: A node that houses a sub-node for each regulator within
+              the device. Each sub-node is identified using the node's
+              name. The content of each sub-node is defined by the
+              standard binding for regulators; see regulator.txt.
+
+Regualtors of MCP16502 PMIC:
+1) VDD_IO      - Buck (1.2 - 3.7 V)
+2) VDD_DDR     - Buck (0.6 - 1.85 V)
+3) VDD_CORE    - Buck (0.6 - 1.85 V)
+4) VDD_OTHER   - BUCK (0.6 - 1.85 V)
+5) LDO1                - LDO  (1.2 - 3.7 V)
+6) LDO2                - LDO  (1.2 - 3.7 V)
+
+Regulator modes:
+2 - FPWM: higher precision, higher consumption
+4 - AutoPFM: lower precision, lower consumption
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+mcp16502@5b {
+       compatible = "microchip,mcp16502";
+       reg = <0x5b>;
+       status = "okay";
+       lpm-gpios = <&pioBU 7 GPIO_ACTIVE_HIGH>;
+
+       regulators {
+               VDD_IO {
+                       regulator-name = "VDD_IO";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <3700000>;
+                       regulator-initial-mode = <2>;
+                       regulator-allowed-modes = <2>, <4>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                               regulator-mode = <4>;
+                       };
+
+                       regulator-state-mem {
+                               regulator-off-in-suspend;
+                               regulator-mode = <4>;
+                       };
+               };
+
+               VDD_DDR {
+                       regulator-name = "VDD_DDR";
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <1850000>;
+                       regulator-initial-mode = <2>;
+                       regulator-allowed-modes = <2>, <4>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                               regulator-mode = <4>;
+                       };
+
+                       regulator-state-mem {
+                               regulator-on-in-suspend;
+                               regulator-mode = <4>;
+                       };
+               };
+
+               VDD_CORE {
+                       regulator-name = "VDD_CORE";
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <1850000>;
+                       regulator-initial-mode = <2>;
+                       regulator-allowed-modes = <2>, <4>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                               regulator-mode = <4>;
+                       };
+
+                       regulator-state-mem {
+                               regulator-off-in-suspend;
+                               regulator-mode = <4>;
+                       };
+               };
+
+               VDD_OTHER {
+                       regulator-name = "VDD_OTHER";
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <1850000>;
+                       regulator-initial-mode = <2>;
+                       regulator-allowed-modes = <2>, <4>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                               regulator-mode = <4>;
+                       };
+
+                       regulator-state-mem {
+                               regulator-off-in-suspend;
+                               regulator-mode = <4>;
+                       };
+               };
+
+               LDO1 {
+                       regulator-name = "LDO1";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <3700000>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                       };
+
+                       regulator-state-mem {
+                               regulator-off-in-suspend;
+                       };
+               };
+
+               LDO2 {
+                       regulator-name = "LDO2";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <3700000>;
+                       regulator-always-on;
+
+                       regulator-state-standby {
+                               regulator-on-in-suspend;
+                       };
+
+                       regulator-state-mem {
+                               regulator-off-in-suspend;
+                       };
+               };
+
+       };
+};
index a7cd36877bfe046905f5d8a4020985a0e6736c7e..0a3f087d584482e27c5521a5aee93b2a119b4cc4 100644 (file)
@@ -33,13 +33,16 @@ Optional properties:
   decreases of any level. This is useful for regulators with exponential
   voltage changes.
 - regulator-soft-start: Enable soft start so that voltage ramps slowly
+- regulator-state-standby sub-root node for Standby mode
+  : equivalent with standby Linux sleep state, which provides energy savings
+  with a relatively quick transition back time.
 - regulator-state-mem sub-root node for Suspend-to-RAM mode
   : suspend to memory, the device goes to sleep, but all data stored in memory,
   only some external interrupt can wake the device.
 - regulator-state-disk sub-root node for Suspend-to-DISK mode
   : suspend to disk, this state operates similarly to Suspend-to-RAM,
   but includes a final step of writing memory contents to disk.
-- regulator-state-[mem/disk] node has following common properties:
+- regulator-state-[mem/disk/standby] node has following common properties:
        - regulator-on-in-suspend: regulator should be on in suspend state.
        - regulator-off-in-suspend: regulator should be off in suspend state.
        - regulator-suspend-min-microvolt: minimum voltage may be set in
@@ -76,8 +79,11 @@ Optional properties:
 - regulator-coupled-with: Regulators with which the regulator
   is coupled. The linkage is 2-way - all coupled regulators should be linked
   with each other. A regulator should not be coupled with its supplier.
-- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
-  in microvolts.
+- regulator-coupled-max-spread: Array of maximum spread between voltages of
+  coupled regulators in microvolts, each value in the array relates to the
+  corresponding couple specified by the regulator-coupled-with property.
+- regulator-max-step-microvolt: Maximum difference between current and target
+  voltages that can be changed safely in a single step.
 
 Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
index deca5e18f304bd2a45723acd4579959a6fe8ce61..ae5f7f057dc3104185d319bd401899cafa09b4c0 100644 (file)
@@ -12,8 +12,8 @@ Required properties:
 
 Optional properties:
 
-  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
-                deasserted before communication to the device starts.
+  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+                 deasserted before communication to the device starts.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/ak4118.txt b/Documentation/devicetree/bindings/sound/ak4118.txt
new file mode 100644 (file)
index 0000000..6e11a2f
--- /dev/null
@@ -0,0 +1,22 @@
+AK4118 S/PDIF transceiver
+
+This device supports I2C mode.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak4118"
+- reg : The I2C address of the device for I2C
+- reset-gpios: A GPIO specifier for the reset pin
+- irq-gpios: A GPIO specifier for the IRQ pin
+
+Example:
+
+&i2c {
+       ak4118: ak4118@13 {
+               #sound-dai-cells = <0>;
+               compatible = "asahi-kasei,ak4118";
+               reg = <0x13>;
+               reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>
+               irq-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
new file mode 100644 (file)
index 0000000..2e6cb7d
--- /dev/null
@@ -0,0 +1,22 @@
+* Amlogic Audio SPDIF Input
+
+Required properties:
+- compatible: 'amlogic,axg-spdifin'
+- interrupts: interrupt specifier for the spdif input.
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+  * "pclk" : peripheral clock.
+  * "refclk" : spdif input reference clock
+- #sound-dai-cells: must be 0.
+
+Example on the A113 SoC:
+
+spdifin: audio-controller@400 {
+       compatible = "amlogic,axg-spdifin";
+       reg = <0x0 0x400 0x0 0x30>;
+       #sound-dai-cells = <0>;
+       interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
+       clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
+                <&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
+       clock-names = "pclk", "refclk";
+};
index 7e63e53a901c65db905b4ded8b46462de43a5267..269682619a702dc38d864d1ca78b4775465c8a2e 100644 (file)
@@ -32,7 +32,9 @@ Required properties:
 Optional properties:
 - pa-gpios: GPIO used to control external amplifier.
 
+-----------------------
 Example: Single DAI case
+-----------------------
 
        sound_card {
                compatible = "audio-graph-card";
@@ -61,7 +63,9 @@ Example: Single DAI case
                };
        };
 
+-----------------------
 Example: Multi DAI case
+-----------------------
 
        sound-card {
                compatible = "audio-graph-card";
@@ -130,3 +134,204 @@ Example: Multi DAI case
                };
        };
 
+
+-----------------------
+Example: Sampling Rate Conversion
+-----------------------
+
+       sound_card {
+               compatible = "audio-graph-card";
+
+               label = "sound-card";
+               prefix = "codec";
+               routing = "codec Playback", "DAI0 Playback",
+                         "DAI0 Capture",   "codec Capture";
+               convert-rate = <48000>;
+
+               dais = <&cpu_port>;
+       };
+
+       audio-codec {
+               ...
+               port {
+                       codec_endpoint: endpoint {
+                               remote-endpoint = <&cpu_endpoint>;
+                       };
+               };
+       };
+
+       dai-controller {
+               ...
+               cpu_port: port {
+                       cpu_endpoint: endpoint {
+                               remote-endpoint = <&codec_endpoint>;
+
+                               dai-format = "left_j";
+                               ...
+                       };
+               };
+       };
+
+-----------------------
+Example: 2 CPU 1 Codec (Mixing)
+-----------------------
+
+       sound_card {
+               compatible = "audio-graph-card";
+
+               label = "sound-card";
+               routing = "codec Playback", "DAI0 Playback",
+                         "codec Playback", "DAI1 Playback",
+                         "DAI0 Capture",   "codec Capture";
+
+               dais = <&cpu_port>;
+       };
+
+       audio-codec {
+               ...
+
+               audio-graph-card,prefix = "codec";
+               audio-graph-card,convert-rate = <48000>;
+               port {
+                       reg = <0>;
+                       codec_endpoint0: endpoint@0 {
+                               remote-endpoint = <&cpu_endpoint0>;
+                       };
+                       codec_endpoint1: endpoint@1 {
+                               remote-endpoint = <&cpu_endpoint1>;
+                       };
+               };
+       };
+
+       dai-controller {
+               ...
+               cpu_port: port {
+                       cpu_endpoint0: endpoint@0 {
+                               remote-endpoint = <&codec_endpoint0>;
+
+                               dai-format = "left_j";
+                               ...
+                       };
+                       cpu_endpoint1: endpoint@1 {
+                               remote-endpoint = <&codec_endpoint1>;
+
+                               dai-format = "left_j";
+                               ...
+                       };
+               };
+       };
+
+-----------------------
+Example: Multi DAI with DPCM
+-----------------------
+
+       CPU0 ------ ak4613
+       CPU1 ------ HDMI
+       CPU2 ------ PCM3168A-p  /* DPCM 1ch/2ch */
+       CPU3 --/                /* DPCM 3ch/4ch */
+       CPU4 --/                /* DPCM 5ch/6ch */
+       CPU5 --/                /* DPCM 7ch/8ch */
+       CPU6 ------ PCM3168A-c
+
+       sound_card: sound {
+               compatible = "audio-graph-card";
+
+               label = "sound-card";
+
+               routing =       "pcm3168a Playback", "DAI2 Playback",
+                               "pcm3168a Playback", "DAI3 Playback",
+                               "pcm3168a Playback", "DAI4 Playback",
+                               "pcm3168a Playback", "DAI5 Playback";
+
+               dais = <&snd_port0      /* ak4613 */
+                       &snd_port1      /* HDMI0  */
+                       &snd_port2      /* pcm3168a playback */
+                       &snd_port3      /* pcm3168a capture  */
+                       >;
+       };
+
+       ak4613: codec@10 {
+               ...
+               port {
+                       ak4613_endpoint: endpoint {
+                               remote-endpoint = <&rsnd_endpoint0>;
+                       };
+               };
+       };
+
+       pcm3168a: audio-codec@44 {
+               ...
+               audio-graph-card,prefix = "pcm3168a";
+               audio-graph-card,convert-channels = <8>; /* TDM Split */
+               ports {
+                       port@0 {
+                               reg = <0>;
+                               pcm3168a_endpoint_p1: endpoint@1 {
+                                       remote-endpoint = <&rsnd_endpoint2>;
+                                       ...
+                               };
+                               pcm3168a_endpoint_p2: endpoint@2 {
+                                       remote-endpoint = <&rsnd_endpoint3>;
+                                       ...
+                               };
+                               pcm3168a_endpoint_p3: endpoint@3 {
+                                       remote-endpoint = <&rsnd_endpoint4>;
+                                       ...
+                               };
+                               pcm3168a_endpoint_p4: endpoint@4 {
+                                       remote-endpoint = <&rsnd_endpoint5>;
+                                       ...
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               pcm3168a_endpoint_c: endpoint {
+                                       remote-endpoint = <&rsnd_endpoint6>;
+                                       ...
+                               };
+                       };
+               };
+       };
+
+       &sound {
+               ports {
+                       snd_port0: port@0 {
+                               rsnd_endpoint0: endpoint {
+                                       remote-endpoint = <&ak4613_endpoint>;
+                                       ...
+                               };
+                       };
+                       snd_port1: port@1 {
+                               rsnd_endpoint1: endpoint {
+                                       remote-endpoint = <&dw_hdmi0_snd_in>;
+                                       ...
+                               };
+                       };
+                       snd_port2: port@2 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               rsnd_endpoint2: endpoint@2 {
+                                       remote-endpoint = <&pcm3168a_endpoint_p1>;
+                                       ...
+                               };
+                               rsnd_endpoint3: endpoint@3 {
+                                       remote-endpoint = <&pcm3168a_endpoint_p2>;
+                                       ...
+                               };
+                               rsnd_endpoint4: endpoint@4 {
+                                       remote-endpoint = <&pcm3168a_endpoint_p3>;
+                                       ...
+                               };
+                               rsnd_endpoint5: endpoint@5 {
+                                       remote-endpoint = <&pcm3168a_endpoint_p4>;
+                                       ...
+                               };
+                       };
+                       snd_port3: port@6 {
+                               rsnd_endpoint6: endpoint {
+                                       remote-endpoint = <&pcm3168a_endpoint_c>;
+                                       ...
+                               };
+                       };
+               };
+       };
index 441dd6f29df13ba987316c5b6a4102c7bf73e636..62d42768a00bf8397204e1514c665f45446054b0 100644 (file)
@@ -77,11 +77,9 @@ Example 2. 2 CPU 1 Codec (Mixing)
                compatible = "audio-graph-scu-card";
 
                label = "sound-card";
-               prefix = "codec";
                routing = "codec Playback", "DAI0 Playback",
                          "codec Playback", "DAI1 Playback",
                          "DAI0 Capture",   "codec Capture";
-               convert-rate = <48000>;
 
                dais = <&cpu_port0
                        &cpu_port1>;
@@ -90,6 +88,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
        audio-codec {
                ...
 
+               audio-graph-card,prefix = "codec";
+               audio-graph-card,convert-rate = <48000>;
                port {
                        codec_endpoint0: endpoint {
                                remote-endpoint = <&cpu_endpoint0>;
index 6b222f9b8ef535b6477e6c236b4ed8ac43d2fe02..c33770ec4c3c726a750c8e5a6b978e5202906149 100644 (file)
@@ -10,8 +10,8 @@ Required properties:
 
 Optional properties:
 
-  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
-                deasserted before communication to the codec starts.
+  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+                 deasserted before communication to the codec starts.
 
 Example:
 
index 46bc9829c71aabe7041bbe4af60d586aa590c1ef..b279b6072bd549b4c9bfc108c9654a4d1484db51 100644 (file)
@@ -30,6 +30,11 @@ Optional properties:
 - ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
 - tx-num-evt : FIFO levels.
 - rx-num-evt : FIFO levels.
+- dismod : Specify the drive on TX pin during inactive slots
+       0 : 3-state
+       2 : logic low
+       3 : logic high
+       Defaults to 'logic low' when the property is not present
 - sram-size-playback : size of sram to be allocated during playback
 - sram-size-capture  : size of sram to be allocated during capture
 - interrupts : Interrupt numbers for McASP
index e957b41367160bf1a01437f74d3b2dd494ebe887..32e8710372696d5ba4a4137fe373a4d1cecbfa4b 100644 (file)
@@ -9,6 +9,7 @@ Optional properties:
        - dmicen-gpios: GPIO specifier for dmic to control start and stop
        - num-channels: Number of microphones on this DAI
        - wakeup-delay-ms: Delay (in ms) after enabling the DMIC
+       - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
 
 Example node:
 
@@ -17,4 +18,5 @@ Example node:
                dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
                num-channels = <1>;
                wakeup-delay-ms <50>;
+               modeswitch-delay-ms <35>;
        };
index dd9e59738e0820b4db57b737e34a37c11c90fd55..2e726b9838450f3284bca7db95c0a876382625c4 100644 (file)
@@ -35,13 +35,13 @@ Required properties:
 
   - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
                          that SAI will work in the synchronous mode (sync Tx
-                         with Rx) which means both the transimitter and the
+                         with Rx) which means both the transmitter and the
                          receiver will send and receive data by following
                          receiver's bit clocks and frame sync clocks.
 
   - fsl,sai-asynchronous: This is a boolean property. If present, indicating
                          that SAI will work in the asynchronous mode, which
-                         means both transimitter and receiver will send and
+                         means both transmitter and receiver will send and
                          receive data by following their own bit clocks and
                          frame sync clocks separately.
 
@@ -58,8 +58,8 @@ Optional properties (for mx6ul):
 Note:
 - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
   default synchronous mode (sync Rx with Tx) will be used, which means both
-  transimitter and receiver will send and receive data by following clocks
-  of transimitter.
+  transmitter and receiver will send and receive data by following clocks
+  of transmitter.
 - fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
 
 Example:
index 5f4e68ca228cb7aec18555533e59a51eecd62ec7..ff98a0cb5b3f242d512fdcb1f80893e29cedbf91 100644 (file)
@@ -7,6 +7,8 @@ Required properties:
        <L3 interconnect address, size>;
 - interrupts: Interrupt number for McPDM
 - ti,hwmods: Name of the hwmod associated to the McPDM
+- clocks:  phandle for the pdmclk provider, likely <&twl6040>
+- clock-names: Must be "pdmclk"
 
 Example:
 
@@ -18,3 +20,11 @@ mcpdm: mcpdm@40132000 {
        interrupt-parent = <&gic>;
        ti,hwmods = "mcpdm";
 };
+
+In board DTS file the pdmclk needs to be added:
+
+&mcpdm {
+       clocks = <&twl6040>;
+       clock-names = "pdmclk";
+       status = "okay";
+};
index 90fcb8523099c7e80ae8f91a2f8b90b57d0a27a7..97de66932d44d22f3a5664e5550780093b412873 100644 (file)
@@ -9,9 +9,15 @@ Required properties:
 - reg : the I2C address of the device for I2C, the chip select
         number for SPI.
 
+Optional properties:
+
+- ti,out-single-ended: "true" if output is single-ended;
+                       "false" or not specified if output is differential.
+
 Examples:
 
        pcm3060: pcm3060@46 {
                 compatible = "ti,pcm3060";
                 reg = <0x46>;
+                ti,out-single-ended = "true";
        };
index f9c7bd8c1bc0fa8f3bb61cbe95ec09639d66122d..9f5378c51686d31aae805b6b0020f3951a2fef05 100644 (file)
@@ -27,6 +27,28 @@ used by the apr service device.
        Value type: <u32>
        Definition: Must be 1
 
+== ASM DAI is subnode of "dais" and represent a dai, it includes board specific
+configuration of each dai. Must contain the following properties.
+
+- reg
+       Usage: required
+       Value type: <u32>
+       Definition: Must be dai id
+
+- direction:
+       Usage: Required for Compress offload dais
+       Value type: <u32>
+       Definition: Specifies the direction of the dai stream
+                       0 for both tx and rx
+                       1 for only tx (Capture/Encode)
+                       2 for only rx (Playback/Decode)
+
+- is-compress-dai:
+       Usage: Required for Compress offload dais
+       Value type: <boolean>
+       Definition: present for Compress offload dais
+
+
 = EXAMPLE
 
 q6asm@7 {
@@ -35,5 +57,10 @@ q6asm@7 {
        q6asmdai: dais {
                compatible = "qcom,q6asm-dais";
                #sound-dai-cells = <1>;
+               mm@0 {
+                       reg = <0>;
+                       direction = <2>;
+                       is-compress-dai;
+               };
        };
 };
index d92b705e7917db2bd192d331fa58a1d99a28f743..648d43e1b1e9544fa1d30c909964406b8900a584 100644 (file)
@@ -39,15 +39,7 @@ This is example of
 Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
 Capture:  [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
 
-       &rcar_sound {
-               ...
-               rcar_sound,dai {
-                       dai0 {
-                               playback = <&ssi0 &src2 &dvc0>;
-                               capture  = <&ssi1 &src3 &dvc1>;
-                       };
-               };
-       };
+see "Example: simple sound card"
 
 You can use below.
 ${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
@@ -83,29 +75,8 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
 **     Asynchronous mode
 ------------------
 
-You need to use "simple-scu-audio-card" sound card for it.
-example)
-
-       sound {
-               compatible = "simple-scu-audio-card";
-               ...
-               /*
-                * SRC Asynchronous mode setting
-                * Playback:
-                * All input data will be converted to 48kHz
-                * Capture:
-                * Inputed 48kHz data will be converted to
-                * system specified Hz
-                */
-               simple-audio-card,convert-rate = <48000>;
-               ...
-               simple-audio-card,cpu {
-                       sound-dai = <&rcar_sound>;
-               };
-               simple-audio-card,codec {
-                       ...
-               };
-       };
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
+see "Example: simple sound card for Asynchronous mode"
 
 ------------------
 **     Synchronous mode
@@ -141,26 +112,8 @@ For more detail information, see below
        ${LINUX}/sound/soc/sh/rcar/ctu.c
         - comment of header
 
-You need to use "simple-scu-audio-card" sound card for it.
-example)
-
-       sound {
-               compatible = "simple-scu-audio-card";
-               ...
-               /*
-                * CTU setting
-                * All input data will be converted to 2ch
-                * as output data
-                */
-               simple-audio-card,convert-channels = <2>;
-               ...
-               simple-audio-card,cpu {
-                       sound-dai = <&rcar_sound>;
-               };
-               simple-audio-card,codec {
-                       ...
-               };
-       };
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
+see "Example: simple sound card for channel convert"
 
 Ex) Exchange output channel
  Input -> Output
@@ -190,42 +143,13 @@ and these sounds will be merged by MIX.
        aplay -D plughw:0,0 xxxx.wav &
        aplay -D plughw:0,1 yyyy.wav
 
-You need to use "simple-scu-audio-card" sound card for it.
+You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
 Ex)
        [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
                                    |
        [MEM] -> [SRC2] -> [CTU03] -+
 
-       sound {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               compatible = "simple-scu-audio-card";
-               ...
-               simple-audio-card,cpu@0 {
-                       reg = <0>;
-                       sound-dai = <&rcar_sound 0>;
-               };
-               simple-audio-card,cpu@1 {
-                       reg = <1>;
-                       sound-dai = <&rcar_sound 1>;
-               };
-               simple-audio-card,codec {
-                       ...
-               };
-       };
-
-       &rcar_sound {
-               ...
-               rcar_sound,dai {
-                       dai0 {
-                               playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
-                       };
-                       dai1 {
-                               playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
-                       };
-               };
-       };
+see "Example: simple sound card for MIXer"
 
 =============================================
 * DVC (Digital Volume and Mute Function)
@@ -257,15 +181,31 @@ Volume Ramp
 * SSIU (Serial Sound Interface Unit)
 =============================================
 
-There is no DT settings for SSIU, because SSIU will be automatically
-selected via SSI.
 SSIU can avoid some under/over run error, because it has some buffer.
 But you can't use it if SSI was PIO mode.
-In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
+In DMA mode, you can select not to use SSIU by using "no-busif" via SSI.
 
-       &ssi0 {
-               no-busif;
-       };
+SSIU handles BUSIF which will be used for TDM Split mode.
+This driver is assuming that audio-graph card will be used.
+
+TDM Split mode merges 4 sounds. You can see 4 sound interface on system,
+and these sounds will be merged SSIU/SSI.
+
+       aplay -D plughw:0,0 xxxx.wav &
+       aplay -D plughw:0,1 xxxx.wav &
+       aplay -D plughw:0,2 xxxx.wav &
+       aplay -D plughw:0,3 xxxx.wav
+
+                 2ch                     8ch
+       [MEM] -> [SSIU 30] -+-> [SSIU 3] --> [Codec]
+                 2ch       |
+       [MEM] -> [SSIU 31] -+
+                 2ch       |
+       [MEM] -> [SSIU 32] -+
+                 2ch       |
+       [MEM] -> [SSIU 33] -+
+
+see "Example: simple sound card for TDM Split"
 
 =============================================
 * SSI (Serial Sound Interface)
@@ -304,14 +244,7 @@ This is example if SSI1 want to share WS pin with SSI0
 You can use Multi-SSI.
 This is example of SSI0/SSI1/SSI2 (= for 6ch)
 
-       &rcar_sound {
-               ...
-               rcar_sound,dai {
-                       dai0 {
-                               playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
-                       };
-               };
-       };
+see "Example: simple sound card for Multi channel"
 
 ** TDM-SSI
 
@@ -319,19 +252,7 @@ You can use TDM with SSI.
 This is example of TDM 6ch.
 Driver can automatically switches TDM <-> stereo mode in this case.
 
-       rsnd_tdm: sound {
-               compatible = "simple-audio-card";
-               ...
-               simple-audio-card,cpu {
-                       /* system can use TDM 6ch */
-                       dai-tdm-slot-num = <6>;
-                       sound-dai = <&rcar_sound>;
-               };
-               simple-audio-card,codec {
-                       ...
-               };
-       };
-
+see "Example: simple sound card for TDM"
 
 =============================================
 Required properties:
@@ -346,6 +267,7 @@ Required properties:
                                    - "renesas,rcar_sound-r8a7744" (RZ/G1N)
                                    - "renesas,rcar_sound-r8a7745" (RZ/G1E)
                                    - "renesas,rcar_sound-r8a774a1" (RZ/G2M)
+                                   - "renesas,rcar_sound-r8a774c0" (RZ/G2E)
                                    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
                                    - "renesas,rcar_sound-r8a7779" (R-Car H1)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
@@ -356,6 +278,7 @@ Required properties:
                                    - "renesas,rcar_sound-r8a7796" (R-Car M3-W)
                                    - "renesas,rcar_sound-r8a77965" (R-Car M3-N)
                                    - "renesas,rcar_sound-r8a77990" (R-Car E3)
+                                   - "renesas,rcar_sound-r8a77995" (R-Car D3)
 - reg                          : Should contain the register physical address.
                                  required register is
                                   SRU/ADG/SSI      if generation1
@@ -363,6 +286,9 @@ Required properties:
 - rcar_sound,ssi               : Should contain SSI feature.
                                  The number of SSI subnode should be same as HW.
                                  see below for detail.
+- rcar_sound,ssiu              : Should contain SSIU feature.
+                                 The number of SSIU subnode should be same as HW.
+                                 see below for detail.
 - rcar_sound,src               : Should contain SRC feature.
                                  The number of SRC subnode should be same as HW.
                                  see below for detail.
@@ -402,8 +328,13 @@ SSI subnode properties:
 - no-busif                     : BUSIF is not ussed when [mem -> SSI] via DMA case
 - dma                          : Should contain Audio DMAC entry
 - dma-names                    : SSI  case "rx"  (=playback), "tx"  (=capture)
+                                 Deprecated: see SSIU subnode properties
                                  SSIU case "rxu" (=playback), "txu" (=capture)
 
+SSIU subnode properties:
+- dma                          : Should contain Audio DMAC entry
+- dma-names                    : "rx" (=playback), "tx" (=capture)
+
 SRC subnode properties:
 - dma                          : Should contain Audio DMAC entry
 - dma-names                    : "rx" (=playback), "tx" (=capture)
@@ -532,56 +463,55 @@ rcar_sound: sound@ec500000 {
                };
        };
 
+       rcar_sound,ssiu {
+               ssiu00: ssiu-0 {
+                       dmas = <&audma0 0x15>, <&audma1 0x16>;
+                       dma-names = "rx", "tx";
+               };
+               ssiu01: ssiu-1 {
+                       dmas = <&audma0 0x35>, <&audma1 0x36>;
+                       dma-names = "rx", "tx";
+               };
+
+               ...
+
+               ssiu95: ssiu-49 {
+                       dmas = <&audma0 0xA5>, <&audma1 0xA6>;
+                       dma-names = "rx", "tx";
+               };
+               ssiu96: ssiu-50 {
+                       dmas = <&audma0 0xA7>, <&audma1 0xA8>;
+                       dma-names = "rx", "tx";
+               };
+               ssiu97: ssiu-51 {
+                       dmas = <&audma0 0xA9>, <&audma1 0xAA>;
+                       dma-names = "rx", "tx";
+               };
+       };
+
        rcar_sound,ssi {
                ssi0: ssi-0 {
                        interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
-                       dma-names = "rx", "tx", "rxu", "txu";
+                       dmas = <&audma0 0x01>, <&audma1 0x02>;
+                       dma-names = "rx", "tx";
                };
                ssi1: ssi-1 {
                        interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi2: ssi-2 {
-                       interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi3: ssi-3 {
-                       interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi4: ssi-4 {
-                       interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi5: ssi-5 {
-                       interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi6: ssi-6 {
-                       interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
-                       dma-names = "rx", "tx", "rxu", "txu";
-               };
-               ssi7: ssi-7 {
-                       interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
-                       dma-names = "rx", "tx", "rxu", "txu";
+                       dmas = <&audma0 0x03>, <&audma1 0x04>;
+                       dma-names = "rx", "tx";
                };
+
+               ...
+
                ssi8: ssi-8 {
                        interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
-                       dma-names = "rx", "tx", "rxu", "txu";
+                       dmas = <&audma0 0x11>, <&audma1 0x12>;
+                       dma-names = "rx", "tx";
                };
                ssi9: ssi-9 {
                        interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
-                       dma-names = "rx", "tx", "rxu", "txu";
+                       dmas = <&audma0 0x13>, <&audma1 0x14>;
+                       dma-names = "rx", "tx";
                };
        };
 
@@ -646,26 +576,175 @@ Example: simple sound card
        shared-pin;
 };
 
+=============================================
+Example: simple sound card for Asynchronous mode
+=============================================
+
+sound {
+       compatible = "simple-scu-audio-card";
+       ...
+       /*
+        * SRC Asynchronous mode setting
+        * Playback:
+        * All input data will be converted to 48kHz
+        * Capture:
+        * Inputed 48kHz data will be converted to
+        * system specified Hz
+        */
+       simple-audio-card,convert-rate = <48000>;
+       ...
+       simple-audio-card,cpu {
+               sound-dai = <&rcar_sound>;
+       };
+       simple-audio-card,codec {
+               ...
+       };
+};
+
+=============================================
+Example: simple sound card for channel convert
+=============================================
+
+sound {
+       compatible = "simple-scu-audio-card";
+       ...
+       /*
+        * CTU setting
+        * All input data will be converted to 2ch
+        * as output data
+        */
+       simple-audio-card,convert-channels = <2>;
+       ...
+       simple-audio-card,cpu {
+               sound-dai = <&rcar_sound>;
+       };
+       simple-audio-card,codec {
+               ...
+       };
+};
+
+=============================================
+Example: simple sound card for MIXer
+=============================================
+
+sound {
+       compatible = "simple-scu-audio-card";
+       ...
+       simple-audio-card,cpu@0 {
+               sound-dai = <&rcar_sound 0>;
+       };
+       simple-audio-card,cpu@1 {
+               sound-dai = <&rcar_sound 1>;
+       };
+       simple-audio-card,codec {
+               ...
+       };
+};
+
+&rcar_sound {
+       ...
+       rcar_sound,dai {
+               dai0 {
+                       playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
+               };
+               dai1 {
+                       playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
+               };
+       };
+};
+
 =============================================
 Example: simple sound card for TDM
 =============================================
 
-       rsnd_tdm: sound {
-               compatible = "simple-audio-card";
+rsnd_tdm: sound {
+       compatible = "simple-audio-card";
 
-               simple-audio-card,format = "left_j";
-               simple-audio-card,bitclock-master = <&sndcodec>;
-               simple-audio-card,frame-master = <&sndcodec>;
+       simple-audio-card,format = "left_j";
+       simple-audio-card,bitclock-master = <&sndcodec>;
+       simple-audio-card,frame-master = <&sndcodec>;
 
-               sndcpu: simple-audio-card,cpu {
-                       sound-dai = <&rcar_sound>;
-                       dai-tdm-slot-num = <6>;
+       sndcpu: simple-audio-card,cpu {
+               sound-dai = <&rcar_sound>;
+               dai-tdm-slot-num = <6>;
+       };
+
+       sndcodec: simple-audio-card,codec {
+               sound-dai = <&xxx>;
+       };
+};
+
+=============================================
+Example: simple sound card for TDM Split
+=============================================
+
+sound_card: sound {
+       compatible = "audio-graph-scu-card";
+       prefix = "xxxx";
+       routing = "xxxx Playback", "DAI0 Playback",
+                 "xxxx Playback", "DAI1 Playback",
+                 "xxxx Playback", "DAI2 Playback",
+                 "xxxx Playback", "DAI3 Playback";
+       convert-channels = <8>; /* TDM Split */
+
+       dais = <&rsnd_port0     /* playback ch1/ch2 */
+               &rsnd_port1     /* playback ch3/ch4 */
+               &rsnd_port2     /* playback ch5/ch6 */
+               &rsnd_port3     /* playback ch7/ch8 */
+               >;
+};
+
+audio-codec {
+       ...
+       port {
+               codec_0: endpoint@1 {
+                       remote-endpoint = <&rsnd_ep0>;
+               };
+               codec_1: endpoint@2 {
+                       remote-endpoint = <&rsnd_ep1>;
+               };
+               codec_2: endpoint@3 {
+                       remote-endpoint = <&rsnd_ep2>;
+               };
+               codec_3: endpoint@4 {
+                       remote-endpoint = <&rsnd_ep3>;
                };
+       };
+};
 
-               sndcodec: simple-audio-card,codec {
-                       sound-dai = <&xxx>;
+&rcar_sound {
+       ...
+       ports {
+               rsnd_port0: port@0 {
+                       rsnd_ep0: endpoint {
+                               remote-endpoint = <&codec_0>;
+                               ...
+                               playback = <&ssiu30 &ssi3>;
+                       };
+               };
+               rsnd_port1: port@1 {
+                       rsnd_ep1: endpoint {
+                               remote-endpoint = <&codec_1>;
+                               ...
+                               playback = <&ssiu31 &ssi3>;
+                       };
+               };
+               rsnd_port2: port@2 {
+                       rsnd_ep2: endpoint {
+                               remote-endpoint = <&codec_2>;
+                               ...
+                               playback = <&ssiu32 &ssi3>;
+                       };
+               };
+               rsnd_port3: port@3 {
+                       rsnd_ep3: endpoint {
+                               remote-endpoint = <&codec_3>;
+                               ...
+                               playback = <&ssiu33 &ssi3>;
+                       };
                };
        };
+};
 
 =============================================
 Example: simple sound card for Multi channel
index 92b986ca337bf82ad048106e4157aea981be4c7a..56bc85232c49d79dd7579c32c25976fc49364fda 100644 (file)
@@ -35,14 +35,14 @@ Pins on the device (for linking into audio routes):
 
 Example:
 
-alc5631: alc5631@1a {
+alc5631: audio-codec@1a {
        compatible = "realtek,alc5631";
        reg = <0x1a>;
 };
 
 or
 
-rt5631: rt5631@1a {
+rt5631: audio-codec@1a {
        compatible = "realtek,rt5631";
        reg = <0x1a>;
 };
index 23386446c63d6fde5b63c35b8badd989a8ada56b..2a55e9133408215f1c46b806a2043b0bc4763a25 100644 (file)
@@ -10,6 +10,10 @@ Required properties:
 
 - interrupts : The CODEC's interrupt output.
 
+- avdd-supply: Power supply for AVDD, providing 1.8V.
+
+- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
+
 Optional properties:
 
 - "realtek,dc_offset_l_manual"
@@ -51,4 +55,6 @@ rt5663: codec@12 {
        compatible = "realtek,rt5663";
        reg = <0x12>;
        interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+       avdd-supply = <&pp1800_a_alc5662>;
+       cpvdd-supply = <&pp3500_a_alc5662>;
 };
index 8647edae7af038a64d2eadf5a1d6a403ecc2cacf..7182ac4f1e6588fd502e42171b892dc04fc13b6d 100644 (file)
@@ -4,9 +4,14 @@ Required properties:
 - compatible : "dioo,dio2125" or "simple-audio-amplifier"
 - enable-gpios : the gpio connected to the enable pin of the simple amplifier
 
+Optional properties:
+- VCC-supply   : power supply for the device, as covered
+                 in Documentation/devicetree/bindings/regulator/regulator.txt
+
 Example:
 
 amp: analog-amplifier {
        compatible = "simple-audio-amplifier";
+       VCC-supply = <&regulator>;
        enable-gpios = <&gpio GPIOH_3 0>;
 };
index a4c72d09cd45718e6ce5197d6f8fce1e782deeac..4629c8f8a6b63f68a69440a3bfa07bf88aeb4f62 100644 (file)
@@ -95,7 +95,9 @@ Optional CPU/CODEC subnodes properties:
                                          initialization. It is useful for some aCPUs with
                                          fixed clocks.
 
+-------------------------------------------
 Example 1 - single DAI link:
+-------------------------------------------
 
 sound {
        compatible = "simple-audio-card";
@@ -138,7 +140,9 @@ sh_fsi2: sh_fsi2@ec230000 {
        interrupts = <0 146 0x4>;
 };
 
+-------------------------------------------
 Example 2 - many DAI links:
+-------------------------------------------
 
 sound {
        compatible = "simple-audio-card";
@@ -176,8 +180,10 @@ sound {
        };
 };
 
+-------------------------------------------
 Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
 through TPA6130A2 amplifier to headphones:
+-------------------------------------------
 
 &i2c0 {
        codec: tlv320dac3100@18 {
@@ -210,3 +216,134 @@ sound {
                clocks = ...
        };
 };
+
+-------------------------------------------
+Example 4. Sampling Rate Conversion
+-------------------------------------------
+
+sound {
+       compatible = "simple-audio-card";
+
+       simple-audio-card,name = "rsnd-ak4643";
+       simple-audio-card,format = "left_j";
+       simple-audio-card,bitclock-master = <&sndcodec>;
+       simple-audio-card,frame-master = <&sndcodec>;
+
+       simple-audio-card,convert-rate = <48000>;
+
+       simple-audio-card,prefix = "ak4642";
+       simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+                       "DAI0 Capture", "ak4642 Capture";
+
+       sndcpu: simple-audio-card,cpu {
+               sound-dai = <&rcar_sound>;
+       };
+
+       sndcodec: simple-audio-card,codec {
+               sound-dai = <&ak4643>;
+               system-clock-frequency = <11289600>;
+       };
+};
+
+-------------------------------------------
+Example 5. 2 CPU 1 Codec (Mixing)
+-------------------------------------------
+sound {
+       compatible = "simple-audio-card";
+
+       simple-audio-card,name = "rsnd-ak4643";
+       simple-audio-card,format = "left_j";
+       simple-audio-card,bitclock-master = <&dpcmcpu>;
+       simple-audio-card,frame-master = <&dpcmcpu>;
+
+       simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
+                       "ak4642 Playback", "DAI1 Playback";
+
+       dpcmcpu: cpu@0 {
+               sound-dai = <&rcar_sound 0>;
+       };
+
+       cpu@1 {
+               sound-dai = <&rcar_sound 1>;
+       };
+
+       codec {
+               prefix = "ak4642";
+               sound-dai = <&ak4643>;
+               clocks = <&audio_clock>;
+       };
+};
+
+-------------------------------------------
+Example 6 - many DAI links with DPCM:
+-------------------------------------------
+
+CPU0 ------ ak4613
+CPU1 ------ PCM3168A-p  /* DPCM 1ch/2ch */
+CPU2 --/                /* DPCM 3ch/4ch */
+CPU3 --/                /* DPCM 5ch/6ch */
+CPU4 --/                /* DPCM 7ch/8ch */
+CPU5 ------ PCM3168A-c
+
+sound {
+       compatible = "simple-audio-card";
+
+       simple-audio-card,routing =
+                 "pcm3168a Playback", "DAI1 Playback",
+                 "pcm3168a Playback", "DAI2 Playback",
+                 "pcm3168a Playback", "DAI3 Playback",
+                 "pcm3168a Playback", "DAI4 Playback";
+
+       simple-audio-card,dai-link@0 {
+               format = "left_j";
+               bitclock-master = <&sndcpu0>;
+               frame-master = <&sndcpu0>;
+
+               sndcpu0: cpu {
+                       sound-dai = <&rcar_sound 0>;
+               };
+               codec {
+                       sound-dai = <&ak4613>;
+               };
+       };
+       simple-audio-card,dai-link@1 {
+               format = "i2s";
+               bitclock-master = <&sndcpu1>;
+               frame-master = <&sndcpu1>;
+
+               convert-channels = <8>; /* TDM Split */
+
+               sndcpu1: cpu@0 {
+                       sound-dai = <&rcar_sound 1>;
+               };
+               cpu@1 {
+                       sound-dai = <&rcar_sound 2>;
+               };
+               cpu@2 {
+                       sound-dai = <&rcar_sound 3>;
+               };
+               cpu@3 {
+                       sound-dai = <&rcar_sound 4>;
+               };
+               codec {
+                       mclk-fs = <512>;
+                       prefix = "pcm3168a";
+                       dai-tdm-slot-num = <8>;
+                       sound-dai = <&pcm3168a 0>;
+               };
+       };
+       simple-audio-card,dai-link@2 {
+               format = "i2s";
+               bitclock-master = <&sndcpu2>;
+               frame-master = <&sndcpu2>;
+
+               sndcpu2: cpu {
+                       sound-dai = <&rcar_sound 5>;
+               };
+               codec {
+                       mclk-fs = <512>;
+                       prefix = "pcm3168a";
+                       sound-dai = <&pcm3168a 1>;
+               };
+       };
+};
index 32f8dbce5241d4a9ad612c7c47e0890fc3438625..3a2f71616cda3bc6c898687251ec9e40032e138f 100644 (file)
@@ -75,7 +75,6 @@ sound {
        simple-audio-card,bitclock-master = <&dpcmcpu>;
        simple-audio-card,frame-master = <&dpcmcpu>;
 
-       simple-audio-card,prefix = "ak4642";
        simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
                        "ak4642 Playback", "DAI1 Playback";
 
@@ -88,6 +87,7 @@ sound {
        };
 
        codec {
+               prefix = "ak4642";
                sound-dai = <&ak4643>;
                clocks = <&audio_clock>;
        };
index 4f8ad0e04d20688e43f9426339dc6a0a9a44ee47..056a098495ccec8a9bd7d725199b0d951d4054e6 100644 (file)
@@ -4,9 +4,11 @@ Required properties:
 - compatible: must be one of the following compatibles:
                - "allwinner,sun50i-a64-codec-analog"
 - reg: must contain the registers location and length
+- cpvdd-supply: Regulator supply for the headphone amplifier
 
 Example:
        codec_analog: codec-analog@1f015c0 {
                compatible = "allwinner,sun50i-a64-codec-analog";
                reg = <0x01f015c0 0x4>;
+               cpvdd-supply = <&reg_eldo1>;
        };
diff --git a/Documentation/devicetree/bindings/sound/xlnx,i2s.txt b/Documentation/devicetree/bindings/sound/xlnx,i2s.txt
new file mode 100644 (file)
index 0000000..5e7c7d5
--- /dev/null
@@ -0,0 +1,28 @@
+Device-Tree bindings for Xilinx I2S PL block
+
+The IP supports I2S based playback/capture audio
+
+Required property:
+ - compatible: "xlnx,i2s-transmitter-1.0" for playback and
+              "xlnx,i2s-receiver-1.0" for capture
+
+Required property common to both I2S playback and capture:
+ - reg: Base address and size of the IP core instance.
+ - xlnx,dwidth: sample data width. Can be any of 16, 24.
+ - xlnx,num-channels: Number of I2S streams. Can be any of 1, 2, 3, 4.
+                     supported channels = 2 * xlnx,num-channels
+
+Example:
+
+       i2s_receiver@a0080000 {
+               compatible = "xlnx,i2s-receiver-1.0";
+               reg = <0x0 0xa0080000 0x0 0x10000>;
+               xlnx,dwidth = <0x18>;
+               xlnx,num-channels = <1>;
+       };
+       i2s_transmitter@a0090000 {
+               compatible = "xlnx,i2s-transmitter-1.0";
+               reg = <0x0 0xa0090000 0x0 0x10000>;
+               xlnx,dwidth = <0x18>;
+               xlnx,num-channels = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/spi/atmel-quadspi.txt b/Documentation/devicetree/bindings/spi/atmel-quadspi.txt
new file mode 100644 (file)
index 0000000..b93c1e2
--- /dev/null
@@ -0,0 +1,31 @@
+* Atmel Quad Serial Peripheral Interface (QSPI)
+
+Required properties:
+- compatible:     Should be "atmel,sama5d2-qspi".
+- reg:            Should contain the locations and lengths of the base registers
+                  and the mapped memory.
+- reg-names:      Should contain the resource reg names:
+                  - qspi_base: configuration register address space
+                  - qspi_mmap: memory mapped address space
+- interrupts:     Should contain the interrupt for the device.
+- clocks:         The phandle of the clock needed by the QSPI controller.
+- #address-cells: Should be <1>.
+- #size-cells:    Should be <0>.
+
+Example:
+
+spi@f0020000 {
+       compatible = "atmel,sama5d2-qspi";
+       reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
+       reg-names = "qspi_base", "qspi_mmap";
+       interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
+       clocks = <&spi0_clk>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi0_default>;
+
+       m25p80@0 {
+               ...
+       };
+};
diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt
new file mode 100644 (file)
index 0000000..1fd9a44
--- /dev/null
@@ -0,0 +1,43 @@
+Nuvoton NPCM Peripheral Serial Peripheral Interface(PSPI) controller driver
+
+Nuvoton NPCM7xx SOC support two PSPI channels.
+
+Required properties:
+ - compatible : "nuvoton,npcm750-pspi" for NPCM7XX BMC
+ - #address-cells : should be 1. see spi-bus.txt
+ - #size-cells : should be 0. see spi-bus.txt
+ - specifies physical base address and size of the register.
+ - interrupts : contain PSPI interrupt.
+ - clocks : phandle of PSPI reference clock.
+ - clock-names: Should be "clk_apb5".
+ - pinctrl-names : a pinctrl state named "default" must be defined.
+ - pinctrl-0 : phandle referencing pin configuration of the device.
+ - cs-gpios: Specifies the gpio pins to be used for chipselects.
+            See: Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+- clock-frequency : Input clock frequency to the PSPI block in Hz.
+                   Default is 25000000 Hz.
+
+Aliases:
+- All the SPI controller nodes should be represented in the aliases node using
+  the following format 'spi{n}' withe the correct numbered in "aliases" node.
+
+Example:
+
+aliases {
+       spi0 = &spi0;
+};
+
+spi0: spi@f0200000 {
+       compatible = "nuvoton,npcm750-pspi";
+       reg = <0xf0200000 0x1000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pspi1_pins>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&clk NPCM7XX_CLK_APB5>;
+       clock-names = "clk_apb5";
+       cs-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+};
index 2ba5f9c023acb93be4e8089fd3c817a44cd08bc7..487208c256c05d7a137fb9e92c69704777017c36 100644 (file)
@@ -2,6 +2,7 @@ OMAP2+ McSPI device
 
 Required properties:
 - compatible :
+  - "ti,am654-mcspi" for AM654.
   - "ti,omap2-mcspi" for OMAP2 & OMAP3.
   - "ti,omap4-mcspi" for OMAP4+.
 - ti,spi-num-cs : Number of chipselect supported  by the instance.
index 4b836ad17b197fc16c20476fa8174bd7f2a54e70..37cf69586d10b059aab05cc299407a4393abbb0c 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
                         "renesas,msiof-r8a7744" (RZ/G1N)
                         "renesas,msiof-r8a7745" (RZ/G1E)
                         "renesas,msiof-r8a774a1" (RZ/G2M)
+                        "renesas,msiof-r8a774c0" (RZ/G2E)
                         "renesas,msiof-r8a7790" (R-Car H2)
                         "renesas,msiof-r8a7791" (R-Car M2-W)
                         "renesas,msiof-r8a7792" (R-Car V2H)
index 8d178a4503cf981d6c9fbcfb13220e5678c7e0bb..6cc3c6fe25a34050a4cfa1d96329d3ef5ab6acb3 100644 (file)
@@ -5,8 +5,11 @@ Required properties:
   - "fsl,imx7ulp-spi" for LPSPI compatible with the one integrated on i.MX7ULP soc
   - "fsl,imx8qxp-spi" for LPSPI compatible with the one integrated on i.MX8QXP soc
 - reg : address and length of the lpspi master registers
+- interrupt-parent : core interrupt controller
 - interrupts : lpspi interrupt
 - clocks : lpspi clock specifier
+- spi-slave : spi slave mode support. In slave mode, add this attribute without
+             value. In master mode, remove it.
 
 Examples:
 
@@ -16,4 +19,5 @@ lpspi2: lpspi@40290000 {
        interrupt-parent = <&intc>;
        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&clks IMX7ULP_CLK_LPSPI2>;
+       spi-slave;
 };
index 236dcb0faf376238d9fe4452c5bcb5f686b87e37..69c356767cf8fb4782d0fb55e4e920233375cdf7 100644 (file)
@@ -6,8 +6,10 @@ Required properties:
     - mediatek,mt2712-spi: for mt2712 platforms
     - mediatek,mt6589-spi: for mt6589 platforms
     - mediatek,mt7622-spi: for mt7622 platforms
+    - "mediatek,mt7629-spi", "mediatek,mt7622-spi": for mt7629 platforms
     - mediatek,mt8135-spi: for mt8135 platforms
     - mediatek,mt8173-spi: for mt8173 platforms
+    - mediatek,mt8183-spi: for mt8183 platforms
 
 - #address-cells: should be 1.
 
diff --git a/Documentation/devicetree/bindings/spi/spi-mxic.txt b/Documentation/devicetree/bindings/spi/spi-mxic.txt
new file mode 100644 (file)
index 0000000..529f2da
--- /dev/null
@@ -0,0 +1,34 @@
+Macronix SPI controller Device Tree Bindings
+--------------------------------------------
+
+Required properties:
+- compatible: should be "mxicy,mx25f0a-spi"
+- #address-cells: should be 1
+- #size-cells: should be 0
+- reg: should contain 2 entries, one for the registers and one for the direct
+       mapping area
+- reg-names: should contain "regs" and "dirmap"
+- interrupts: interrupt line connected to the SPI controller
+- clock-names: should contain "ps_clk", "send_clk" and "send_dly_clk"
+- clocks: should contain 3 entries for the "ps_clk", "send_clk" and
+         "send_dly_clk" clocks
+
+Example:
+
+       spi@43c30000 {
+               compatible = "mxicy,mx25f0a-spi";
+               reg = <0x43c30000 0x10000>, <0xa0000000 0x20000000>;
+               reg-names = "regs", "dirmap";
+               clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 18>;
+               clock-names = "send_clk", "send_dly_clk", "ps_clk";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               flash@0 {
+                       compatible = "jedec,spi-nor";
+                       reg = <0>;
+                       spi-max-frequency = <25000000>;
+                       spi-tx-bus-width = <4>;
+                       spi-rx-bus-width = <4>;
+               };
+       };
index 0335a9bd2e8a6835894c8539eb561aaa00fa5356..e30e0c2a4bce135543eb628bdcb3cf32ffa9ede9 100644 (file)
@@ -11,6 +11,9 @@ Required properties:
 Optional properties:
 - cs-gpios: list of GPIO chip selects. See the SPI bus bindings,
   Documentation/devicetree/bindings/spi/spi-bus.txt
+- spi-slave: Empty property indicating the SPI controller is used in slave mode.
+- ready-gpios: GPIO used to signal a SPI master that the FIFO is filled
+  and we're ready to service a transfer. Only useful in slave mode.
 
 Child nodes represent devices on the SPI bus
   See ../spi/spi-bus.txt
index fc97ad64fbf284eed4055ba6aab026ecf6da0af6..421722b9399223527e73a8544ad3c04e0b47ff4e 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
                        - "renesas,qspi-r8a7743" (RZ/G1M)
                        - "renesas,qspi-r8a7744" (RZ/G1N)
                        - "renesas,qspi-r8a7745" (RZ/G1E)
+                       - "renesas,qspi-r8a77470" (RZ/G1C)
                        - "renesas,qspi-r8a7790" (R-Car H2)
                        - "renesas,qspi-r8a7791" (R-Car M2-W)
                        - "renesas,qspi-r8a7792" (R-Car V2H)
index b04e66a52de5dfc4ca66a3efc5339e4986275033..e1201573a29a7dc96a85ae2735bd10ed2d069e45 100644 (file)
@@ -5,6 +5,8 @@ UniPhier SoCs have SCSSI which supports SPI single channel.
 Required properties:
  - compatible: should be "socionext,uniphier-scssi"
  - reg: address and length of the spi master registers
+ - #address-cells: must be <1>, see spi-bus.txt
+ - #size-cells: must be <0>, see spi-bus.txt
  - interrupts: a single interrupt specifier
  - pinctrl-names: should be "default"
  - pinctrl-0: pin control state for the default mode
@@ -16,6 +18,8 @@ Example:
 spi0: spi@54006000 {
        compatible = "socionext,uniphier-scssi";
        reg = <0x54006000 0x100>;
+       #address-cells = <1>;
+       #size-cells = <0>;
        interrupts = <0 39 4>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_spi0>;
index 4b1a2a8fcc16185cd5fae518e0e2fb953becac6f..a2f4451cf3f9c6f579095f6489a2f61b94ca6edf 100644 (file)
@@ -67,6 +67,7 @@ capella       Capella Microsystems, Inc
 cascoda        Cascoda, Ltd.
 cavium Cavium, Inc.
 cdns   Cadence Design Systems Inc.
+cdtech CDTech(H.K.) Electronics Limited
 ceva   Ceva, Inc.
 chipidea       Chipidea, Inc
 chipone                ChipOne
diff --git a/Documentation/driver-api/i3c/device-driver-api.rst b/Documentation/driver-api/i3c/device-driver-api.rst
new file mode 100644 (file)
index 0000000..85bc338
--- /dev/null
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+I3C device driver API
+=====================
+
+.. kernel-doc:: include/linux/i3c/device.h
+
+.. kernel-doc:: drivers/i3c/device.c
diff --git a/Documentation/driver-api/i3c/index.rst b/Documentation/driver-api/i3c/index.rst
new file mode 100644 (file)
index 0000000..783d6da
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+I3C subsystem
+=============
+
+.. toctree::
+
+   protocol
+   device-driver-api
+   master-driver-api
diff --git a/Documentation/driver-api/i3c/master-driver-api.rst b/Documentation/driver-api/i3c/master-driver-api.rst
new file mode 100644 (file)
index 0000000..332552b
--- /dev/null
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================
+I3C master controller driver API
+================================
+
+.. kernel-doc:: drivers/i3c/master.c
+
+.. kernel-doc:: include/linux/i3c/master.h
diff --git a/Documentation/driver-api/i3c/protocol.rst b/Documentation/driver-api/i3c/protocol.rst
new file mode 100644 (file)
index 0000000..dae3b6d
--- /dev/null
@@ -0,0 +1,203 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+I3C protocol
+============
+
+Disclaimer
+==========
+
+This chapter will focus on aspects that matter to software developers. For
+everything hardware related (like how things are transmitted on the bus, how
+collisions are prevented, ...) please have a look at the I3C specification.
+
+This document is just a brief introduction to the I3C protocol and the concepts
+it brings to the table. If you need more information, please refer to the MIPI
+I3C specification (can be downloaded here
+http://resources.mipi.org/mipi-i3c-v1-download).
+
+Introduction
+============
+
+The I3C (pronounced 'eye-three-see') is a MIPI standardized protocol designed
+to overcome I2C limitations (limited speed, external signals needed for
+interrupts, no automatic detection of the devices connected to the bus, ...)
+while remaining power-efficient.
+
+I3C Bus
+=======
+
+An I3C bus is made of several I3C devices and possibly some I2C devices as
+well, but let's focus on I3C devices for now.
+
+An I3C device on the I3C bus can have one of the following roles:
+
+* Master: the device is driving the bus. It's the one in charge of initiating
+  transactions or deciding who is allowed to talk on the bus (slave generated
+  events are possible in I3C, see below).
+* Slave: the device acts as a slave, and is not able to send frames to another
+  slave on the bus. The device can still send events to the master on
+  its own initiative if the master allowed it.
+
+I3C is a multi-master protocol, so there might be several masters on a bus,
+though only one device can act as a master at a given time. In order to gain
+bus ownership, a master has to follow a specific procedure.
+
+Each device on the I3C bus has to be assigned a dynamic address to be able to
+communicate. Until this is done, the device should only respond to a limited
+set of commands. If it has a static address (also called legacy I2C address),
+the device can reply to I2C transfers.
+
+In addition to these per-device addresses, the protocol defines a broadcast
+address in order to address all devices on the bus.
+
+Once a dynamic address has been assigned to a device, this address will be used
+for any direct communication with the device. Note that even after being
+assigned a dynamic address, the device should still process broadcast messages.
+
+I3C Device discovery
+====================
+
+The I3C protocol defines a mechanism to automatically discover devices present
+on the bus, their capabilities and the functionalities they provide. In this
+regard I3C is closer to a discoverable bus like USB than it is to I2C or SPI.
+
+The discovery mechanism is called DAA (Dynamic Address Assignment), because it
+not only discovers devices but also assigns them a dynamic address.
+
+During DAA, each I3C device reports 3 important things:
+
+* BCR: Bus Characteristic Register. This 8-bit register describes the device bus
+  related capabilities
+* DCR: Device Characteristic Register. This 8-bit register describes the
+  functionalities provided by the device
+* Provisional ID: A 48-bit unique identifier. On a given bus there should be no
+  Provisional ID collision, otherwise the discovery mechanism may fail.
+
+I3C slave events
+================
+
+The I3C protocol allows slaves to generate events on their own, and thus allows
+them to take temporary control of the bus.
+
+This mechanism is called IBI for In Band Interrupts, and as stated in the name,
+it allows devices to generate interrupts without requiring an external signal.
+
+During DAA, each device on the bus has been assigned an address, and this
+address will serve as a priority identifier to determine who wins if 2 different
+devices are generating an interrupt at the same moment on the bus (the lower the
+dynamic address the higher the priority).
+
+Masters are allowed to inhibit interrupts if they want to. This inhibition
+request can be broadcast (applies to all devices) or sent to a specific
+device.
+
+I3C Hot-Join
+============
+
+The Hot-Join mechanism is similar to USB hotplug. This mechanism allows
+slaves to join the bus after it has been initialized by the master.
+
+This covers the following use cases:
+
+* the device is not powered when the bus is probed
+* the device is hotplugged on the bus through an extension board
+
+This mechanism is relying on slave events to inform the master that a new
+device joined the bus and is waiting for a dynamic address.
+
+The master is then free to address the request as it wishes: ignore it or
+assign a dynamic address to the slave.
+
+I3C transfer types
+==================
+
+If you omit SMBus (which is just a standardization on how to access registers
+exposed by I2C devices), I2C has only one transfer type.
+
+I3C defines 3 different classes of transfer in addition to I2C transfers which
+are here for backward compatibility with I2C devices.
+
+I3C CCC commands
+----------------
+
+CCC (Common Command Code) commands are meant to be used for anything that is
+related to bus management and all features that are common to a set of devices.
+
+CCC commands contain an 8-bit CCC ID describing the command that is executed.
+The MSB of this ID specifies whether this is a broadcast command (bit7 = 0) or a
+unicast one (bit7 = 1).
+
+The command ID can be followed by a payload. Depending on the command, this
+payload is either sent by the master sending the command (write CCC command),
+or sent by the slave receiving the command (read CCC command). Of course, read
+accesses only apply to unicast commands.
+Note that, when sending a CCC command to a specific device, the device address
+is passed in the first byte of the payload.
+
+The payload length is not explicitly passed on the bus, and should be extracted
+from the CCC ID.
+
+Note that vendors can use a dedicated range of CCC IDs for their own commands
+(0x61-0x7f and 0xe0-0xef).
+
+I3C Private SDR transfers
+-------------------------
+
+Private SDR (Single Data Rate) transfers should be used for anything that is
+device specific and does not require high transfer speed.
+
+It is the equivalent of I2C transfers but in the I3C world. Each transfer is
+passed the device address (dynamic address assigned during DAA), a payload
+and a direction.
+
+The only difference with I2C is that the transfer is much faster (typical clock
+frequency is 12.5MHz).
+
+I3C HDR commands
+----------------
+
+HDR commands should be used for anything that is device specific and requires
+high transfer speed.
+
+The first thing attached to an HDR command is the HDR mode. There are currently
+3 different modes defined by the I3C specification (refer to the specification
+for more details):
+
+* HDR-DDR: Double Data Rate mode
+* HDR-TSP: Ternary Symbol Pure. Only usable on busses with no I2C devices
+* HDR-TSL: Ternary Symbol Legacy. Usable on busses with I2C devices
+
+When sending an HDR command, the whole bus has to enter HDR mode, which is done
+using a broadcast CCC command.
+Once the bus has entered a specific HDR mode, the master sends the HDR command.
+An HDR command is made of:
+
+* one 16-bits command word in big endian
+* N 16-bits data words in big endian
+
+Those words may be wrapped with specific preambles/post-ambles which depend on
+the chosen HDR mode and are detailed here (see the specification for more
+details).
+
+The 16-bits command word is made of:
+
+* bit[15]: direction bit, read is 1, write is 0
+* bit[14:8]: command code. Identifies the command being executed, the amount of
+  data words and their meaning
+* bit[7:1]: I3C address of the device this command is addressed to
+* bit[0]: reserved/parity-bit
+
+Backward compatibility with I2C devices
+=======================================
+
+The I3C protocol has been designed to be backward compatible with I2C devices.
+This backward compatibility allows one to connect a mix of I2C and I3C devices
+on the same bus, though, in order to be really efficient, I2C devices should
+be equipped with 50 ns spike filters.
+
+I2C devices can't be discovered like I3C ones and have to be statically
+declared. In order to let the master know what these devices are capable of
+(both in terms of bus related limitations and functionalities), the software
+has to provide some information, which is done through the LVR (Legacy I2C
+Virtual Register).
index 909f991b4c0d2e40b91b98ad5bbcee39379fbb3e..ab38ced66a4424164baea9b79468b910869f5757 100644 (file)
@@ -33,6 +33,7 @@ available subsections can be seen below.
    pci/index
    spi
    i2c
+   i3c/index
    hsi
    edac
    scsi
index 43681ca0837f8d7c78fa576831c029a50e730203..fc4cc24dfb9767e38760295ac157adba3b88b182 100644 (file)
@@ -254,6 +254,7 @@ GPIO
   devm_gpiod_get_index_optional()
   devm_gpiod_get_optional()
   devm_gpiod_put()
+  devm_gpiod_unhinge()
   devm_gpiochip_add_data()
   devm_gpiochip_remove()
   devm_gpio_request()
diff --git a/Documentation/gpu/amdgpu-dc.rst b/Documentation/gpu/amdgpu-dc.rst
new file mode 100644 (file)
index 0000000..cc89b0f
--- /dev/null
@@ -0,0 +1,68 @@
+===================================
+drm/amd/display - Display Core (DC)
+===================================
+
+*placeholder - general description of supported platforms, what dc is, etc.*
+
+Because it is partially shared with other operating systems, the Display Core
+Driver is divided in two pieces.
+
+1. **Display Core (DC)** contains the OS-agnostic components. Things like
+   hardware programming and resource management are handled here.
+2. **Display Manager (DM)** contains the OS-dependent components. Hooks to the
+   amdgpu base driver and DRM are implemented here.
+
+It doesn't help that the entire package is frequently referred to as DC. But
+with the context in mind, it should be clear.
+
+When CONFIG_DRM_AMD_DC is enabled, DC will be initialized by default for
+supported ASICs. To force disable, set `amdgpu.dc=0` on kernel command line.
+Likewise, to force enable on unsupported ASICs, set `amdgpu.dc=1`.
+
+To determine if DC is loaded, search dmesg for the following entry:
+
+``Display Core initialized with <version number here>``
+
+AMDgpu Display Manager
+======================
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+   :internal:
+
+Lifecycle
+---------
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :doc: DM Lifecycle
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :functions: dm_hw_init dm_hw_fini
+
+Interrupts
+----------
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+   :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :functions: register_hpd_handlers dm_crtc_high_irq dm_pflip_high_irq
+
+Atomic Implementation
+---------------------
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :doc: atomic
+
+.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+   :functions: amdgpu_dm_atomic_check amdgpu_dm_atomic_commit_tail
+
+Display Core
+============
+
+**WIP**
index 7d2d3875ff1a0cf17f463410df0e0acdab2f88b6..7c1672118a73f4c59f066ef78fa95badb6a1ce43 100644 (file)
@@ -5,6 +5,7 @@ GPU Driver Documentation
 .. toctree::
 
    amdgpu
+   amdgpu-dc
    i915
    meson
    pl111
index f9cfcdcdf024fc88cbf8edf82d7c2fc1c4f4c8a7..b422eb8edf1627baba10a231560eca754e31e846 100644 (file)
@@ -59,19 +59,28 @@ Implementing Asynchronous Atomic Commit
 .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c
    :doc: implementing nonblocking commit
 
+Helper Functions Reference
+--------------------------
+
+.. kernel-doc:: include/drm/drm_atomic_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c
+   :export:
+
 Atomic State Reset and Initialization
 -------------------------------------
 
-.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c
    :doc: atomic state reset and initialization
 
-Helper Functions Reference
---------------------------
+Atomic State Helper Reference
+-----------------------------
 
-.. kernel-doc:: include/drm/drm_atomic_helper.h
+.. kernel-doc:: include/drm/drm_atomic_state_helper.h
    :internal:
 
-.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c
    :export:
 
 Simple KMS Helper Reference
@@ -223,6 +232,18 @@ MIPI DSI Helper Functions Reference
 .. kernel-doc:: drivers/gpu/drm/drm_mipi_dsi.c
    :export:
 
+Display Stream Compression Helper Functions Reference
+=====================================================
+
+.. kernel-doc:: drivers/gpu/drm/drm_dsc.c
+   :doc: dsc helpers
+
+.. kernel-doc:: include/drm/drm_dsc.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_dsc.c
+   :export:
+
 Output Probing Helper Functions Reference
 =========================================
 
index 4b1501b4835b1a41c44207f1b4b4cf1d264cda1a..75c882e09feec13081b34381ad2e2d1def67e70c 100644 (file)
@@ -554,6 +554,18 @@ Plane Composition Properties
 .. kernel-doc:: drivers/gpu/drm/drm_blend.c
    :export:
 
+FB_DAMAGE_CLIPS
+~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
+   :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
+   :export:
+
+.. kernel-doc:: include/drm/drm_damage_helper.h
+   :internal:
+
 Color Management Properties
 ---------------------------
 
@@ -575,6 +587,13 @@ Explicit Fencing Properties
 .. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c
    :doc: explicit fencing properties
 
+
+Variable Refresh Properties
+---------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_connector.c
+   :doc: Variable refresh properties
+
 Existing KMS Properties
 -----------------------
 
index e725e8449e7257212490547f4afd6924695b9632..54a696d961a7c923761c0765f985039d575e32e7 100644 (file)
@@ -72,16 +72,13 @@ object TTM to provide a pool for buffer object allocation by clients and
 the kernel itself. The type of this object should be
 TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct
 ttm_bo_global). Again, driver-specific init and release functions may
-be provided, likely eventually calling ttm_bo_global_init() and
-ttm_bo_global_release(), respectively. Also, like the previous
+be provided, likely eventually calling ttm_bo_global_ref_init() and
+ttm_bo_global_ref_release(), respectively. Also, like the previous
 object, ttm_global_item_ref() is used to create an initial reference
 count for the TTM, which will call your initialization function.
 
 See the radeon_ttm.c file for an example of usage.
 
-.. kernel-doc:: drivers/gpu/drm/drm_global.c
-   :export:
-
 
 The Graphics Execution Manager (GEM)
 ====================================
index a2214cc1f821a3bb4b9b096adf3df5e29874a838..4b4bf2c5eac5d8f54e0bfb5992837099740008a9 100644 (file)
@@ -197,6 +197,9 @@ EPERM/EACCESS:
         difference between EACCESS and EPERM.
 
 ENODEV:
+        The device is not (yet) present or fully initialized.
+
+EOPNOTSUPP:
         Feature (like PRIME, modesetting, GEM) is not supported by the driver.
 
 ENXIO:
index 77c2b3c25565f2b619e005ad8715dcb65c75b92e..14191b64446df0eadae3215f690e07ec4a09885b 100644 (file)
@@ -28,22 +28,16 @@ them, but also all the virtual ones used by KVM, so everyone qualifies).
 
 Contact: Daniel Vetter, Thierry Reding, respective driver maintainers
 
-Switch from reference/unreference to get/put
---------------------------------------------
-
-For some reason DRM core uses ``reference``/``unreference`` suffixes for
-refcounting functions, but kernel uses ``get``/``put`` (e.g.
-``kref_get``/``put()``). It would be good to switch over for consistency, and
-it's shorter. Needs to be done in 3 steps for each pair of functions:
 
-* Create new ``get``/``put`` functions, define the old names as compatibility
-  wrappers
-* Switch over each file/driver using a cocci-generated spatch.
-* Once all users of the old names are gone, remove them.
+Remove custom dumb_map_offset implementations
+---------------------------------------------
 
-This way drivers/patches in the progress of getting merged won't break.
+All GEM based drivers should be using drm_gem_create_mmap_offset() instead.
+Audit each individual driver, make sure it'll work with the generic
+implementation (there's lots of outdated locking leftovers in various
+implementations), and then remove it.
 
-Contact: Daniel Vetter
+Contact: Daniel Vetter, respective driver maintainers
 
 Convert existing KMS drivers to atomic modesetting
 --------------------------------------------------
@@ -234,6 +228,34 @@ efficient.
 
 Contact: Daniel Vetter
 
+Defaults for .gem_prime_import and export
+-----------------------------------------
+
+Most drivers don't need to set drm_driver->gem_prime_import and
+->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export()
+are the default.
+
+struct drm_gem_object_funcs
+---------------------------
+
+GEM objects can now have a function table instead of having the callbacks on the
+DRM driver struct. This is now the preferred way and drivers can be moved over.
+
+Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate
+---------------------------------------------------------
+
+For cases where drivers are attempting to grab the modeset locks with a local
+acquire context. Replace the boilerplate code surrounding
+drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and
+DRM_MODESET_LOCK_ALL_END() instead.
+
+This should also be done for all places where drm_modest_lock_all() is still
+used.
+
+As a reference, take a look at the conversions already completed in drm core.
+
+Contact: Sean Paul, respective driver maintainers
+
 Core refactorings
 =================
 
@@ -339,6 +361,16 @@ Some of these date from the very introduction of KMS in 2008 ...
   leftovers from older (never merged into upstream) KMS designs where modes
   where set using their ID, including support to add/remove modes.
 
+- Make ->funcs and ->helper_private vtables optional. There's a bunch of empty
+  function tables in drivers, but before we can remove them we need to make sure
+  that all the users in helpers and drivers do correctly check for a NULL
+  vtable.
+
+- Cleanup up the various ->destroy callbacks. A lot of them just wrapt the
+  drm_*_cleanup implementations and can be removed. Some tack a kfree() at the
+  end, for which we could add drm_*_cleanup_kfree(). And then there's the (for
+  historical reasons) misnamed drm_primary_helper_destroy() function.
+
 Better Testing
 ==============
 
index 0a6ea6216e41d6bf9f962ec255702d55e1d7fc99..7dfc349a4508b1c477d065bb268eb8850b2b6745 100644 (file)
@@ -10,8 +10,8 @@
 TODO
 ====
 
-CRC API
--------
+CRC API Improvements
+--------------------
 
 - Optimize CRC computation ``compute_crc()`` and plane blending ``blend()``
 
@@ -22,3 +22,100 @@ CRC API
 
 - Add igt test to check extreme alpha values i.e. fully opaque and fully
   transparent (intermediate values are affected by hw-specific rounding modes).
+
+Vblank issues
+-------------
+
+Some IGT test cases are failing. Need to analyze why and fix the issues:
+
+- plain-flip-fb-recreate
+- plain-flip-ts-check
+- flip-vs-blocking-wf-vblank
+- plain-flip-fb-recreate-interruptible
+- flip-vs-wf_vblank-interruptible
+
+Runtime Configuration
+---------------------
+
+We want to be able to reconfigure vkms instance without having to reload the
+module. Use/Test-cases:
+
+- Hotplug/hotremove connectors on the fly (to be able to test DP MST handling of
+  compositors).
+
+- Configure planes/crtcs/connectors (we'd need some code to have more than 1 of
+  them first).
+
+- Change output configuration: Plug/unplug screens, change EDID, allow changing
+  the refresh rate.
+
+The currently proposed solution is to expose vkms configuration through
+configfs.  All existing module options should be supported through configfs too.
+
+Add Plane Features
+------------------
+
+There's lots of plane features we could add support for:
+
+- Real overlay planes, not just cursor.
+
+- Full alpha blending on all planes.
+
+- Rotation, scaling.
+
+- Additional buffer formats, especially YUV formats for video like NV12.
+  Low/high bpp RGB formats would also be interesting.
+
+- Async updates (currently only possible on cursor plane using the legacy cursor
+  api).
+
+For all of these, we also want to review the igt test coverage and make sure all
+relevant igt testcases work on vkms.
+
+Writeback support
+-----------------
+
+Currently vkms only computes a CRC for each frame. Once we have additional plane
+features, we could write back the entire composited frame, and expose it as:
+
+- Writeback connector. This is useful for testing compositors if you don't have
+  hardware with writeback support.
+
+- As a v4l device. This is useful for debugging compositors on special vkms
+  configurations, so that developers see what's really going on.
+
+Prime Buffer Sharing
+--------------------
+
+We already have vgem, which is a gem driver for testing rendering, similar to
+how vkms is for testing the modeset side. Adding buffer sharing support to vkms
+allows us to test them together, to test synchronization and lots of other
+features. Also, this allows compositors to test whether they work correctly on
+SoC chips, where the display and rendering is very often split between 2
+drivers.
+
+Output Features
+---------------
+
+- Variable refresh rate/freesync support. This probably needs prime buffer
+  sharing support, so that we can use vgem fences to simulate rendering in
+  testing. Also needs support to specify the EDID.
+
+- Add support for link status, so that compositors can validate their runtime
+  fallbacks when e.g. a Display Port link goes bad.
+
+- All the hotplug handling describe under "Runtime Configuration".
+
+Atomic Check using eBPF
+-----------------------
+
+Atomic drivers have lots of restrictions which are not exposed to userspace in
+any explicit form through e.g. possible property values. Userspace can only
+inquiry about these limits through the atomic IOCTL, possibly using the
+TEST_ONLY flag. Trying to add configurable code for all these limits, to allow
+compositors to be tested against them, would be rather futile exercise. Instead
+we could add support for eBPF to validate any kind of atomic state, and
+implement a library of different restrictions.
+
+This needs a bunch of features (plane compositing, multiple outputs, ...)
+enabled already to make sense.
index 08b21de3ef94bdb6b92aaa5280d0c4eb2b48e70d..53adc029061fbd64b077ca563cf619028a046760 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 *.pdf
 # Files generated from *.dot
 uapi/v4l/pipeline.svg
index 36166952d555fbc5444e6c2c9c11c081c81df2f1..d75d70f191bc3d080079c6303f777e5144d3b9b3 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Rules to convert a .h file to inline RST documentation
 
 SRC_DIR=$(srctree)/Documentation/media
index 940458774cf6ec6ab759903b4d43c9fcf0d90763..cf6620477f736f14b6b87f8966e80fd8eb8d2db0 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _DVBAUDIO_H_
 
index 553559cc6ad7de7148ec8ef84f3584b9c1760b2e..f6828238eb48ae905745a3b9028edd5792bfdc7e 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _DVBCA_H_
 
index 7ef204823422659b4545e42239fbc338f7e3717f..2b7fcaa4311b09df727bfd977785ece657588ce0 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 .. include:: <isonum.txt>
 
index 99551c6a9bc59f6a8d8ff3cc4f90801e2344eeb6..356d08b519f3d13d701c35e7e1a0bf42f778c471 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Pulse-Eight CEC Adapter driver
 ==============================
 
index d9fd092de6f8b3fae015e1f09658007dfadef6b7..014816d04b9ee7d94cf77b3be72ad9f486bb97e0 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _CEC_UAPI_H
 
index bef927bc46595b55cfd5c4501da6d02715a88e2f..1f194fcd2caedb40e32065bf4a5259be6be05821 100644 (file)
@@ -1,5 +1,7 @@
 # -*- coding: utf-8; mode: python -*-
 
+# SPDX-License-Identifier: GPL-2.0
+
 project = 'Linux Media Subsystem Documentation'
 
 tags.add("subproject")
index 480d548af670273e6ca99a5b8f0ca147d24cc6c7..d0c50d75f51851724469781f82d9dfb165fa2ab0 100644 (file)
@@ -1,5 +1,7 @@
 # -*- coding: utf-8; mode: python -*-
 
+# SPDX-License-Identifier: GPL-2.0
+
 project = 'Linux Media Subsystem Documentation'
 
 # It is possible to run Sphinx in nickpick mode with:
index a8c4239ed95bab6c87d8adcdb4edfa52de981099..afc14d384b83ce2afbbb703913f609532fc72ffd 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _UAPI_DVBDMX_H_
 
index 49cd9c9353071cef0a06c76d8a8a866acfd64fc2..14f437ca38d385d2059b4a2ef405ff956d3dcbd0 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 HOWTO: Get An Avermedia DVB-T working under Linux
 -------------------------------------------------
 
index e3e387bdf498d1860e5dfb11f568759327c08f25..7936cd96fc8f9c621d29144a38ddcb9c1dd07b93 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 How to get the bt8xx cards working
 ==================================
 
index 177cbeb2b561cb12680566eca3ed6f3045c310b4..e2e30a56b450287a548837fdbcb9cc7065dd1b5d 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Hardware supported by the linuxtv.org DVB drivers
 =================================================
 
index 87f3748c49b94c204ac09e899e0a381a631c0bfa..35f33f1f9e2af369bd3a38dc2b636dea52c9fb0e 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Conditional Access Interface (CI API)
 ================================================
 
index 5949753008aecb368213811c97fb2a5193de6353..f23b6e6faf463a1237a939d47a7d3d94471ea974 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Contributors
 ============
 
index eec99cd07a30821a6bb4d939a3d3a72729a02b36..6679191819aa79f9c4ddbaed5fca667228a534d6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Idea behind the dvb-usb-framework
 =================================
 
index a8593d3792faaa2c3018bac1f09b5b03b2746a06..52f153d1827821e6aa8a459eb150c8dbc8a5afc3 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 FAQ
 ===
 
index 1f5f5798919627411ec88a2a96097d5fa6444c8a..7b8336ece681a5d3d6746d2fcad56b08282aa844 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 ****************
 Frontend drivers
 ****************
index 314e127d82e310e42f97a96a21dbf566db6b43ab..9d3fce544f8524e4b5ad010a154e85e0c7b70d98 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 .. include:: <isonum.txt>
 
index d6eeb2708b9b253b860c9cc17afbfacc9a6b5057..4e361bcc3ad4f78d55a0ee5497d413ef5e735a6c 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Introduction
 ============
 
index e8913d4481a0c9dfac3a8edcb32eb2bf490d8451..a6ee33413748d10671ece7c3ccf5893a4bcb8b21 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Firmware files for lmedm04 cards
 ================================
 
index 41236b43c124eeec13962d752a6c7385e0fe8788..fab3581551de2a107ecab0d10202b75b0a7c2922 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Opera firmware
 ==============
 
index f80f4ecc15601611e3075c4f3c1163b10f1ca022..9eaa12366bbf6958a059fb8c0a38bf37627cb304 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 How to set up the Technisat/B2C2 Flexcop devices
 ================================================
 
index 84fc2199dc2969b4846e03e682189294da3ac76d..516bbab8a87281deec69637057e76d11f2989401 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 TechnoTrend/Hauppauge DEC USB Driver
 ====================================
 
index 7d7d5d82108a3468a8f04ad07b086fb058fde703..ca6c9c226902735bc42fd415a2fa8cbc044b7c22 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 UDEV rules for DVB
 ==================
 
index f7c4df620a52b4e116949304b904b9964065c954..6283702c08c8c8354f5e1b2df409dbe663616d58 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _DVBFRONTEND_H_
 
index 1cf5316c8ff800b69ccbde624552066b52caef31..0a222fc1d7caf22a235cf4d5e8403fde4bd2152c 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Linux Media Subsystem Documentation
 ===================================
 
index 9ce2e23a0236796c557b3dd371ad71db845a646a..4a6bd665b88488ae4543c421cc690294dc3c6b57 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 ============
 Introduction
index bca1d9d1d22317357cc9929a6eac8e9f9f82afa4..3ce26b7c2b2b6f597ea1f9532ec59c8e17073db5 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 CEC Kernel Support
 ==================
 
index 0560100efca2e14f16cdd33cc45440c6f4d9afd6..a7e75e2eba85a1cbd2e405d678c5ee8685aa8575 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 MIPI CSI-2
 ==========
 
index fded096b937cc85976ef1b96c046c84f9e19b258..8a09862b428b407e15d21fadd96747070f1ea693 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Conditional Access kABI
 ----------------------------------
 
index 7a9574f031906f0b01b0dc7bded9e7d7555ab1cf..f8b2c4dc81701119d80b0ac2a63ae5fafe62dcff 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Common functions
 ---------------------------
 
index bca743dc6b435396f470b9b6b82e62b505465c1e..17454a2cf6b04e361ba0a9a22d88a84166c92027 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV (DVB) devices
 ------------------------
 
index 24857133e4e8fdfb48b634afc67501308baf298a..c0ae5dec53281694cb82659007bcdb0d7f9eac07 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Demux kABI
 ---------------------
 
index 472650cdb100ad285cfe0b2b6875ed7cc0cf51f3..8ea64742c7ba9468f8cdb74e23e47a4cd465e6cb 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Frontend kABI
 ------------------------
 
index 158c7cbd76003b5d911b609797f39584e8cb5fda..deb6bffe96bbcee2465e8ab8c4b535314082ccf7 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Digital TV Network kABI
 -----------------------
 
index 69362b3135c2375412b23a130b27bfa2b1d9de7b..0bcfeadbc52d8948b831a770c343199bb50df8cf 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Media Controller devices
 ------------------------
 
index 4759f020d6b27d5b90908cc864a15ad9a20d1d79..53f5e643b6e9e77ce5e842609d0d0194011c95e2 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Remote Controller devices
 -------------------------
 
index 523ff9eb09a065aa0fc39d2a8a5c27310664116f..3422330b3b1fddc906603f0fc8a3a32d82248bb8 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 async kAPI
 ^^^^^^^^^^^^^^^
 .. kernel-doc:: include/media/v4l2-async.h
index b8a895860a8a0c9d1609def6c25a4f3325814664..5c22eecab7bac2f6f2be98436972cd9acdad505b 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 clocks
 -----------
 
index 525d804871ffb72a75547038bccc489abcc663f1..b1e70eb56aa48077d4762b694c7e31e1c79327e5 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 common functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 07a179eeb2fb5f4c24466e2ceb3749a83ffce001..64ab99abf0b699cce98e4b1c6a5e9e17f0a3e492 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 Controls
 =============
 
index 5cf292037a48a01924bffb791545d733a525fde8..0dcad7a2314149719eaec6000c4d89c9c2044016 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Video4Linux devices
 -------------------
 
index eb03ccc41c41c931036966bd8d73575ccfe4d308..b359f1804bbe26674ed274f98a65eb751384ac32 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Video device' s internal representation
 =======================================
 
index 6c58bbbaa66f12474c497f96b40307a013cc09db..c4311f0421befb3284ff38cd6b515ffe92566c66 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 device instance
 --------------------
 
index 55274329d229fbfec07e8f7f1fd623bd0be8c490..b178f931518b869171009146345812c11faf6cfd 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 DV Timings functions
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 5c7e31224ddc86f3e590e28ed92d96d973dbb0e9..a4b7ae2b94d8152ad5edc7b81fb187b36d748a05 100644 (file)
@@ -1,3 +1,4 @@
+.. SPDX-License-Identifier: GPL-2.0
 
 V4L2 events
 -----------
index 3ee64adf46358128bec5f71c9c3ed5c1aebe80d7..4c62b19af74496ca6ebd0c72fd39c5187fce06e9 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 File handlers
 ------------------
 
index 20798bdac3872c0ebc0059e379a031716739b355..2aa6bed9b8dbe2df89eb443aec5d4362e7c08ce6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 flash functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 6c8bccdfeb25bc0287441d46a657ce29868c75a1..e313b6cddcd0d32cb48faeae6d6cf18e4ada5394 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 fwnode kAPI
 ^^^^^^^^^^^^^^^^
 .. kernel-doc:: include/media/v4l2-fwnode.h
index e614d8d4ca1c4041963942fc5d08c1e1c311e12d..cea3e263e48bae2f9737cbbcb0c5bbf6f8a4faf3 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Introduction
 ------------
 
index 8af3470134906e345f7279c26e5c9feac5ac5199..0c352ac588b2ff693d81fd12ed694a5de4302ed6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 Media Controller functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index e64131906d11711fe0c27bf6d3657bad5bdd5473..1f2254cba92d47e2239cb2f8ea87a56ea78f37f6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 Media Bus functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 5536b4a71e5103f558f253b2a836467e1d0c746f..a43b31cc82616e2fcaa672b1a21a5ecd6c16eb49 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 Memory to Memory functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 8df5067ad57dced4a799686fe1160d3855757769..fc315cd84156e6ecc0ad3ee4e7ec7762497a5a5e 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 rect helper functions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 1280e05b662b1136ca8f157012d4a844f4ebebba..be4970909f408719a9b8714ee71c79b8fbc56a8c 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 V4L2 sub-devices
 ----------------
 
index 86e89463965142b85423bb46cb0b6e36ed9298c2..e6caa33215669d1c6c0bac0ad7d6479105bc7d04 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Tuner functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 33422cb26aa716b676ba0c20e94f5f85d2f28ec7..43fb391edabad03044d85d40b780ffcd9478af2c 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Hauppauge TV EEPROM functions and data structures
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 54adfd772d28a9015c72fddc1fd465077fd05088..1a7756397b1ab5eca3cb34729370a32b10f21be4 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. _vb_framework:
 
 Videobuf Framework
index 3c4cb1e7e05f29b3aae5f13750cfa3c46a67f2b5..1044f64ff168f247467538dc945d68ea22c48bda 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. _vb2_framework:
 
 V4L2 videobuf2 functions and data structures
index 984b61dc3f2ea14425edef144df7b327910aa5f4..379b9e7df5d0b94bab47ce9481491b525f30d10d 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _LINUX_LIRC_H
 
index 684fe9c86deeffe383d7d385f37f2fafcba94602..9b4c26502d95c540d6b1bca31aae7ede4b2ae865 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define __LINUX_MEDIA_H
 
index 83da736fad726c40de570f71eb599869bdd1f45c..1389998c90f779b9e415ccf88dfa06f7432f26b3 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 .. include:: <isonum.txt>
 
index 28eb35a1f965cc84d902bf7e420b20a565a29f4b..0753005c7bb44b4f060e11a292db086de1d384f2 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 .. include:: <isonum.txt>
 
@@ -10,9 +10,9 @@ Linux Media Infrastructure userspace API
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.1 or
-any later version published by the Free Software Foundation. A copy of
-the license is included in the chapter entitled "GNU Free Documentation
-License".
+any later version published by the Free Software Foundation, with no
+Invariant Sections. A copy of the license is included in the chapter
+entitled "GNU Free Documentation License".
 
 .. only:: html
 
index afe6bef9156765e5885d1db8439f860d6133e3d4..5159aa4bbbb92d8646f8767179c04cc40002ccbd 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _DVBNET_H_
 
index d6fad90ec19987ad2be86387b72277094a677c3d..bfd5c7db3b001179540f16e7f98ad7b655ef1802 100644 (file)
@@ -1,4 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg id="svg2" width="235mm" height="179mm" clip-path="url(#a)" fill-rule="evenodd" stroke-linejoin="round" stroke-width="28.222" preserveAspectRatio="xMidYMid" version="1.2" viewBox="0 0 22648.239 17899.829" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata id="metadata1533"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs id="defs4"><clipPath id="a"><rect id="rect7" width="28000" height="21000"/></clipPath></defs><path id="path11" d="m10146 2636c-518.06 0-1035.1 515-1035.1 1031v4124c0 516 517.06 1032 1035.1 1032h8572.2c518.06 0 1036.1-516 1036.1-1032v-4124c0-516-518.06-1031-1036.1-1031h-8572.2z"
 fill="#fcf" style=""/><path id="path15" d="m1505.5 13443c-293 0-585 292-585 585v2340c0 293 292 586 585 586h3275c293 0 586-293 586-586v-2340c0-293-293-585-586-585h-3275z" fill="#ffc" style=""/><path id="path19" d="m517.15 22.013c-461 0-922 461-922 922v11169c0 461 461 923 922 923h3692c461 0 922-462 922-923v-11169c0-461-461-922-922-922h-3692z" fill="#e6e6e6" style=""/><path id="path23" d="m2371.5 6438h-2260v-1086h4520v1086h-2260z" fill="#ff8080" style=""/><path id="path25" d="m2371.5 6438h-2260v-1086h4520v1086h-2260z" fill="none" stroke="#3465af" style=""/><text id="text27" class="TextShape" x="-2089.4541" y="-2163.9871" font-family="Serif, serif" font-size="493.88px"><tspan id="tspan29" class="TextParagraph" font-family="Serif, serif" font-size="493.88px"><tspan id="tspan31" class="TextPosition" x="489.5459" y="6111.0132" font-family="Serif, serif" font-size="493.88px"><tspan id="tspan33"
 fill="#000000" font-family="Serif, serif" font-size="493.88px">Audio decoder</tspan></tspan></tspan></text>
index 1e2cf498ba30ad62a630bf77e33b91217218c7de..b614bf81aa20ad7ee554b70c4d7f9d7c2352ffff 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. include:: <isonum.txt>
 
index 334358dfa72e442b98528368cd25359fc9441def..e10d675546f8539ef854a818fb18fcae90183b0b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _cec-func-close:
 
index e2b6260b00866198d1d14c828de0393422e719b9..c18d4ba5eb373fd45993de6f8482a443e3561d08 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _cec-func-ioctl:
 
index 5d6663a649bd67e6a22dccbdea4a631aa49608f4..f235aa80155cb9cbd04e26fe0242b47abd0a12bc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _cec-func-open:
 
index c698c969635c5732b3cb4ca6d4993807283e8519..3f6c5b0effa3e94c7c6ef4dd7c68023c70c00553 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _cec-func-poll:
 
index 6d696cead5cb58fe5f615960680c5ec44582bc61..620590b168c9e737c7c2c46b83262482d4d8f27f 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _cec-user-func:
 
 ******************
index d5a9a2828274c5e58126b2a607ebeed6e78e00d8..726f9766a130483c507b8aaee0528bca9e113d13 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _cec_header:
 
index 07ee2b8f89d6a320d66f1a9ed3d20977aa60c34b..05088fcefe8100ffdc968276bbfb0ab3938fad65 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _cec-intro:
 
 Introduction
index 6c1f6efb822e3012527c9d18e53b0a39936351bd..0c44f31a9b599523e121c61d35fa0f7f18f27b90 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_ADAP_G_CAPS:
 
index 84f431a022ad84e6531bc496e3671a592ec707bd..26465094e3f178afd5d6fdbe6175ed0e3b0e831e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_ADAP_LOG_ADDRS:
 .. _CEC_ADAP_G_LOG_ADDRS:
index 9e49d4be35d5b6b7332ee5c6522400f57012b55e..693be2f9bf2ef1d100ec646de8cfe766d9028238 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_ADAP_PHYS_ADDR:
 .. _CEC_ADAP_G_PHYS_ADDR:
index 8d5633e6ae04828899b6a14a732641971680f44e..46a1c99a595e1a8dd4bb29b325a59d63dc1c2dc0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_DQEVENT:
 
index 508e2e3256834667801ca5256fc770548db2f6e5..c53bb5f73f0df72c5ee720b64e1ccd87b8d3739d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_MODE:
 .. _CEC_G_MODE:
index b25e48afaa0877199953e0de0a9f0fcbd2676b91..c3a685ff05cb9d7bb43e7a86357809798b6e9610 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CEC_TRANSMIT:
 .. _CEC_RECEIVE:
index 464b006dbe0a07506c9f41805864bbf7374f005c..725f8b1c99659366caa3a83cc47d86bce4b43f16 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 CEC Pin Framework Error Injection
 =================================
 
index 1279bd21dbd0483b8ec6a2d65166417f3a3fd11b..ee2ee74dafa343791ea56c7d53bb4bdb0c58f46b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_BILINGUAL_CHANNEL_SELECT:
 
index 8cab3d7abff538e2a304518500457dee8c1233a1..ebb2f121c4c89476f261a8261c432a7ae2d0f918 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_CHANNEL_SELECT:
 
index f6bed67cb070be512364ad4fce69e46dca592e55..c5b62cde18c8ee1bef75f3906decc07a14c54e10 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_CLEAR_BUFFER:
 
index ca587869306e3ac0b3308745b887a54952b15986..6bdc99e39e20da4fd2b474ed405b3f238602c3b5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_CONTINUE:
 
index 58d351a3af4b0d2ef28906c661bf4a0c1f3f0837..1e4ad7a0325da65b497aa6c7f3164e146951ed34 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio_fclose:
 
index 4a174640bf119c23dd62cc3d9d6dc693ae7e054c..2cf4d83661f4410e6dd00b6cbaaaa82b2c331a18 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio_fopen:
 
index 4980ae7953ef382b3721f142c4b677ba1f1a83d9..6dc6bf6cbbc7dbe296f2b0a980e7d932e4b44cc5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio_fwrite:
 
index 0d867f189c22a8bfe4e135bc0cc4c07b9eb10988..4f1ec47e8ac209b53bad7e7832738df8a6f5f49f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_GET_CAPABILITIES:
 
index 857b058325f125f43ff3d13ff3a5c9c692be6466..30e4dd7fce6ddf4bbead4bda8f6c723f9038be6d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_GET_STATUS:
 
index c7310dffbff2f9b7cfb70e3e052e9ceeb8755633..4567ecd9e0a32174f41b891b4e31ab789ce43780 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_PAUSE:
 
index 943b5eec9f280505f391fd088d3c6ae451864268..17acd4c411b8830bdcfac647fb929872bca70c90 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_PLAY:
 
index c0434a0bd324431c31d6c7c5ed72805d743ce9f4..c5ed6243b11c75337095e7ca5dd4a1e430b2c636 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SELECT_SOURCE:
 
index cf621f3a30377e48143256da21430e434a67b8ad..c116d105fdead7bb1301f29dc5feb843dfb33fbb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_AV_SYNC:
 
index f0db1fbdb0661eb63fcf270710188c83b9dbae53..d537da90acf50aafc1e14ff8eb7f4c5af34dbd7d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_BYPASS_MODE:
 
index 8b1081d244733e23e79fe0cc00c3308a139d5b6d..aeb6ace6cd1edc3fec51d582ac1752631f4b33ad 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_ID:
 
index 248aab8c8909f98d87aa9e7e6c74924f4f7c7b3c..60781aa882022eaafc4db58954568d8ae855c9b1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_MIXER:
 
index 0af105a8ddcc0785e854948b836e2a0e2510eaa4..4449f225e48c2b772d9f069f115cd71eef1c761e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_MUTE:
 
index 46c0362ac71d31afc52505e758b1d44153a63152..d20c34fc712880f8e0c03264a760c012b756399a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_SET_STREAMTYPE:
 
index dd6c3b6826ece8eb2c364330f16f0826e407f78f..1bba2e50c3648028ba31ead21149d0472ae3384e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _AUDIO_STOP:
 
index e9f9e589c486d82c3a1bf3fe0ab7e421c4fc226c..ebc18fca76a413c6fa23605b6ff6a0b02013c98d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_audio:
 
index 5bffa2c98a24d87fcc712a96703c002cd27d99e5..5b032fe13b9d8031993809f56630b8a7858ed851 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio_data_types:
 
index 7dba16285dabf6d261b2f71bbfd56c1dffa7c1e0..5478e78b085ea33c975242b002ac90d35bcca5dd 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio_function_calls:
 
index e84bbfcfa1846d946b0f82d4c02c751ed9b07c76..e273444ccc67770712f08f06c62a63e912937b88 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _ca_fclose:
 
index 056c71b53a70a4d8a135952de6fc2cf2cddd55bb..e11ebeae569313efcbe828bc8c6f5d36cab4efdb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _ca_fopen:
 
index d2d5c135539682733176ebde4f5c9f4702fd8385..9e4fb51863732f5c1dcf2d079cb139954b4dd8e7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_GET_CAP:
 
index e564fbb8d5240522b5467d6aca3330e5d9f6f2e2..80ef43a339df61cf9689a6c1cb6c7f52f5af2c0b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_GET_DESCR_INFO:
 
index ceeda623ce9358d9b8bbfc3849b4be398979f9ab..bcb7955a0ddc4c50f6fc642046b5c3d0c97ac2fe 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_GET_MSG:
 
index 1a1d6f0c71b99a799b9a081a87dbe5d3860d580a..1ea5c497f2ea0771ea6acf590689bf6eac04ce80 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_GET_SLOT_INFO:
 
index 29788325f90e58363043ba3225a33c3004486785..29fda19984bed88ab98f16867b6c7e73a57becf7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_RESET:
 
index 9e91287b7bbcbd7d314106947dabecfa6f65d9cd..5a3c4e8120c41d905bb7200e7ea89e099172c326 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_SEND_MSG:
 
index a6c47205ffd859514c881a2b38ec69b3cec0d42b..22c8b8f94c7e93377942d13523f10c85596efffa 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _CA_SET_DESCR:
 
index deac72d89e9313ad863ba0451763ba52bfaa48be..8796512c1378bfd212e9fdb36bb43b101ab24d88 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_ca:
 
index ac7cbd76ddd51c6f122e7d5dd4f38f9379de2a34..834c8ab4c300c350b253837136c0bd70560e765d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _ca_data_types:
 
index 87d697851e82dbffd58f7512fcded351a7ad4710..6985bebd0661add87c54d2716def64d5a3501d30 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _ca_function_calls:
 
index 45c3d6405c46a7e8f9d7c0ce2d01336dc2f41d69..d8c0ff4015fe508fb2ebb5cd6255f2f4955da41a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_demux:
 
index 4d5632dfb43e958d2fc9a8cfc9bb2b84f890f112..f483268e4ede6190087f473f350da64dc486e93b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_ADD_PID:
 
index 2d96cfe891dfd6bfcd3195eeb3b26cd992790ab4..d7f0658f3db343b25e31cbcfb9988270033cd9fe 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _DMX_EXPBUF:
 
 ****************
index 578e929f4bde9305e63f1f3d23b2edfc801ba782..05ff322702745331cb513497236fc60d272e0a8d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_fclose:
 
index 55628a18ba67245c6e7d23b5c19851b1bfa81027..2700a2fad68b95bba57ba1ae2799a73dbe4a9bfe 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_fopen:
 
index 488bdc4ba178a90c37758e42d1b8a049f20a36b8..292fa98f39ffee65dc0d032f5c949cc04c3d4308 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_fread:
 
index 519e5733e53b06f512d64f90c8d78095e11f6660..bdd4d4743bd5efa77f28cf96f80c613debf0490b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_fwrite:
 
index fbdbc12869d1c7b88433e1226403df58944a510b..fcd3dc06c0954e2620c9a0ddaf7c3e616b756a12 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_GET_PES_PIDS:
 
index 604031f7904b0b06a67913e8f24182e47d950442..2c81595f470a28df691a02624802af6ed9bd7ec5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_GET_STC:
 
index 15d107348b9fdfb385e4fc130e222fd472098313..34bb7766718feb653b7905d3327489a3f200f236 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _dmx-mmap:
 
 *****************
index d77218732bb6ab21bf206359c15f5ea08a1b07b3..ef26b6f2b12bb3d449fc38ce5aaf3dcfdfee6809 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _dmx-munmap:
 
 ************
index be5a4c6f19040c6e5bf1acbb34f9598e6eec0b2f..9a1d85147c2546b8ac0a56d1a6f7ee4368b90766 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _DMX_QBUF:
 
 *************************
index 89481e24bb86b312ac49c6398c7b136b3c0f9014..4cf36e8216960509e28a52fa80a2a7940ac3c9a8 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _DMX_QUERYBUF:
 
 ******************
index 456cc2ded2c053ac1f3f64b37847b7bebb59c31b..be992f44f306c626ac67a506b96d36bfd5ddfe4f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_REMOVE_PID:
 
index 14b80d60bf3514d0b4a8692e8431b8623d95a8c5..b302785bf678d2e19ca5236023359df11522eb99 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _DMX_REQBUFS:
 
 *****************
index 74fd076a9b901581cd2c43c9ab3d8902ec33700d..2dee0fb11f625f79125da1cc8671d7607b3c1d56 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_SET_BUFFER_SIZE:
 
index 88594b8d3846f6725503b62e7acc8cde47e1ce15..66afbb9f2fe47de667bf71ea02ee1c41a3df5d86 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_SET_FILTER:
 
index d70e7bf96a41c36c8557f8a2b800164de17d34a8..dae5ab7878e5bcf9f8c163d4f1d3a13469cabe92 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_SET_PES_FILTER:
 
index 36700e7752967209661d8036668226eed478c4ff..488289d0250403530882cbe6673f5edc03abe8eb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_START:
 
index 6d9c927bcd5f995e110bc12ef476db312ed6b439..982384d129233c36ce1a383df3bd174e59f7f5e3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _DMX_STOP:
 
index 4c391cf2554fae4cc5799cf2a60eb52fc1d85aae..67312ab65f943acdfbf0053f13b2b090935895fd 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_fcalls:
 
index 2a023a4f516c75bb39ecf521b27d7b196f6bc2ad..b5cf704199e5d68d853d2ecf660537853c090655 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmx_types:
 
index 212f032cad8bd5c405ac5d09364f9de63416338a..172783b75fb73e034a7b0acd79c68aaa0ddd8203 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb-fe-read-status:
 
index 2088bc6cacd8195e8726e8541b264da254347639..ad4af66040c75a7b116c6f83443baa626fc3c598 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. c:type:: dvb_frontend_event
 
index b152166f8fa7efc24e99cecadebcea9ff0d9c1ea..67c2a316019f35b6e752799f89903c72e651e08f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. c:type:: dvb_frontend_parameters
 
index 89ddca38626f9e0cf490177fd0213e52f0ec9658..0fcc01f182f9fb24d8213b51c8aca9a7dc3ac739 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. include:: <isonum.txt>
 
index 1a56c1724e595b849720c9f17b980fa01aec028b..371c72bb94196fa6c752c6b20b7cbb0737dd579b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend-properties:
 
index f6fe2f8373737410ee0556dfa814a658cd2b4aad..c7672148d6ffa883f52235b41314920606039310 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg id="svg2" width="15.847cm" height="8.4187cm" fill-rule="evenodd" stroke-linejoin="round" stroke-width="28.222" preserveAspectRatio="xMidYMid" version="1.2" viewBox="0 0 23770.123 12628.122" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><defs id="defs142"><marker id="Arrow1Lend" overflow="visible" orient="auto"><path id="path954" transform="matrix(-.8 0 0 -.8 -10 0)" d="m0 0 5-5-17.5 5 17.5 5z" fill-rule="evenodd" stroke="#000" stroke-width="1pt"/></marker><marker id="marker1243" overflow="visible" orient="auto"><path id="path1241" transform="matrix(-.8 0 0 -.8 -10 0)" d="m0 0 5-5-17.5 5 17.5 5z" fill-rule="evenodd" stroke="#000" stroke-width="1pt"/></marker></defs><metadata id="metadata519"><rdf:RDF><cc:Work
 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><rect id="rect197" class="BoundingBox" x="5355.1" y="13.122" width="18403" height="9603" fill="none"/><path id="path199" d="m14556 9614.1h-9200v-9600h18400v9600z" fill="#fff"/><path id="path201" d="m14556 9614.1h-9200v-9600h18400v9600z" fill="none" stroke="#000"/><rect id="rect206" class="BoundingBox" x="13.122" y="4013.1" width="4544" height="2403" fill="none"/><path id="path208" d="m2285.1 6414.1h-2271v-2400h4541v2400z" fill="#fff"/><path id="path210" d="m2285.1 6414.1h-2271v-2400h4541v2400z" fill="none" stroke="#000"/><text id="text212" class="TextShape" x="-2443.8779" y="-4585.8779"><tspan id="tspan214" class="TextParagraph" font-family="sans-serif" font-size="635px" font-weight="400"><tspan id="tspan216" class="TextPosition"
 x="1281.1219" y="5435.1221"><tspan id="tspan218" fill="#000000">Antena</tspan></tspan></tspan></text>
index 16dd90fa9e94eae3b1aae295171da99ee8d0f503..eaa41bc8d1731b54457e4e83a4f7896bd47a5caa 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_examples:
 
index 70256180e9b3375b3a7a9fa74ba15487516e7d16..c3d7837b5f87d81437da4abc5ddabb38e8a82354 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ******************
 Frontend bandwidth
index f220ee351e15fc1085c51e42e929bf082395144a..88fd2186ca4daa7cac84d042e5788f7b69080baa 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_DISEQC_RECV_SLAVE_REPLY:
 
index 78476c1c7bf5568094621c28a0f0753c8e61ad07..92929c2e75dbff6d1c5f57e24ccb1f21f0dfcc82 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_DISEQC_RESET_OVERLOAD:
 
index a7e05914efae534e02c635ac8a31342b0983799c..8af872d306aaff7c87cb49e32b5743cf06341071 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_DISEQC_SEND_BURST:
 
index 6bd3994edfc2c010db18294ef16e1b1d87b7bdf5..30a48114153c0b20b2485fd27332911d04e05a14 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_DISEQC_SEND_MASTER_CMD:
 
index dcf2d20d460fc79444921ecf12cdb1d13ed9bd7b..13811289971b03b2d188706e205a2f13e152d447 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_DISHNETWORK_SEND_LEGACY_CMD:
 
index b20cb360fe37962a6c75c60c4e7802fcadbfb6cc..32b7d140d80b56828ad97bf51b8b0f8124eaf920 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_ENABLE_HIGH_LNB_VOLTAGE:
 
index 505db94bf1835619478cb392d8773bcab9635a77..2573d5b9b63650e82601ef666342eb06e2540447 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_GET_EVENT:
 
index 5db552cedd703019e12f5515a36c72ef924f8b1e..6cd5250d1832af332679088fdf03b568715c77d2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_GET_FRONTEND:
 
index 49307c0abfee1d96cb83730ce5311c0444a04308..551e68b115283bc54131d3557c85995c91b84df9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_GET_INFO:
 
index b69741d9cedfc30adaa9af94aaaed01adfddcc41..99386c7461b32fa7a8f260ccfc841779a7a2e7d1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_GET_PROPERTY:
 
index 1e6a79567a4cdf94009b728b65974bc74ca43542..e579d648687efcaba6c3b8f6a65219d3498fd6b9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_READ_BER:
 
index 198f6dfb53a17bc0a2086ca3d6e3ef3d05482535..0a0c0c2ff207aebc5a93eefd152300a8a5de2352 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_READ_SIGNAL_STRENGTH:
 
index 6db22c043512554359bd08e6a5f47422c5e52b9d..2a7a0d8f1fd55f74c1cef7de8d6f2e5f8b746d4a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_READ_SNR:
 
index 4adb52f084ffc70bab03ffd7b496fbe2917903e0..0dfc9fdf568f43fa00755828f3039e87f5d12300 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_READ_STATUS:
 
index f2c688bcacb3545652f980b812be5e54006cf9ce..19c532f750aa3a550a7804b0413b504649717f5e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_READ_UNCORRECTED_BLOCKS:
 
index 3c4bc179b31368b396f614d87c1229273c1df238..36e8913170e1c551224f8a1faab5fecfb5442f11 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_SET_FRONTEND_TUNE_MODE:
 
index 4f3dcf338254a248a65bd76388ec8deaf97a358a..23caae2588d27bbeb2e0490d7146563585658551 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_SET_FRONTEND:
 
index 758efa11014cf550dad08baf6ef0c2ca32889535..fb605e8c9fc433efd06ac866f7d8a10ae14f8a1d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_SET_TONE:
 
index 38d4485290a05b1ecbc908d463ab31a5f02836d7..c81a8e6a59aa42d80c580967eb1d55dbdf761c35 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _FE_SET_VOLTAGE:
 
index dee32ae104d735d3bd19f67251ee6356b88d703a..9720d2f7ba353172274370aeda5a39e17138bb06 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 *************
 Frontend type
index 3524dcae4604997a2550672fa9e94a1e890ffa90..2fd2954d8dae095c8a1e86bc549ae2b6294fa552 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _fe_property_parameters:
 
index 8d8433cf1e129959e2030bf7ba1c9256c6c774c7..635fb425121440531ae195eef50478cd7967ab2c 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 Frontend uAPI data types
 ========================
 
index bf2328627af5f865cc365e6b8fe7b0d740769ceb..97fbfc228c109bfbb379059d6f46d44105abc7d8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend-property-cable-systems:
 
index 2929e6999a7ab0c72c33b98db6b5a7ac73d252dc..2bc880a3c8261f0721fe68b971f27fc7a5ecbe47 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend-property-satellite-systems:
 
index 0beb5cb3d7293d299d4e8ca57d3ae756fbeeb10c..c20af13297e5992df2a91b46cf512a26a390e379 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend-property-terrestrial-systems:
 
index e73754fd06317766fb09e5bfefddbae347e8c3d8..546464db04b58ae50d0f02ba231771a24034ff22 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend-stat-properties:
 
index 4967c48d46ce3513c29ad0a3c7f7cba778987f20..7ff225dfe11cab4446069def9698cddf5ba238f8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_frontend:
 
index 67958d73cf348092a88d00b82e2c09e7d6c72a38..af87c2a8371950b5e05df61c859708cd18ea1f3d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend_f_close:
 
index 8e8cb466c24badad5893d754c9b39b90b2948b28..6a46ec5acf7bda2328d9e5229eb7864ae2487b80 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend_f_open:
 
index b03f9cab6d5a19fc42f82123ec79c5b2405d4c40..9b3586f538ea2d40de6e31dba74c74558eab279d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend_fcalls:
 
index 759833d3eaa483b8e57d694338e9204588e2dcb2..1ea749d09ca22b71c09087ea39db1759624e41a2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend_legacy_types:
 
index a4d5319cb76bc112605d51d7a0603ff7aca55807..1567bc73855ae583288399dc7bf22008a5a0f940 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _frontend_legacy_dvbv3_api:
 
index c13fd537fbff470fc300fec9becf72fce4795ddc..edeabd9e8e90f9b646b242dc44ce0b228cab4bd9 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 ****************************
 Digital TV uAPI header files
 ****************************
index 79b4d0e4e920296a07a6acbeffb0da7a4d86dfa5..f1384616ac4ecb0820ae074369c9394ddcab96f2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_introdution:
 
index e1b2c9c7b620b3e6d29e663f5e77631c55e48496..a43b4c36d9358fe5a9c7d1876d45aff6886504ab 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _legacy_dvb_apis:
 
index 6749b70246c5269916019327fd4c746c1d239c9a..1188641b453e5beba64164af38ab586d53ac99a0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _NET_ADD_IF:
 
index 3733b34da9db8132ff6d8f8924914d6211150b4c..7c4ef4b9d6cc8f0b699aa5cc8a31e646287417fc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _NET_GET_IF:
 
index 4ebe07a6b79a6eb03705b30396bc2f2a3047c51b..bf9a1602eeec109c195eb1b9b28e7677067c69d9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _NET_REMOVE_IF:
 
index 8fa3292eaa42596d45280d187ea3e9ded4508e25..9e16462a1ef42dd3ee22b4a64ab467c6081d720d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _net_types:
 
index e0cd4e402627ef84faeaa43a0ae55f344219cc13..833daa381968b6591a825a7fe9d760fa8926a15a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _net:
 
index 51ec0b04b496cc806525e09cdbcb49c9180cd94c..9a6badc1d29558203f31fbaabb19836c6e78e8ae 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _query-dvb-frontend-info:
 
index 2e51a78a69f1cdf2c62eb2ea9201fbde6c7d342a..5eb5546e8ce481ca6c58e3e013dce61b61bfd93f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_CLEAR_BUFFER:
 
index 536d0fdd8399824975fa2abc59fc2c3eaa048ba2..020b49645c6b8141a17c4eef46ccf5c7200350dc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_COMMAND:
 
index e65e600be6322eb1ea7987558f8c4c6111104cea..2ae2067dfba89f4c0154b5a5ca057a1457928b03 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_CONTINUE:
 
index 70a53e110335290f138c84091ae8618372118fbf..3f805f334ae1a13bf382e01563d7c9d416163733 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_FAST_FORWARD:
 
index 8a997ae6f6a7c6bcb7da4e69fa903e44c6f7e3d8..3b0285b96a3c547c171e980338ab20471004381c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video_fclose:
 
index 203a2c56f10a601f4a4b3a139caa4f922c3a8377..7b2a8c750e6a5ed0042598ec71493b002e53540b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video_fopen:
 
index 5a28bdc8badd2467cd15c10a0665980de5b0858d..6b31a4755d2c5b9aff5cf43a7b6238fd84e83e0e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_FREEZE:
 
index cfe7c57dcfc74eabc28c8cc0e9f44c4fe3614551..eb35b79eb85c2dea3a77d03dac733f99cff5cd20 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video_fwrite:
 
index 6987f659a1ad42dda7b3d6e8beafe016202b5c48..971fdab70e15c31f133985122564a58d017b2aaa 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_CAPABILITIES:
 
index b4f53616db9a4969b02959ee4de9d92ce6d06aba..def6c40db6013c15284dbc92a0ddca703fdee3c8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_EVENT:
 
index 0ffe22cd6108b4a4462904da7669358f300bd0c3..ef35da7d48610aeae758832d62b9e8ddb3e89339 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_FRAME_COUNT:
 
index c73f86f1d35b0a9d337fe47d3c0033b7b9350063..86ceefff78342d05bef951e24536e9d374a99ba7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_PTS:
 
index d077fe2305a0942411897fa31afa3a7d6ad91bac..cc92189d31fd5e4496580fec1ba2c3a3ef3b832f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_SIZE:
 
index ed6ea19827a6145546629860506dc06e83481ce5..8bfcf8fc3e195311fc2f7841d78f5073a52f726a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_GET_STATUS:
 
index 2124120aec2205fa827afd20143ad6e2f3428cb9..fb3f4f168814eeae26bc622aa08dc3a73338358f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_PLAY:
 
index cde6542723ca2eddcabddddfb9f920927fdd1c52..32cf025356dc88b944864171342fbc1328b2aaec 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SELECT_SOURCE:
 
index 3858c69496a5ec31be8f338eec11a81ef06a7f1e..901c3c80f167a5bbefb1cdcfee12b7ab6a2b51ee 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SET_BLANK:
 
index 2ef7401781be0b3742e91e685e24168eb552535c..ffdefa34120786c6a8e6d3f42bac02cb98a3390d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SET_DISPLAY_FORMAT:
 
index 4239a4e365bb2b2818435aa3616231c4d79ebdec..63e60214ab37d71dca0270c4e4acdeb25ddcb5d2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SET_FORMAT:
 
index 02a3c2e4e67c5ad9ce3182227f500e5f18a69d1c..845486a6e049a6d5115aacee3eee419727c367f9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SET_STREAMTYPE:
 
index bd3d1a4070d9769e3b19684af5b46bddbd5663d3..32c934aaf2bacee47dfd62f643298af415c87f2a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_SLOWMOTION:
 
index 6f943f5e27bdbfe889bc7f62ab0531688c092aad..58035a7630e67c6664109236a9fa23612144736f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_STILLPICTURE:
 
index 474309ad31c2b62fa916c4a7d7edab6df759de78..732ace05e34b1522251119e3978cfbe0f6775459 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_STOP:
 
index 008e6a9ab696abb11d48cdffb9dd00b0fb57fe94..37ecf8e91eb82ffa58be4b9fa266d67157958ed7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDEO_TRY_COMMAND:
 
index e7d68cd0cf23e4d50365f81bf6137aa2686fa0e4..6d72ed0e2b2dbbb70c2e38de9c38aca01ab549d5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dvb_video:
 
index a4222b6cd2d3b7ffa558a9efee9db8c41ea3d58a..9e8e49e52b191d9fc4b77728ef999d8e4a32df7b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video_function_calls:
 
index a0942171596c0625fc8a5157e85e237d66d155c9..2ed8aad84003e058bd803c330f5e67e81343ca5b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video_types:
 
index fd475180fed828a2868e4350d004cf4e36f56b26..f8dc85d3939c5fbf9cf833c0d18fc88b503e68af 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _fdl:
 
index 689d3b101ede2b28e72e95a307c751c500babdee..043c312dc06d161eab86990d1b04fed3d93df762 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _gen_errors:
 
index 3e776c0d827671eb0490696d0f28840d4e46b839..281c559c2f3c0bbd7e37974d08d2768d599ebab6 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-controller-intro:
 
index 558273cf9570364d621abd7e919868974746ab69..b6d5902b556df0964f09683f65d68faa6535048d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-controller-model:
 
index 66aff38cd4994d6a75ae76b73339f7786f809621..6e624f69033167e89d1659cd5ac4dcf48234301b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. include:: <isonum.txt>
 
index a8f5203afe4b71048dffb6c71248e7b641da2b5a..369ccd4dee56449a6f90c4cc5d6824154925c6e4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-func-close:
 
index fe072b7c8765456dff957459f84783e28e1318f9..9a990d6480f5a5fe0d13ac1042f3b0f4580fc8a1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-func-ioctl:
 
index 32f53016a9e5194525ea517b70af5d5871c532b3..cd2f840ddf73f9bf8f5864e289c41c75aec9a229 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-func-open:
 
index 260f9dcadcdecb795b6d1ad4a4b84a421d7fbcc6..87b65df8252a5353d4eb0a7952bf62d75af54fa8 100644 (file)
@@ -1,3 +1,12 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _media-user-func:
 
 ******************
index 96f7b0155e5a5a6630687dd722d3afd1acff5870..1cb7c88aeff0b3d05f5e9f14ae464d211fc2366e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_header:
 
index c6f224e404b79ce46b2f908aeaff03caa2437629..f8038cfb708c8b6483d9eca02a8fee3429fb24f4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_ioc_device_info:
 
index 02738640e34e82f1edad0cb47b968f41039f15b5..6218d9cbdd83e90f40004f87c0792fd25a1f9443 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_ioc_enum_entities:
 
index b89aaae373df5af9252338eca2fbe81a5a2018de..a982f16e55a460315de9fd847ec706979890a83d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_ioc_enum_links:
 
index 4e1c59238371a274012e9bb995376160193cd03a..0a7d76ac8dede54b009b918984dd4a631eae2b46 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_ioc_g_topology:
 
index de131f00c24966e29dde6e61b489cafef39c9b9e..6d4ca4ada2e0c5caaa0231b671d592b943a17a5c 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index e345e7dc9ad78971db1eee485383b9b7be1a1440..ae39dbbe48a0ead2d45212306b94312b34fc20d1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media_ioc_setup_link:
 
index 5d2604345e191c9a34fe63d3b57a2ed719e57fa0..fc8458746d51b5748ed2b1e44ca1e8a72463b95f 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index ec61960c81ce9b4eb47381eef9b5dfb57df1e7fb..61381e87665aa4af5451ba9ffe7dcc2a45bb3450 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index e4c57c8f45530de9d55aaceefbfb33b9ed507d3a..8627587b7075a5564c717a2153728bac9cb92dcd 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _media-controller-types:
 
index 945113dcb2185762e4d74d20712868755dbee0ca..4b25ad03f45aea8364d8e36d6dda33e5f677438a 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index dcf3f35bcf176d8a0d1a33e3b0d4a42c8832c72a..2cff7770558e1e3fd1c99b98ddfd518e9a1af85b 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index 11a22f8878439cb1fbae0837879b7e1b3c64d5da..de0781c618730944a8fa6d3fc22ae3ff48a724fe 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index 2609fd54d519cb2379f6ec19033ea87ac7c3469d..ebaf33e218738d44c7df6759e715b075f59ed363 100644 (file)
@@ -1,12 +1,12 @@
 .. This file is dual-licensed: you can use it either under the terms
-.. of the GPL or the GFDL 1.1+ license, at your option. Note that this
+.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
 .. dual licensing only applies to this file, and not this project as a
 .. whole.
 ..
 .. a) This file 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.
+..    published by the Free Software Foundation version 2 of
+..    the License.
 ..
 ..    This file is distributed in the hope that it will be useful,
 ..    but WITHOUT ANY WARRANTY; without even the implied warranty of
index 217237f93b378e7448a41a3a6b9ed89987a45fbf..46f98569e999d8eae785828a5d4cf807cbe8a9e3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 file: uapi/v4l/keytable.c
 =========================
index 11516c8bff62dd5403809ac04d72bb5849608ce5..1a901d8e1797c764d312749f5828ee32bb23c5f6 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_dev_intro:
 
index 03cde25f5859dfcac2118de1b6e25f57f3573b5c..7058e0b2296a0e6cd576123adedd1733324d7a84 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_dev:
 
index ddb4620de2940784fdacdcbcecc62109c0ba590f..25058369f724f5e437b60fcefd2f5508397bee25 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_func:
 
index 889a8807037b31b5b559f8a01c8ef22f9f775772..1d590df8164a9e7e8a6d3ddee33db47d95a12e86 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_get_features:
 
index 2722118484fac7305f249c9a86568081c0cea0d8..0a3e02aca80e79a048ac06f00ee1705dff79a35d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_get_rec_mode:
 .. _lirc_set_rec_mode:
index 6e016edc2bc47c442e8002517321872ee63ea832..f560b694ccf27e93b824e8d72ce997e971683398 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_get_rec_resolution:
 
index c44e61a79ad19a699bb74889ee7bfadbbcb2f7af..4f440c69705298b194d311cb756a5f0fbafdf25d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_get_send_mode:
 .. _lirc_set_send_mode:
index c94bc5dcaa8eb5da554b047e848a9f8e3facaa71..1de214529f2726bc1f8046dc7f75de3ba25d9328 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_get_min_timeout:
 .. _lirc_get_max_timeout:
index 487fe00e5517ddf5546dd3bc4cf0ffc0cb7f3716..c9b4f33e1031426a91f87318b7500e75e0d103bf 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_header:
 
index c024aaffb8ad3877d24bfda6b20e359540918274..a8fedfaaf0ab303b5b5fc45945716c0a0b2da3b4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc-read:
 
index 6307b5715595626784dabc7111c50dcae42b0ae5..c80acd85e369023a0977df9891e881d332a07920 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_measure_carrier_mode:
 
index a89246806c4b908a52931200f3cd2b2a804dd13c..443681d5cc101f5a3c3529ee2742de3ee4a50bb9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_rec_carrier_range:
 
index a411c033081898c23f467ebd075c0c05e855146c..cbe1e48b2a4a84e8c1eff8af2c73c0ce7bd3721e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_rec_carrier:
 
index 86353e6026955f9ff85005325b3d1cc267886a76..d06d69414c1edaaf06a8f622319fe3909a68309b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_rec_timeout_reports:
 
index a833a6a4c25a7c703a3028f35a04c1aff477cbff..163ac60657370c620529937e84dd1f140c0d515e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_rec_timeout:
 .. _lirc_get_rec_timeout:
index 42c8cfb42df5effad63ca8020c757cad33782e64..cffc6c1e15ccf6119acd82c82bc50359da3c7133 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_send_carrier:
 
index 20d07c2a37a58882b71eb69dc292e1249c5f666e..08ab3d1a96cdb19828284f148fe6b0a30fd500d0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_send_duty_cycle:
 
index 69b7ad8c2afb0560bb84e4123bd627e80f8136a4..889a739eaf0d847adfdc9c425bed88484dfc2ac8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_transmitter_mask:
 
index 0415c6a54f23d758c13ad7d9bcf4b15b54d103ce..592715452fce63bb90e4e4dd915a48fe3cccb5f5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc_set_wideband_receiver:
 
index d4566b0a2015f796750ef44cb5d19c726bc9c1ed..6adf5ddbac9948c844962fb8e555e99c44b1f83b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _lirc-write:
 
index 3707c29d37eddd43696652ac004dc7eb2fd14217..37c5f90c76e7c4d1d33f4c6ffabaddfb8d1e14ee 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _Remote_controllers_Intro:
 
index 2d01358d5504513f1bdcd3efc5f42e1ee23e1c26..b8e8319e33171794dd9276426cd06486c395a54d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _remote_controllers_sysfs_nodes:
 
index d604896bca8783f048b7a45760f731c0d2139652..4a2e601b89fbc304a5ac4cb1029a81f35dfbc439 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _Remote_controllers_table_change:
 
index c8ae9479f842e7f3dfcacb4e485016ea935a2292..cb670d10998b9d52d40616c76388734ee63c2c9b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _Remote_controllers_tables:
 
index 46a8acb82125d3b9a4d6e43e74cd2386ca0c0865..3051f7abe11d3ca1f9422a1d3f45df0709f91d04 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. include:: <isonum.txt>
 
index a8c41a7ec3965df56bcaf25ab5479e0bf83378e3..c25c1271b4f6819322b822d63501633b7f56333f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _app-pri:
 
@@ -8,7 +15,7 @@ Application Priority
 
 When multiple applications share a device it may be desirable to assign
 them different priorities. Contrary to the traditional "rm -rf /" school
-of thought a video recording application could for example block other
+of thought, a video recording application could for example block other
 applications from changing video controls or switching the current TV
 channel. Another objective is to permit low priority applications
 working in background, which can be preempted by user controlled
index 5affc0adb95b66578157b18f587cd08676ac62b5..be9539313f607cff6faecce0c4f7330ae8c0e404 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _async:
 
index 5ec99a2809fe4ccf6371d3ecf4eb99adfb5497a8..4c7fdbc8a860571abd575f4e44273a287cbbfea0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _audio:
 
@@ -31,7 +38,7 @@ outputs applications can enumerate them with the
 :ref:`VIDIOC_ENUMAUDOUT <VIDIOC_ENUMAUDOUT>` ioctl, respectively.
 The struct :c:type:`v4l2_audio` returned by the
 :ref:`VIDIOC_ENUMAUDIO` ioctl also contains signal
-:status information applicable when the current audio input is queried.
+status information applicable when the current audio input is queried.
 
 The :ref:`VIDIOC_G_AUDIO <VIDIOC_G_AUDIO>` and
 :ref:`VIDIOC_G_AUDOUT <VIDIOC_G_AUDOUT>` ioctls report the current
index c395113d1876b4daefd5eb222c15286f491bcaaf..c5bf85103901f7716221c61d8a9ee1f0bb678c1f 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg id="svg2" width="164.15mm" height="46.771mm" fill-rule="evenodd" stroke-linejoin="round" stroke-width="28.222" preserveAspectRatio="xMidYMid" version="1.2" viewBox="0 0 16415.333 4677.1107" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata id="metadata652"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g id="g186" class="com.sun.star.drawing.CustomShape" transform="translate(-3285.9 -3185.9)"><g id="id6"><rect id="rect189" class="BoundingBox" x="3299" y="3199" width="1303" height="1203" fill="none"/><path id="path191" d="m3950 4400h-650v-1200h1300v1200h-650z" fill="#00f"/><path id="path193" d="m3950
 4400h-650v-1200h1300v1200h-650z" fill="none" stroke="#3465a4"/><text id="text195" class="TextShape"><tspan id="tspan197" class="TextParagraph" font-family="sans-serif" font-size="635px" font-weight="400"><tspan id="tspan199" class="TextPosition" x="3739" y="4021"><tspan id="tspan201" fill="#ffffff">B</tspan></tspan></tspan></text>
 </g></g><g id="g203" class="com.sun.star.drawing.CustomShape" transform="translate(-3285.9 -3185.9)"><g id="id7"><rect id="rect206" class="BoundingBox" x="4599" y="3199" width="1303" height="1203" fill="none"/><path id="path208" d="m5250 4400h-650v-1200h1300v1200h-650z" fill="#0c0"/><path id="path210" d="m5250 4400h-650v-1200h1300v1200h-650z" fill="none" stroke="#3465a4"/><text id="text212" class="TextShape"><tspan id="tspan214" class="TextParagraph" font-family="sans-serif" font-size="635px" font-weight="400"><tspan id="tspan216" class="TextPosition" x="5003" y="4021"><tspan id="tspan218" fill="#ffffff">G</tspan></tspan></tspan></text>
index 386d6cf83e9cab74e741b2251c8e48e26f35418c..ec33768c055ec6d7285b1b88847e38c7d16bd60c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 **********
 References
index 2e266d32470ae5169a7b6bc1f1aa48c0ad6863bc..86878bb0087f2b4e4c1b9288d4454c588858c4ea 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _buffer:
 
@@ -465,6 +472,9 @@ enum v4l2_buf_type
     * - ``V4L2_BUF_TYPE_META_CAPTURE``
       - 13
       - Buffer for metadata capture, see :ref:`metadata`.
+    * - ``V4L2_BUF_TYPE_META_OUTPUT``
+      - 14
+      - Buffer for metadata output, see :ref:`metadata`.
 
 
 
index ac1cd057e25b9646a674b0e13ca403245697bfb8..130ca47ef796d20022f947c9e1427b9a82cb31b2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _capture-example:
 
index 56525a0fb2faf2ab532eaac1f47b59d093c67ef2..b4652c2351f2ceb3413e1e9b255d77f6c5516051 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 file: media/v4l/capture.c
 =========================
index f24615544792b2c20ee2325e815dfe52fb79e275..c4e8fc62037913ae2bc4274eda8a469c4d2ab6f2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ****************************
 Defining Colorspaces in V4L2
index 09fabf4cd4126b320c4e26d311e064cdaee17841..8b0ba3668101d6ac500641005a6150b5b06cef7c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ********************************
 Detailed Colorspace Descriptions
index 322eb94c1d44a949360c383bd3d2c8053606aaa7..c5a560f0c13d88dda6b239619837995fd0ea4ebe 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _colorspaces:
 
index 39058216b630b40f00577e96071f11d244fddc69..504c6c93c9b0fcf2cc37d76bde02f7373457806d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _common-defs:
 
index 5f93e71122efef492fba5eaa685788b27d19d27f..889f2f2632a18fb718ae1fbca13744acbc4def30 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _common:
 
index 8b5e1cebd8f4f894ca50d1a10e187f058128e955..f35575a300b4eef17e731e78eb92f80bddd35924 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _compat:
 
index 7e5d7185ca49ddbd40d4666d5f1dbaa0858ad0f2..08f9f8b0985eb10c137d76240af71ec67689be43 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg id="svg2" width="249.01mm" height="143.01mm" fill-rule="evenodd" stroke-linejoin="round" stroke-width="28.222" preserveAspectRatio="xMidYMid" version="1.2" viewBox="0 0 24900.998 14300.999" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata id="metadata325"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs id="defs4" class="ClipPathGroup"><marker id="marker6261" overflow="visible" orient="auto"><path id="path6263" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#f00" fill-rule="evenodd" stroke="#f00" stroke-width="1pt"/></marker><marker id="marker6125" overflow="visible"
 orient="auto"><path id="path6127" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#f00" fill-rule="evenodd" stroke="#f00" stroke-width="1pt"/></marker><marker id="marker6001" overflow="visible" orient="auto"><path id="path6003" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#f00" fill-rule="evenodd" stroke="#f00" stroke-width="1pt"/></marker><marker id="marker5693" overflow="visible" orient="auto"><path id="path5695" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#f00" fill-rule="evenodd" stroke="#f00" stroke-width="1pt"/></marker><marker id="marker5575" overflow="visible" orient="auto"><path id="path5577" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#000080" fill-rule="evenodd" stroke="#000080" stroke-width="1pt"/></marker><marker id="marker5469" overflow="visible"
 orient="auto"><path id="path5471" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#000080" fill-rule="evenodd" stroke="#000080" stroke-width="1pt"/></marker><marker id="marker5259" overflow="visible" orient="auto"><path id="path5261" transform="matrix(-.4 0 0 -.4 -4 0)" d="m0 0 5-5-17.5 5 17.5 5-5-5z" fill="#000080" fill-rule="evenodd" stroke="#000080" stroke-width="1pt"/></marker><marker id="Arrow2Mend" overflow="visible" orient="auto"><path id="path4241" transform="scale(-.6)" d="m8.7186 4.0337-10.926-4.0177 10.926-4.0177c-1.7455 2.3721-1.7354 5.6175-6e-7 8.0354z" fill="#000080" fill-rule="evenodd" stroke="#000080" stroke-linejoin="round" stroke-width=".625"/></marker></defs><g id="g204" class="com.sun.star.drawing.CustomShape" transform="translate(-1350,-3250)"><g id="id6"><rect id="rect207" class="BoundingBox" x="1350" y="3250" width="24901" height="14301"
index c1e6adbe83d7793505478a25160eb913b371dc05..0d46526b5935e2747337d6606474b71c6d242a0d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _control:
 
index 45e8a895a3202980a7db29d891de03ef9e0b5c19..ada7c22e6291b834c83bdaec1528d6a9ffe3614f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _crop:
 
index 3878fe4c49e99736e703903411eb9e04c89ec87d..32d72598d1359ccee358b1333ee4a6dd2032f32f 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index d1641e9687a61d8fba79a53da38b393cd50a85ec..1bfd0b82cb8595f19b787b7758c8c14fcb998882 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _depth-formats:
 
@@ -14,3 +21,4 @@ Depth data provides distance to points, mapped onto the image plane
 
     pixfmt-inzi
     pixfmt-z16
+    pixfmt-cnf4
index 4218742ab5d91364fc873ca049e878cfd053007e..134e22b32338e055998bbeb92f012c050bc4b9c7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _capture:
 
@@ -99,6 +106,6 @@ requests and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_F
 Reading Images
 ==============
 
-A video capture device may support the ::ref:`read() function <func-read>`
+A video capture device may support the :ref:`read() function <func-read>`
 and/or streaming (:ref:`memory mapping <func-mmap>` or
 :ref:`user pointer <userp>`) I/O. See :ref:`io` for details.
index c61e938bd8dcc36e964c9737c3d405132ec5b35c..b5e017c178342bf159193c3651f66544e5b5e02a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _codec:
 
index b946cc9e1064bb1603cd272a85e9a93ece5516e7..b165e2c20910546aacd911da54d9301abae2297c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _effect:
 
index a06ec4d65359c78950c34c42bd5da8487663bc1c..6029101fe1d7db27b0270bfa9adac9a2513a9ab7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _event:
 
index b65dc078abeb8ca4a1a9a045eddc2d1b8844c333..c5dbe882be654df5cdf97a815c152bde93af27aa 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _metadata:
 
@@ -7,21 +14,27 @@ Metadata Interface
 ******************
 
 Metadata refers to any non-image data that supplements video frames with
-additional information. This may include statistics computed over the image
-or frame capture parameters supplied by the image source. This interface is
-intended for transfer of metadata to userspace and control of that operation.
+additional information. This may include statistics computed over the image,
+frame capture parameters supplied by the image source or device specific
+parameters for specifying how the device processes images. This interface is
+intended for transfer of metadata between the userspace and the hardware and
+control of that operation.
 
-The metadata interface is implemented on video capture device nodes. The device
-can be dedicated to metadata or can implement both video and metadata capture
-as specified in its reported capabilities.
+The metadata interface is implemented on video device nodes. The device can be
+dedicated to metadata or can support both video and metadata as specified in its
+reported capabilities.
 
 Querying Capabilities
 =====================
 
-Device nodes supporting the metadata interface set the ``V4L2_CAP_META_CAPTURE``
-flag in the ``device_caps`` field of the
+Device nodes supporting the metadata capture interface set the
+``V4L2_CAP_META_CAPTURE`` flag in the ``device_caps`` field of the
 :c:type:`v4l2_capability` structure returned by the :c:func:`VIDIOC_QUERYCAP`
-ioctl. That flag means the device can capture metadata to memory.
+ioctl. That flag means the device can capture metadata to memory. Similarly,
+device nodes supporting metadata output interface set the
+``V4L2_CAP_META_OUTPUT`` flag in the ``device_caps`` field of
+:c:type:`v4l2_capability` structure. That flag means the device can read
+metadata from memory.
 
 At least one of the read/write or streaming I/O methods must be supported.
 
@@ -35,10 +48,11 @@ to the basic :ref:`format` ioctls, the :c:func:`VIDIOC_ENUM_FMT` ioctl must be
 supported as well.
 
 To use the :ref:`format` ioctls applications set the ``type`` field of the
-:c:type:`v4l2_format` structure to ``V4L2_BUF_TYPE_META_CAPTURE`` and use the
-:c:type:`v4l2_meta_format` ``meta`` member of the ``fmt`` union as needed per
-the desired operation. Both drivers and applications must set the remainder of
-the :c:type:`v4l2_format` structure to 0.
+:c:type:`v4l2_format` structure to ``V4L2_BUF_TYPE_META_CAPTURE`` or to
+``V4L2_BUF_TYPE_META_OUTPUT`` and use the :c:type:`v4l2_meta_format` ``meta``
+member of the ``fmt`` union as needed per the desired operation. Both drivers
+and applications must set the remainder of the :c:type:`v4l2_format` structure
+to 0.
 
 .. c:type:: v4l2_meta_format
 
index 71da85ed7e4bd744c1615e4d153f261362108271..d3ad67da6386da2b5ac703d34ea9beee37a30cb3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _osd:
 
index 342eb4931f5ccf080f013df17f0b4cc659ced680..3fe1b39696ed584f86df1b9acdffcd80512add30 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _output:
 
index 9be14b55e305cfbee3dc4511b7938413f9c03c61..b91b3837d4e70bbb202dd2d26c3e00c7e80224c2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _overlay:
 
index 2b5b836574eb930e131e70403ceb0bd005acff4d..133eb0e788c2ffd7efbb872d733edcf132886441 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _radio:
 
index 2e6878b624f65248a8ab38a42fc8fe4c8d88041e..d6a707f0b24f068d149a33159aa95620a9448fa3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _raw-vbi:
 
index 9c4e39dd66bd49468d59fb15fc1527b92a871dea..624d6f95b842215a863785d9eb5b1d279cc4effc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _rds:
 
index b3e828d8cb1f5057cdef21809edd0104f42961eb..75595c58cb5b7ffe6a1b7370987bf9ec6d368b1c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _sdr:
 
index d311a6866b3b0d4092a16a6994aea254add1e8f4..0aa6cb8a272bcefe6c33d92e65e2c416d26f98e5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _sliced:
 
index d20d945803a78bdb2fc348eff6ce6d404ac189b1..2c2768c7343b914438c4bd81ed1a28900dcd9f68 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _subdev:
 
index 2648f6b37ea35e31435741ce61e6672f9ed6fa10..35e8c4b354589d8e262c7c4ee5112eb67dcb7c7b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _ttx:
 
@@ -10,7 +17,7 @@ This interface was aimed at devices receiving and demodulating Teletext
 data [:ref:`ets300706`, :ref:`itu653`], evaluating the Teletext
 packages and storing formatted pages in cache memory. Such devices are
 usually implemented as microcontrollers with serial interface
-(I:sup:`2`\ C) and could be found on old TV cards, dedicated Teletext
+(I:sup:`2`\ C) and could be found on old TV cards, dedicated Teletext
 decoding cards and home-brew devices connected to the PC parallel port.
 
 The Teletext API was designed by Martin Buck. It was defined in the
index 98797f255ce0843e6f8df868fe30ae24986b9db9..356f013852215a754229f1f1bd2a93b770527f8d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _touch:
 
index fb7f8c26cf09e348e4d3807e1be72e41159afa8b..5dbe9d13b6e60a5f55b4a8d1589bf6c368bbe34d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _devices:
 
index 8209eeb63dd2404779fcbe84292da64541029314..dd6739e8a5b20daead63277bc6c329831acab9e1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _diff-v4l:
 
index 4e980a7e9c9ce137d52f5723b1e1eb101693dcee..bb8fd943b14e2ba8a85b22d70e2f4ff494ed6cdb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dmabuf:
 
index 415a0c4e2ccb04a2643ccfc1ccbfbdc3646399e5..b3c69ca559e2c49932091b6f269c790e1c52f15f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _dv-timings:
 
index 027358b91082534edb2f6da8955689ec20868ba3..c471408d9bf98f415fd62303cd3a7ab660e22828 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _extended-controls:
 
@@ -1110,10 +1117,16 @@ enum v4l2_mpeg_video_h264_loop_filter_mode -
 
 ``V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (integer)``
     Loop filter alpha coefficient, defined in the H264 standard.
+    This value corresponds to the slice_alpha_c0_offset_div2 slice header
+    field, and should be in the range of -6 to +6, inclusive. The actual alpha
+    offset FilterOffsetA is twice this value.
     Applicable to the H264 encoder.
 
 ``V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (integer)``
     Loop filter beta coefficient, defined in the H264 standard.
+    This corresponds to the slice_beta_offset_div2 slice header field, and
+    should be in the range of -6 to +6, inclusive. The actual beta offset
+    FilterOffsetB is twice this value.
     Applicable to the H264 encoder.
 
 .. _v4l2-mpeg-video-h264-entropy-mode:
index 5f3f82cbfa34bf8bd1aa475dcccf3661ea492393..8415268d439ccc6eb12fccd74956d32805bb9933 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _field-order:
 
index 909d758f8543fea33e710deb77ad8c6c461a2c6e..1dab1cd1b6de93fb01a494847acda5a010151dea 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
         sodipodi:role="line"
         y="-328.99481"
         x="10.054964 14.17972 18.766451 20.597849 25.18458 29.771311 34.358047 38.944778 41.238144 43.531509 48.118244 50.865334 53.158699 55.452068 57.283459 61.870193 63.701588 68.288322">v4l2_buffer.field:</tspan></text>
-</g></svg>
\ No newline at end of file
+</g></svg>
index 7c74344e770fa64658d20b86d3e7be42743b91ab..041071e43f9bb085e442a9620ba6f9ef20e2d7ce 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
         y="-311.9397"
         x="10.05469 15.55712 20.143852 24.730585 29.317318 33.904053 38.944508 41.237877 46.740307 51.327042 57.283192 61.869926 66.910378 73.328506 95.0867 100.58913 105.17586 109.7626 114.34933 118.93606 123.97652 126.26987 131.77232 136.35905 142.3152 146.90193 152.40436 158.82249 163.86295 168.9034 175.32153 197.12534 202.62778 207.21451 211.80124 216.38797 220.9747 226.01515 228.30853 233.81096 238.39769 244.35384 248.94058 253.98103 260.39917 282.15695 287.65936 292.24609 296.83282 301.41956 306.00629 311.04675 313.34012 318.84256 323.42929 329.38544 333.97217 339.47461 345.89273 350.9332 355.97363 362.39175 384.19559 389.698 394.28473 398.87149 403.45822 408.04495 413.08539 415.37875 420.8812 425.46793 431.42407 436.0108 441.05127 447.46939 469.2276 474.73001 479.31674 483.90347 488.49023 493.07697 498.1174 500.41077 505.91321 510.49994 516.45612 521.04285 526.54523 532.96338
 538.00385 543.04431 549.4624">V4L2_FIELD_TOPV4L2_FIELD_BOTTOMV4L2_FIELD_TOPV4L2_FIELD_BOTTOMV4L2_FIELD_TOPV4L2_FIELD_BOTTOM</tspan></text>
-</g></svg>
\ No newline at end of file
+</g></svg>
index 3e3efb0e349e60930f5ca30575b3385ef886a59e..9cdb296333b8df74f8432dd12e279ad9e4730333 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _format:
 
@@ -12,7 +19,7 @@ Data Format Negotiation
 
 Different devices exchange different kinds of data with applications,
 for example video images, raw or sliced VBI data, RDS datagrams. Even
-within one kind many different formats are possible, in particular an
+within one kind many different formats are possible, in particular there is an
 abundance of image formats. Although drivers must provide a default and
 the selection persists across closing and reopening a device,
 applications should always negotiate a data format before engaging in
index e85a6744eb913e67aacf14837cf14f4d2e4ca808..1a56811b827e82d4d05c03b669b8b66e4770031b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-close:
 
index ebfbe92f0478c14b8dc13e9197fbba2de143d588..e7a8cf62752e97c4386b2905cb8e20f2cc5cb84d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-ioctl:
 
index 6d2ce539bd723ec747ce0fa111085307e0e5f78d..75985d80788a6531ca252d52cef0361383fba999 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-mmap:
 
index c2f4043d7d2b7612114f2b6989be946fa4baef91..0d472d86a0361da94fe21eedbf28260c2264de8e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-munmap:
 
index deea34cc778b4ddf7c8ade576599456150701252..a3d149ce6635c506ae90cd84871825819cecb2a6 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-open:
 
index 967fe8920729c5721594fb75244432c24e478611..4c579ed31358dbde2949e692b6ff33359f0988a9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-poll:
 
index ae38c2d59d4999272dd17aab977e78094186ae4d..14aca4d5e8fdbc03928e2130b8592a130d6cf6e3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-read:
 
index 002dedba26661743a521228eb8884282b174f3b8..af5f1e31c0fbfc8fcd8eddf868eaccbe10a5704d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-select:
 
index 938f33f854550dd4eade94c57bbf06a950aca001..865129c726ad533840824f245d694b8013bf5b78 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _func-write:
 
index 058b5db95c32bd505f9c75b5146b41d5797f8d12..7d8e9efbeb1ed0ee5fc57a3e83bc6da9367b03ea 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _hist-v4l2:
 
index f0f2615eaa958c834760877435d30bb9c70594b0..f52f8ba131f001bfeca4ca2d79be49c361af746b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _hsv-formats:
 
index 94b38a10ee658dbd4208d33485d60a48ac42bb91..049a2530d3a25125ff36f0b18179609e1e42a506 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _io:
 
index ccc3c4d2fc0feb04be988bbfc4bd1c7267f37f69..1b206d380d4bbf0bdf229512680a9671e8e4318a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _libv4l-introduction:
 
index 332c1d42688b5ea76ee032bb4524718cef79ea9e..d114fbf1ffa65b3053c39bf8e8550c20fcb745a8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _libv4l:
 
index cf971d5ad9ea7d7d52ea4668b65572c96ad76b57..5f956fa784b7f4218ccf4c8efc51ff83816ac900 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _meta-formats:
 
@@ -12,6 +19,7 @@ These formats are used for the :ref:`metadata` interface only.
 .. toctree::
     :maxdepth: 1
 
+    pixfmt-meta-intel-ipu3
     pixfmt-meta-d4xx
     pixfmt-meta-uvc
     pixfmt-meta-vsp1-hgo
index 670596c1a4f7b5dc88a5aa6ae2a006f9f2f6f5bf..c47708bf2c8714829e7db9ad381f0353342e4536 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _mmap:
 
@@ -231,17 +238,17 @@ up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
 In the write loop, when the application runs out of free buffers, it
 must wait until an empty buffer can be dequeued and reused.
 
-To enqueue and dequeue a buffer applications use the :ref:`VIDIOC_QBUF`
-and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The status of a buffer
-being mapped, enqueued, full or empty can be determined at any time
-using the :ref:`VIDIOC_QUERYBUF` ioctl. Two methods exist to suspend
-execution of the application until one or more buffers can be dequeued.
-By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` blocks when no buffer is
-in the outgoing queue. When the ``O_NONBLOCK`` flag was given to the
-:ref:`open() <func-open>` function, :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
-returns immediately with an ``EAGAIN`` error code when no buffer is
-available. The :ref:`select() <func-select>` or :ref:`poll()
-<func-poll>` functions are always available.
+To enqueue and dequeue a buffer applications use the
+:ref:`VIVIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
+ioctl. The status of a buffer being mapped, enqueued, full or empty can
+be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
+methods exist to suspend execution of the application until one or more
+buffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
+blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
+flag was given to the :ref:`open() <func-open>` function,
+:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
+error code when no buffer is available. The :ref:`select() <func-select>`
+or :ref:`poll() <func-poll>` functions are always available.
 
 To start and stop capturing or output applications call the
 :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
index 65d05606c04cdb360aab9a29b4684e235c0c4344..067d8fb34ba27d03cfbb0a0c18895d4e28a7d4ff 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index fc51fe8fda8b677e3a74969009e31ac197851124..70c3200fdb3288f4bfb7b0e4b84bdc1e3dfec1f5 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index afd116edb40d1c00d878443fed75049141024591..42fad5001c5c03a7a636f5b93fa2007b4cdc6f95 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _open:
 
@@ -53,7 +60,7 @@ ranges. These ranges are listed in :ref:`devices`.
 
 The creation of character special files (with mknod) is a privileged
 operation and devices cannot be opened by major and minor number. That
-means applications cannot *reliable* scan for loaded or installed
+means applications cannot *reliably* scan for loaded or installed
 drivers. The user must enter a device name, or the application can try
 the conventional device names.
 
index 02d7fcf12b26bf1a62bd398b62aec69780b05e9b..8c53ce719a147d115b31bb771ffa5cdeaee58733 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 digraph board {
        rankdir=TB
        colorscheme=x11
diff --git a/Documentation/media/uapi/v4l/pixfmt-cnf4.rst b/Documentation/media/uapi/v4l/pixfmt-cnf4.rst
new file mode 100644 (file)
index 0000000..8f46929
--- /dev/null
@@ -0,0 +1,31 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _V4L2-PIX-FMT-CNF4:
+
+******************************
+V4L2_PIX_FMT_CNF4 ('CNF4')
+******************************
+
+Depth sensor confidence information as a 4 bits per pixel packed array
+
+Description
+===========
+
+Proprietary format used by Intel RealSense Depth cameras containing depth
+confidence information in range 0-15 with 0 indicating that the sensor was
+unable to resolve any signal and 15 indicating maximum level of confidence for
+the specific sensor (actual error margins might change from sensor to sensor).
+
+Every two consecutive pixels are packed into a single byte.
+Bits 0-3 of byte n refer to confidence value of depth pixel 2*n,
+bits 4-7 to confidence value of depth pixel 2*n+1.
+
+**Bit-packed representation.**
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths: 64 64
+
+    * - Y'\ :sub:`01[3:0]`\ (bits 7--4) Y'\ :sub:`00[3:0]`\ (bits 3--0)
+      - Y'\ :sub:`03[3:0]`\ (bits 7--4) Y'\ :sub:`02[3:0]`\ (bits 3--0)
index ba0f6c49d9bf6bf3492c4d82bb82a7108ec28183..e4c5e456df59e3c7a2005fb13f75de2eff9e0200 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ******************
 Compressed Formats
index dad813819d3ef9505085194175e7d14b61368fcf..3a8156164d39661b221e2409c1394e39a9cd35f4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-GREY:
 
index 6edac54dad747f90df34a414b6dce3dd97729b5b..4538b425a046e4abc4371005558bdfe2c82a2eda 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _pixfmt-indexed:
 
index 4bc116aa8193040f81cbfdd174cd222b64846f77..ca0a6e0d89595ddde043d89c022d7b2dc7db7702 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 **********************
 Standard Image Formats
index 75272f80bc8a9d3b91094cbeddaa71967bd568b8..af2940d844ff652b3bfb4c501c19fde915049d99 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-INZI:
 
index 6703f4079c3ee07b83acbb12b5d1dd48f002f218..c2bae959bf5138a2e1a640771e357d894e5e5004 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-M420:
 
index 63bf1a2c911610237ddc8f39bf2e827e52553bd4..862e1f327150815dddf935b2c37b6d8706cab6b1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-meta-fmt-d4xx:
 
diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst b/Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
new file mode 100644 (file)
index 0000000..dc87100
--- /dev/null
@@ -0,0 +1,178 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _v4l2-meta-fmt-params:
+.. _v4l2-meta-fmt-stat-3a:
+
+******************************************************************
+V4L2_META_FMT_IPU3_PARAMS ('ip3p'), V4L2_META_FMT_IPU3_3A ('ip3s')
+******************************************************************
+
+.. c:type:: ipu3_uapi_stats_3a
+
+3A statistics
+=============
+
+For IPU3 ImgU, the 3A statistics accelerators collect different statistics over
+an input bayer frame. Those statistics, defined in data struct :c:type:`ipu3_uapi_stats_3a`,
+are obtained from "ipu3-imgu 3a stat" metadata capture video node, which are then
+passed to user space for statistics analysis using :c:type:`v4l2_meta_format` interface.
+
+The statistics collected are AWB (Auto-white balance) RGBS (Red, Green, Blue and
+Saturation measure) cells, AWB filter response, AF (Auto-focus) filter response,
+and AE (Auto-exposure) histogram.
+
+struct :c:type:`ipu3_uapi_4a_config` saves configurable parameters for all above.
+
+.. code-block:: c
+
+       struct ipu3_uapi_stats_3a {
+               struct ipu3_uapi_awb_raw_buffer awb_raw_buffer;
+               struct ipu3_uapi_ae_raw_buffer_aligned ae_raw_buffer[IPU3_UAPI_MAX_STRIPES];
+               struct ipu3_uapi_af_raw_buffer af_raw_buffer;
+               struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer;
+               struct ipu3_uapi_4a_config stats_4a_config;
+               __u32 ae_join_buffers;
+               __u8 padding[28];
+               struct ipu3_uapi_stats_3a_bubble_info_per_stripe stats_3a_bubble_per_stripe;
+               struct ipu3_uapi_ff_status stats_3a_status;
+       };
+
+.. c:type:: ipu3_uapi_params
+
+Pipeline parameters
+===================
+
+IPU3 pipeline has a number of image processing stages, each of which takes a
+set of parameters as input. The major stages of pipelines are shown here:
+
+Raw pixels -> Bayer Downscaling -> Optical Black Correction ->
+
+Linearization -> Lens Shading Correction -> White Balance / Exposure /
+
+Focus Apply -> Bayer Noise Reduction -> ANR -> Demosaicing -> Color
+
+Correction Matrix -> Gamma correction -> Color Space Conversion ->
+
+Chroma Down Scaling -> Chromatic Noise Reduction -> Total Color
+
+Correction -> XNR3 -> TNR -> DDR
+
+The table below presents a description of the above algorithms.
+
+======================== =======================================================
+Name                    Description
+======================== =======================================================
+Optical Black Correction Optical Black Correction block subtracts a pre-defined
+                        value from the respective pixel values to obtain better
+                        image quality.
+                        Defined in :c:type:`ipu3_uapi_obgrid_param`.
+Linearization           This algo block uses linearization parameters to
+                        address non-linearity sensor effects. The Lookup table
+                        table is defined in
+                        :c:type:`ipu3_uapi_isp_lin_vmem_params`.
+SHD                     Lens shading correction is used to correct spatial
+                        non-uniformity of the pixel response due to optical
+                        lens shading. This is done by applying a different gain
+                        for each pixel. The gain, black level etc are
+                        configured in :c:type:`ipu3_uapi_shd_config_static`.
+BNR                     Bayer noise reduction block removes image noise by
+                        applying a bilateral filter.
+                        See :c:type:`ipu3_uapi_bnr_static_config` for details.
+ANR                     Advanced Noise Reduction is a block based algorithm
+                        that performs noise reduction in the Bayer domain. The
+                        convolution matrix etc can be found in
+                        :c:type:`ipu3_uapi_anr_config`.
+Demosaicing             Demosaicing converts raw sensor data in Bayer format
+                        into RGB (Red, Green, Blue) presentation. Then add
+                        outputs of estimation of Y channel for following stream
+                        processing by Firmware. The struct is defined as
+                        :c:type:`ipu3_uapi_dm_config`. (TODO)
+Color Correction        Color Correction algo transforms sensor specific color
+                        space to the standard "sRGB" color space. This is done
+                        by applying 3x3 matrix defined in
+                        :c:type:`ipu3_uapi_ccm_mat_config`.
+Gamma correction        Gamma correction :c:type:`ipu3_uapi_gamma_config` is a
+                        basic non-linear tone mapping correction that is
+                        applied per pixel for each pixel component.
+CSC                     Color space conversion transforms each pixel from the
+                        RGB primary presentation to YUV (Y: brightness,
+                        UV: Luminance) presentation. This is done by applying
+                        a 3x3 matrix defined in
+                        :c:type:`ipu3_uapi_csc_mat_config`
+CDS                     Chroma down sampling
+                        After the CSC is performed, the Chroma Down Sampling
+                        is applied for a UV plane down sampling by a factor
+                        of 2 in each direction for YUV 4:2:0 using a 4x2
+                        configurable filter :c:type:`ipu3_uapi_cds_params`.
+CHNR                    Chroma noise reduction
+                        This block processes only the chrominance pixels and
+                        performs noise reduction by cleaning the high
+                        frequency noise.
+                        See struct :c:type:`ipu3_uapi_yuvp1_chnr_config`.
+TCC                     Total color correction as defined in struct
+                        :c:type:`ipu3_uapi_yuvp2_tcc_static_config`.
+XNR3                    eXtreme Noise Reduction V3 is the third revision of
+                        noise reduction algorithm used to improve image
+                        quality. This removes the low frequency noise in the
+                        captured image. Two related structs are  being defined,
+                        :c:type:`ipu3_uapi_isp_xnr3_params` for ISP data memory
+                        and :c:type:`ipu3_uapi_isp_xnr3_vmem_params` for vector
+                        memory.
+TNR                     Temporal Noise Reduction block compares successive
+                        frames in time to remove anomalies / noise in pixel
+                        values. :c:type:`ipu3_uapi_isp_tnr3_vmem_params` and
+                        :c:type:`ipu3_uapi_isp_tnr3_params` are defined for ISP
+                        vector and data memory respectively.
+======================== =======================================================
+
+A few stages of the pipeline will be executed by firmware running on the ISP
+processor, while many others will use a set of fixed hardware blocks also
+called accelerator cluster (ACC) to crunch pixel data and produce statistics.
+
+ACC parameters of individual algorithms, as defined by
+:c:type:`ipu3_uapi_acc_param`, can be chosen to be applied by the user
+space through struct :c:type:`ipu3_uapi_flags` embedded in
+:c:type:`ipu3_uapi_params` structure. For parameters that are configured as
+not enabled by the user space, the corresponding structs are ignored by the
+driver, in which case the existing configuration of the algorithm will be
+preserved.
+
+Both 3A statistics and pipeline parameters described here are closely tied to
+the underlying camera sub-system (CSS) APIs. They are usually consumed and
+produced by dedicated user space libraries that comprise the important tuning
+tools, thus freeing the developers from being bothered with the low level
+hardware and algorithm details.
+
+It should be noted that IPU3 DMA operations require the addresses of all data
+structures (that includes both input and output) to be aligned on 32 byte
+boundaries.
+
+The meta data :c:type:`ipu3_uapi_params` will be sent to "ipu3-imgu parameters"
+video node in ``V4L2_BUF_TYPE_META_CAPTURE`` format.
+
+.. code-block:: c
+
+       struct ipu3_uapi_params {
+               /* Flags which of the settings below are to be applied */
+               struct ipu3_uapi_flags use;
+
+               /* Accelerator cluster parameters */
+               struct ipu3_uapi_acc_param acc_param;
+
+               /* ISP vector address space parameters */
+               struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
+               struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
+               struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
+
+               /* ISP data memory (DMEM) parameters */
+               struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
+               struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
+
+               /* Optical black level compensation */
+               struct ipu3_uapi_obgrid_param obgrid_param;
+       };
+
+Intel IPU3 ImgU uAPI data types
+===============================
+
+.. kernel-doc:: drivers/staging/media/ipu3/include/intel-ipu3.h
index b5165dc090c2fb8917053d8bf07cc0555c722749..481e4e0e6e1d29dfb9ec93a8fe1d298875b9df91 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-meta-fmt-uvc:
 
index 67796594fd4842456adb28fe1e6665d7ff390067..f7a861696281833bea6e8fd43add53f35d3f2d1d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-meta-fmt-vsp1-hgo:
 
index fb9f79466319abfb9a64f519dd11fdcf08839d4c..2ebccdcca95d3b24bcb6cedb0bf89cbc04bfefbb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-meta-fmt-vsp1-hgt:
 
index 2776b41377d5d118f0c0c7096da1d0cdb86b8b78..b8c021b07fd2b2eb8a2d7d01abc3981e4734f93e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV12:
 .. _V4L2-PIX-FMT-NV21:
index c1a2779f604c474b83ca899dda7413ef3c2a96e3..9b2c5c21280a73cb692371e5ac81baa461909705 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV12M:
 .. _v4l2-pix-fmt-nv12mt-16x16:
index 172a3825604ecc09dccbd9bd519164926f3c3a9b..2092725de33cb57ed7b5f2b698afe622d128564a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV12MT:
 
index f0fdad3006cfcba5e29b627fb46860cead8ac6f7..5ec4b7fa8f04e4d39802a365c976357c0c08c74a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV16:
 .. _V4L2-PIX-FMT-NV61:
index c45f036763e7b3233d956c353a8567be9bca04aa..4a63bcf18b70c07a41f6dd62d0457f0d29119f2e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV16M:
 .. _v4l2-pix-fmt-nv61m:
index bda973e86227e78682d5f77a638eb87929fc742b..13fc6fe1a3d6b5a45c9550a2f74c634a3bb93e15 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-NV24:
 .. _V4L2-PIX-FMT-NV42:
index 8edf65c80660cf1139ad6abb0a25e4482d9a5bf6..38b1895a509f1221afc194257aa63f6f0181d4d9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _packed-hsv:
 
index 4938d9655a41fee032ec0e6fbf60d597335bbafb..6b3781c04dd5ac9c60f60e86cf2bec96154f444f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _packed-rgb:
 
index d7644b411cccaaee242271dd15e9f3faf968c505..f53e8f57a003e697542522af7de7cc45b0072acc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _packed-yuv:
 
index 0c399858bda2e58477a3a97b1100ada9205502d2..b2cd155e691bc85961bf3d08c11dbb83bd933c22 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _pixfmt-reserved:
 
index 1f9a7e3a07c9c18869b9eff41e3ddbb95ec93bf6..48ab800248352788b4950aaa923d57963414eca9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _pixfmt-rgb:
 
index 179894f6f8fb81dd321959cbf685241b39dc4cca..e7a89fe7e117dd1d84ef1e1ab69b40c0a19c54f5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-sdr-fmt-cs8:
 
index 5cf7d387447ceeccce6860d64ebf1d5ecd7d520a..d10d56f0e63adeca5415f2d4bc76bebdf6c80fef 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-SDR-FMT-CS14LE:
 
index fd915b7629b75b21b536730075e873548a3eb72a..f37df90f5a21f7507a0b14424c0af0480e341655 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-sdr-fmt-cu8:
 
index 8922f5b35457641c8d02f853f8afa1072e81bac9..237998fb5f9f55d5314590fe70cb299cca6e18c6 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-SDR-FMT-CU16LE:
 
index 2de1b1a0f51753873c5827572a27f184f47bb26c..df078dcfd18ddb44dd49ee3c2a2dfced66f7b11d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-SDR-FMT-PCU16BE:
 
index da8b26bf6b95563b2288d309ee1370d5a993d8ba..a1ea63db92303466e0cabc76e98403afb321d681 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-SDR-FMT-PCU18BE:
 
index 5499eed39477412e8531d567df5a033fbcae0545..11a05ea60e26f788855e676633faf46b6732bc1a 100644 (file)
@@ -1,4 +1,12 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
 .. _V4L2-SDR-FMT-PCU20BE:
 
 ******************************
index 5e383382802f421ac9b2318d196e7ab340bb0118..3c2c9f75fc5e6ef432f6d582d17b4fc2bebd7d7f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-SDR-FMT-RU12LE:
 
index 99cde5077519a47250e140c4ab68deaa42921883..75279f0fdad86967fcc885acafb9dd9b9c027b96 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-pix-fmt-ipu3-sbggr10:
 .. _v4l2-pix-fmt-ipu3-sgbrg10:
index af2538ce34e509ef5722309d26dd6b4ff1fda093..cab7fbb1f2fef5833b057353299b42cbd37e62a9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB10:
 .. _v4l2-pix-fmt-sbggr10:
index c44e093514deda4cdfc7af8dbecdd6e6081e5243..5bb58764b53264a101239a2f3ddcb4a509b4aa97 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SBGGR10ALAW8:
 .. _v4l2-pix-fmt-sgbrg10alaw8:
index 5e041d02eff07236167175f6b5396d2554bf2e15..cbc9c0a52ab41911ae1fd7bdd6f01beb7a9cfc9e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SBGGR10DPCM8:
 .. _v4l2-pix-fmt-sgbrg10dpcm8:
index d9e07a4b8b314b016243c86b2a96bbbf98ed6a86..cdb70ac2612668f460326412bfcfb27a052eb416 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB10P:
 .. _v4l2-pix-fmt-sbggr10p:
index 15041e568a0a5a0590158d234442f742fddc1054..6fb6a937e6adbeed0351eb4b96653080b36a022d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB12:
 .. _v4l2-pix-fmt-sbggr12:
index 59918a7913fe5d613cd0bfb579f729512af57564..01413be12916017c2acf86e6ecaa590b8a7edab4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB12P:
 .. _v4l2-pix-fmt-sbggr12p:
index 88d20c0e42826280b06ec399166e422db7afe7c7..b583531c2853177c845663962b563451045e8c07 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB14P:
 .. _v4l2-pix-fmt-sbggr14p:
index d407b2b2050ff9b94b77978f7a4d97bdfefa7530..36527c49eaf708d3963862339895b62bc7606ff3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB16:
 .. _v4l2-pix-fmt-sbggr16:
index 5ac25a634d300d093a049c9a70225d0452586ea2..f5233c1e2314d831dd39a7a478813fbdcbc8f7d5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-SRGGB8:
 .. _v4l2-pix-fmt-sbggr8:
index 07834cd1249e3b374c594ecf927df68f177d3474..b7d3d6ccebc51ee06facdb7254aed018adffaec0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-TCH-FMT-DELTA-TD08:
 
index 29ebcf40a989b46277e3f25b4cb6f62dd1d87a9d..4031b175257c2220c2477d8bff31322da87ab5d3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-TCH-FMT-DELTA-TD16:
 
index e7fb7ddd191bf1ac2bf01c2ab9e7629cc397b1d8..2d447475aaa73fd1a26214fe28550510183c10c0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-TCH-FMT-TU08:
 
index 1588fcc3f1e77f3392ff3abbc92d1c1bff8faa03..8278543be99aeb78ce3940475cc5869e4d80e758 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-TCH-FMT-TU16:
 
index c449231b51bb8e75cbf8fea941732387cde85216..6008c898305daa5b0567b724ad21f6c47d9223b0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-UV8:
 
index ecdc2d94c209cb5325d980a696ae3ab6ea0131c8..72da2639d37e24b80bdad79eb29b92dc81c2e599 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-UYVY:
 
index ef52f637d8e9c86268bd0677ee110d31118d3d28..7f82dad9013a548f45ab7b0f2c738774e8124d3d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ******************************
 Multi-planar format structures
index 826f2305da01ef93d322c25327af7da135c75cb6..71eebfc6d8534b52d68c9442fd7f81025dbcb02c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ******************************
 Single-planar format structure
index 670c339c1714dac5adecbeabd3f6cbe71edd1906..39b99707cd99656369c69f099952bc93c487e0c1 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-VYUY:
 
index 89e22899cd817ba590e1fbcc4e3ca808ac9fb5a6..63277686764a10b60c9bd79c007107f71bf1a291 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y10:
 
index 9feddf3ae07bfd9c30a22f5ef2d4fa0cc487d796..49c4dd4324130e20d6b13418f5917dfc79735a3d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y10BPACK:
 
index 13b571306915855cefd570d23ec44420135c74ad..7893642faee300b19bf22e231948be87b608c07a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y10P:
 
index 0f230713290ba5dcf0a8ea7c4890633fe2aceb7c..33a943b4996a9d63bed257a674dfc8ccd8b5a71c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y12:
 
index bb39a246356488ddddfb5dc1ed89637602529e2d..1d4a14e1ec6e09e199d07322db257afa04810e8d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y12I:
 
index 54ce35ef84b7de150a338dd1b06daadd577b0730..1e72bfe2d557d862a25ba6c78a95f6e47a620c13 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y16-BE:
 
index bcbd52de3aca3b4c5ac5e8f9fcc7353e7dab5e4b..f77d900db13121a6f09e24d97c777b12827714f3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y16:
 
index e1fe548807a4ddb6aeed7285536a9063c18bb2b1..829c68afd8d7a51095e504f616bfd05e319e422b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y41P:
 
index fd8ed23dd342eb86bcaf188687a515a6f565824d..2c88ed90522dd28d5ea3bbaa2a5ab8179419afb9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Y8I:
 
index b51a0d1c6108940ff0b8221bf760f98575c07855..ebb72a5c7ceb85586a1c07d8bd9c74a1488a9993 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YVU410:
 .. _v4l2-pix-fmt-yuv410:
index 2582341972db5fc2f0a50d33f9b6e3de2029bc8d..83ddaa3f8dfbd5a9601e15fdff3ab2a2efc2f460 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUV411P:
 
index a9b85c4b1dbc721e55db275ecaffbeb7716df56c..f4f6f792a23ed65c951d587c9415934856941767 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YVU420:
 .. _V4L2-PIX-FMT-YUV420:
index 32c68c33f2b17f20dce14aefb429a1bf326e855f..c29b30c6445a984df6772505af63d5c07de7fef7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUV420M:
 .. _v4l2-pix-fmt-yvu420m:
index 9e7028c4967c8edb662136ca714bc4d908d1866b..737fd94a9ae9dea55496162303e013d8496f99ba 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUV422M:
 .. _v4l2-pix-fmt-yvu422m:
index a96f836c7fa5228d9357487c8669a8be35cb9c83..7cebb6ebb621a9c97b5494c623c28be5669adf5e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUV422P:
 
index 8605bfaee1120768f0bc472ea522af1ace322250..8f14ca37881639a89307c150fdd5c070759d47e9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUV444M:
 .. _v4l2-pix-fmt-yvu444m:
index 53e876d053fb2af50a529f6c39d627385d3ddf12..d86d7f086c418fc9ecf37a845154be1e31a20c17 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YUYV:
 
index b9c31746e5652bb842890fdc030eeef622c50ce3..656a830fed02b9fec96cc17774d6e8f8bb4991bb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-YVYU:
 
index eb713a9bccaed19c1c1f3fec527065f93ffdaf51..eccf235bf02d1a8c67b9d1bb90bcc2c08d9d2e45 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _V4L2-PIX-FMT-Z16:
 
index 2aa449e2da67246175f9c83b6a5df4d104cbd9e6..29be001796dbc0689e4523d9955567c88512e49f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _pixfmt:
 
index 4e059fb44153a4598d447242f9043a1020145092..a422dc9d592c9c05fc270ed4ae0c283e323eacdb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _planar-apis:
 
index c19cce7a816fb7c9bc48b897193c6e4429f7ee4d..8d01ef52f7803221c0a18b73e96fb8da08c6786f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _querycap:
 
index 91596c0cc2f3c8e396c78eb7f1e77f94abbe4ed5..6e498fcf32c46d1afcc67f6f955a5220f9d562cf 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _rw:
 
index 2037f5bad727f969e89bbaddcbd1d8a84e62b3de..f452f5574ebb3281fe6268704266b41ab94d093d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _sdr-formats:
 
index 0a4ddc2d71dbc056a46b68f4ac37b9b7d0aef573..6e0c98c37067ced3eaf24640d71440a4adc222dd 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 *************
 Configuration
index 67e0e9aed9e82f8ba346158370027a1d66e08fe2..bb288b06cc175ec6ac064d0b0de661a36a587ed8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ********
 Examples
index 09ca93f91bf76864ff2c0a138f2ac5368feac000..0faed02d0226a29c1f31c691339d2cee04b3c02a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 ************
 Introduction
index bf7e76dfbdf96069768f4e857e59f344f057937d..83d633bcbd6f3c1b8db4b588818b29c354be4fda 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 *****************
 Selection targets
index e7455fb1e572f0953fad18af8ac9331f088c50ca..79b3abca341ad825b8fe579b1b8a593d30321cf8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _selection-vs-crop:
 
index 390233f704a3819f93fd3b2f25a5759e13103e17..5386004e87cf46303eb451f37d0bff8d583207e9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _selection-api:
 
index 911062bd28446efeb6f4dbc9a6e818fafd9c4ed0..59d2bec9b27809de21e14d3be13b5d4f08973018 100644 (file)
@@ -1,4 +1,31 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    This file is dual-licensed: you can use it either under the terms
+    of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this
+    dual licensing only applies to this file, and not this project as a
+    whole.
+
+    a) This file is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License as
+       published by the Free Software Foundation version 2 of
+       the License.
+
+       This file 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.
+
+    Or, alternatively,
+
+    b) Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation License,
+       Version 1.1 or any later version published by the Free Software
+       Foundation, with no Invariant Sections, no Front-Cover Texts
+       and no Back-Cover Texts. A copy of the license is included at
+       Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg enable-background="new" version="1" viewBox="0 0 4226.3 1686.8" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
   <pattern id="ig" xlink:href="#ka" patternTransform="matrix(5.4432 0 0 10.1 1722.4 161.06)"/>
index 69dbce4e6e47444e1c1b4042581f856198d4da1c..28b32db280f22350ec86b823d0baaebb21ab0287 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-selections-common:
 
index 75a14895aed752d75e5202c6f9881f7bc77d0a21..bf8959b729882480e77c9ecd9cd7f49e03ac00c5 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _standard:
 
index f9b93c53f75c0723aef9d63dc069aa0c63f9211c..425bd0ff14777a85112eed9bc60974325281aea8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _streaming-par:
 
index 8e73fcfc690004d8c65c4c7aa9941781ab3655ff..ff4b2a972fd2ea6c1b5fca88c6ec6e72fe298b6d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-mbus-format:
 
index ee1df49f83e8078c6ce4eced10d910be86db3bec..59321e09929d76ea60beaacdc21d0aedd18cb28f 100644 (file)
@@ -1,4 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index c10d222b9ea963a82ed7451e3575b1a59e4af4f3..e739c54fbbfb29282502ab26267f5bfdbf9880bf 100644 (file)
@@ -1,4 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index 3cb68bf9fc047fb12ba331615bc62043336270c0..401d1456958c5a81c72f0548165d2fc38a4f452a 100644 (file)
@@ -1,4 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
+
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
index dbaabf33a5b891ec11c56d3a4502a7f73118727c..429c1010149d71bac4ea96510d9c3cedee71241d 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _tch-formats:
 
index ad117b068831c224f0fbaa0f6569d978f18fd8a2..601dc535199c75971724c89fd833441d15b5565f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _tuner:
 
@@ -31,7 +38,7 @@ current video or radio input is queried.
 .. note::
 
    :ref:`VIDIOC_S_TUNER <VIDIOC_G_TUNER>` does not switch the
-   current tuner, when there is more than one at all. The tuner is solely
+   current tuner, when there is more than one. The tuner is solely
    determined by the current video input. Drivers must support both ioctls
    and set the ``V4L2_CAP_TUNER`` flag in the struct :c:type:`v4l2_capability`
    returned by the :ref:`VIDIOC_QUERYCAP` ioctl when the
@@ -41,7 +48,7 @@ current video or radio input is queried.
 Modulators
 ==========
 
-Video output devices can have one or more modulators, uh, modulating a
+Video output devices can have one or more modulators, that modulate a
 video signal for radiation or connection to the antenna input of a TV
 set or video recorder. Each modulator is associated with one or more
 video outputs, depending on the number of RF connectors on the
index 3e0413b83a3383cbc11cdca56c1e3a26aebf578c..ca0ef21d77fee648cee9d05076ef85d6c96b809a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _user-func:
 
index dc2893a60d650df6473a8e84a28be180d75efd17..b19da8655452b8aa5fce88f9ce4953b55bfafbc2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _userp:
 
@@ -62,9 +69,9 @@ memory pages at any time between the completion of the DMA and this
 ioctl. The memory is also unlocked when
 :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` is called,
 :ref:`VIDIOC_REQBUFS`, or when the device is closed.
-Applications must take care not to free buffers without dequeuing. For
-once, the buffers remain locked until further, wasting physical memory.
-Second the driver will not be notified when the memory is returned to
+Applications must take care not to free buffers without dequeuing.
+Firstly, the buffers remain locked for longer, wasting physical memory.
+Secondly the driver will not be notified when the memory is returned to
 the application's free list and subsequently reused for other purposes,
 possibly completing the requested DMA and overwriting valuable data.
 
@@ -90,7 +97,7 @@ To start and stop capturing or output applications call the
 
 .. note::
 
-   ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` removes all buffers from
+   :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` removes all buffers from
    both queues and unlocks all buffers as a side effect. Since there is no
    notion of doing anything "now" on a multitasking system, if an
    application needs to synchronize with another event it should examine
index 1f9a03851d0ff007f81b434265d09aee7c12a893..cc8f2a2b7cbaa942c4948a4ec1e78703713f3a7f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-selection-flags:
 
index 87433ec76c6bfa1cbb1b333d7ebc8b0aad42d480..f74f239b0510d4da9e147e6809e217c28892f6cf 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2-selection-targets:
 
@@ -42,12 +49,7 @@ of the two interfaces they are used.
     * - ``V4L2_SEL_TGT_NATIVE_SIZE``
       - 0x0003
       - The native size of the device, e.g. a sensor's pixel array.
-       ``left`` and ``top`` fields are zero for this target. Setting the
-       native size will generally only make sense for memory to memory
-       devices where the software can create a canvas of a given size in
-       which for example a video frame can be composed. In that case
-       V4L2_SEL_TGT_NATIVE_SIZE can be used to configure the size of
-       that canvas.
+       ``left`` and ``top`` fields are zero for this target.
       - Yes
       - Yes
     * - ``V4L2_SEL_TGT_COMPOSE``
index b89e5621ae69c46a8fc872cbaf3d3fe548b1f2ee..004ec00db6bdc71b94770f999b8543a9c26a32f4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. include:: <isonum.txt>
 .. _v4l2spec:
index c240f0513bee1e6e978ec9ddee712145a115da27..2a0cfd4429c180dc6e87edcadd926bcbf7a3deaf 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _v4l2grab-example:
 
index f0d0ab6abd413642cc108830d57326cfaa4f8bb4..e76c5fb7bd19a028b8744009541655f79c5d437b 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 file: media/v4l/v4l2grab.c
 ==========================
index 643aec8d0ba2cd093ebe54d59b45fcefc969fac2..6cd5def22b1fb74bb25e61562119859bac6ad4e5 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
         sodipodi:role="line"
         y="-3648.6809"
         x="3528.1047 3569.0876 3610.0703 3651.0532 3671.5447 3692.0361 3708.3999 3749.3826 3765.7463">2nd field</tspan></text>
-</g></svg>
\ No newline at end of file
+</g></svg>
index 9b18243c0a066e931e5cd856a196aff406eb83c6..7aaae5ec487828888b1e3bcc9dc5b4ea90c96cdb 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
         y="-5054.106"
         sodipodi:role="line"
         id="tspan4129">24</tspan></text>
-</g></svg>
\ No newline at end of file
+</g></svg>
index e17ff8314e7b12ce4c0cf136767384f38a7c3fb6..f8e979ada7e3303042098f85e1a08c36bdda33ea 100644 (file)
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!--
+    Permission is granted to copy, distribute and/or modify this
+    document under the terms of the GNU Free Documentation License,
+    Version 1.1 or any later version published by the Free Software
+    Foundation, with no Invariant Sections, no Front-Cover Texts
+    and no Back-Cover Texts. A copy of the license is included at
+    Documentation/media/uapi/fdl-appendix.rst.
 
+    TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+-->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
         sodipodi:role="line"
         y="-395.66284"
         x="438.29504 457.96585 469.55164 474.17761 479.97049 491.55627 497.34915 508.93494 520.52069 530.93958 542.52533">White Level</tspan></text>
-</g></svg>
\ No newline at end of file
+</g></svg>
index d2bc06b064ad88400bfcd1eb59c97601d1e08298..69603b5efbb5f557c1faa4c02c4025e3116c3ff2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _video:
 
@@ -7,7 +14,7 @@ Video Inputs and Outputs
 ************************
 
 Video inputs and outputs are physical connectors of a device. These can
-be for example RF connectors (antenna/cable), CVBS a.k.a. Composite
+be for example: RF connectors (antenna/cable), CVBS a.k.a. Composite
 Video, S-Video and RGB connectors. Camera sensors are also considered to
 be a video input. Video and VBI capture devices have inputs. Video and
 VBI output devices have outputs, at least one each. Radio devices have
@@ -19,7 +26,7 @@ outputs applications can enumerate them with the
 :ref:`VIDIOC_ENUMOUTPUT` ioctl, respectively. The
 struct :c:type:`v4l2_input` returned by the
 :ref:`VIDIOC_ENUMINPUT` ioctl also contains signal
-:status information applicable when the current video input is queried.
+status information applicable when the current video input is queried.
 
 The :ref:`VIDIOC_G_INPUT <VIDIOC_G_INPUT>` and
 :ref:`VIDIOC_G_OUTPUT <VIDIOC_G_OUTPUT>` ioctls return the index of
index b9ee4672d639ec30ad8d78986688d7d567095504..fa3d3398930a17622f32762e33debb0597b7ae02 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _videodev:
 
index eadf6f757fbfecb1ffa7b7e5b21bb0ddcdaafe55..bd08e4f77ae422d30afd75f217417b53d1c6b998 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_CREATE_BUFS:
 
index 0a7b8287fd3885b429932d465714d47e88f96a87..019d3d3a0e0d5b8d0dd95b5fa76f3efaf8fa4c4e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_CROPCAP:
 
index 7709852282c258a8bff350f786c4c91efed0fa36..a1cf20181cf1ede899b1ea975aaf8799c9620fc7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_DBG_G_CHIP_INFO:
 
index f4e8dd5f7889e2dd6c9f3128afa4e34a98d22c77..29e1d4fc4f522a7ccefba8cd78d3cccf3b6e81e7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_DBG_G_REGISTER:
 
index 85c916b0ce076ba18ef756c9de6f5fbb9fc735e7..ccf83b05afa736718797c5289e6c4a187ddebc57 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_DECODER_CMD:
 
index 04416b6943c0bd53ab9f4d72b65e9f4c751032bc..dea9c0cc00ab92344bfe66909c2b308af9b5ac95 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_DQEVENT:
 
index 63ead6b7a11503422a4f475988861df4aa7c29cd..e62d45d37072cf9ed3d92e32ca267025e1edcddc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_DV_TIMINGS_CAP:
 
index 5ae8c933b1b9c7bc4151eb93744db06f2136d201..c313ca8b8cb553dcb9cef1fc4e396f27afc954de 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENCODER_CMD:
 
index 63dca65f49e4db1126089cac9b279a51fb298189..0b286e19b46bcc6e5ed8e7af0f44709abcdfcccf 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUM_DV_TIMINGS:
 
index 019c513df217a27e81628879c30651df5cf9ec25..822d6730e7d2c99e4ef9316a71d3bb22c1e5bad0 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUM_FMT:
 
@@ -64,8 +71,12 @@ one until ``EINVAL`` is returned.
        are valid here: ``V4L2_BUF_TYPE_VIDEO_CAPTURE``,
        ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``,
        ``V4L2_BUF_TYPE_VIDEO_OUTPUT``,
-       ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE`` and
-       ``V4L2_BUF_TYPE_VIDEO_OVERLAY``. See :c:type:`v4l2_buf_type`.
+       ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``,
+       ``V4L2_BUF_TYPE_VIDEO_OVERLAY``,
+       ``V4L2_BUF_TYPE_SDR_CAPTURE``,
+       ``V4L2_BUF_TYPE_SDR_OUTPUT`` and
+       ``V4L2_BUF_TYPE_META_CAPTURE``.
+       See :c:type:`v4l2_buf_type`.
     * - __u32
       - ``flags``
       - See :ref:`fmtdesc-flags`
index fea7dc3c879d046a7692533dfd92c1e2b1da7b12..2c69f26b165ddf3784e04396af5968aacb8ef560 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUM_FRAMEINTERVALS:
 
index 6de117f163e00d2e53f227041a10214b91d09e9d..cf31f548826fa89fa3d8688c10f6c660f57d5f15 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUM_FRAMESIZES:
 
index 195cf45f3c3217292ee7e60c59ba04409852cee0..0e97c09afe0e8ed7932a517a4855d8c416576c65 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUM_FREQ_BANDS:
 
index 8e5193e8696f0966dfb6b64a4304b605c7ab5e9b..ee0c336c8721c343903a9e52ea5a17e9654d8328 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUMAUDIO:
 
index 6d2b4f6e78b0e6989177fb2544767a8ca14d2de4..3a8882214d62d64968ae05f0c4e7e80ed9b0b932 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUMAUDOUT:
 
index 0350069a56c551e0920a9f80e0107f12f508cc24..a0e4c4413121df125202de1ae0c8a70a5b18fdfb 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUMINPUT:
 
index 697dcd186ae30406d992a870bda4bc46aec730f1..0fea81f60541ab01d593c834e0bfbaadf54c6eef 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUMOUTPUT:
 
index 2644a62acd4b682250037c5f48250cdb0728db2a..1603b1b3b6e832f889a58dad2e94165d60cab0ad 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_ENUMSTD:
 
index 226e83eb28a9c56c25cd5513bac508d592332c60..4bd8cd79754c3cf11fde0671dc948bd5a8c4ca98 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_EXPBUF:
 
index 290851f993863e398ffa1f05c377650135f2b7a9..7af4fe478ba42277dee7c4b27a1b6a1a1471be44 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_AUDIO:
 
index 1c98af33ee70682e992ebb92f4865318c4500baa..c6ea0396a96a611247730c5faab019a6e6d10926 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_AUDOUT:
 
index b95ba6743cbd7297f0a6609ba0c2186f9fbadb3a..1eff59dc5f358d86f1c360c4ad5803a005588d46 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_CROP:
 
index 299b9aabbac235c805e0db90c4a2bad74293feff..8493b52adbb2df5f5d73a09d65fc1b75c2126793 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_CTRL:
 
index 35cba2c8d4595d4431add09979c86203d1f65878..5712bd48e6870301c164ae56934a858c2dd64e62 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_DV_TIMINGS:
 
index acab90f06e5a0f691e0529e061e2ae244ac46f88..e55b349a0c7ee4a1519ba01794497a7561e80364 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_EDID:
 
index 9dfe64fc21a42e64197d794420961ebdf4a2a86b..e285a1f14cdf105290d9ced3c9a6a0e97828dd35 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_ENC_INDEX:
 
index d9930fe776cf811143553ed84aa5cfad1b36b27c..13dc1a98624957615c68441694cfeeda427b84e2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_EXT_CTRLS:
 
index fc73bf0f60528405b245529d28659773f0c515c2..7b61796278035f147c5965831b1cd3b42100ce8c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_FBUF:
 
index 9ea494a8facab2cca0b51745cda1af6f0f53fd4c..e35a9caff65280e9b8b490b4a65ed87c4ec68b21 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_FMT:
 
index c1cccb1446600f6c9390f8bc62632d5fae7a5322..cc30bae3dd6e2256aaadb9f95319ce51cbd2b567 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_FREQUENCY:
 
index 1dcef44eef02bcd4568ee0a79acb5c338cbcffc4..76b7d487466e2492a7dd88b12f43c875f53b35e4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_INPUT:
 
index a1773ea9543e71f9663a2ad67de95be82575e4fd..5480277ab3273d5dbe9d8eafec360b54994581e3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_JPEGCOMP:
 
index a47b6a15cfbe8ef8a14b2ee6b80d97c744954fb9..2c33a8bdcc471c29a8d6112159028b03ef88b128 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_MODULATOR:
 
index 3e0093f668343d657ca1feb947d9dbea943f64f2..69542d78977bbb5c62ec55497b598bd4085d5707 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_OUTPUT:
 
index e831fa5512f035e1c09fc88e2595aeef72372bb8..0d2593176c90ec4b6e65199a3a8f662c03ac5bfd 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_PARM:
 
@@ -42,6 +49,9 @@ side. This is especially useful when using the :ref:`read() <func-read>` or
 :ref:`write() <func-write>`, which are not augmented by timestamps or sequence
 counters, and to avoid unnecessary data copying.
 
+Changing the frame interval shall never change the format. Changing the
+format, on the other hand, may change the frame interval.
+
 Further these ioctls can be used to determine the number of buffers used
 internally by a driver in read/write mode. For implications see the
 section discussing the :ref:`read() <func-read>` function.
index c28996b4a45c04cff1348ef96f4cd980f2b26385..244b4dbe9df32a511e401c0ea7d395384fdf6f26 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_PRIORITY:
 
index f1d9df029e0d43028c6a40628b9e4408243f6575..7d8ef7ac8e2743a1aa9ca2fbc66f1fea9725bd2c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_SELECTION:
 
index a9633cae76c5df96d220fdf943ecdb87d461c141..388b826d44b32ad0b3b41c1ee977cdb101098e6a 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_SLICED_VBI_CAP:
 
index 8d94f0404df270db3cf26f5ce5db538d3558d195..e633e42e391042f6d7f7ec2731f55490d14f6bb7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_STD:
 
index acdd15901a51d44e21cd32247b3121148042b4a1..82d23b8bd1957f1cd0fb5545d20fb57a5ec41dd2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_G_TUNER:
 
index bbeb7b5f516b1b056cc96716985bb8d3c6c8182a..16bb5509ad667f6adeb47033769f64f1765e85d7 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_LOG_STATUS:
 
index 1383e3db25fcee4c3ef8ffe933ffd3c1668790b6..fc5a86e8c1f2108ebacbb48d7f9fb3cc86de03c3 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_OVERLAY:
 
index 49f9f4c181de75e76e300ed3c847bae7e8069643..60986710967b136c1e1b206fcf2a5d3ddb8bd537 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_PREPARE_BUF:
 
index 753b3b5946b1a88bf403ba5211e7ae1c9ff9c6a6..3259168a735853897d5c4f187663683a0c59a41e 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QBUF:
 
index 6c82eafd28bbc23fed02fb606cd6d3084d5cae23..e9b055395382151472b6c094a26e6badc0854138 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QUERY_DV_TIMINGS:
 
index dd54747fabc9ad7ac1b0805d7eed0745806b05d2..7da60b24e8b67e4b614137fa6fb9a462faa2fbe4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QUERYBUF:
 
index 66fb1b3d6e6efe52b07402855bacab3ff9299fb5..5f9930195d624c73862c428ed69d6d74ea5d8e69 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QUERYCAP:
 
@@ -251,6 +258,9 @@ specification the ioctl returns an ``EINVAL`` error code.
     * - ``V4L2_CAP_STREAMING``
       - 0x04000000
       - The device supports the :ref:`streaming <mmap>` I/O method.
+    * - ``V4L2_CAP_META_OUTPUT``
+      - 0x08000000
+      - The device supports the :ref:`metadata` output interface.
     * - ``V4L2_CAP_TOUCH``
       - 0x10000000
       - This is a touch device.
index 258f5813f281c89f43211501aeb9acdd478f17b4..f824162d0ea99714756b7d068d712c624747ddd2 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QUERYCTRL:
 
index a8385cc7481869dd4471a060a142a3f8e6f9a83b..d8cf28274cfc836cc59b387ba403f19bd5e25cb8 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_QUERYSTD:
 
index d4bbbb0c60e80c94cadf94d928c60a0dcfec7adc..d7faef10e39ba9c770f353042f1676c4b3972420 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_REQBUFS:
 
@@ -59,9 +66,14 @@ When the I/O method is not supported the ioctl returns an ``EINVAL`` error
 code.
 
 Applications can call :ref:`VIDIOC_REQBUFS` again to change the number of
-buffers, however this cannot succeed when any buffers are still mapped.
-A ``count`` value of zero frees all buffers, after aborting or finishing
-any DMA in progress, an implicit
+buffers. Note that if any buffers are still mapped or exported via DMABUF,
+then :ref:`VIDIOC_REQBUFS` can only succeed if the
+``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` capability is set. Otherwise
+:ref:`VIDIOC_REQBUFS` will return the ``EBUSY`` error code.
+If ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` is set, then these buffers are
+orphaned and will be freed when they are unmapped or when the exported DMABUF
+fds are closed. A ``count`` value of zero frees or orphans all buffers, after
+aborting or finishing any DMA in progress, an implicit
 :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`.
 
 
@@ -112,6 +124,7 @@ any DMA in progress, an implicit
 .. _V4L2-BUF-CAP-SUPPORTS-USERPTR:
 .. _V4L2-BUF-CAP-SUPPORTS-DMABUF:
 .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
+.. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS:
 
 .. cssclass:: longtable
 
@@ -132,6 +145,11 @@ any DMA in progress, an implicit
     * - ``V4L2_BUF_CAP_SUPPORTS_REQUESTS``
       - 0x00000008
       - This buffer type supports :ref:`requests <media-request-api>`.
+    * - ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS``
+      - 0x00000010
+      - The kernel allows calling :ref:`VIDIOC_REQBUFS` while buffers are still
+        mapped or exported via DMABUF. These orphaned buffers will be freed
+        when they are unmapped or when the exported DMABUF fds are closed.
 
 Return Value
 ============
index b318cb8e1df3a07fc392c1599f8010546b6d8541..4daec97651f25ca4ec5160b501f5c634697868d4 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_S_HW_FREQ_SEEK:
 
index e851a6961b78e197ff7f1c7953aa168d314d4e97..2b5528ec9f8904e2e6f868baff1652098e70930c 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_STREAMON:
 
index 1bfe3865dcc241fd05b42ea61dd295548b1c3e75..6b4bf9ef56065e7fd117117c386491a6411a1634 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL:
 
index 33fdc3ac9316473d9187a677dfae4b9eb596d829..253b128b194e0a0c2114b1f0ac5db6ae089f64ba 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_ENUM_FRAME_SIZE:
 
index 4e4291798e4be1d8d08c57fc99f94650c22ab373..fefe4d7349ee277b30bccf7d5d7f9b8c09987027 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_ENUM_MBUS_CODE:
 
index 69b2ae8e7c150c487d2ecb55e99907df2eaf3dd6..632ee053accc48e962b18c7d79533a634474aaec 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_G_CROP:
 
index 81c5d331af9a71be93c136f72d443f7f0e5e0d9a..472577bd17454ca013996f851c594fa2c00c0f33 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_G_FMT:
 
index 5af0a7179941668bb1fd9955f10330c75ee1443c..4b1b4bc78bfea7ebb31a9a3db61f09719cc9255f 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_G_FRAME_INTERVAL:
 
@@ -63,6 +70,9 @@ doesn't match the device capabilities. They must instead modify the
 interval to match what the hardware can provide. The modified interval
 should be as close as possible to the original request.
 
+Changing the frame interval shall never change the format. Changing the
+format, on the other hand, may change the frame interval.
+
 Sub-devices that support the frame interval ioctls should implement them
 on a single pad only. Their behaviour when supported on multiple pads of
 the same sub-device is not defined.
index b1d3dbbef42a89d07d69ac6f1a3564d76b0b5e75..fc73d27e6d74709b26b2cfc18f1a927ae2ae17dc 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBDEV_G_SELECTION:
 
index b521efa53ceb8aeddabe49193b85507c75e91241..a2d3454555ba3d20b2955d855c60492ea937a087 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _VIDIOC_SUBSCRIBE_EVENT:
 .. _VIDIOC_UNSUBSCRIBE_EVENT:
index 9ab0592d08dac86a08a9ebdde6a33cb0cfa5bc73..867470e5f9e1242a335a586422f102f8288fe4f9 100644 (file)
@@ -1,4 +1,11 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
 
 .. _yuv-formats:
 
index bb87b7b36a838ba02d5486300197452515603c47..aaaadc934e7a935648f6a8fe2db9e61731d417e1 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 AU0828 cards list
 =================
 
index 8da27b924e016c21d91d9cd118027f72729a6543..f5806856b5a197183d7beb8f4aa724c8d9970b1e 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 BTTV cards list
 ===============
 
index 5f35e2fb5afa1cf6abc726cb7997e203e54a837f..d72a0f8fd267efd427f71cab0634dceec4aa8965 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The bttv driver
 ===============
 
index 94f0f58ebe3743f27c7c9861a316347a7f708208..ff7fbce1342a86bce49addb77a5bd98eef7b8374 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The cafe_ccic driver
 ====================
 
index 8a0728d206848263b025d3e68ec6a46d6013e9fd..14249f47fbc24570fb75f593cb40c7544e96e06b 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Cards List
 ==========
 
index b5125016cfcbc0d604727308b0e79988d40a2679..a86baa1c83f1bd89adfc5db2807e794dc60b5239 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The cpia2 driver
 ================
 
index afa03f65b01cbe98397d85d1d073d717f216087e..16895a734baecf8d89724cb354c2eec5b1348ee2 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The cx18 driver
 ===============
 
index e06d07ebdecd29bccb73feb679c806e58433853b..8ca37deb56b68de280cf46ce2f7b8063916f9239 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The cx2341x driver
 ==================
 
index 8c24df8e0423fcfb7329dbf4b6406e32aa453c4b..ddff8da98eebcb7beb26962d294a7255671cd352 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 cx23885 cards list
 ==================
 
index 21648b8c2e8341abc6bf711a746b1e750e3f8d6f..56ee0802810674ff463a11d108df7d08f041025b 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 CX88 cards list
 ===============
 
index d8f3a014726a9785a42401fde1457d73647c3f7a..698c73ea2e36bec7af0fc5e17d8c948d8a1f25d7 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The cx88 driver
 ===============
 
index b545fe00191992694e33cc0acbab2673b100f1f2..0fde433e5c71f4ddfe35076c4de4792f57057508 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The VPBE V4L2 driver design
 ===========================
 
index dfe882ca945f71c7e74a32ed67b9c84c195fb948..2956cbdc28e06f6971b2e4d0c2955cae19b7c077 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 EM28xx cards list
 =================
 
@@ -233,7 +235,7 @@ EM28xx cards list
      - em2882
      - eb1a:e323
    * - 55
-     - Terratec Cinnergy Hybrid T USB XS (em2882)
+     - Terratec Cinergy Hybrid T USB XS (em2882)
      - em2882
      - 0ccd:005e, 0ccd:0042
    * - 56
index 3adc19bcf03948ab28c389618d4d6cd9a91d2046..74585ba48b7f4a2af56e3555fec52c4d289dabb6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 The Samsung S5P/EXYNOS4 FIMC driver
index 9c82106e8a26be7fae8c20b43d1b0451afc8dde3..d3482c40da621a7fe370f809e8a07d92721a1ad6 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Guidelines for Video4Linux pixel format 4CCs
 ============================================
 
index e18d87e80d780efd121fc038a0930b12cdb1c30f..adda933616f108d41454e5328642c3cbdc43af28 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The gspca cards list
 ====================
 
index 65d3d15eb1593403295d6bd0ae2c5ccba1377e23..6922dde4a82bf202a3028d6cd5ec134f2f67ec0b 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 i.MX Video Capture Driver
 =========================
 
index 679238e786a77b8bd1b310b1795804aabfffdf3d..f28570ec9e42763875eb39aa0d89542d00e24909 100644 (file)
@@ -1,4 +1,4 @@
-.. -*- coding: utf-8; mode: rst -*-
+.. SPDX-License-Identifier: GPL-2.0
 
 .. include:: <isonum.txt>
 
@@ -44,6 +44,7 @@ For more details see the file COPYING in the source distribution of Linux.
        davinci-vpbe
        fimc
        imx
+       ipu3
        ivtv
        max2175
        meye
diff --git a/Documentation/media/v4l-drivers/ipu3.rst b/Documentation/media/v4l-drivers/ipu3.rst
new file mode 100644 (file)
index 0000000..f89b51d
--- /dev/null
@@ -0,0 +1,369 @@
+.. include:: <isonum.txt>
+
+===============================================================
+Intel Image Processing Unit 3 (IPU3) Imaging Unit (ImgU) driver
+===============================================================
+
+Copyright |copy| 2018 Intel Corporation
+
+Introduction
+============
+
+This file documents the Intel IPU3 (3rd generation Image Processing Unit)
+Imaging Unit drivers located under drivers/media/pci/intel/ipu3 (CIO2) as well
+as under drivers/staging/media/ipu3 (ImgU).
+
+The Intel IPU3 found in certain Kaby Lake (as well as certain Sky Lake)
+platforms (U/Y processor lines) is made up of two parts namely the Imaging Unit
+(ImgU) and the CIO2 device (MIPI CSI2 receiver).
+
+The CIO2 device receives the raw Bayer data from the sensors and outputs the
+frames in a format that is specific to the IPU3 (for consumption by the IPU3
+ImgU). The CIO2 driver is available as drivers/media/pci/intel/ipu3/ipu3-cio2*
+and is enabled through the CONFIG_VIDEO_IPU3_CIO2 config option.
+
+The Imaging Unit (ImgU) is responsible for processing images captured
+by the IPU3 CIO2 device. The ImgU driver sources can be found under
+drivers/staging/media/ipu3 directory. The driver is enabled through the
+CONFIG_VIDEO_IPU3_IMGU config option.
+
+The two driver modules are named ipu3_csi2 and ipu3_imgu, respectively.
+
+The drivers has been tested on Kaby Lake platforms (U/Y processor lines).
+
+Both of the drivers implement V4L2, Media Controller and V4L2 sub-device
+interfaces. The IPU3 CIO2 driver supports camera sensors connected to the CIO2
+MIPI CSI-2 interfaces through V4L2 sub-device sensor drivers.
+
+CIO2
+====
+
+The CIO2 is represented as a single V4L2 subdev, which provides a V4L2 subdev
+interface to the user space. There is a video node for each CSI-2 receiver,
+with a single media controller interface for the entire device.
+
+The CIO2 contains four independent capture channel, each with its own MIPI CSI-2
+receiver and DMA engine. Each channel is modelled as a V4L2 sub-device exposed
+to userspace as a V4L2 sub-device node and has two pads:
+
+.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|
+
+.. flat-table::
+
+    * - pad
+      - direction
+      - purpose
+
+    * - 0
+      - sink
+      - MIPI CSI-2 input, connected to the sensor subdev
+
+    * - 1
+      - source
+      - Raw video capture, connected to the V4L2 video interface
+
+The V4L2 video interfaces model the DMA engines. They are exposed to userspace
+as V4L2 video device nodes.
+
+Capturing frames in raw Bayer format
+------------------------------------
+
+CIO2 MIPI CSI2 receiver is used to capture frames (in packed raw Bayer format)
+from the raw sensors connected to the CSI2 ports. The captured frames are used
+as input to the ImgU driver.
+
+Image processing using IPU3 ImgU requires tools such as raw2pnm [#f1]_, and
+yavta [#f2]_ due to the following unique requirements and / or features specific
+to IPU3.
+
+-- The IPU3 CSI2 receiver outputs the captured frames from the sensor in packed
+raw Bayer format that is specific to IPU3.
+
+-- Multiple video nodes have to be operated simultaneously.
+
+Let us take the example of ov5670 sensor connected to CSI2 port 0, for a
+2592x1944 image capture.
+
+Using the media contorller APIs, the ov5670 sensor is configured to send
+frames in packed raw Bayer format to IPU3 CSI2 receiver.
+
+# This example assumes /dev/media0 as the CIO2 media device
+
+export MDEV=/dev/media0
+
+# and that ov5670 sensor is connected to i2c bus 10 with address 0x36
+
+export SDEV=$(media-ctl -d $MDEV -e "ov5670 10-0036")
+
+# Establish the link for the media devices using media-ctl [#f3]_
+media-ctl -d $MDEV -l "ov5670:0 -> ipu3-csi2 0:0[1]"
+
+# Set the format for the media devices
+media-ctl -d $MDEV -V "ov5670:0 [fmt:SGRBG10/2592x1944]"
+
+media-ctl -d $MDEV -V "ipu3-csi2 0:0 [fmt:SGRBG10/2592x1944]"
+
+media-ctl -d $MDEV -V "ipu3-csi2 0:1 [fmt:SGRBG10/2592x1944]"
+
+Once the media pipeline is configured, desired sensor specific settings
+(such as exposure and gain settings) can be set, using the yavta tool.
+
+e.g
+
+yavta -w 0x009e0903 444 $SDEV
+
+yavta -w 0x009e0913 1024 $SDEV
+
+yavta -w 0x009e0911 2046 $SDEV
+
+Once the desired sensor settings are set, frame captures can be done as below.
+
+e.g
+
+yavta --data-prefix -u -c10 -n5 -I -s2592x1944 --file=/tmp/frame-#.bin \
+      -f IPU3_SGRBG10 $(media-ctl -d $MDEV -e "ipu3-cio2 0")
+
+With the above command, 10 frames are captured at 2592x1944 resolution, with
+sGRBG10 format and output as IPU3_SGRBG10 format.
+
+The captured frames are available as /tmp/frame-#.bin files.
+
+ImgU
+====
+
+The ImgU is represented as two V4L2 subdevs, each of which provides a V4L2
+subdev interface to the user space.
+
+Each V4L2 subdev represents a pipe, which can support a maximum of 2 streams.
+This helps to support advanced camera features like Continuous View Finder (CVF)
+and Snapshot During Video(SDV).
+
+The ImgU contains two independent pipes, each modelled as a V4L2 sub-device
+exposed to userspace as a V4L2 sub-device node.
+
+Each pipe has two sink pads and three source pads for the following purpose:
+
+.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|
+
+.. flat-table::
+
+    * - pad
+      - direction
+      - purpose
+
+    * - 0
+      - sink
+      - Input raw video stream
+
+    * - 1
+      - sink
+      - Processing parameters
+
+    * - 2
+      - source
+      - Output processed video stream
+
+    * - 3
+      - source
+      - Output viewfinder video stream
+
+    * - 4
+      - source
+      - 3A statistics
+
+Each pad is connected to a corresponding V4L2 video interface, exposed to 
+userspace as a V4L2 video device node.
+
+Device operation
+----------------
+
+With ImgU, once the input video node ("ipu3-imgu 0/1":0, in
+<entity>:<pad-number> format) is queued with buffer (in packed raw Bayer
+format), ImgU starts processing the buffer and produces the video output in YUV
+format and statistics output on respective output nodes. The driver is expected
+to have buffers ready for all of parameter, output and statistics nodes, when
+input video node is queued with buffer.
+
+At a minimum, all of input, main output, 3A statistics and viewfinder
+video nodes should be enabled for IPU3 to start image processing.
+
+Each ImgU V4L2 subdev has the following set of video nodes.
+
+input, output and viewfinder video nodes
+----------------------------------------
+
+The frames (in packed raw Bayer format specific to the IPU3) received by the
+input video node is processed by the IPU3 Imaging Unit and are output to 2 video
+nodes, with each targeting a different purpose (main output and viewfinder
+output).
+
+Details onand the Bayer format specific to the IPU3 can be found in
+:ref:`v4l2-pix-fmt-ipu3-sbggr10`.
+
+The driver supports V4L2 Video Capture Interface as defined at :ref:`devices`.
+
+Only the multi-planar API is supported. More details can be found at
+:ref:`planar-apis`.
+
+Parameters video node
+---------------------
+
+The parameters video node receives the ImgU algorithm parameters that are used
+to configure how the ImgU algorithms process the image.
+
+Details on processing parameters specific to the IPU3 can be found in
+:ref:`v4l2-meta-fmt-params`.
+
+3A statistics video node
+------------------------
+
+3A statistics video node is used by the ImgU driver to output the 3A (auto
+focus, auto exposure and auto white balance) statistics for the frames that are
+being processed by the ImgU to user space applications. User space applications
+can use this statistics data to compute the desired algorithm parameters for
+the ImgU.
+
+Configuring the Intel IPU3
+==========================
+
+The IPU3 ImgU pipelines can be configured using the Media Controller, defined at
+:ref:`media_controller`.
+
+Firmware binary selection
+-------------------------
+
+The firmware binary is selected using the V4L2_CID_INTEL_IPU3_MODE, currently
+defined in drivers/staging/media/ipu3/include/intel-ipu3.h . "VIDEO" and "STILL"
+modes are available.
+
+Processing the image in raw Bayer format
+----------------------------------------
+
+Configuring ImgU V4L2 subdev for image processing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ImgU V4L2 subdevs have to be configured with media controller APIs to have
+all the video nodes setup correctly.
+
+Let us take "ipu3-imgu 0" subdev as an example.
+
+media-ctl -d $MDEV -r
+
+media-ctl -d $MDEV -l "ipu3-imgu 0 input":0 -> "ipu3-imgu 0":0[1]
+
+media-ctl -d $MDEV -l "ipu3-imgu 0":2 -> "ipu3-imgu 0 output":0[1]
+
+media-ctl -d $MDEV -l "ipu3-imgu 0":3 -> "ipu3-imgu 0 viewfinder":0[1]
+
+media-ctl -d $MDEV -l "ipu3-imgu 0":4 -> "ipu3-imgu 0 3a stat":0[1]
+
+Also the pipe mode of the corresponding V4L2 subdev should be set as desired
+(e.g 0 for video mode or 1 for still mode) through the control id 0x009819a1 as
+below.
+
+yavta -w "0x009819A1 1" /dev/v4l-subdev7
+
+RAW Bayer frames go through the following ImgU pipeline HW blocks to have the
+processed image output to the DDR memory.
+
+RAW Bayer frame -> Input Feeder -> Bayer Down Scaling (BDS) -> Geometric
+Distortion Correction (GDC) -> DDR
+
+The ImgU V4L2 subdev has to be configured with the supported resolutions in all
+the above HW blocks, for a given input resolution.
+
+For a given supported resolution for an input frame, the Input Feeder, Bayer
+Down Scaling and GDC blocks should be configured with the supported resolutions.
+This information can be obtained by looking at the following IPU3 ImgU
+configuration table.
+
+https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master
+
+Under baseboard-poppy/media-libs/cros-camera-hal-configs-poppy/files/gcss
+directory, graph_settings_ov5670.xml can be used as an example.
+
+The following steps prepare the ImgU pipeline for the image processing.
+
+1. The ImgU V4L2 subdev data format should be set by using the
+VIDIOC_SUBDEV_S_FMT on pad 0, using the GDC width and height obtained above.
+
+2. The ImgU V4L2 subdev cropping should be set by using the
+VIDIOC_SUBDEV_S_SELECTION on pad 0, with V4L2_SEL_TGT_CROP as the target,
+using the input feeder height and width.
+
+3. The ImgU V4L2 subdev composing should be set by using the
+VIDIOC_SUBDEV_S_SELECTION on pad 0, with V4L2_SEL_TGT_COMPOSE as the target,
+using the BDS height and width.
+
+For the ov5670 example, for an input frame with a resolution of 2592x1944
+(which is input to the ImgU subdev pad 0), the corresponding resolutions
+for input feeder, BDS and GDC are 2592x1944, 2592x1944 and 2560x1920
+respectively.
+
+Once this is done, the received raw Bayer frames can be input to the ImgU
+V4L2 subdev as below, using the open source application v4l2n [#f1]_.
+
+For an image captured with 2592x1944 [#f4]_ resolution, with desired output
+resolution as 2560x1920 and viewfinder resolution as 2560x1920, the following
+v4l2n command can be used. This helps process the raw Bayer frames and produces
+the desired results for the main output image and the viewfinder output, in NV12
+format.
+
+v4l2n --pipe=4 --load=/tmp/frame-#.bin --open=/dev/video4
+--fmt=type:VIDEO_OUTPUT_MPLANE,width=2592,height=1944,pixelformat=0X47337069
+--reqbufs=type:VIDEO_OUTPUT_MPLANE,count:1 --pipe=1 --output=/tmp/frames.out
+--open=/dev/video5
+--fmt=type:VIDEO_CAPTURE_MPLANE,width=2560,height=1920,pixelformat=NV12
+--reqbufs=type:VIDEO_CAPTURE_MPLANE,count:1 --pipe=2 --output=/tmp/frames.vf
+--open=/dev/video6
+--fmt=type:VIDEO_CAPTURE_MPLANE,width=2560,height=1920,pixelformat=NV12
+--reqbufs=type:VIDEO_CAPTURE_MPLANE,count:1 --pipe=3 --open=/dev/video7
+--output=/tmp/frames.3A --fmt=type:META_CAPTURE,?
+--reqbufs=count:1,type:META_CAPTURE --pipe=1,2,3,4 --stream=5
+
+where /dev/video4, /dev/video5, /dev/video6 and /dev/video7 devices point to
+input, output, viewfinder and 3A statistics video nodes respectively.
+
+Converting the raw Bayer image into YUV domain
+----------------------------------------------
+
+The processed images after the above step, can be converted to YUV domain
+as below.
+
+Main output frames
+~~~~~~~~~~~~~~~~~~
+
+raw2pnm -x2560 -y1920 -fNV12 /tmp/frames.out /tmp/frames.out.ppm
+
+where 2560x1920 is output resolution, NV12 is the video format, followed
+by input frame and output PNM file.
+
+Viewfinder output frames
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+raw2pnm -x2560 -y1920 -fNV12 /tmp/frames.vf /tmp/frames.vf.ppm
+
+where 2560x1920 is output resolution, NV12 is the video format, followed
+by input frame and output PNM file.
+
+Example user space code for IPU3
+================================
+
+User space code that configures and uses IPU3 is available here.
+
+https://chromium.googlesource.com/chromiumos/platform/arc-camera/+/master/
+
+The source can be located under hal/intel directory.
+
+References
+==========
+
+.. [#f5] include/uapi/linux/intel-ipu3.h
+
+.. [#f1] https://github.com/intel/nvt
+
+.. [#f2] http://git.ideasonboard.org/yavta.git
+
+.. [#f3] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
+
+.. [#f4] ImgU limitation requires an additional 16x16 for all input resolutions
index 022dca80c2c8717befff64a5ee234e33a571d388..c34a9ebc9ac2f40d93e9fca647c0fb3ba58dcff2 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 IVTV cards list
 ===============
 
index 3ba464c4f9bf7ed77c7dc42cde79ae599ed88dca..7b8775d20214380a9f5b84e9d52660d66be47937 100644 (file)
@@ -1,3 +1,4 @@
+.. SPDX-License-Identifier: GPL-2.0
 
 The ivtv driver
 ===============
index b1a4c89fd869eb688418d938c024c2bae88d4063..a5e35059d98d9748c3f79421bb709538b772e6ea 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Maxim Integrated MAX2175 RF to bits tuner driver
 ================================================
 
index cfaba602185041cab74a88929f6382d18787d67a..a572996cdbf60ab602e3d4ddaaf4658b746eff6a 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 Vaio Picturebook Motion Eye Camera Driver
index 336e58feaee224cd3899222fa2beee74588d5a2e..8974c444e3a17c241a7f3e5d928514f31df881fe 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 OMAP 3 Image Signal Processor (ISP) driver
index 54b427b28e5f7395bce2f198dd5652910cf04f4a..24db4222d36dca173dff8c0105eb69a25f9b6704 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 OMAP4 ISS Driver
 ================
 
index 4f68947e6a13eb6923c07fbe6b2cc34c678e1bda..e2840be10d088f2cbd24f8d70c17c21f75714f34 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Philips webcams (pwc driver)
 ============================
 
index dc0e72d94b1a1d7af487b1083ed5db49c462e52d..83bfaa531ea87d398b6b6f3833effb874063574c 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The pvrusb2 driver
 ==================
 
index 554f91b04e705ba5c4aa9bc012b65e216b68bd54..e4fbca755e1aa42f7b52c018d5377a080c43ba23 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 PXA-Camera Host Driver
 ======================
 
index f27c8df20b2b4acc466245454c035ea0ea1d9393..6b15385b12b3970e7cf802db5a2f41c4db452517 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 Qualcomm Camera Subsystem driver
index de34f0a7afdcd7567f99a01acbebf280ae9b4d2e..7ed243b41b67af396803abf9fa79210c29526a4f 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 digraph board {
        rankdir=TB
        n00000001 [label="{{<port0> 0} | msm_csiphy0\n/dev/v4l-subdev0 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
index 827fc7112c1eeb0f69280c8e7ac99f9f65118a9e..ef7dca92fd0b88f37d91b4b604598f15de845847 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 digraph board {
        rankdir=TB
        n00000001 [label="{{<port0> 0} | msm_csiphy0\n/dev/v4l-subdev0 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
index 2f6325ebfd169bf802e7d4d57ca0dbd4a5c0a7cc..a85cb6205db89e71d5c8efb74d68123e25ba1b73 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The Radiotrack radio driver
 ===========================
 
index a59b1e8e3e9c0b1ff9b1736e0f8aa6a6f51d6b17..88b0edcf9046eba70c0e0c79b48fdb9e96af9569 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Renesas R-Car Fine Display Processor (FDP1) Driver
 ==================================================
 
index 6e4c35cbaabf11d267dc7d1a15cba10e7bc934d3..afb0e2fb52b05b9f6256111f23fc4869703b0571 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 SAA7134 cards list
 ==================
 
index 36b2ee9e0fdc5536581de000c70b6093bea6c220..15d06facdbc193b32f9edeef21540e1024b607cc 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The saa7134 driver
 ==================
 
index e28382ba82e67352ccaad4f5cd6f4492b8fd109e..e8f36e084537cd1177312f86ae9cd01c4ba51a58 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 SAA7164 cards list
 ==================
 
index e40ffea7708c8b8497d2fa85e6050843ee7e4e87..822fcb8368ae2c885337e24d8fe43b57f03bc57a 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
 =======================================================================
 
@@ -114,7 +116,7 @@ window:
 S_CROP
 ------
 
-The API at http://v4l2spec.bytesex.org/spec/x1904.htm says:
+The :ref:`V4L2 crop API <crop-scale>` says:
 
 "...specification does not define an origin or units. However by convention
 drivers should horizontally count unscaled samples relative to 0H."
index 955d8ca159fed93c574f5e051638a5137a423d24..d53bf5f952003e6db7bf9702b7ef1bb98369c486 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 The Silicon Labs Si470x FM Radio Receivers driver
index 3022e7cfe9a80bb3c35c06b62ad40f201dafcb16..be8e6b49b7b4a041367110e663b3807d04ff3e35 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 The Silicon Labs Si4713 FM Radio Transmitter Driver
index 677512566f15d334018fe490cd3f0dc60c3d7f02..87062301d6a1e0b2f999f3df8c128f57b396f520 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 .. include:: <isonum.txt>
 
 
index 79d09e423700e70c8c4b0d5d6f9699ad999cb87c..7c39711aebf82d8a417bc6e77acac25441b3bdaf 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The Soc-Camera Drivers
 ======================
 
index 6bd083544457aaf427c91efc91422e93bbee8ee2..6d2769c0f4d8a36521b1199ab1a48d36ec48c282 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 TM6000 cards list
 =================
 
index 276dd90e0c5908a9c123a8685622fedc89700d31..362617c59c5d01ced7e1ab87bda33f5d2ff61927 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Tuner cards list
 ================
 
index c3e8a1cf64a63334c5c63cd6afcd4c2125dcd7c0..7509be888909374a1cc5cc8f23db76d4bd4dced5 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Tuner drivers
 =============
 
index 5a8ffbfc204e18755114208fc6e3eb51ebfcd93c..6aee115ee6e25a611cb5fc962283d6e974bb7ee4 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 USBvision cards list
 ====================
 
index d68b3d59a4b506ddf3eb1ec7a16a92e36a07ad09..e5fd8fad333c9515e6280411aa27d81b65787cb0 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The Linux USB Video Class (UVC) driver
 ======================================
 
index 613e1e79fc965214f5450955c95698ca8fac2456..ce23c8a7bc9385ad360fa30897de7953eaa44854 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Infrared remote control support in video4linux drivers
 ======================================================
 
index 089595ce11c5fdfa44de69c4439df955dd92c973..edb6f33e029c3bce287b35cedbd4d640779bf008 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The Virtual Video Test Driver (vivid)
 =====================================
 
index c3a0f7bc2c7be3a03e411b676459f0cef80d231d..d2724a863d1d5a5cabc810690bfff8bcba4f58cd 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 The Zoran driver
 ================
 
index 3d193f01d8bb8a4f61d8af25d7e331a0d7e61e58..ec8acb3e98fc7a63e0e2f0988038ae103c07adcd 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 Zoran 364xx based USB webcam module
 ===================================
 
index 371cdbd7d062aef7c1228051667e93ab9dcd608d..ea9de59ad8b77505246950a18f1bbc53d6f7a180 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _UAPI_DVBVIDEO_H_
 
index 1ec425a7c3642e66a6b250c1223129b3b09eab5a..64d348e67df990554bda30fc4a336c37cfe91820 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 # Ignore header name
 ignore define _UAPI__LINUX_VIDEODEV2_H
 
@@ -28,6 +30,7 @@ replace symbol V4L2_FIELD_TOP :c:type:`v4l2_field`
 
 # Documented enum v4l2_buf_type
 replace symbol V4L2_BUF_TYPE_META_CAPTURE :c:type:`v4l2_buf_type`
+replace symbol V4L2_BUF_TYPE_META_OUTPUT :c:type:`v4l2_buf_type`
 replace symbol V4L2_BUF_TYPE_SDR_CAPTURE :c:type:`v4l2_buf_type`
 replace symbol V4L2_BUF_TYPE_SDR_OUTPUT :c:type:`v4l2_buf_type`
 replace symbol V4L2_BUF_TYPE_SLICED_VBI_CAPTURE :c:type:`v4l2_buf_type`
@@ -161,6 +164,7 @@ replace define V4L2_CAP_META_CAPTURE device-capabilities
 replace define V4L2_CAP_READWRITE device-capabilities
 replace define V4L2_CAP_ASYNCIO device-capabilities
 replace define V4L2_CAP_STREAMING device-capabilities
+replace define V4L2_CAP_META_OUTPUT device-capabilities
 replace define V4L2_CAP_DEVICE_CAPS device-capabilities
 replace define V4L2_CAP_TOUCH device-capabilities
 
index fdd84cb8d511f4aef71f18f281ba629ad025d17f..b8e29f977f2d1f3a2898444bc9720c39ab9eaa4f 100644 (file)
@@ -143,7 +143,7 @@ using a number of wrapper functions:
        Query the address space, and return true if it is completely
        unevictable.
 
-These are currently used in two places in the kernel:
+These are currently used in three places in the kernel:
 
  (1) By ramfs to mark the address spaces of its inodes when they are created,
      and this mark remains for the life of the inode.
@@ -154,6 +154,10 @@ These are currently used in two places in the kernel:
      swapped out; the application must touch the pages manually if it wants to
      ensure they're in memory.
 
+ (3) By the i915 driver to mark pinned address space until it's unpinned. The
+     amount of unevictable memory marked by i915 driver is roughly the bounded
+     object size in debugfs/dri/0/i915_gem_objects.
+
 
 Detecting Unevictable Pages
 ---------------------------
index 3318f30903b2aca669056219e4a024ab92867180..f0f0c23fce543a8b75f1b0d9a73ff4fa608f7cbc 100644 (file)
@@ -1310,6 +1310,13 @@ F:       drivers/pinctrl/meson/
 F:     drivers/mmc/host/meson*
 N:     meson
 
+ARM/Amlogic Meson SoC Sound Drivers
+M:     Jerome Brunet <jbrunet@baylibre.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/meson/
+F:     Documentation/devicetree/bindings/sound/amlogic*
+
 ARM/Annapurna Labs ALPINE ARCHITECTURE
 M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
 M:     Antoine Tenart <antoine.tenart@bootlin.com>
@@ -2067,7 +2074,6 @@ M:        Andrzej Hajda <a.hajda@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     arch/arm/plat-samsung/s5p-dev-mfc.c
 F:     drivers/media/platform/s5p-mfc/
 
 ARM/SHMOBILE ARM ARCHITECTURE
@@ -2419,6 +2425,14 @@ S:       Maintained
 F:     Documentation/hwmon/asc7621
 F:     drivers/hwmon/asc7621.c
 
+ASPEED VIDEO ENGINE DRIVER
+M:     Eddie James <eajames@linux.ibm.com>
+L:     linux-media@vger.kernel.org
+L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/media/platform/aspeed-video.c
+F:     Documentation/devicetree/bindings/media/aspeed-video.txt
+
 ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
 M:     Corentin Chary <corentin.chary@gmail.com>
 L:     acpi4asus-user@lists.sourceforge.net
@@ -2633,6 +2647,13 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/sound/axentia,*
 F:     sound/soc/atmel/tse850-pcm5142.c
 
+AXXIA I2C CONTROLLER
+M:     Krzysztof Adamski <krzysztof.adamski@nokia.com>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/i2c/i2c-axxia.txt
+F:     drivers/i2c/busses/i2c-axxia.c
+
 AZ6007 DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
@@ -3988,13 +4009,20 @@ T:      git git://linuxtv.org/media_tree.git
 W:     http://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/i2c/cs3308.c
-F:     drivers/media/i2c/cs3308.h
 
 CS5535 Audio ALSA driver
 M:     Jaya Kumar <jayakumar.alsa@gmail.com>
 S:     Maintained
 F:     sound/pci/cs5535audio/
 
+CSI DRIVERS FOR ALLWINNER V3s
+M:     Yong Deng <yong.deng@magewell.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/platform/sunxi/sun6i-csi/
+F:     Documentation/devicetree/bindings/media/sun6i-csi.txt
+
 CW1200 WLAN driver
 M:     Solomon Peachy <pizza@shaftnet.org>
 S:     Maintained
@@ -4019,7 +4047,7 @@ T:        git git://linuxtv.org/media_tree.git
 W:     https://linuxtv.org
 S:     Maintained
 F:     drivers/media/common/cx2341x*
-F:     include/media/cx2341x*
+F:     include/media/drv-intf/cx2341x.h
 
 CX24120 MEDIA DRIVER
 M:     Jemma Denson <jdenson@gmail.com>
@@ -4050,7 +4078,7 @@ S:        Maintained
 F:     drivers/media/dvb-frontends/cxd2820r*
 
 CXGB3 ETHERNET DRIVER (CXGB3)
-M:     Santosh Raspatur <santosh@chelsio.com>
+M:     Arjun Vynipadath <arjun@chelsio.com>
 L:     netdev@vger.kernel.org
 W:     http://www.chelsio.com
 S:     Supported
@@ -4079,7 +4107,7 @@ S:        Supported
 F:     drivers/crypto/chelsio
 
 CXGB4 ETHERNET DRIVER (CXGB4)
-M:     Ganesh Goudar <ganeshgr@chelsio.com>
+M:     Arjun Vynipadath <arjun@chelsio.com>
 L:     netdev@vger.kernel.org
 W:     http://www.chelsio.com
 S:     Supported
@@ -4730,6 +4758,13 @@ S:       Maintained
 F:     drivers/gpu/drm/tinydrm/ili9225.c
 F:     Documentation/devicetree/bindings/display/ilitek,ili9225.txt
 
+DRM DRIVER FOR HX8357D PANELS
+M:     Eric Anholt <eric@anholt.net>
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+S:     Maintained
+F:     drivers/gpu/drm/tinydrm/hx8357d.c
+F:     Documentation/devicetree/bindings/display/himax,hx8357d.txt
+
 DRM DRIVER FOR INTEL I810 VIDEO CARDS
 S:     Orphan / Obsolete
 F:     drivers/gpu/drm/i810/
@@ -4771,6 +4806,12 @@ S:       Supported
 F:     drivers/gpu/drm/nouveau/
 F:     include/uapi/drm/nouveau_drm.h
 
+DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
+M:     Stefan Mavrodiev <stefan@olimex.com>
+S:     Maintained
+F:     drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
+F:     Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt
+
 DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
 M:     Noralf Trønnes <noralf@tronnes.org>
 S:     Maintained
@@ -4836,10 +4877,8 @@ T:       git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVER FOR VMWARE VIRTUAL GPU
 M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
-M:     Sinclair Yeh <syeh@vmware.com>
 M:     Thomas Hellstrom <thellstrom@vmware.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~syeh/repos_linux
 T:     git git://people.freedesktop.org/~thomash/linux
 S:     Supported
 F:     drivers/gpu/drm/vmwgfx/
@@ -4897,7 +4936,7 @@ F:        Documentation/gpu/meson.rst
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR ATMEL HLCDC
-M:     Boris Brezillon <boris.brezillon@bootlin.com>
+M:     Boris Brezillon <bbrezillon@kernel.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/atmel-hlcdc/
@@ -5406,7 +5445,6 @@ S:        Maintained
 F:     drivers/edac/i82443bxgx_edac.c
 
 EDAC-I82975X
-M:     Ranganathan Desikan <ravi@jetztechnologies.com>
 M:     "Arvind R." <arvino55@gmail.com>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
@@ -6906,8 +6944,10 @@ Hyper-V CORE AND DRIVERS
 M:     "K. Y. Srinivasan" <kys@microsoft.com>
 M:     Haiyang Zhang <haiyangz@microsoft.com>
 M:     Stephen Hemminger <sthemmin@microsoft.com>
+M:     Sasha Levin <sashal@kernel.org>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
 L:     devel@linuxdriverproject.org
-S:     Maintained
+S:     Supported
 F:     Documentation/networking/netvsc.txt
 F:     arch/x86/include/asm/mshyperv.h
 F:     arch/x86/include/asm/trace/hyperv.h
@@ -7068,6 +7108,24 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-stub.c
 
+I3C SUBSYSTEM
+M:     Boris Brezillon <bbrezillon@kernel.org>
+L:     linux-i3c@lists.infradead.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
+S:     Maintained
+F:     Documentation/ABI/testing/sysfs-bus-i3c
+F:     Documentation/devicetree/bindings/i3c/
+F:     Documentation/driver-api/i3c
+F:     drivers/i3c/
+F:     include/linux/i3c/
+F:     include/dt-bindings/i3c/
+
+I3C DRIVER FOR SYNOPSYS DESIGNWARE
+M:     Vitor Soares <vitor.soares@synopsys.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt
+F:     drivers/i3c/master/dw*
+
 IA64 (Itanium) PLATFORM
 M:     Tony Luck <tony.luck@intel.com>
 M:     Fenghua Yu <fenghua.yu@intel.com>
@@ -7593,6 +7651,14 @@ S:       Maintained
 F:     drivers/media/pci/intel/ipu3/
 F:     Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst
 
+INTEL IPU3 CSI-2 IMGU DRIVER
+M:     Sakari Ailus <sakari.ailus@linux.intel.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/staging/media/ipu3/
+F:     Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
+F:     Documentation/media/v4l-drivers/ipu3.rst
+
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
 S:     Maintained
@@ -8943,7 +9009,7 @@ F:        arch/mips/boot/dts/img/pistachio_marduk.dts
 
 MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
 M:     Andrew Lunn <andrew@lunn.ch>
-M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+M:     Vivien Didelot <vivien.didelot@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/dsa/mv88e6xxx/
@@ -8960,7 +9026,7 @@ F:        include/uapi/drm/armada_drm.h
 F:     Documentation/devicetree/bindings/display/armada/
 
 MARVELL CRYPTO DRIVER
-M:     Boris Brezillon <boris.brezillon@bootlin.com>
+M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Arnaud Ebalard <arno@natisbad.org>
 F:     drivers/crypto/marvell/
 S:     Maintained
@@ -9448,6 +9514,13 @@ F:       drivers/media/platform/mtk-vpu/
 F:     Documentation/devicetree/bindings/media/mediatek-vcodec.txt
 F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
 
+MEDIATEK MT76 WIRELESS LAN DRIVER
+M:     Felix Fietkau <nbd@nbd.name>
+M:     Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     drivers/net/wireless/mediatek/mt76/
+
 MEDIATEK MT7601U WIRELESS LAN DRIVER
 M:     Jakub Kicinski <kubakici@wp.pl>
 L:     linux-wireless@vger.kernel.org
@@ -9664,7 +9737,7 @@ F:        mm/
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Brian Norris <computersforpeace@gmail.com>
-M:     Boris Brezillon <boris.brezillon@bootlin.com>
+M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Marek Vasut <marek.vasut@gmail.com>
 M:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
@@ -9765,14 +9838,14 @@ L:      linux-media@vger.kernel.org
 S:     Supported
 F:     drivers/media/platform/atmel/atmel-isc.c
 F:     drivers/media/platform/atmel/atmel-isc-regs.h
-F:     devicetree/bindings/media/atmel-isc.txt
+F:     Documentation/devicetree/bindings/media/atmel-isc.txt
 
 MICROCHIP ISI DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
 F:     drivers/media/platform/atmel/atmel-isi.c
-F:     include/media/atmel-isi.h
+F:     drivers/media/platform/atmel/atmel-isi.h
 
 MICROCHIP AT91 USART MFD DRIVER
 M:     Radu Pirea <radu_nicolae.pirea@upb.ro>
@@ -9818,6 +9891,13 @@ M:       Ludovic Desroches <ludovic.desroches@microchip.com>
 S:     Maintained
 F:     drivers/mmc/host/atmel-mci.c
 
+MICROCHIP MCP16502 PMIC DRIVER
+M:     Andrei Stefanescu <andrei.stefanescu@microchip.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
+F:     drivers/regulator/mcp16502.c
+
 MICROCHIP MCP3911 ADC DRIVER
 M:     Marcus Folkesson <marcus.folkesson@gmail.com>
 M:     Kent Gustavsson <kent@minoris.se>
@@ -10251,7 +10331,7 @@ S:      Supported
 F:     drivers/net/ethernet/myricom/myri10ge/
 
 NAND FLASH SUBSYSTEM
-M:     Boris Brezillon <boris.brezillon@bootlin.com>
+M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 R:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
@@ -10418,7 +10498,7 @@ F:      drivers/net/wireless/
 
 NETWORKING [DSA]
 M:     Andrew Lunn <andrew@lunn.ch>
-M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+M:     Vivien Didelot <vivien.didelot@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/dsa/
@@ -10795,7 +10875,10 @@ M:     Jarkko Nikula <jarkko.nikula@bitmer.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linux-omap@vger.kernel.org
 S:     Maintained
-F:     sound/soc/omap/
+F:     sound/soc/ti/omap*
+F:     sound/soc/ti/rx51.c
+F:     sound/soc/ti/n810.c
+F:     sound/soc/ti/sdma-pcm.*
 
 OMAP CLOCK FRAMEWORK SUPPORT
 M:     Paul Walmsley <paul@pwsan.com>
@@ -12411,7 +12494,7 @@ S:      Supported
 F:     drivers/net/wireless/ath/ath9k/
 
 QUALCOMM CAMERA SUBSYSTEM DRIVER
-M:     Todor Tomov <todor.tomov@linaro.org>
+M:     Todor Tomov <todor.too@gmail.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/qcom,camss.txt
@@ -12844,6 +12927,13 @@ S:     Maintained
 F:     drivers/media/platform/rockchip/rga/
 F:     Documentation/devicetree/bindings/media/rockchip-rga.txt
 
+ROCKCHIP VPU CODEC DRIVER
+M:     Ezequiel Garcia <ezequiel@collabora.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/staging/media/platform/rockchip/vpu/
+F:     Documentation/devicetree/bindings/media/rockchip-vpu.txt
+
 ROCKER DRIVER
 M:     Jiri Pirko <jiri@resnulli.us>
 L:     netdev@vger.kernel.org
@@ -13093,7 +13183,7 @@ T:      git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/common/saa7146/
 F:     drivers/media/pci/saa7146/
-F:     include/media/saa7146*
+F:     include/media/drv-intf/saa7146*
 
 SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Krzysztof Kozlowski <krzk@kernel.org>
@@ -13359,6 +13449,12 @@ L:     sdricohcs-devel@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 F:     drivers/mmc/host/sdricoh_cs.c
 
+SECO BOARDS CEC DRIVER
+M:     Ettore Chimenti <ek5.chimenti@gmail.com>
+S:     Maintained
+F:     drivers/media/platform/seco-cec/seco-cec.c
+F:     drivers/media/platform/seco-cec/seco-cec.h
+
 SECURE COMPUTING
 M:     Kees Cook <keescook@chromium.org>
 R:     Andy Lutomirski <luto@amacapital.net>
@@ -13932,6 +14028,14 @@ S:     Maintained
 F:     drivers/ssb/
 F:     include/linux/ssb/
 
+SONY IMX214 SENSOR DRIVER
+M:     Ricardo Ribalda <ricardo.ribalda@gmail.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/i2c/imx214.c
+F:     Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
+
 SONY IMX258 SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
@@ -14839,6 +14943,12 @@ F:     Documentation/devicetree/bindings/clock/ti,sci-clk.txt
 F:     drivers/clk/keystone/sci-clk.c
 F:     drivers/reset/reset-ti-sci.c
 
+Texas Instruments ASoC drivers
+M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/ti/
+
 THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -16426,6 +16536,12 @@ F:     include/linux/idr.h
 F:     include/linux/xarray.h
 F:     tools/testing/radix-tree
 
+XBOX DVD IR REMOTE
+M:     Benjamin Valentin <benpicco@googlemail.com>
+S:     Maintained
+F:     drivers/media/rc/xbox_remote.c
+F:     drivers/media/rc/keymaps/rc-xbox-dvd.c
+
 XC2028/3028 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
index 56d5270f22f8c73e06056dd39bb4d6a8d3c8bced..7a2a9a175756c41c10e7ca85b87115dbd89f8c39 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 4
 PATCHLEVEL = 20
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Shy Crocodile
 
 # *DOCUMENTATION*
@@ -962,11 +962,6 @@ ifdef CONFIG_STACK_VALIDATION
   ifeq ($(has_libelf),1)
     objtool_target := tools/objtool FORCE
   else
-    ifdef CONFIG_UNWINDER_ORC
-      $(error "Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
-    else
-      $(warning "Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
-    endif
     SKIP_STACK_VALIDATION := 1
     export SKIP_STACK_VALIDATION
   endif
@@ -1081,7 +1076,7 @@ scripts: scripts_basic scripts_dtc asm-generic gcc-plugins $(autoksyms_h)
 # version.h and scripts_basic is processed / created.
 
 # Listed in dependency order
-PHONY += prepare archprepare macroprepare prepare0 prepare1 prepare2 prepare3
+PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
 
 # prepare3 is used to check if we are building in a separate output directory,
 # and if so do:
@@ -1104,9 +1099,7 @@ prepare2: prepare3 outputmakefile asm-generic
 prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h
        $(cmd_crmodverdir)
 
-macroprepare: prepare1 archmacros
-
-archprepare: archheaders archscripts macroprepare scripts_basic
+archprepare: archheaders archscripts prepare1 scripts_basic
 
 prepare0: archprepare gcc-plugins
        $(Q)$(MAKE) $(build)=.
@@ -1125,6 +1118,14 @@ uapi-asm-generic:
 
 PHONY += prepare-objtool
 prepare-objtool: $(objtool_target)
+ifeq ($(SKIP_STACK_VALIDATION),1)
+ifdef CONFIG_UNWINDER_ORC
+       @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2
+       @false
+else
+       @echo "warning: Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2
+endif
+endif
 
 # Generate some files
 # ---------------------------------------------------------------------------
@@ -1174,9 +1175,6 @@ archheaders:
 PHONY += archscripts
 archscripts:
 
-PHONY += archmacros
-archmacros:
-
 PHONY += __headers
 __headers: $(version_h) scripts_basic uapi-asm-generic archheaders archscripts
        $(Q)$(MAKE) $(build)=scripts build_unifdef
index b828677f331d5d6c89763d3e5a76d1779bd583af..ffafe9720b3590126dbc36195b692f85431bfcb9 100644 (file)
        regulator-min-microvolt = <2800000>;
        regulator-max-microvolt = <2800000>;
        regulator-name = "vddio-csi0";
+       regulator-soft-start;
+       regulator-ramp-delay = <1600>;
 };
 
 &reg_ldo4 {
index 07b2eadac3dd5f2a9da6d4e0f3bc3a151d0a8363..207962a656a26b0d6cc07d6f40586e54d3c0701a 100644 (file)
@@ -167,8 +167,9 @@ CONFIG_SOUND=m
 CONFIG_SND=m
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_SOC=m
-CONFIG_SND_EDMA_SOC=m
-CONFIG_SND_DA850_SOC_EVM=m
+CONFIG_SND_SOC_TLV320AIC3X=m
+CONFIG_SND_SOC_DAVINCI_MCASP=m
+CONFIG_SND_SOC_DAVINCI_EVM=m
 CONFIG_SND_SIMPLE_CARD=m
 CONFIG_HID=m
 CONFIG_HID_A4TECH=m
index 72f4bc83f4671bfbe25404d5a6c6852ff376219e..cfc00b0961ec5b00054653b123ea0c0af3bf42ff 100644 (file)
@@ -175,8 +175,6 @@ CONFIG_SND_PCM_OSS=y
 # CONFIG_SND_VERBOSE_PROCFS is not set
 CONFIG_SND_DUMMY=y
 CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_PHY=y
index 6491419b1dad76d502eda9ac492e9e0978ec22b6..2274e45623f994cab2497264a91f043f989fb5e9 100644 (file)
@@ -381,13 +381,13 @@ CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_SOC=m
-CONFIG_SND_EDMA_SOC=m
-CONFIG_SND_AM33XX_SOC_EVM=m
-CONFIG_SND_OMAP_SOC=m
-CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m
-CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
-CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
+CONFIG_SND_SOC_TLV320AIC3X=m
+CONFIG_SND_SOC_DAVINCI_MCASP=m
+CONFIG_SND_SOC_NOKIA_RX51=m
+CONFIG_SND_SOC_OMAP_HDMI=m
+CONFIG_SND_SOC_OMAP_ABE_TWL6040=m
+CONFIG_SND_SOC_OMAP3_PANDORA=m
+CONFIG_SND_SOC_OMAP3_TWL4030=m
 CONFIG_SND_SOC_CPCAP=m
 CONFIG_SND_SIMPLE_CARD=m
 CONFIG_SND_AUDIO_GRAPH_CARD=m
index 8143756ff38b022be3011fc6c901d9097edcf02b..09e439d4abf5398a251381991819e2614610c0e6 100644 (file)
@@ -794,9 +794,9 @@ static __init void dm365_evm_init(void)
        /* maybe setup mmc1/etc ... _after_ mmc0 */
        evm_init_cpld();
 
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
+#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
        dm365_init_asp();
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
+#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
        dm365_init_vc();
 #endif
        dm365_init_rtc();
index e8ccf51c6f292959c4f373d7a802c19ddf278c09..a7e9c6d19fb588a07f5ff1f7ed0636c8975043aa 100644 (file)
@@ -8,7 +8,7 @@ obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
         serial.o devices.o dma.o fb.o
 obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
 
-ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
 obj-y += mcbsp.o
 endif
 
index 17886744dbe694b1598524b72333374603a6b658..691a8da13fac771473cb167ec15119f31f8c5056 100644 (file)
@@ -296,23 +296,13 @@ struct modem_private_data {
 
 static struct modem_private_data modem_priv;
 
-static struct resource ams_delta_nand_resources[] = {
-       [0] = {
-               .start  = OMAP1_MPUIO_BASE,
-               .end    = OMAP1_MPUIO_BASE +
-                               OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
 static struct platform_device ams_delta_nand_device = {
        .name   = "ams-delta-nand",
        .id     = -1,
-       .num_resources  = ARRAY_SIZE(ams_delta_nand_resources),
-       .resource       = ams_delta_nand_resources,
 };
 
-#define OMAP_GPIO_LABEL        "gpio-0-15"
+#define OMAP_GPIO_LABEL                "gpio-0-15"
+#define OMAP_MPUIO_LABEL       "mpuio"
 
 static struct gpiod_lookup_table ams_delta_nand_gpio_table = {
        .table = {
@@ -324,6 +314,14 @@ static struct gpiod_lookup_table ams_delta_nand_gpio_table = {
                GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NWE, "nwe", 0),
                GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_ALE, "ale", 0),
                GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_CLE, "cle", 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 0, "data", 0, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 1, "data", 1, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 2, "data", 2, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 3, "data", 3, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 4, "data", 4, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 5, "data", 5, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 6, "data", 6, 0),
+               GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 7, "data", 7, 0),
                { },
        },
 };
index 01377c292db43f6e48e7d3f4098140c7bf5cea7f..899c60fac15938c1c2d839280ab8abd3de3672c5 100644 (file)
@@ -24,7 +24,7 @@ obj-$(CONFIG_SOC_OMAP5)        += $(hwmod-common) $(secure-common)
 obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
 obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
 
-ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
 obj-y += mcbsp.o
 endif
 
index 9fec5f84bf772c8d7105c30cb2e0ae3d2cd85576..8a5b6ed4ec3602a92707d86cdabf5e8dae01d612 100644 (file)
@@ -524,7 +524,7 @@ void omap_auxdata_legacy_init(struct device *dev)
        dev->platform_data = &twl_gpio_auxdata;
 }
 
-#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
+#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
 static struct omap_mcbsp_platform_data mcbsp_pdata;
 static void __init omap3_mcbsp_init(void)
 {
@@ -572,7 +572,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
        OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
                       &am35xx_emac_pdata),
        /* McBSP modules with sidetone core */
-#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
+#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
        OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
        OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata),
 #endif
index 5aa472892465ad377f46eff786890bde573addb6..76c4855a03bce23b21a4f178e1a562c1e3511cc6 100644 (file)
@@ -194,8 +194,8 @@ static struct wm8994_pdata wm8994_pdata = {
                0x3,          /* IRQ out, active high, CMOS */
        },
        .ldo = {
-                { .enable = S3C64XX_GPN(6), .init_data = &wm8994_ldo1, },
-                { .enable = S3C64XX_GPN(4), .init_data = &wm8994_ldo2, },
+                { .init_data = &wm8994_ldo1, },
+                { .init_data = &wm8994_ldo2, },
        },
 };
 
@@ -203,6 +203,18 @@ static const struct i2c_board_info wm1277_devs[] = {
        { I2C_BOARD_INFO("wm8958", 0x1a),  /* WM8958 is the superset */
          .platform_data = &wm8994_pdata,
          .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
+         .dev_name = "wm8958",
+       },
+};
+
+static struct gpiod_lookup_table wm8994_gpiod_table = {
+       .dev_id = "i2c-wm8958", /* I2C device name */
+       .table = {
+               GPIO_LOOKUP("GPION", 6,
+                           "wlf,ldo1ena", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPION", 4,
+                           "wlf,ldo2ena", GPIO_ACTIVE_HIGH),
+               { },
        },
 };
 
@@ -381,6 +393,7 @@ static int wlf_gf_module_probe(struct i2c_client *i2c,
 
        gpiod_add_lookup_table(&wm5102_reva_gpiod_table);
        gpiod_add_lookup_table(&wm5102_gpiod_table);
+       gpiod_add_lookup_table(&wm8994_gpiod_table);
 
        if (i < ARRAY_SIZE(gf_mods)) {
                dev_info(&i2c->dev, "%s revision %d\n",
index ea2ab0330e3a14f67deabada3b8903cca6fcea3b..bcb6262044d80d242c1e0add584b1404797dabb3 100644 (file)
@@ -5,7 +5,7 @@ config ARM64
        select ACPI_GTDT if ACPI
        select ACPI_IORT if ACPI
        select ACPI_REDUCED_HARDWARE_ONLY if ACPI
-       select ACPI_MCFG if ACPI
+       select ACPI_MCFG if (ACPI && PCI)
        select ACPI_SPCR_TABLE if ACPI
        select ACPI_PPTT if ACPI
        select ARCH_CLOCKSOURCE_DATA
@@ -163,7 +163,7 @@ config ARM64
        select OF
        select OF_EARLY_FLATTREE
        select OF_RESERVED_MEM
-       select PCI_ECAM if ACPI
+       select PCI_ECAM if (ACPI && PCI)
        select POWER_RESET
        select POWER_SUPPLY
        select REFCOUNT_FULL
index a1a3eaeaf58c960df8e406dca1fcdf0e434470a2..ad0195cbe04255eada56bc8cff364086dc38642e 100644 (file)
@@ -164,8 +164,6 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record)
                                        be32_to_cpu(m->addr);
                                m68k_memory[m68k_num_memory].size =
                                        be32_to_cpu(m->size);
-                               memblock_add(m68k_memory[m68k_num_memory].addr,
-                                            m68k_memory[m68k_num_memory].size);
                                m68k_num_memory++;
                        } else
                                pr_warn("%s: too many memory chunks\n",
index 7497cf30bf1cd41b51afd915a45b5b80fd9dd939..3f3d0bf360910c0d45095a0ef51db604afe5b02b 100644 (file)
@@ -228,6 +228,7 @@ void __init paging_init(void)
 
        min_addr = m68k_memory[0].addr;
        max_addr = min_addr + m68k_memory[0].size;
+       memblock_add(m68k_memory[0].addr, m68k_memory[0].size);
        for (i = 1; i < m68k_num_memory;) {
                if (m68k_memory[i].addr < min_addr) {
                        printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n",
@@ -238,6 +239,7 @@ void __init paging_init(void)
                                (m68k_num_memory - i) * sizeof(struct m68k_mem_info));
                        continue;
                }
+               memblock_add(m68k_memory[i].addr, m68k_memory[i].size);
                addr = m68k_memory[i].addr + m68k_memory[i].size;
                if (addr > max_addr)
                        max_addr = addr;
index 13664c377196441096f3a09b6de1d6eac9f410ec..3fd238e54af9cd89c4ace53c89776b554581c130 100644 (file)
@@ -310,25 +310,24 @@ void __init setup_arch(char **cmdline_p)
 
        register_console(&prom_early_console);
 
-       printk("ARCH: ");
        switch(sparc_cpu_model) {
        case sun4m:
-               printk("SUN4M\n");
+               pr_info("ARCH: SUN4M\n");
                break;
        case sun4d:
-               printk("SUN4D\n");
+               pr_info("ARCH: SUN4D\n");
                break;
        case sun4e:
-               printk("SUN4E\n");
+               pr_info("ARCH: SUN4E\n");
                break;
        case sun4u:
-               printk("SUN4U\n");
+               pr_info("ARCH: SUN4U\n");
                break;
        case sparc_leon:
-               printk("LEON\n");
+               pr_info("ARCH: LEON\n");
                break;
        default:
-               printk("UNKNOWN!\n");
+               pr_info("ARCH: UNKNOWN!\n");
                break;
        }
 
index cd2825cb84207c16b3cf82870a25877a5793ffee..ecc788aa07bdec63554295cfc3e957b3c524c17b 100644 (file)
@@ -642,9 +642,9 @@ void __init setup_arch(char **cmdline_p)
                register_console(&prom_early_console);
 
        if (tlb_type == hypervisor)
-               printk("ARCH: SUN4V\n");
+               pr_info("ARCH: SUN4V\n");
        else
-               printk("ARCH: SUN4U\n");
+               pr_info("ARCH: SUN4U\n");
 
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
index a6e18ca4cc18ce25fe87135b3034588c25fbee36..74e97f77e23b2b9bc439c997ef0a4f1e8ff54efa 100644 (file)
@@ -34,7 +34,7 @@ targets += $(vdso_img_sodbg) $(vdso_img-y:%=vdso%.so)
 CPPFLAGS_vdso.lds += -P -C
 
 VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 --no-undefined \
-                       -z max-page-size=8192 -z common-page-size=8192
+                       -z max-page-size=8192
 
 $(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE
        $(call if_changed,vdso)
index 75ef499a66e2b81c82fb6abb9bb4bd9a64521e73..85a66c4a8b652b2568473a3384785364495846ab 100644 (file)
@@ -232,13 +232,6 @@ archscripts: scripts_basic
 archheaders:
        $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all
 
-archmacros:
-       $(Q)$(MAKE) $(build)=arch/x86/kernel arch/x86/kernel/macros.s
-
-ASM_MACRO_FLAGS = -Wa,arch/x86/kernel/macros.s
-export ASM_MACRO_FLAGS
-KBUILD_CFLAGS += $(ASM_MACRO_FLAGS)
-
 ###
 # Kernel objects
 
index 25e5a6bda8c3a971609dff93919ccab27d6a3aa9..20d0885b00fbec4c77dfee23c701ba0c3612890b 100644 (file)
@@ -352,7 +352,7 @@ For 32-bit we have the following conventions - kernel is built with
 .macro CALL_enter_from_user_mode
 #ifdef CONFIG_CONTEXT_TRACKING
 #ifdef HAVE_JUMP_LABEL
-       STATIC_BRANCH_JMP l_yes=.Lafter_call_\@, key=context_tracking_enabled, branch=1
+       STATIC_JUMP_IF_FALSE .Lafter_call_\@, context_tracking_enabled, def=0
 #endif
        call enter_from_user_mode
 .Lafter_call_\@:
index 0624bf2266fd76d2852ce005acb2f9d67dbe6b8f..5bfe2243a08f882c4ab622cd87799ac1a28ff3c2 100644 (file)
@@ -171,7 +171,8 @@ quiet_cmd_vdso = VDSO    $@
                 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
 VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \
-       $(call ld-option, --build-id) -Bsymbolic
+       $(call ld-option, --build-id) $(call ld-option, --eh-frame-hdr) \
+       -Bsymbolic
 GCOV_PROFILE := n
 
 #
index 8e4ea39e55d071de447bb1c1336dce2ec314ad5e..31b627b43a8e01933d6209e746f4c08912d0cdef 100644 (file)
@@ -7,24 +7,16 @@
 #include <asm/asm.h>
 
 #ifdef CONFIG_SMP
-.macro LOCK_PREFIX_HERE
+       .macro LOCK_PREFIX
+672:   lock
        .pushsection .smp_locks,"a"
        .balign 4
-       .long 671f - .          # offset
+       .long 672b - .
        .popsection
-671:
-.endm
-
-.macro LOCK_PREFIX insn:vararg
-       LOCK_PREFIX_HERE
-       lock \insn
-.endm
+       .endm
 #else
-.macro LOCK_PREFIX_HERE
-.endm
-
-.macro LOCK_PREFIX insn:vararg
-.endm
+       .macro LOCK_PREFIX
+       .endm
 #endif
 
 /*
index d7faa16622d81d39ff11d703fad17ed7931cce86..4cd6a3b71824293ae3edb664bc5ed6e48ca5a459 100644 (file)
  */
 
 #ifdef CONFIG_SMP
-#define LOCK_PREFIX_HERE "LOCK_PREFIX_HERE\n\t"
-#define LOCK_PREFIX "LOCK_PREFIX "
+#define LOCK_PREFIX_HERE \
+               ".pushsection .smp_locks,\"a\"\n"       \
+               ".balign 4\n"                           \
+               ".long 671f - .\n" /* offset */         \
+               ".popsection\n"                         \
+               "671:"
+
+#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
+
 #else /* ! CONFIG_SMP */
 #define LOCK_PREFIX_HERE ""
 #define LOCK_PREFIX ""
index 21b086786404baff684ef450bd13aad5abd181ec..6467757bb39f6b6622c0121fe40f9f6fbcfd0b39 100644 (file)
 /* Exception table entry */
 #ifdef __ASSEMBLY__
 # define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
-       ASM_EXTABLE_HANDLE from to handler
-
-.macro ASM_EXTABLE_HANDLE from:req to:req handler:req
-       .pushsection "__ex_table","a"
-       .balign 4
-       .long (\from) - .
-       .long (\to) - .
-       .long (\handler) - .
+       .pushsection "__ex_table","a" ;                         \
+       .balign 4 ;                                             \
+       .long (from) - . ;                                      \
+       .long (to) - . ;                                        \
+       .long (handler) - . ;                                   \
        .popsection
-.endm
-#else /* __ASSEMBLY__ */
-
-# define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
-       "ASM_EXTABLE_HANDLE from=" #from " to=" #to             \
-       " handler=\"" #handler "\"\n\t"
-
-/* For C file, we already have NOKPROBE_SYMBOL macro */
-
-#endif /* __ASSEMBLY__ */
 
 # define _ASM_EXTABLE(from, to)                                        \
        _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
        _ASM_PTR (entry);                                       \
        .popsection
 
-#ifdef __ASSEMBLY__
 .macro ALIGN_DESTINATION
        /* check for bad alignment of destination */
        movl %edi,%ecx
        _ASM_EXTABLE_UA(100b, 103b)
        _ASM_EXTABLE_UA(101b, 103b)
        .endm
-#endif /* __ASSEMBLY__ */
+
+#else
+# define _EXPAND_EXTABLE_HANDLE(x) #x
+# define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
+       " .pushsection \"__ex_table\",\"a\"\n"                  \
+       " .balign 4\n"                                          \
+       " .long (" #from ") - .\n"                              \
+       " .long (" #to ") - .\n"                                \
+       " .long (" _EXPAND_EXTABLE_HANDLE(handler) ") - .\n"    \
+       " .popsection\n"
+
+# define _ASM_EXTABLE(from, to)                                        \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
+
+# define _ASM_EXTABLE_UA(from, to)                             \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
+
+# define _ASM_EXTABLE_FAULT(from, to)                          \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
+
+# define _ASM_EXTABLE_EX(from, to)                             \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
+
+# define _ASM_EXTABLE_REFCOUNT(from, to)                       \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount)
+
+/* For C file, we already have NOKPROBE_SYMBOL macro */
+#endif
 
 #ifndef __ASSEMBLY__
 /*
index 5090035e6d160fed62820f4eb40a363bb6dff763..6804d66427673ec314659944e65052b5dfba273e 100644 (file)
@@ -4,8 +4,6 @@
 
 #include <linux/stringify.h>
 
-#ifndef __ASSEMBLY__
-
 /*
  * Despite that some emulators terminate on UD2, we use it for WARN().
  *
 
 #define LEN_UD2                2
 
+#ifdef CONFIG_GENERIC_BUG
+
+#ifdef CONFIG_X86_32
+# define __BUG_REL(val)        ".long " __stringify(val)
+#else
+# define __BUG_REL(val)        ".long " __stringify(val) " - 2b"
+#endif
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define _BUG_FLAGS(ins, flags)                                         \
+do {                                                                   \
+       asm volatile("1:\t" ins "\n"                                    \
+                    ".pushsection __bug_table,\"aw\"\n"                \
+                    "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
+                    "\t"  __BUG_REL(%c0) "\t# bug_entry::file\n"       \
+                    "\t.word %c1"        "\t# bug_entry::line\n"       \
+                    "\t.word %c2"        "\t# bug_entry::flags\n"      \
+                    "\t.org 2b+%c3\n"                                  \
+                    ".popsection"                                      \
+                    : : "i" (__FILE__), "i" (__LINE__),                \
+                        "i" (flags),                                   \
+                        "i" (sizeof(struct bug_entry)));               \
+} while (0)
+
+#else /* !CONFIG_DEBUG_BUGVERBOSE */
+
 #define _BUG_FLAGS(ins, flags)                                         \
 do {                                                                   \
-       asm volatile("ASM_BUG ins=\"" ins "\" file=%c0 line=%c1 "       \
-                    "flags=%c2 size=%c3"                               \
-                    : : "i" (__FILE__), "i" (__LINE__),                \
-                        "i" (flags),                                   \
+       asm volatile("1:\t" ins "\n"                                    \
+                    ".pushsection __bug_table,\"aw\"\n"                \
+                    "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
+                    "\t.word %c0"        "\t# bug_entry::flags\n"      \
+                    "\t.org 2b+%c1\n"                                  \
+                    ".popsection"                                      \
+                    : : "i" (flags),                                   \
                         "i" (sizeof(struct bug_entry)));               \
 } while (0)
 
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
+#else
+
+#define _BUG_FLAGS(ins, flags)  asm volatile(ins)
+
+#endif /* CONFIG_GENERIC_BUG */
+
 #define HAVE_ARCH_BUG
 #define BUG()                                                  \
 do {                                                           \
@@ -46,54 +82,4 @@ do {                                                         \
 
 #include <asm-generic/bug.h>
 
-#else /* __ASSEMBLY__ */
-
-#ifdef CONFIG_GENERIC_BUG
-
-#ifdef CONFIG_X86_32
-.macro __BUG_REL val:req
-       .long \val
-.endm
-#else
-.macro __BUG_REL val:req
-       .long \val - 2b
-.endm
-#endif
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-
-.macro ASM_BUG ins:req file:req line:req flags:req size:req
-1:     \ins
-       .pushsection __bug_table,"aw"
-2:     __BUG_REL val=1b        # bug_entry::bug_addr
-       __BUG_REL val=\file     # bug_entry::file
-       .word \line             # bug_entry::line
-       .word \flags            # bug_entry::flags
-       .org 2b+\size
-       .popsection
-.endm
-
-#else /* !CONFIG_DEBUG_BUGVERBOSE */
-
-.macro ASM_BUG ins:req file:req line:req flags:req size:req
-1:     \ins
-       .pushsection __bug_table,"aw"
-2:     __BUG_REL val=1b        # bug_entry::bug_addr
-       .word \flags            # bug_entry::flags
-       .org 2b+\size
-       .popsection
-.endm
-
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
-
-#else /* CONFIG_GENERIC_BUG */
-
-.macro ASM_BUG ins:req file:req line:req flags:req size:req
-       \ins
-.endm
-
-#endif /* CONFIG_GENERIC_BUG */
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* _ASM_X86_BUG_H */
index 7d442722ef241b684c348dc47b6be916d4728a3d..aced6c9290d6f96cdaf4eaadab3dd3835d80b94a 100644 (file)
@@ -2,10 +2,10 @@
 #ifndef _ASM_X86_CPUFEATURE_H
 #define _ASM_X86_CPUFEATURE_H
 
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
 #include <asm/processor.h>
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+
 #include <asm/asm.h>
 #include <linux/bitops.h>
 
@@ -161,10 +161,37 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
  */
 static __always_inline __pure bool _static_cpu_has(u16 bit)
 {
-       asm_volatile_goto("STATIC_CPU_HAS bitnum=%[bitnum] "
-                         "cap_byte=\"%[cap_byte]\" "
-                         "feature=%P[feature] t_yes=%l[t_yes] "
-                         "t_no=%l[t_no] always=%P[always]"
+       asm_volatile_goto("1: jmp 6f\n"
+                "2:\n"
+                ".skip -(((5f-4f) - (2b-1b)) > 0) * "
+                        "((5f-4f) - (2b-1b)),0x90\n"
+                "3:\n"
+                ".section .altinstructions,\"a\"\n"
+                " .long 1b - .\n"              /* src offset */
+                " .long 4f - .\n"              /* repl offset */
+                " .word %P[always]\n"          /* always replace */
+                " .byte 3b - 1b\n"             /* src len */
+                " .byte 5f - 4f\n"             /* repl len */
+                " .byte 3b - 2b\n"             /* pad len */
+                ".previous\n"
+                ".section .altinstr_replacement,\"ax\"\n"
+                "4: jmp %l[t_no]\n"
+                "5:\n"
+                ".previous\n"
+                ".section .altinstructions,\"a\"\n"
+                " .long 1b - .\n"              /* src offset */
+                " .long 0\n"                   /* no replacement */
+                " .word %P[feature]\n"         /* feature bit */
+                " .byte 3b - 1b\n"             /* src len */
+                " .byte 0\n"                   /* repl len */
+                " .byte 0\n"                   /* pad len */
+                ".previous\n"
+                ".section .altinstr_aux,\"ax\"\n"
+                "6:\n"
+                " testb %[bitnum],%[cap_byte]\n"
+                " jnz %l[t_yes]\n"
+                " jmp %l[t_no]\n"
+                ".previous\n"
                 : : [feature]  "i" (bit),
                     [always]   "i" (X86_FEATURE_ALWAYS),
                     [bitnum]   "i" (1 << (bit & 7)),
@@ -199,44 +226,5 @@ t_no:
 #define CPU_FEATURE_TYPEVAL            boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
                                        boot_cpu_data.x86_model
 
-#else /* __ASSEMBLY__ */
-
-.macro STATIC_CPU_HAS bitnum:req cap_byte:req feature:req t_yes:req t_no:req always:req
-1:
-       jmp 6f
-2:
-       .skip -(((5f-4f) - (2b-1b)) > 0) * ((5f-4f) - (2b-1b)),0x90
-3:
-       .section .altinstructions,"a"
-       .long 1b - .            /* src offset */
-       .long 4f - .            /* repl offset */
-       .word \always           /* always replace */
-       .byte 3b - 1b           /* src len */
-       .byte 5f - 4f           /* repl len */
-       .byte 3b - 2b           /* pad len */
-       .previous
-       .section .altinstr_replacement,"ax"
-4:
-       jmp \t_no
-5:
-       .previous
-       .section .altinstructions,"a"
-       .long 1b - .            /* src offset */
-       .long 0                 /* no replacement */
-       .word \feature          /* feature bit */
-       .byte 3b - 1b           /* src len */
-       .byte 0                 /* repl len */
-       .byte 0                 /* pad len */
-       .previous
-       .section .altinstr_aux,"ax"
-6:
-       testb \bitnum,\cap_byte
-       jnz \t_yes
-       jmp \t_no
-       .previous
-.endm
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
+#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
 #endif /* _ASM_X86_CPUFEATURE_H */
index eb377b6e9eedee2e311bb13c1616e0ecbe7af350..bca4c743de77c6d80f21f1bb4aeb0e2a188d824b 100644 (file)
@@ -16,8 +16,8 @@
  */
 extern unsigned long x86_fsbase_read_task(struct task_struct *task);
 extern unsigned long x86_gsbase_read_task(struct task_struct *task);
-extern int x86_fsbase_write_task(struct task_struct *task, unsigned long fsbase);
-extern int x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase);
+extern void x86_fsbase_write_task(struct task_struct *task, unsigned long fsbase);
+extern void x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase);
 
 /* Helper functions for reading/writing FS/GS base */
 
@@ -39,8 +39,15 @@ static inline unsigned long x86_gsbase_read_cpu_inactive(void)
        return gsbase;
 }
 
-extern void x86_fsbase_write_cpu(unsigned long fsbase);
-extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase);
+static inline void x86_fsbase_write_cpu(unsigned long fsbase)
+{
+       wrmsrl(MSR_FS_BASE, fsbase);
+}
+
+static inline void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
+{
+       wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
+}
 
 #endif /* CONFIG_X86_64 */
 
index a5fb34fe56a4bb31f78023ff3d258132ff93ee16..21efc9d07ed909adfc37b06188b331ea0e6f747d 100644 (file)
@@ -2,6 +2,19 @@
 #ifndef _ASM_X86_JUMP_LABEL_H
 #define _ASM_X86_JUMP_LABEL_H
 
+#ifndef HAVE_JUMP_LABEL
+/*
+ * For better or for worse, if jump labels (the gcc extension) are missing,
+ * then the entire static branch patching infrastructure is compiled out.
+ * If that happens, the code in here will malfunction.  Raise a compiler
+ * error instead.
+ *
+ * In theory, jump labels and the static branch patching infrastructure
+ * could be decoupled to fix this.
+ */
+#error asm/jump_label.h included on a non-jump-label kernel
+#endif
+
 #define JUMP_LABEL_NOP_SIZE 5
 
 #ifdef CONFIG_X86_64
 
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
-       asm_volatile_goto("STATIC_BRANCH_NOP l_yes=\"%l[l_yes]\" key=\"%c0\" "
-                         "branch=\"%c1\""
-                       : :  "i" (key), "i" (branch) : : l_yes);
+       asm_volatile_goto("1:"
+               ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
+               ".pushsection __jump_table,  \"aw\" \n\t"
+               _ASM_ALIGN "\n\t"
+               ".long 1b - ., %l[l_yes] - . \n\t"
+               _ASM_PTR "%c0 + %c1 - .\n\t"
+               ".popsection \n\t"
+               : :  "i" (key), "i" (branch) : : l_yes);
+
        return false;
 l_yes:
        return true;
@@ -30,8 +49,14 @@ l_yes:
 
 static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
 {
-       asm_volatile_goto("STATIC_BRANCH_JMP l_yes=\"%l[l_yes]\" key=\"%c0\" "
-                         "branch=\"%c1\""
+       asm_volatile_goto("1:"
+               ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t"
+               "2:\n\t"
+               ".pushsection __jump_table,  \"aw\" \n\t"
+               _ASM_ALIGN "\n\t"
+               ".long 1b - ., %l[l_yes] - . \n\t"
+               _ASM_PTR "%c0 + %c1 - .\n\t"
+               ".popsection \n\t"
                : :  "i" (key), "i" (branch) : : l_yes);
 
        return false;
@@ -41,26 +66,37 @@ l_yes:
 
 #else  /* __ASSEMBLY__ */
 
-.macro STATIC_BRANCH_NOP l_yes:req key:req branch:req
-.Lstatic_branch_nop_\@:
-       .byte STATIC_KEY_INIT_NOP
-.Lstatic_branch_no_after_\@:
+.macro STATIC_JUMP_IF_TRUE target, key, def
+.Lstatic_jump_\@:
+       .if \def
+       /* Equivalent to "jmp.d32 \target" */
+       .byte           0xe9
+       .long           \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+       .else
+       .byte           STATIC_KEY_INIT_NOP
+       .endif
        .pushsection __jump_table, "aw"
        _ASM_ALIGN
-       .long           .Lstatic_branch_nop_\@ - ., \l_yes - .
-       _ASM_PTR        \key + \branch - .
+       .long           .Lstatic_jump_\@ - ., \target - .
+       _ASM_PTR        \key - .
        .popsection
 .endm
 
-.macro STATIC_BRANCH_JMP l_yes:req key:req branch:req
-.Lstatic_branch_jmp_\@:
-       .byte 0xe9
-       .long \l_yes - .Lstatic_branch_jmp_after_\@
-.Lstatic_branch_jmp_after_\@:
+.macro STATIC_JUMP_IF_FALSE target, key, def
+.Lstatic_jump_\@:
+       .if \def
+       .byte           STATIC_KEY_INIT_NOP
+       .else
+       /* Equivalent to "jmp.d32 \target" */
+       .byte           0xe9
+       .long           \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+       .endif
        .pushsection __jump_table, "aw"
        _ASM_ALIGN
-       .long           .Lstatic_branch_jmp_\@ - ., \l_yes - .
-       _ASM_PTR        \key + \branch - .
+       .long           .Lstatic_jump_\@ - ., \target - .
+       _ASM_PTR        \key + 1 - .
        .popsection
 .endm
 
index c8f73efb4eceb82391bf908f1f8f292586be5925..9e39cc8bd989855cc2ca8c349c335fe36d029b37 100644 (file)
 #define MSR_F15H_NB_PERF_CTR           0xc0010241
 #define MSR_F15H_PTSC                  0xc0010280
 #define MSR_F15H_IC_CFG                        0xc0011021
+#define MSR_F15H_EX_CFG                        0xc001102c
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE      0xc0010058
index 26942ad63830407255afc9e6de77267056a97135..488c59686a733cc8ad627f7150a7d4aab72507b9 100644 (file)
@@ -348,11 +348,23 @@ extern struct paravirt_patch_template pv_ops;
 #define paravirt_clobber(clobber)              \
        [paravirt_clobber] "i" (clobber)
 
+/*
+ * Generate some code, and mark it as patchable by the
+ * apply_paravirt() alternate instruction patcher.
+ */
+#define _paravirt_alt(insn_string, type, clobber)      \
+       "771:\n\t" insn_string "\n" "772:\n"            \
+       ".pushsection .parainstructions,\"a\"\n"        \
+       _ASM_ALIGN "\n"                                 \
+       _ASM_PTR " 771b\n"                              \
+       "  .byte " type "\n"                            \
+       "  .byte 772b-771b\n"                           \
+       "  .short " clobber "\n"                        \
+       ".popsection\n"
+
 /* Generate patchable code, with the default asm parameters. */
-#define paravirt_call                                                  \
-       "PARAVIRT_CALL type=\"%c[paravirt_typenum]\""                   \
-       " clobber=\"%c[paravirt_clobber]\""                             \
-       " pv_opptr=\"%c[paravirt_opptr]\";"
+#define paravirt_alt(insn_string)                                      \
+       _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
 
 /* Simple instruction patching code. */
 #define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t"
@@ -372,6 +384,16 @@ unsigned native_patch(u8 type, void *ibuf, unsigned long addr, unsigned len);
 
 int paravirt_disable_iospace(void);
 
+/*
+ * This generates an indirect call based on the operation type number.
+ * The type number, computed in PARAVIRT_PATCH, is derived from the
+ * offset into the paravirt_patch_template structure, and can therefore be
+ * freely converted back into a structure offset.
+ */
+#define PARAVIRT_CALL                                  \
+       ANNOTATE_RETPOLINE_SAFE                         \
+       "call *%c[paravirt_opptr];"
+
 /*
  * These macros are intended to wrap calls through one of the paravirt
  * ops structs, so that they can be later identified and patched at
@@ -509,7 +531,7 @@ int paravirt_disable_iospace(void);
                /* since this condition will never hold */              \
                if (sizeof(rettype) > sizeof(unsigned long)) {          \
                        asm volatile(pre                                \
-                                    paravirt_call                      \
+                                    paravirt_alt(PARAVIRT_CALL)        \
                                     post                               \
                                     : call_clbr, ASM_CALL_CONSTRAINT   \
                                     : paravirt_type(op),               \
@@ -519,7 +541,7 @@ int paravirt_disable_iospace(void);
                        __ret = (rettype)((((u64)__edx) << 32) | __eax); \
                } else {                                                \
                        asm volatile(pre                                \
-                                    paravirt_call                      \
+                                    paravirt_alt(PARAVIRT_CALL)        \
                                     post                               \
                                     : call_clbr, ASM_CALL_CONSTRAINT   \
                                     : paravirt_type(op),               \
@@ -546,7 +568,7 @@ int paravirt_disable_iospace(void);
                PVOP_VCALL_ARGS;                                        \
                PVOP_TEST_NULL(op);                                     \
                asm volatile(pre                                        \
-                            paravirt_call                              \
+                            paravirt_alt(PARAVIRT_CALL)                \
                             post                                       \
                             : call_clbr, ASM_CALL_CONSTRAINT           \
                             : paravirt_type(op),                       \
@@ -664,26 +686,6 @@ struct paravirt_patch_site {
 extern struct paravirt_patch_site __parainstructions[],
        __parainstructions_end[];
 
-#else  /* __ASSEMBLY__ */
-
-/*
- * This generates an indirect call based on the operation type number.
- * The type number, computed in PARAVIRT_PATCH, is derived from the
- * offset into the paravirt_patch_template structure, and can therefore be
- * freely converted back into a structure offset.
- */
-.macro PARAVIRT_CALL type:req clobber:req pv_opptr:req
-771:   ANNOTATE_RETPOLINE_SAFE
-       call *\pv_opptr
-772:   .pushsection .parainstructions,"a"
-       _ASM_ALIGN
-       _ASM_PTR 771b
-       .byte \type
-       .byte 772b-771b
-       .short \clobber
-       .popsection
-.endm
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_X86_PARAVIRT_TYPES_H */
index 959d618dbb1707fcdda5bd8c17c6082c498a9046..73bb404f4d2a23c2e1e01afdc30a132553672b04 100644 (file)
@@ -121,7 +121,14 @@ extern void __init dmi_check_pciprobe(void);
 extern void __init dmi_check_skip_isa_align(void);
 
 /* some common used subsys_initcalls */
+#ifdef CONFIG_PCI
 extern int __init pci_acpi_init(void);
+#else
+static inline int  __init pci_acpi_init(void)
+{
+       return -EINVAL;
+}
+#endif
 extern void __init pcibios_irq_init(void);
 extern int __init pcibios_init(void);
 extern int pci_legacy_init(void);
index 84bd9bdc1987faa634cd1daad7dbfe94d586a82b..88bca456da994c5b2a76f7046bf12f4f2615361d 100644 (file)
@@ -111,6 +111,11 @@ extern unsigned int ptrs_per_p4d;
  */
 #define MAXMEM                 (1UL << MAX_PHYSMEM_BITS)
 
+#define GUARD_HOLE_PGD_ENTRY   -256UL
+#define GUARD_HOLE_SIZE                (16UL << PGDIR_SHIFT)
+#define GUARD_HOLE_BASE_ADDR   (GUARD_HOLE_PGD_ENTRY << PGDIR_SHIFT)
+#define GUARD_HOLE_END_ADDR    (GUARD_HOLE_BASE_ADDR + GUARD_HOLE_SIZE)
+
 #define LDT_PGD_ENTRY          -240UL
 #define LDT_BASE_ADDR          (LDT_PGD_ENTRY << PGDIR_SHIFT)
 #define LDT_END_ADDR           (LDT_BASE_ADDR + PGDIR_SIZE)
index a8b5e1e133190ff1b8acf6d38795485d11fd061d..dbaed55c1c2442263624aeea5c1faa5afeefba26 100644 (file)
@@ -4,41 +4,6 @@
  * x86-specific implementation of refcount_t. Based on PAX_REFCOUNT from
  * PaX/grsecurity.
  */
-
-#ifdef __ASSEMBLY__
-
-#include <asm/asm.h>
-#include <asm/bug.h>
-
-.macro REFCOUNT_EXCEPTION counter:req
-       .pushsection .text..refcount
-111:   lea \counter, %_ASM_CX
-112:   ud2
-       ASM_UNREACHABLE
-       .popsection
-113:   _ASM_EXTABLE_REFCOUNT(112b, 113b)
-.endm
-
-/* Trigger refcount exception if refcount result is negative. */
-.macro REFCOUNT_CHECK_LT_ZERO counter:req
-       js 111f
-       REFCOUNT_EXCEPTION counter="\counter"
-.endm
-
-/* Trigger refcount exception if refcount result is zero or negative. */
-.macro REFCOUNT_CHECK_LE_ZERO counter:req
-       jz 111f
-       REFCOUNT_CHECK_LT_ZERO counter="\counter"
-.endm
-
-/* Trigger refcount exception unconditionally. */
-.macro REFCOUNT_ERROR counter:req
-       jmp 111f
-       REFCOUNT_EXCEPTION counter="\counter"
-.endm
-
-#else /* __ASSEMBLY__ */
-
 #include <linux/refcount.h>
 #include <asm/bug.h>
 
  * central refcount exception. The fixup address for the exception points
  * back to the regular execution flow in .text.
  */
+#define _REFCOUNT_EXCEPTION                            \
+       ".pushsection .text..refcount\n"                \
+       "111:\tlea %[var], %%" _ASM_CX "\n"             \
+       "112:\t" ASM_UD2 "\n"                           \
+       ASM_UNREACHABLE                                 \
+       ".popsection\n"                                 \
+       "113:\n"                                        \
+       _ASM_EXTABLE_REFCOUNT(112b, 113b)
+
+/* Trigger refcount exception if refcount result is negative. */
+#define REFCOUNT_CHECK_LT_ZERO                         \
+       "js 111f\n\t"                                   \
+       _REFCOUNT_EXCEPTION
+
+/* Trigger refcount exception if refcount result is zero or negative. */
+#define REFCOUNT_CHECK_LE_ZERO                         \
+       "jz 111f\n\t"                                   \
+       REFCOUNT_CHECK_LT_ZERO
+
+/* Trigger refcount exception unconditionally. */
+#define REFCOUNT_ERROR                                 \
+       "jmp 111f\n\t"                                  \
+       _REFCOUNT_EXCEPTION
 
 static __always_inline void refcount_add(unsigned int i, refcount_t *r)
 {
        asm volatile(LOCK_PREFIX "addl %1,%0\n\t"
-               "REFCOUNT_CHECK_LT_ZERO counter=\"%[counter]\""
-               : [counter] "+m" (r->refs.counter)
+               REFCOUNT_CHECK_LT_ZERO
+               : [var] "+m" (r->refs.counter)
                : "ir" (i)
                : "cc", "cx");
 }
@@ -63,32 +51,31 @@ static __always_inline void refcount_add(unsigned int i, refcount_t *r)
 static __always_inline void refcount_inc(refcount_t *r)
 {
        asm volatile(LOCK_PREFIX "incl %0\n\t"
-               "REFCOUNT_CHECK_LT_ZERO counter=\"%[counter]\""
-               : [counter] "+m" (r->refs.counter)
+               REFCOUNT_CHECK_LT_ZERO
+               : [var] "+m" (r->refs.counter)
                : : "cc", "cx");
 }
 
 static __always_inline void refcount_dec(refcount_t *r)
 {
        asm volatile(LOCK_PREFIX "decl %0\n\t"
-               "REFCOUNT_CHECK_LE_ZERO counter=\"%[counter]\""
-               : [counter] "+m" (r->refs.counter)
+               REFCOUNT_CHECK_LE_ZERO
+               : [var] "+m" (r->refs.counter)
                : : "cc", "cx");
 }
 
 static __always_inline __must_check
 bool refcount_sub_and_test(unsigned int i, refcount_t *r)
 {
-
        return GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl",
-                                        "REFCOUNT_CHECK_LT_ZERO counter=\"%[var]\"",
+                                        REFCOUNT_CHECK_LT_ZERO,
                                         r->refs.counter, e, "er", i, "cx");
 }
 
 static __always_inline __must_check bool refcount_dec_and_test(refcount_t *r)
 {
        return GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl",
-                                       "REFCOUNT_CHECK_LT_ZERO counter=\"%[var]\"",
+                                       REFCOUNT_CHECK_LT_ZERO,
                                        r->refs.counter, e, "cx");
 }
 
@@ -106,8 +93,8 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r)
 
                /* Did we try to increment from/to an undesirable state? */
                if (unlikely(c < 0 || c == INT_MAX || result < c)) {
-                       asm volatile("REFCOUNT_ERROR counter=\"%[counter]\""
-                                    : : [counter] "m" (r->refs.counter)
+                       asm volatile(REFCOUNT_ERROR
+                                    : : [var] "m" (r->refs.counter)
                                     : "cc", "cx");
                        break;
                }
@@ -122,6 +109,4 @@ static __always_inline __must_check bool refcount_inc_not_zero(refcount_t *r)
        return refcount_add_not_zero(1, r);
 }
 
-#endif /* __ASSEMBLY__ */
-
 #endif
index 27937458c231b62772bf956b1bc584fc030281ba..efa4a519f5e552eb1bb67f4ea980728310b3e0a5 100644 (file)
@@ -23,6 +23,7 @@
 
 #define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
 
+#include <linux/cpu.h>
 #include <linux/kernfs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
@@ -310,9 +311,11 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
                return -EINVAL;
        buf[nbytes - 1] = '\0';
 
+       cpus_read_lock();
        rdtgrp = rdtgroup_kn_lock_live(of->kn);
        if (!rdtgrp) {
                rdtgroup_kn_unlock(of->kn);
+               cpus_read_unlock();
                return -ENOENT;
        }
        rdt_last_cmd_clear();
@@ -367,6 +370,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
 
 out:
        rdtgroup_kn_unlock(of->kn);
+       cpus_read_unlock();
        return ret ?: nbytes;
 }
 
index 2e173d47b450d4febbb9e2028f153bc91382b915..4d36dcc1cf87c5b75bcf085df5e77d745a852070 100644 (file)
@@ -165,6 +165,8 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
        struct mtrr_gentry gentry;
        void __user *arg = (void __user *) __arg;
 
+       memset(&gentry, 0, sizeof(gentry));
+
        switch (cmd) {
        case MTRRIOC_ADD_ENTRY:
        case MTRRIOC_SET_ENTRY:
diff --git a/arch/x86/kernel/macros.S b/arch/x86/kernel/macros.S
deleted file mode 100644 (file)
index 161c950..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-/*
- * This file includes headers whose assembly part includes macros which are
- * commonly used. The macros are precompiled into assmebly file which is later
- * assembled together with each compiled file.
- */
-
-#include <linux/compiler.h>
-#include <asm/refcount.h>
-#include <asm/alternative-asm.h>
-#include <asm/bug.h>
-#include <asm/paravirt.h>
-#include <asm/asm.h>
-#include <asm/cpufeature.h>
-#include <asm/jump_label.h>
index bbfbf017065c387c76f3f7c6394f34816fb7a4f5..ddd4fa718c43d271cdcdf326ad88339bc412829d 100644 (file)
@@ -339,24 +339,6 @@ static unsigned long x86_fsgsbase_read_task(struct task_struct *task,
        return base;
 }
 
-void x86_fsbase_write_cpu(unsigned long fsbase)
-{
-       /*
-        * Set the selector to 0 as a notion, that the segment base is
-        * overwritten, which will be checked for skipping the segment load
-        * during context switch.
-        */
-       loadseg(FS, 0);
-       wrmsrl(MSR_FS_BASE, fsbase);
-}
-
-void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
-{
-       /* Set the selector to 0 for the same reason as %fs above. */
-       loadseg(GS, 0);
-       wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
-}
-
 unsigned long x86_fsbase_read_task(struct task_struct *task)
 {
        unsigned long fsbase;
@@ -385,38 +367,18 @@ unsigned long x86_gsbase_read_task(struct task_struct *task)
        return gsbase;
 }
 
-int x86_fsbase_write_task(struct task_struct *task, unsigned long fsbase)
+void x86_fsbase_write_task(struct task_struct *task, unsigned long fsbase)
 {
-       /*
-        * Not strictly needed for %fs, but do it for symmetry
-        * with %gs
-        */
-       if (unlikely(fsbase >= TASK_SIZE_MAX))
-               return -EPERM;
+       WARN_ON_ONCE(task == current);
 
-       preempt_disable();
        task->thread.fsbase = fsbase;
-       if (task == current)
-               x86_fsbase_write_cpu(fsbase);
-       task->thread.fsindex = 0;
-       preempt_enable();
-
-       return 0;
 }
 
-int x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase)
+void x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase)
 {
-       if (unlikely(gsbase >= TASK_SIZE_MAX))
-               return -EPERM;
+       WARN_ON_ONCE(task == current);
 
-       preempt_disable();
        task->thread.gsbase = gsbase;
-       if (task == current)
-               x86_gsbase_write_cpu_inactive(gsbase);
-       task->thread.gsindex = 0;
-       preempt_enable();
-
-       return 0;
 }
 
 int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
@@ -754,11 +716,60 @@ long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2)
 
        switch (option) {
        case ARCH_SET_GS: {
-               ret = x86_gsbase_write_task(task, arg2);
+               if (unlikely(arg2 >= TASK_SIZE_MAX))
+                       return -EPERM;
+
+               preempt_disable();
+               /*
+                * ARCH_SET_GS has always overwritten the index
+                * and the base. Zero is the most sensible value
+                * to put in the index, and is the only value that
+                * makes any sense if FSGSBASE is unavailable.
+                */
+               if (task == current) {
+                       loadseg(GS, 0);
+                       x86_gsbase_write_cpu_inactive(arg2);
+
+                       /*
+                        * On non-FSGSBASE systems, save_base_legacy() expects
+                        * that we also fill in thread.gsbase.
+                        */
+                       task->thread.gsbase = arg2;
+
+               } else {
+                       task->thread.gsindex = 0;
+                       x86_gsbase_write_task(task, arg2);
+               }
+               preempt_enable();
                break;
        }
        case ARCH_SET_FS: {
-               ret = x86_fsbase_write_task(task, arg2);
+               /*
+                * Not strictly needed for %fs, but do it for symmetry
+                * with %gs
+                */
+               if (unlikely(arg2 >= TASK_SIZE_MAX))
+                       return -EPERM;
+
+               preempt_disable();
+               /*
+                * Set the selector to 0 for the same reason
+                * as %gs above.
+                */
+               if (task == current) {
+                       loadseg(FS, 0);
+                       x86_fsbase_write_cpu(arg2);
+
+                       /*
+                        * On non-FSGSBASE systems, save_base_legacy() expects
+                        * that we also fill in thread.fsbase.
+                        */
+                       task->thread.fsbase = arg2;
+               } else {
+                       task->thread.fsindex = 0;
+                       x86_fsbase_write_task(task, arg2);
+               }
+               preempt_enable();
                break;
        }
        case ARCH_GET_FS: {
index ffae9b9740fdf3a53619f03c4261be6711d7e7a7..4b8ee05dd6addf89478a4f26e8b8d6be29329721 100644 (file)
@@ -397,11 +397,12 @@ static int putreg(struct task_struct *child,
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
                /*
-                * When changing the FS base, use the same
-                * mechanism as for do_arch_prctl_64().
+                * When changing the FS base, use do_arch_prctl_64()
+                * to set the index to zero and to set the base
+                * as requested.
                 */
                if (child->thread.fsbase != value)
-                       return x86_fsbase_write_task(child, value);
+                       return do_arch_prctl_64(child, ARCH_SET_FS, value);
                return 0;
        case offsetof(struct user_regs_struct,gs_base):
                /*
@@ -410,7 +411,7 @@ static int putreg(struct task_struct *child,
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
                if (child->thread.gsbase != value)
-                       return x86_gsbase_write_task(child, value);
+                       return do_arch_prctl_64(child, ARCH_SET_GS, value);
                return 0;
 #endif
        }
index cc6467b35a85f6cec9300011cfa0c464574ed5d3..101f53ccf5718d99e5c1e95927b153031114c497 100644 (file)
@@ -2937,6 +2937,8 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
 static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
 {
        WARN_ON(mmu_is_nested(vcpu));
+
+       vcpu->arch.mmu = &vcpu->arch.guest_mmu;
        kvm_init_shadow_mmu(vcpu);
        vcpu->arch.mmu->set_cr3           = nested_svm_set_tdp_cr3;
        vcpu->arch.mmu->get_cr3           = nested_svm_get_tdp_cr3;
@@ -2949,6 +2951,7 @@ static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
 
 static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
 {
+       vcpu->arch.mmu = &vcpu->arch.root_mmu;
        vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
 }
 
@@ -3458,7 +3461,6 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
                svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
 
        if (nested_vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) {
-               kvm_mmu_unload(&svm->vcpu);
                svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
                nested_svm_init_mmu_context(&svm->vcpu);
        }
index 02edd9960e9d94cf8cbac80ea1bfccc5673f3089..8d5d984541beaa111b94e59e512871f91c08a7da 100644 (file)
@@ -11985,6 +11985,8 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                        kunmap(vmx->nested.pi_desc_page);
                        kvm_release_page_dirty(vmx->nested.pi_desc_page);
                        vmx->nested.pi_desc_page = NULL;
+                       vmx->nested.pi_desc = NULL;
+                       vmcs_write64(POSTED_INTR_DESC_ADDR, -1ull);
                }
                page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->posted_intr_desc_addr);
                if (is_error_page(page))
index d02937760c3ba8adc6de37ed4b39db9a926f320d..f049ecfac7bb8a8cd7780efd9b40fbbdf8a7d089 100644 (file)
@@ -2426,6 +2426,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_AMD64_PATCH_LOADER:
        case MSR_AMD64_BU_CFG2:
        case MSR_AMD64_DC_CFG:
+       case MSR_F15H_EX_CFG:
                break;
 
        case MSR_IA32_UCODE_REV:
@@ -2721,6 +2722,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_AMD64_BU_CFG2:
        case MSR_IA32_PERF_CTL:
        case MSR_AMD64_DC_CFG:
+       case MSR_F15H_EX_CFG:
                msr_info->data = 0;
                break;
        case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5:
@@ -7446,7 +7448,7 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm)
 
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
-       if (!kvm_apic_hw_enabled(vcpu->arch.apic))
+       if (!kvm_apic_present(vcpu))
                return;
 
        bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256);
index fc37bbd23eb8b4c996cddeb1c1f6c39cc2a23f5d..abcb8d00b01486f431fc9fa591f6e6260c8e1153 100644 (file)
@@ -55,10 +55,10 @@ struct addr_marker {
 enum address_markers_idx {
        USER_SPACE_NR = 0,
        KERNEL_SPACE_NR,
-       LOW_KERNEL_NR,
-#if defined(CONFIG_MODIFY_LDT_SYSCALL) && defined(CONFIG_X86_5LEVEL)
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
        LDT_NR,
 #endif
+       LOW_KERNEL_NR,
        VMALLOC_START_NR,
        VMEMMAP_START_NR,
 #ifdef CONFIG_KASAN
@@ -66,9 +66,6 @@ enum address_markers_idx {
        KASAN_SHADOW_END_NR,
 #endif
        CPU_ENTRY_AREA_NR,
-#if defined(CONFIG_MODIFY_LDT_SYSCALL) && !defined(CONFIG_X86_5LEVEL)
-       LDT_NR,
-#endif
 #ifdef CONFIG_X86_ESPFIX64
        ESPFIX_START_NR,
 #endif
@@ -512,11 +509,11 @@ static inline bool is_hypervisor_range(int idx)
 {
 #ifdef CONFIG_X86_64
        /*
-        * ffff800000000000 - ffff87ffffffffff is reserved for
-        * the hypervisor.
+        * A hole in the beginning of kernel address space reserved
+        * for a hypervisor.
         */
-       return  (idx >= pgd_index(__PAGE_OFFSET) - 16) &&
-               (idx <  pgd_index(__PAGE_OFFSET));
+       return  (idx >= pgd_index(GUARD_HOLE_BASE_ADDR)) &&
+               (idx <  pgd_index(GUARD_HOLE_END_ADDR));
 #else
        return false;
 #endif
index db7a1008223886d398c531d8d34720cd0265d17d..a1bcde35db4cac8468a4a344094eee9daacb0f41 100644 (file)
@@ -285,20 +285,16 @@ static void cpa_flush_all(unsigned long cache)
        on_each_cpu(__cpa_flush_all, (void *) cache, 1);
 }
 
-static bool __cpa_flush_range(unsigned long start, int numpages, int cache)
+static bool __inv_flush_all(int cache)
 {
        BUG_ON(irqs_disabled() && !early_boot_irqs_disabled);
 
-       WARN_ON(PAGE_ALIGN(start) != start);
-
        if (cache && !static_cpu_has(X86_FEATURE_CLFLUSH)) {
                cpa_flush_all(cache);
                return true;
        }
 
-       flush_tlb_kernel_range(start, start + PAGE_SIZE * numpages);
-
-       return !cache;
+       return false;
 }
 
 static void cpa_flush_range(unsigned long start, int numpages, int cache)
@@ -306,7 +302,14 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
        unsigned int i, level;
        unsigned long addr;
 
-       if (__cpa_flush_range(start, numpages, cache))
+       WARN_ON(PAGE_ALIGN(start) != start);
+
+       if (__inv_flush_all(cache))
+               return;
+
+       flush_tlb_kernel_range(start, start + PAGE_SIZE * numpages);
+
+       if (!cache)
                return;
 
        /*
@@ -332,7 +335,12 @@ static void cpa_flush_array(unsigned long baddr, unsigned long *start,
 {
        unsigned int i, level;
 
-       if (__cpa_flush_range(baddr, numpages, cache))
+       if (__inv_flush_all(cache))
+               return;
+
+       flush_tlb_all();
+
+       if (!cache)
                return;
 
        /*
index 08013524fba18ebe2afc44bf798c5ad77839fa0b..4fe956a63b25b54fe479aadfeb51dfdf66ef74d2 100644 (file)
@@ -519,8 +519,13 @@ static u64 sanitize_phys(u64 address)
         * for a "decoy" virtual address (bit 63 clear) passed to
         * set_memory_X(). __pa() on a "decoy" address results in a
         * physical address with bit 63 set.
+        *
+        * Decoy addresses are not present for 32-bit builds, see
+        * set_mce_nospec().
         */
-       return address & __PHYSICAL_MASK;
+       if (IS_ENABLED(CONFIG_X86_64))
+               return address & __PHYSICAL_MASK;
+       return address;
 }
 
 /*
@@ -546,7 +551,11 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
 
        start = sanitize_phys(start);
        end = sanitize_phys(end);
-       BUG_ON(start >= end); /* end is exclusive */
+       if (start >= end) {
+               WARN(1, "%s failed: [mem %#010Lx-%#010Lx], req %s\n", __func__,
+                               start, end - 1, cattr_name(req_type));
+               return -EINVAL;
+       }
 
        if (!pat_enabled()) {
                /* This is identical to page table setting without PAT */
index a5d7ed12533707f8714e066cd4be4c30f880988d..0f4fe206dcc2015ce212b19c8865b06f854fb3b1 100644 (file)
@@ -648,19 +648,20 @@ static int __xen_pgd_walk(struct mm_struct *mm, pgd_t *pgd,
                          unsigned long limit)
 {
        int i, nr, flush = 0;
-       unsigned hole_low, hole_high;
+       unsigned hole_low = 0, hole_high = 0;
 
        /* The limit is the last byte to be touched */
        limit--;
        BUG_ON(limit >= FIXADDR_TOP);
 
+#ifdef CONFIG_X86_64
        /*
         * 64-bit has a great big hole in the middle of the address
-        * space, which contains the Xen mappings.  On 32-bit these
-        * will end up making a zero-sized hole and so is a no-op.
+        * space, which contains the Xen mappings.
         */
-       hole_low = pgd_index(USER_LIMIT);
-       hole_high = pgd_index(PAGE_OFFSET);
+       hole_low = pgd_index(GUARD_HOLE_BASE_ADDR);
+       hole_high = pgd_index(GUARD_HOLE_END_ADDR);
+#endif
 
        nr = pgd_index(limit) + 1;
        for (i = 0; i < nr; i++) {
index ab4d43923c4dd5a6860ef81d7241003ba9bcc53b..8395bc515996f18982e89bc393c4edb458997873 100644 (file)
@@ -57,6 +57,8 @@ source "drivers/char/Kconfig"
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/i3c/Kconfig"
+
 source "drivers/spi/Kconfig"
 
 source "drivers/spmi/Kconfig"
index 578f469f72fbb223d903151c68c5b9cd057675ea..e1ce029d28fdba01b73752d311d072ec6b81fab5 100644 (file)
@@ -111,7 +111,7 @@ obj-$(CONFIG_SERIO)         += input/serio/
 obj-$(CONFIG_GAMEPORT)         += input/gameport/
 obj-$(CONFIG_INPUT)            += input/
 obj-$(CONFIG_RTC_LIB)          += rtc/
-obj-y                          += i2c/ media/
+obj-y                          += i2c/ i3c/ media/
 obj-$(CONFIG_PPS)              += pps/
 obj-y                          += ptp/
 obj-$(CONFIG_W1)               += w1/
index 7cea769c37df55b50c55a7e8751a05057b5348cd..7b65a807b3dda5f955d96aadbff59a1e75c09600 100644 (file)
@@ -9,7 +9,6 @@ config ARCH_SUPPORTS_ACPI
 menuconfig ACPI
        bool "ACPI (Advanced Configuration and Power Interface) Support"
        depends on ARCH_SUPPORTS_ACPI
-       depends on PCI
        select PNP
        default y if X86
        help
@@ -336,7 +335,7 @@ config ACPI_CUSTOM_DSDT_FILE
          See Documentation/acpi/dsdt-override.txt
 
          Enter the full path name to the file which includes the AmlCode
-         declaration.
+         or dsdt_aml_code declaration.
 
          If unsure, don't enter a file name.
 
@@ -370,7 +369,7 @@ config ACPI_DEBUG
 
 config ACPI_PCI_SLOT
        bool "PCI slot detection driver"
-       depends on SYSFS
+       depends on SYSFS && PCI
        help
          This driver creates entries in /sys/bus/pci/slots/ for all PCI
          slots in the system.  This can help correlate PCI bus addresses,
index edc039313cd68bf6056afbd0de5f40f7ee6eab2d..7c6afc111d76b7b5cd101b37924ec83577462c71 100644 (file)
@@ -39,7 +39,7 @@ acpi-y                                += processor_core.o
 acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y                         += ec.o
 acpi-$(CONFIG_ACPI_DOCK)       += dock.o
-acpi-y                         += pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI)             += pci_root.o pci_link.o pci_irq.o
 obj-$(CONFIG_ACPI_MCFG)                += pci_mcfg.o
 acpi-y                         += acpi_lpss.o acpi_apd.o
 acpi-y                         += acpi_platform.o
index 2664452fa112630d254106099bc8e3026a2ecb7b..ddf598ae8b6b4c311683d3da5159d66214ed31c2 100644 (file)
@@ -166,6 +166,11 @@ static const struct apd_device_desc thunderx2_i2c_desc = {
        .setup = acpi_apd_setup,
        .fixed_clk_rate = 125000000,
 };
+
+static const struct apd_device_desc hip08_spi_desc = {
+       .setup = acpi_apd_setup,
+       .fixed_clk_rate = 250000000,
+};
 #endif
 
 #else
@@ -234,6 +239,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
        { "CAV9007",  APD_ADDR(thunderx2_i2c_desc) },
        { "HISI02A1", APD_ADDR(hip07_i2c_desc) },
        { "HISI02A2", APD_ADDR(hip08_i2c_desc) },
+       { "HISI0173", APD_ADDR(hip08_spi_desc) },
 #endif
        { }
 };
index b9bda06d344d7eea58fddc3a3a8328868f1c662c..5f94c35d165fe917151fa90127819b6f1d686db3 100644 (file)
@@ -673,12 +673,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
         * have _PS0 and _PS3 without _PSC (and no power resources), so
         * acpi_bus_init_power() will assume that the BIOS has put them into D0.
         */
-       ret = acpi_device_fix_up_power(adev);
-       if (ret) {
-               /* Skip the device, but continue the namespace scan. */
-               ret = 0;
-               goto err_out;
-       }
+       acpi_device_fix_up_power(adev);
 
        adev->driver_data = pdata;
        pdev = acpi_create_platform_device(adev, dev_desc->properties);
index b14621da5413ce71518d567e6705287dac918127..59700433a96e51599adf6306068b03bcb3dceec7 100644 (file)
@@ -77,13 +77,13 @@ acpi-y +=           \
        hwacpi.o        \
        hwesleep.o      \
        hwgpe.o         \
-       hwpci.o         \
        hwregs.o        \
        hwsleep.o       \
        hwvalid.o       \
        hwxface.o       \
        hwxfsleep.o
 
+acpi-$(CONFIG_PCI) += hwpci.o
 acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
 acpi-y +=              \
index 1e6204518496cffb6f02953d1ee1b3a12561f22a..87d6eb01beaf5a33e0119be30f11439855ff0f79 100644 (file)
@@ -172,11 +172,7 @@ ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking);
  *
  ****************************************************************************/
 
-#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
 #define NUM_PREDEFINED_NAMES            10
-#else
-#define NUM_PREDEFINED_NAMES            9
-#endif
 
 ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct);
 ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node);
index 43ce67a9da1fc19d08f4366c244ab3105369fd3f..ef99e2fc37f89011a14f38c25c8ad157d8caf849 100644 (file)
@@ -106,11 +106,20 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                                 struct acpi_gpe_block_info *gpe_block,
                                 void *context);
 
+#ifdef ACPI_PCI_CONFIGURED
 /*
  * hwpci - PCI configuration support
  */
 acpi_status
 acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
                      acpi_handle root_pci_device, acpi_handle pci_region);
+#else
+static inline acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id, acpi_handle root_pci_device,
+                     acpi_handle pci_region)
+{
+       return AE_SUPPORT;
+}
+#endif
 
 #endif                         /* __ACHWARE_H__ */
index bbb3b4d1e796cef48aad9362ca7d3022d3acab17..9bd25f36c6080395ce13b685ca9d3164841f5bad 100644 (file)
@@ -34,6 +34,7 @@
 #define ACPI_NS_TEMPORARY           0x0040
 #define ACPI_NS_OVERRIDE_IF_FOUND   0x0080
 #define ACPI_NS_EARLY_INIT          0x0100
+#define ACPI_NS_PREFIX_MUST_EXIST   0x0200
 
 /* Flags for acpi_ns_walk_namespace */
 
index acf27156dbd41be9d4cf05776e9bc55f7c2878c1..14be32961b4cae24ff61b731fb05f63802dc6fff 100644 (file)
@@ -60,6 +60,8 @@ struct acpi_walk_state {
        struct acpi_parse_state parser_state;   /* Current state of parser */
        u32 prev_arg_types;
        u32 arg_count;          /* push for fixed or var args */
+       u16 method_nesting_depth;
+       u8 method_is_nested;
 
        struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS];     /* Control method arguments */
        struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS];     /* Control method locals */
@@ -74,7 +76,8 @@ struct acpi_walk_state {
        struct acpi_namespace_node *method_call_node;   /* Called method Node */
        union acpi_parse_object *method_call_op;        /* method_call Op if running a method */
        union acpi_operand_object *method_desc; /* Method descriptor if running a method */
-       struct acpi_namespace_node *method_node;        /* Method node if running a method. */
+       struct acpi_namespace_node *method_node;        /* Method node if running a method */
+       char *method_pathname;  /* Full pathname of running method */
        union acpi_parse_object *op;    /* Current parser op */
        const struct acpi_opcode_info *op_info; /* Info on current opcode */
        union acpi_parse_object *origin;        /* Start of walk [Obsolete] */
index f2526726daf6cbf7c2c72e7697aaab398ba0beca..3eb45ea93e5e98d0b7ef3fb0429c8a6cec254b97 100644 (file)
@@ -24,6 +24,13 @@ acpi_db_start_command(struct acpi_walk_state *walk_state,
 void acpi_db_method_end(struct acpi_walk_state *walk_state);
 #endif
 
+#ifdef ACPI_DISASSEMBLER
+static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state
+                                                      *walk_state,
+                                                      union acpi_parse_object
+                                                      *op);
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_db_start_command
@@ -113,6 +120,70 @@ void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
        acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
 }
 
+#ifdef ACPI_DISASSEMBLER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_display_op
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing op (from aml interpreter)
+ *
+ * RETURN:      Opcode to display
+ *
+ * DESCRIPTION: Find the opcode to display during single stepping
+ *
+ ******************************************************************************/
+
+static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state
+                                                      *walk_state,
+                                                      union acpi_parse_object
+                                                      *op)
+{
+       union acpi_parse_object *display_op;
+       union acpi_parse_object *parent_op;
+
+       display_op = op;
+       parent_op = op->common.parent;
+       if (parent_op) {
+               if ((walk_state->control_state) &&
+                   (walk_state->control_state->common.state ==
+                    ACPI_CONTROL_PREDICATE_EXECUTING)) {
+                       /*
+                        * We are executing the predicate of an IF or WHILE statement
+                        * Search upwards for the containing IF or WHILE so that the
+                        * entire predicate can be displayed.
+                        */
+                       while (parent_op) {
+                               if ((parent_op->common.aml_opcode == AML_IF_OP)
+                                   || (parent_op->common.aml_opcode ==
+                                       AML_WHILE_OP)) {
+                                       display_op = parent_op;
+                                       break;
+                               }
+                               parent_op = parent_op->common.parent;
+                       }
+               } else {
+                       while (parent_op) {
+                               if ((parent_op->common.aml_opcode == AML_IF_OP)
+                                   || (parent_op->common.aml_opcode ==
+                                       AML_ELSE_OP)
+                                   || (parent_op->common.aml_opcode ==
+                                       AML_SCOPE_OP)
+                                   || (parent_op->common.aml_opcode ==
+                                       AML_METHOD_OP)
+                                   || (parent_op->common.aml_opcode ==
+                                       AML_WHILE_OP)) {
+                                       break;
+                               }
+                               display_op = parent_op;
+                               parent_op = parent_op->common.parent;
+                       }
+               }
+       }
+       return display_op;
+}
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_db_single_step
@@ -134,8 +205,6 @@ acpi_db_single_step(struct acpi_walk_state *walk_state,
        union acpi_parse_object *next;
        acpi_status status = AE_OK;
        u32 original_debug_level;
-       union acpi_parse_object *display_op;
-       union acpi_parse_object *parent_op;
        u32 aml_offset;
 
        ACPI_FUNCTION_ENTRY();
@@ -222,51 +291,12 @@ acpi_db_single_step(struct acpi_walk_state *walk_state,
                next = op->common.next;
                op->common.next = NULL;
 
-               display_op = op;
-               parent_op = op->common.parent;
-               if (parent_op) {
-                       if ((walk_state->control_state) &&
-                           (walk_state->control_state->common.state ==
-                            ACPI_CONTROL_PREDICATE_EXECUTING)) {
-                               /*
-                                * We are executing the predicate of an IF or WHILE statement
-                                * Search upwards for the containing IF or WHILE so that the
-                                * entire predicate can be displayed.
-                                */
-                               while (parent_op) {
-                                       if ((parent_op->common.aml_opcode ==
-                                            AML_IF_OP)
-                                           || (parent_op->common.aml_opcode ==
-                                               AML_WHILE_OP)) {
-                                               display_op = parent_op;
-                                               break;
-                                       }
-                                       parent_op = parent_op->common.parent;
-                               }
-                       } else {
-                               while (parent_op) {
-                                       if ((parent_op->common.aml_opcode ==
-                                            AML_IF_OP)
-                                           || (parent_op->common.aml_opcode ==
-                                               AML_ELSE_OP)
-                                           || (parent_op->common.aml_opcode ==
-                                               AML_SCOPE_OP)
-                                           || (parent_op->common.aml_opcode ==
-                                               AML_METHOD_OP)
-                                           || (parent_op->common.aml_opcode ==
-                                               AML_WHILE_OP)) {
-                                               break;
-                                       }
-                                       display_op = parent_op;
-                                       parent_op = parent_op->common.parent;
-                               }
-                       }
-               }
-
                /* Now we can disassemble and display it */
 
 #ifdef ACPI_DISASSEMBLER
-               acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
+               acpi_dm_disassemble(walk_state,
+                                   acpi_db_get_display_op(walk_state, op),
+                                   ACPI_UINT32_MAX);
 #else
                /*
                 * The AML Disassembler is not configured - at least we can
index dd4deb678d13ea24df8de76cf6e4181a91bf99e1..c1a4d02fafd5ab2d6114c4f8975696516ae4db5b 100644 (file)
@@ -532,6 +532,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
                goto cleanup;
        }
 
+       next_walk_state->method_nesting_depth =
+           this_walk_state->method_nesting_depth + 1;
+
        /*
         * Delete the operands on the previous walkstate operand stack
         * (they were copied to new objects)
@@ -549,6 +552,17 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
                          "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
                          method_node->name.ascii, next_walk_state));
 
+       this_walk_state->method_pathname =
+           acpi_ns_get_normalized_pathname(method_node, TRUE);
+       this_walk_state->method_is_nested = TRUE;
+
+       /* Optional object evaluation log */
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                             "%-26s:  %*s%s\n", "   Nested method call",
+                             next_walk_state->method_nesting_depth * 3, " ",
+                             &this_walk_state->method_pathname[1]));
+
        /* Invoke an internal method if necessary */
 
        if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
index 6992c8d5ab431db04d6987e1faa6afe6c1147e53..6a9cc613adaaae08dd034890557bb6954d9670d4 100644 (file)
@@ -18,7 +18,6 @@
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsobject")
 
-#ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_build_internal_object
@@ -299,8 +298,6 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state,
        return_ACPI_STATUS(status);
 }
 
-#endif                         /* ACPI_NO_METHOD_EXECUTION */
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_init_object_from_op
@@ -404,9 +401,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                                /* Truncate value if we are executing from a 32-bit ACPI table */
 
-#ifndef ACPI_NO_METHOD_EXECUTION
                                (void)acpi_ex_truncate_for32bit_table(obj_desc);
-#endif
                                break;
 
                        case AML_REVISION_OP:
@@ -428,7 +423,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        obj_desc->integer.value = op->common.value.integer;
 
-#ifndef ACPI_NO_METHOD_EXECUTION
                        if (acpi_ex_truncate_for32bit_table(obj_desc)) {
 
                                /* Warn if we found a 64-bit constant in a 32-bit table */
@@ -439,7 +433,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                                                                 value.integer),
                                              (u32)obj_desc->integer.value));
                        }
-#endif
                        break;
 
                default:
@@ -477,7 +470,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                            ((u32)opcode) - AML_FIRST_LOCAL_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
 
-#ifndef ACPI_NO_METHOD_EXECUTION
                        status =
                            acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL,
                                                         obj_desc->reference.
@@ -487,7 +479,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                                                          acpi_namespace_node,
                                                          &obj_desc->reference.
                                                          object));
-#endif
                        break;
 
                case AML_TYPE_METHOD_ARGUMENT:
@@ -498,7 +489,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                            ((u32)opcode) - AML_FIRST_ARG_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_ARG;
 
-#ifndef ACPI_NO_METHOD_EXECUTION
                        status = acpi_ds_method_data_get_node(ACPI_REFCLASS_ARG,
                                                              obj_desc->
                                                              reference.value,
@@ -509,7 +499,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                                                               &obj_desc->
                                                               reference.
                                                               object));
-#endif
                        break;
 
                default:        /* Object name or Debug object */
index d703a5594a02fa9c2b00624edfeca7179d86d004..584853385268ade419a0f8f034db9f334cae75a5 100644 (file)
@@ -152,6 +152,32 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
         */
        for (i = 0; arg && (i < element_count); i++) {
                if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+                       if (!arg->common.node) {
+                               /*
+                                * This is the case where an expression has returned a value.
+                                * The use of expressions (term_args) within individual
+                                * package elements is not supported by the AML interpreter,
+                                * even though the ASL grammar supports it. Example:
+                                *
+                                *      Name (INT1, 0x1234)
+                                *
+                                *      Name (PKG3, Package () {
+                                *          Add (INT1, 0xAAAA0000)
+                                *      })
+                                *
+                                *  1) No known AML interpreter supports this type of construct
+                                *  2) This fixes a fault if the construct is encountered
+                                */
+                               ACPI_EXCEPTION((AE_INFO, AE_SUPPORT,
+                                               "Expressions within package elements are not supported"));
+
+                               /* Cleanup the return object, it is not needed */
+
+                               acpi_ut_remove_reference(walk_state->results->
+                                                        results.obj_desc[0]);
+                               return_ACPI_STATUS(AE_SUPPORT);
+                       }
+
                        if (arg->common.node->type == ACPI_TYPE_METHOD) {
                                /*
                                 * A method reference "looks" to the parser to be a method
index 8d1b754005158ff0d90329c80e908bebd473a142..fb9ed5e1da89dc0d3b0c2371d65b1cd47363d65d 100644 (file)
@@ -57,7 +57,6 @@ void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state)
        }
 }
 
-#ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_do_implicit_return
@@ -401,7 +400,6 @@ void acpi_ds_clear_operands(struct acpi_walk_state *walk_state)
        walk_state->num_operands = 0;
        return_VOID;
 }
-#endif
 
 /*******************************************************************************
  *
index d06c414462822dfb0ceb49691b0643309fa653e6..e2ef09643d50831d531c8e7072d34bc0785758e6 100644 (file)
@@ -73,12 +73,10 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
 
                /* Execution pass */
 
-#ifndef ACPI_NO_METHOD_EXECUTION
                walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
                    ACPI_PARSE_DELETE_TREE;
                walk_state->descending_callback = acpi_ds_exec_begin_op;
                walk_state->ascending_callback = acpi_ds_exec_end_op;
-#endif
                break;
 
        default:
@@ -364,7 +362,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state,
 
        /* Initialize the op */
 
-#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY))
+#ifdef ACPI_CONSTANT_EVAL_ONLY
        op->named.path = path;
 #endif
 
@@ -422,7 +420,6 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
 
        object_type = walk_state->op_info->object_type;
 
-#ifndef ACPI_NO_METHOD_EXECUTION
        if (walk_state->op_info->flags & AML_FIELD) {
                /*
                 * If we are executing a method, do not create any namespace objects
@@ -466,7 +463,6 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
                        }
                }
        }
-#endif
 
        if (op->common.aml_opcode == AML_NAME_OP) {
 
index b4685bb5f071eb48ce2597b4b8bca59521877704..9a309f5c4de8a6c6169cb0d287a58fde5a197d2f 100644 (file)
@@ -296,6 +296,14 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
                }
 #endif
 
+               /*
+                * For name creation opcodes, the full namepath prefix must
+                * exist, except for the final (new) nameseg.
+                */
+               if (walk_state->op_info->flags & AML_NAMED) {
+                       flags |= ACPI_NS_PREFIX_MUST_EXIST;
+               }
+
                /* Add new entry or lookup existing entry */
 
                status =
@@ -363,10 +371,8 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
        struct acpi_namespace_node *node;
        union acpi_parse_object *arg;
        struct acpi_namespace_node *new_node;
-#ifndef ACPI_NO_METHOD_EXECUTION
        u32 i;
        u8 region_space;
-#endif
 
        ACPI_FUNCTION_TRACE(ds_load2_end_op);
 
@@ -453,7 +459,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
        arg = op->common.value.arg;
 
        switch (walk_state->op_info->type) {
-#ifndef ACPI_NO_METHOD_EXECUTION
 
        case AML_TYPE_CREATE_FIELD:
                /*
@@ -550,12 +555,10 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                }
 
                break;
-#endif                         /* ACPI_NO_METHOD_EXECUTION */
 
        case AML_TYPE_NAMED_COMPLEX:
 
                switch (op->common.aml_opcode) {
-#ifndef ACPI_NO_METHOD_EXECUTION
                case AML_REGION_OP:
                case AML_DATA_REGION_OP:
 
@@ -643,8 +646,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                        }
                        break;
 
-#endif                         /* ACPI_NO_METHOD_EXECUTION */
-
                default:
 
                        /* All NAMED_COMPLEX opcodes must be handled above */
index c879380e5ce1720b33a99cffa01e06332650376b..4c1ec202d5ab81504e051f302a0b5510dbc9c1e1 100644 (file)
@@ -530,7 +530,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
 
        /* Init the method args/local */
 
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+#ifndef ACPI_CONSTANT_EVAL_ONLY
        acpi_ds_method_data_init(walk_state);
 #endif
 
index d319ee33d0401e9f28259be046957b5c40fc2d6a..4ed1e67db6be8d3a4c36c9d91597905ce292d209 100644 (file)
@@ -364,25 +364,25 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,
                        handler = acpi_ex_system_io_space_handler;
                        setup = acpi_ev_io_space_region_setup;
                        break;
-
+#ifdef ACPI_PCI_CONFIGURED
                case ACPI_ADR_SPACE_PCI_CONFIG:
 
                        handler = acpi_ex_pci_config_space_handler;
                        setup = acpi_ev_pci_config_region_setup;
                        break;
-
+#endif
                case ACPI_ADR_SPACE_CMOS:
 
                        handler = acpi_ex_cmos_space_handler;
                        setup = acpi_ev_cmos_region_setup;
                        break;
-
+#ifdef ACPI_PCI_CONFIGURED
                case ACPI_ADR_SPACE_PCI_BAR_TARGET:
 
                        handler = acpi_ex_pci_bar_space_handler;
                        setup = acpi_ev_pci_bar_region_setup;
                        break;
-
+#endif
                case ACPI_ADR_SPACE_DATA_TABLE:
 
                        handler = acpi_ex_data_table_space_handler;
index 98de48481776b13315203634a0d7694d36afc156..1a70b80cc40619b3d47f3fd8a91398b14571db25 100644 (file)
@@ -323,7 +323,7 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
 
                /* hex_length: 2 ascii hex chars per data byte */
 
-               hex_length = ACPI_MUL_2(data_width);
+               hex_length = (data_width * 2);
                for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) {
 
                        /* Get one hex digit, most significant digits first */
@@ -364,7 +364,8 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Convert an ACPI Object to a string
+ * DESCRIPTION: Convert an ACPI Object to a string. Supports both implicit
+ *              and explicit conversions and related rules.
  *
  ******************************************************************************/
 
@@ -393,9 +394,11 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
 
                switch (type) {
                case ACPI_EXPLICIT_CONVERT_DECIMAL:
-
-                       /* Make room for maximum decimal number */
-
+                       /*
+                        * From to_decimal_string, integer source.
+                        *
+                        * Make room for the maximum decimal number size
+                        */
                        string_length = ACPI_MAX_DECIMAL_DIGITS;
                        base = 10;
                        break;
@@ -440,8 +443,10 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
                switch (type) {
                case ACPI_EXPLICIT_CONVERT_DECIMAL:     /* Used by to_decimal_string */
                        /*
-                        * From ACPI: "If Data is a buffer, it is converted to a string of
-                        * decimal values separated by commas."
+                        * Explicit conversion from the to_decimal_string ASL operator.
+                        *
+                        * From ACPI: "If the input is a buffer, it is converted to a
+                        * a string of decimal values separated by commas."
                         */
                        base = 10;
 
@@ -462,20 +467,29 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
 
                case ACPI_IMPLICIT_CONVERT_HEX:
                        /*
+                        * Implicit buffer-to-string conversion
+                        *
                         * From the ACPI spec:
-                        *"The entire contents of the buffer are converted to a string of
+                        * "The entire contents of the buffer are converted to a string of
                         * two-character hexadecimal numbers, each separated by a space."
+                        *
+                        * Each hex number is prefixed with 0x (11/2018)
                         */
                        separator = ' ';
-                       string_length = (obj_desc->buffer.length * 3);
+                       string_length = (obj_desc->buffer.length * 5);
                        break;
 
-               case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string */
+               case ACPI_EXPLICIT_CONVERT_HEX:
                        /*
+                        * Explicit conversion from the to_hex_string ASL operator.
+                        *
                         * From ACPI: "If Data is a buffer, it is converted to a string of
                         * hexadecimal values separated by commas."
+                        *
+                        * Each hex number is prefixed with 0x (11/2018)
                         */
-                       string_length = (obj_desc->buffer.length * 3);
+                       separator = ',';
+                       string_length = (obj_desc->buffer.length * 5);
                        break;
 
                default:
@@ -504,10 +518,21 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
                 * (separated by commas or spaces)
                 */
                for (i = 0; i < obj_desc->buffer.length; i++) {
+                       if (base == 16) {
+
+                               /* Emit 0x prefix for explict/implicit hex conversion */
+
+                               *new_buf++ = '0';
+                               *new_buf++ = 'x';
+                       }
+
                        new_buf += acpi_ex_convert_to_ascii((u64) obj_desc->
                                                            buffer.pointer[i],
                                                            base, new_buf, 1);
-                       *new_buf++ = separator; /* each separated by a comma or space */
+
+                       /* Each digit is separated by either a comma or space */
+
+                       *new_buf++ = separator;
                }
 
                /*
index e49fa3c1321a3644741e32d4f02387f8be187726..3304c6b1e8a7fe5d7456d470f09567e7a3f80958 100644 (file)
@@ -15,7 +15,6 @@
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("excreate")
-#ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_create_alias
@@ -390,7 +389,6 @@ acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state)
        acpi_ut_remove_reference(obj_desc);
        return_ACPI_STATUS(status);
 }
-#endif
 
 /*******************************************************************************
  *
index d5b3efd35a5be4898f147759f31024b36dd9f55a..3a477566ba1b309b7de90dbedc824d335b140a7c 100644 (file)
@@ -287,9 +287,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
                 * NOTE: A length of zero is ok, and will create a zero-length, null
                 *       terminated string.
                 */
-               while ((length < operand[0]->buffer.length) &&
-                      (length < operand[1]->integer.value) &&
-                      (operand[0]->buffer.pointer[length])) {
+               while ((length < operand[0]->buffer.length) &&  /* Length of input buffer */
+                      (length < operand[1]->integer.value) &&  /* Length operand */
+                      (operand[0]->buffer.pointer[length])) {  /* Null terminator */
                        length++;
                }
 
index 97bbfd07fcf759c86e033f3d2d83b6cb8b334a3b..2c58f5e00b1a18ad6c6a354fe77d559159d41264 100644 (file)
@@ -311,6 +311,7 @@ acpi_ex_system_io_space_handler(u32 function,
        return_ACPI_STATUS(status);
 }
 
+#ifdef ACPI_PCI_CONFIGURED
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_pci_config_space_handler
@@ -387,6 +388,7 @@ acpi_ex_pci_config_space_handler(u32 function,
 
        return_ACPI_STATUS(status);
 }
+#endif
 
 /*******************************************************************************
  *
@@ -420,6 +422,7 @@ acpi_ex_cmos_space_handler(u32 function,
        return_ACPI_STATUS(status);
 }
 
+#ifdef ACPI_PCI_CONFIGURED
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_pci_bar_space_handler
@@ -451,6 +454,7 @@ acpi_ex_pci_bar_space_handler(u32 function,
 
        return_ACPI_STATUS(status);
 }
+#endif
 
 /*******************************************************************************
  *
index 9920fac6413ffb94cce8d5eb146dbb15df5283a4..ec61553c448377ac0f177945bf635ed115829a4f 100644 (file)
@@ -244,6 +244,7 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
 {
        acpi_status status;
        u32 buffer_length;
+       u32 data_length;
        void *buffer;
        union acpi_operand_object *buffer_desc;
        u32 function;
@@ -324,8 +325,9 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
        /* Copy the input buffer data to the transfer buffer */
 
        buffer = buffer_desc->buffer.pointer;
-       memcpy(buffer, source_desc->buffer.pointer,
-              min(buffer_length, source_desc->buffer.length));
+       data_length = (buffer_length < source_desc->buffer.length ?
+                      buffer_length : source_desc->buffer.length);
+       memcpy(buffer, source_desc->buffer.pointer, data_length);
 
        /* Lock entire transaction if requested */
 
index 6ce307d5ce2a6f855a58edfa080c69e8505078e6..bd22e27adf9b775422385983ebd7acacacd15d97 100644 (file)
@@ -34,7 +34,6 @@ ACPI_MODULE_NAME("exutils")
 /* Local prototypes */
 static u32 acpi_ex_digits_needed(u64 value, u32 base);
 
-#ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_enter_interpreter
@@ -409,5 +408,3 @@ u8 acpi_is_valid_space_id(u8 space_id)
 
        return (TRUE);
 }
-
-#endif
index e3f10afde5ffae47deb166544cf8f5ded393f726..75192b958544e0b5ef385cd64df27b2d7646d0ed 100644 (file)
@@ -267,6 +267,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
        acpi_object_type this_search_type;
        u32 search_parent_flag = ACPI_NS_SEARCH_PARENT;
        u32 local_flags;
+       acpi_interpreter_mode local_interpreter_mode;
 
        ACPI_FUNCTION_TRACE(ns_lookup);
 
@@ -506,6 +507,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
         */
        this_search_type = ACPI_TYPE_ANY;
        current_node = this_node;
+
        while (num_segments && current_node) {
                num_segments--;
                if (!num_segments) {
@@ -536,6 +538,16 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
                        }
                }
 
+               /* Handle opcodes that create a new name_seg via a full name_path */
+
+               local_interpreter_mode = interpreter_mode;
+               if ((flags & ACPI_NS_PREFIX_MUST_EXIST) && (num_segments > 0)) {
+
+                       /* Every element of the path must exist (except for the final name_seg) */
+
+                       local_interpreter_mode = ACPI_IMODE_EXECUTE;
+               }
+
                /* Extract one ACPI name from the front of the pathname */
 
                ACPI_MOVE_32_TO_32(&simple_name, path);
@@ -544,12 +556,19 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
 
                status =
                    acpi_ns_search_and_enter(simple_name, walk_state,
-                                            current_node, interpreter_mode,
+                                            current_node,
+                                            local_interpreter_mode,
                                             this_search_type, local_flags,
                                             &this_node);
                if (ACPI_FAILURE(status)) {
                        if (status == AE_NOT_FOUND) {
-
+#if !defined ACPI_ASL_COMPILER /* Note: iASL reports this error by itself, not needed here */
+                               if (flags & ACPI_NS_PREFIX_MUST_EXIST) {
+                                       acpi_os_printf(ACPI_MSG_BIOS_ERROR
+                                                      "Object does not exist: %4.4s\n",
+                                                      &simple_name);
+                               }
+#endif
                                /* Name not found in ACPI namespace */
 
                                ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
index 64ba80ede0ad7127d2fe1ccf3eb81095ec5aed81..6390b7951ebfac913c1d55d747797c676da748ae 100644 (file)
@@ -104,6 +104,13 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
+       /* Optional object evaluation log */
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                             "%-26s:  %s (%s)\n", "   Enter evaluation",
+                             &info->full_pathname[1],
+                             acpi_ut_get_type_name(info->node->type)));
+
        /* Count the number of arguments being passed in */
 
        info->param_count = 0;
@@ -289,6 +296,12 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                          info->relative_pathname));
 
 cleanup:
+       /* Optional object evaluation log */
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                             "%-26s:  %s\n", "   Exit evaluation",
+                             &info->full_pathname[1]));
+
        /*
         * Namespace was unlocked by the handling acpi_ns* function, so we
         * just free the pathname and return
index e291bb8cd3693f395d18c931d16cab010534172b..04bc73e82aed3f4160ca6ac2818ee98029b38d1e 100644 (file)
@@ -24,7 +24,6 @@ acpi_status acpi_ns_unload_namespace(acpi_handle handle);
 static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
 #endif
 
-#ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_load_table
@@ -297,4 +296,3 @@ acpi_status acpi_ns_unload_namespace(acpi_handle handle)
        return_ACPI_STATUS(status);
 }
 #endif
-#endif
index c9ef4949869f2de82e3b815a5a05c7c5d365d458..488ff39d86f799217aec6adcd841bf60fe0fa921 100644 (file)
@@ -107,8 +107,20 @@ acpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
                goto cleanup;
        }
 
+       /* Optional object evaluation log */
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                             "%-26s:  (Definition Block level)\n",
+                             "Module-level evaluation"));
+
        status = acpi_ps_execute_table(info);
 
+       /* Optional object evaluation log */
+
+       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                             "%-26s:  (Definition Block level)\n",
+                             "Module-level complete"));
+
 cleanup:
        if (info) {
                ACPI_FREE(info->full_pathname);
index 0fa01c9e353e45b444a342ea43cd4c0072c7dc75..e00d1af6fa80d17874015937e1768fbf79f0ac9d 100644 (file)
@@ -428,7 +428,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
        parser_state = &walk_state->parser_state;
        walk_state->arg_types = 0;
 
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+#ifndef ACPI_CONSTANT_EVAL_ONLY
 
        if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
 
@@ -508,7 +508,8 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
                                 */
                                if ((walk_state->
                                     parse_flags & ACPI_PARSE_MODULE_LEVEL)
-                                   && status == AE_ALREADY_EXISTS) {
+                                   && ((status == AE_ALREADY_EXISTS)
+                                       || (status == AE_NOT_FOUND))) {
                                        status = AE_OK;
                                }
                                if (status == AE_CTRL_PARSE_CONTINUE) {
@@ -537,10 +538,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
                                         * the scope op because the parse failure indicates that
                                         * the device may not exist.
                                         */
-                                       ACPI_ERROR((AE_INFO,
-                                                   "Skip parsing opcode %s",
-                                                   acpi_ps_get_opcode_name
-                                                   (walk_state->opcode)));
+                                       ACPI_INFO(("Skipping parse of AML opcode: %s (0x%4.4X)", acpi_ps_get_opcode_name(walk_state->opcode), walk_state->opcode));
 
                                        /*
                                         * Determine the opcode length before skipping the opcode.
index 3138e7a00da815dc44f882b4be35f97b3250e82b..e1fd819a2955e8152d4cf3d878823a6fde7d40fb 100644 (file)
@@ -600,8 +600,7 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
                         * because there could be correct AML beyond the parts that caused
                         * the runtime error.
                         */
-                       ACPI_ERROR((AE_INFO,
-                                   "Ignore error and continue table load"));
+                       ACPI_INFO(("Ignoring error and continuing table load"));
                        return_ACPI_STATUS(AE_OK);
                }
                return_ACPI_STATUS(status);
index a16a6ea5ae02aded254903cc265fa34b874c8033..65603473b6cb155258ce4979e46f3ee9d2369c34 100644 (file)
@@ -479,6 +479,21 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
                                  "Completed one call to walk loop, %s State=%p\n",
                                  acpi_format_exception(status), walk_state));
 
+               if (walk_state->method_pathname && walk_state->method_is_nested) {
+
+                       /* Optional object evaluation log */
+
+                       ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
+                                             "%-26s:  %*s%s\n",
+                                             "   Exit nested method",
+                                             (walk_state->
+                                              method_nesting_depth + 1) * 3,
+                                             " ",
+                                             &walk_state->method_pathname[1]));
+
+                       ACPI_FREE(walk_state->method_pathname);
+                       walk_state->method_is_nested = FALSE;
+               }
                if (status == AE_CTRL_TRANSFER) {
                        /*
                         * A method call was detected.
index f26bcbbc2c2767af80d2e1168a4fd35a38c0dc02..5743b22399a0b4f5518d07f3070b7394c906e81a 100644 (file)
@@ -147,6 +147,9 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
                goto cleanup;
        }
 
+       walk_state->method_pathname = info->full_pathname;
+       walk_state->method_is_nested = FALSE;
+
        if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) {
                walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL;
        }
@@ -267,6 +270,9 @@ acpi_status acpi_ps_execute_table(struct acpi_evaluate_info *info)
                goto cleanup;
        }
 
+       walk_state->method_pathname = info->full_pathname;
+       walk_state->method_is_nested = FALSE;
+
        if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) {
                walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL;
        }
index fa674e9b0e62a7610bd9071a044d64b4cc122240..f8c5b49344dfab484e6ec9c0fe3e0012ec2e95d2 100644 (file)
@@ -83,10 +83,7 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
        {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR(char, 2)},
        {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
        {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR(char, 1)},
-
-#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
        {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR(char, 1)},
-#endif
 
        /* Table terminator */
 
index ed73d79b500e6c4e498d3f3eb19468b8d59e4a7d..afaadc73196b9f713805c06d5ecb851ea0e73436 100644 (file)
@@ -62,7 +62,8 @@ u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
        if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
            ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
            ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT) ||
-           ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT)) {
+           ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) ||
+           ACPI_IS_OEM_SIG(table->signature)) {
                return (TRUE);
        }
 
index 64b63c81994b696d7e4885b662eba7af3a0859e1..902a47463abf992b249ee81e33af0145b5ddc3de 100644 (file)
@@ -70,6 +70,8 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
        {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */
        {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */
        {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3},       /* Windows 10 version 1709 - Added 02/2018 */
+       {"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4}, /* Windows 10 version 1803 - Added 11/2018 */
+       {"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5},       /* Windows 10 version 1809 - Added 11/2018 */
 
        /* Feature Group Strings */
 
index b38737c83a243b02ca423ba649b7db48afb65415..fcccbfdbdd1af35956bb86fc4753bb71a1ff8f54 100644 (file)
@@ -607,17 +607,7 @@ static int available_error_type_show(struct seq_file *m, void *v)
        return 0;
 }
 
-static int available_error_type_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, available_error_type_show, NULL);
-}
-
-static const struct file_operations available_error_type_fops = {
-       .open           = available_error_type_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(available_error_type);
 
 static int error_type_get(void *data, u64 *val)
 {
index 02c6fd9caff7dc173c0d7552532e0c3588800e27..f008ba7c9cedc952852ca1550b0c58a7fece1529 100644 (file)
@@ -691,6 +691,8 @@ static void __ghes_panic(struct ghes *ghes)
 {
        __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
 
+       ghes_clear_estatus(ghes);
+
        /* reboot to log the error! */
        if (!panic_timeout)
                panic_timeout = ghes_panic_timeout;
index 70f4e80b9246a16f62e9459925ef1efd9905d9f5..2159ad9bf9ed8721733fdfd8f5ee29098b42850a 100644 (file)
@@ -1435,8 +1435,14 @@ dev_put:
        return ret;
 }
 
-static bool __init iort_enable_acs(struct acpi_iort_node *iort_node)
+#ifdef CONFIG_PCI
+static void __init iort_enable_acs(struct acpi_iort_node *iort_node)
 {
+       static bool acs_enabled __initdata;
+
+       if (acs_enabled)
+               return;
+
        if (iort_node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
                struct acpi_iort_node *parent;
                struct acpi_iort_id_mapping *map;
@@ -1458,13 +1464,15 @@ static bool __init iort_enable_acs(struct acpi_iort_node *iort_node)
                        if ((parent->type == ACPI_IORT_NODE_SMMU) ||
                                (parent->type == ACPI_IORT_NODE_SMMU_V3)) {
                                pci_request_acs();
-                               return true;
+                               acs_enabled = true;
+                               return;
                        }
                }
        }
-
-       return false;
 }
+#else
+static inline void iort_enable_acs(struct acpi_iort_node *iort_node) { }
+#endif
 
 static void __init iort_init_platform_devices(void)
 {
@@ -1472,7 +1480,6 @@ static void __init iort_init_platform_devices(void)
        struct acpi_table_iort *iort;
        struct fwnode_handle *fwnode;
        int i, ret;
-       bool acs_enabled = false;
        const struct iort_dev_config *ops;
 
        /*
@@ -1493,8 +1500,7 @@ static void __init iort_init_platform_devices(void)
                        return;
                }
 
-               if (!acs_enabled)
-                       acs_enabled = iort_enable_acs(iort_node);
+               iort_enable_acs(iort_node);
 
                ops = iort_get_dev_cfg(iort_node);
                if (ops) {
index d4e5610e09c51beb8810a3bf5f4d42ee563288c5..9d66a47d32fbd3fca6f78f6687e6f597303c0d21 100644 (file)
@@ -1034,6 +1034,18 @@ void acpi_ec_unblock_transactions(void)
                acpi_ec_start(first_ec, true);
 }
 
+void acpi_ec_mark_gpe_for_wake(void)
+{
+       if (first_ec && !ec_no_wakeup)
+               acpi_mark_gpe_for_wake(NULL, first_ec->gpe);
+}
+
+void acpi_ec_set_gpe_wake_mask(u8 action)
+{
+       if (first_ec && !ec_no_wakeup)
+               acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
+}
+
 void acpi_ec_dispatch_gpe(void)
 {
        if (first_ec)
index 530a3f67549049c1600ccb2ac9af26a683a7099a..c112dccc76b5049d33b8956f9012b3ce05ac6e55 100644 (file)
@@ -25,8 +25,13 @@ int acpi_osi_init(void);
 acpi_status acpi_os_initialize1(void);
 void init_acpi_device_notify(void);
 int acpi_scan_init(void);
+#ifdef CONFIG_PCI
 void acpi_pci_root_init(void);
 void acpi_pci_link_init(void);
+#else
+static inline void acpi_pci_root_init(void) {}
+static inline void acpi_pci_link_init(void) {}
+#endif
 void acpi_processor_init(void);
 void acpi_platform_init(void);
 void acpi_pnp_init(void);
@@ -188,6 +193,8 @@ int acpi_ec_ecdt_probe(void);
 int acpi_ec_dsdt_probe(void);
 void acpi_ec_block_transactions(void);
 void acpi_ec_unblock_transactions(void);
+void acpi_ec_mark_gpe_for_wake(void);
+void acpi_ec_set_gpe_wake_mask(u8 action);
 void acpi_ec_dispatch_gpe(void);
 int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
                              acpi_handle handle, acpi_ec_query_func func,
index b2a16ed7e81a97da10129fcaea23ce93a4926f3c..efd2ce099893b5b77dc73dfd5a30d9c85b1ae59f 100644 (file)
@@ -74,6 +74,13 @@ osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
         * a BIOS workaround.
         */
        {"Linux-Lenovo-NV-HDMI-Audio", true},
+       /*
+        * Linux-HPI-Hybrid-Graphics is used by BIOS to enable dGPU to
+        * output video directly to external monitors on HP Inc. mobile
+        * workstations as Nvidia and AMD VGA drivers provide limited
+        * hybrid graphics supports.
+        */
+       {"Linux-HPI-Hybrid-Graphics", true},
 };
 
 static u32 acpi_osi_handler(acpi_string interface, u32 supported)
index b48874b8e1ea05e75cf34976b4b669ffb0b3f204..f29e427d0d1d5cc8065f0ba0a6ce025814bd6350 100644 (file)
@@ -769,6 +769,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width)
        return AE_OK;
 }
 
+#ifdef CONFIG_PCI
 acpi_status
 acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                               u64 *value, u32 width)
@@ -827,6 +828,7 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
 
        return (result ? AE_ERROR : AE_OK);
 }
+#endif
 
 static void acpi_os_execute_deferred(struct work_struct *work)
 {
index 6fa9c2a4cfe9d31f31ee129128995733a1b7a3be..ca707f5b521d0990370e9f7fdbc531d97497cb4f 100644 (file)
@@ -4,11 +4,35 @@
 #include <linux/acpi.h>
 #include <acpi/reboot.h>
 
+#ifdef CONFIG_PCI
+static void acpi_pci_reboot(struct acpi_generic_address *rr, u8 reset_value)
+{
+       unsigned int devfn;
+       struct pci_bus *bus0;
+
+       /* The reset register can only live on bus 0. */
+       bus0 = pci_find_bus(0, 0);
+       if (!bus0)
+               return;
+       /* Form PCI device/function pair. */
+       devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
+                         (rr->address >> 16) & 0xffff);
+       pr_debug("Resetting with ACPI PCI RESET_REG.\n");
+       /* Write the value that resets us. */
+       pci_bus_write_config_byte(bus0, devfn,
+                       (rr->address & 0xffff), reset_value);
+}
+#else
+static inline void acpi_pci_reboot(struct acpi_generic_address *rr,
+                                  u8 reset_value)
+{
+       pr_warn_once("PCI configuration space access is not supported\n");
+}
+#endif
+
 void acpi_reboot(void)
 {
        struct acpi_generic_address *rr;
-       struct pci_bus *bus0;
-       unsigned int devfn;
        u8 reset_value;
 
        if (acpi_disabled)
@@ -33,17 +57,7 @@ void acpi_reboot(void)
         * on a device on bus 0. */
        switch (rr->space_id) {
        case ACPI_ADR_SPACE_PCI_CONFIG:
-               /* The reset register can only live on bus 0. */
-               bus0 = pci_find_bus(0, 0);
-               if (!bus0)
-                       return;
-               /* Form PCI device/function pair. */
-               devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
-                                 (rr->address >> 16) & 0xffff);
-               printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.\n");
-               /* Write the value that resets us. */
-               pci_bus_write_config_byte(bus0, devfn,
-                               (rr->address & 0xffff), reset_value);
+               acpi_pci_reboot(rr, reset_value);
                break;
 
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
index bd1c59fb0e17525bf42aec73fce8c40bcf43210a..e9eda5558c1fc5c2e312e8023c0ebb89cd28c80a 100644 (file)
@@ -1541,6 +1541,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
        static const struct acpi_device_id i2c_multi_instantiate_ids[] = {
                {"BSG1160", },
                {"INT33FE", },
+               {"INT3515", },
                {}
        };
 
index 754d59f95500497b5dd914323f04926f253593ac..403c4ff1534982eff19a839ab5bcfc4bc7b414cc 100644 (file)
@@ -940,6 +940,8 @@ static int lps0_device_attach(struct acpi_device *adev,
 
                acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
                                  bitmask);
+
+               acpi_ec_mark_gpe_for_wake();
        } else {
                acpi_handle_debug(adev->handle,
                                  "_DSM function 0 evaluation failed\n");
@@ -968,16 +970,23 @@ static int acpi_s2idle_prepare(void)
        if (lps0_device_handle) {
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
+
+               acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
        }
 
        if (acpi_sci_irq_valid())
                enable_irq_wake(acpi_sci_irq);
 
+       /* Change the configuration of GPEs to avoid spurious wakeup. */
+       acpi_enable_all_wakeup_gpes();
+       acpi_os_wait_events_complete();
        return 0;
 }
 
 static void acpi_s2idle_wake(void)
 {
+       if (!lps0_device_handle)
+               return;
 
        if (pm_debug_messages_on)
                lpi_check_constraints();
@@ -996,8 +1005,7 @@ static void acpi_s2idle_wake(void)
                 * takes too much time for EC wakeup events to survive, so look
                 * for them now.
                 */
-               if (lps0_device_handle)
-                       acpi_ec_dispatch_gpe();
+               acpi_ec_dispatch_gpe();
        }
 }
 
@@ -1017,10 +1025,14 @@ static void acpi_s2idle_sync(void)
 
 static void acpi_s2idle_restore(void)
 {
+       acpi_enable_all_runtime_gpes();
+
        if (acpi_sci_irq_valid())
                disable_irq_wake(acpi_sci_irq);
 
        if (lps0_device_handle) {
+               acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
+
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
        }
index 9d52743080a4f65200ea6e33f0d0d2fefdb881ea..c336784d0bcbeabd86a7bd27150342058b3c2af0 100644 (file)
@@ -148,6 +148,13 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
        }
 
        switch (table->baud_rate) {
+       case 0:
+               /*
+                * SPCR 1.04 defines 0 as a preconfigured state of UART.
+                * Assume firmware or bootloader configures console correctly.
+                */
+               baud_rate = 0;
+               break;
        case 3:
                baud_rate = 9600;
                break;
@@ -196,6 +203,10 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
                 * UART so don't attempt to change to the baud rate state
                 * in the table because driver cannot calculate the dividers
                 */
+               baud_rate = 0;
+       }
+
+       if (!baud_rate) {
                snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
                         table->serial_port.address);
        } else {
index 61203eebf3a1ae8cc3e70a7658b49cd39a8f249a..48eabb6c2d4fc9a656c6cfdbe6b7cb5d59928229 100644 (file)
@@ -712,6 +712,11 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table,
                                          table_length);
 }
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+static void *amlcode __attribute__ ((weakref("AmlCode")));
+static void *dsdt_amlcode __attribute__ ((weakref("dsdt_aml_code")));
+#endif
+
 acpi_status
 acpi_os_table_override(struct acpi_table_header *existing_table,
                       struct acpi_table_header **new_table)
@@ -722,8 +727,11 @@ acpi_os_table_override(struct acpi_table_header *existing_table,
        *new_table = NULL;
 
 #ifdef CONFIG_ACPI_CUSTOM_DSDT
-       if (strncmp(existing_table->signature, "DSDT", 4) == 0)
-               *new_table = (struct acpi_table_header *)AmlCode;
+       if (!strncmp(existing_table->signature, "DSDT", 4)) {
+               *new_table = (struct acpi_table_header *)&amlcode;
+               if (!(*new_table))
+                       *new_table = (struct acpi_table_header *)&dsdt_amlcode;
+       }
 #endif
        if (*new_table != NULL)
                acpi_table_taint(existing_table);
index 81c22d20d9d9c568ffc2f6c191a407baee330719..60e0b772673f3bd0c631efb6e45b0f624f75aa8a 100644 (file)
@@ -538,6 +538,9 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
        }
        case 'x':       /* gotoxy : LxXXX[yYYY]; */
        case 'y':       /* gotoxy : LyYYY[xXXX]; */
+               if (priv->esc_seq.buf[priv->esc_seq.len - 1] != ';')
+                       break;
+
                /* If the command is valid, move to the new address */
                if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
                        charlcd_gotoxy(lcd);
index 7f38a92b444a9aa3d7593a4efd9dc1067721b73b..500de1dee967bc201cbd5626f6b5b367267ece6d 100644 (file)
@@ -239,6 +239,127 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
 static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
 #endif
 
+static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
+                                          unsigned int state)
+{
+       struct generic_pm_domain_data *pd_data;
+       struct pm_domain_data *pdd;
+       struct gpd_link *link;
+
+       /* New requested state is same as Max requested state */
+       if (state == genpd->performance_state)
+               return state;
+
+       /* New requested state is higher than Max requested state */
+       if (state > genpd->performance_state)
+               return state;
+
+       /* Traverse all devices within the domain */
+       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+               pd_data = to_gpd_data(pdd);
+
+               if (pd_data->performance_state > state)
+                       state = pd_data->performance_state;
+       }
+
+       /*
+        * Traverse all sub-domains within the domain. This can be
+        * done without any additional locking as the link->performance_state
+        * field is protected by the master genpd->lock, which is already taken.
+        *
+        * Also note that link->performance_state (subdomain's performance state
+        * requirement to master domain) is different from
+        * link->slave->performance_state (current performance state requirement
+        * of the devices/sub-domains of the subdomain) and so can have a
+        * different value.
+        *
+        * Note that we also take vote from powered-off sub-domains into account
+        * as the same is done for devices right now.
+        */
+       list_for_each_entry(link, &genpd->master_links, master_node) {
+               if (link->performance_state > state)
+                       state = link->performance_state;
+       }
+
+       return state;
+}
+
+static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
+                                       unsigned int state, int depth)
+{
+       struct generic_pm_domain *master;
+       struct gpd_link *link;
+       int master_state, ret;
+
+       if (state == genpd->performance_state)
+               return 0;
+
+       /* Propagate to masters of genpd */
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               master = link->master;
+
+               if (!master->set_performance_state)
+                       continue;
+
+               /* Find master's performance state */
+               ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
+                                                        master->opp_table,
+                                                        state);
+               if (unlikely(ret < 0))
+                       goto err;
+
+               master_state = ret;
+
+               genpd_lock_nested(master, depth + 1);
+
+               link->prev_performance_state = link->performance_state;
+               link->performance_state = master_state;
+               master_state = _genpd_reeval_performance_state(master,
+                                               master_state);
+               ret = _genpd_set_performance_state(master, master_state, depth + 1);
+               if (ret)
+                       link->performance_state = link->prev_performance_state;
+
+               genpd_unlock(master);
+
+               if (ret)
+                       goto err;
+       }
+
+       ret = genpd->set_performance_state(genpd, state);
+       if (ret)
+               goto err;
+
+       genpd->performance_state = state;
+       return 0;
+
+err:
+       /* Encountered an error, lets rollback */
+       list_for_each_entry_continue_reverse(link, &genpd->slave_links,
+                                            slave_node) {
+               master = link->master;
+
+               if (!master->set_performance_state)
+                       continue;
+
+               genpd_lock_nested(master, depth + 1);
+
+               master_state = link->prev_performance_state;
+               link->performance_state = master_state;
+
+               master_state = _genpd_reeval_performance_state(master,
+                                               master_state);
+               if (_genpd_set_performance_state(master, master_state, depth + 1)) {
+                       pr_err("%s: Failed to roll back to %d performance state\n",
+                              master->name, master_state);
+               }
+
+               genpd_unlock(master);
+       }
+
+       return ret;
+}
+
 /**
  * dev_pm_genpd_set_performance_state- Set performance state of device's power
  * domain.
@@ -257,10 +378,9 @@ static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
 int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
 {
        struct generic_pm_domain *genpd;
-       struct generic_pm_domain_data *gpd_data, *pd_data;
-       struct pm_domain_data *pdd;
+       struct generic_pm_domain_data *gpd_data;
        unsigned int prev;
-       int ret = 0;
+       int ret;
 
        genpd = dev_to_genpd(dev);
        if (IS_ERR(genpd))
@@ -281,47 +401,11 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
        prev = gpd_data->performance_state;
        gpd_data->performance_state = state;
 
-       /* New requested state is same as Max requested state */
-       if (state == genpd->performance_state)
-               goto unlock;
-
-       /* New requested state is higher than Max requested state */
-       if (state > genpd->performance_state)
-               goto update_state;
-
-       /* Traverse all devices within the domain */
-       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
-               pd_data = to_gpd_data(pdd);
-
-               if (pd_data->performance_state > state)
-                       state = pd_data->performance_state;
-       }
-
-       if (state == genpd->performance_state)
-               goto unlock;
-
-       /*
-        * We aren't propagating performance state changes of a subdomain to its
-        * masters as we don't have hardware that needs it. Over that, the
-        * performance states of subdomain and its masters may not have
-        * one-to-one mapping and would require additional information. We can
-        * get back to this once we have hardware that needs it. For that
-        * reason, we don't have to consider performance state of the subdomains
-        * of genpd here.
-        */
-
-update_state:
-       if (genpd_status_on(genpd)) {
-               ret = genpd->set_performance_state(genpd, state);
-               if (ret) {
-                       gpd_data->performance_state = prev;
-                       goto unlock;
-               }
-       }
-
-       genpd->performance_state = state;
+       state = _genpd_reeval_performance_state(genpd, state);
+       ret = _genpd_set_performance_state(genpd, state, 0);
+       if (ret)
+               gpd_data->performance_state = prev;
 
-unlock:
        genpd_unlock(genpd);
 
        return ret;
@@ -347,15 +431,6 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
                return ret;
 
        elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-
-       if (unlikely(genpd->set_performance_state)) {
-               ret = genpd->set_performance_state(genpd, genpd->performance_state);
-               if (ret) {
-                       pr_warn("%s: Failed to set performance state %d (%d)\n",
-                               genpd->name, genpd->performance_state, ret);
-               }
-       }
-
        if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
                return ret;
 
@@ -1907,12 +1982,21 @@ int of_genpd_add_provider_simple(struct device_node *np,
                                ret);
                        goto unlock;
                }
+
+               /*
+                * Save table for faster processing while setting performance
+                * state.
+                */
+               genpd->opp_table = dev_pm_opp_get_opp_table(&genpd->dev);
+               WARN_ON(!genpd->opp_table);
        }
 
        ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
        if (ret) {
-               if (genpd->set_performance_state)
+               if (genpd->set_performance_state) {
+                       dev_pm_opp_put_opp_table(genpd->opp_table);
                        dev_pm_opp_of_remove_table(&genpd->dev);
+               }
 
                goto unlock;
        }
@@ -1965,6 +2049,13 @@ int of_genpd_add_provider_onecell(struct device_node *np,
                                        i, ret);
                                goto error;
                        }
+
+                       /*
+                        * Save table for faster processing while setting
+                        * performance state.
+                        */
+                       genpd->opp_table = dev_pm_opp_get_opp_table_indexed(&genpd->dev, i);
+                       WARN_ON(!genpd->opp_table);
                }
 
                genpd->provider = &np->fwnode;
@@ -1989,8 +2080,10 @@ error:
                genpd->provider = NULL;
                genpd->has_provider = false;
 
-               if (genpd->set_performance_state)
+               if (genpd->set_performance_state) {
+                       dev_pm_opp_put_opp_table(genpd->opp_table);
                        dev_pm_opp_of_remove_table(&genpd->dev);
+               }
        }
 
        mutex_unlock(&gpd_list_lock);
@@ -2024,6 +2117,7 @@ void of_genpd_del_provider(struct device_node *np)
                                        if (!gpd->set_performance_state)
                                                continue;
 
+                                       dev_pm_opp_put_opp_table(gpd->opp_table);
                                        dev_pm_opp_of_remove_table(&gpd->dev);
                                }
                        }
@@ -2338,7 +2432,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
 struct device *genpd_dev_pm_attach_by_id(struct device *dev,
                                         unsigned int index)
 {
-       struct device *genpd_dev;
+       struct device *virt_dev;
        int num_domains;
        int ret;
 
@@ -2352,31 +2446,31 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
                return NULL;
 
        /* Allocate and register device on the genpd bus. */
-       genpd_dev = kzalloc(sizeof(*genpd_dev), GFP_KERNEL);
-       if (!genpd_dev)
+       virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
+       if (!virt_dev)
                return ERR_PTR(-ENOMEM);
 
-       dev_set_name(genpd_dev, "genpd:%u:%s", index, dev_name(dev));
-       genpd_dev->bus = &genpd_bus_type;
-       genpd_dev->release = genpd_release_dev;
+       dev_set_name(virt_dev, "genpd:%u:%s", index, dev_name(dev));
+       virt_dev->bus = &genpd_bus_type;
+       virt_dev->release = genpd_release_dev;
 
-       ret = device_register(genpd_dev);
+       ret = device_register(virt_dev);
        if (ret) {
-               kfree(genpd_dev);
+               kfree(virt_dev);
                return ERR_PTR(ret);
        }
 
        /* Try to attach the device to the PM domain at the specified index. */
-       ret = __genpd_dev_pm_attach(genpd_dev, dev->of_node, index, false);
+       ret = __genpd_dev_pm_attach(virt_dev, dev->of_node, index, false);
        if (ret < 1) {
-               device_unregister(genpd_dev);
+               device_unregister(virt_dev);
                return ret ? ERR_PTR(ret) : NULL;
        }
 
-       pm_runtime_enable(genpd_dev);
-       genpd_queue_power_off_work(dev_to_genpd(genpd_dev));
+       pm_runtime_enable(virt_dev);
+       genpd_queue_power_off_work(dev_to_genpd(virt_dev));
 
-       return genpd_dev;
+       return virt_dev;
 }
 EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id);
 
@@ -2521,52 +2615,36 @@ int of_genpd_parse_idle_states(struct device_node *dn,
 EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
 
 /**
- * of_genpd_opp_to_performance_state- Gets performance state of device's
- * power domain corresponding to a DT node's "required-opps" property.
+ * pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node.
  *
- * @dev: Device for which the performance-state needs to be found.
- * @np: DT node where the "required-opps" property is present. This can be
- *     the device node itself (if it doesn't have an OPP table) or a node
- *     within the OPP table of a device (if device has an OPP table).
+ * @genpd_dev: Genpd's device for which the performance-state needs to be found.
+ * @opp: struct dev_pm_opp of the OPP for which we need to find performance
+ *     state.
  *
- * Returns performance state corresponding to the "required-opps" property of
- * a DT node. This calls platform specific genpd->opp_to_performance_state()
- * callback to translate power domain OPP to performance state.
+ * Returns performance state encoded in the OPP of the genpd. This calls
+ * platform specific genpd->opp_to_performance_state() callback to translate
+ * power domain OPP to performance state.
  *
  * Returns performance state on success and 0 on failure.
  */
-unsigned int of_genpd_opp_to_performance_state(struct device *dev,
-                                              struct device_node *np)
+unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev,
+                                              struct dev_pm_opp *opp)
 {
-       struct generic_pm_domain *genpd;
-       struct dev_pm_opp *opp;
-       int state = 0;
+       struct generic_pm_domain *genpd = NULL;
+       int state;
 
-       genpd = dev_to_genpd(dev);
-       if (IS_ERR(genpd))
-               return 0;
+       genpd = container_of(genpd_dev, struct generic_pm_domain, dev);
 
-       if (unlikely(!genpd->set_performance_state))
+       if (unlikely(!genpd->opp_to_performance_state))
                return 0;
 
        genpd_lock(genpd);
-
-       opp = of_dev_pm_opp_find_required_opp(&genpd->dev, np);
-       if (IS_ERR(opp)) {
-               dev_err(dev, "Failed to find required OPP: %ld\n",
-                       PTR_ERR(opp));
-               goto unlock;
-       }
-
        state = genpd->opp_to_performance_state(genpd, opp);
-       dev_pm_opp_put(opp);
-
-unlock:
        genpd_unlock(genpd);
 
        return state;
 }
-EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state);
+EXPORT_SYMBOL_GPL(pm_genpd_opp_to_performance_state);
 
 static int __init genpd_bus_init(void)
 {
@@ -2671,7 +2749,7 @@ exit:
        return 0;
 }
 
-static int genpd_summary_show(struct seq_file *s, void *data)
+static int summary_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd;
        int ret = 0;
@@ -2694,7 +2772,7 @@ static int genpd_summary_show(struct seq_file *s, void *data)
        return ret;
 }
 
-static int genpd_status_show(struct seq_file *s, void *data)
+static int status_show(struct seq_file *s, void *data)
 {
        static const char * const status_lookup[] = {
                [GPD_STATE_ACTIVE] = "on",
@@ -2721,7 +2799,7 @@ exit:
        return ret;
 }
 
-static int genpd_sub_domains_show(struct seq_file *s, void *data)
+static int sub_domains_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
        struct gpd_link *link;
@@ -2738,7 +2816,7 @@ static int genpd_sub_domains_show(struct seq_file *s, void *data)
        return ret;
 }
 
-static int genpd_idle_states_show(struct seq_file *s, void *data)
+static int idle_states_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
        unsigned int i;
@@ -2767,7 +2845,7 @@ static int genpd_idle_states_show(struct seq_file *s, void *data)
        return ret;
 }
 
-static int genpd_active_time_show(struct seq_file *s, void *data)
+static int active_time_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
        ktime_t delta = 0;
@@ -2787,7 +2865,7 @@ static int genpd_active_time_show(struct seq_file *s, void *data)
        return ret;
 }
 
-static int genpd_total_idle_time_show(struct seq_file *s, void *data)
+static int total_idle_time_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
        ktime_t delta = 0, total = 0;
@@ -2815,7 +2893,7 @@ static int genpd_total_idle_time_show(struct seq_file *s, void *data)
 }
 
 
-static int genpd_devices_show(struct seq_file *s, void *data)
+static int devices_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
        struct pm_domain_data *pm_data;
@@ -2841,7 +2919,7 @@ static int genpd_devices_show(struct seq_file *s, void *data)
        return ret;
 }
 
-static int genpd_perf_state_show(struct seq_file *s, void *data)
+static int perf_state_show(struct seq_file *s, void *data)
 {
        struct generic_pm_domain *genpd = s->private;
 
@@ -2854,37 +2932,14 @@ static int genpd_perf_state_show(struct seq_file *s, void *data)
        return 0;
 }
 
-#define define_genpd_open_function(name) \
-static int genpd_##name##_open(struct inode *inode, struct file *file) \
-{ \
-       return single_open(file, genpd_##name##_show, inode->i_private); \
-}
-
-define_genpd_open_function(summary);
-define_genpd_open_function(status);
-define_genpd_open_function(sub_domains);
-define_genpd_open_function(idle_states);
-define_genpd_open_function(active_time);
-define_genpd_open_function(total_idle_time);
-define_genpd_open_function(devices);
-define_genpd_open_function(perf_state);
-
-#define define_genpd_debugfs_fops(name) \
-static const struct file_operations genpd_##name##_fops = { \
-       .open = genpd_##name##_open, \
-       .read = seq_read, \
-       .llseek = seq_lseek, \
-       .release = single_release, \
-}
-
-define_genpd_debugfs_fops(summary);
-define_genpd_debugfs_fops(status);
-define_genpd_debugfs_fops(sub_domains);
-define_genpd_debugfs_fops(idle_states);
-define_genpd_debugfs_fops(active_time);
-define_genpd_debugfs_fops(total_idle_time);
-define_genpd_debugfs_fops(devices);
-define_genpd_debugfs_fops(perf_state);
+DEFINE_SHOW_ATTRIBUTE(summary);
+DEFINE_SHOW_ATTRIBUTE(status);
+DEFINE_SHOW_ATTRIBUTE(sub_domains);
+DEFINE_SHOW_ATTRIBUTE(idle_states);
+DEFINE_SHOW_ATTRIBUTE(active_time);
+DEFINE_SHOW_ATTRIBUTE(total_idle_time);
+DEFINE_SHOW_ATTRIBUTE(devices);
+DEFINE_SHOW_ATTRIBUTE(perf_state);
 
 static int __init genpd_debug_init(void)
 {
@@ -2897,7 +2952,7 @@ static int __init genpd_debug_init(void)
                return -ENOMEM;
 
        d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
-                       genpd_debugfs_dir, NULL, &genpd_summary_fops);
+                       genpd_debugfs_dir, NULL, &summary_fops);
        if (!d)
                return -ENOMEM;
 
@@ -2907,20 +2962,20 @@ static int __init genpd_debug_init(void)
                        return -ENOMEM;
 
                debugfs_create_file("current_state", 0444,
-                               d, genpd, &genpd_status_fops);
+                               d, genpd, &status_fops);
                debugfs_create_file("sub_domains", 0444,
-                               d, genpd, &genpd_sub_domains_fops);
+                               d, genpd, &sub_domains_fops);
                debugfs_create_file("idle_states", 0444,
-                               d, genpd, &genpd_idle_states_fops);
+                               d, genpd, &idle_states_fops);
                debugfs_create_file("active_time", 0444,
-                               d, genpd, &genpd_active_time_fops);
+                               d, genpd, &active_time_fops);
                debugfs_create_file("total_idle_time", 0444,
-                               d, genpd, &genpd_total_idle_time_fops);
+                               d, genpd, &total_idle_time_fops);
                debugfs_create_file("devices", 0444,
-                               d, genpd, &genpd_devices_fops);
+                               d, genpd, &devices_fops);
                if (genpd->set_performance_state)
                        debugfs_create_file("perf_state", 0444,
-                                           d, genpd, &genpd_perf_state_fops);
+                                           d, genpd, &perf_state_fops);
        }
 
        return 0;
index beb85c31f3fa3b9f997a4f21c72891f40e7535ed..70624695b6d55eeab9fe00584042145ef5ac6c3a 100644 (file)
@@ -8,6 +8,8 @@
  */
 
 #include <linux/sched/mm.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
 #include <linux/export.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
@@ -93,7 +95,7 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status)
 static void pm_runtime_deactivate_timer(struct device *dev)
 {
        if (dev->power.timer_expires > 0) {
-               del_timer(&dev->power.suspend_timer);
+               hrtimer_cancel(&dev->power.suspend_timer);
                dev->power.timer_expires = 0;
        }
 }
@@ -124,12 +126,11 @@ static void pm_runtime_cancel_pending(struct device *dev)
  * This function may be called either with or without dev->power.lock held.
  * Either way it can be racy, since power.last_busy may be updated at any time.
  */
-unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
+u64 pm_runtime_autosuspend_expiration(struct device *dev)
 {
        int autosuspend_delay;
-       long elapsed;
-       unsigned long last_busy;
-       unsigned long expires = 0;
+       u64 last_busy, expires = 0;
+       u64 now = ktime_to_ns(ktime_get());
 
        if (!dev->power.use_autosuspend)
                goto out;
@@ -139,19 +140,9 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
                goto out;
 
        last_busy = READ_ONCE(dev->power.last_busy);
-       elapsed = jiffies - last_busy;
-       if (elapsed < 0)
-               goto out;       /* jiffies has wrapped around. */
 
-       /*
-        * If the autosuspend_delay is >= 1 second, align the timer by rounding
-        * up to the nearest second.
-        */
-       expires = last_busy + msecs_to_jiffies(autosuspend_delay);
-       if (autosuspend_delay >= 1000)
-               expires = round_jiffies(expires);
-       expires += !expires;
-       if (elapsed >= expires - last_busy)
+       expires = last_busy + autosuspend_delay * NSEC_PER_MSEC;
+       if (expires <= now)
                expires = 0;    /* Already expired. */
 
  out:
@@ -515,7 +506,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        /* If the autosuspend_delay time hasn't expired yet, reschedule. */
        if ((rpmflags & RPM_AUTO)
            && dev->power.runtime_status != RPM_SUSPENDING) {
-               unsigned long expires = pm_runtime_autosuspend_expiration(dev);
+               u64 expires = pm_runtime_autosuspend_expiration(dev);
 
                if (expires != 0) {
                        /* Pending requests need to be canceled. */
@@ -528,10 +519,20 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                         * expire; pm_suspend_timer_fn() will take care of the
                         * rest.
                         */
-                       if (!(dev->power.timer_expires && time_before_eq(
-                           dev->power.timer_expires, expires))) {
+                       if (!(dev->power.timer_expires &&
+                                       dev->power.timer_expires <= expires)) {
+                               /*
+                                * We add a slack of 25% to gather wakeups
+                                * without sacrificing the granularity.
+                                */
+                               u64 slack = READ_ONCE(dev->power.autosuspend_delay) *
+                                                   (NSEC_PER_MSEC >> 2);
+
                                dev->power.timer_expires = expires;
-                               mod_timer(&dev->power.suspend_timer, expires);
+                               hrtimer_start_range_ns(&dev->power.suspend_timer,
+                                               ns_to_ktime(expires),
+                                               slack,
+                                               HRTIMER_MODE_ABS);
                        }
                        dev->power.timer_autosuspends = 1;
                        goto out;
@@ -895,23 +896,25 @@ static void pm_runtime_work(struct work_struct *work)
  *
  * Check if the time is right and queue a suspend request.
  */
-static void pm_suspend_timer_fn(struct timer_list *t)
+static enum hrtimer_restart  pm_suspend_timer_fn(struct hrtimer *timer)
 {
-       struct device *dev = from_timer(dev, t, power.suspend_timer);
+       struct device *dev = container_of(timer, struct device, power.suspend_timer);
        unsigned long flags;
-       unsigned long expires;
+       u64 expires;
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
        expires = dev->power.timer_expires;
        /* If 'expire' is after 'jiffies' we've been called too early. */
-       if (expires > 0 && !time_after(expires, jiffies)) {
+       if (expires > 0 && expires < ktime_to_ns(ktime_get())) {
                dev->power.timer_expires = 0;
                rpm_suspend(dev, dev->power.timer_autosuspends ?
                    (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
        }
 
        spin_unlock_irqrestore(&dev->power.lock, flags);
+
+       return HRTIMER_NORESTART;
 }
 
 /**
@@ -922,6 +925,7 @@ static void pm_suspend_timer_fn(struct timer_list *t)
 int pm_schedule_suspend(struct device *dev, unsigned int delay)
 {
        unsigned long flags;
+       ktime_t expires;
        int retval;
 
        spin_lock_irqsave(&dev->power.lock, flags);
@@ -938,10 +942,10 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)
        /* Other scheduled or pending requests need to be canceled. */
        pm_runtime_cancel_pending(dev);
 
-       dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
-       dev->power.timer_expires += !dev->power.timer_expires;
+       expires = ktime_add(ktime_get(), ms_to_ktime(delay));
+       dev->power.timer_expires = ktime_to_ns(expires);
        dev->power.timer_autosuspends = 0;
-       mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
+       hrtimer_start(&dev->power.suspend_timer, expires, HRTIMER_MODE_ABS);
 
  out:
        spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -1491,7 +1495,8 @@ void pm_runtime_init(struct device *dev)
        INIT_WORK(&dev->power.work, pm_runtime_work);
 
        dev->power.timer_expires = 0;
-       timer_setup(&dev->power.suspend_timer, pm_suspend_timer_fn, 0);
+       hrtimer_init(&dev->power.suspend_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       dev->power.suspend_timer.function = pm_suspend_timer_fn;
 
        init_waitqueue_head(&dev->power.wait_queue);
 }
index 4e1131ef85ae109b7424cbf076d726afd611701a..688f10227793d73a687416ad2a3aa69fab53f3a6 100644 (file)
@@ -114,6 +114,17 @@ config ARM_QCOM_CPUFREQ_KRYO
 
          If in doubt, say N.
 
+config ARM_QCOM_CPUFREQ_HW
+       tristate "QCOM CPUFreq HW driver"
+       depends on ARCH_QCOM || COMPILE_TEST
+       help
+         Support for the CPUFreq HW driver.
+         Some QCOM chipsets have a HW engine to offload the steps
+         necessary for changing the frequency of the CPUs. Firmware loaded
+         in this engine exposes a programming interface to the OS.
+         The driver implements the cpufreq interface for this HW engine.
+         Say Y if you want to support CPUFreq HW.
+
 config ARM_S3C_CPUFREQ
        bool
        help
index d5ee4562ed06b44f17c7b4f149d4fb4d1ecd9683..08c071be24912f86514907352aa82d14b625db8d 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_MACH_MVEBU_V7)           += mvebu-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)    += omap-cpufreq.o
 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)       += pxa2xx-cpufreq.o
 obj-$(CONFIG_PXA3xx)                   += pxa3xx-cpufreq.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW)      += qcom-cpufreq-hw.o
 obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO)    += qcom-cpufreq-kryo.o
 obj-$(CONFIG_ARM_S3C2410_CPUFREQ)      += s3c2410-cpufreq.o
 obj-$(CONFIG_ARM_S3C2412_CPUFREQ)      += s3c2412-cpufreq.o
index dbf82f36d270dfd8fd5bd51b4db5f261c37930c4..33c309a08c64d51aaa3792f5b762837b2f69db5c 100644 (file)
@@ -123,8 +123,6 @@ static void nforce2_write_pll(int pll)
        /* Now write the value in all 64 registers */
        for (temp = 0; temp <= 0x3f; temp++)
                pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
-
-       return;
 }
 
 /**
@@ -438,4 +436,3 @@ static void __exit nforce2_exit(void)
 
 module_init(nforce2_init);
 module_exit(nforce2_exit);
-
index dd5440d3372d21528f0df5715fcc03e656863b1f..80c5bf590acbfc0f5ee9632511b261fe3e433d7a 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 #include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <asm/io.h>
 #include <linux/uaccess.h>
 #include <asm/pal.h>
@@ -28,7 +27,6 @@ MODULE_AUTHOR("Venkatesh Pallipadi");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
 MODULE_LICENSE("GPL");
 
-
 struct cpufreq_acpi_io {
        struct acpi_processor_performance       acpi_data;
        unsigned int                            resume;
@@ -348,10 +346,7 @@ acpi_cpufreq_exit (void)
        pr_debug("acpi_cpufreq_exit\n");
 
        cpufreq_unregister_driver(&acpi_cpufreq_driver);
-       return;
 }
 
-
 late_initcall(acpi_cpufreq_init);
 module_exit(acpi_cpufreq_exit);
-
index d8c3595e90236e5f9d87ca9b5f55a7cbdb76ccdc..9fedf627e000d5338b3c97b1f0760c8b67dbb28d 100644 (file)
@@ -177,22 +177,16 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
        /* scaling down?  scale voltage after frequency */
        if (new_freq < old_freq) {
                ret = regulator_set_voltage_tol(arm_reg, volt, 0);
-               if (ret) {
+               if (ret)
                        dev_warn(cpu_dev,
                                 "failed to scale vddarm down: %d\n", ret);
-                       ret = 0;
-               }
                ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
-               if (ret) {
+               if (ret)
                        dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);
-                       ret = 0;
-               }
                if (!IS_ERR(pu_reg)) {
                        ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
-                       if (ret) {
+                       if (ret)
                                dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret);
-                               ret = 0;
-                       }
                }
        }
 
@@ -411,9 +405,10 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
        if (of_machine_is_compatible("fsl,imx6ul") ||
            of_machine_is_compatible("fsl,imx6ull")) {
                ret = imx6ul_opp_check_speed_grading(cpu_dev);
-               if (ret == -EPROBE_DEFER)
-                       return ret;
                if (ret) {
+                       if (ret == -EPROBE_DEFER)
+                               return ret;
+
                        dev_err(cpu_dev, "failed to read ocotp: %d\n",
                                ret);
                        return ret;
index 9578312e43f2f1ef5f10327e49225b61897f2a4b..106402b899611872f2989e781ca9c0848f9e4fc0 100644 (file)
@@ -830,6 +830,28 @@ skip_epp:
        wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
 }
 
+static void intel_pstate_hwp_force_min_perf(int cpu)
+{
+       u64 value;
+       int min_perf;
+
+       value = all_cpu_data[cpu]->hwp_req_cached;
+       value &= ~GENMASK_ULL(31, 0);
+       min_perf = HWP_LOWEST_PERF(all_cpu_data[cpu]->hwp_cap_cached);
+
+       /* Set hwp_max = hwp_min */
+       value |= HWP_MAX_PERF(min_perf);
+       value |= HWP_MIN_PERF(min_perf);
+
+       /* Set EPP/EPB to min */
+       if (static_cpu_has(X86_FEATURE_HWP_EPP))
+               value |= HWP_ENERGY_PERF_PREFERENCE(HWP_EPP_POWERSAVE);
+       else
+               intel_pstate_set_epb(cpu, HWP_EPP_BALANCE_POWERSAVE);
+
+       wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
+}
+
 static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy)
 {
        struct cpudata *cpu_data = all_cpu_data[policy->cpu];
@@ -2084,10 +2106,12 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
        pr_debug("CPU %d exiting\n", policy->cpu);
 
        intel_pstate_clear_update_util_hook(policy->cpu);
-       if (hwp_active)
+       if (hwp_active) {
                intel_pstate_hwp_save_state(policy);
-       else
+               intel_pstate_hwp_force_min_perf(policy->cpu);
+       } else {
                intel_cpufreq_stop_cpu(policy);
+       }
 }
 
 static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
index be623dd7b9f2a38bdd814391439a393f7137e836..1d32a863332d3135dbaf14da48b3c957db8ed0f4 100644 (file)
@@ -411,6 +411,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
                pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
                pfunc_vdnap0_complete =
                        pmf_find_function(root, "slewing-done");
+               of_node_put(root);
                if (pfunc_set_vdnap0 == NULL ||
                    pfunc_vdnap0_complete == NULL) {
                        pr_err("Can't find required platform function\n");
index bf6519cf64bc2e040b6e004f1771e47e5691c7e0..7e7ad3879c4e0510ee1de789815fec26ad807040 100644 (file)
@@ -253,18 +253,18 @@ static int init_powernv_pstates(void)
 
        if (of_property_read_u32(power_mgt, "ibm,pstate-min", &pstate_min)) {
                pr_warn("ibm,pstate-min node not found\n");
-               return -ENODEV;
+               goto out;
        }
 
        if (of_property_read_u32(power_mgt, "ibm,pstate-max", &pstate_max)) {
                pr_warn("ibm,pstate-max node not found\n");
-               return -ENODEV;
+               goto out;
        }
 
        if (of_property_read_u32(power_mgt, "ibm,pstate-nominal",
                                 &pstate_nominal)) {
                pr_warn("ibm,pstate-nominal not found\n");
-               return -ENODEV;
+               goto out;
        }
 
        if (of_property_read_u32(power_mgt, "ibm,pstate-ultra-turbo",
@@ -293,14 +293,14 @@ next:
        pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids);
        if (!pstate_ids) {
                pr_warn("ibm,pstate-ids not found\n");
-               return -ENODEV;
+               goto out;
        }
 
        pstate_freqs = of_get_property(power_mgt, "ibm,pstate-frequencies-mhz",
                                      &len_freqs);
        if (!pstate_freqs) {
                pr_warn("ibm,pstate-frequencies-mhz not found\n");
-               return -ENODEV;
+               goto out;
        }
 
        if (len_ids != len_freqs) {
@@ -311,7 +311,7 @@ next:
        nr_pstates = min(len_ids, len_freqs) / sizeof(u32);
        if (!nr_pstates) {
                pr_warn("No PStates found\n");
-               return -ENODEV;
+               goto out;
        }
 
        powernv_pstate_info.nr_pstates = nr_pstates;
@@ -352,7 +352,12 @@ next:
 
        /* End of list marker entry */
        powernv_freqs[i].frequency = CPUFREQ_TABLE_END;
+
+       of_node_put(power_mgt);
        return 0;
+out:
+       of_node_put(power_mgt);
+       return -ENODEV;
 }
 
 /* Returns the CPU frequency corresponding to the pstate_id. */
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
new file mode 100644 (file)
index 0000000..d83939a
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#define LUT_MAX_ENTRIES                        40U
+#define LUT_SRC                                GENMASK(31, 30)
+#define LUT_L_VAL                      GENMASK(7, 0)
+#define LUT_CORE_COUNT                 GENMASK(18, 16)
+#define LUT_ROW_SIZE                   32
+#define CLK_HW_DIV                     2
+
+/* Register offsets */
+#define REG_ENABLE                     0x0
+#define REG_LUT_TABLE                  0x110
+#define REG_PERF_STATE                 0x920
+
+static unsigned long cpu_hw_rate, xo_rate;
+static struct platform_device *global_pdev;
+
+static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
+                                       unsigned int index)
+{
+       void __iomem *perf_state_reg = policy->driver_data;
+
+       writel_relaxed(index, perf_state_reg);
+
+       return 0;
+}
+
+static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
+{
+       void __iomem *perf_state_reg;
+       struct cpufreq_policy *policy;
+       unsigned int index;
+
+       policy = cpufreq_cpu_get_raw(cpu);
+       if (!policy)
+               return 0;
+
+       perf_state_reg = policy->driver_data;
+
+       index = readl_relaxed(perf_state_reg);
+       index = min(index, LUT_MAX_ENTRIES - 1);
+
+       return policy->freq_table[index].frequency;
+}
+
+static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
+                                               unsigned int target_freq)
+{
+       void __iomem *perf_state_reg = policy->driver_data;
+       int index;
+
+       index = policy->cached_resolved_idx;
+       if (index < 0)
+               return 0;
+
+       writel_relaxed(index, perf_state_reg);
+
+       return policy->freq_table[index].frequency;
+}
+
+static int qcom_cpufreq_hw_read_lut(struct device *dev,
+                                   struct cpufreq_policy *policy,
+                                   void __iomem *base)
+{
+       u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq;
+       unsigned int max_cores = cpumask_weight(policy->cpus);
+       struct cpufreq_frequency_table  *table;
+
+       table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       for (i = 0; i < LUT_MAX_ENTRIES; i++) {
+               data = readl_relaxed(base + REG_LUT_TABLE + i * LUT_ROW_SIZE);
+               src = FIELD_GET(LUT_SRC, data);
+               lval = FIELD_GET(LUT_L_VAL, data);
+               core_count = FIELD_GET(LUT_CORE_COUNT, data);
+
+               if (src)
+                       freq = xo_rate * lval / 1000;
+               else
+                       freq = cpu_hw_rate / 1000;
+
+               /* Ignore boosts in the middle of the table */
+               if (core_count != max_cores) {
+                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               } else {
+                       table[i].frequency = freq;
+                       dev_dbg(dev, "index=%d freq=%d, core_count %d\n", i,
+                               freq, core_count);
+               }
+
+               /*
+                * Two of the same frequencies with the same core counts means
+                * end of table
+                */
+               if (i > 0 && prev_freq == freq && prev_cc == core_count) {
+                       struct cpufreq_frequency_table *prev = &table[i - 1];
+
+                       /*
+                        * Only treat the last frequency that might be a boost
+                        * as the boost frequency
+                        */
+                       if (prev_cc != max_cores) {
+                               prev->frequency = prev_freq;
+                               prev->flags = CPUFREQ_BOOST_FREQ;
+                       }
+
+                       break;
+               }
+
+               prev_cc = core_count;
+               prev_freq = freq;
+       }
+
+       table[i].frequency = CPUFREQ_TABLE_END;
+       policy->freq_table = table;
+
+       return 0;
+}
+
+static void qcom_get_related_cpus(int index, struct cpumask *m)
+{
+       struct device_node *cpu_np;
+       struct of_phandle_args args;
+       int cpu, ret;
+
+       for_each_possible_cpu(cpu) {
+               cpu_np = of_cpu_device_node_get(cpu);
+               if (!cpu_np)
+                       continue;
+
+               ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
+                                                "#freq-domain-cells", 0,
+                                                &args);
+               of_node_put(cpu_np);
+               if (ret < 0)
+                       continue;
+
+               if (index == args.args[0])
+                       cpumask_set_cpu(cpu, m);
+       }
+}
+
+static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
+{
+       struct device *dev = &global_pdev->dev;
+       struct of_phandle_args args;
+       struct device_node *cpu_np;
+       struct resource *res;
+       void __iomem *base;
+       int ret, index;
+
+       cpu_np = of_cpu_device_node_get(policy->cpu);
+       if (!cpu_np)
+               return -EINVAL;
+
+       ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
+                                        "#freq-domain-cells", 0, &args);
+       of_node_put(cpu_np);
+       if (ret)
+               return ret;
+
+       index = args.args[0];
+
+       res = platform_get_resource(global_pdev, IORESOURCE_MEM, index);
+       if (!res)
+               return -ENODEV;
+
+       base = devm_ioremap(dev, res->start, resource_size(res));
+       if (!base)
+               return -ENOMEM;
+
+       /* HW should be in enabled state to proceed */
+       if (!(readl_relaxed(base + REG_ENABLE) & 0x1)) {
+               dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index);
+               ret = -ENODEV;
+               goto error;
+       }
+
+       qcom_get_related_cpus(index, policy->cpus);
+       if (!cpumask_weight(policy->cpus)) {
+               dev_err(dev, "Domain-%d failed to get related CPUs\n", index);
+               ret = -ENOENT;
+               goto error;
+       }
+
+       policy->driver_data = base + REG_PERF_STATE;
+
+       ret = qcom_cpufreq_hw_read_lut(dev, policy, base);
+       if (ret) {
+               dev_err(dev, "Domain-%d failed to read LUT\n", index);
+               goto error;
+       }
+
+       policy->fast_switch_possible = true;
+
+       return 0;
+error:
+       devm_iounmap(dev, base);
+       return ret;
+}
+
+static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
+{
+       void __iomem *base = policy->driver_data - REG_PERF_STATE;
+
+       kfree(policy->freq_table);
+       devm_iounmap(&global_pdev->dev, base);
+
+       return 0;
+}
+
+static struct freq_attr *qcom_cpufreq_hw_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       &cpufreq_freq_attr_scaling_boost_freqs,
+       NULL
+};
+
+static struct cpufreq_driver cpufreq_qcom_hw_driver = {
+       .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                         CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
+       .verify         = cpufreq_generic_frequency_table_verify,
+       .target_index   = qcom_cpufreq_hw_target_index,
+       .get            = qcom_cpufreq_hw_get,
+       .init           = qcom_cpufreq_hw_cpu_init,
+       .exit           = qcom_cpufreq_hw_cpu_exit,
+       .fast_switch    = qcom_cpufreq_hw_fast_switch,
+       .name           = "qcom-cpufreq-hw",
+       .attr           = qcom_cpufreq_hw_attr,
+};
+
+static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
+{
+       struct clk *clk;
+       int ret;
+
+       clk = clk_get(&pdev->dev, "xo");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       xo_rate = clk_get_rate(clk);
+       clk_put(clk);
+
+       clk = clk_get(&pdev->dev, "alternate");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       cpu_hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
+       clk_put(clk);
+
+       global_pdev = pdev;
+
+       ret = cpufreq_register_driver(&cpufreq_qcom_hw_driver);
+       if (ret)
+               dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n");
+       else
+               dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n");
+
+       return ret;
+}
+
+static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
+{
+       return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
+}
+
+static const struct of_device_id qcom_cpufreq_hw_match[] = {
+       { .compatible = "qcom,cpufreq-hw" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
+
+static struct platform_driver qcom_cpufreq_hw_driver = {
+       .probe = qcom_cpufreq_hw_driver_probe,
+       .remove = qcom_cpufreq_hw_driver_remove,
+       .driver = {
+               .name = "qcom-cpufreq-hw",
+               .of_match_table = qcom_cpufreq_hw_match,
+       },
+};
+
+static int __init qcom_cpufreq_hw_init(void)
+{
+       return platform_driver_register(&qcom_cpufreq_hw_driver);
+}
+subsys_initcall(qcom_cpufreq_hw_init);
+
+static void __exit qcom_cpufreq_hw_exit(void)
+{
+       platform_driver_unregister(&qcom_cpufreq_hw_driver);
+}
+module_exit(qcom_cpufreq_hw_exit);
+
+MODULE_DESCRIPTION("QCOM CPUFREQ HW Driver");
+MODULE_LICENSE("GPL v2");
index 4d976e8dbb2f4135819a19bbf4ab4b510f8f3d4d..0df87b6480fe7d54b108f551a36136a245634508 100644 (file)
@@ -63,18 +63,7 @@ static int board_show(struct seq_file *seq, void *p)
        return 0;
 }
 
-static int fops_board_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, board_show, NULL);
-}
-
-static const struct file_operations fops_board = {
-       .open           = fops_board_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .owner          = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(board);
 
 static int info_show(struct seq_file *seq, void *p)
 {
@@ -105,18 +94,7 @@ static int info_show(struct seq_file *seq, void *p)
        return 0;
 }
 
-static int fops_info_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, info_show, NULL);
-}
-
-static const struct file_operations fops_info = {
-       .open           = fops_info_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .owner          = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(info);
 
 static int io_show(struct seq_file *seq, void *p)
 {
@@ -162,19 +140,7 @@ static int io_show(struct seq_file *seq, void *p)
        return 0;
 }
 
-static int fops_io_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, io_show, NULL);
-}
-
-static const struct file_operations fops_io = {
-       .open           = fops_io_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .owner          = THIS_MODULE,
-};
-
+DEFINE_SHOW_ATTRIBUTE(io);
 
 static int __init s3c_freq_debugfs_init(void)
 {
@@ -185,13 +151,13 @@ static int __init s3c_freq_debugfs_init(void)
        }
 
        dbgfs_file_io = debugfs_create_file("io-timing", S_IRUGO, dbgfs_root,
-                                           NULL, &fops_io);
+                                           NULL, &io_fops);
 
        dbgfs_file_info = debugfs_create_file("info", S_IRUGO, dbgfs_root,
-                                             NULL, &fops_info);
+                                             NULL, &info_fops);
 
        dbgfs_file_board = debugfs_create_file("board", S_IRUGO, dbgfs_root,
-                                              NULL, &fops_board);
+                                              NULL, &board_fops);
 
        return 0;
 }
index db2ede565f1aab2228d818d38ee41a8a358a3fc8..b44476a1b7ad8a8806e63f48897b383e736d1677 100644 (file)
@@ -167,6 +167,7 @@ static int __init bl_idle_init(void)
 {
        int ret;
        struct device_node *root = of_find_node_by_path("/");
+       const struct of_device_id *match_id;
 
        if (!root)
                return -ENODEV;
@@ -174,7 +175,11 @@ static int __init bl_idle_init(void)
        /*
         * Initialize the driver just for a compliant set of machines
         */
-       if (!of_match_node(compatible_machine_match, root))
+       match_id = of_match_node(compatible_machine_match, root);
+
+       of_node_put(root);
+
+       if (!match_id)
                return -ENODEV;
 
        if (!mcpm_is_available())
index 4a97446f66d836bbf4129454420108313872b26e..7f108309e871ea63fbc16b1b896e3ef4cd443216 100644 (file)
@@ -202,7 +202,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
        struct cpuidle_state *target_state = &drv->states[index];
        bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
        ktime_t time_start, time_end;
-       s64 diff;
 
        /*
         * Tell the time framework to switch to a broadcast timer because our
@@ -248,6 +247,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                local_irq_enable();
 
        if (entered_state >= 0) {
+               s64 diff, delay = drv->states[entered_state].exit_latency;
+               int i;
+
                /*
                 * Update cpuidle counters
                 * This can be moved to within driver enter routine,
@@ -260,6 +262,33 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                dev->last_residency = (int)diff;
                dev->states_usage[entered_state].time += dev->last_residency;
                dev->states_usage[entered_state].usage++;
+
+               if (diff < drv->states[entered_state].target_residency) {
+                       for (i = entered_state - 1; i >= 0; i--) {
+                               if (drv->states[i].disabled ||
+                                   dev->states_usage[i].disable)
+                                       continue;
+
+                               /* Shallower states are enabled, so update. */
+                               dev->states_usage[entered_state].above++;
+                               break;
+                       }
+               } else if (diff > delay) {
+                       for (i = entered_state + 1; i < drv->state_count; i++) {
+                               if (drv->states[i].disabled ||
+                                   dev->states_usage[i].disable)
+                                       continue;
+
+                               /*
+                                * Update if a deeper state would have been a
+                                * better match for the observed idle duration.
+                                */
+                               if (diff - delay >= drv->states[i].target_residency)
+                                       dev->states_usage[entered_state].below++;
+
+                               break;
+                       }
+               }
        } else {
                dev->last_residency = 0;
        }
@@ -702,4 +731,5 @@ static int __init cpuidle_init(void)
 }
 
 module_param(off, int, 0444);
+module_param_string(governor, param_governor, CPUIDLE_NAME_LEN, 0444);
 core_initcall(cpuidle_init);
index 2965ab32a583f769ea919c30427eb7255b04909a..d6613101af9246ee112df42c36a5abd2d63ceb56 100644 (file)
@@ -7,6 +7,7 @@
 #define __DRIVER_CPUIDLE_H
 
 /* For internal use only */
+extern char param_governor[];
 extern struct cpuidle_governor *cpuidle_curr_governor;
 extern struct list_head cpuidle_governors;
 extern struct list_head cpuidle_detected_devices;
index 9fed1b82929278d08d3aa8ef26c77ebd705fbd1f..bb93e5cf6a4ae5ca386ef8bb67fbe22d6d8c651d 100644 (file)
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/mutex.h>
+#include <linux/module.h>
 #include <linux/pm_qos.h>
 
 #include "cpuidle.h"
 
+char param_governor[CPUIDLE_NAME_LEN];
+
 LIST_HEAD(cpuidle_governors);
 struct cpuidle_governor *cpuidle_curr_governor;
 
@@ -86,9 +89,11 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
        mutex_lock(&cpuidle_lock);
        if (__cpuidle_find_governor(gov->name) == NULL) {
                ret = 0;
-               list_add_tail(&gov->governor_list, &cpuidle_governors);
                if (!cpuidle_curr_governor ||
-                   cpuidle_curr_governor->rating < gov->rating)
+                   !strncasecmp(param_governor, gov->name, CPUIDLE_NAME_LEN) ||
+                   (cpuidle_curr_governor->rating < gov->rating &&
+                    strncasecmp(param_governor, cpuidle_curr_governor->name,
+                                CPUIDLE_NAME_LEN)))
                        cpuidle_switch_governor(gov);
        }
        mutex_unlock(&cpuidle_lock);
index 85792d371add6558ffd429da2b0b6638c64ac921..b17d153e724fd3c693930ad67583e4804a8b580d 100644 (file)
@@ -20,8 +20,17 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev,
 
        local_irq_enable();
        if (!current_set_polling_and_test()) {
-               u64 limit = (u64)drv->states[1].target_residency * NSEC_PER_USEC;
                unsigned int loop_count = 0;
+               u64 limit = TICK_USEC;
+               int i;
+
+               for (i = 1; i < drv->state_count; i++) {
+                       if (drv->states[i].disabled || dev->states_usage[i].disable)
+                               continue;
+
+                       limit = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
+                       break;
+               }
 
                while (!need_resched()) {
                        cpu_relax();
index e754c7aae7f7bba331459f2500c7339e2321a7ba..eb20adb5de2349c059d328bb24d75696b2e1890e 100644 (file)
@@ -301,6 +301,8 @@ define_show_state_str_function(name)
 define_show_state_str_function(desc)
 define_show_state_ull_function(disable)
 define_store_state_ull_function(disable)
+define_show_state_ull_function(above)
+define_show_state_ull_function(below)
 
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
@@ -310,6 +312,8 @@ define_one_state_ro(power, show_state_power_usage);
 define_one_state_ro(usage, show_state_usage);
 define_one_state_ro(time, show_state_time);
 define_one_state_rw(disable, show_state_disable, store_state_disable);
+define_one_state_ro(above, show_state_above);
+define_one_state_ro(below, show_state_below);
 
 static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_name.attr,
@@ -320,6 +324,8 @@ static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_usage.attr,
        &attr_time.attr,
        &attr_disable.attr,
+       &attr_above.attr,
+       &attr_below.attr,
        NULL
 };
 
index 7725b6ee14efb2ecc89d9c0822aa19903284d3f5..59bb67d5a7cede7198c652b53550941754cb9a3e 100644 (file)
@@ -153,6 +153,11 @@ struct chtls_dev {
        unsigned int cdev_state;
 };
 
+struct chtls_listen {
+       struct chtls_dev *cdev;
+       struct sock *sk;
+};
+
 struct chtls_hws {
        struct sk_buff_head sk_recv_queue;
        u8 txqid;
@@ -215,6 +220,8 @@ struct chtls_sock {
        u16 resv2;
        u32 delack_mode;
        u32 delack_seq;
+       u32 snd_win;
+       u32 rcv_win;
 
        void *passive_reap_next;        /* placeholder for passive */
        struct chtls_hws tlshws;
index 20209e29f814659227ef11861571c9ed6d7ace9d..931b96c220af973f450cf0b34a37924d40656e9f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kallsyms.h>
 #include <linux/kprobes.h>
 #include <linux/if_vlan.h>
+#include <net/inet_common.h>
 #include <net/tcp.h>
 #include <net/dst.h>
 
@@ -887,24 +888,6 @@ static unsigned int chtls_select_mss(const struct chtls_sock *csk,
        return mtu_idx;
 }
 
-static unsigned int select_rcv_wnd(struct chtls_sock *csk)
-{
-       unsigned int rcvwnd;
-       unsigned int wnd;
-       struct sock *sk;
-
-       sk = csk->sk;
-       wnd = tcp_full_space(sk);
-
-       if (wnd < MIN_RCV_WND)
-               wnd = MIN_RCV_WND;
-
-       rcvwnd = MAX_RCV_WND;
-
-       csk_set_flag(csk, CSK_UPDATE_RCV_WND);
-       return min(wnd, rcvwnd);
-}
-
 static unsigned int select_rcv_wscale(int space, int wscale_ok, int win_clamp)
 {
        int wscale = 0;
@@ -951,7 +934,7 @@ static void chtls_pass_accept_rpl(struct sk_buff *skb,
        csk->mtu_idx = chtls_select_mss(csk, dst_mtu(__sk_dst_get(sk)),
                                        req);
        opt0 = TCAM_BYPASS_F |
-              WND_SCALE_V((tp)->rx_opt.rcv_wscale) |
+              WND_SCALE_V(RCV_WSCALE(tp)) |
               MSS_IDX_V(csk->mtu_idx) |
               L2T_IDX_V(csk->l2t_entry->idx) |
               NAGLE_V(!(tp->nonagle & TCP_NAGLE_OFF)) |
@@ -1005,6 +988,25 @@ static int chtls_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
+static void chtls_set_tcp_window(struct chtls_sock *csk)
+{
+       struct net_device *ndev = csk->egress_dev;
+       struct port_info *pi = netdev_priv(ndev);
+       unsigned int linkspeed;
+       u8 scale;
+
+       linkspeed = pi->link_cfg.speed;
+       scale = linkspeed / SPEED_10000;
+#define CHTLS_10G_RCVWIN (256 * 1024)
+       csk->rcv_win = CHTLS_10G_RCVWIN;
+       if (scale)
+               csk->rcv_win *= scale;
+#define CHTLS_10G_SNDWIN (256 * 1024)
+       csk->snd_win = CHTLS_10G_SNDWIN;
+       if (scale)
+               csk->snd_win *= scale;
+}
+
 static struct sock *chtls_recv_sock(struct sock *lsk,
                                    struct request_sock *oreq,
                                    void *network_hdr,
@@ -1067,6 +1069,9 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
        csk->port_id = port_id;
        csk->egress_dev = ndev;
        csk->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
+       chtls_set_tcp_window(csk);
+       tp->rcv_wnd = csk->rcv_win;
+       csk->sndbuf = csk->snd_win;
        csk->ulp_mode = ULP_MODE_TLS;
        step = cdev->lldi->nrxq / cdev->lldi->nchan;
        csk->rss_qid = cdev->lldi->rxq_ids[port_id * step];
@@ -1076,9 +1081,9 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
        csk->sndbuf = newsk->sk_sndbuf;
        csk->smac_idx = cxgb4_tp_smt_idx(cdev->lldi->adapter_type,
                                         cxgb4_port_viid(ndev));
-       tp->rcv_wnd = select_rcv_wnd(csk);
        RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
-                                          WSCALE_OK(tp),
+                                          sock_net(newsk)->
+                                               ipv4.sysctl_tcp_window_scaling,
                                           tp->window_clamp);
        neigh_release(n);
        inet_inherit_port(&tcp_hashinfo, lsk, newsk);
@@ -1130,6 +1135,7 @@ static void chtls_pass_accept_request(struct sock *sk,
        struct cpl_t5_pass_accept_rpl *rpl;
        struct cpl_pass_accept_req *req;
        struct listen_ctx *listen_ctx;
+       struct vlan_ethhdr *vlan_eh;
        struct request_sock *oreq;
        struct sk_buff *reply_skb;
        struct chtls_sock *csk;
@@ -1142,6 +1148,10 @@ static void chtls_pass_accept_request(struct sock *sk,
        unsigned int stid;
        unsigned int len;
        unsigned int tid;
+       bool th_ecn, ect;
+       __u8 ip_dsfield; /* IPv4 tos or IPv6 dsfield */
+       u16 eth_hdr_len;
+       bool ecn_ok;
 
        req = cplhdr(skb) + RSS_HDR;
        tid = GET_TID(req);
@@ -1180,24 +1190,40 @@ static void chtls_pass_accept_request(struct sock *sk,
        oreq->mss = 0;
        oreq->ts_recent = 0;
 
-       eh = (struct ethhdr *)(req + 1);
-       iph = (struct iphdr *)(eh + 1);
+       eth_hdr_len = T6_ETH_HDR_LEN_G(ntohl(req->hdr_len));
+       if (eth_hdr_len == ETH_HLEN) {
+               eh = (struct ethhdr *)(req + 1);
+               iph = (struct iphdr *)(eh + 1);
+               network_hdr = (void *)(eh + 1);
+       } else {
+               vlan_eh = (struct vlan_ethhdr *)(req + 1);
+               iph = (struct iphdr *)(vlan_eh + 1);
+               network_hdr = (void *)(vlan_eh + 1);
+       }
        if (iph->version != 0x4)
                goto free_oreq;
 
-       network_hdr = (void *)(eh + 1);
        tcph = (struct tcphdr *)(iph + 1);
+       skb_set_network_header(skb, (void *)iph - (void *)req);
 
        tcp_rsk(oreq)->tfo_listener = false;
        tcp_rsk(oreq)->rcv_isn = ntohl(tcph->seq);
        chtls_set_req_port(oreq, tcph->source, tcph->dest);
-       inet_rsk(oreq)->ecn_ok = 0;
        chtls_set_req_addr(oreq, iph->daddr, iph->saddr);
-       if (req->tcpopt.wsf <= 14) {
+       ip_dsfield = ipv4_get_dsfield(iph);
+       if (req->tcpopt.wsf <= 14 &&
+           sock_net(sk)->ipv4.sysctl_tcp_window_scaling) {
                inet_rsk(oreq)->wscale_ok = 1;
                inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf;
        }
        inet_rsk(oreq)->ir_iif = sk->sk_bound_dev_if;
+       th_ecn = tcph->ece && tcph->cwr;
+       if (th_ecn) {
+               ect = !INET_ECN_is_not_ect(ip_dsfield);
+               ecn_ok = sock_net(sk)->ipv4.sysctl_tcp_ecn;
+               if ((!ect && ecn_ok) || tcp_ca_needs_ecn(sk))
+                       inet_rsk(oreq)->ecn_ok = 1;
+       }
 
        newsk = chtls_recv_sock(sk, oreq, network_hdr, req, cdev);
        if (!newsk)
index afebbd87c4aa1d22ca179f558552cb2f410fcc0a..18f553fcc1673dda35c0aaf663c0670d7a24e458 100644 (file)
@@ -397,7 +397,7 @@ static void tls_tx_data_wr(struct sock *sk, struct sk_buff *skb,
 
        req_wr->lsodisable_to_flags =
                        htonl(TX_ULP_MODE_V(ULP_MODE_TLS) |
-                             FW_OFLD_TX_DATA_WR_URGENT_V(skb_urgent(skb)) |
+                             TX_URG_V(skb_urgent(skb)) |
                              T6_TX_FORCE_F | wr_ulp_mode_force |
                              TX_SHOVE_V((!csk_flag(sk, CSK_TX_MORE_DATA)) &&
                                         skb_queue_empty(&csk->txq)));
@@ -534,10 +534,9 @@ static void make_tx_data_wr(struct sock *sk, struct sk_buff *skb,
                                FW_OFLD_TX_DATA_WR_SHOVE_F);
 
        req->tunnel_to_proxy = htonl(wr_ulp_mode_force |
-                       FW_OFLD_TX_DATA_WR_URGENT_V(skb_urgent(skb)) |
-                       FW_OFLD_TX_DATA_WR_SHOVE_V((!csk_flag
-                                       (sk, CSK_TX_MORE_DATA)) &&
-                                        skb_queue_empty(&csk->txq)));
+                       TX_URG_V(skb_urgent(skb)) |
+                       TX_SHOVE_V((!csk_flag(sk, CSK_TX_MORE_DATA)) &&
+                                  skb_queue_empty(&csk->txq)));
        req->plen = htonl(len);
 }
 
@@ -995,7 +994,6 @@ int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        int mss, flags, err;
        int recordsz = 0;
        int copied = 0;
-       int hdrlen = 0;
        long timeo;
 
        lock_sock(sk);
@@ -1032,7 +1030,7 @@ int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 
                        recordsz = tls_header_read(&hdr, &msg->msg_iter);
                        size -= TLS_HEADER_LENGTH;
-                       hdrlen += TLS_HEADER_LENGTH;
+                       copied += TLS_HEADER_LENGTH;
                        csk->tlshws.txleft = recordsz;
                        csk->tlshws.type = hdr.type;
                        if (skb)
@@ -1083,10 +1081,8 @@ new_buf:
                        int off = TCP_OFF(sk);
                        bool merge;
 
-                       if (!page)
-                               goto wait_for_memory;
-
-                       pg_size <<= compound_order(page);
+                       if (page)
+                               pg_size <<= compound_order(page);
                        if (off < pg_size &&
                            skb_can_coalesce(skb, i, page, off)) {
                                merge = 1;
@@ -1187,7 +1183,7 @@ out:
                chtls_tcp_push(sk, flags);
 done:
        release_sock(sk);
-       return copied + hdrlen;
+       return copied;
 do_fault:
        if (!skb->len) {
                __skb_unlink(skb, &csk->txq);
index f472c51abe56ac7de376d58483a3508eabcc069b..563f8fe7686adc9c895dbb623cac3f7c9ae5a3a6 100644 (file)
@@ -55,24 +55,19 @@ static void unregister_listen_notifier(struct notifier_block *nb)
 static int listen_notify_handler(struct notifier_block *this,
                                 unsigned long event, void *data)
 {
-       struct chtls_dev *cdev;
-       struct sock *sk;
-       int ret;
+       struct chtls_listen *clisten;
+       int ret = NOTIFY_DONE;
 
-       sk = data;
-       ret =  NOTIFY_DONE;
+       clisten = (struct chtls_listen *)data;
 
        switch (event) {
        case CHTLS_LISTEN_START:
+               ret = chtls_listen_start(clisten->cdev, clisten->sk);
+               kfree(clisten);
+               break;
        case CHTLS_LISTEN_STOP:
-               mutex_lock(&cdev_list_lock);
-               list_for_each_entry(cdev, &cdev_list, list) {
-                       if (event == CHTLS_LISTEN_START)
-                               ret = chtls_listen_start(cdev, sk);
-                       else
-                               chtls_listen_stop(cdev, sk);
-               }
-               mutex_unlock(&cdev_list_lock);
+               chtls_listen_stop(clisten->cdev, clisten->sk);
+               kfree(clisten);
                break;
        }
        return ret;
@@ -90,8 +85,9 @@ static int listen_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-static int chtls_start_listen(struct sock *sk)
+static int chtls_start_listen(struct chtls_dev *cdev, struct sock *sk)
 {
+       struct chtls_listen *clisten;
        int err;
 
        if (sk->sk_protocol != IPPROTO_TCP)
@@ -102,21 +98,33 @@ static int chtls_start_listen(struct sock *sk)
                return -EADDRNOTAVAIL;
 
        sk->sk_backlog_rcv = listen_backlog_rcv;
+       clisten = kmalloc(sizeof(*clisten), GFP_KERNEL);
+       if (!clisten)
+               return -ENOMEM;
+       clisten->cdev = cdev;
+       clisten->sk = sk;
        mutex_lock(&notify_mutex);
        err = raw_notifier_call_chain(&listen_notify_list,
-                                     CHTLS_LISTEN_START, sk);
+                                     CHTLS_LISTEN_START, clisten);
        mutex_unlock(&notify_mutex);
        return err;
 }
 
-static void chtls_stop_listen(struct sock *sk)
+static void chtls_stop_listen(struct chtls_dev *cdev, struct sock *sk)
 {
+       struct chtls_listen *clisten;
+
        if (sk->sk_protocol != IPPROTO_TCP)
                return;
 
+       clisten = kmalloc(sizeof(*clisten), GFP_KERNEL);
+       if (!clisten)
+               return;
+       clisten->cdev = cdev;
+       clisten->sk = sk;
        mutex_lock(&notify_mutex);
        raw_notifier_call_chain(&listen_notify_list,
-                               CHTLS_LISTEN_STOP, sk);
+                               CHTLS_LISTEN_STOP, clisten);
        mutex_unlock(&notify_mutex);
 }
 
@@ -138,15 +146,43 @@ static int chtls_inline_feature(struct tls_device *dev)
 
 static int chtls_create_hash(struct tls_device *dev, struct sock *sk)
 {
+       struct chtls_dev *cdev = to_chtls_dev(dev);
+
        if (sk->sk_state == TCP_LISTEN)
-               return chtls_start_listen(sk);
+               return chtls_start_listen(cdev, sk);
        return 0;
 }
 
 static void chtls_destroy_hash(struct tls_device *dev, struct sock *sk)
 {
+       struct chtls_dev *cdev = to_chtls_dev(dev);
+
        if (sk->sk_state == TCP_LISTEN)
-               chtls_stop_listen(sk);
+               chtls_stop_listen(cdev, sk);
+}
+
+static void chtls_free_uld(struct chtls_dev *cdev)
+{
+       int i;
+
+       tls_unregister_device(&cdev->tlsdev);
+       kvfree(cdev->kmap.addr);
+       idr_destroy(&cdev->hwtid_idr);
+       for (i = 0; i < (1 << RSPQ_HASH_BITS); i++)
+               kfree_skb(cdev->rspq_skb_cache[i]);
+       kfree(cdev->lldi);
+       kfree_skb(cdev->askb);
+       kfree(cdev);
+}
+
+static inline void chtls_dev_release(struct kref *kref)
+{
+       struct chtls_dev *cdev;
+       struct tls_device *dev;
+
+       dev = container_of(kref, struct tls_device, kref);
+       cdev = to_chtls_dev(dev);
+       chtls_free_uld(cdev);
 }
 
 static void chtls_register_dev(struct chtls_dev *cdev)
@@ -159,15 +195,12 @@ static void chtls_register_dev(struct chtls_dev *cdev)
        tlsdev->feature = chtls_inline_feature;
        tlsdev->hash = chtls_create_hash;
        tlsdev->unhash = chtls_destroy_hash;
-       tls_register_device(&cdev->tlsdev);
+       tlsdev->release = chtls_dev_release;
+       kref_init(&tlsdev->kref);
+       tls_register_device(tlsdev);
        cdev->cdev_state = CHTLS_CDEV_STATE_UP;
 }
 
-static void chtls_unregister_dev(struct chtls_dev *cdev)
-{
-       tls_unregister_device(&cdev->tlsdev);
-}
-
 static void process_deferq(struct work_struct *task_param)
 {
        struct chtls_dev *cdev = container_of(task_param,
@@ -262,28 +295,16 @@ out:
        return NULL;
 }
 
-static void chtls_free_uld(struct chtls_dev *cdev)
-{
-       int i;
-
-       chtls_unregister_dev(cdev);
-       kvfree(cdev->kmap.addr);
-       idr_destroy(&cdev->hwtid_idr);
-       for (i = 0; i < (1 << RSPQ_HASH_BITS); i++)
-               kfree_skb(cdev->rspq_skb_cache[i]);
-       kfree(cdev->lldi);
-       kfree_skb(cdev->askb);
-       kfree(cdev);
-}
-
 static void chtls_free_all_uld(void)
 {
        struct chtls_dev *cdev, *tmp;
 
        mutex_lock(&cdev_mutex);
        list_for_each_entry_safe(cdev, tmp, &cdev_list, list) {
-               if (cdev->cdev_state == CHTLS_CDEV_STATE_UP)
-                       chtls_free_uld(cdev);
+               if (cdev->cdev_state == CHTLS_CDEV_STATE_UP) {
+                       list_del(&cdev->list);
+                       kref_put(&cdev->tlsdev.kref, cdev->tlsdev.release);
+               }
        }
        mutex_unlock(&cdev_mutex);
 }
@@ -304,7 +325,7 @@ static int chtls_uld_state_change(void *handle, enum cxgb4_state new_state)
                mutex_lock(&cdev_mutex);
                list_del(&cdev->list);
                mutex_unlock(&cdev_mutex);
-               chtls_free_uld(cdev);
+               kref_put(&cdev->tlsdev.kref, cdev->tlsdev.release);
                break;
        default:
                break;
index 141413067b5ce25ca6e57d534a9d9c854d40ea62..0ae3de76833b7da0c16f01ca79e482ec66217594 100644 (file)
@@ -285,6 +285,44 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
        return 0;
 }
 
+static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
+                             u32 flags)
+{
+       struct devfreq_freqs freqs;
+       unsigned long cur_freq;
+       int err = 0;
+
+       if (devfreq->profile->get_cur_freq)
+               devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
+       else
+               cur_freq = devfreq->previous_freq;
+
+       freqs.old = cur_freq;
+       freqs.new = new_freq;
+       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
+
+       err = devfreq->profile->target(devfreq->dev.parent, &new_freq, flags);
+       if (err) {
+               freqs.new = cur_freq;
+               devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
+               return err;
+       }
+
+       freqs.new = new_freq;
+       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
+
+       if (devfreq_update_status(devfreq, new_freq))
+               dev_err(&devfreq->dev,
+                       "Couldn't update frequency transition information.\n");
+
+       devfreq->previous_freq = new_freq;
+
+       if (devfreq->suspend_freq)
+               devfreq->resume_freq = cur_freq;
+
+       return err;
+}
+
 /* Load monitoring helper functions for governors use */
 
 /**
@@ -296,8 +334,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
  */
 int update_devfreq(struct devfreq *devfreq)
 {
-       struct devfreq_freqs freqs;
-       unsigned long freq, cur_freq, min_freq, max_freq;
+       unsigned long freq, min_freq, max_freq;
        int err = 0;
        u32 flags = 0;
 
@@ -333,31 +370,8 @@ int update_devfreq(struct devfreq *devfreq)
                flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
        }
 
-       if (devfreq->profile->get_cur_freq)
-               devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
-       else
-               cur_freq = devfreq->previous_freq;
+       return devfreq_set_target(devfreq, freq, flags);
 
-       freqs.old = cur_freq;
-       freqs.new = freq;
-       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
-
-       err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
-       if (err) {
-               freqs.new = cur_freq;
-               devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
-               return err;
-       }
-
-       freqs.new = freq;
-       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
-
-       if (devfreq_update_status(devfreq, freq))
-               dev_err(&devfreq->dev,
-                       "Couldn't update frequency transition information.\n");
-
-       devfreq->previous_freq = freq;
-       return err;
 }
 EXPORT_SYMBOL(update_devfreq);
 
@@ -657,6 +671,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
        }
        devfreq->max_freq = devfreq->scaling_max_freq;
 
+       devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
+       atomic_set(&devfreq->suspend_count, 0);
+
        dev_set_name(&devfreq->dev, "devfreq%d",
                                atomic_inc_return(&devfreq_no));
        err = device_register(&devfreq->dev);
@@ -857,14 +874,28 @@ EXPORT_SYMBOL(devm_devfreq_remove_device);
  */
 int devfreq_suspend_device(struct devfreq *devfreq)
 {
+       int ret;
+
        if (!devfreq)
                return -EINVAL;
 
-       if (!devfreq->governor)
+       if (atomic_inc_return(&devfreq->suspend_count) > 1)
                return 0;
 
-       return devfreq->governor->event_handler(devfreq,
-                               DEVFREQ_GOV_SUSPEND, NULL);
+       if (devfreq->governor) {
+               ret = devfreq->governor->event_handler(devfreq,
+                                       DEVFREQ_GOV_SUSPEND, NULL);
+               if (ret)
+                       return ret;
+       }
+
+       if (devfreq->suspend_freq) {
+               ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(devfreq_suspend_device);
 
@@ -878,17 +909,75 @@ EXPORT_SYMBOL(devfreq_suspend_device);
  */
 int devfreq_resume_device(struct devfreq *devfreq)
 {
+       int ret;
+
        if (!devfreq)
                return -EINVAL;
 
-       if (!devfreq->governor)
+       if (atomic_dec_return(&devfreq->suspend_count) >= 1)
                return 0;
 
-       return devfreq->governor->event_handler(devfreq,
-                               DEVFREQ_GOV_RESUME, NULL);
+       if (devfreq->resume_freq) {
+               ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
+               if (ret)
+                       return ret;
+       }
+
+       if (devfreq->governor) {
+               ret = devfreq->governor->event_handler(devfreq,
+                                       DEVFREQ_GOV_RESUME, NULL);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(devfreq_resume_device);
 
+/**
+ * devfreq_suspend() - Suspend devfreq governors and devices
+ *
+ * Called during system wide Suspend/Hibernate cycles for suspending governors
+ * and devices preserving the state for resume. On some platforms the devfreq
+ * device must have precise state (frequency) after resume in order to provide
+ * fully operating setup.
+ */
+void devfreq_suspend(void)
+{
+       struct devfreq *devfreq;
+       int ret;
+
+       mutex_lock(&devfreq_list_lock);
+       list_for_each_entry(devfreq, &devfreq_list, node) {
+               ret = devfreq_suspend_device(devfreq);
+               if (ret)
+                       dev_err(&devfreq->dev,
+                               "failed to suspend devfreq device\n");
+       }
+       mutex_unlock(&devfreq_list_lock);
+}
+
+/**
+ * devfreq_resume() - Resume devfreq governors and devices
+ *
+ * Called during system wide Suspend/Hibernate cycle for resuming governors and
+ * devices that are suspended with devfreq_suspend().
+ */
+void devfreq_resume(void)
+{
+       struct devfreq *devfreq;
+       int ret;
+
+       mutex_lock(&devfreq_list_lock);
+       list_for_each_entry(devfreq, &devfreq_list, node) {
+               ret = devfreq_resume_device(devfreq);
+               if (ret)
+                       dev_warn(&devfreq->dev,
+                                "failed to resume devfreq device\n");
+       }
+       mutex_unlock(&devfreq_list_lock);
+}
+
 /**
  * devfreq_add_governor() - Add devfreq governor
  * @governor:  the devfreq governor to be added
index 1551ca7df394113fca8fc923fb1fdb98d63b13aa..136ec04d683f1c5b80598301f8fab897cd99b5e4 100644 (file)
 EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit);
 EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal);
 
+static DEFINE_SPINLOCK(dma_fence_stub_lock);
+static struct dma_fence dma_fence_stub;
+
 /*
  * fence context counter: each execution context should have its own
  * fence context, this allows checking if fences belong to the same
  * context or not. One device can have multiple separate contexts,
  * and they're used if some engine can run independently of another.
  */
-static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0);
+static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1);
 
 /**
  * DOC: DMA fences overview
@@ -68,6 +71,37 @@ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0);
  *   &dma_buf.resv pointer.
  */
 
+static const char *dma_fence_stub_get_name(struct dma_fence *fence)
+{
+        return "stub";
+}
+
+static const struct dma_fence_ops dma_fence_stub_ops = {
+       .get_driver_name = dma_fence_stub_get_name,
+       .get_timeline_name = dma_fence_stub_get_name,
+};
+
+/**
+ * dma_fence_get_stub - return a signaled fence
+ *
+ * Return a stub fence which is already signaled.
+ */
+struct dma_fence *dma_fence_get_stub(void)
+{
+       spin_lock(&dma_fence_stub_lock);
+       if (!dma_fence_stub.ops) {
+               dma_fence_init(&dma_fence_stub,
+                              &dma_fence_stub_ops,
+                              &dma_fence_stub_lock,
+                              0, 0);
+               dma_fence_signal_locked(&dma_fence_stub);
+       }
+       spin_unlock(&dma_fence_stub_lock);
+
+       return dma_fence_get(&dma_fence_stub);
+}
+EXPORT_SYMBOL(dma_fence_get_stub);
+
 /**
  * dma_fence_context_alloc - allocate an array of fence contexts
  * @num: amount of contexts to allocate
index 6c95f61a32e73d54ed70f461e676826075419f45..c1618335ca9944e11c537eb7bd2c13ed3dd93b2b 100644 (file)
@@ -56,9 +56,10 @@ const char reservation_seqcount_string[] = "reservation_seqcount";
 EXPORT_SYMBOL(reservation_seqcount_string);
 
 /**
- * reservation_object_reserve_shared - Reserve space to add a shared
- * fence to a reservation_object.
+ * reservation_object_reserve_shared - Reserve space to add shared fences to
+ * a reservation_object.
  * @obj: reservation object
+ * @num_fences: number of fences we want to add
  *
  * Should be called before reservation_object_add_shared_fence().  Must
  * be called with obj->lock held.
@@ -66,107 +67,27 @@ EXPORT_SYMBOL(reservation_seqcount_string);
  * RETURNS
  * Zero for success, or -errno
  */
-int reservation_object_reserve_shared(struct reservation_object *obj)
+int reservation_object_reserve_shared(struct reservation_object *obj,
+                                     unsigned int num_fences)
 {
-       struct reservation_object_list *fobj, *old;
-       u32 max;
+       struct reservation_object_list *old, *new;
+       unsigned int i, j, k, max;
 
        old = reservation_object_get_list(obj);
 
        if (old && old->shared_max) {
-               if (old->shared_count < old->shared_max) {
-                       /* perform an in-place update */
-                       kfree(obj->staged);
-                       obj->staged = NULL;
+               if ((old->shared_count + num_fences) <= old->shared_max)
                        return 0;
-               } else
-                       max = old->shared_max * 2;
-       } else
-               max = 4;
-
-       /*
-        * resize obj->staged or allocate if it doesn't exist,
-        * noop if already correct size
-        */
-       fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]),
-                       GFP_KERNEL);
-       if (!fobj)
-               return -ENOMEM;
-
-       obj->staged = fobj;
-       fobj->shared_max = max;
-       return 0;
-}
-EXPORT_SYMBOL(reservation_object_reserve_shared);
-
-static void
-reservation_object_add_shared_inplace(struct reservation_object *obj,
-                                     struct reservation_object_list *fobj,
-                                     struct dma_fence *fence)
-{
-       struct dma_fence *signaled = NULL;
-       u32 i, signaled_idx;
-
-       dma_fence_get(fence);
-
-       preempt_disable();
-       write_seqcount_begin(&obj->seq);
-
-       for (i = 0; i < fobj->shared_count; ++i) {
-               struct dma_fence *old_fence;
-
-               old_fence = rcu_dereference_protected(fobj->shared[i],
-                                               reservation_object_held(obj));
-
-               if (old_fence->context == fence->context) {
-                       /* memory barrier is added by write_seqcount_begin */
-                       RCU_INIT_POINTER(fobj->shared[i], fence);
-                       write_seqcount_end(&obj->seq);
-                       preempt_enable();
-
-                       dma_fence_put(old_fence);
-                       return;
-               }
-
-               if (!signaled && dma_fence_is_signaled(old_fence)) {
-                       signaled = old_fence;
-                       signaled_idx = i;
-               }
-       }
-
-       /*
-        * memory barrier is added by write_seqcount_begin,
-        * fobj->shared_count is protected by this lock too
-        */
-       if (signaled) {
-               RCU_INIT_POINTER(fobj->shared[signaled_idx], fence);
+               else
+                       max = max(old->shared_count + num_fences,
+                                 old->shared_max * 2);
        } else {
-               BUG_ON(fobj->shared_count >= fobj->shared_max);
-               RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
-               fobj->shared_count++;
+               max = 4;
        }
 
-       write_seqcount_end(&obj->seq);
-       preempt_enable();
-
-       dma_fence_put(signaled);
-}
-
-static void
-reservation_object_add_shared_replace(struct reservation_object *obj,
-                                     struct reservation_object_list *old,
-                                     struct reservation_object_list *fobj,
-                                     struct dma_fence *fence)
-{
-       unsigned i, j, k;
-
-       dma_fence_get(fence);
-
-       if (!old) {
-               RCU_INIT_POINTER(fobj->shared[0], fence);
-               fobj->shared_count = 1;
-               goto done;
-       }
+       new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
 
        /*
         * no need to bump fence refcounts, rcu_read access
@@ -174,46 +95,45 @@ reservation_object_add_shared_replace(struct reservation_object *obj,
         * references from the old struct are carried over to
         * the new.
         */
-       for (i = 0, j = 0, k = fobj->shared_max; i < old->shared_count; ++i) {
-               struct dma_fence *check;
-
-               check = rcu_dereference_protected(old->shared[i],
-                                               reservation_object_held(obj));
+       for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
+               struct dma_fence *fence;
 
-               if (check->context == fence->context ||
-                   dma_fence_is_signaled(check))
-                       RCU_INIT_POINTER(fobj->shared[--k], check);
+               fence = rcu_dereference_protected(old->shared[i],
+                                                 reservation_object_held(obj));
+               if (dma_fence_is_signaled(fence))
+                       RCU_INIT_POINTER(new->shared[--k], fence);
                else
-                       RCU_INIT_POINTER(fobj->shared[j++], check);
+                       RCU_INIT_POINTER(new->shared[j++], fence);
        }
-       fobj->shared_count = j;
-       RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
-       fobj->shared_count++;
+       new->shared_count = j;
+       new->shared_max = max;
 
-done:
        preempt_disable();
        write_seqcount_begin(&obj->seq);
        /*
         * RCU_INIT_POINTER can be used here,
         * seqcount provides the necessary barriers
         */
-       RCU_INIT_POINTER(obj->fence, fobj);
+       RCU_INIT_POINTER(obj->fence, new);
        write_seqcount_end(&obj->seq);
        preempt_enable();
 
        if (!old)
-               return;
+               return 0;
 
        /* Drop the references to the signaled fences */
-       for (i = k; i < fobj->shared_max; ++i) {
-               struct dma_fence *f;
+       for (i = k; i < new->shared_max; ++i) {
+               struct dma_fence *fence;
 
-               f = rcu_dereference_protected(fobj->shared[i],
-                                             reservation_object_held(obj));
-               dma_fence_put(f);
+               fence = rcu_dereference_protected(new->shared[i],
+                                                 reservation_object_held(obj));
+               dma_fence_put(fence);
        }
        kfree_rcu(old, rcu);
+
+       return 0;
 }
+EXPORT_SYMBOL(reservation_object_reserve_shared);
 
 /**
  * reservation_object_add_shared_fence - Add a fence to a shared slot
@@ -226,15 +146,39 @@ done:
 void reservation_object_add_shared_fence(struct reservation_object *obj,
                                         struct dma_fence *fence)
 {
-       struct reservation_object_list *old, *fobj = obj->staged;
+       struct reservation_object_list *fobj;
+       unsigned int i, count;
 
-       old = reservation_object_get_list(obj);
-       obj->staged = NULL;
+       dma_fence_get(fence);
 
-       if (!fobj)
-               reservation_object_add_shared_inplace(obj, old, fence);
-       else
-               reservation_object_add_shared_replace(obj, old, fobj, fence);
+       fobj = reservation_object_get_list(obj);
+       count = fobj->shared_count;
+
+       preempt_disable();
+       write_seqcount_begin(&obj->seq);
+
+       for (i = 0; i < count; ++i) {
+               struct dma_fence *old_fence;
+
+               old_fence = rcu_dereference_protected(fobj->shared[i],
+                                                     reservation_object_held(obj));
+               if (old_fence->context == fence->context ||
+                   dma_fence_is_signaled(old_fence)) {
+                       dma_fence_put(old_fence);
+                       goto replace;
+               }
+       }
+
+       BUG_ON(fobj->shared_count >= fobj->shared_max);
+       count++;
+
+replace:
+       RCU_INIT_POINTER(fobj->shared[i], fence);
+       /* pointer update must be visible before we extend the shared_count */
+       smp_store_mb(fobj->shared_count, count);
+
+       write_seqcount_end(&obj->seq);
+       preempt_enable();
 }
 EXPORT_SYMBOL(reservation_object_add_shared_fence);
 
@@ -343,9 +287,6 @@ retry:
        new = dma_fence_get_rcu_safe(&src->fence_excl);
        rcu_read_unlock();
 
-       kfree(dst->staged);
-       dst->staged = NULL;
-
        src_list = reservation_object_get_list(dst);
        old = reservation_object_get_excl(dst);
 
index 41c9ccdd20d65658f461991ab4e8bc74d0e6fa4a..e286b5b990035f85edd6ca86a11c674e09ed0282 100644 (file)
@@ -231,10 +231,10 @@ config EDAC_SBRIDGE
 
 config EDAC_SKX
        tristate "Intel Skylake server Integrated MC"
-       depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG
+       depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG && ACPI
        depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_SKX can't be y
        select DMI
-       select ACPI_ADXL if ACPI
+       select ACPI_ADXL
        help
          Support for error detection and correction the Intel
          Skylake server Integrated Memory Controllers. If your
@@ -442,7 +442,7 @@ config EDAC_ALTERA_SDMMC
 
 config EDAC_SYNOPSYS
        tristate "Synopsys DDR Memory Controller"
-       depends on ARCH_ZYNQ
+       depends on ARCH_ZYNQ || ARCH_ZYNQMP
        help
          Support for error detection and correction on the Synopsys DDR
          memory controller.
index b5de9a13ea3fee357cf3ca6273bc38129f2a10d6..de732dc2ef33e85bf71adbdaf709a0ed7b3fc785 100644 (file)
@@ -1446,8 +1446,8 @@ static int __init e752x_init(void)
 
        edac_dbg(3, "\n");
 
-       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
-       opstate_init();
+       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+       opstate_init();
 
        pci_rc = pci_register_driver(&e752x_driver);
        return (pci_rc < 0) ? pci_rc : 0;
index 7d3edd7139328b5466dfe2041d24e353e166ea7a..13594ffadcb3aca4b50d0c6e3b89afc78a6addf3 100644 (file)
@@ -55,8 +55,6 @@ static LIST_HEAD(mc_devices);
  */
 static const char *edac_mc_owner;
 
-static struct bus_type mc_bus[EDAC_MAX_MCS];
-
 int edac_get_report_status(void)
 {
        return edac_report;
@@ -716,11 +714,6 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
        int ret = -EINVAL;
        edac_dbg(0, "\n");
 
-       if (mci->mc_idx >= EDAC_MAX_MCS) {
-               pr_warn_once("Too many memory controllers: %d\n", mci->mc_idx);
-               return -ENODEV;
-       }
-
 #ifdef CONFIG_EDAC_DEBUG
        if (edac_debug_level >= 3)
                edac_mc_dump_mci(mci);
@@ -760,7 +753,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
        /* set load time so that error rate can be tracked */
        mci->start_time = jiffies;
 
-       mci->bus = &mc_bus[mci->mc_idx];
+       mci->bus = edac_get_sysfs_subsys();
 
        if (edac_create_sysfs_mci_device(mci, groups)) {
                edac_mc_printk(mci, KERN_WARNING,
index 20374b8248f087e343738bee152a8b34e746d6d6..46417468558945921e52cba2c997229bb87694aa 100644 (file)
@@ -405,7 +405,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
                                    struct csrow_info *csrow, int index)
 {
        csrow->dev.type = &csrow_attr_type;
-       csrow->dev.bus = mci->bus;
        csrow->dev.groups = csrow_dev_groups;
        device_initialize(&csrow->dev);
        csrow->dev.parent = &mci->dev;
@@ -636,7 +635,6 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        dimm->mci = mci;
 
        dimm->dev.type = &dimm_attr_type;
-       dimm->dev.bus = mci->bus;
        device_initialize(&dimm->dev);
 
        dimm->dev.parent = &mci->dev;
@@ -914,33 +912,13 @@ static const struct device_type mci_attr_type = {
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
                                 const struct attribute_group **groups)
 {
-       char *name;
        int i, err;
 
-       /*
-        * The memory controller needs its own bus, in order to avoid
-        * namespace conflicts at /sys/bus/edac.
-        */
-       name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
-       if (!name)
-               return -ENOMEM;
-
-       mci->bus->name = name;
-
-       edac_dbg(0, "creating bus %s\n", mci->bus->name);
-
-       err = bus_register(mci->bus);
-       if (err < 0) {
-               kfree(name);
-               return err;
-       }
-
        /* get the /sys/devices/system/edac subsys reference */
        mci->dev.type = &mci_attr_type;
        device_initialize(&mci->dev);
 
        mci->dev.parent = mci_pdev;
-       mci->dev.bus = mci->bus;
        mci->dev.groups = groups;
        dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
        dev_set_drvdata(&mci->dev, mci);
@@ -950,7 +928,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
-               goto fail_unregister_bus;
+               goto out;
        }
 
        /*
@@ -998,10 +976,8 @@ fail_unregister_dimm:
                device_unregister(&dimm->dev);
        }
        device_unregister(&mci->dev);
-fail_unregister_bus:
-       bus_unregister(mci->bus);
-       kfree(name);
 
+out:
        return err;
 }
 
@@ -1032,13 +1008,8 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
-       struct bus_type *bus = mci->bus;
-       const char *name = mci->bus->name;
-
        edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
-       bus_unregister(bus);
-       kfree(name);
 }
 
 static void mc_attr_release(struct device *dev)
index efc8276d1d9cc83610a84d5fd6740bf8cd638bd4..6d8ea226010d2d793176591c1e1b5b3afef140f7 100644 (file)
@@ -2,8 +2,8 @@
  * Freescale Memory Controller kernel module
  *
  * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and
- * ARM-based Layerscape SoCs including LS2xxx. Originally split
- * out from mpc85xx_edac EDAC driver.
+ * ARM-based Layerscape SoCs including LS2xxx and LS1021A. Originally
+ * split out from mpc85xx_edac EDAC driver.
  *
  * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
  *
@@ -51,6 +51,7 @@ static inline void ddr_out32(void __iomem *addr, u32 value)
                iowrite32be(value, addr);
 }
 
+#ifdef CONFIG_EDAC_DEBUG
 /************************ MC SYSFS parts ***********************************/
 
 #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
@@ -151,11 +152,14 @@ static DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR,
                   fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store);
 static DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR,
                   fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store);
+#endif /* CONFIG_EDAC_DEBUG */
 
 static struct attribute *fsl_ddr_dev_attrs[] = {
+#ifdef CONFIG_EDAC_DEBUG
        &dev_attr_inject_data_hi.attr,
        &dev_attr_inject_data_lo.attr,
        &dev_attr_inject_ctrl.attr,
+#endif
        NULL
 };
 
index 4ccee292eff152ee2f555890f41f0c9b33926f33..589b9b4a5e8a97b75f0ed20996e0d46498bc6751 100644 (file)
@@ -2,8 +2,8 @@
  * Freescale Memory Controller kernel module
  *
  * Support  Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and
- * ARM-based Layerscape SoCs including LS2xxx. Originally split
- * out from mpc85xx_edac EDAC driver.
+ * ARM-based Layerscape SoCs including LS2xxx and LS1021A. Originally
+ * split out from mpc85xx_edac EDAC driver.
  *
  * Author: Dave Jiang <djiang@mvista.com>
  *
index 8085a32ec3bdbfb3e799224b0157e99d2ac67027..f564a4a8a4aec88cf1cfa1ebe9b4648c16d2a523 100644 (file)
@@ -508,8 +508,8 @@ static int __init i3000_init(void)
 
        edac_dbg(3, "MC:\n");
 
-       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
-       opstate_init();
+       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+       opstate_init();
 
        pci_rc = pci_register_driver(&i3000_driver);
        if (pci_rc < 0)
index 53f24b18cd6134d6c8c90c5a7a6034d798b6ddcf..078a7351bf0566b9a53db577497ce78ac306d50a 100644 (file)
@@ -1134,8 +1134,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
        u32 actual_tolm;
        u16 limit;
        int slot_row;
-       int maxch;
-       int maxdimmperch;
        int way0, way1;
 
        pvt = mci->pvt_info;
@@ -1145,9 +1143,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
        pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
                        &pvt->u.ambase_top);
 
-       maxdimmperch = pvt->maxdimmperch;
-       maxch = pvt->maxch;
-
        edac_dbg(2, "AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
                 (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
 
@@ -1253,7 +1248,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
 {
        struct i5000_pvt *pvt;
        struct dimm_info *dimm;
-       int empty, channel_count;
+       int empty;
        int max_csrows;
        int mtr;
        int csrow_megs;
@@ -1261,8 +1256,6 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
        int slot;
 
        pvt = mci->pvt_info;
-
-       channel_count = pvt->maxch;
        max_csrows = pvt->maxdimmperch * 2;
 
        empty = 1;              /* Assume NO memory */
@@ -1559,8 +1552,8 @@ static int __init i5000_init(void)
 
        edac_dbg(2, "MC:\n");
 
-       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
-       opstate_init();
+       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+       opstate_init();
 
        pci_rc = pci_register_driver(&i5000_driver);
 
index 9ef448fef12f38b427b340be1e2cb645885addaa..40297550313ac90fa534a996187cd14af94fd5fe 100644 (file)
@@ -724,7 +724,7 @@ static ssize_t i7core_inject_type_store(struct device *dev,
                                        const char *data, size_t count)
 {
        struct mem_ctl_info *mci = to_mci(dev);
-struct i7core_pvt *pvt = mci->pvt_info;
+       struct i7core_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int rc;
 
index 892815eaa97b9191080fc688f6a80a2026751b50..7c6a2d4d23606de53e9edcbdab9f334a21b04499 100644 (file)
@@ -104,7 +104,7 @@ NOTE: Only ONE of the three must be enabled
                                         *
                                         * 31:14 Base Addr of 16K memory-mapped
                                         *      configuration space
-                                        * 13:1  reserverd
+                                        * 13:1  reserved
                                         *  0    mem-mapped config space enable
                                         */
 
@@ -358,14 +358,6 @@ static int dual_channel_active(void __iomem *mch_window)
        return dualch;
 }
 
-static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
-{
-       /*
-        * ECC is possible on i92975x ONLY with DEV_X8
-        */
-       return DEV_X8;
-}
-
 static void i82975x_init_csrows(struct mem_ctl_info *mci,
                struct pci_dev *pdev, void __iomem *mch_window)
 {
@@ -375,7 +367,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
        u32 cumul_size, nr_pages;
        int index, chan;
        struct dimm_info *dimm;
-       enum dev_type dtype;
 
        last_cumul_size = 0;
 
@@ -413,7 +404,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
                 *   [0-7] for single-channel; i.e. csrow->nr_channels = 1
                 *   [0-3] for dual-channel; i.e. csrow->nr_channels = 2
                 */
-               dtype = i82975x_dram_type(mch_window, index);
                for (chan = 0; chan < csrow->nr_channels; chan++) {
                        dimm = mci->csrows[index]->channels[chan]->dimm;
 
@@ -423,7 +413,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
                                 (chan == 0) ? 'A' : 'B',
                                 index);
                        dimm->grain = 1 << 7;   /* 128Byte cache-line resolution */
-                       dimm->dtype = i82975x_dram_type(mch_window, index);
+
+                       /* ECC is possible on i92975x ONLY with DEV_X8.  */
+                       dimm->dtype = DEV_X8;
+
                        dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
                        dimm->edac_mode = EDAC_SECDED; /* only supported */
                }
@@ -655,8 +648,8 @@ static int __init i82975x_init(void)
 
        edac_dbg(3, "\n");
 
-       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
-       opstate_init();
+       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+       opstate_init();
 
        pci_rc = pci_register_driver(&i82975x_driver);
        if (pci_rc < 0)
index 82bd775124f2c899d6570e147159ddd71f7097e1..97a27e42dd610db0d3cf656357bf7421e57b56ff 100644 (file)
@@ -292,7 +292,6 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
        struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
        irqreturn_t irq_rc = IRQ_NONE;
        u32 drp_error, trp_error, i;
-       bool irq_handled;
        int ret;
 
        /* Iterate over the banks and look for Tag RAM or Data RAM errors */
@@ -311,7 +310,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
                        ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
                }
                if (!ret)
-                       irq_handled = true;
+                       irq_rc = IRQ_HANDLED;
 
                ret = regmap_read(drv->regmap,
                                  drv->offsets[i] + TRP_INTERRUPT_0_STATUS,
@@ -327,12 +326,9 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
                        ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
                }
                if (!ret)
-                       irq_handled = true;
+                       irq_rc = IRQ_HANDLED;
        }
 
-       if (irq_handled)
-               irq_rc = IRQ_HANDLED;
-
        return irq_rc;
 }
 
index a99ea61dad321dddad4ab28bea15ce593ae0c24f..93ef161bb5e1f40b6488191b1821cdafd397a1ef 100644 (file)
@@ -209,7 +209,7 @@ static int get_all_bus_mappings(void)
                d->bus[1] =  GET_BITFIELD(reg, 8, 15);
                d->bus[2] =  GET_BITFIELD(reg, 16, 23);
                d->bus[3] =  GET_BITFIELD(reg, 24, 31);
-               edac_dbg(2, "busses: %x, %x, %x, %x\n",
+               edac_dbg(2, "busses: 0x%x, 0x%x, 0x%x, 0x%x\n",
                         d->bus[0], d->bus[1], d->bus[2], d->bus[3]);
                list_add_tail(&d->list, &skx_edac_list);
                skx_num_sockets++;
@@ -245,8 +245,8 @@ static int get_all_munits(const struct munit *m)
 
                /* Be sure that the device is enabled */
                if (unlikely(pci_enable_device(pdev) < 0)) {
-                       skx_printk(KERN_ERR,
-                               "Couldn't enable %04x:%04x\n", PCI_VENDOR_ID_INTEL, m->did);
+                       skx_printk(KERN_ERR, "Couldn't enable device %04x:%04x\n",
+                                  PCI_VENDOR_ID_INTEL, m->did);
                        goto fail;
                }
 
@@ -323,7 +323,7 @@ static int get_dimm_attr(u32 reg, int lobit, int hibit, int add, int minval,
        u32 val = GET_BITFIELD(reg, lobit, hibit);
 
        if (val < minval || val > maxval) {
-               edac_dbg(2, "bad %s = %d (raw=%x)\n", name, val, reg);
+               edac_dbg(2, "bad %s = %d (raw=0x%x)\n", name, val, reg);
                return -EINVAL;
        }
        return val + add;
@@ -368,7 +368,7 @@ static int skx_get_hi_lo(void)
        skx_tohm |= (u64)reg << 32;
 
        pci_dev_put(pdev);
-       edac_dbg(2, "tolm=%llx tohm=%llx\n", skx_tolm, skx_tohm);
+       edac_dbg(2, "tolm=0x%llx tohm=0x%llx\n", skx_tolm, skx_tohm);
 
        return 0;
 }
@@ -389,7 +389,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
        size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3);
        npages = MiB_TO_PAGES(size);
 
-       edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+       edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: 0x%#x, col: 0x%#x\n",
                 imc->mc, chan, dimmno, size, npages,
                 banks, 1 << ranks, rows, cols);
 
@@ -430,18 +430,18 @@ static int get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,
        }
 
        if (smbios_handle < 0) {
-               skx_printk(KERN_ERR, "Can't find handle for NVDIMM ADR=%x\n", dev_handle);
+               skx_printk(KERN_ERR, "Can't find handle for NVDIMM ADR=0x%x\n", dev_handle);
                goto unknown_size;
        }
 
        if (flags & ACPI_NFIT_MEM_MAP_FAILED) {
-               skx_printk(KERN_ERR, "NVDIMM ADR=%x is not mapped\n", dev_handle);
+               skx_printk(KERN_ERR, "NVDIMM ADR=0x%x is not mapped\n", dev_handle);
                goto unknown_size;
        }
 
        size = dmi_memdev_size(smbios_handle);
        if (size == ~0ull)
-               skx_printk(KERN_ERR, "Can't find size for NVDIMM ADR=%x/SMBIOS=%x\n",
+               skx_printk(KERN_ERR, "Can't find size for NVDIMM ADR=0x%x/SMBIOS=0x%x\n",
                           dev_handle, smbios_handle);
 
 unknown_size:
@@ -616,7 +616,7 @@ static bool skx_sad_decode(struct decoded_addr *res)
 
        /* Simple sanity check for I/O space or out of range */
        if (addr >= skx_tohm || (addr >= skx_tolm && addr < BIT_ULL(32))) {
-               edac_dbg(0, "Address %llx out of range\n", addr);
+               edac_dbg(0, "Address 0x%llx out of range\n", addr);
                return false;
        }
 
@@ -631,7 +631,7 @@ restart:
                }
                prev_limit = limit + 1;
        }
-       edac_dbg(0, "No SAD entry for %llx\n", addr);
+       edac_dbg(0, "No SAD entry for 0x%llx\n", addr);
        return false;
 
 sad_found:
@@ -709,7 +709,7 @@ sad_found:
        res->imc = GET_BITFIELD(d->mcroute, lchan * 3, lchan * 3 + 2);
        res->channel = GET_BITFIELD(d->mcroute, lchan * 2 + 18, lchan * 2 + 19);
 
-       edac_dbg(2, "%llx: socket=%d imc=%d channel=%d\n",
+       edac_dbg(2, "0x%llx: socket=%d imc=%d channel=%d\n",
                 res->addr, res->socket, res->imc, res->channel);
        return true;
 }
@@ -756,7 +756,7 @@ static bool skx_tad_decode(struct decoded_addr *res)
                if (SKX_TAD_BASE(base) <= res->addr && res->addr <= SKX_TAD_LIMIT(wayness))
                        goto tad_found;
        }
-       edac_dbg(0, "No TAD entry for %llx\n", res->addr);
+       edac_dbg(0, "No TAD entry for 0x%llx\n", res->addr);
        return false;
 
 tad_found:
@@ -784,7 +784,7 @@ tad_found:
 
        res->chan_addr = channel_addr;
 
-       edac_dbg(2, "%llx: chan_addr=%llx sktways=%d chanways=%d\n",
+       edac_dbg(2, "0x%llx: chan_addr=0x%llx sktways=%d chanways=%d\n",
                 res->addr, res->chan_addr, res->sktways, res->chanways);
        return true;
 }
@@ -826,7 +826,7 @@ static bool skx_rir_decode(struct decoded_addr *res)
                }
                prev_limit = limit;
        }
-       edac_dbg(0, "No RIR entry for %llx\n", res->addr);
+       edac_dbg(0, "No RIR entry for 0x%llx\n", res->addr);
        return false;
 
 rir_found:
@@ -845,7 +845,7 @@ rir_found:
        res->dimm = chan_rank / 4;
        res->rank = chan_rank % 4;
 
-       edac_dbg(2, "%llx: dimm=%d rank=%d chan_rank=%d rank_addr=%llx\n",
+       edac_dbg(2, "0x%llx: dimm=%d rank=%d chan_rank=%d rank_addr=0x%llx\n",
                 res->addr, res->dimm, res->rank,
                 res->channel_rank, res->rank_address);
        return true;
@@ -908,7 +908,7 @@ static bool skx_mad_decode(struct decoded_addr *r)
        }
        r->row &= (1u << dimm->rowbits) - 1;
 
-       edac_dbg(2, "%llx: row=%x col=%x bank_addr=%d bank_group=%d\n",
+       edac_dbg(2, "0x%llx: row=0x%x col=0x%x bank_addr=%d bank_group=%d\n",
                 r->addr, r->row, r->column, r->bank_address,
                 r->bank_group);
        return true;
@@ -921,53 +921,6 @@ static bool skx_decode(struct decoded_addr *res)
                skx_rir_decode(res) && skx_mad_decode(res);
 }
 
-#ifdef CONFIG_EDAC_DEBUG
-/*
- * Debug feature. Make /sys/kernel/debug/skx_edac_test/addr.
- * Write an address to this file to exercise the address decode
- * logic in this driver.
- */
-static struct dentry *skx_test;
-static u64 skx_fake_addr;
-
-static int debugfs_u64_set(void *data, u64 val)
-{
-       struct decoded_addr res;
-
-       res.addr = val;
-       skx_decode(&res);
-
-       return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
-
-static struct dentry *mydebugfs_create(const char *name, umode_t mode,
-                                      struct dentry *parent, u64 *value)
-{
-       return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
-}
-
-static void setup_skx_debug(void)
-{
-       skx_test = debugfs_create_dir("skx_edac_test", NULL);
-       mydebugfs_create("addr", S_IWUSR, skx_test, &skx_fake_addr);
-}
-
-static void teardown_skx_debug(void)
-{
-       debugfs_remove_recursive(skx_test);
-}
-#else
-static void setup_skx_debug(void)
-{
-}
-
-static void teardown_skx_debug(void)
-{
-}
-#endif /*CONFIG_EDAC_DEBUG*/
-
 static bool skx_adxl_decode(struct decoded_addr *res)
 
 {
@@ -1069,13 +1022,13 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
                }
        }
        if (adxl_component_count) {
-               snprintf(skx_msg, MSG_SIZE, "%s%s err_code:%04x:%04x %s",
+               snprintf(skx_msg, MSG_SIZE, "%s%s err_code:0x%04x:0x%04x %s",
                         overflow ? " OVERFLOW" : "",
                         (uncorrected_error && recoverable) ? " recoverable" : "",
                         mscod, errcode, adxl_msg);
        } else {
                snprintf(skx_msg, MSG_SIZE,
-                        "%s%s err_code:%04x:%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:%x col:%x",
+                        "%s%s err_code:0x%04x:0x%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:0x%x col:0x%x",
                         overflow ? " OVERFLOW" : "",
                         (uncorrected_error && recoverable) ? " recoverable" : "",
                         mscod, errcode,
@@ -1151,15 +1104,15 @@ static int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
 
        skx_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n");
 
-       skx_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx "
+       skx_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: 0x%llx "
                          "Bank %d: %016Lx\n", mce->extcpu, type,
                          mce->mcgstatus, mce->bank, mce->status);
-       skx_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc);
-       skx_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr);
-       skx_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc);
+       skx_mc_printk(mci, KERN_DEBUG, "TSC 0x%llx ", mce->tsc);
+       skx_mc_printk(mci, KERN_DEBUG, "ADDR 0x%llx ", mce->addr);
+       skx_mc_printk(mci, KERN_DEBUG, "MISC 0x%llx ", mce->misc);
 
-       skx_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET "
-                         "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
+       skx_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:0x%x TIME %llu SOCKET "
+                         "%u APIC 0x%x\n", mce->cpuvendor, mce->cpuid,
                          mce->time, mce->socketid, mce->apicid);
 
        skx_mce_output_error(mci, mce, &res);
@@ -1172,6 +1125,54 @@ static struct notifier_block skx_mce_dec = {
        .priority       = MCE_PRIO_EDAC,
 };
 
+#ifdef CONFIG_EDAC_DEBUG
+/*
+ * Debug feature.
+ * Exercise the address decode logic by writing an address to
+ * /sys/kernel/debug/edac/skx_test/addr.
+ */
+static struct dentry *skx_test;
+
+static int debugfs_u64_set(void *data, u64 val)
+{
+       struct mce m;
+
+       pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
+
+       memset(&m, 0, sizeof(m));
+       /* ADDRV + MemRd + Unknown channel */
+       m.status = MCI_STATUS_ADDRV + 0x90;
+       /* One corrected error */
+       m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
+       m.addr = val;
+       skx_mce_check_error(NULL, 0, &m);
+
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+
+static void setup_skx_debug(void)
+{
+       skx_test = edac_debugfs_create_dir("skx_test");
+       if (!skx_test)
+               return;
+
+       if (!edac_debugfs_create_file("addr", 0200, skx_test,
+                                     NULL, &fops_u64_wo)) {
+               debugfs_remove(skx_test);
+               skx_test = NULL;
+       }
+}
+
+static void teardown_skx_debug(void)
+{
+       debugfs_remove_recursive(skx_test);
+}
+#else
+static void setup_skx_debug(void) {}
+static void teardown_skx_debug(void) {}
+#endif /*CONFIG_EDAC_DEBUG*/
+
 static void skx_remove(void)
 {
        int i, j;
@@ -1291,7 +1292,7 @@ static int __init skx_init(void)
                if (rc < 0)
                        goto fail;
                if (rc != m->per_socket * skx_num_sockets) {
-                       edac_dbg(2, "Expected %d, got %d of %x\n",
+                       edac_dbg(2, "Expected %d, got %d of 0x%x\n",
                                 m->per_socket * skx_num_sockets, rc, m->did);
                        rc = -ENODEV;
                        goto fail;
@@ -1339,11 +1340,11 @@ static void __exit skx_exit(void)
 {
        edac_dbg(2, "\n");
        mce_unregister_decode_chain(&skx_mce_dec);
-       skx_remove();
+       teardown_skx_debug();
        if (nvdimm_count)
                skx_adxl_put();
        kfree(skx_msg);
-       teardown_skx_debug();
+       skx_remove();
 }
 
 module_init(skx_init);
index 0c9c59e2b5a3f0e34c82da27911fa52bed6ed88d..2d263382d797f0440d1e07408445ef4bf76c70fc 100644 (file)
 #include <linux/edac.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "edac_module.h"
 
 /* Number of cs_rows needed per memory controller */
-#define SYNPS_EDAC_NR_CSROWS   1
+#define SYNPS_EDAC_NR_CSROWS           1
 
 /* Number of channels per memory controller */
-#define SYNPS_EDAC_NR_CHANS    1
+#define SYNPS_EDAC_NR_CHANS            1
 
 /* Granularity of reported error in bytes */
-#define SYNPS_EDAC_ERR_GRAIN   1
+#define SYNPS_EDAC_ERR_GRAIN           1
 
-#define SYNPS_EDAC_MSG_SIZE    256
+#define SYNPS_EDAC_MSG_SIZE            256
 
-#define SYNPS_EDAC_MOD_STRING  "synps_edac"
-#define SYNPS_EDAC_MOD_VER     "1"
+#define SYNPS_EDAC_MOD_STRING          "synps_edac"
+#define SYNPS_EDAC_MOD_VER             "1"
 
 /* Synopsys DDR memory controller registers that are relevant to ECC */
-#define CTRL_OFST              0x0
-#define T_ZQ_OFST              0xA4
+#define CTRL_OFST                      0x0
+#define T_ZQ_OFST                      0xA4
 
 /* ECC control register */
-#define ECC_CTRL_OFST          0xC4
+#define ECC_CTRL_OFST                  0xC4
 /* ECC log register */
-#define CE_LOG_OFST            0xC8
+#define CE_LOG_OFST                    0xC8
 /* ECC address register */
-#define CE_ADDR_OFST           0xCC
+#define CE_ADDR_OFST                   0xCC
 /* ECC data[31:0] register */
-#define CE_DATA_31_0_OFST      0xD0
+#define CE_DATA_31_0_OFST              0xD0
 
 /* Uncorrectable error info registers */
-#define UE_LOG_OFST            0xDC
-#define UE_ADDR_OFST           0xE0
-#define UE_DATA_31_0_OFST      0xE4
+#define UE_LOG_OFST                    0xDC
+#define UE_ADDR_OFST                   0xE0
+#define UE_DATA_31_0_OFST              0xE4
 
-#define STAT_OFST              0xF0
-#define SCRUB_OFST             0xF4
+#define STAT_OFST                      0xF0
+#define SCRUB_OFST                     0xF4
 
 /* Control register bit field definitions */
-#define CTRL_BW_MASK           0xC
-#define CTRL_BW_SHIFT          2
+#define CTRL_BW_MASK                   0xC
+#define CTRL_BW_SHIFT                  2
 
-#define DDRCTL_WDTH_16         1
-#define DDRCTL_WDTH_32         0
+#define DDRCTL_WDTH_16                 1
+#define DDRCTL_WDTH_32                 0
 
 /* ZQ register bit field definitions */
-#define T_ZQ_DDRMODE_MASK      0x2
+#define T_ZQ_DDRMODE_MASK              0x2
 
 /* ECC control register bit field definitions */
-#define ECC_CTRL_CLR_CE_ERR    0x2
-#define ECC_CTRL_CLR_UE_ERR    0x1
+#define ECC_CTRL_CLR_CE_ERR            0x2
+#define ECC_CTRL_CLR_UE_ERR            0x1
 
 /* ECC correctable/uncorrectable error log register definitions */
-#define LOG_VALID              0x1
-#define CE_LOG_BITPOS_MASK     0xFE
-#define CE_LOG_BITPOS_SHIFT    1
+#define LOG_VALID                      0x1
+#define CE_LOG_BITPOS_MASK             0xFE
+#define CE_LOG_BITPOS_SHIFT            1
 
 /* ECC correctable/uncorrectable error address register definitions */
-#define ADDR_COL_MASK          0xFFF
-#define ADDR_ROW_MASK          0xFFFF000
-#define ADDR_ROW_SHIFT         12
-#define ADDR_BANK_MASK         0x70000000
-#define ADDR_BANK_SHIFT                28
+#define ADDR_COL_MASK                  0xFFF
+#define ADDR_ROW_MASK                  0xFFFF000
+#define ADDR_ROW_SHIFT                 12
+#define ADDR_BANK_MASK                 0x70000000
+#define ADDR_BANK_SHIFT                        28
 
 /* ECC statistic register definitions */
-#define STAT_UECNT_MASK                0xFF
-#define STAT_CECNT_MASK                0xFF00
-#define STAT_CECNT_SHIFT       8
+#define STAT_UECNT_MASK                        0xFF
+#define STAT_CECNT_MASK                        0xFF00
+#define STAT_CECNT_SHIFT               8
 
 /* ECC scrub register definitions */
-#define SCRUB_MODE_MASK                0x7
-#define SCRUB_MODE_SECDED      0x4
+#define SCRUB_MODE_MASK                        0x7
+#define SCRUB_MODE_SECDED              0x4
+
+/* DDR ECC Quirks */
+#define DDR_ECC_INTR_SUPPORT           BIT(0)
+#define DDR_ECC_DATA_POISON_SUPPORT    BIT(1)
+
+/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
+/* ECC Configuration Registers */
+#define ECC_CFG0_OFST                  0x70
+#define ECC_CFG1_OFST                  0x74
+
+/* ECC Status Register */
+#define ECC_STAT_OFST                  0x78
+
+/* ECC Clear Register */
+#define ECC_CLR_OFST                   0x7C
+
+/* ECC Error count Register */
+#define ECC_ERRCNT_OFST                        0x80
+
+/* ECC Corrected Error Address Register */
+#define ECC_CEADDR0_OFST               0x84
+#define ECC_CEADDR1_OFST               0x88
+
+/* ECC Syndrome Registers */
+#define ECC_CSYND0_OFST                        0x8C
+#define ECC_CSYND1_OFST                        0x90
+#define ECC_CSYND2_OFST                        0x94
+
+/* ECC Bit Mask0 Address Register */
+#define ECC_BITMASK0_OFST              0x98
+#define ECC_BITMASK1_OFST              0x9C
+#define ECC_BITMASK2_OFST              0xA0
+
+/* ECC UnCorrected Error Address Register */
+#define ECC_UEADDR0_OFST               0xA4
+#define ECC_UEADDR1_OFST               0xA8
+
+/* ECC Syndrome Registers */
+#define ECC_UESYND0_OFST               0xAC
+#define ECC_UESYND1_OFST               0xB0
+#define ECC_UESYND2_OFST               0xB4
+
+/* ECC Poison Address Reg */
+#define ECC_POISON0_OFST               0xB8
+#define ECC_POISON1_OFST               0xBC
+
+#define ECC_ADDRMAP0_OFFSET            0x200
+
+/* Control register bitfield definitions */
+#define ECC_CTRL_BUSWIDTH_MASK         0x3000
+#define ECC_CTRL_BUSWIDTH_SHIFT                12
+#define ECC_CTRL_CLR_CE_ERRCNT         BIT(2)
+#define ECC_CTRL_CLR_UE_ERRCNT         BIT(3)
+
+/* DDR Control Register width definitions  */
+#define DDRCTL_EWDTH_16                        2
+#define DDRCTL_EWDTH_32                        1
+#define DDRCTL_EWDTH_64                        0
+
+/* ECC status register definitions */
+#define ECC_STAT_UECNT_MASK            0xF0000
+#define ECC_STAT_UECNT_SHIFT           16
+#define ECC_STAT_CECNT_MASK            0xF00
+#define ECC_STAT_CECNT_SHIFT           8
+#define ECC_STAT_BITNUM_MASK           0x7F
+
+/* DDR QOS Interrupt register definitions */
+#define DDR_QOS_IRQ_STAT_OFST          0x20200
+#define DDR_QOSUE_MASK                 0x4
+#define        DDR_QOSCE_MASK                  0x2
+#define        ECC_CE_UE_INTR_MASK             0x6
+#define DDR_QOS_IRQ_EN_OFST            0x20208
+#define DDR_QOS_IRQ_DB_OFST            0x2020C
+
+/* ECC Corrected Error Register Mask and Shifts*/
+#define ECC_CEADDR0_RW_MASK            0x3FFFF
+#define ECC_CEADDR0_RNK_MASK           BIT(24)
+#define ECC_CEADDR1_BNKGRP_MASK                0x3000000
+#define ECC_CEADDR1_BNKNR_MASK         0x70000
+#define ECC_CEADDR1_BLKNR_MASK         0xFFF
+#define ECC_CEADDR1_BNKGRP_SHIFT       24
+#define ECC_CEADDR1_BNKNR_SHIFT                16
+
+/* ECC Poison register shifts */
+#define ECC_POISON0_RANK_SHIFT         24
+#define ECC_POISON0_RANK_MASK          BIT(24)
+#define ECC_POISON0_COLUMN_SHIFT       0
+#define ECC_POISON0_COLUMN_MASK                0xFFF
+#define ECC_POISON1_BG_SHIFT           28
+#define ECC_POISON1_BG_MASK            0x30000000
+#define ECC_POISON1_BANKNR_SHIFT       24
+#define ECC_POISON1_BANKNR_MASK                0x7000000
+#define ECC_POISON1_ROW_SHIFT          0
+#define ECC_POISON1_ROW_MASK           0x3FFFF
+
+/* DDR Memory type defines */
+#define MEM_TYPE_DDR3                  0x1
+#define MEM_TYPE_LPDDR3                        0x8
+#define MEM_TYPE_DDR2                  0x4
+#define MEM_TYPE_DDR4                  0x10
+#define MEM_TYPE_LPDDR4                        0x20
+
+/* DDRC Software control register */
+#define DDRC_SWCTL                     0x320
+
+/* DDRC ECC CE & UE poison mask */
+#define ECC_CEPOISON_MASK              0x3
+#define ECC_UEPOISON_MASK              0x1
+
+/* DDRC Device config masks */
+#define DDRC_MSTR_CFG_MASK             0xC0000000
+#define DDRC_MSTR_CFG_SHIFT            30
+#define DDRC_MSTR_CFG_X4_MASK          0x0
+#define DDRC_MSTR_CFG_X8_MASK          0x1
+#define DDRC_MSTR_CFG_X16_MASK         0x2
+#define DDRC_MSTR_CFG_X32_MASK         0x3
+
+#define DDR_MAX_ROW_SHIFT              18
+#define DDR_MAX_COL_SHIFT              14
+#define DDR_MAX_BANK_SHIFT             3
+#define DDR_MAX_BANKGRP_SHIFT          2
+
+#define ROW_MAX_VAL_MASK               0xF
+#define COL_MAX_VAL_MASK               0xF
+#define BANK_MAX_VAL_MASK              0x1F
+#define BANKGRP_MAX_VAL_MASK           0x1F
+#define RANK_MAX_VAL_MASK              0x1F
+
+#define ROW_B0_BASE                    6
+#define ROW_B1_BASE                    7
+#define ROW_B2_BASE                    8
+#define ROW_B3_BASE                    9
+#define ROW_B4_BASE                    10
+#define ROW_B5_BASE                    11
+#define ROW_B6_BASE                    12
+#define ROW_B7_BASE                    13
+#define ROW_B8_BASE                    14
+#define ROW_B9_BASE                    15
+#define ROW_B10_BASE                   16
+#define ROW_B11_BASE                   17
+#define ROW_B12_BASE                   18
+#define ROW_B13_BASE                   19
+#define ROW_B14_BASE                   20
+#define ROW_B15_BASE                   21
+#define ROW_B16_BASE                   22
+#define ROW_B17_BASE                   23
+
+#define COL_B2_BASE                    2
+#define COL_B3_BASE                    3
+#define COL_B4_BASE                    4
+#define COL_B5_BASE                    5
+#define COL_B6_BASE                    6
+#define COL_B7_BASE                    7
+#define COL_B8_BASE                    8
+#define COL_B9_BASE                    9
+#define COL_B10_BASE                   10
+#define COL_B11_BASE                   11
+#define COL_B12_BASE                   12
+#define COL_B13_BASE                   13
+
+#define BANK_B0_BASE                   2
+#define BANK_B1_BASE                   3
+#define BANK_B2_BASE                   4
+
+#define BANKGRP_B0_BASE                        2
+#define BANKGRP_B1_BASE                        3
+
+#define RANK_B0_BASE                   6
 
 /**
- * struct ecc_error_info - ECC error log information
- * @row:       Row number
- * @col:       Column number
- * @bank:      Bank number
- * @bitpos:    Bit position
- * @data:      Data causing the error
+ * struct ecc_error_info - ECC error log information.
+ * @row:       Row number.
+ * @col:       Column number.
+ * @bank:      Bank number.
+ * @bitpos:    Bit position.
+ * @data:      Data causing the error.
+ * @bankgrpnr: Bank group number.
+ * @blknr:     Block number.
  */
 struct ecc_error_info {
        u32 row;
@@ -109,14 +282,16 @@ struct ecc_error_info {
        u32 bank;
        u32 bitpos;
        u32 data;
+       u32 bankgrpnr;
+       u32 blknr;
 };
 
 /**
- * struct synps_ecc_status - ECC status information to report
- * @ce_cnt:    Correctable error count
- * @ue_cnt:    Uncorrectable error count
- * @ceinfo:    Correctable error log information
- * @ueinfo:    Uncorrectable error log information
+ * struct synps_ecc_status - ECC status information to report.
+ * @ce_cnt:    Correctable error count.
+ * @ue_cnt:    Uncorrectable error count.
+ * @ceinfo:    Correctable error log information.
+ * @ueinfo:    Uncorrectable error log information.
  */
 struct synps_ecc_status {
        u32 ce_cnt;
@@ -126,34 +301,67 @@ struct synps_ecc_status {
 };
 
 /**
- * struct synps_edac_priv - DDR memory controller private instance data
- * @baseaddr:  Base address of the DDR controller
- * @message:   Buffer for framing the event specific info
- * @stat:      ECC status information
- * @ce_cnt:    Correctable Error count
- * @ue_cnt:    Uncorrectable Error count
+ * struct synps_edac_priv - DDR memory controller private instance data.
+ * @baseaddr:          Base address of the DDR controller.
+ * @message:           Buffer for framing the event specific info.
+ * @stat:              ECC status information.
+ * @p_data:            Platform data.
+ * @ce_cnt:            Correctable Error count.
+ * @ue_cnt:            Uncorrectable Error count.
+ * @poison_addr:       Data poison address.
+ * @row_shift:         Bit shifts for row bit.
+ * @col_shift:         Bit shifts for column bit.
+ * @bank_shift:                Bit shifts for bank bit.
+ * @bankgrp_shift:     Bit shifts for bank group bit.
+ * @rank_shift:                Bit shifts for rank bit.
  */
 struct synps_edac_priv {
        void __iomem *baseaddr;
        char message[SYNPS_EDAC_MSG_SIZE];
        struct synps_ecc_status stat;
+       const struct synps_platform_data *p_data;
        u32 ce_cnt;
        u32 ue_cnt;
+#ifdef CONFIG_EDAC_DEBUG
+       ulong poison_addr;
+       u32 row_shift[18];
+       u32 col_shift[14];
+       u32 bank_shift[3];
+       u32 bankgrp_shift[2];
+       u32 rank_shift[1];
+#endif
 };
 
 /**
- * synps_edac_geterror_info - Get the current ecc error info
- * @base:      Pointer to the base address of the ddr memory controller
- * @p:         Pointer to the synopsys ecc status structure
- *
- * Determines there is any ecc error or not
+ * struct synps_platform_data -  synps platform data structure.
+ * @get_error_info:    Get EDAC error info.
+ * @get_mtype:         Get mtype.
+ * @get_dtype:         Get dtype.
+ * @get_ecc_state:     Get ECC state.
+ * @quirks:            To differentiate IPs.
+ */
+struct synps_platform_data {
+       int (*get_error_info)(struct synps_edac_priv *priv);
+       enum mem_type (*get_mtype)(const void __iomem *base);
+       enum dev_type (*get_dtype)(const void __iomem *base);
+       bool (*get_ecc_state)(void __iomem *base);
+       int quirks;
+};
+
+/**
+ * zynq_get_error_info - Get the current ECC error info.
+ * @priv:      DDR memory controller private instance data.
  *
- * Return: one if there is no error otherwise returns zero
+ * Return: one if there is no error, otherwise zero.
  */
-static int synps_edac_geterror_info(void __iomem *base,
-                                   struct synps_ecc_status *p)
+static int zynq_get_error_info(struct synps_edac_priv *priv)
 {
+       struct synps_ecc_status *p;
        u32 regval, clearval = 0;
+       void __iomem *base;
+
+       base = priv->baseaddr;
+       p = &priv->stat;
 
        regval = readl(base + STAT_OFST);
        if (!regval)
@@ -172,7 +380,7 @@ static int synps_edac_geterror_info(void __iomem *base,
        p->ceinfo.col = regval & ADDR_COL_MASK;
        p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
        p->ceinfo.data = readl(base + CE_DATA_31_0_OFST);
-       edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos,
+       edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos,
                 p->ceinfo.data);
        clearval = ECC_CTRL_CLR_CE_ERR;
 
@@ -196,23 +404,98 @@ out:
 }
 
 /**
- * synps_edac_handle_error - Handle controller error types CE and UE
- * @mci:       Pointer to the edac memory controller instance
- * @p:         Pointer to the synopsys ecc status structure
+ * zynqmp_get_error_info - Get the current ECC error info.
+ * @priv:      DDR memory controller private instance data.
  *
- * Handles the controller ECC correctable and un correctable error.
+ * Return: one if there is no error otherwise returns zero.
  */
-static void synps_edac_handle_error(struct mem_ctl_info *mci,
-                                   struct synps_ecc_status *p)
+static int zynqmp_get_error_info(struct synps_edac_priv *priv)
+{
+       struct synps_ecc_status *p;
+       u32 regval, clearval = 0;
+       void __iomem *base;
+
+       base = priv->baseaddr;
+       p = &priv->stat;
+
+       regval = readl(base + ECC_STAT_OFST);
+       if (!regval)
+               return 1;
+
+       p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT;
+       p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT;
+       if (!p->ce_cnt)
+               goto ue_err;
+
+       p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK);
+
+       regval = readl(base + ECC_CEADDR0_OFST);
+       p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK);
+       regval = readl(base + ECC_CEADDR1_OFST);
+       p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >>
+                                       ECC_CEADDR1_BNKNR_SHIFT;
+       p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >>
+                                       ECC_CEADDR1_BNKGRP_SHIFT;
+       p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK);
+       p->ceinfo.data = readl(base + ECC_CSYND0_OFST);
+       edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n",
+                readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST),
+                readl(base + ECC_CSYND2_OFST));
+ue_err:
+       if (!p->ue_cnt)
+               goto out;
+
+       regval = readl(base + ECC_UEADDR0_OFST);
+       p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK);
+       regval = readl(base + ECC_UEADDR1_OFST);
+       p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >>
+                                       ECC_CEADDR1_BNKGRP_SHIFT;
+       p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >>
+                                       ECC_CEADDR1_BNKNR_SHIFT;
+       p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK);
+       p->ueinfo.data = readl(base + ECC_UESYND0_OFST);
+out:
+       clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT;
+       clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT;
+       writel(clearval, base + ECC_CLR_OFST);
+       writel(0x0, base + ECC_CLR_OFST);
+
+       return 0;
+}
+
+/**
+ * handle_error - Handle Correctable and Uncorrectable errors.
+ * @mci:       EDAC memory controller instance.
+ * @p:         Synopsys ECC status structure.
+ *
+ * Handles ECC correctable and uncorrectable errors.
+ */
+static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
 {
        struct synps_edac_priv *priv = mci->pvt_info;
        struct ecc_error_info *pinf;
 
        if (p->ce_cnt) {
                pinf = &p->ceinfo;
-               snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                        "DDR ECC error type :%s Row %d Bank %d Col %d ",
-                        "CE", pinf->row, pinf->bank, pinf->col);
+               if (!priv->p_data->quirks) {
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "DDR ECC error type:%s Row %d Bank %d Col %d ",
+                                 "CE", pinf->row, pinf->bank, pinf->col);
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "Bit Position: %d Data: 0x%08x\n",
+                                pinf->bitpos, pinf->data);
+               } else {
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "DDR ECC error type:%s Row %d Bank %d Col %d ",
+                                 "CE", pinf->row, pinf->bank, pinf->col);
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "BankGroup Number %d Block Number %d ",
+                                pinf->bankgrpnr, pinf->blknr);
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "Bit Position: %d Data: 0x%08x\n",
+                                pinf->bitpos, pinf->data);
+               }
+
                edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
                                     p->ce_cnt, 0, 0, 0, 0, 0, -1,
                                     priv->message, "");
@@ -220,9 +503,19 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci,
 
        if (p->ue_cnt) {
                pinf = &p->ueinfo;
-               snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                        "DDR ECC error type :%s Row %d Bank %d Col %d ",
-                        "UE", pinf->row, pinf->bank, pinf->col);
+               if (!priv->p_data->quirks) {
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "DDR ECC error type :%s Row %d Bank %d Col %d ",
+                               "UE", pinf->row, pinf->bank, pinf->col);
+               } else {
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "DDR ECC error type :%s Row %d Bank %d Col %d ",
+                                "UE", pinf->row, pinf->bank, pinf->col);
+                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+                                "BankGroup Number %d Block Number %d",
+                                pinf->bankgrpnr, pinf->blknr);
+               }
+
                edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
                                     p->ue_cnt, 0, 0, 0, 0, 0, -1,
                                     priv->message, "");
@@ -232,38 +525,78 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci,
 }
 
 /**
- * synps_edac_check - Check controller for ECC errors
- * @mci:       Pointer to the edac memory controller instance
+ * intr_handler - Interrupt Handler for ECC interrupts.
+ * @irq:        IRQ number.
+ * @dev_id:     Device ID.
  *
- * Used to check and post ECC errors. Called by the polling thread
+ * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise.
  */
-static void synps_edac_check(struct mem_ctl_info *mci)
+static irqreturn_t intr_handler(int irq, void *dev_id)
 {
-       struct synps_edac_priv *priv = mci->pvt_info;
+       const struct synps_platform_data *p_data;
+       struct mem_ctl_info *mci = dev_id;
+       struct synps_edac_priv *priv;
+       int status, regval;
+
+       priv = mci->pvt_info;
+       p_data = priv->p_data;
+
+       regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
+       regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
+       if (!(regval & ECC_CE_UE_INTR_MASK))
+               return IRQ_NONE;
+
+       status = p_data->get_error_info(priv);
+       if (status)
+               return IRQ_NONE;
+
+       priv->ce_cnt += priv->stat.ce_cnt;
+       priv->ue_cnt += priv->stat.ue_cnt;
+       handle_error(mci, &priv->stat);
+
+       edac_dbg(3, "Total error count CE %d UE %d\n",
+                priv->ce_cnt, priv->ue_cnt);
+       writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
+       return IRQ_HANDLED;
+}
+
+/**
+ * check_errors - Check controller for ECC errors.
+ * @mci:       EDAC memory controller instance.
+ *
+ * Check and post ECC errors. Called by the polling thread.
+ */
+static void check_errors(struct mem_ctl_info *mci)
+{
+       const struct synps_platform_data *p_data;
+       struct synps_edac_priv *priv;
        int status;
 
-       status = synps_edac_geterror_info(priv->baseaddr, &priv->stat);
+       priv = mci->pvt_info;
+       p_data = priv->p_data;
+
+       status = p_data->get_error_info(priv);
        if (status)
                return;
 
        priv->ce_cnt += priv->stat.ce_cnt;
        priv->ue_cnt += priv->stat.ue_cnt;
-       synps_edac_handle_error(mci, &priv->stat);
+       handle_error(mci, &priv->stat);
 
-       edac_dbg(3, "Total error count ce %d ue %d\n",
+       edac_dbg(3, "Total error count CE %d UE %d\n",
                 priv->ce_cnt, priv->ue_cnt);
 }
 
 /**
- * synps_edac_get_dtype - Return the controller memory width
- * @base:      Pointer to the ddr memory controller base address
+ * zynq_get_dtype - Return the controller memory width.
+ * @base:      DDR memory controller base address.
  *
  * Get the EDAC device type width appropriate for the current controller
  * configuration.
  *
  * Return: a device type width enumeration.
  */
-static enum dev_type synps_edac_get_dtype(const void __iomem *base)
+static enum dev_type zynq_get_dtype(const void __iomem *base)
 {
        enum dev_type dt;
        u32 width;
@@ -286,36 +619,93 @@ static enum dev_type synps_edac_get_dtype(const void __iomem *base)
 }
 
 /**
- * synps_edac_get_eccstate - Return the controller ecc enable/disable status
- * @base:      Pointer to the ddr memory controller base address
+ * zynqmp_get_dtype - Return the controller memory width.
+ * @base:      DDR memory controller base address.
+ *
+ * Get the EDAC device type width appropriate for the current controller
+ * configuration.
+ *
+ * Return: a device type width enumeration.
+ */
+static enum dev_type zynqmp_get_dtype(const void __iomem *base)
+{
+       enum dev_type dt;
+       u32 width;
+
+       width = readl(base + CTRL_OFST);
+       width = (width & ECC_CTRL_BUSWIDTH_MASK) >> ECC_CTRL_BUSWIDTH_SHIFT;
+       switch (width) {
+       case DDRCTL_EWDTH_16:
+               dt = DEV_X2;
+               break;
+       case DDRCTL_EWDTH_32:
+               dt = DEV_X4;
+               break;
+       case DDRCTL_EWDTH_64:
+               dt = DEV_X8;
+               break;
+       default:
+               dt = DEV_UNKNOWN;
+       }
+
+       return dt;
+}
+
+/**
+ * zynq_get_ecc_state - Return the controller ECC enable/disable status.
+ * @base:      DDR memory controller base address.
  *
- * Get the ECC enable/disable status for the controller
+ * Get the ECC enable/disable status of the controller.
  *
- * Return: a ecc status boolean i.e true/false - enabled/disabled.
+ * Return: true if enabled, otherwise false.
  */
-static bool synps_edac_get_eccstate(void __iomem *base)
+static bool zynq_get_ecc_state(void __iomem *base)
 {
        enum dev_type dt;
        u32 ecctype;
-       bool state = false;
 
-       dt = synps_edac_get_dtype(base);
+       dt = zynq_get_dtype(base);
        if (dt == DEV_UNKNOWN)
-               return state;
+               return false;
 
        ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
        if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
-               state = true;
+               return true;
 
-       return state;
+       return false;
 }
 
 /**
- * synps_edac_get_memsize - reads the size of the attached memory device
+ * zynqmp_get_ecc_state - Return the controller ECC enable/disable status.
+ * @base:      DDR memory controller base address.
  *
- * Return: the memory size in bytes
+ * Get the ECC enable/disable status for the controller.
+ *
+ * Return: a ECC status boolean i.e true/false - enabled/disabled.
  */
-static u32 synps_edac_get_memsize(void)
+static bool zynqmp_get_ecc_state(void __iomem *base)
+{
+       enum dev_type dt;
+       u32 ecctype;
+
+       dt = zynqmp_get_dtype(base);
+       if (dt == DEV_UNKNOWN)
+               return false;
+
+       ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
+       if ((ecctype == SCRUB_MODE_SECDED) &&
+           ((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8)))
+               return true;
+
+       return false;
+}
+
+/**
+ * get_memsize - Read the size of the attached memory device.
+ *
+ * Return: the memory size in bytes.
+ */
+static u32 get_memsize(void)
 {
        struct sysinfo inf;
 
@@ -325,15 +715,15 @@ static u32 synps_edac_get_memsize(void)
 }
 
 /**
- * synps_edac_get_mtype - Returns controller memory type
- * @base:      pointer to the synopsys ecc status structure
+ * zynq_get_mtype - Return the controller memory type.
+ * @base:      Synopsys ECC status structure.
  *
  * Get the EDAC memory type appropriate for the current controller
  * configuration.
  *
  * Return: a memory type enumeration.
  */
-static enum mem_type synps_edac_get_mtype(const void __iomem *base)
+static enum mem_type zynq_get_mtype(const void __iomem *base)
 {
        enum mem_type mt;
        u32 memtype;
@@ -349,54 +739,77 @@ static enum mem_type synps_edac_get_mtype(const void __iomem *base)
 }
 
 /**
- * synps_edac_init_csrows - Initialize the cs row data
- * @mci:       Pointer to the edac memory controller instance
+ * zynqmp_get_mtype - Returns controller memory type.
+ * @base:      Synopsys ECC status structure.
  *
- * Initializes the chip select rows associated with the EDAC memory
- * controller instance
+ * Get the EDAC memory type appropriate for the current controller
+ * configuration.
  *
- * Return: Unconditionally 0.
+ * Return: a memory type enumeration.
  */
-static int synps_edac_init_csrows(struct mem_ctl_info *mci)
+static enum mem_type zynqmp_get_mtype(const void __iomem *base)
 {
+       enum mem_type mt;
+       u32 memtype;
+
+       memtype = readl(base + CTRL_OFST);
+
+       if ((memtype & MEM_TYPE_DDR3) || (memtype & MEM_TYPE_LPDDR3))
+               mt = MEM_DDR3;
+       else if (memtype & MEM_TYPE_DDR2)
+               mt = MEM_RDDR2;
+       else if ((memtype & MEM_TYPE_LPDDR4) || (memtype & MEM_TYPE_DDR4))
+               mt = MEM_DDR4;
+       else
+               mt = MEM_EMPTY;
+
+       return mt;
+}
+
+/**
+ * init_csrows - Initialize the csrow data.
+ * @mci:       EDAC memory controller instance.
+ *
+ * Initialize the chip select rows associated with the EDAC memory
+ * controller instance.
+ */
+static void init_csrows(struct mem_ctl_info *mci)
+{
+       struct synps_edac_priv *priv = mci->pvt_info;
+       const struct synps_platform_data *p_data;
        struct csrow_info *csi;
        struct dimm_info *dimm;
-       struct synps_edac_priv *priv = mci->pvt_info;
-       u32 size;
-       int row, j;
+       u32 size, row;
+       int j;
+
+       p_data = priv->p_data;
 
        for (row = 0; row < mci->nr_csrows; row++) {
                csi = mci->csrows[row];
-               size = synps_edac_get_memsize();
+               size = get_memsize();
 
                for (j = 0; j < csi->nr_channels; j++) {
-                       dimm            = csi->channels[j]->dimm;
-                       dimm->edac_mode = EDAC_FLAG_SECDED;
-                       dimm->mtype     = synps_edac_get_mtype(priv->baseaddr);
-                       dimm->nr_pages  = (size >> PAGE_SHIFT) / csi->nr_channels;
-                       dimm->grain     = SYNPS_EDAC_ERR_GRAIN;
-                       dimm->dtype     = synps_edac_get_dtype(priv->baseaddr);
+                       dimm            = csi->channels[j]->dimm;
+                       dimm->edac_mode = EDAC_FLAG_SECDED;
+                       dimm->mtype     = p_data->get_mtype(priv->baseaddr);
+                       dimm->nr_pages  = (size >> PAGE_SHIFT) / csi->nr_channels;
+                       dimm->grain     = SYNPS_EDAC_ERR_GRAIN;
+                       dimm->dtype     = p_data->get_dtype(priv->baseaddr);
                }
        }
-
-       return 0;
 }
 
 /**
- * synps_edac_mc_init - Initialize driver instance
- * @mci:       Pointer to the edac memory controller instance
- * @pdev:      Pointer to the platform_device struct
+ * mc_init - Initialize one driver instance.
+ * @mci:       EDAC memory controller instance.
+ * @pdev:      platform device.
  *
- * Performs initialization of the EDAC memory controller instance and
+ * Perform initialization of the EDAC memory controller instance and
  * related driver-private data associated with the memory controller the
  * instance is bound to.
- *
- * Return: Always zero.
  */
-static int synps_edac_mc_init(struct mem_ctl_info *mci,
-                                struct platform_device *pdev)
+static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
 {
-       int status;
        struct synps_edac_priv *priv;
 
        mci->pdev = &pdev->dev;
@@ -414,39 +827,491 @@ static int synps_edac_mc_init(struct mem_ctl_info *mci,
        mci->dev_name = SYNPS_EDAC_MOD_STRING;
        mci->mod_name = SYNPS_EDAC_MOD_VER;
 
-       edac_op_state = EDAC_OPSTATE_POLL;
-       mci->edac_check = synps_edac_check;
+       if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
+               edac_op_state = EDAC_OPSTATE_INT;
+       } else {
+               edac_op_state = EDAC_OPSTATE_POLL;
+               mci->edac_check = check_errors;
+       }
+
        mci->ctl_page_to_phys = NULL;
 
-       status = synps_edac_init_csrows(mci);
+       init_csrows(mci);
+}
+
+static void enable_intr(struct synps_edac_priv *priv)
+{
+       /* Enable UE/CE Interrupts */
+       writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
+                       priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
+}
+
+static void disable_intr(struct synps_edac_priv *priv)
+{
+       /* Disable UE/CE Interrupts */
+       writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
+                       priv->baseaddr + DDR_QOS_IRQ_DB_OFST);
+}
+
+static int setup_irq(struct mem_ctl_info *mci,
+                    struct platform_device *pdev)
+{
+       struct synps_edac_priv *priv = mci->pvt_info;
+       int ret, irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "No IRQ %d in DT\n", irq);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, intr_handler,
+                              0, dev_name(&pdev->dev), mci);
+       if (ret < 0) {
+               edac_printk(KERN_ERR, EDAC_MC, "Failed to request IRQ\n");
+               return ret;
+       }
+
+       enable_intr(priv);
+
+       return 0;
+}
+
+static const struct synps_platform_data zynq_edac_def = {
+       .get_error_info = zynq_get_error_info,
+       .get_mtype      = zynq_get_mtype,
+       .get_dtype      = zynq_get_dtype,
+       .get_ecc_state  = zynq_get_ecc_state,
+       .quirks         = 0,
+};
+
+static const struct synps_platform_data zynqmp_edac_def = {
+       .get_error_info = zynqmp_get_error_info,
+       .get_mtype      = zynqmp_get_mtype,
+       .get_dtype      = zynqmp_get_dtype,
+       .get_ecc_state  = zynqmp_get_ecc_state,
+       .quirks         = (DDR_ECC_INTR_SUPPORT
+#ifdef CONFIG_EDAC_DEBUG
+                         | DDR_ECC_DATA_POISON_SUPPORT
+#endif
+                         ),
+};
+
+static const struct of_device_id synps_edac_match[] = {
+       {
+               .compatible = "xlnx,zynq-ddrc-a05",
+               .data = (void *)&zynq_edac_def
+       },
+       {
+               .compatible = "xlnx,zynqmp-ddrc-2.40a",
+               .data = (void *)&zynqmp_edac_def
+       },
+       {
+               /* end of table */
+       }
+};
+
+MODULE_DEVICE_TABLE(of, synps_edac_match);
+
+#ifdef CONFIG_EDAC_DEBUG
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+/**
+ * ddr_poison_setup -  Update poison registers.
+ * @priv:              DDR memory controller private instance data.
+ *
+ * Update poison registers as per DDR mapping.
+ * Return: none.
+ */
+static void ddr_poison_setup(struct synps_edac_priv *priv)
+{
+       int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
+       int index;
+       ulong hif_addr = 0;
+
+       hif_addr = priv->poison_addr >> 3;
+
+       for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) {
+               if (priv->row_shift[index])
+                       row |= (((hif_addr >> priv->row_shift[index]) &
+                                               BIT(0)) << index);
+               else
+                       break;
+       }
+
+       for (index = 0; index < DDR_MAX_COL_SHIFT; index++) {
+               if (priv->col_shift[index] || index < 3)
+                       col |= (((hif_addr >> priv->col_shift[index]) &
+                                               BIT(0)) << index);
+               else
+                       break;
+       }
+
+       for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) {
+               if (priv->bank_shift[index])
+                       bank |= (((hif_addr >> priv->bank_shift[index]) &
+                                               BIT(0)) << index);
+               else
+                       break;
+       }
+
+       for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) {
+               if (priv->bankgrp_shift[index])
+                       bankgrp |= (((hif_addr >> priv->bankgrp_shift[index])
+                                               & BIT(0)) << index);
+               else
+                       break;
+       }
+
+       if (priv->rank_shift[0])
+               rank = (hif_addr >> priv->rank_shift[0]) & BIT(0);
+
+       regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK;
+       regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK;
+       writel(regval, priv->baseaddr + ECC_POISON0_OFST);
+
+       regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK;
+       regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_POISON1_BANKNR_MASK;
+       regval |= (row << ECC_POISON1_ROW_SHIFT) & ECC_POISON1_ROW_MASK;
+       writel(regval, priv->baseaddr + ECC_POISON1_OFST);
+}
+
+static ssize_t inject_data_error_show(struct device *dev,
+                                     struct device_attribute *mattr,
+                                     char *data)
+{
+       struct mem_ctl_info *mci = to_mci(dev);
+       struct synps_edac_priv *priv = mci->pvt_info;
+
+       return sprintf(data, "Poison0 Addr: 0x%08x\n\rPoison1 Addr: 0x%08x\n\r"
+                       "Error injection Address: 0x%lx\n\r",
+                       readl(priv->baseaddr + ECC_POISON0_OFST),
+                       readl(priv->baseaddr + ECC_POISON1_OFST),
+                       priv->poison_addr);
+}
+
+static ssize_t inject_data_error_store(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      const char *data, size_t count)
+{
+       struct mem_ctl_info *mci = to_mci(dev);
+       struct synps_edac_priv *priv = mci->pvt_info;
+
+       if (kstrtoul(data, 0, &priv->poison_addr))
+               return -EINVAL;
+
+       ddr_poison_setup(priv);
+
+       return count;
+}
+
+static ssize_t inject_data_poison_show(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      char *data)
+{
+       struct mem_ctl_info *mci = to_mci(dev);
+       struct synps_edac_priv *priv = mci->pvt_info;
+
+       return sprintf(data, "Data Poisoning: %s\n\r",
+                       (((readl(priv->baseaddr + ECC_CFG1_OFST)) & 0x3) == 0x3)
+                       ? ("Correctable Error") : ("UnCorrectable Error"));
+}
+
+static ssize_t inject_data_poison_store(struct device *dev,
+                                       struct device_attribute *mattr,
+                                       const char *data, size_t count)
+{
+       struct mem_ctl_info *mci = to_mci(dev);
+       struct synps_edac_priv *priv = mci->pvt_info;
+
+       writel(0, priv->baseaddr + DDRC_SWCTL);
+       if (strncmp(data, "CE", 2) == 0)
+               writel(ECC_CEPOISON_MASK, priv->baseaddr + ECC_CFG1_OFST);
+       else
+               writel(ECC_UEPOISON_MASK, priv->baseaddr + ECC_CFG1_OFST);
+       writel(1, priv->baseaddr + DDRC_SWCTL);
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(inject_data_error);
+static DEVICE_ATTR_RW(inject_data_poison);
+
+static int edac_create_sysfs_attributes(struct mem_ctl_info *mci)
+{
+       int rc;
+
+       rc = device_create_file(&mci->dev, &dev_attr_inject_data_error);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_data_poison);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
+
+static void edac_remove_sysfs_attributes(struct mem_ctl_info *mci)
+{
+       device_remove_file(&mci->dev, &dev_attr_inject_data_error);
+       device_remove_file(&mci->dev, &dev_attr_inject_data_poison);
+}
+
+static void setup_row_address_map(struct synps_edac_priv *priv, u32 *addrmap)
+{
+       u32 addrmap_row_b2_10;
+       int index;
+
+       priv->row_shift[0] = (addrmap[5] & ROW_MAX_VAL_MASK) + ROW_B0_BASE;
+       priv->row_shift[1] = ((addrmap[5] >> 8) &
+                       ROW_MAX_VAL_MASK) + ROW_B1_BASE;
+
+       addrmap_row_b2_10 = (addrmap[5] >> 16) & ROW_MAX_VAL_MASK;
+       if (addrmap_row_b2_10 != ROW_MAX_VAL_MASK) {
+               for (index = 2; index < 11; index++)
+                       priv->row_shift[index] = addrmap_row_b2_10 +
+                               index + ROW_B0_BASE;
+
+       } else {
+               priv->row_shift[2] = (addrmap[9] &
+                               ROW_MAX_VAL_MASK) + ROW_B2_BASE;
+               priv->row_shift[3] = ((addrmap[9] >> 8) &
+                               ROW_MAX_VAL_MASK) + ROW_B3_BASE;
+               priv->row_shift[4] = ((addrmap[9] >> 16) &
+                               ROW_MAX_VAL_MASK) + ROW_B4_BASE;
+               priv->row_shift[5] = ((addrmap[9] >> 24) &
+                               ROW_MAX_VAL_MASK) + ROW_B5_BASE;
+               priv->row_shift[6] = (addrmap[10] &
+                               ROW_MAX_VAL_MASK) + ROW_B6_BASE;
+               priv->row_shift[7] = ((addrmap[10] >> 8) &
+                               ROW_MAX_VAL_MASK) + ROW_B7_BASE;
+               priv->row_shift[8] = ((addrmap[10] >> 16) &
+                               ROW_MAX_VAL_MASK) + ROW_B8_BASE;
+               priv->row_shift[9] = ((addrmap[10] >> 24) &
+                               ROW_MAX_VAL_MASK) + ROW_B9_BASE;
+               priv->row_shift[10] = (addrmap[11] &
+                               ROW_MAX_VAL_MASK) + ROW_B10_BASE;
+       }
 
-       return status;
+       priv->row_shift[11] = (((addrmap[5] >> 24) & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : (((addrmap[5] >> 24) &
+                               ROW_MAX_VAL_MASK) + ROW_B11_BASE);
+       priv->row_shift[12] = ((addrmap[6] & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : ((addrmap[6] &
+                               ROW_MAX_VAL_MASK) + ROW_B12_BASE);
+       priv->row_shift[13] = (((addrmap[6] >> 8) & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 8) &
+                               ROW_MAX_VAL_MASK) + ROW_B13_BASE);
+       priv->row_shift[14] = (((addrmap[6] >> 16) & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 16) &
+                               ROW_MAX_VAL_MASK) + ROW_B14_BASE);
+       priv->row_shift[15] = (((addrmap[6] >> 24) & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : (((addrmap[6] >> 24) &
+                               ROW_MAX_VAL_MASK) + ROW_B15_BASE);
+       priv->row_shift[16] = ((addrmap[7] & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : ((addrmap[7] &
+                               ROW_MAX_VAL_MASK) + ROW_B16_BASE);
+       priv->row_shift[17] = (((addrmap[7] >> 8) & ROW_MAX_VAL_MASK) ==
+                               ROW_MAX_VAL_MASK) ? 0 : (((addrmap[7] >> 8) &
+                               ROW_MAX_VAL_MASK) + ROW_B17_BASE);
+}
+
+static void setup_column_address_map(struct synps_edac_priv *priv, u32 *addrmap)
+{
+       u32 width, memtype;
+       int index;
+
+       memtype = readl(priv->baseaddr + CTRL_OFST);
+       width = (memtype & ECC_CTRL_BUSWIDTH_MASK) >> ECC_CTRL_BUSWIDTH_SHIFT;
+
+       priv->col_shift[0] = 0;
+       priv->col_shift[1] = 1;
+       priv->col_shift[2] = (addrmap[2] & COL_MAX_VAL_MASK) + COL_B2_BASE;
+       priv->col_shift[3] = ((addrmap[2] >> 8) &
+                       COL_MAX_VAL_MASK) + COL_B3_BASE;
+       priv->col_shift[4] = (((addrmap[2] >> 16) & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : (((addrmap[2] >> 16) &
+                                       COL_MAX_VAL_MASK) + COL_B4_BASE);
+       priv->col_shift[5] = (((addrmap[2] >> 24) & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : (((addrmap[2] >> 24) &
+                                       COL_MAX_VAL_MASK) + COL_B5_BASE);
+       priv->col_shift[6] = ((addrmap[3] & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : ((addrmap[3] &
+                                       COL_MAX_VAL_MASK) + COL_B6_BASE);
+       priv->col_shift[7] = (((addrmap[3] >> 8) & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 8) &
+                                       COL_MAX_VAL_MASK) + COL_B7_BASE);
+       priv->col_shift[8] = (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 16) &
+                                       COL_MAX_VAL_MASK) + COL_B8_BASE);
+       priv->col_shift[9] = (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) ==
+                       COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 24) &
+                                       COL_MAX_VAL_MASK) + COL_B9_BASE);
+       if (width == DDRCTL_EWDTH_64) {
+               if (memtype & MEM_TYPE_LPDDR3) {
+                       priv->col_shift[10] = ((addrmap[4] &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               ((addrmap[4] & COL_MAX_VAL_MASK) +
+                                COL_B10_BASE);
+                       priv->col_shift[11] = (((addrmap[4] >> 8) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[4] >> 8) & COL_MAX_VAL_MASK) +
+                                COL_B11_BASE);
+               } else {
+                       priv->col_shift[11] = ((addrmap[4] &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               ((addrmap[4] & COL_MAX_VAL_MASK) +
+                                COL_B10_BASE);
+                       priv->col_shift[13] = (((addrmap[4] >> 8) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[4] >> 8) & COL_MAX_VAL_MASK) +
+                                COL_B11_BASE);
+               }
+       } else if (width == DDRCTL_EWDTH_32) {
+               if (memtype & MEM_TYPE_LPDDR3) {
+                       priv->col_shift[10] = (((addrmap[3] >> 24) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
+                                COL_B9_BASE);
+                       priv->col_shift[11] = ((addrmap[4] &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               ((addrmap[4] & COL_MAX_VAL_MASK) +
+                                COL_B10_BASE);
+               } else {
+                       priv->col_shift[11] = (((addrmap[3] >> 24) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
+                                COL_B9_BASE);
+                       priv->col_shift[13] = ((addrmap[4] &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               ((addrmap[4] & COL_MAX_VAL_MASK) +
+                                COL_B10_BASE);
+               }
+       } else {
+               if (memtype & MEM_TYPE_LPDDR3) {
+                       priv->col_shift[10] = (((addrmap[3] >> 16) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
+                                COL_B8_BASE);
+                       priv->col_shift[11] = (((addrmap[3] >> 24) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
+                                COL_B9_BASE);
+                       priv->col_shift[13] = ((addrmap[4] &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               ((addrmap[4] & COL_MAX_VAL_MASK) +
+                                COL_B10_BASE);
+               } else {
+                       priv->col_shift[11] = (((addrmap[3] >> 16) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
+                                COL_B8_BASE);
+                       priv->col_shift[13] = (((addrmap[3] >> 24) &
+                               COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
+                                COL_B9_BASE);
+               }
+       }
+
+       if (width) {
+               for (index = 9; index > width; index--) {
+                       priv->col_shift[index] = priv->col_shift[index - width];
+                       priv->col_shift[index - width] = 0;
+               }
+       }
+
+}
+
+static void setup_bank_address_map(struct synps_edac_priv *priv, u32 *addrmap)
+{
+       priv->bank_shift[0] = (addrmap[1] & BANK_MAX_VAL_MASK) + BANK_B0_BASE;
+       priv->bank_shift[1] = ((addrmap[1] >> 8) &
+                               BANK_MAX_VAL_MASK) + BANK_B1_BASE;
+       priv->bank_shift[2] = (((addrmap[1] >> 16) &
+                               BANK_MAX_VAL_MASK) == BANK_MAX_VAL_MASK) ? 0 :
+                               (((addrmap[1] >> 16) & BANK_MAX_VAL_MASK) +
+                                BANK_B2_BASE);
+
+}
+
+static void setup_bg_address_map(struct synps_edac_priv *priv, u32 *addrmap)
+{
+       priv->bankgrp_shift[0] = (addrmap[8] &
+                               BANKGRP_MAX_VAL_MASK) + BANKGRP_B0_BASE;
+       priv->bankgrp_shift[1] = (((addrmap[8] >> 8) & BANKGRP_MAX_VAL_MASK) ==
+                               BANKGRP_MAX_VAL_MASK) ? 0 : (((addrmap[8] >> 8)
+                               & BANKGRP_MAX_VAL_MASK) + BANKGRP_B1_BASE);
+
+}
+
+static void setup_rank_address_map(struct synps_edac_priv *priv, u32 *addrmap)
+{
+       priv->rank_shift[0] = ((addrmap[0] & RANK_MAX_VAL_MASK) ==
+                               RANK_MAX_VAL_MASK) ? 0 : ((addrmap[0] &
+                               RANK_MAX_VAL_MASK) + RANK_B0_BASE);
 }
 
 /**
- * synps_edac_mc_probe - Check controller and bind driver
- * @pdev:      Pointer to the platform_device struct
+ * setup_address_map - Set Address Map by querying ADDRMAP registers.
+ * @priv:              DDR memory controller private instance data.
  *
- * Probes a specific controller instance for binding with the driver.
+ * Set Address Map by querying ADDRMAP registers.
+ *
+ * Return: none.
+ */
+static void setup_address_map(struct synps_edac_priv *priv)
+{
+       u32 addrmap[12];
+       int index;
+
+       for (index = 0; index < 12; index++) {
+               u32 addrmap_offset;
+
+               addrmap_offset = ECC_ADDRMAP0_OFFSET + (index * 4);
+               addrmap[index] = readl(priv->baseaddr + addrmap_offset);
+       }
+
+       setup_row_address_map(priv, addrmap);
+
+       setup_column_address_map(priv, addrmap);
+
+       setup_bank_address_map(priv, addrmap);
+
+       setup_bg_address_map(priv, addrmap);
+
+       setup_rank_address_map(priv, addrmap);
+}
+#endif /* CONFIG_EDAC_DEBUG */
+
+/**
+ * mc_probe - Check controller and bind driver.
+ * @pdev:      platform device.
+ *
+ * Probe a specific controller instance for binding with the driver.
  *
  * Return: 0 if the controller instance was successfully bound to the
  * driver; otherwise, < 0 on error.
  */
-static int synps_edac_mc_probe(struct platform_device *pdev)
+static int mc_probe(struct platform_device *pdev)
 {
-       struct mem_ctl_info *mci;
+       const struct synps_platform_data *p_data;
        struct edac_mc_layer layers[2];
        struct synps_edac_priv *priv;
-       int rc;
-       struct resource *res;
+       struct mem_ctl_info *mci;
        void __iomem *baseaddr;
+       struct resource *res;
+       int rc;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        baseaddr = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(baseaddr))
                return PTR_ERR(baseaddr);
 
-       if (!synps_edac_get_eccstate(baseaddr)) {
+       p_data = of_device_get_match_data(&pdev->dev);
+       if (!p_data)
+               return -ENODEV;
+
+       if (!p_data->get_ecc_state(baseaddr)) {
                edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
                return -ENXIO;
        }
@@ -468,11 +1333,14 @@ static int synps_edac_mc_probe(struct platform_device *pdev)
 
        priv = mci->pvt_info;
        priv->baseaddr = baseaddr;
-       rc = synps_edac_mc_init(mci, pdev);
-       if (rc) {
-               edac_printk(KERN_ERR, EDAC_MC,
-                           "Failed to initialize instance\n");
-               goto free_edac_mc;
+       priv->p_data = p_data;
+
+       mc_init(mci, pdev);
+
+       if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
+               rc = setup_irq(mci, pdev);
+               if (rc)
+                       goto free_edac_mc;
        }
 
        rc = edac_mc_add_mc(mci);
@@ -482,11 +1350,27 @@ static int synps_edac_mc_probe(struct platform_device *pdev)
                goto free_edac_mc;
        }
 
+#ifdef CONFIG_EDAC_DEBUG
+       if (priv->p_data->quirks & DDR_ECC_DATA_POISON_SUPPORT) {
+               if (edac_create_sysfs_attributes(mci)) {
+                       edac_printk(KERN_ERR, EDAC_MC,
+                                       "Failed to create sysfs entries\n");
+                       goto free_edac_mc;
+               }
+       }
+
+       if (of_device_is_compatible(pdev->dev.of_node,
+                                   "xlnx,zynqmp-ddrc-2.40a"))
+               setup_address_map(priv);
+#endif
+
        /*
         * Start capturing the correctable and uncorrectable errors. A write of
         * 0 starts the counters.
         */
-       writel(0x0, baseaddr + ECC_CTRL_OFST);
+       if (!(priv->p_data->quirks & DDR_ECC_INTR_SUPPORT))
+               writel(0x0, baseaddr + ECC_CTRL_OFST);
+
        return rc;
 
 free_edac_mc:
@@ -496,14 +1380,23 @@ free_edac_mc:
 }
 
 /**
- * synps_edac_mc_remove - Unbind driver from controller
- * @pdev:      Pointer to the platform_device struct
+ * mc_remove - Unbind driver from controller.
+ * @pdev:      Platform device.
  *
  * Return: Unconditionally 0
  */
-static int synps_edac_mc_remove(struct platform_device *pdev)
+static int mc_remove(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+       struct synps_edac_priv *priv = mci->pvt_info;
+
+       if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT)
+               disable_intr(priv);
+
+#ifdef CONFIG_EDAC_DEBUG
+       if (priv->p_data->quirks & DDR_ECC_DATA_POISON_SUPPORT)
+               edac_remove_sysfs_attributes(mci);
+#endif
 
        edac_mc_del_mc(&pdev->dev);
        edac_mc_free(mci);
@@ -511,20 +1404,13 @@ static int synps_edac_mc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id synps_edac_match[] = {
-       { .compatible = "xlnx,zynq-ddrc-a05", },
-       { /* end of table */ }
-};
-
-MODULE_DEVICE_TABLE(of, synps_edac_match);
-
 static struct platform_driver synps_edac_mc_driver = {
        .driver = {
                   .name = "synopsys-edac",
                   .of_match_table = synps_edac_match,
                   },
-       .probe = synps_edac_mc_probe,
-       .remove = synps_edac_mc_remove,
+       .probe = mc_probe,
+       .remove = mc_remove,
 };
 
 module_platform_driver(synps_edac_mc_driver);
index 05813fbf3daf25f4aeb6ea0233f13c13dd95ad73..647dfbbc4e1cf44ac989a1562e2c2f711fca5d36 100644 (file)
@@ -25,7 +25,7 @@ static int max7301_spi_write(struct device *dev, unsigned int reg,
        struct spi_device *spi = to_spi_device(dev);
        u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
 
-       return spi_write(spi, (const u8 *)&word, sizeof(word));
+       return spi_write_then_read(spi, &word, sizeof(word), NULL, 0);
 }
 
 /* A read from the MAX7301 means two transfers; here, one message each */
@@ -37,14 +37,8 @@ static int max7301_spi_read(struct device *dev, unsigned int reg)
        struct spi_device *spi = to_spi_device(dev);
 
        word = 0x8000 | (reg << 8);
-       ret = spi_write(spi, (const u8 *)&word, sizeof(word));
-       if (ret)
-               return ret;
-       /*
-        * This relies on the fact, that a transfer with NULL tx_buf shifts out
-        * zero bytes (=NOOP for MAX7301)
-        */
-       ret = spi_read(spi, (u8 *)&word, sizeof(word));
+       ret = spi_write_then_read(spi, &word, sizeof(word), &word,
+                                 sizeof(word));
        if (ret)
                return ret;
        return word & 0xff;
index 6e02148c208b2cc600d75263d1c87064db2ebc23..adc768f908f1ae1937f3d245088c590b449e574f 100644 (file)
@@ -773,9 +773,6 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
                                     "marvell,armada-370-gpio"))
                return 0;
 
-       if (IS_ERR(mvchip->clk))
-               return PTR_ERR(mvchip->clk);
-
        /*
         * There are only two sets of PWM configuration registers for
         * all the GPIO lines on those SoCs which this driver reserves
@@ -786,6 +783,9 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
        if (!res)
                return 0;
 
+       if (IS_ERR(mvchip->clk))
+               return PTR_ERR(mvchip->clk);
+
        /*
         * Use set A for lines of GPIO chip with id 0, B for GPIO chip
         * with id 1. Don't allow further GPIO chips to be used for PWM.
index 9887c3db6e16ace91790fbb938452584512e45c5..5b3e83cd71378b0ee81f83a51e4a69380d752fef 100644 (file)
@@ -32,7 +32,6 @@
 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
 
 #define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER    BIT(2)
-#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN       BIT(1)
 
 struct gpio_regs {
        u32 irqenable1;
@@ -379,18 +378,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
                        readl_relaxed(bank->base + bank->regs->fallingdetect);
 
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-               /* Defer wkup_en register update until we idle? */
-               if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
-                       if (trigger)
-                               bank->context.wake_en |= gpio_bit;
-                       else
-                               bank->context.wake_en &= ~gpio_bit;
-               } else {
-                       omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
-                                     trigger != 0);
-                       bank->context.wake_en =
-                               readl_relaxed(bank->base + bank->regs->wkup_en);
-               }
+               omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+               bank->context.wake_en =
+                       readl_relaxed(bank->base + bank->regs->wkup_en);
        }
 
        /* This part needs to be executed always for OMAP{34xx, 44xx} */
@@ -942,44 +932,6 @@ omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
                       bank->base + bank->regs->risingdetect);
 }
 
-/*
- * On omap4 and later SoC variants a level interrupt with wkup_en
- * enabled blocks the GPIO functional clock from idling until the GPIO
- * instance has been reset. To avoid that, we must set wkup_en only for
- * idle for level interrupts, and clear level registers for the duration
- * of idle. The level interrupts will be still there on wakeup by their
- * nature.
- */
-static void __maybe_unused
-omap4_gpio_enable_level_quirk(struct gpio_bank *bank)
-{
-       /* Update wake register for idle, edge bits might be already set */
-       writel_relaxed(bank->context.wake_en,
-                      bank->base + bank->regs->wkup_en);
-
-       /* Clear level registers for idle */
-       writel_relaxed(0, bank->base + bank->regs->leveldetect0);
-       writel_relaxed(0, bank->base + bank->regs->leveldetect1);
-}
-
-static void __maybe_unused
-omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
-{
-       /* Restore level registers after idle */
-       writel_relaxed(bank->context.leveldetect0,
-                      bank->base + bank->regs->leveldetect0);
-       writel_relaxed(bank->context.leveldetect1,
-                      bank->base + bank->regs->leveldetect1);
-
-       /* Clear saved wkup_en for level, it will be set for next idle again */
-       bank->context.wake_en &= ~(bank->context.leveldetect0 |
-                                  bank->context.leveldetect1);
-
-       /* Update wake with only edge configuration */
-       writel_relaxed(bank->context.wake_en,
-                      bank->base + bank->regs->wkup_en);
-}
-
 /*---------------------------------------------------------------------*/
 
 static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -1412,12 +1364,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
                                omap_set_gpio_dataout_mask_multiple;
        }
 
-       if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
-               bank->funcs.idle_enable_level_quirk =
-                       omap4_gpio_enable_level_quirk;
-               bank->funcs.idle_disable_level_quirk =
-                       omap4_gpio_disable_level_quirk;
-       } else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
+       if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
                bank->funcs.idle_enable_level_quirk =
                        omap2_gpio_enable_level_quirk;
                bank->funcs.idle_disable_level_quirk =
@@ -1806,8 +1753,7 @@ static const struct omap_gpio_platform_data omap4_pdata = {
        .regs = &omap4_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
-       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER |
-                 OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN,
+       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
 };
 
 static const struct of_device_id omap_gpio_match[] = {
index 55b72fbe163169c29766fbb6e24f58ccfdfd62c2..7f93954c58ea47f3be84c0955d6887f45fac5c25 100644 (file)
 
 #include "gpiolib.h"
 
+/**
+ * struct acpi_gpio_event - ACPI GPIO event handler data
+ *
+ * @node:        list-entry of the events list of the struct acpi_gpio_chip
+ * @handle:      handle of ACPI method to execute when the IRQ triggers
+ * @handler:     irq_handler to pass to request_irq when requesting the IRQ
+ * @pin:         GPIO pin number on the gpio_chip
+ * @irq:         Linux IRQ number for the event, for request_ / free_irq
+ * @irqflags:     flags to pass to request_irq when requesting the IRQ
+ * @irq_is_wake:  If the ACPI flags indicate the IRQ is a wakeup source
+ * @is_requested: True if request_irq has been done
+ * @desc:        gpio_desc for the GPIO pin for this event
+ */
 struct acpi_gpio_event {
        struct list_head node;
        acpi_handle handle;
+       irq_handler_t handler;
        unsigned int pin;
        unsigned int irq;
+       unsigned long irqflags;
+       bool irq_is_wake;
+       bool irq_requested;
        struct gpio_desc *desc;
 };
 
@@ -49,10 +66,10 @@ struct acpi_gpio_chip {
 
 /*
  * For gpiochips which call acpi_gpiochip_request_interrupts() before late_init
- * (so builtin drivers) we register the ACPI GpioInt event handlers from a
+ * (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
  * late_initcall_sync handler, so that other builtin drivers can register their
  * OpRegions before the event handlers can run.  This list contains gpiochips
- * for which the acpi_gpiochip_request_interrupts() has been deferred.
+ * for which the acpi_gpiochip_request_irqs() call has been deferred.
  */
 static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
 static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
@@ -133,8 +150,42 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
 }
 EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
 
-static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
-                                                  void *context)
+static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
+                                     struct acpi_gpio_event *event)
+{
+       int ret, value;
+
+       ret = request_threaded_irq(event->irq, NULL, event->handler,
+                                  event->irqflags, "ACPI:Event", event);
+       if (ret) {
+               dev_err(acpi_gpio->chip->parent,
+                       "Failed to setup interrupt handler for %d\n",
+                       event->irq);
+               return;
+       }
+
+       if (event->irq_is_wake)
+               enable_irq_wake(event->irq);
+
+       event->irq_requested = true;
+
+       /* Make sure we trigger the initial state of edge-triggered IRQs */
+       value = gpiod_get_raw_value_cansleep(event->desc);
+       if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
+           ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
+               event->handler(event->irq, event);
+}
+
+static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
+{
+       struct acpi_gpio_event *event;
+
+       list_for_each_entry(event, &acpi_gpio->events, node)
+               acpi_gpiochip_request_irq(acpi_gpio, event);
+}
+
+static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
+                                            void *context)
 {
        struct acpi_gpio_chip *acpi_gpio = context;
        struct gpio_chip *chip = acpi_gpio->chip;
@@ -143,8 +194,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        struct acpi_gpio_event *event;
        irq_handler_t handler = NULL;
        struct gpio_desc *desc;
-       unsigned long irqflags;
-       int ret, pin, irq, value;
+       int ret, pin, irq;
 
        if (!acpi_gpio_get_irq_resource(ares, &agpio))
                return AE_OK;
@@ -175,8 +225,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
 
        gpiod_direction_input(desc);
 
-       value = gpiod_get_value_cansleep(desc);
-
        ret = gpiochip_lock_as_irq(chip, pin);
        if (ret) {
                dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
@@ -189,64 +237,42 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
                goto fail_unlock_irq;
        }
 
-       irqflags = IRQF_ONESHOT;
+       event = kzalloc(sizeof(*event), GFP_KERNEL);
+       if (!event)
+               goto fail_unlock_irq;
+
+       event->irqflags = IRQF_ONESHOT;
        if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
                if (agpio->polarity == ACPI_ACTIVE_HIGH)
-                       irqflags |= IRQF_TRIGGER_HIGH;
+                       event->irqflags |= IRQF_TRIGGER_HIGH;
                else
-                       irqflags |= IRQF_TRIGGER_LOW;
+                       event->irqflags |= IRQF_TRIGGER_LOW;
        } else {
                switch (agpio->polarity) {
                case ACPI_ACTIVE_HIGH:
-                       irqflags |= IRQF_TRIGGER_RISING;
+                       event->irqflags |= IRQF_TRIGGER_RISING;
                        break;
                case ACPI_ACTIVE_LOW:
-                       irqflags |= IRQF_TRIGGER_FALLING;
+                       event->irqflags |= IRQF_TRIGGER_FALLING;
                        break;
                default:
-                       irqflags |= IRQF_TRIGGER_RISING |
-                                   IRQF_TRIGGER_FALLING;
+                       event->irqflags |= IRQF_TRIGGER_RISING |
+                                          IRQF_TRIGGER_FALLING;
                        break;
                }
        }
 
-       event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (!event)
-               goto fail_unlock_irq;
-
        event->handle = evt_handle;
+       event->handler = handler;
        event->irq = irq;
+       event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE;
        event->pin = pin;
        event->desc = desc;
 
-       ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
-                                  "ACPI:Event", event);
-       if (ret) {
-               dev_err(chip->parent,
-                       "Failed to setup interrupt handler for %d\n",
-                       event->irq);
-               goto fail_free_event;
-       }
-
-       if (agpio->wake_capable == ACPI_WAKE_CAPABLE)
-               enable_irq_wake(irq);
-
        list_add_tail(&event->node, &acpi_gpio->events);
 
-       /*
-        * Make sure we trigger the initial state of the IRQ when using RISING
-        * or FALLING.  Note we run the handlers on late_init, the AML code
-        * may refer to OperationRegions from other (builtin) drivers which
-        * may be probed after us.
-        */
-       if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
-           ((irqflags & IRQF_TRIGGER_FALLING) && value == 0))
-               handler(event->irq, event);
-
        return AE_OK;
 
-fail_free_event:
-       kfree(event);
 fail_unlock_irq:
        gpiochip_unlock_as_irq(chip, pin);
 fail_free_desc:
@@ -283,6 +309,9 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
        if (ACPI_FAILURE(status))
                return;
 
+       acpi_walk_resources(handle, "_AEI",
+                           acpi_gpiochip_alloc_event, acpi_gpio);
+
        mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
        defer = !acpi_gpio_deferred_req_irqs_done;
        if (defer)
@@ -293,8 +322,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
        if (defer)
                return;
 
-       acpi_walk_resources(handle, "_AEI",
-                           acpi_gpiochip_request_interrupt, acpi_gpio);
+       acpi_gpiochip_request_irqs(acpi_gpio);
 }
 EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
 
@@ -331,10 +359,13 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
        list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
                struct gpio_desc *desc;
 
-               if (irqd_is_wakeup_set(irq_get_irq_data(event->irq)))
-                       disable_irq_wake(event->irq);
+               if (event->irq_requested) {
+                       if (event->irq_is_wake)
+                               disable_irq_wake(event->irq);
+
+                       free_irq(event->irq, event);
+               }
 
-               free_irq(event->irq, event);
                desc = event->desc;
                if (WARN_ON(IS_ERR(desc)))
                        continue;
@@ -1200,23 +1231,16 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
        return con_id == NULL;
 }
 
-/* Run deferred acpi_gpiochip_request_interrupts() */
-static int acpi_gpio_handle_deferred_request_interrupts(void)
+/* Run deferred acpi_gpiochip_request_irqs() */
+static int acpi_gpio_handle_deferred_request_irqs(void)
 {
        struct acpi_gpio_chip *acpi_gpio, *tmp;
 
        mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
        list_for_each_entry_safe(acpi_gpio, tmp,
                                 &acpi_gpio_deferred_req_irqs_list,
-                                deferred_req_irqs_list_entry) {
-               acpi_handle handle;
-
-               handle = ACPI_HANDLE(acpi_gpio->chip->parent);
-               acpi_walk_resources(handle, "_AEI",
-                                   acpi_gpiochip_request_interrupt, acpi_gpio);
-
-               list_del_init(&acpi_gpio->deferred_req_irqs_list_entry);
-       }
+                                deferred_req_irqs_list_entry)
+               acpi_gpiochip_request_irqs(acpi_gpio);
 
        acpi_gpio_deferred_req_irqs_done = true;
        mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
@@ -1224,4 +1248,4 @@ static int acpi_gpio_handle_deferred_request_interrupts(void)
        return 0;
 }
 /* We must use _sync so that this runs after the first deferred_probe run */
-late_initcall_sync(acpi_gpio_handle_deferred_request_interrupts);
+late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
index 01959369360bd761cdb6a30c06980363e78ef40d..0acc2cc6e868fdefec661540d97513959e00575e 100644 (file)
@@ -98,15 +98,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
        struct gpio_desc **dr;
        struct gpio_desc *desc;
 
+       desc = gpiod_get_index(dev, con_id, idx, flags);
+       if (IS_ERR(desc))
+               return desc;
+
+       /*
+        * For non-exclusive GPIO descriptors, check if this descriptor is
+        * already under resource management by this device.
+        */
+       if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+               struct devres *dres;
+
+               dres = devres_find(dev, devm_gpiod_release,
+                                  devm_gpiod_match, &desc);
+               if (dres)
+                       return desc;
+       }
+
        dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
                          GFP_KERNEL);
-       if (!dr)
+       if (!dr) {
+               gpiod_put(desc);
                return ERR_PTR(-ENOMEM);
-
-       desc = gpiod_get_index(dev, con_id, idx, flags);
-       if (IS_ERR(desc)) {
-               devres_free(dr);
-               return desc;
        }
 
        *dr = desc;
@@ -140,15 +153,28 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
        struct gpio_desc **dr;
        struct gpio_desc *desc;
 
+       desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
+       if (IS_ERR(desc))
+               return desc;
+
+       /*
+        * For non-exclusive GPIO descriptors, check if this descriptor is
+        * already under resource management by this device.
+        */
+       if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+               struct devres *dres;
+
+               dres = devres_find(dev, devm_gpiod_release,
+                                  devm_gpiod_match, &desc);
+               if (dres)
+                       return desc;
+       }
+
        dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
                          GFP_KERNEL);
-       if (!dr)
+       if (!dr) {
+               gpiod_put(desc);
                return ERR_PTR(-ENOMEM);
-
-       desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
-       if (IS_ERR(desc)) {
-               devres_free(dr);
-               return desc;
        }
 
        *dr = desc;
@@ -320,6 +346,36 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
 }
 EXPORT_SYMBOL(devm_gpiod_put);
 
+/**
+ * devm_gpiod_unhinge - Remove resource management from a gpio descriptor
+ * @dev:       GPIO consumer
+ * @desc:      GPIO descriptor to remove resource management from
+ *
+ * Remove resource management from a GPIO descriptor. This is needed when
+ * you want to hand over lifecycle management of a descriptor to another
+ * mechanism.
+ */
+
+void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
+{
+       int ret;
+
+       if (IS_ERR_OR_NULL(desc))
+               return;
+       ret = devres_destroy(dev, devm_gpiod_release,
+                            devm_gpiod_match, &desc);
+       /*
+        * If the GPIO descriptor is requested as nonexclusive, we
+        * may call this function several times on the same descriptor
+        * so it is OK if devres_destroy() returns -ENOENT.
+        */
+       if (ret == -ENOENT)
+               return;
+       /* Anything else we should warn about */
+       WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_gpiod_unhinge);
+
 /**
  * devm_gpiod_put_array - Resource-managed gpiod_put_array()
  * @dev:       GPIO consumer
index a2cbb474901c224bebae335cd0789273a78955ae..985c09ce80fbc45a2e74f54b2d9cd0cba1a8a828 100644 (file)
@@ -4205,6 +4205,8 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
        transitory = flags & OF_GPIO_TRANSITORY;
 
        ret = gpiod_request(desc, label);
+       if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
+               return desc;
        if (ret)
                return ERR_PTR(ret);
 
index 087d865286a0c8ffe620c5abf33a14778a3f5e36..bc57f0dc59532f9c0d085e74b9ebc0f0e5bb6841 100644 (file)
@@ -201,12 +201,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
                                  struct gpio_array *array_info,
                                  unsigned long *value_bitmap);
 
-/* This is just passed between gpiolib and devres */
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label);
-
 extern struct spinlock gpio_lock;
 extern struct list_head gpio_devices;
 
index bc6a16a3c36ef9f90c8bdab7f907620a40d78e25..ce8d1d38431924f95fa5d2a695d8e71c5479f92e 100644 (file)
@@ -10,8 +10,8 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
                drm_scatter.o drm_pci.o \
                drm_sysfs.o drm_hashtab.o drm_mm.o \
                drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
-               drm_info.o drm_encoder_slave.o \
-               drm_trace_points.o drm_global.o drm_prime.o \
+               drm_encoder_slave.o \
+               drm_trace_points.o drm_prime.o \
                drm_rect.o drm_vma_manager.o drm_flip_work.o \
                drm_modeset_lock.o drm_atomic.o drm_bridge.o \
                drm_framebuffer.o drm_connector.o drm_blend.o \
@@ -32,11 +32,12 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 
-drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
+drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
                drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
                drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
                drm_simple_kms_helper.o drm_modeset_helper.o \
-               drm_scdc_helper.o drm_gem_framebuffer_helper.o
+               drm_scdc_helper.o drm_gem_framebuffer_helper.o \
+               drm_atomic_state_helper.o drm_damage_helper.o
 
 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
index 138cb787d27e832dd773d87e293dce189239f5af..f76bcb9c45e488a07d1f17dc7125d831563c76fc 100644 (file)
@@ -53,7 +53,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
        amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
        amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
        amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \
-       amdgpu_gmc.o amdgpu_xgmi.o
+       amdgpu_gmc.o amdgpu_xgmi.o amdgpu_csa.o
 
 # add asic specific block
 amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
@@ -105,6 +105,7 @@ amdgpu-y += \
 # add GFX block
 amdgpu-y += \
        amdgpu_gfx.o \
+       amdgpu_rlc.o \
        gfx_v8_0.o \
        gfx_v9_0.o
 
index b0fc116296cb3bff55f6b95b432fbc018a29bbde..bcef6ea4bcf9f83d49f6c3739406b52eb8a196b0 100644 (file)
 #include "amdgpu_sdma.h"
 #include "amdgpu_dm.h"
 #include "amdgpu_virt.h"
+#include "amdgpu_csa.h"
 #include "amdgpu_gart.h"
 #include "amdgpu_debugfs.h"
 #include "amdgpu_job.h"
 #include "amdgpu_bo_list.h"
 #include "amdgpu_gem.h"
+#include "amdgpu_doorbell.h"
+#include "amdgpu_amdkfd.h"
 
 #define MAX_GPU_INSTANCE               16
 
@@ -161,6 +164,7 @@ extern int amdgpu_si_support;
 extern int amdgpu_cik_support;
 #endif
 
+#define AMDGPU_VM_MAX_NUM_CTX                  4096
 #define AMDGPU_SG_THRESHOLD                    (256*1024*1024)
 #define AMDGPU_DEFAULT_GTT_SIZE_MB             3072ULL /* 3GB by default */
 #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS         3000
@@ -359,123 +363,6 @@ struct amdgpu_sa_bo {
 int amdgpu_fence_slab_init(void);
 void amdgpu_fence_slab_fini(void);
 
-/*
- * GPU doorbell structures, functions & helpers
- */
-typedef enum _AMDGPU_DOORBELL_ASSIGNMENT
-{
-       AMDGPU_DOORBELL_KIQ                     = 0x000,
-       AMDGPU_DOORBELL_HIQ                     = 0x001,
-       AMDGPU_DOORBELL_DIQ                     = 0x002,
-       AMDGPU_DOORBELL_MEC_RING0               = 0x010,
-       AMDGPU_DOORBELL_MEC_RING1               = 0x011,
-       AMDGPU_DOORBELL_MEC_RING2               = 0x012,
-       AMDGPU_DOORBELL_MEC_RING3               = 0x013,
-       AMDGPU_DOORBELL_MEC_RING4               = 0x014,
-       AMDGPU_DOORBELL_MEC_RING5               = 0x015,
-       AMDGPU_DOORBELL_MEC_RING6               = 0x016,
-       AMDGPU_DOORBELL_MEC_RING7               = 0x017,
-       AMDGPU_DOORBELL_GFX_RING0               = 0x020,
-       AMDGPU_DOORBELL_sDMA_ENGINE0            = 0x1E0,
-       AMDGPU_DOORBELL_sDMA_ENGINE1            = 0x1E1,
-       AMDGPU_DOORBELL_IH                      = 0x1E8,
-       AMDGPU_DOORBELL_MAX_ASSIGNMENT          = 0x3FF,
-       AMDGPU_DOORBELL_INVALID                 = 0xFFFF
-} AMDGPU_DOORBELL_ASSIGNMENT;
-
-struct amdgpu_doorbell {
-       /* doorbell mmio */
-       resource_size_t         base;
-       resource_size_t         size;
-       u32 __iomem             *ptr;
-       u32                     num_doorbells;  /* Number of doorbells actually reserved for amdgpu. */
-};
-
-/*
- * 64bit doorbell, offset are in QWORD, occupy 2KB doorbell space
- */
-typedef enum _AMDGPU_DOORBELL64_ASSIGNMENT
-{
-       /*
-        * All compute related doorbells: kiq, hiq, diq, traditional compute queue, user queue, should locate in
-        * a continues range so that programming CP_MEC_DOORBELL_RANGE_LOWER/UPPER can cover this range.
-        *  Compute related doorbells are allocated from 0x00 to 0x8a
-        */
-
-
-       /* kernel scheduling */
-       AMDGPU_DOORBELL64_KIQ                     = 0x00,
-
-       /* HSA interface queue and debug queue */
-       AMDGPU_DOORBELL64_HIQ                     = 0x01,
-       AMDGPU_DOORBELL64_DIQ                     = 0x02,
-
-       /* Compute engines */
-       AMDGPU_DOORBELL64_MEC_RING0               = 0x03,
-       AMDGPU_DOORBELL64_MEC_RING1               = 0x04,
-       AMDGPU_DOORBELL64_MEC_RING2               = 0x05,
-       AMDGPU_DOORBELL64_MEC_RING3               = 0x06,
-       AMDGPU_DOORBELL64_MEC_RING4               = 0x07,
-       AMDGPU_DOORBELL64_MEC_RING5               = 0x08,
-       AMDGPU_DOORBELL64_MEC_RING6               = 0x09,
-       AMDGPU_DOORBELL64_MEC_RING7               = 0x0a,
-
-       /* User queue doorbell range (128 doorbells) */
-       AMDGPU_DOORBELL64_USERQUEUE_START         = 0x0b,
-       AMDGPU_DOORBELL64_USERQUEUE_END           = 0x8a,
-
-       /* Graphics engine */
-       AMDGPU_DOORBELL64_GFX_RING0               = 0x8b,
-
-       /*
-        * Other graphics doorbells can be allocated here: from 0x8c to 0xdf
-        * Graphics voltage island aperture 1
-        * default non-graphics QWORD index is 0xe0 - 0xFF inclusive
-        */
-
-       /* sDMA engines  reserved from 0xe0 -oxef  */
-       AMDGPU_DOORBELL64_sDMA_ENGINE0            = 0xE0,
-       AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE0     = 0xE1,
-       AMDGPU_DOORBELL64_sDMA_ENGINE1            = 0xE8,
-       AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE1     = 0xE9,
-
-       /* For vega10 sriov, the sdma doorbell must be fixed as follow
-        * to keep the same setting with host driver, or it will
-        * happen conflicts
-        */
-       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE0            = 0xF0,
-       AMDGPU_VEGA10_DOORBELL64_sDMA_HI_PRI_ENGINE0     = 0xF1,
-       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE1            = 0xF2,
-       AMDGPU_VEGA10_DOORBELL64_sDMA_HI_PRI_ENGINE1     = 0xF3,
-
-       /* Interrupt handler */
-       AMDGPU_DOORBELL64_IH                      = 0xF4,  /* For legacy interrupt ring buffer */
-       AMDGPU_DOORBELL64_IH_RING1                = 0xF5,  /* For page migration request log */
-       AMDGPU_DOORBELL64_IH_RING2                = 0xF6,  /* For page migration translation/invalidation log */
-
-       /* VCN engine use 32 bits doorbell  */
-       AMDGPU_DOORBELL64_VCN0_1                  = 0xF8, /* lower 32 bits for VNC0 and upper 32 bits for VNC1 */
-       AMDGPU_DOORBELL64_VCN2_3                  = 0xF9,
-       AMDGPU_DOORBELL64_VCN4_5                  = 0xFA,
-       AMDGPU_DOORBELL64_VCN6_7                  = 0xFB,
-
-       /* overlap the doorbell assignment with VCN as they are  mutually exclusive
-        * VCE engine's doorbell is 32 bit and two VCE ring share one QWORD
-        */
-       AMDGPU_DOORBELL64_UVD_RING0_1             = 0xF8,
-       AMDGPU_DOORBELL64_UVD_RING2_3             = 0xF9,
-       AMDGPU_DOORBELL64_UVD_RING4_5             = 0xFA,
-       AMDGPU_DOORBELL64_UVD_RING6_7             = 0xFB,
-
-       AMDGPU_DOORBELL64_VCE_RING0_1             = 0xFC,
-       AMDGPU_DOORBELL64_VCE_RING2_3             = 0xFD,
-       AMDGPU_DOORBELL64_VCE_RING4_5             = 0xFE,
-       AMDGPU_DOORBELL64_VCE_RING6_7             = 0xFF,
-
-       AMDGPU_DOORBELL64_MAX_ASSIGNMENT          = 0xFF,
-       AMDGPU_DOORBELL64_INVALID                 = 0xFFFF
-} AMDGPU_DOORBELL64_ASSIGNMENT;
-
 /*
  * IRQS.
  */
@@ -653,6 +540,8 @@ struct amdgpu_asic_funcs {
                               struct amdgpu_ring *ring);
        /* check if the asic needs a full reset of if soft reset will work */
        bool (*need_full_reset)(struct amdgpu_device *adev);
+       /* initialize doorbell layout for specific asic*/
+       void (*init_doorbell_index)(struct amdgpu_device *adev);
 };
 
 /*
@@ -831,7 +720,6 @@ struct amdgpu_device {
        bool                            need_dma32;
        bool                            need_swiotlb;
        bool                            accel_working;
-       struct work_struct              reset_work;
        struct notifier_block           acpi_nb;
        struct amdgpu_i2c_chan          *i2c_bus[AMDGPU_MAX_I2C_BUS];
        struct amdgpu_debugfs           debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
@@ -976,6 +864,9 @@ struct amdgpu_device {
        /* GDS */
        struct amdgpu_gds               gds;
 
+       /* KFD */
+       struct amdgpu_kfd_dev           kfd;
+
        /* display related functionality */
        struct amdgpu_display_manager dm;
 
@@ -989,9 +880,6 @@ struct amdgpu_device {
        atomic64_t visible_pin_size;
        atomic64_t gart_pin_size;
 
-       /* amdkfd interface */
-       struct kfd_dev          *kfd;
-
        /* soc15 register offset based on ip, instance and  segment */
        uint32_t                *reg_offset[MAX_HWIP][HWIP_MAX_INSTANCE];
 
@@ -1023,6 +911,10 @@ struct amdgpu_device {
        unsigned long last_mm_index;
        bool                            in_gpu_reset;
        struct mutex  lock_reset;
+       struct amdgpu_doorbell_index doorbell_index;
+
+       int asic_reset_res;
+       struct work_struct              xgmi_reset_work;
 };
 
 static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev)
@@ -1047,11 +939,6 @@ uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset);
 u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg);
 void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v);
 
-u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index);
-void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
-u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index);
-void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v);
-
 bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type);
 bool amdgpu_device_has_dc_support(struct amdgpu_device *adev);
 
@@ -1113,11 +1000,6 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
 #define RREG32_IO(reg) amdgpu_io_rreg(adev, (reg))
 #define WREG32_IO(reg, v) amdgpu_io_wreg(adev, (reg), (v))
 
-#define RDOORBELL32(index) amdgpu_mm_rdoorbell(adev, (index))
-#define WDOORBELL32(index, v) amdgpu_mm_wdoorbell(adev, (index), (v))
-#define RDOORBELL64(index) amdgpu_mm_rdoorbell64(adev, (index))
-#define WDOORBELL64(index, v) amdgpu_mm_wdoorbell64(adev, (index), (v))
-
 #define REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
 #define REG_FIELD_MASK(reg, field) reg##__##field##_MASK
 
@@ -1159,6 +1041,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
 #define amdgpu_asic_flush_hdp(adev, r) (adev)->asic_funcs->flush_hdp((adev), (r))
 #define amdgpu_asic_invalidate_hdp(adev, r) (adev)->asic_funcs->invalidate_hdp((adev), (r))
 #define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev))
+#define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev))
 
 /* Common functions */
 bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
@@ -1219,12 +1102,6 @@ void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
 long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
-
-/*
- * functions used by amdgpu_xgmi.c
- */
-int amdgpu_xgmi_add_device(struct amdgpu_device *adev);
-
 /*
  * functions used by amdgpu_encoder.c
  */
@@ -1252,6 +1129,9 @@ bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *ade
 int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
                                                u8 perf_req, bool advertise);
 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
+
+void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev,
+               struct amdgpu_dm_backlight_caps *caps);
 #else
 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
index 7f0afc52641934c95e0a7765350ed0228b92d501..4376b17ca594614f9a02b5f9dfd70601cd06c017 100644 (file)
@@ -41,28 +41,21 @@ struct amdgpu_atif_notification_cfg {
 };
 
 struct amdgpu_atif_notifications {
-       bool display_switch;
-       bool expansion_mode_change;
        bool thermal_state;
        bool forced_power_state;
        bool system_power_state;
-       bool display_conf_change;
-       bool px_gfx_switch;
        bool brightness_change;
        bool dgpu_display_event;
+       bool gpu_package_power_limit;
 };
 
 struct amdgpu_atif_functions {
        bool system_params;
        bool sbios_requests;
-       bool select_active_disp;
-       bool lid_state;
-       bool get_tv_standard;
-       bool set_tv_standard;
-       bool get_panel_expansion_mode;
-       bool set_panel_expansion_mode;
        bool temperature_change;
-       bool graphics_device_types;
+       bool query_backlight_transfer_characteristics;
+       bool ready_to_undock;
+       bool external_gpu_information;
 };
 
 struct amdgpu_atif {
@@ -72,6 +65,7 @@ struct amdgpu_atif {
        struct amdgpu_atif_functions functions;
        struct amdgpu_atif_notification_cfg notification_cfg;
        struct amdgpu_encoder *encoder_for_bl;
+       struct amdgpu_dm_backlight_caps backlight_caps;
 };
 
 /* Call the ATIF method
@@ -137,15 +131,12 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
  */
 static void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask)
 {
-       n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
-       n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
        n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
        n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
        n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
-       n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
-       n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
        n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
        n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
+       n->gpu_package_power_limit = mask & ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST_SUPPORTED;
 }
 
 /**
@@ -162,14 +153,11 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas
 {
        f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
        f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
-       f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
-       f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
-       f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
-       f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
-       f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
-       f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
        f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
-       f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
+       f->query_backlight_transfer_characteristics =
+               mask & ATIF_QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS_SUPPORTED;
+       f->ready_to_undock = mask & ATIF_READY_TO_UNDOCK_NOTIFICATION_SUPPORTED;
+       f->external_gpu_information = mask & ATIF_GET_EXTERNAL_GPU_INFORMATION_SUPPORTED;
 }
 
 /**
@@ -310,6 +298,65 @@ out:
        return err;
 }
 
+/**
+ * amdgpu_atif_query_backlight_caps - get min and max backlight input signal
+ *
+ * @handle: acpi handle
+ *
+ * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function
+ * to determine the acceptable range of backlight values
+ *
+ * Backlight_caps.caps_valid will be set to true if the query is successful
+ *
+ * The input signals are in range 0-255
+ *
+ * This function assumes the display with backlight is the first LCD
+ *
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif)
+{
+       union acpi_object *info;
+       struct atif_qbtc_output characteristics;
+       struct atif_qbtc_arguments arguments;
+       struct acpi_buffer params;
+       size_t size;
+       int err = 0;
+
+       arguments.size = sizeof(arguments);
+       arguments.requested_display = ATIF_QBTC_REQUEST_LCD1;
+
+       params.length = sizeof(arguments);
+       params.pointer = (void *)&arguments;
+
+       info = amdgpu_atif_call(atif,
+               ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS,
+               &params);
+       if (!info) {
+               err = -EIO;
+               goto out;
+       }
+
+       size = *(u16 *) info->buffer.pointer;
+       if (size < 10) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       memset(&characteristics, 0, sizeof(characteristics));
+       size = min(sizeof(characteristics), size);
+       memcpy(&characteristics, info->buffer.pointer, size);
+
+       atif->backlight_caps.caps_valid = true;
+       atif->backlight_caps.min_input_signal =
+                       characteristics.min_input_signal;
+       atif->backlight_caps.max_input_signal =
+                       characteristics.max_input_signal;
+out:
+       kfree(info);
+       return err;
+}
+
 /**
  * amdgpu_atif_get_sbios_requests - get requested sbios event
  *
@@ -799,6 +846,17 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
                }
        }
 
+       if (atif->functions.query_backlight_transfer_characteristics) {
+               ret = amdgpu_atif_query_backlight_caps(atif);
+               if (ret) {
+                       DRM_DEBUG_DRIVER("Call to QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS failed: %d\n",
+                                       ret);
+                       atif->backlight_caps.caps_valid = false;
+               }
+       } else {
+               atif->backlight_caps.caps_valid = false;
+       }
+
 out:
        adev->acpi_nb.notifier_call = amdgpu_acpi_event;
        register_acpi_notifier(&adev->acpi_nb);
@@ -806,6 +864,18 @@ out:
        return ret;
 }
 
+void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev,
+               struct amdgpu_dm_backlight_caps *caps)
+{
+       if (!adev->atif) {
+               caps->caps_valid = false;
+               return;
+       }
+       caps->caps_valid = adev->atif->backlight_caps.caps_valid;
+       caps->min_input_signal = adev->atif->backlight_caps.min_input_signal;
+       caps->max_input_signal = adev->atif->backlight_caps.max_input_signal;
+}
+
 /**
  * amdgpu_acpi_fini - tear down driver acpi support
  *
@@ -816,6 +886,5 @@ out:
 void amdgpu_acpi_fini(struct amdgpu_device *adev)
 {
        unregister_acpi_notifier(&adev->acpi_nb);
-       if (adev->atif)
-               kfree(adev->atif);
+       kfree(adev->atif);
 }
index 1580ec60b89f753ce2e12018b2a07eb936802d2e..2dfaf158ef073340e778c9f51a9e6bc905f3f48d 100644 (file)
 #include "amdgpu.h"
 #include "amdgpu_gfx.h"
 #include <linux/module.h>
+#include <linux/dma-buf.h>
 
 const struct kgd2kfd_calls *kgd2kfd;
 
 static const unsigned int compute_vmid_bitmap = 0xFF00;
 
+/* Total memory size in system memory and all GPU VRAM. Used to
+ * estimate worst case amount of memory to reserve for page tables
+ */
+uint64_t amdgpu_amdkfd_total_mem_size;
+
 int amdgpu_amdkfd_init(void)
 {
+       struct sysinfo si;
        int ret;
 
+       si_meminfo(&si);
+       amdgpu_amdkfd_total_mem_size = si.totalram - si.totalhigh;
+       amdgpu_amdkfd_total_mem_size *= si.mem_unit;
+
 #ifdef CONFIG_HSA_AMD
        ret = kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd);
        if (ret)
@@ -73,9 +84,11 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions();
                break;
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                kfd2kgd = amdgpu_amdkfd_gfx_9_0_get_functions();
@@ -85,8 +98,11 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
                return;
        }
 
-       adev->kfd = kgd2kfd->probe((struct kgd_dev *)adev,
-                                  adev->pdev, kfd2kgd);
+       adev->kfd.dev = kgd2kfd->probe((struct kgd_dev *)adev,
+                                      adev->pdev, kfd2kgd);
+
+       if (adev->kfd.dev)
+               amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size;
 }
 
 /**
@@ -126,7 +142,8 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
 {
        int i, n;
        int last_valid_bit;
-       if (adev->kfd) {
+
+       if (adev->kfd.dev) {
                struct kgd2kfd_shared_resources gpu_resources = {
                        .compute_vmid_bitmap = compute_vmid_bitmap,
                        .num_pipe_per_mec = adev->gfx.mec.num_pipe_per_mec,
@@ -144,7 +161,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
                                  KGD_MAX_QUEUES);
 
                /* remove the KIQ bit as well */
-               if (adev->gfx.kiq.ring.ready)
+               if (adev->gfx.kiq.ring.sched.ready)
                        clear_bit(amdgpu_gfx_queue_to_bit(adev,
                                                          adev->gfx.kiq.ring.me - 1,
                                                          adev->gfx.kiq.ring.pipe,
@@ -165,7 +182,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
                                &gpu_resources.doorbell_start_offset);
 
                if (adev->asic_type < CHIP_VEGA10) {
-                       kgd2kfd->device_init(adev->kfd, &gpu_resources);
+                       kgd2kfd->device_init(adev->kfd.dev, &gpu_resources);
                        return;
                }
 
@@ -179,25 +196,14 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
                         * process in case of 64-bit doorbells so we
                         * can use each doorbell assignment twice.
                         */
-                       if (adev->asic_type == CHIP_VEGA10) {
-                               gpu_resources.sdma_doorbell[0][i] =
-                                       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE0 + (i >> 1);
-                               gpu_resources.sdma_doorbell[0][i+1] =
-                                       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE0 + 0x200 + (i >> 1);
-                               gpu_resources.sdma_doorbell[1][i] =
-                                       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE1 + (i >> 1);
-                               gpu_resources.sdma_doorbell[1][i+1] =
-                                       AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE1 + 0x200 + (i >> 1);
-                       } else {
-                               gpu_resources.sdma_doorbell[0][i] =
-                                       AMDGPU_DOORBELL64_sDMA_ENGINE0 + (i >> 1);
-                               gpu_resources.sdma_doorbell[0][i+1] =
-                                       AMDGPU_DOORBELL64_sDMA_ENGINE0 + 0x200 + (i >> 1);
-                               gpu_resources.sdma_doorbell[1][i] =
-                                       AMDGPU_DOORBELL64_sDMA_ENGINE1 + (i >> 1);
-                               gpu_resources.sdma_doorbell[1][i+1] =
-                                       AMDGPU_DOORBELL64_sDMA_ENGINE1 + 0x200 + (i >> 1);
-                       }
+                       gpu_resources.sdma_doorbell[0][i] =
+                               adev->doorbell_index.sdma_engine0 + (i >> 1);
+                       gpu_resources.sdma_doorbell[0][i+1] =
+                               adev->doorbell_index.sdma_engine0 + 0x200 + (i >> 1);
+                       gpu_resources.sdma_doorbell[1][i] =
+                               adev->doorbell_index.sdma_engine1 + (i >> 1);
+                       gpu_resources.sdma_doorbell[1][i+1] =
+                               adev->doorbell_index.sdma_engine1 + 0x200 + (i >> 1);
                }
                /* Doorbells 0x0e0-0ff and 0x2e0-2ff are reserved for
                 * SDMA, IH and VCN. So don't use them for the CP.
@@ -205,37 +211,37 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
                gpu_resources.reserved_doorbell_mask = 0x1e0;
                gpu_resources.reserved_doorbell_val  = 0x0e0;
 
-               kgd2kfd->device_init(adev->kfd, &gpu_resources);
+               kgd2kfd->device_init(adev->kfd.dev, &gpu_resources);
        }
 }
 
 void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev)
 {
-       if (adev->kfd) {
-               kgd2kfd->device_exit(adev->kfd);
-               adev->kfd = NULL;
+       if (adev->kfd.dev) {
+               kgd2kfd->device_exit(adev->kfd.dev);
+               adev->kfd.dev = NULL;
        }
 }
 
 void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,
                const void *ih_ring_entry)
 {
-       if (adev->kfd)
-               kgd2kfd->interrupt(adev->kfd, ih_ring_entry);
+       if (adev->kfd.dev)
+               kgd2kfd->interrupt(adev->kfd.dev, ih_ring_entry);
 }
 
 void amdgpu_amdkfd_suspend(struct amdgpu_device *adev)
 {
-       if (adev->kfd)
-               kgd2kfd->suspend(adev->kfd);
+       if (adev->kfd.dev)
+               kgd2kfd->suspend(adev->kfd.dev);
 }
 
 int amdgpu_amdkfd_resume(struct amdgpu_device *adev)
 {
        int r = 0;
 
-       if (adev->kfd)
-               r = kgd2kfd->resume(adev->kfd);
+       if (adev->kfd.dev)
+               r = kgd2kfd->resume(adev->kfd.dev);
 
        return r;
 }
@@ -244,8 +250,8 @@ int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev)
 {
        int r = 0;
 
-       if (adev->kfd)
-               r = kgd2kfd->pre_reset(adev->kfd);
+       if (adev->kfd.dev)
+               r = kgd2kfd->pre_reset(adev->kfd.dev);
 
        return r;
 }
@@ -254,8 +260,8 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev)
 {
        int r = 0;
 
-       if (adev->kfd)
-               r = kgd2kfd->post_reset(adev->kfd);
+       if (adev->kfd.dev)
+               r = kgd2kfd->post_reset(adev->kfd.dev);
 
        return r;
 }
@@ -268,9 +274,9 @@ void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd)
                amdgpu_device_gpu_recover(adev, NULL);
 }
 
-int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
-                       void **mem_obj, uint64_t *gpu_addr,
-                       void **cpu_ptr, bool mqd_gfx9)
+int amdgpu_amdkfd_alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+                               void **mem_obj, uint64_t *gpu_addr,
+                               void **cpu_ptr, bool mqd_gfx9)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
        struct amdgpu_bo *bo = NULL;
@@ -340,7 +346,7 @@ allocate_mem_reserve_bo_failed:
        return r;
 }
 
-void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
+void amdgpu_amdkfd_free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
 {
        struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj;
 
@@ -351,8 +357,8 @@ void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
        amdgpu_bo_unref(&(bo));
 }
 
-void get_local_mem_info(struct kgd_dev *kgd,
-                       struct kfd_local_mem_info *mem_info)
+void amdgpu_amdkfd_get_local_mem_info(struct kgd_dev *kgd,
+                                     struct kfd_local_mem_info *mem_info)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
        uint64_t address_mask = adev->dev->dma_mask ? ~*adev->dev->dma_mask :
@@ -383,7 +389,7 @@ void get_local_mem_info(struct kgd_dev *kgd,
                mem_info->mem_clk_max = 100;
 }
 
-uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
+uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct kgd_dev *kgd)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
 
@@ -392,7 +398,7 @@ uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
        return 0;
 }
 
-uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
+uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
 
@@ -405,7 +411,7 @@ uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
                return 100;
 }
 
-void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
+void amdgpu_amdkfd_get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
        struct amdgpu_cu_info acu_info = adev->gfx.cu_info;
@@ -428,6 +434,62 @@ void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
        cu_info->lds_size = acu_info.lds_size;
 }
 
+int amdgpu_amdkfd_get_dmabuf_info(struct kgd_dev *kgd, int dma_buf_fd,
+                                 struct kgd_dev **dma_buf_kgd,
+                                 uint64_t *bo_size, void *metadata_buffer,
+                                 size_t buffer_size, uint32_t *metadata_size,
+                                 uint32_t *flags)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
+       struct dma_buf *dma_buf;
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *bo;
+       uint64_t metadata_flags;
+       int r = -EINVAL;
+
+       dma_buf = dma_buf_get(dma_buf_fd);
+       if (IS_ERR(dma_buf))
+               return PTR_ERR(dma_buf);
+
+       if (dma_buf->ops != &amdgpu_dmabuf_ops)
+               /* Can't handle non-graphics buffers */
+               goto out_put;
+
+       obj = dma_buf->priv;
+       if (obj->dev->driver != adev->ddev->driver)
+               /* Can't handle buffers from different drivers */
+               goto out_put;
+
+       adev = obj->dev->dev_private;
+       bo = gem_to_amdgpu_bo(obj);
+       if (!(bo->preferred_domains & (AMDGPU_GEM_DOMAIN_VRAM |
+                                   AMDGPU_GEM_DOMAIN_GTT)))
+               /* Only VRAM and GTT BOs are supported */
+               goto out_put;
+
+       r = 0;
+       if (dma_buf_kgd)
+               *dma_buf_kgd = (struct kgd_dev *)adev;
+       if (bo_size)
+               *bo_size = amdgpu_bo_size(bo);
+       if (metadata_size)
+               *metadata_size = bo->metadata_size;
+       if (metadata_buffer)
+               r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size,
+                                          metadata_size, &metadata_flags);
+       if (flags) {
+               *flags = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
+                       ALLOC_MEM_FLAGS_VRAM : ALLOC_MEM_FLAGS_GTT;
+
+               if (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
+                       *flags |= ALLOC_MEM_FLAGS_PUBLIC;
+       }
+
+out_put:
+       dma_buf_put(dma_buf);
+       return r;
+}
+
 uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
@@ -510,7 +572,7 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle)
 
 bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid)
 {
-       if (adev->kfd) {
+       if (adev->kfd.dev) {
                if ((1 << vmid) & compute_vmid_bitmap)
                        return true;
        }
@@ -524,7 +586,7 @@ bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm)
        return false;
 }
 
-void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo)
+void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo)
 {
 }
 
index 8e0d4f7196b4f483818ad951df7f59e8e0b0f60f..70429f7aa9a84c0189ce3e3748a55f4b3549b08b 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/mmu_context.h>
 #include <linux/workqueue.h>
 #include <kgd_kfd_interface.h>
 #include <drm/ttm/ttm_execbuf_util.h>
@@ -35,6 +34,7 @@
 #include "amdgpu_vm.h"
 
 extern const struct kgd2kfd_calls *kgd2kfd;
+extern uint64_t amdgpu_amdkfd_total_mem_size;
 
 struct amdgpu_device;
 
@@ -77,6 +77,11 @@ struct amdgpu_amdkfd_fence {
        char timeline_name[TASK_COMM_LEN];
 };
 
+struct amdgpu_kfd_dev {
+       struct kfd_dev *dev;
+       uint64_t vram_used;
+};
+
 struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
                                                       struct mm_struct *mm);
 bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm);
@@ -134,16 +139,21 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev);
 void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd);
 
 /* Shared API */
-int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
-                       void **mem_obj, uint64_t *gpu_addr,
-                       void **cpu_ptr, bool mqd_gfx9);
-void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
-void get_local_mem_info(struct kgd_dev *kgd,
-                       struct kfd_local_mem_info *mem_info);
-uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
-
-uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
-void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info);
+int amdgpu_amdkfd_alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+                               void **mem_obj, uint64_t *gpu_addr,
+                               void **cpu_ptr, bool mqd_gfx9);
+void amdgpu_amdkfd_free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
+void amdgpu_amdkfd_get_local_mem_info(struct kgd_dev *kgd,
+                                     struct kfd_local_mem_info *mem_info);
+uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct kgd_dev *kgd);
+
+uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
+void amdgpu_amdkfd_get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info);
+int amdgpu_amdkfd_get_dmabuf_info(struct kgd_dev *kgd, int dma_buf_fd,
+                                 struct kgd_dev **dmabuf_kgd,
+                                 uint64_t *bo_size, void *metadata_buffer,
+                                 size_t buffer_size, uint32_t *metadata_size,
+                                 uint32_t *flags);
 uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd);
 uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd);
 
@@ -195,7 +205,13 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info,
 int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd,
                                              struct kfd_vm_fault_info *info);
 
+int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd,
+                                     struct dma_buf *dmabuf,
+                                     uint64_t va, void *vm,
+                                     struct kgd_mem **mem, uint64_t *size,
+                                     uint64_t *mmap_offset);
+
 void amdgpu_amdkfd_gpuvm_init_mem_limits(void);
-void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo);
+void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo);
 
 #endif /* AMDGPU_AMDKFD_H_INCLUDED */
index 244d9834a3814381e638758a091b9f8287f8b57e..ff7fac7df34b5be7b7e46cabc1f743e3775a8761 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/fdtable.h>
 #include <linux/uaccess.h>
 #include <linux/firmware.h>
+#include <linux/mmu_context.h>
 #include <drm/drmP.h>
 #include "amdgpu.h"
 #include "amdgpu_amdkfd.h"
@@ -173,13 +174,6 @@ static int get_tile_config(struct kgd_dev *kgd,
 }
 
 static const struct kfd2kgd_calls kfd2kgd = {
-       .init_gtt_mem_allocation = alloc_gtt_mem,
-       .free_gtt_mem = free_gtt_mem,
-       .get_local_mem_info = get_local_mem_info,
-       .get_gpu_clock_counter = get_gpu_clock_counter,
-       .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
-       .alloc_pasid = amdgpu_pasid_alloc,
-       .free_pasid = amdgpu_pasid_free,
        .program_sh_mem_settings = kgd_program_sh_mem_settings,
        .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
        .init_interrupts = kgd_init_interrupts,
@@ -200,28 +194,10 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .get_fw_version = get_fw_version,
        .set_scratch_backing_va = set_scratch_backing_va,
        .get_tile_config = get_tile_config,
-       .get_cu_info = get_cu_info,
-       .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
-       .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
-       .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
-       .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
-       .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
-       .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
        .set_vm_context_page_table_base = set_vm_context_page_table_base,
-       .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
-       .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
-       .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
-       .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
-       .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
-       .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
-       .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
        .invalidate_tlbs = invalidate_tlbs,
        .invalidate_tlbs_vmid = invalidate_tlbs_vmid,
-       .submit_ib = amdgpu_amdkfd_submit_ib,
-       .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info,
        .read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg,
-       .gpu_recover = amdgpu_amdkfd_gpu_reset,
-       .set_compute_idle = amdgpu_amdkfd_set_compute_idle
 };
 
 struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void)
index 9f149914ad6cd113343cdd6ec406fa240d9fe7c4..56ea929f524b5c31831abdb8d50233aa01929636 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fdtable.h>
 #include <linux/uaccess.h>
 #include <linux/firmware.h>
+#include <linux/mmu_context.h>
 #include <drm/drmP.h>
 #include "amdgpu.h"
 #include "amdgpu_amdkfd.h"
@@ -128,13 +129,6 @@ static int get_tile_config(struct kgd_dev *kgd,
 }
 
 static const struct kfd2kgd_calls kfd2kgd = {
-       .init_gtt_mem_allocation = alloc_gtt_mem,
-       .free_gtt_mem = free_gtt_mem,
-       .get_local_mem_info = get_local_mem_info,
-       .get_gpu_clock_counter = get_gpu_clock_counter,
-       .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
-       .alloc_pasid = amdgpu_pasid_alloc,
-       .free_pasid = amdgpu_pasid_free,
        .program_sh_mem_settings = kgd_program_sh_mem_settings,
        .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
        .init_interrupts = kgd_init_interrupts,
@@ -157,27 +151,9 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .get_fw_version = get_fw_version,
        .set_scratch_backing_va = set_scratch_backing_va,
        .get_tile_config = get_tile_config,
-       .get_cu_info = get_cu_info,
-       .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
-       .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
-       .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
-       .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
-       .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
-       .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
        .set_vm_context_page_table_base = set_vm_context_page_table_base,
-       .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
-       .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
-       .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
-       .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
-       .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
-       .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
-       .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
        .invalidate_tlbs = invalidate_tlbs,
        .invalidate_tlbs_vmid = invalidate_tlbs_vmid,
-       .submit_ib = amdgpu_amdkfd_submit_ib,
-       .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info,
-       .gpu_recover = amdgpu_amdkfd_gpu_reset,
-       .set_compute_idle = amdgpu_amdkfd_set_compute_idle
 };
 
 struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void)
index 42cb4c4e0929150de17d2056dbb055883e642157..5c51d4910650934752d22c5bd2b0f06c768708ee 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/fdtable.h>
 #include <linux/uaccess.h>
 #include <linux/firmware.h>
+#include <linux/mmu_context.h>
 #include <drm/drmP.h>
 #include "amdgpu.h"
 #include "amdgpu_amdkfd.h"
 #include "v9_structs.h"
 #include "soc15.h"
 #include "soc15d.h"
+#include "mmhub_v1_0.h"
+#include "gfxhub_v1_0.h"
 
-/* HACK: MMHUB and GC both have VM-related register with the same
- * names but different offsets. Define the MMHUB register we need here
- * with a prefix. A proper solution would be to move the functions
- * programming these registers into gfx_v9_0.c and mmhub_v1_0.c
- * respectively.
- */
-#define mmMMHUB_VM_INVALIDATE_ENG16_REQ                                0x06f3
-#define mmMMHUB_VM_INVALIDATE_ENG16_REQ_BASE_IDX               0
-
-#define mmMMHUB_VM_INVALIDATE_ENG16_ACK                                0x0705
-#define mmMMHUB_VM_INVALIDATE_ENG16_ACK_BASE_IDX               0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32          0x072b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32_BASE_IDX 0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32          0x072c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32_BASE_IDX 0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32         0x074b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32_BASE_IDX        0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32         0x074c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32_BASE_IDX        0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32           0x076b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32_BASE_IDX  0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32           0x076c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32_BASE_IDX  0
-
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32            0x0727
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32_BASE_IDX   0
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32            0x0728
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32_BASE_IDX   0
 
 #define V9_PIPE_PER_MEC                (4)
 #define V9_QUEUES_PER_PIPE_MEC (8)
@@ -167,13 +139,6 @@ static int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd,
 }
 
 static const struct kfd2kgd_calls kfd2kgd = {
-       .init_gtt_mem_allocation = alloc_gtt_mem,
-       .free_gtt_mem = free_gtt_mem,
-       .get_local_mem_info = get_local_mem_info,
-       .get_gpu_clock_counter = get_gpu_clock_counter,
-       .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
-       .alloc_pasid = amdgpu_pasid_alloc,
-       .free_pasid = amdgpu_pasid_free,
        .program_sh_mem_settings = kgd_program_sh_mem_settings,
        .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
        .init_interrupts = kgd_init_interrupts,
@@ -196,26 +161,9 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .get_fw_version = get_fw_version,
        .set_scratch_backing_va = set_scratch_backing_va,
        .get_tile_config = amdgpu_amdkfd_get_tile_config,
-       .get_cu_info = get_cu_info,
-       .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
-       .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
-       .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
-       .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
-       .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
-       .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
        .set_vm_context_page_table_base = set_vm_context_page_table_base,
-       .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
-       .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
-       .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
-       .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
-       .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
-       .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
-       .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
        .invalidate_tlbs = invalidate_tlbs,
        .invalidate_tlbs_vmid = invalidate_tlbs_vmid,
-       .submit_ib = amdgpu_amdkfd_submit_ib,
-       .gpu_recover = amdgpu_amdkfd_gpu_reset,
-       .set_compute_idle = amdgpu_amdkfd_set_compute_idle,
        .get_hive_id = amdgpu_amdkfd_get_hive_id,
 };
 
@@ -785,15 +733,6 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
 static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
-       uint32_t req = (1 << vmid) |
-               (0 << VM_INVALIDATE_ENG16_REQ__FLUSH_TYPE__SHIFT) | /* legacy */
-               VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PTES_MASK |
-               VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE0_MASK |
-               VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE1_MASK |
-               VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE2_MASK |
-               VM_INVALIDATE_ENG16_REQ__INVALIDATE_L1_PTES_MASK;
-
-       mutex_lock(&adev->srbm_mutex);
 
        /* Use legacy mode tlb invalidation.
         *
@@ -810,34 +749,7 @@ static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid)
         * TODO 2: support range-based invalidation, requires kfg2kgd
         * interface change
         */
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ADDR_RANGE_LO32),
-                               0xffffffff);
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ADDR_RANGE_HI32),
-                               0x0000001f);
-
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0,
-                               mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32),
-                               0xffffffff);
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0,
-                               mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32),
-                               0x0000001f);
-
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_REQ), req);
-
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_INVALIDATE_ENG16_REQ),
-                               req);
-
-       while (!(RREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ACK)) &
-                                       (1 << vmid)))
-               cpu_relax();
-
-       while (!(RREG32(SOC15_REG_OFFSET(MMHUB, 0,
-                                       mmMMHUB_VM_INVALIDATE_ENG16_ACK)) &
-                                       (1 << vmid)))
-               cpu_relax();
-
-       mutex_unlock(&adev->srbm_mutex);
-
+       amdgpu_gmc_flush_gpu_tlb(adev, vmid, 0);
 }
 
 static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid)
@@ -876,7 +788,7 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
        if (adev->in_gpu_reset)
                return -EIO;
 
-       if (ring->ready)
+       if (ring->sched.ready)
                return invalidate_tlbs_with_kiq(adev, pasid);
 
        for (vmid = 0; vmid < 16; vmid++) {
@@ -1016,7 +928,6 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
                uint64_t page_table_base)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
-       uint64_t base = page_table_base | AMDGPU_PTE_VALID;
 
        if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
                pr_err("trying to set page table base for wrong VMID %u\n",
@@ -1028,25 +939,7 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
         * now, all processes share the same address space size, like
         * on GFX8 and older.
         */
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32) + (vmid*2), 0);
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32) + (vmid*2), 0);
-
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32) + (vmid*2),
-                       lower_32_bits(adev->vm_manager.max_pfn - 1));
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32) + (vmid*2),
-                       upper_32_bits(adev->vm_manager.max_pfn - 1));
-
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32) + (vmid*2), lower_32_bits(base));
-       WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) + (vmid*2), upper_32_bits(base));
-
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32) + (vmid*2), 0);
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32) + (vmid*2), 0);
-
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32) + (vmid*2),
-                       lower_32_bits(adev->vm_manager.max_pfn - 1));
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32) + (vmid*2),
-                       upper_32_bits(adev->vm_manager.max_pfn - 1));
+       mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
 
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32) + (vmid*2), lower_32_bits(base));
-       WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) + (vmid*2), upper_32_bits(base));
+       gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
 }
index df0a059565f93aaadeec263b0999cda1fca09bcb..be1ab43473c6c727bd1832efa3d5b7c09edffed2 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/list.h>
 #include <linux/pagemap.h>
 #include <linux/sched/mm.h>
+#include <linux/dma-buf.h>
 #include <drm/drmP.h>
 #include "amdgpu_object.h"
 #include "amdgpu_vm.h"
@@ -46,9 +47,9 @@
 /* Impose limit on how much memory KFD can use */
 static struct {
        uint64_t max_system_mem_limit;
-       uint64_t max_userptr_mem_limit;
+       uint64_t max_ttm_mem_limit;
        int64_t system_mem_used;
-       int64_t userptr_mem_used;
+       int64_t ttm_mem_used;
        spinlock_t mem_limit_lock;
 } kfd_mem_limit;
 
@@ -90,8 +91,8 @@ static bool check_if_add_bo_to_vm(struct amdgpu_vm *avm,
 }
 
 /* Set memory usage limits. Current, limits are
- *  System (kernel) memory - 3/8th System RAM
- *  Userptr memory - 3/4th System RAM
+ *  System (TTM + userptr) memory - 3/4th System RAM
+ *  TTM memory - 3/8th System RAM
  */
 void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
 {
@@ -103,48 +104,61 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
        mem *= si.mem_unit;
 
        spin_lock_init(&kfd_mem_limit.mem_limit_lock);
-       kfd_mem_limit.max_system_mem_limit = (mem >> 1) - (mem >> 3);
-       kfd_mem_limit.max_userptr_mem_limit = mem - (mem >> 2);
-       pr_debug("Kernel memory limit %lluM, userptr limit %lluM\n",
+       kfd_mem_limit.max_system_mem_limit = (mem >> 1) + (mem >> 2);
+       kfd_mem_limit.max_ttm_mem_limit = (mem >> 1) - (mem >> 3);
+       pr_debug("Kernel memory limit %lluM, TTM limit %lluM\n",
                (kfd_mem_limit.max_system_mem_limit >> 20),
-               (kfd_mem_limit.max_userptr_mem_limit >> 20));
+               (kfd_mem_limit.max_ttm_mem_limit >> 20));
 }
 
-static int amdgpu_amdkfd_reserve_system_mem_limit(struct amdgpu_device *adev,
-                                             uint64_t size, u32 domain)
+static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
+               uint64_t size, u32 domain, bool sg)
 {
-       size_t acc_size;
+       size_t acc_size, system_mem_needed, ttm_mem_needed, vram_needed;
+       uint64_t reserved_for_pt = amdgpu_amdkfd_total_mem_size >> 9;
        int ret = 0;
 
        acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
                                       sizeof(struct amdgpu_bo));
 
-       spin_lock(&kfd_mem_limit.mem_limit_lock);
+       vram_needed = 0;
        if (domain == AMDGPU_GEM_DOMAIN_GTT) {
-               if (kfd_mem_limit.system_mem_used + (acc_size + size) >
-                       kfd_mem_limit.max_system_mem_limit) {
-                       ret = -ENOMEM;
-                       goto err_no_mem;
-               }
-               kfd_mem_limit.system_mem_used += (acc_size + size);
-       } else if (domain == AMDGPU_GEM_DOMAIN_CPU) {
-               if ((kfd_mem_limit.system_mem_used + acc_size >
-                       kfd_mem_limit.max_system_mem_limit) ||
-                       (kfd_mem_limit.userptr_mem_used + (size + acc_size) >
-                       kfd_mem_limit.max_userptr_mem_limit)) {
-                       ret = -ENOMEM;
-                       goto err_no_mem;
-               }
-               kfd_mem_limit.system_mem_used += acc_size;
-               kfd_mem_limit.userptr_mem_used += size;
+               /* TTM GTT memory */
+               system_mem_needed = acc_size + size;
+               ttm_mem_needed = acc_size + size;
+       } else if (domain == AMDGPU_GEM_DOMAIN_CPU && !sg) {
+               /* Userptr */
+               system_mem_needed = acc_size + size;
+               ttm_mem_needed = acc_size;
+       } else {
+               /* VRAM and SG */
+               system_mem_needed = acc_size;
+               ttm_mem_needed = acc_size;
+               if (domain == AMDGPU_GEM_DOMAIN_VRAM)
+                       vram_needed = size;
+       }
+
+       spin_lock(&kfd_mem_limit.mem_limit_lock);
+
+       if ((kfd_mem_limit.system_mem_used + system_mem_needed >
+            kfd_mem_limit.max_system_mem_limit) ||
+           (kfd_mem_limit.ttm_mem_used + ttm_mem_needed >
+            kfd_mem_limit.max_ttm_mem_limit) ||
+           (adev->kfd.vram_used + vram_needed >
+            adev->gmc.real_vram_size - reserved_for_pt)) {
+               ret = -ENOMEM;
+       } else {
+               kfd_mem_limit.system_mem_used += system_mem_needed;
+               kfd_mem_limit.ttm_mem_used += ttm_mem_needed;
+               adev->kfd.vram_used += vram_needed;
        }
-err_no_mem:
+
        spin_unlock(&kfd_mem_limit.mem_limit_lock);
        return ret;
 }
 
-static void unreserve_system_mem_limit(struct amdgpu_device *adev,
-                                      uint64_t size, u32 domain)
+static void unreserve_mem_limit(struct amdgpu_device *adev,
+               uint64_t size, u32 domain, bool sg)
 {
        size_t acc_size;
 
@@ -154,35 +168,39 @@ static void unreserve_system_mem_limit(struct amdgpu_device *adev,
        spin_lock(&kfd_mem_limit.mem_limit_lock);
        if (domain == AMDGPU_GEM_DOMAIN_GTT) {
                kfd_mem_limit.system_mem_used -= (acc_size + size);
-       } else if (domain == AMDGPU_GEM_DOMAIN_CPU) {
+               kfd_mem_limit.ttm_mem_used -= (acc_size + size);
+       } else if (domain == AMDGPU_GEM_DOMAIN_CPU && !sg) {
+               kfd_mem_limit.system_mem_used -= (acc_size + size);
+               kfd_mem_limit.ttm_mem_used -= acc_size;
+       } else {
                kfd_mem_limit.system_mem_used -= acc_size;
-               kfd_mem_limit.userptr_mem_used -= size;
+               kfd_mem_limit.ttm_mem_used -= acc_size;
+               if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
+                       adev->kfd.vram_used -= size;
+                       WARN_ONCE(adev->kfd.vram_used < 0,
+                                 "kfd VRAM memory accounting unbalanced");
+               }
        }
        WARN_ONCE(kfd_mem_limit.system_mem_used < 0,
                  "kfd system memory accounting unbalanced");
-       WARN_ONCE(kfd_mem_limit.userptr_mem_used < 0,
-                 "kfd userptr memory accounting unbalanced");
+       WARN_ONCE(kfd_mem_limit.ttm_mem_used < 0,
+                 "kfd TTM memory accounting unbalanced");
 
        spin_unlock(&kfd_mem_limit.mem_limit_lock);
 }
 
-void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo)
+void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo)
 {
-       spin_lock(&kfd_mem_limit.mem_limit_lock);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+       u32 domain = bo->preferred_domains;
+       bool sg = (bo->preferred_domains == AMDGPU_GEM_DOMAIN_CPU);
 
        if (bo->flags & AMDGPU_AMDKFD_USERPTR_BO) {
-               kfd_mem_limit.system_mem_used -= bo->tbo.acc_size;
-               kfd_mem_limit.userptr_mem_used -= amdgpu_bo_size(bo);
-       } else if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_GTT) {
-               kfd_mem_limit.system_mem_used -=
-                       (bo->tbo.acc_size + amdgpu_bo_size(bo));
+               domain = AMDGPU_GEM_DOMAIN_CPU;
+               sg = false;
        }
-       WARN_ONCE(kfd_mem_limit.system_mem_used < 0,
-                 "kfd system memory accounting unbalanced");
-       WARN_ONCE(kfd_mem_limit.userptr_mem_used < 0,
-                 "kfd userptr memory accounting unbalanced");
 
-       spin_unlock(&kfd_mem_limit.mem_limit_lock);
+       unreserve_mem_limit(adev, amdgpu_bo_size(bo), domain, sg);
 }
 
 
@@ -395,23 +413,6 @@ static int vm_validate_pt_pd_bos(struct amdgpu_vm *vm)
        return 0;
 }
 
-static int sync_vm_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync,
-                        struct dma_fence *f)
-{
-       int ret = amdgpu_sync_fence(adev, sync, f, false);
-
-       /* Sync objects can't handle multiple GPUs (contexts) updating
-        * sync->last_vm_update. Fortunately we don't need it for
-        * KFD's purposes, so we can just drop that fence.
-        */
-       if (sync->last_vm_update) {
-               dma_fence_put(sync->last_vm_update);
-               sync->last_vm_update = NULL;
-       }
-
-       return ret;
-}
-
 static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync)
 {
        struct amdgpu_bo *pd = vm->root.base.bo;
@@ -422,7 +423,7 @@ static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync)
        if (ret)
                return ret;
 
-       return sync_vm_fence(adev, sync, vm->last_update);
+       return amdgpu_sync_fence(NULL, sync, vm->last_update, false);
 }
 
 /* add_bo_to_vm - Add a BO to a VM
@@ -536,7 +537,7 @@ static void add_kgd_mem_to_kfd_bo_list(struct kgd_mem *mem,
        struct amdgpu_bo *bo = mem->bo;
 
        INIT_LIST_HEAD(&entry->head);
-       entry->shared = true;
+       entry->num_shared = 1;
        entry->bo = &bo->tbo;
        mutex_lock(&process_info->lock);
        if (userptr)
@@ -677,7 +678,7 @@ static int reserve_bo_and_vm(struct kgd_mem *mem,
 
        ctx->kfd_bo.priority = 0;
        ctx->kfd_bo.tv.bo = &bo->tbo;
-       ctx->kfd_bo.tv.shared = true;
+       ctx->kfd_bo.tv.num_shared = 1;
        ctx->kfd_bo.user_pages = NULL;
        list_add(&ctx->kfd_bo.tv.head, &ctx->list);
 
@@ -741,7 +742,7 @@ static int reserve_bo_and_cond_vms(struct kgd_mem *mem,
 
        ctx->kfd_bo.priority = 0;
        ctx->kfd_bo.tv.bo = &bo->tbo;
-       ctx->kfd_bo.tv.shared = true;
+       ctx->kfd_bo.tv.num_shared = 1;
        ctx->kfd_bo.user_pages = NULL;
        list_add(&ctx->kfd_bo.tv.head, &ctx->list);
 
@@ -826,7 +827,7 @@ static int unmap_bo_from_gpuvm(struct amdgpu_device *adev,
        /* Add the eviction fence back */
        amdgpu_bo_fence(pd, &vm->process_info->eviction_fence->base, true);
 
-       sync_vm_fence(adev, sync, bo_va->last_pt_update);
+       amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false);
 
        return 0;
 }
@@ -851,7 +852,7 @@ static int update_gpuvm_pte(struct amdgpu_device *adev,
                return ret;
        }
 
-       return sync_vm_fence(adev, sync, bo_va->last_pt_update);
+       return amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false);
 }
 
 static int map_bo_to_gpuvm(struct amdgpu_device *adev,
@@ -886,6 +887,24 @@ update_gpuvm_pte_failed:
        return ret;
 }
 
+static struct sg_table *create_doorbell_sg(uint64_t addr, uint32_t size)
+{
+       struct sg_table *sg = kmalloc(sizeof(*sg), GFP_KERNEL);
+
+       if (!sg)
+               return NULL;
+       if (sg_alloc_table(sg, 1, GFP_KERNEL)) {
+               kfree(sg);
+               return NULL;
+       }
+       sg->sgl->dma_address = addr;
+       sg->sgl->length = size;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+       sg->sgl->dma_length = size;
+#endif
+       return sg;
+}
+
 static int process_validate_vms(struct amdkfd_process_info *process_info)
 {
        struct amdgpu_vm *peer_vm;
@@ -901,6 +920,26 @@ static int process_validate_vms(struct amdkfd_process_info *process_info)
        return 0;
 }
 
+static int process_sync_pds_resv(struct amdkfd_process_info *process_info,
+                                struct amdgpu_sync *sync)
+{
+       struct amdgpu_vm *peer_vm;
+       int ret;
+
+       list_for_each_entry(peer_vm, &process_info->vm_list_head,
+                           vm_list_node) {
+               struct amdgpu_bo *pd = peer_vm->root.base.bo;
+
+               ret = amdgpu_sync_resv(NULL,
+                                       sync, pd->tbo.resv,
+                                       AMDGPU_FENCE_OWNER_UNDEFINED, false);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int process_update_pds(struct amdkfd_process_info *process_info,
                              struct amdgpu_sync *sync)
 {
@@ -1149,6 +1188,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
        struct amdgpu_vm *avm = (struct amdgpu_vm *)vm;
+       enum ttm_bo_type bo_type = ttm_bo_type_device;
+       struct sg_table *sg = NULL;
        uint64_t user_addr = 0;
        struct amdgpu_bo *bo;
        struct amdgpu_bo_param bp;
@@ -1177,13 +1218,25 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
                if (!offset || !*offset)
                        return -EINVAL;
                user_addr = *offset;
+       } else if (flags & ALLOC_MEM_FLAGS_DOORBELL) {
+               domain = AMDGPU_GEM_DOMAIN_GTT;
+               alloc_domain = AMDGPU_GEM_DOMAIN_CPU;
+               bo_type = ttm_bo_type_sg;
+               alloc_flags = 0;
+               if (size > UINT_MAX)
+                       return -EINVAL;
+               sg = create_doorbell_sg(*offset, size);
+               if (!sg)
+                       return -ENOMEM;
        } else {
                return -EINVAL;
        }
 
        *mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL);
-       if (!*mem)
-               return -ENOMEM;
+       if (!*mem) {
+               ret = -ENOMEM;
+               goto err;
+       }
        INIT_LIST_HEAD(&(*mem)->bo_va_list);
        mutex_init(&(*mem)->lock);
        (*mem)->aql_queue = !!(flags & ALLOC_MEM_FLAGS_AQL_QUEUE_MEM);
@@ -1199,7 +1252,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
        byte_align = (adev->family == AMDGPU_FAMILY_VI &&
                        adev->asic_type != CHIP_FIJI &&
                        adev->asic_type != CHIP_POLARIS10 &&
-                       adev->asic_type != CHIP_POLARIS11) ?
+                       adev->asic_type != CHIP_POLARIS11 &&
+                       adev->asic_type != CHIP_POLARIS12) ?
                        VI_BO_SIZE_ALIGN : 1;
 
        mapping_flags = AMDGPU_VM_PAGE_READABLE;
@@ -1215,10 +1269,10 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
 
        amdgpu_sync_create(&(*mem)->sync);
 
-       ret = amdgpu_amdkfd_reserve_system_mem_limit(adev, size, alloc_domain);
+       ret = amdgpu_amdkfd_reserve_mem_limit(adev, size, alloc_domain, !!sg);
        if (ret) {
                pr_debug("Insufficient system memory\n");
-               goto err_reserve_system_mem;
+               goto err_reserve_limit;
        }
 
        pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n",
@@ -1229,7 +1283,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
        bp.byte_align = byte_align;
        bp.domain = alloc_domain;
        bp.flags = alloc_flags;
-       bp.type = ttm_bo_type_device;
+       bp.type = bo_type;
        bp.resv = NULL;
        ret = amdgpu_bo_create(adev, &bp, &bo);
        if (ret) {
@@ -1237,6 +1291,10 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
                                domain_string(alloc_domain), ret);
                goto err_bo_create;
        }
+       if (bo_type == ttm_bo_type_sg) {
+               bo->tbo.sg = sg;
+               bo->tbo.ttm->sg = sg;
+       }
        bo->kfd_bo = *mem;
        (*mem)->bo = bo;
        if (user_addr)
@@ -1266,12 +1324,17 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
 allocate_init_user_pages_failed:
        amdgpu_bo_unref(&bo);
        /* Don't unreserve system mem limit twice */
-       goto err_reserve_system_mem;
+       goto err_reserve_limit;
 err_bo_create:
-       unreserve_system_mem_limit(adev, size, alloc_domain);
-err_reserve_system_mem:
+       unreserve_mem_limit(adev, size, alloc_domain, !!sg);
+err_reserve_limit:
        mutex_destroy(&(*mem)->lock);
        kfree(*mem);
+err:
+       if (sg) {
+               sg_free_table(sg);
+               kfree(sg);
+       }
        return ret;
 }
 
@@ -1341,6 +1404,14 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
        /* Free the sync object */
        amdgpu_sync_free(&mem->sync);
 
+       /* If the SG is not NULL, it's one we created for a doorbell
+        * BO. We need to free it.
+        */
+       if (mem->bo->tbo.sg) {
+               sg_free_table(mem->bo->tbo.sg);
+               kfree(mem->bo->tbo.sg);
+       }
+
        /* Free the BO*/
        amdgpu_bo_unref(&mem->bo);
        mutex_destroy(&mem->lock);
@@ -1405,7 +1476,8 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
         * the queues are still stopped and we can leave mapping for
         * the next restore worker
         */
-       if (bo->tbo.mem.mem_type == TTM_PL_SYSTEM)
+       if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
+           bo->tbo.mem.mem_type == TTM_PL_SYSTEM)
                is_invalid_userptr = true;
 
        if (check_if_add_bo_to_vm(avm, mem)) {
@@ -1642,6 +1714,60 @@ int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd,
        return 0;
 }
 
+int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd,
+                                     struct dma_buf *dma_buf,
+                                     uint64_t va, void *vm,
+                                     struct kgd_mem **mem, uint64_t *size,
+                                     uint64_t *mmap_offset)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *bo;
+       struct amdgpu_vm *avm = (struct amdgpu_vm *)vm;
+
+       if (dma_buf->ops != &amdgpu_dmabuf_ops)
+               /* Can't handle non-graphics buffers */
+               return -EINVAL;
+
+       obj = dma_buf->priv;
+       if (obj->dev->dev_private != adev)
+               /* Can't handle buffers from other devices */
+               return -EINVAL;
+
+       bo = gem_to_amdgpu_bo(obj);
+       if (!(bo->preferred_domains & (AMDGPU_GEM_DOMAIN_VRAM |
+                                   AMDGPU_GEM_DOMAIN_GTT)))
+               /* Only VRAM and GTT BOs are supported */
+               return -EINVAL;
+
+       *mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL);
+       if (!*mem)
+               return -ENOMEM;
+
+       if (size)
+               *size = amdgpu_bo_size(bo);
+
+       if (mmap_offset)
+               *mmap_offset = amdgpu_bo_mmap_offset(bo);
+
+       INIT_LIST_HEAD(&(*mem)->bo_va_list);
+       mutex_init(&(*mem)->lock);
+       (*mem)->mapping_flags =
+               AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
+               AMDGPU_VM_PAGE_EXECUTABLE | AMDGPU_VM_MTYPE_NC;
+
+       (*mem)->bo = amdgpu_bo_ref(bo);
+       (*mem)->va = va;
+       (*mem)->domain = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
+               AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT;
+       (*mem)->mapped_to_gpu_memory = 0;
+       (*mem)->process_info = avm->process_info;
+       add_kgd_mem_to_kfd_bo_list(*mem, avm->process_info, false);
+       amdgpu_sync_create(&(*mem)->sync);
+
+       return 0;
+}
+
 /* Evict a userptr BO by stopping the queues if necessary
  *
  * Runs in MMU notifier, may be in RECLAIM_FS context. This means it
@@ -1808,7 +1934,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info)
                            validate_list.head) {
                list_add_tail(&mem->resv_list.head, &resv_list);
                mem->resv_list.bo = mem->validate_list.bo;
-               mem->resv_list.shared = mem->validate_list.shared;
+               mem->resv_list.num_shared = mem->validate_list.num_shared;
        }
 
        /* Reserve all BOs and page tables for validation */
@@ -2027,7 +2153,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
 
                list_add_tail(&mem->resv_list.head, &ctx.list);
                mem->resv_list.bo = mem->validate_list.bo;
-               mem->resv_list.shared = mem->validate_list.shared;
+               mem->resv_list.num_shared = mem->validate_list.num_shared;
        }
 
        ret = ttm_eu_reserve_buffers(&ctx.ticket, &ctx.list,
@@ -2044,13 +2170,10 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
        if (ret)
                goto validate_map_fail;
 
-       /* Wait for PD/PTs validate to finish */
-       /* FIXME: I think this isn't needed */
-       list_for_each_entry(peer_vm, &process_info->vm_list_head,
-                           vm_list_node) {
-               struct amdgpu_bo *bo = peer_vm->root.base.bo;
-
-               ttm_bo_wait(&bo->tbo, false, false);
+       ret = process_sync_pds_resv(process_info, &sync_obj);
+       if (ret) {
+               pr_debug("Memory eviction: Failed to sync to PD BO moving fence. Try again\n");
+               goto validate_map_fail;
        }
 
        /* Validate BOs and map them to GPUVM (update VM page tables). */
@@ -2066,7 +2189,11 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
                        pr_debug("Memory eviction: Validate BOs failed. Try again\n");
                        goto validate_map_fail;
                }
-
+               ret = amdgpu_sync_fence(NULL, &sync_obj, bo->tbo.moving, false);
+               if (ret) {
+                       pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
+                       goto validate_map_fail;
+               }
                list_for_each_entry(bo_va_entry, &mem->bo_va_list,
                                    bo_list) {
                        ret = update_gpuvm_pte((struct amdgpu_device *)
@@ -2087,6 +2214,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
                goto validate_map_fail;
        }
 
+       /* Wait for validate and PT updates to finish */
        amdgpu_sync_wait(&sync_obj, false);
 
        /* Release old eviction fence and create new one, because fence only
@@ -2105,10 +2233,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
        process_info->eviction_fence = new_fence;
        *ef = dma_fence_get(&new_fence->base);
 
-       /* Wait for validate to finish and attach new eviction fence */
-       list_for_each_entry(mem, &process_info->kfd_bo_list,
-               validate_list.head)
-               ttm_bo_wait(&mem->bo->tbo, false, false);
+       /* Attach new eviction fence to all BOs */
        list_for_each_entry(mem, &process_info->kfd_bo_list,
                validate_list.head)
                amdgpu_bo_fence(mem->bo,
index 14d2982a47cce32b028e151f6a78b291efe08263..5c79da8e1150ac9ee30e6ce90579961173033c5d 100644 (file)
@@ -118,7 +118,6 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
                entry->priority = min(info[i].bo_priority,
                                      AMDGPU_BO_LIST_MAX_PRIORITY);
                entry->tv.bo = &bo->tbo;
-               entry->tv.shared = !bo->prime_shared_count;
 
                if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_GDS)
                        list->gds_obj = bo;
index 0acc8dee2cb8d3ba99ebcef8af507b91021523ea..cf4e190c0a72bf4df0edcd0f8a358b1a1db6833b 100644 (file)
@@ -50,7 +50,8 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
        bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
        p->uf_entry.priority = 0;
        p->uf_entry.tv.bo = &bo->tbo;
-       p->uf_entry.tv.shared = true;
+       /* One for TTM and one for the CS job */
+       p->uf_entry.tv.num_shared = 2;
        p->uf_entry.user_pages = NULL;
 
        drm_gem_object_put_unlocked(gobj);
@@ -598,6 +599,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                        return r;
        }
 
+       /* One for TTM and one for the CS job */
+       amdgpu_bo_list_for_each_entry(e, p->bo_list)
+               e->tv.num_shared = 2;
+
        amdgpu_bo_list_get_list(p->bo_list, &p->validated);
        if (p->bo_list->first_userptr != p->bo_list->num_entries)
                p->mn = amdgpu_mn_get(p->adev, AMDGPU_MN_TYPE_GFX);
@@ -717,8 +722,14 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
        gws = p->bo_list->gws_obj;
        oa = p->bo_list->oa_obj;
 
-       amdgpu_bo_list_for_each_entry(e, p->bo_list)
-               e->bo_va = amdgpu_vm_bo_find(vm, ttm_to_amdgpu_bo(e->tv.bo));
+       amdgpu_bo_list_for_each_entry(e, p->bo_list) {
+               struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
+
+               /* Make sure we use the exclusive slot for shared BOs */
+               if (bo->prime_shared_count)
+                       e->tv.num_shared = 0;
+               e->bo_va = amdgpu_vm_bo_find(vm, bo);
+       }
 
        if (gds) {
                p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT;
@@ -955,10 +966,6 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
        if (r)
                return r;
 
-       r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv);
-       if (r)
-               return r;
-
        p->job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.base.bo);
 
        if (amdgpu_vm_debug) {
@@ -1104,7 +1111,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
 {
        int r;
        struct dma_fence *fence;
-       r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
+       r = drm_syncobj_find_fence(p->filp, handle, 0, 0, &fence);
        if (r)
                return r;
 
@@ -1193,7 +1200,7 @@ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p)
        int i;
 
        for (i = 0; i < p->num_post_dep_syncobjs; ++i)
-               drm_syncobj_replace_fence(p->post_dep_syncobjs[i], 0, p->fence);
+               drm_syncobj_replace_fence(p->post_dep_syncobjs[i], p->fence);
 }
 
 static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
@@ -1260,8 +1267,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
        return 0;
 
 error_abort:
-       dma_fence_put(&job->base.s_fence->finished);
-       job->base.s_fence = NULL;
+       drm_sched_job_cleanup(&job->base);
        amdgpu_mn_unlock(p->mn);
 
 error_unlock:
@@ -1285,7 +1291,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 
        r = amdgpu_cs_parser_init(&parser, data);
        if (r) {
-               DRM_ERROR("Failed to initialize parser !\n");
+               DRM_ERROR("Failed to initialize parser %d!\n", r);
                goto out;
        }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
new file mode 100644 (file)
index 0000000..7e22be7
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+
+ * * Author: Monk.liu@amd.com
+ */
+
+#include "amdgpu.h"
+
+uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev)
+{
+       uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT;
+
+       addr -= AMDGPU_VA_RESERVED_SIZE;
+       addr = amdgpu_gmc_sign_extend(addr);
+
+       return addr;
+}
+
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev, struct amdgpu_bo **bo,
+                               u32 domain, uint32_t size)
+{
+       int r;
+       void *ptr;
+
+       r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
+                               domain, bo,
+                               NULL, &ptr);
+       if (!*bo)
+               return -ENOMEM;
+
+       memset(ptr, 0, size);
+       return 0;
+}
+
+void amdgpu_free_static_csa(struct amdgpu_bo **bo)
+{
+       amdgpu_bo_free_kernel(bo, NULL, NULL);
+}
+
+/*
+ * amdgpu_map_static_csa should be called during amdgpu_vm_init
+ * it maps virtual address amdgpu_csa_vaddr() to this VM, and each command
+ * submission of GFX should use this virtual address within META_DATA init
+ * package to support SRIOV gfx preemption.
+ */
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+                         struct amdgpu_bo *bo, struct amdgpu_bo_va **bo_va,
+                         uint64_t csa_addr, uint32_t size)
+{
+       struct ww_acquire_ctx ticket;
+       struct list_head list;
+       struct amdgpu_bo_list_entry pd;
+       struct ttm_validate_buffer csa_tv;
+       int r;
+
+       INIT_LIST_HEAD(&list);
+       INIT_LIST_HEAD(&csa_tv.head);
+       csa_tv.bo = &bo->tbo;
+       csa_tv.num_shared = 1;
+
+       list_add(&csa_tv.head, &list);
+       amdgpu_vm_get_pd_bo(vm, &list, &pd);
+
+       r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
+       if (r) {
+               DRM_ERROR("failed to reserve CSA,PD BOs: err=%d\n", r);
+               return r;
+       }
+
+       *bo_va = amdgpu_vm_bo_add(adev, vm, bo);
+       if (!*bo_va) {
+               ttm_eu_backoff_reservation(&ticket, &list);
+               DRM_ERROR("failed to create bo_va for static CSA\n");
+               return -ENOMEM;
+       }
+
+       r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, csa_addr,
+                               size);
+       if (r) {
+               DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r);
+               amdgpu_vm_bo_rmv(adev, *bo_va);
+               ttm_eu_backoff_reservation(&ticket, &list);
+               return r;
+       }
+
+       r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, size,
+                            AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
+                            AMDGPU_PTE_EXECUTABLE);
+
+       if (r) {
+               DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
+               amdgpu_vm_bo_rmv(adev, *bo_va);
+               ttm_eu_backoff_reservation(&ticket, &list);
+               return r;
+       }
+
+       ttm_eu_backoff_reservation(&ticket, &list);
+       return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h
new file mode 100644 (file)
index 0000000..524b443
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Monk.liu@amd.com
+ */
+
+#ifndef AMDGPU_CSA_MANAGER_H
+#define AMDGPU_CSA_MANAGER_H
+
+#define AMDGPU_CSA_SIZE                (128 * 1024)
+
+uint32_t amdgpu_get_total_csa_size(struct amdgpu_device *adev);
+uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev);
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev, struct amdgpu_bo **bo,
+                               u32 domain, uint32_t size);
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+                         struct amdgpu_bo *bo, struct amdgpu_bo_va **bo_va,
+                         uint64_t csa_addr, uint32_t size);
+void amdgpu_free_static_csa(struct amdgpu_bo **bo);
+
+#endif
index 95f4c4139fc60a078d651b8164d11b0befcf766b..d85184b5b35cf8851a1459f0879433da0a40c274 100644 (file)
@@ -248,7 +248,7 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
                return -ENOMEM;
 
        mutex_lock(&mgr->lock);
-       r = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
+       r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL);
        if (r < 0) {
                mutex_unlock(&mgr->lock);
                kfree(ctx);
index 30bc345d6fdf0d5827c2aa737d284da92787ea70..b60afeade50a3f86db57c26f993f2aacedd1c71e 100644 (file)
@@ -59,6 +59,8 @@
 #include "amdgpu_amdkfd.h"
 #include "amdgpu_pm.h"
 
+#include "amdgpu_xgmi.h"
+
 MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
@@ -513,6 +515,7 @@ void amdgpu_device_pci_config_reset(struct amdgpu_device *adev)
  */
 static int amdgpu_device_doorbell_init(struct amdgpu_device *adev)
 {
+
        /* No doorbell on SI hardware generation */
        if (adev->asic_type < CHIP_BONAIRE) {
                adev->doorbell.base = 0;
@@ -525,15 +528,26 @@ static int amdgpu_device_doorbell_init(struct amdgpu_device *adev)
        if (pci_resource_flags(adev->pdev, 2) & IORESOURCE_UNSET)
                return -EINVAL;
 
+       amdgpu_asic_init_doorbell_index(adev);
+
        /* doorbell bar mapping */
        adev->doorbell.base = pci_resource_start(adev->pdev, 2);
        adev->doorbell.size = pci_resource_len(adev->pdev, 2);
 
        adev->doorbell.num_doorbells = min_t(u32, adev->doorbell.size / sizeof(u32),
-                                            AMDGPU_DOORBELL_MAX_ASSIGNMENT+1);
+                                            adev->doorbell_index.max_assignment+1);
        if (adev->doorbell.num_doorbells == 0)
                return -EINVAL;
 
+       /* For Vega, reserve and map two pages on doorbell BAR since SDMA
+        * paging queue doorbell use the second page. The
+        * AMDGPU_DOORBELL64_MAX_ASSIGNMENT definition assumes all the
+        * doorbells are in the first page. So with paging queue enabled,
+        * the max num_doorbells should + 1 page (0x400 in dword)
+        */
+       if (adev->asic_type >= CHIP_VEGA10)
+               adev->doorbell.num_doorbells += 0x400;
+
        adev->doorbell.ptr = ioremap(adev->doorbell.base,
                                     adev->doorbell.num_doorbells *
                                     sizeof(u32));
@@ -1656,7 +1670,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
 
                        /* right after GMC hw init, we create CSA */
                        if (amdgpu_sriov_vf(adev)) {
-                               r = amdgpu_allocate_static_csa(adev);
+                               r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
+                                                               AMDGPU_GEM_DOMAIN_VRAM,
+                                                               AMDGPU_CSA_SIZE);
                                if (r) {
                                        DRM_ERROR("allocate CSA failed %d\n", r);
                                        return r;
@@ -1681,7 +1697,8 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
        if (r)
                return r;
 
-       amdgpu_xgmi_add_device(adev);
+       if (adev->gmc.xgmi.num_physical_nodes > 1)
+               amdgpu_xgmi_add_device(adev);
        amdgpu_amdkfd_device_init(adev);
 
        if (amdgpu_sriov_vf(adev))
@@ -1848,6 +1865,9 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
 {
        int i, r;
 
+       if (adev->gmc.xgmi.num_physical_nodes > 1)
+               amdgpu_xgmi_remove_device(adev);
+
        amdgpu_amdkfd_device_fini(adev);
 
        amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
@@ -1890,7 +1910,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
 
                if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
                        amdgpu_ucode_free_bo(adev);
-                       amdgpu_free_static_csa(adev);
+                       amdgpu_free_static_csa(&adev->virt.csa_obj);
                        amdgpu_device_wb_fini(adev);
                        amdgpu_device_vram_scratch_fini(adev);
                }
@@ -2337,6 +2357,19 @@ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
        return amdgpu_device_asic_has_dc_support(adev->asic_type);
 }
 
+
+static void amdgpu_device_xgmi_reset_func(struct work_struct *__work)
+{
+       struct amdgpu_device *adev =
+               container_of(__work, struct amdgpu_device, xgmi_reset_work);
+
+       adev->asic_reset_res =  amdgpu_asic_reset(adev);
+       if (adev->asic_reset_res)
+               DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s",
+                        adev->asic_reset_res, adev->ddev->unique);
+}
+
+
 /**
  * amdgpu_device_init - initialize the driver
  *
@@ -2435,6 +2468,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        INIT_DELAYED_WORK(&adev->gfx.gfx_off_delay_work,
                          amdgpu_device_delay_enable_gfx_off);
 
+       INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
+
        adev->gfx.gfx_off_req_count = 1;
        adev->pm.ac_power = power_supply_is_system_supplied() > 0 ? true : false;
 
@@ -2455,9 +2490,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base);
        DRM_INFO("register mmio size: %u\n", (unsigned)adev->rmmio_size);
 
-       /* doorbell bar mapping */
-       amdgpu_device_doorbell_init(adev);
-
        /* io port mapping */
        for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
                if (pci_resource_flags(adev->pdev, i) & IORESOURCE_IO) {
@@ -2476,6 +2508,9 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        if (r)
                return r;
 
+       /* doorbell bar mapping and doorbell index init*/
+       amdgpu_device_doorbell_init(adev);
+
        /* if we have > 1 VGA cards, then disable the amdgpu VGA resources */
        /* this will fail for cards that aren't VGA class devices, just
         * ignore it */
@@ -3148,86 +3183,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev)
        return 0;
 }
 
-/**
- * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough
- *
- * @adev: amdgpu device pointer
- *
- * attempt to do soft-reset or full-reset and reinitialize Asic
- * return 0 means succeeded otherwise failed
- */
-static int amdgpu_device_reset(struct amdgpu_device *adev)
-{
-       bool need_full_reset, vram_lost = 0;
-       int r;
-
-       need_full_reset = amdgpu_device_ip_need_full_reset(adev);
-
-       if (!need_full_reset) {
-               amdgpu_device_ip_pre_soft_reset(adev);
-               r = amdgpu_device_ip_soft_reset(adev);
-               amdgpu_device_ip_post_soft_reset(adev);
-               if (r || amdgpu_device_ip_check_soft_reset(adev)) {
-                       DRM_INFO("soft reset failed, will fallback to full reset!\n");
-                       need_full_reset = true;
-               }
-       }
-
-       if (need_full_reset) {
-               r = amdgpu_device_ip_suspend(adev);
-
-retry:
-               r = amdgpu_asic_reset(adev);
-               /* post card */
-               amdgpu_atom_asic_init(adev->mode_info.atom_context);
-
-               if (!r) {
-                       dev_info(adev->dev, "GPU reset succeeded, trying to resume\n");
-                       r = amdgpu_device_ip_resume_phase1(adev);
-                       if (r)
-                               goto out;
-
-                       vram_lost = amdgpu_device_check_vram_lost(adev);
-                       if (vram_lost) {
-                               DRM_ERROR("VRAM is lost!\n");
-                               atomic_inc(&adev->vram_lost_counter);
-                       }
-
-                       r = amdgpu_gtt_mgr_recover(
-                               &adev->mman.bdev.man[TTM_PL_TT]);
-                       if (r)
-                               goto out;
-
-                       r = amdgpu_device_fw_loading(adev);
-                       if (r)
-                               return r;
-
-                       r = amdgpu_device_ip_resume_phase2(adev);
-                       if (r)
-                               goto out;
-
-                       if (vram_lost)
-                               amdgpu_device_fill_reset_magic(adev);
-               }
-       }
-
-out:
-       if (!r) {
-               amdgpu_irq_gpu_reset_resume_helper(adev);
-               r = amdgpu_ib_ring_tests(adev);
-               if (r) {
-                       dev_err(adev->dev, "ib ring test failed (%d).\n", r);
-                       r = amdgpu_device_ip_suspend(adev);
-                       need_full_reset = true;
-                       goto retry;
-               }
-       }
-
-       if (!r)
-               r = amdgpu_device_recover_vram(adev);
-
-       return r;
-}
 
 /**
  * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf
@@ -3295,40 +3250,46 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
                return false;
        }
 
-       if (amdgpu_gpu_recovery == 0 || (amdgpu_gpu_recovery == -1  &&
-                                        !amdgpu_sriov_vf(adev))) {
-               DRM_INFO("GPU recovery disabled.\n");
-               return false;
-       }
+       if (amdgpu_gpu_recovery == 0)
+               goto disabled;
 
-       return true;
-}
+       if (amdgpu_sriov_vf(adev))
+               return true;
 
-/**
- * amdgpu_device_gpu_recover - reset the asic and recover scheduler
- *
- * @adev: amdgpu device pointer
- * @job: which job trigger hang
- *
- * Attempt to reset the GPU if it has hung (all asics).
- * Returns 0 for success or an error on failure.
- */
-int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
-                             struct amdgpu_job *job)
-{
-       int i, r, resched;
+       if (amdgpu_gpu_recovery == -1) {
+               switch (adev->asic_type) {
+               case CHIP_BONAIRE:
+               case CHIP_HAWAII:
+               case CHIP_TOPAZ:
+               case CHIP_TONGA:
+               case CHIP_FIJI:
+               case CHIP_POLARIS10:
+               case CHIP_POLARIS11:
+               case CHIP_POLARIS12:
+               case CHIP_VEGAM:
+               case CHIP_VEGA20:
+               case CHIP_VEGA10:
+               case CHIP_VEGA12:
+                       break;
+               default:
+                       goto disabled;
+               }
+       }
 
-       dev_info(adev->dev, "GPU reset begin!\n");
+       return true;
 
-       mutex_lock(&adev->lock_reset);
-       atomic_inc(&adev->gpu_reset_counter);
-       adev->in_gpu_reset = 1;
+disabled:
+               DRM_INFO("GPU recovery disabled.\n");
+               return false;
+}
 
-       /* Block kfd */
-       amdgpu_amdkfd_pre_reset(adev);
 
-       /* block TTM */
-       resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
+static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
+                                       struct amdgpu_job *job,
+                                       bool *need_full_reset_arg)
+{
+       int i, r = 0;
+       bool need_full_reset  = *need_full_reset_arg;
 
        /* block all schedulers and reset given job's ring */
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
@@ -3348,10 +3309,144 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
                amdgpu_fence_driver_force_completion(ring);
        }
 
-       if (amdgpu_sriov_vf(adev))
-               r = amdgpu_device_reset_sriov(adev, job ? false : true);
-       else
-               r = amdgpu_device_reset(adev);
+
+
+       if (!amdgpu_sriov_vf(adev)) {
+
+               if (!need_full_reset)
+                       need_full_reset = amdgpu_device_ip_need_full_reset(adev);
+
+               if (!need_full_reset) {
+                       amdgpu_device_ip_pre_soft_reset(adev);
+                       r = amdgpu_device_ip_soft_reset(adev);
+                       amdgpu_device_ip_post_soft_reset(adev);
+                       if (r || amdgpu_device_ip_check_soft_reset(adev)) {
+                               DRM_INFO("soft reset failed, will fallback to full reset!\n");
+                               need_full_reset = true;
+                       }
+               }
+
+               if (need_full_reset)
+                       r = amdgpu_device_ip_suspend(adev);
+
+               *need_full_reset_arg = need_full_reset;
+       }
+
+       return r;
+}
+
+static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
+                              struct list_head *device_list_handle,
+                              bool *need_full_reset_arg)
+{
+       struct amdgpu_device *tmp_adev = NULL;
+       bool need_full_reset = *need_full_reset_arg, vram_lost = false;
+       int r = 0;
+
+       /*
+        * ASIC reset has to be done on all HGMI hive nodes ASAP
+        * to allow proper links negotiation in FW (within 1 sec)
+        */
+       if (need_full_reset) {
+               list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
+                       /* For XGMI run all resets in parallel to speed up the process */
+                       if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
+                               if (!queue_work(system_highpri_wq, &tmp_adev->xgmi_reset_work))
+                                       r = -EALREADY;
+                       } else
+                               r = amdgpu_asic_reset(tmp_adev);
+
+                       if (r) {
+                               DRM_ERROR("ASIC reset failed with err r, %d for drm dev, %s",
+                                        r, tmp_adev->ddev->unique);
+                               break;
+                       }
+               }
+
+               /* For XGMI wait for all PSP resets to complete before proceed */
+               if (!r) {
+                       list_for_each_entry(tmp_adev, device_list_handle,
+                                           gmc.xgmi.head) {
+                               if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
+                                       flush_work(&tmp_adev->xgmi_reset_work);
+                                       r = tmp_adev->asic_reset_res;
+                                       if (r)
+                                               break;
+                               }
+                       }
+               }
+       }
+
+
+       list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
+               if (need_full_reset) {
+                       /* post card */
+                       if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context))
+                               DRM_WARN("asic atom init failed!");
+
+                       if (!r) {
+                               dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n");
+                               r = amdgpu_device_ip_resume_phase1(tmp_adev);
+                               if (r)
+                                       goto out;
+
+                               vram_lost = amdgpu_device_check_vram_lost(tmp_adev);
+                               if (vram_lost) {
+                                       DRM_ERROR("VRAM is lost!\n");
+                                       atomic_inc(&tmp_adev->vram_lost_counter);
+                               }
+
+                               r = amdgpu_gtt_mgr_recover(
+                                       &tmp_adev->mman.bdev.man[TTM_PL_TT]);
+                               if (r)
+                                       goto out;
+
+                               r = amdgpu_device_fw_loading(tmp_adev);
+                               if (r)
+                                       return r;
+
+                               r = amdgpu_device_ip_resume_phase2(tmp_adev);
+                               if (r)
+                                       goto out;
+
+                               if (vram_lost)
+                                       amdgpu_device_fill_reset_magic(tmp_adev);
+
+                               /* Update PSP FW topology after reset */
+                               if (hive && tmp_adev->gmc.xgmi.num_physical_nodes > 1)
+                                       r = amdgpu_xgmi_update_topology(hive, tmp_adev);
+                       }
+               }
+
+
+out:
+               if (!r) {
+                       amdgpu_irq_gpu_reset_resume_helper(tmp_adev);
+                       r = amdgpu_ib_ring_tests(tmp_adev);
+                       if (r) {
+                               dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r);
+                               r = amdgpu_device_ip_suspend(tmp_adev);
+                               need_full_reset = true;
+                               r = -EAGAIN;
+                               goto end;
+                       }
+               }
+
+               if (!r)
+                       r = amdgpu_device_recover_vram(tmp_adev);
+               else
+                       tmp_adev->asic_reset_res = r;
+       }
+
+end:
+       *need_full_reset_arg = need_full_reset;
+       return r;
+}
+
+static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev,
+                                         struct amdgpu_job *job)
+{
+       int i;
 
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
@@ -3363,7 +3458,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
                 * or all rings (in the case @job is NULL)
                 * after above amdgpu_reset accomplished
                 */
-               if ((!job || job->base.sched == &ring->sched) && !r)
+               if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res)
                        drm_sched_job_recovery(&ring->sched);
 
                kthread_unpark(ring->sched.thread);
@@ -3373,21 +3468,142 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
                drm_helper_resume_force_mode(adev->ddev);
        }
 
-       ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
+       adev->asic_reset_res = 0;
+}
 
-       if (r) {
-               /* bad news, how to tell it to userspace ? */
-               dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter));
-               amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r);
-       } else {
-               dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter));
-       }
+static void amdgpu_device_lock_adev(struct amdgpu_device *adev)
+{
+       mutex_lock(&adev->lock_reset);
+       atomic_inc(&adev->gpu_reset_counter);
+       adev->in_gpu_reset = 1;
+       /* Block kfd */
+       amdgpu_amdkfd_pre_reset(adev);
+}
 
+static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
+{
        /*unlock kfd */
        amdgpu_amdkfd_post_reset(adev);
        amdgpu_vf_error_trans_all(adev);
        adev->in_gpu_reset = 0;
        mutex_unlock(&adev->lock_reset);
+}
+
+
+/**
+ * amdgpu_device_gpu_recover - reset the asic and recover scheduler
+ *
+ * @adev: amdgpu device pointer
+ * @job: which job trigger hang
+ *
+ * Attempt to reset the GPU if it has hung (all asics).
+ * Attempt to do soft-reset or full-reset and reinitialize Asic
+ * Returns 0 for success or an error on failure.
+ */
+
+int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
+                             struct amdgpu_job *job)
+{
+       int r;
+       struct amdgpu_hive_info *hive = NULL;
+       bool need_full_reset = false;
+       struct amdgpu_device *tmp_adev = NULL;
+       struct list_head device_list, *device_list_handle =  NULL;
+
+       INIT_LIST_HEAD(&device_list);
+
+       dev_info(adev->dev, "GPU reset begin!\n");
+
+       /*
+        * In case of XGMI hive disallow concurrent resets to be triggered
+        * by different nodes. No point also since the one node already executing
+        * reset will also reset all the other nodes in the hive.
+        */
+       hive = amdgpu_get_xgmi_hive(adev);
+       if (hive && adev->gmc.xgmi.num_physical_nodes > 1 &&
+           !mutex_trylock(&hive->hive_lock))
+               return 0;
+
+       /* Start with adev pre asic reset first for soft reset check.*/
+       amdgpu_device_lock_adev(adev);
+       r = amdgpu_device_pre_asic_reset(adev,
+                                        job,
+                                        &need_full_reset);
+       if (r) {
+               /*TODO Should we stop ?*/
+               DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",
+                         r, adev->ddev->unique);
+               adev->asic_reset_res = r;
+       }
+
+       /* Build list of devices to reset */
+       if  (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) {
+               if (!hive) {
+                       amdgpu_device_unlock_adev(adev);
+                       return -ENODEV;
+               }
+
+               /*
+                * In case we are in XGMI hive mode device reset is done for all the
+                * nodes in the hive to retrain all XGMI links and hence the reset
+                * sequence is executed in loop on all nodes.
+                */
+               device_list_handle = &hive->device_list;
+       } else {
+               list_add_tail(&adev->gmc.xgmi.head, &device_list);
+               device_list_handle = &device_list;
+       }
+
+retry: /* Rest of adevs pre asic reset from XGMI hive. */
+       list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
+
+               if (tmp_adev == adev)
+                       continue;
+
+               amdgpu_device_lock_adev(tmp_adev);
+               r = amdgpu_device_pre_asic_reset(tmp_adev,
+                                                NULL,
+                                                &need_full_reset);
+               /*TODO Should we stop ?*/
+               if (r) {
+                       DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",
+                                 r, tmp_adev->ddev->unique);
+                       tmp_adev->asic_reset_res = r;
+               }
+       }
+
+       /* Actual ASIC resets if needed.*/
+       /* TODO Implement XGMI hive reset logic for SRIOV */
+       if (amdgpu_sriov_vf(adev)) {
+               r = amdgpu_device_reset_sriov(adev, job ? false : true);
+               if (r)
+                       adev->asic_reset_res = r;
+       } else {
+               r  = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset);
+               if (r && r == -EAGAIN)
+                       goto retry;
+       }
+
+       /* Post ASIC reset for all devs .*/
+       list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
+               amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL);
+
+               if (r) {
+                       /* bad news, how to tell it to userspace ? */
+                       dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter));
+                       amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r);
+               } else {
+                       dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter));
+               }
+
+               amdgpu_device_unlock_adev(tmp_adev);
+       }
+
+       if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
+               mutex_unlock(&hive->hive_lock);
+
+       if (r)
+               dev_info(adev->dev, "GPU reset end with ret = %d\n", r);
        return r;
 }
 
index 686a26de50f91e816471548bf3c1a0fc3f86db86..15ce7e681d67c1776be90449a6d61bc0dfd02aa5 100644 (file)
@@ -631,6 +631,11 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
                        drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16);
                if (!adev->mode_info.max_bpc_property)
                        return -ENOMEM;
+               adev->mode_info.abm_level_property =
+                       drm_property_create_range(adev->ddev, 0,
+                                               "abm level", 0, 4);
+               if (!adev->mode_info.abm_level_property)
+                       return -ENOMEM;
        }
 
        return 0;
@@ -857,7 +862,12 @@ int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev,
        /* Inside "upper part" of vblank area? Apply corrective offset if so: */
        if (in_vbl && (*vpos >= vbl_start)) {
                vtotal = mode->crtc_vtotal;
-               *vpos = *vpos - vtotal;
+
+               /* With variable refresh rate displays the vpos can exceed
+                * the vtotal value. Clamp to 0 to return -vbl_end instead
+                * of guessing the remaining number of lines until scanout.
+                */
+               *vpos = (*vpos < vtotal) ? (*vpos - vtotal) : 0;
        }
 
        /* Correct for shifted end of vbl at vbl_end. */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h
new file mode 100644 (file)
index 0000000..be620b2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct amdgpu_doorbell {
+       /* doorbell mmio */
+       resource_size_t         base;
+       resource_size_t         size;
+       u32 __iomem             *ptr;
+       u32                     num_doorbells;  /* Number of doorbells actually reserved for amdgpu. */
+};
+
+/* Reserved doorbells for amdgpu (including multimedia).
+ * KFD can use all the rest in the 2M doorbell bar.
+ * For asic before vega10, doorbell is 32-bit, so the
+ * index/offset is in dword. For vega10 and after, doorbell
+ * can be 64-bit, so the index defined is in qword.
+ */
+struct amdgpu_doorbell_index {
+       uint32_t kiq;
+       uint32_t mec_ring0;
+       uint32_t mec_ring1;
+       uint32_t mec_ring2;
+       uint32_t mec_ring3;
+       uint32_t mec_ring4;
+       uint32_t mec_ring5;
+       uint32_t mec_ring6;
+       uint32_t mec_ring7;
+       uint32_t userqueue_start;
+       uint32_t userqueue_end;
+       uint32_t gfx_ring0;
+       uint32_t sdma_engine0;
+       uint32_t sdma_engine1;
+       uint32_t sdma_engine2;
+       uint32_t sdma_engine3;
+       uint32_t sdma_engine4;
+       uint32_t sdma_engine5;
+       uint32_t sdma_engine6;
+       uint32_t sdma_engine7;
+       uint32_t ih;
+       union {
+               struct {
+                       uint32_t vcn_ring0_1;
+                       uint32_t vcn_ring2_3;
+                       uint32_t vcn_ring4_5;
+                       uint32_t vcn_ring6_7;
+               } vcn;
+               struct {
+                       uint32_t uvd_ring0_1;
+                       uint32_t uvd_ring2_3;
+                       uint32_t uvd_ring4_5;
+                       uint32_t uvd_ring6_7;
+                       uint32_t vce_ring0_1;
+                       uint32_t vce_ring2_3;
+                       uint32_t vce_ring4_5;
+                       uint32_t vce_ring6_7;
+               } uvd_vce;
+       };
+       uint32_t max_assignment;
+};
+
+typedef enum _AMDGPU_DOORBELL_ASSIGNMENT
+{
+       AMDGPU_DOORBELL_KIQ                     = 0x000,
+       AMDGPU_DOORBELL_HIQ                     = 0x001,
+       AMDGPU_DOORBELL_DIQ                     = 0x002,
+       AMDGPU_DOORBELL_MEC_RING0               = 0x010,
+       AMDGPU_DOORBELL_MEC_RING1               = 0x011,
+       AMDGPU_DOORBELL_MEC_RING2               = 0x012,
+       AMDGPU_DOORBELL_MEC_RING3               = 0x013,
+       AMDGPU_DOORBELL_MEC_RING4               = 0x014,
+       AMDGPU_DOORBELL_MEC_RING5               = 0x015,
+       AMDGPU_DOORBELL_MEC_RING6               = 0x016,
+       AMDGPU_DOORBELL_MEC_RING7               = 0x017,
+       AMDGPU_DOORBELL_GFX_RING0               = 0x020,
+       AMDGPU_DOORBELL_sDMA_ENGINE0            = 0x1E0,
+       AMDGPU_DOORBELL_sDMA_ENGINE1            = 0x1E1,
+       AMDGPU_DOORBELL_IH                      = 0x1E8,
+       AMDGPU_DOORBELL_MAX_ASSIGNMENT          = 0x3FF,
+       AMDGPU_DOORBELL_INVALID                 = 0xFFFF
+} AMDGPU_DOORBELL_ASSIGNMENT;
+
+typedef enum _AMDGPU_VEGA20_DOORBELL_ASSIGNMENT
+{
+       /* Compute + GFX: 0~255 */
+       AMDGPU_VEGA20_DOORBELL_KIQ                     = 0x000,
+       AMDGPU_VEGA20_DOORBELL_HIQ                     = 0x001,
+       AMDGPU_VEGA20_DOORBELL_DIQ                     = 0x002,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING0               = 0x003,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING1               = 0x004,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING2               = 0x005,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING3               = 0x006,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING4               = 0x007,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING5               = 0x008,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING6               = 0x009,
+       AMDGPU_VEGA20_DOORBELL_MEC_RING7               = 0x00A,
+       AMDGPU_VEGA20_DOORBELL_USERQUEUE_START         = 0x00B,
+       AMDGPU_VEGA20_DOORBELL_USERQUEUE_END           = 0x08A,
+       AMDGPU_VEGA20_DOORBELL_GFX_RING0               = 0x08B,
+       /* SDMA:256~335*/
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE0            = 0x100,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE1            = 0x10A,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE2            = 0x114,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE3            = 0x11E,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE4            = 0x128,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE5            = 0x132,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE6            = 0x13C,
+       AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE7            = 0x146,
+       /* IH: 376~391 */
+       AMDGPU_VEGA20_DOORBELL_IH                      = 0x178,
+       /* MMSCH: 392~407
+        * overlap the doorbell assignment with VCN as they are  mutually exclusive
+        * VCE engine's doorbell is 32 bit and two VCE ring share one QWORD
+        */
+       AMDGPU_VEGA20_DOORBELL64_VCN0_1                  = 0x188, /* lower 32 bits for VNC0 and upper 32 bits for VNC1 */
+       AMDGPU_VEGA20_DOORBELL64_VCN2_3                  = 0x189,
+       AMDGPU_VEGA20_DOORBELL64_VCN4_5                  = 0x18A,
+       AMDGPU_VEGA20_DOORBELL64_VCN6_7                  = 0x18B,
+
+       AMDGPU_VEGA20_DOORBELL64_UVD_RING0_1             = 0x188,
+       AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3             = 0x189,
+       AMDGPU_VEGA20_DOORBELL64_UVD_RING4_5             = 0x18A,
+       AMDGPU_VEGA20_DOORBELL64_UVD_RING6_7             = 0x18B,
+
+       AMDGPU_VEGA20_DOORBELL64_VCE_RING0_1             = 0x18C,
+       AMDGPU_VEGA20_DOORBELL64_VCE_RING2_3             = 0x18D,
+       AMDGPU_VEGA20_DOORBELL64_VCE_RING4_5             = 0x18E,
+       AMDGPU_VEGA20_DOORBELL64_VCE_RING6_7             = 0x18F,
+       AMDGPU_VEGA20_DOORBELL_MAX_ASSIGNMENT            = 0x18F,
+       AMDGPU_VEGA20_DOORBELL_INVALID                   = 0xFFFF
+} AMDGPU_VEGA20_DOORBELL_ASSIGNMENT;
+
+/*
+ * 64bit doorbell, offset are in QWORD, occupy 2KB doorbell space
+ */
+typedef enum _AMDGPU_DOORBELL64_ASSIGNMENT
+{
+       /*
+        * All compute related doorbells: kiq, hiq, diq, traditional compute queue, user queue, should locate in
+        * a continues range so that programming CP_MEC_DOORBELL_RANGE_LOWER/UPPER can cover this range.
+        *  Compute related doorbells are allocated from 0x00 to 0x8a
+        */
+
+
+       /* kernel scheduling */
+       AMDGPU_DOORBELL64_KIQ                     = 0x00,
+
+       /* HSA interface queue and debug queue */
+       AMDGPU_DOORBELL64_HIQ                     = 0x01,
+       AMDGPU_DOORBELL64_DIQ                     = 0x02,
+
+       /* Compute engines */
+       AMDGPU_DOORBELL64_MEC_RING0               = 0x03,
+       AMDGPU_DOORBELL64_MEC_RING1               = 0x04,
+       AMDGPU_DOORBELL64_MEC_RING2               = 0x05,
+       AMDGPU_DOORBELL64_MEC_RING3               = 0x06,
+       AMDGPU_DOORBELL64_MEC_RING4               = 0x07,
+       AMDGPU_DOORBELL64_MEC_RING5               = 0x08,
+       AMDGPU_DOORBELL64_MEC_RING6               = 0x09,
+       AMDGPU_DOORBELL64_MEC_RING7               = 0x0a,
+
+       /* User queue doorbell range (128 doorbells) */
+       AMDGPU_DOORBELL64_USERQUEUE_START         = 0x0b,
+       AMDGPU_DOORBELL64_USERQUEUE_END           = 0x8a,
+
+       /* Graphics engine */
+       AMDGPU_DOORBELL64_GFX_RING0               = 0x8b,
+
+       /*
+        * Other graphics doorbells can be allocated here: from 0x8c to 0xdf
+        * Graphics voltage island aperture 1
+        * default non-graphics QWORD index is 0xe0 - 0xFF inclusive
+        */
+
+       /* For vega10 sriov, the sdma doorbell must be fixed as follow
+        * to keep the same setting with host driver, or it will
+        * happen conflicts
+        */
+       AMDGPU_DOORBELL64_sDMA_ENGINE0            = 0xF0,
+       AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE0     = 0xF1,
+       AMDGPU_DOORBELL64_sDMA_ENGINE1            = 0xF2,
+       AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE1     = 0xF3,
+
+       /* Interrupt handler */
+       AMDGPU_DOORBELL64_IH                      = 0xF4,  /* For legacy interrupt ring buffer */
+       AMDGPU_DOORBELL64_IH_RING1                = 0xF5,  /* For page migration request log */
+       AMDGPU_DOORBELL64_IH_RING2                = 0xF6,  /* For page migration translation/invalidation log */
+
+       /* VCN engine use 32 bits doorbell  */
+       AMDGPU_DOORBELL64_VCN0_1                  = 0xF8, /* lower 32 bits for VNC0 and upper 32 bits for VNC1 */
+       AMDGPU_DOORBELL64_VCN2_3                  = 0xF9,
+       AMDGPU_DOORBELL64_VCN4_5                  = 0xFA,
+       AMDGPU_DOORBELL64_VCN6_7                  = 0xFB,
+
+       /* overlap the doorbell assignment with VCN as they are  mutually exclusive
+        * VCE engine's doorbell is 32 bit and two VCE ring share one QWORD
+        */
+       AMDGPU_DOORBELL64_UVD_RING0_1             = 0xF8,
+       AMDGPU_DOORBELL64_UVD_RING2_3             = 0xF9,
+       AMDGPU_DOORBELL64_UVD_RING4_5             = 0xFA,
+       AMDGPU_DOORBELL64_UVD_RING6_7             = 0xFB,
+
+       AMDGPU_DOORBELL64_VCE_RING0_1             = 0xFC,
+       AMDGPU_DOORBELL64_VCE_RING2_3             = 0xFD,
+       AMDGPU_DOORBELL64_VCE_RING4_5             = 0xFE,
+       AMDGPU_DOORBELL64_VCE_RING6_7             = 0xFF,
+
+       AMDGPU_DOORBELL64_MAX_ASSIGNMENT          = 0xFF,
+       AMDGPU_DOORBELL64_INVALID                 = 0xFFFF
+} AMDGPU_DOORBELL64_ASSIGNMENT;
+
+u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index);
+void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
+u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index);
+void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v);
+
+#define RDOORBELL32(index) amdgpu_mm_rdoorbell(adev, (index))
+#define WDOORBELL32(index, v) amdgpu_mm_wdoorbell(adev, (index), (v))
+#define RDOORBELL64(index) amdgpu_mm_rdoorbell64(adev, (index))
+#define WDOORBELL64(index, v) amdgpu_mm_wdoorbell64(adev, (index), (v))
+
index 74b611e8a1b10c88abfaa0eb66950a073a09bd7b..9c77eaa45982b663288d18e9627689f5aacab4a3 100644 (file)
@@ -454,9 +454,10 @@ module_param_named(cntl_sb_buf_per_se, amdgpu_cntl_sb_buf_per_se, int, 0444);
 
 /**
  * DOC: param_buf_per_se (int)
- * Override the size of Off-Chip Pramater Cache per Shader Engine in Byte. The default is 0 (depending on gfx).
+ * Override the size of Off-Chip Parameter Cache per Shader Engine in Byte.
+ * The default is 0 (depending on gfx).
  */
-MODULE_PARM_DESC(param_buf_per_se, "the size of Off-Chip Pramater Cache per Shader Engine (default depending on gfx)");
+MODULE_PARM_DESC(param_buf_per_se, "the size of Off-Chip Parameter Cache per Shader Engine (default depending on gfx)");
 module_param_named(param_buf_per_se, amdgpu_param_buf_per_se, int, 0444);
 
 /**
@@ -1227,9 +1228,6 @@ static struct drm_driver kms_driver = {
        .patchlevel = KMS_DRIVER_PATCHLEVEL,
 };
 
-static struct drm_driver *driver;
-static struct pci_driver *pdriver;
-
 static struct pci_driver amdgpu_kms_pci_driver = {
        .name = DRIVER_NAME,
        .id_table = pciidlist,
@@ -1259,16 +1257,14 @@ static int __init amdgpu_init(void)
                goto error_fence;
 
        DRM_INFO("amdgpu kernel modesetting enabled.\n");
-       driver = &kms_driver;
-       pdriver = &amdgpu_kms_pci_driver;
-       driver->num_ioctls = amdgpu_max_kms_ioctl;
+       kms_driver.num_ioctls = amdgpu_max_kms_ioctl;
        amdgpu_register_atpx_handler();
 
        /* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */
        amdgpu_amdkfd_init();
 
        /* let modprobe override vga console setting */
-       return pci_register_driver(pdriver);
+       return pci_register_driver(&amdgpu_kms_pci_driver);
 
 error_fence:
        amdgpu_sync_fini();
@@ -1280,7 +1276,7 @@ error_sync:
 static void __exit amdgpu_exit(void)
 {
        amdgpu_amdkfd_fini();
-       pci_unregister_driver(pdriver);
+       pci_unregister_driver(&amdgpu_kms_pci_driver);
        amdgpu_unregister_atpx_handler();
        amdgpu_sync_fini();
        amdgpu_fence_slab_fini();
index 5448cf27654ee61c09632c8f88626b54e4a5fb26..ee47c11e92ce7f021e7ce87d5613c7a9543eb900 100644 (file)
@@ -398,9 +398,9 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
        ring->fence_drv.irq_type = irq_type;
        ring->fence_drv.initialized = true;
 
-       dev_dbg(adev->dev, "fence driver on ring %d use gpu addr 0x%016llx, "
-               "cpu addr 0x%p\n", ring->idx,
-               ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
+       DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr "
+                     "0x%016llx, cpu addr 0x%p\n", ring->name,
+                     ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
        return 0;
 }
 
index 11fea28f8ad30da94a18a28763a498bb5f84868e..6d11e1721147e53f13c096cae6e2f5662b580cc8 100644 (file)
@@ -248,7 +248,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
        }
        mb();
        amdgpu_asic_flush_hdp(adev, NULL);
-       amdgpu_gmc_flush_gpu_tlb(adev, 0);
+       amdgpu_gmc_flush_gpu_tlb(adev, 0, 0);
        return 0;
 }
 
@@ -259,6 +259,8 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
  * @offset: offset into the GPU's gart aperture
  * @pages: number of pages to bind
  * @dma_addr: DMA addresses of pages
+ * @flags: page table entry flags
+ * @dst: CPU address of the gart table
  *
  * Map the dma_addresses into GART entries (all asics).
  * Returns 0 for success, -EINVAL for failure.
@@ -331,7 +333,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
 
        mb();
        amdgpu_asic_flush_hdp(adev, NULL);
-       amdgpu_gmc_flush_gpu_tlb(adev, 0);
+       amdgpu_gmc_flush_gpu_tlb(adev, 0, 0);
        return 0;
 }
 
index 9ff62887e4e32cd0378295720e7517d74b035efd..afa2e2877d87cf7065d7000a4a5ed451ca673e43 100644 (file)
@@ -41,6 +41,7 @@ struct amdgpu_bo;
 
 struct amdgpu_gart {
        struct amdgpu_bo                *bo;
+       /* CPU kmapped address of gart table */
        void                            *ptr;
        unsigned                        num_gpu_pages;
        unsigned                        num_cpu_pages;
index 7b3d1ebda9df6140524be2d01cf6f1fb11563c85..f4f00217546eacc02c1a4f3dbb1be809c4cbe494 100644 (file)
@@ -169,7 +169,7 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
        INIT_LIST_HEAD(&duplicates);
 
        tv.bo = &bo->tbo;
-       tv.shared = true;
+       tv.num_shared = 1;
        list_add(&tv.head, &list);
 
        amdgpu_vm_get_pd_bo(vm, &list, &vm_pd);
@@ -604,7 +604,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
                        return -ENOENT;
                abo = gem_to_amdgpu_bo(gobj);
                tv.bo = &abo->tbo;
-               tv.shared = !!(abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID);
+               if (abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID)
+                       tv.num_shared = 1;
+               else
+                       tv.num_shared = 0;
                list_add(&tv.head, &list);
        } else {
                gobj = NULL;
index d63daba9b17c554912e2a82fd4c1620b5b654455..f1ddfc50bcc763636d6080a527870a10001dd27b 100644 (file)
@@ -54,6 +54,8 @@ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj);
 void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 
+extern const struct dma_buf_ops amdgpu_dmabuf_ops;
+
 /*
  * GEM objects.
  */
index 1a656b8657f736fa0385aba0c54c6548d72af819..97a60da62004a39cc8b78e1229a96f7bf8731ff9 100644 (file)
@@ -25,6 +25,7 @@
 #include <drm/drmP.h>
 #include "amdgpu.h"
 #include "amdgpu_gfx.h"
+#include "amdgpu_rlc.h"
 
 /* delay 0.1 second to enable gfx off feature */
 #define GFX_OFF_DELAY_ENABLE         msecs_to_jiffies(100)
@@ -249,7 +250,7 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev,
        ring->adev = NULL;
        ring->ring_obj = NULL;
        ring->use_doorbell = true;
-       ring->doorbell_index = AMDGPU_DOORBELL_KIQ;
+       ring->doorbell_index = adev->doorbell_index.kiq;
 
        r = amdgpu_gfx_kiq_acquire(adev, ring);
        if (r)
index b61b5c11aeadd3893c5ed8659aec88f1861bbb8c..f790e15bcd087901d784b7963ec20487ae4814fb 100644 (file)
@@ -29,6 +29,7 @@
  */
 #include "clearstate_defs.h"
 #include "amdgpu_ring.h"
+#include "amdgpu_rlc.h"
 
 /* GFX current status */
 #define AMDGPU_GFX_NORMAL_MODE                 0x00000000L
 #define AMDGPU_GFX_CG_DISABLED_MODE            0x00000004L
 #define AMDGPU_GFX_LBPW_DISABLED_MODE          0x00000008L
 
-
-struct amdgpu_rlc_funcs {
-       void (*enter_safe_mode)(struct amdgpu_device *adev);
-       void (*exit_safe_mode)(struct amdgpu_device *adev);
-};
-
-struct amdgpu_rlc {
-       /* for power gating */
-       struct amdgpu_bo        *save_restore_obj;
-       uint64_t                save_restore_gpu_addr;
-       volatile uint32_t       *sr_ptr;
-       const u32               *reg_list;
-       u32                     reg_list_size;
-       /* for clear state */
-       struct amdgpu_bo        *clear_state_obj;
-       uint64_t                clear_state_gpu_addr;
-       volatile uint32_t       *cs_ptr;
-       const struct cs_section_def   *cs_data;
-       u32                     clear_state_size;
-       /* for cp tables */
-       struct amdgpu_bo        *cp_table_obj;
-       uint64_t                cp_table_gpu_addr;
-       volatile uint32_t       *cp_table_ptr;
-       u32                     cp_table_size;
-
-       /* safe mode for updating CG/PG state */
-       bool in_safe_mode;
-       const struct amdgpu_rlc_funcs *funcs;
-
-       /* for firmware data */
-       u32 save_and_restore_offset;
-       u32 clear_state_descriptor_offset;
-       u32 avail_scratch_ram_locations;
-       u32 reg_restore_list_size;
-       u32 reg_list_format_start;
-       u32 reg_list_format_separate_start;
-       u32 starting_offsets_start;
-       u32 reg_list_format_size_bytes;
-       u32 reg_list_size_bytes;
-       u32 reg_list_format_direct_reg_list_length;
-       u32 save_restore_list_cntl_size_bytes;
-       u32 save_restore_list_gpm_size_bytes;
-       u32 save_restore_list_srm_size_bytes;
-
-       u32 *register_list_format;
-       u32 *register_restore;
-       u8 *save_restore_list_cntl;
-       u8 *save_restore_list_gpm;
-       u8 *save_restore_list_srm;
-
-       bool is_rlc_v2_1;
-};
-
 #define AMDGPU_MAX_COMPUTE_QUEUES KGD_MAX_QUEUES
 
 struct amdgpu_mec {
index 6fa7ef446e4631136df9c4b17fe6d510de8561eb..81e6070d255b513301dca839320d1410f2baa2ed 100644 (file)
@@ -64,7 +64,7 @@ struct amdgpu_vmhub {
 struct amdgpu_gmc_funcs {
        /* flush the vm tlb via mmio */
        void (*flush_gpu_tlb)(struct amdgpu_device *adev,
-                             uint32_t vmid);
+                             uint32_t vmid, uint32_t flush_type);
        /* flush the vm tlb via ring */
        uint64_t (*emit_flush_gpu_tlb)(struct amdgpu_ring *ring, unsigned vmid,
                                       uint64_t pd_addr);
@@ -89,7 +89,7 @@ struct amdgpu_gmc_funcs {
 
 struct amdgpu_xgmi {
        /* from psp */
-       u64 device_id;
+       u64 node_id;
        u64 hive_id;
        /* fixed per family */
        u64 node_segment_size;
@@ -99,6 +99,7 @@ struct amdgpu_xgmi {
        unsigned num_physical_nodes;
        /* gpu list in the same hive */
        struct list_head head;
+       bool supported;
 };
 
 struct amdgpu_gmc {
@@ -151,7 +152,7 @@ struct amdgpu_gmc {
        struct amdgpu_xgmi xgmi;
 };
 
-#define amdgpu_gmc_flush_gpu_tlb(adev, vmid) (adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid))
+#define amdgpu_gmc_flush_gpu_tlb(adev, vmid, type) (adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid), (type))
 #define amdgpu_gmc_emit_flush_gpu_tlb(r, vmid, addr) (r)->adev->gmc.gmc_funcs->emit_flush_gpu_tlb((r), (vmid), (addr))
 #define amdgpu_gmc_emit_pasid_mapping(r, vmid, pasid) (r)->adev->gmc.gmc_funcs->emit_pasid_mapping((r), (vmid), (pasid))
 #define amdgpu_gmc_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gmc.gmc_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
index b8963b725dfa05baf9353f0859bde8af7c4e14f7..c48207b377bc5f5c64549eca69662896285971e5 100644 (file)
@@ -146,7 +146,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
                fence_ctx = 0;
        }
 
-       if (!ring->ready) {
+       if (!ring->sched.ready) {
                dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name);
                return -EINVAL;
        }
@@ -221,8 +221,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
                        !amdgpu_sriov_vf(adev)) /* for SRIOV preemption, Preamble CE ib must be inserted anyway */
                        continue;
 
-               amdgpu_ring_emit_ib(ring, ib, job ? job->vmid : 0,
-                                   need_ctx_switch);
+               amdgpu_ring_emit_ib(ring, job, ib, need_ctx_switch);
                need_ctx_switch = false;
        }
 
@@ -347,19 +346,14 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
                tmo_gfx = 8 * AMDGPU_IB_TEST_TIMEOUT;
        }
 
-       for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+       for (i = 0; i < adev->num_rings; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
                long tmo;
 
-               if (!ring || !ring->ready)
-                       continue;
-
-               /* skip IB tests for KIQ in general for the below reasons:
-                * 1. We never submit IBs to the KIQ
-                * 2. KIQ doesn't use the EOP interrupts,
-                *    we use some other CP interrupt.
+               /* KIQ rings don't have an IB test because we never submit IBs
+                * to them and they have no interrupt support.
                 */
-               if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
+               if (!ring->sched.ready || !ring->funcs->test_ib)
                        continue;
 
                /* MM engine need more time */
@@ -374,20 +368,23 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
                        tmo = tmo_gfx;
 
                r = amdgpu_ring_test_ib(ring, tmo);
-               if (r) {
-                       ring->ready = false;
-
-                       if (ring == &adev->gfx.gfx_ring[0]) {
-                               /* oh, oh, that's really bad */
-                               DRM_ERROR("amdgpu: failed testing IB on GFX ring (%d).\n", r);
-                               adev->accel_working = false;
-                               return r;
-
-                       } else {
-                               /* still not good, but we can live with it */
-                               DRM_ERROR("amdgpu: failed testing IB on ring %d (%d).\n", i, r);
-                               ret = r;
-                       }
+               if (!r) {
+                       DRM_DEV_DEBUG(adev->dev, "ib test on %s succeeded\n",
+                                     ring->name);
+                       continue;
+               }
+
+               ring->sched.ready = false;
+               DRM_DEV_ERROR(adev->dev, "IB test failed on %s (%d).\n",
+                         ring->name, r);
+
+               if (ring == &adev->gfx.gfx_ring[0]) {
+                       /* oh, oh, that's really bad */
+                       adev->accel_working = false;
+                       return r;
+
+               } else {
+                       ret = r;
                }
        }
        return ret;
index 9ce8c93ec19bf9422e8e1a8c9f60f1a58291bc87..f877bb78d10a31b11ebb9d8563d7b86055390966 100644 (file)
@@ -51,14 +51,12 @@ struct amdgpu_ih_ring {
 struct amdgpu_ih_funcs {
        /* ring read/write ptr handling, called from interrupt context */
        u32 (*get_wptr)(struct amdgpu_device *adev);
-       bool (*prescreen_iv)(struct amdgpu_device *adev);
        void (*decode_iv)(struct amdgpu_device *adev,
                          struct amdgpu_iv_entry *entry);
        void (*set_rptr)(struct amdgpu_device *adev);
 };
 
 #define amdgpu_ih_get_wptr(adev) (adev)->irq.ih_funcs->get_wptr((adev))
-#define amdgpu_ih_prescreen_iv(adev) (adev)->irq.ih_funcs->prescreen_iv((adev))
 #define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv))
 #define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev))
 
index 52c17f6219a706d2793d999eef39979342c5ab28..b7968f4268625e99f7dc62fdddf3b44a896edae5 100644 (file)
@@ -93,23 +93,6 @@ static void amdgpu_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
-/**
- * amdgpu_irq_reset_work_func - execute GPU reset
- *
- * @work: work struct pointer
- *
- * Execute scheduled GPU reset (Cayman+).
- * This function is called when the IRQ handler thinks we need a GPU reset.
- */
-static void amdgpu_irq_reset_work_func(struct work_struct *work)
-{
-       struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
-                                                 reset_work);
-
-       if (!amdgpu_sriov_vf(adev) && amdgpu_device_should_recover_gpu(adev))
-               amdgpu_device_gpu_recover(adev, NULL);
-}
-
 /**
  * amdgpu_irq_disable_all - disable *all* interrupts
  *
@@ -162,13 +145,6 @@ static void amdgpu_irq_callback(struct amdgpu_device *adev,
        u32 ring_index = ih->rptr >> 2;
        struct amdgpu_iv_entry entry;
 
-       /* Prescreening of high-frequency interrupts */
-       if (!amdgpu_ih_prescreen_iv(adev))
-               return;
-
-       /* Before dispatching irq to IP blocks, send it to amdkfd */
-       amdgpu_amdkfd_interrupt(adev, (const void *) &ih->ring[ring_index]);
-
        entry.iv_entry = (const uint32_t *)&ih->ring[ring_index];
        amdgpu_ih_decode_iv(adev, &entry);
 
@@ -262,15 +238,12 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
                                amdgpu_hotplug_work_func);
        }
 
-       INIT_WORK(&adev->reset_work, amdgpu_irq_reset_work_func);
-
        adev->irq.installed = true;
        r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
        if (r) {
                adev->irq.installed = false;
                if (!amdgpu_device_has_dc_support(adev))
                        flush_work(&adev->hotplug_work);
-               cancel_work_sync(&adev->reset_work);
                return r;
        }
        adev->ddev->max_vblank_count = 0x00ffffff;
@@ -299,7 +272,6 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
                        pci_disable_msi(adev->pdev);
                if (!amdgpu_device_has_dc_support(adev))
                        flush_work(&adev->hotplug_work);
-               cancel_work_sync(&adev->reset_work);
        }
 
        for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
@@ -392,39 +364,38 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
        unsigned client_id = entry->client_id;
        unsigned src_id = entry->src_id;
        struct amdgpu_irq_src *src;
+       bool handled = false;
        int r;
 
        trace_amdgpu_iv(entry);
 
        if (client_id >= AMDGPU_IRQ_CLIENTID_MAX) {
                DRM_DEBUG("Invalid client_id in IV: %d\n", client_id);
-               return;
-       }
 
-       if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
+       } else  if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
                DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
-               return;
-       }
 
-       if (adev->irq.virq[src_id]) {
+       } else if (adev->irq.virq[src_id]) {
                generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
-       } else {
-               if (!adev->irq.client[client_id].sources) {
-                       DRM_DEBUG("Unregistered interrupt client_id: %d src_id: %d\n",
-                                 client_id, src_id);
-                       return;
-               }
 
-               src = adev->irq.client[client_id].sources[src_id];
-               if (!src) {
-                       DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
-                       return;
-               }
+       } else if (!adev->irq.client[client_id].sources) {
+               DRM_DEBUG("Unregistered interrupt client_id: %d src_id: %d\n",
+                         client_id, src_id);
 
+       } else if ((src = adev->irq.client[client_id].sources[src_id])) {
                r = src->funcs->process(adev, src, entry);
-               if (r)
+               if (r < 0)
                        DRM_ERROR("error processing interrupt (%d)\n", r);
+               else if (r)
+                       handled = true;
+
+       } else {
+               DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
        }
+
+       /* Send it to amdkfd as well if it isn't already handled */
+       if (!handled)
+               amdgpu_amdkfd_interrupt(adev, entry->iv_entry);
 }
 
 /**
index 755f733bf0d9517591f945e931a116cb0ae2c4ac..e0af44fd6a0cf7b52c266400510a857b74ea5efa 100644 (file)
@@ -112,6 +112,8 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
        struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
        struct amdgpu_job *job = to_amdgpu_job(s_job);
 
+       drm_sched_job_cleanup(s_job);
+
        amdgpu_ring_priority_put(ring, s_job->s_priority);
        dma_fence_put(job->fence);
        amdgpu_sync_free(&job->sync);
index 57cfe78a262b11e70eb037afda5755769932fabd..e1b46a6703ded9a60370bedf20bab108b19fd808 100644 (file)
@@ -33,6 +33,8 @@
 #define to_amdgpu_job(sched_job)               \
                container_of((sched_job), struct amdgpu_job, base)
 
+#define AMDGPU_JOB_GET_VMID(job) ((job) ? (job)->vmid : 0)
+
 struct amdgpu_fence;
 
 struct amdgpu_job {
index 8f3d44e5e78785a18089204113636553de40064d..bc62bf41b7e9b428a66b88e7d67a7f684133f7dd 100644 (file)
@@ -336,7 +336,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        case AMDGPU_HW_IP_GFX:
                type = AMD_IP_BLOCK_TYPE_GFX;
                for (i = 0; i < adev->gfx.num_gfx_rings; i++)
-                       if (adev->gfx.gfx_ring[i].ready)
+                       if (adev->gfx.gfx_ring[i].sched.ready)
                                ++num_rings;
                ib_start_alignment = 32;
                ib_size_alignment = 32;
@@ -344,7 +344,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        case AMDGPU_HW_IP_COMPUTE:
                type = AMD_IP_BLOCK_TYPE_GFX;
                for (i = 0; i < adev->gfx.num_compute_rings; i++)
-                       if (adev->gfx.compute_ring[i].ready)
+                       if (adev->gfx.compute_ring[i].sched.ready)
                                ++num_rings;
                ib_start_alignment = 32;
                ib_size_alignment = 32;
@@ -352,7 +352,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        case AMDGPU_HW_IP_DMA:
                type = AMD_IP_BLOCK_TYPE_SDMA;
                for (i = 0; i < adev->sdma.num_instances; i++)
-                       if (adev->sdma.instance[i].ring.ready)
+                       if (adev->sdma.instance[i].ring.sched.ready)
                                ++num_rings;
                ib_start_alignment = 256;
                ib_size_alignment = 4;
@@ -363,7 +363,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
                        if (adev->uvd.harvest_config & (1 << i))
                                continue;
 
-                       if (adev->uvd.inst[i].ring.ready)
+                       if (adev->uvd.inst[i].ring.sched.ready)
                                ++num_rings;
                }
                ib_start_alignment = 64;
@@ -372,7 +372,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        case AMDGPU_HW_IP_VCE:
                type = AMD_IP_BLOCK_TYPE_VCE;
                for (i = 0; i < adev->vce.num_rings; i++)
-                       if (adev->vce.ring[i].ready)
+                       if (adev->vce.ring[i].sched.ready)
                                ++num_rings;
                ib_start_alignment = 4;
                ib_size_alignment = 1;
@@ -384,7 +384,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
                                continue;
 
                        for (j = 0; j < adev->uvd.num_enc_rings; j++)
-                               if (adev->uvd.inst[i].ring_enc[j].ready)
+                               if (adev->uvd.inst[i].ring_enc[j].sched.ready)
                                        ++num_rings;
                }
                ib_start_alignment = 64;
@@ -392,7 +392,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
                break;
        case AMDGPU_HW_IP_VCN_DEC:
                type = AMD_IP_BLOCK_TYPE_VCN;
-               if (adev->vcn.ring_dec.ready)
+               if (adev->vcn.ring_dec.sched.ready)
                        ++num_rings;
                ib_start_alignment = 16;
                ib_size_alignment = 16;
@@ -400,14 +400,14 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        case AMDGPU_HW_IP_VCN_ENC:
                type = AMD_IP_BLOCK_TYPE_VCN;
                for (i = 0; i < adev->vcn.num_enc_rings; i++)
-                       if (adev->vcn.ring_enc[i].ready)
+                       if (adev->vcn.ring_enc[i].sched.ready)
                                ++num_rings;
                ib_start_alignment = 64;
                ib_size_alignment = 1;
                break;
        case AMDGPU_HW_IP_VCN_JPEG:
                type = AMD_IP_BLOCK_TYPE_VCN;
-               if (adev->vcn.ring_jpeg.ready)
+               if (adev->vcn.ring_jpeg.sched.ready)
                        ++num_rings;
                ib_start_alignment = 16;
                ib_size_alignment = 16;
@@ -978,7 +978,10 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
        }
 
        if (amdgpu_sriov_vf(adev)) {
-               r = amdgpu_map_static_csa(adev, &fpriv->vm, &fpriv->csa_va);
+               uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_GMC_HOLE_MASK;
+
+               r = amdgpu_map_static_csa(adev, &fpriv->vm, adev->virt.csa_obj,
+                                               &fpriv->csa_va, csa_addr, AMDGPU_CSA_SIZE);
                if (r)
                        goto error_vm;
        }
@@ -1048,8 +1051,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
        pasid = fpriv->vm.pasid;
        pd = amdgpu_bo_ref(fpriv->vm.root.base.bo);
 
-       amdgpu_vm_fini(adev, &fpriv->vm);
        amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
+       amdgpu_vm_fini(adev, &fpriv->vm);
 
        if (pasid)
                amdgpu_pasid_free_delayed(pd->tbo.resv, pasid);
index d1b4d9b6aae0d1743f77dc2373d0c9159d03f937..aadd0fa42e430d02bfb386152f5510fc332183e3 100644 (file)
@@ -38,7 +38,6 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_plane_helper.h>
-#include <drm/drm_fb_helper.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/hrtimer.h>
@@ -57,7 +56,6 @@ struct amdgpu_hpd;
 #define to_amdgpu_connector(x) container_of(x, struct amdgpu_connector, base)
 #define to_amdgpu_encoder(x) container_of(x, struct amdgpu_encoder, base)
 #define to_amdgpu_framebuffer(x) container_of(x, struct amdgpu_framebuffer, base)
-#define to_amdgpu_plane(x)     container_of(x, struct amdgpu_plane, base)
 
 #define to_dm_plane_state(x)   container_of(x, struct dm_plane_state, base);
 
@@ -295,13 +293,6 @@ struct amdgpu_display_funcs {
                              uint16_t connector_object_id,
                              struct amdgpu_hpd *hpd,
                              struct amdgpu_router *router);
-       /* it is used to enter or exit into free sync mode */
-       int (*notify_freesync)(struct drm_device *dev, void *data,
-                              struct drm_file *filp);
-       /* it is used to allow enablement of freesync mode */
-       int (*set_freesync_property)(struct drm_connector *connector,
-                                    struct drm_property *property,
-                                    uint64_t val);
 
 
 };
@@ -325,7 +316,7 @@ struct amdgpu_mode_info {
        struct card_info *atom_card_info;
        bool mode_config_initialized;
        struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS];
-       struct amdgpu_plane *planes[AMDGPU_MAX_PLANES];
+       struct drm_plane *planes[AMDGPU_MAX_PLANES];
        struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS];
        /* DVI-I properties */
        struct drm_property *coherent_mode_property;
@@ -341,6 +332,8 @@ struct amdgpu_mode_info {
        struct drm_property *dither_property;
        /* maximum number of bits per channel for monitor color */
        struct drm_property *max_bpc_property;
+       /* Adaptive Backlight Modulation (power feature) */
+       struct drm_property *abm_level_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -436,11 +429,6 @@ struct amdgpu_crtc {
        struct drm_pending_vblank_event *event;
 };
 
-struct amdgpu_plane {
-       struct drm_plane base;
-       enum drm_plane_type plane_type;
-};
-
 struct amdgpu_encoder_atom_dig {
        bool linkb;
        /* atom dig */
index 904014dc5915f8142dd0dc6c169a76bacbaf7e9f..fd271f9746a29ee6799f623557ffaf0354e31b45 100644 (file)
@@ -81,7 +81,7 @@ static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo)
                amdgpu_bo_subtract_pin_size(bo);
 
        if (bo->kfd_bo)
-               amdgpu_amdkfd_unreserve_system_memory_limit(bo);
+               amdgpu_amdkfd_unreserve_memory_limit(bo);
 
        amdgpu_bo_kunmap(bo);
 
@@ -607,53 +607,6 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
        return r;
 }
 
-/**
- * amdgpu_bo_backup_to_shadow - Backs up an &amdgpu_bo buffer object
- * @adev: amdgpu device object
- * @ring: amdgpu_ring for the engine handling the buffer operations
- * @bo: &amdgpu_bo buffer to be backed up
- * @resv: reservation object with embedded fence
- * @fence: dma_fence associated with the operation
- * @direct: whether to submit the job directly
- *
- * Copies an &amdgpu_bo buffer object to its shadow object.
- * Not used for now.
- *
- * Returns:
- * 0 for success or a negative error code on failure.
- */
-int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
-                              struct amdgpu_ring *ring,
-                              struct amdgpu_bo *bo,
-                              struct reservation_object *resv,
-                              struct dma_fence **fence,
-                              bool direct)
-
-{
-       struct amdgpu_bo *shadow = bo->shadow;
-       uint64_t bo_addr, shadow_addr;
-       int r;
-
-       if (!shadow)
-               return -EINVAL;
-
-       bo_addr = amdgpu_bo_gpu_offset(bo);
-       shadow_addr = amdgpu_bo_gpu_offset(bo->shadow);
-
-       r = reservation_object_reserve_shared(bo->tbo.resv);
-       if (r)
-               goto err;
-
-       r = amdgpu_copy_buffer(ring, bo_addr, shadow_addr,
-                              amdgpu_bo_size(bo), resv, fence,
-                              direct, false);
-       if (!r)
-               amdgpu_bo_fence(bo, *fence, true);
-
-err:
-       return r;
-}
-
 /**
  * amdgpu_bo_validate - validate an &amdgpu_bo buffer object
  * @bo: pointer to the buffer object
index 7d3312d0da1174dcc62e75d782fcb55c5f1cbd39..9291c2f837e95b674dd535f35c4e7daa82cbcb7a 100644 (file)
@@ -267,11 +267,6 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
                     bool shared);
 u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo);
-int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
-                              struct amdgpu_ring *ring,
-                              struct amdgpu_bo *bo,
-                              struct reservation_object *resv,
-                              struct dma_fence **fence, bool direct);
 int amdgpu_bo_validate(struct amdgpu_bo *bo);
 int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow,
                             struct dma_fence **fence);
index 59cc678de8c1570642afc2d488f63fbc179a1e99..1f61ed95727ce3083faa9036c0d05f2d16641a5c 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/nospec.h>
+#include "hwmgr.h"
+#define WIDTH_4K 3840
 
 static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
 
@@ -1642,6 +1644,19 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
            attr == &sensor_dev_attr_fan1_enable.dev_attr.attr))
                return 0;
 
+       /* Skip fan attributes on APU */
+       if ((adev->flags & AMD_IS_APU) &&
+           (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+            attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+            attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+            attr == &sensor_dev_attr_pwm1_min.dev_attr.attr ||
+            attr == &sensor_dev_attr_fan1_input.dev_attr.attr ||
+            attr == &sensor_dev_attr_fan1_min.dev_attr.attr ||
+            attr == &sensor_dev_attr_fan1_max.dev_attr.attr ||
+            attr == &sensor_dev_attr_fan1_target.dev_attr.attr ||
+            attr == &sensor_dev_attr_fan1_enable.dev_attr.attr))
+               return 0;
+
        /* Skip limit attributes if DPM is not enabled */
        if (!adev->pm.dpm_enabled &&
            (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
@@ -1956,6 +1971,17 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
                amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable);
                mutex_unlock(&adev->pm.mutex);
        }
+       /* enable/disable Low Memory PState for UVD (4k videos) */
+       if (adev->asic_type == CHIP_STONEY &&
+               adev->uvd.decode_image_width >= WIDTH_4K) {
+               struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
+
+               if (hwmgr && hwmgr->hwmgr_func &&
+                   hwmgr->hwmgr_func->update_nbdpm_pstate)
+                       hwmgr->hwmgr_func->update_nbdpm_pstate(hwmgr,
+                                                              !enable,
+                                                              true);
+       }
 }
 
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
@@ -2129,7 +2155,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
 
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
-               if (ring && ring->ready)
+               if (ring && ring->sched.ready)
                        amdgpu_fence_wait_empty(ring);
        }
 
index e45e929aaab5b00d85dee7e835aad6231a3984bd..71913a18d142cb028fe4077b0d4dca0d36be7f02 100644 (file)
@@ -39,8 +39,6 @@
 #include <drm/amdgpu_drm.h>
 #include <linux/dma-buf.h>
 
-static const struct dma_buf_ops amdgpu_dmabuf_ops;
-
 /**
  * amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table
  * implementation
@@ -332,15 +330,13 @@ static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf,
        return ret;
 }
 
-static const struct dma_buf_ops amdgpu_dmabuf_ops = {
+const struct dma_buf_ops amdgpu_dmabuf_ops = {
        .attach = amdgpu_gem_map_attach,
        .detach = amdgpu_gem_map_detach,
        .map_dma_buf = drm_gem_map_dma_buf,
        .unmap_dma_buf = drm_gem_unmap_dma_buf,
        .release = drm_gem_dmabuf_release,
        .begin_cpu_access = amdgpu_gem_begin_cpu_access,
-       .map = drm_gem_dmabuf_kmap,
-       .unmap = drm_gem_dmabuf_kunmap,
        .mmap = drm_gem_dmabuf_mmap,
        .vmap = drm_gem_dmabuf_vmap,
        .vunmap = drm_gem_dmabuf_vunmap,
index 25d2f3e757f1bdac06054172f3ad9db6ef5ea8fa..6759d898b3aba103998e177702e10526d03cc62a 100644 (file)
@@ -90,6 +90,8 @@ static int psp_sw_fini(void *handle)
        adev->psp.sos_fw = NULL;
        release_firmware(adev->psp.asd_fw);
        adev->psp.asd_fw = NULL;
+       release_firmware(adev->psp.ta_fw);
+       adev->psp.ta_fw = NULL;
        return 0;
 }
 
@@ -118,21 +120,25 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
 static int
 psp_cmd_submit_buf(struct psp_context *psp,
                   struct amdgpu_firmware_info *ucode,
-                  struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr,
-                  int index)
+                  struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
 {
        int ret;
+       int index;
 
        memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
 
        memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
 
+       index = atomic_inc_return(&psp->fence_value);
        ret = psp_cmd_submit(psp, ucode, psp->cmd_buf_mc_addr,
                             fence_mc_addr, index);
+       if (ret) {
+               atomic_dec(&psp->fence_value);
+               return ret;
+       }
 
-       while (*((unsigned int *)psp->fence_buf) != index) {
+       while (*((unsigned int *)psp->fence_buf) != index)
                msleep(1);
-       }
 
        /* the status field must be 0 after FW is loaded */
        if (ucode && psp->cmd_buf_mem->resp.status) {
@@ -149,10 +155,22 @@ psp_cmd_submit_buf(struct psp_context *psp,
        return ret;
 }
 
-static void psp_prep_tmr_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+bool psp_support_vmr_ring(struct psp_context *psp)
+{
+       if (amdgpu_sriov_vf(psp->adev) && psp->sos_fw_version > 0x80045)
+               return true;
+       else
+               return false;
+}
+
+static void psp_prep_tmr_cmd_buf(struct psp_context *psp,
+                                struct psp_gfx_cmd_resp *cmd,
                                 uint64_t tmr_mc, uint32_t size)
 {
-       cmd->cmd_id = GFX_CMD_ID_SETUP_TMR;
+       if (psp_support_vmr_ring(psp))
+               cmd->cmd_id = GFX_CMD_ID_SETUP_VMR;
+       else
+               cmd->cmd_id = GFX_CMD_ID_SETUP_TMR;
        cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc);
        cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc);
        cmd->cmd.cmd_setup_tmr.buf_size = size;
@@ -186,12 +204,12 @@ static int psp_tmr_load(struct psp_context *psp)
        if (!cmd)
                return -ENOMEM;
 
-       psp_prep_tmr_cmd_buf(cmd, psp->tmr_mc_addr, PSP_TMR_SIZE);
+       psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, PSP_TMR_SIZE);
        DRM_INFO("reserve 0x%x from 0x%llx for PSP TMR SIZE\n",
                        PSP_TMR_SIZE, psp->tmr_mc_addr);
 
        ret = psp_cmd_submit_buf(psp, NULL, cmd,
-                                psp->fence_buf_mc_addr, 1);
+                                psp->fence_buf_mc_addr);
        if (ret)
                goto failed;
 
@@ -258,13 +276,194 @@ static int psp_asd_load(struct psp_context *psp)
                             psp->asd_ucode_size, PSP_ASD_SHARED_MEM_SIZE);
 
        ret = psp_cmd_submit_buf(psp, NULL, cmd,
-                                psp->fence_buf_mc_addr, 2);
+                                psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static void psp_prep_xgmi_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                         uint64_t xgmi_ta_mc, uint64_t xgmi_mc_shared,
+                                         uint32_t xgmi_ta_size, uint32_t shared_size)
+{
+        cmd->cmd_id = GFX_CMD_ID_LOAD_TA;
+        cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(xgmi_ta_mc);
+        cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(xgmi_ta_mc);
+        cmd->cmd.cmd_load_ta.app_len = xgmi_ta_size;
+
+        cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(xgmi_mc_shared);
+        cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(xgmi_mc_shared);
+        cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size;
+}
+
+static int psp_xgmi_init_shared_buf(struct psp_context *psp)
+{
+       int ret;
+
+       /*
+        * Allocate 16k memory aligned to 4k from Frame Buffer (local
+        * physical) for xgmi ta <-> Driver
+        */
+       ret = amdgpu_bo_create_kernel(psp->adev, PSP_XGMI_SHARED_MEM_SIZE,
+                                     PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+                                     &psp->xgmi_context.xgmi_shared_bo,
+                                     &psp->xgmi_context.xgmi_shared_mc_addr,
+                                     &psp->xgmi_context.xgmi_shared_buf);
+
+       return ret;
+}
+
+static int psp_xgmi_load(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+       memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
+
+       psp_prep_xgmi_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
+                                     psp->xgmi_context.xgmi_shared_mc_addr,
+                                     psp->ta_xgmi_ucode_size, PSP_XGMI_SHARED_MEM_SIZE);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                                psp->fence_buf_mc_addr);
+
+       if (!ret) {
+               psp->xgmi_context.initialized = 1;
+               psp->xgmi_context.session_id = cmd->resp.session_id;
+       }
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static void psp_prep_xgmi_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                           uint32_t xgmi_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
+       cmd->cmd.cmd_unload_ta.session_id = xgmi_session_id;
+}
+
+static int psp_xgmi_unload(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the unloading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_xgmi_ta_unload_cmd_buf(cmd, psp->xgmi_context.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                                psp->fence_buf_mc_addr);
 
        kfree(cmd);
 
        return ret;
 }
 
+static void psp_prep_xgmi_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                           uint32_t ta_cmd_id,
+                                           uint32_t xgmi_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
+       cmd->cmd.cmd_invoke_cmd.session_id = xgmi_session_id;
+       cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
+       /* Note: cmd_invoke_cmd.buf is not used for now */
+}
+
+int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+       */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_xgmi_ta_invoke_cmd_buf(cmd, ta_cmd_id,
+                                       psp->xgmi_context.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                                psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+        return ret;
+}
+
+static int psp_xgmi_terminate(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->xgmi_context.initialized)
+               return 0;
+
+       ret = psp_xgmi_unload(psp);
+       if (ret)
+               return ret;
+
+       psp->xgmi_context.initialized = 0;
+
+       /* free xgmi shared memory */
+       amdgpu_bo_free_kernel(&psp->xgmi_context.xgmi_shared_bo,
+                       &psp->xgmi_context.xgmi_shared_mc_addr,
+                       &psp->xgmi_context.xgmi_shared_buf);
+
+       return 0;
+}
+
+static int psp_xgmi_initialize(struct psp_context *psp)
+{
+       struct ta_xgmi_shared_memory *xgmi_cmd;
+       int ret;
+
+       if (!psp->xgmi_context.initialized) {
+               ret = psp_xgmi_init_shared_buf(psp);
+               if (ret)
+                       return ret;
+       }
+
+       /* Load XGMI TA */
+       ret = psp_xgmi_load(psp);
+       if (ret)
+               return ret;
+
+       /* Initialize XGMI session */
+       xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.xgmi_shared_buf);
+       memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+       xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE;
+
+       ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+
+       return ret;
+}
+
 static int psp_hw_start(struct psp_context *psp)
 {
        struct amdgpu_device *adev = psp->adev;
@@ -292,6 +491,15 @@ static int psp_hw_start(struct psp_context *psp)
        if (ret)
                return ret;
 
+       if (adev->gmc.xgmi.num_physical_nodes > 1) {
+               ret = psp_xgmi_initialize(psp);
+               /* Warning the XGMI seesion initialize failure
+                * Instead of stop driver initialization
+                */
+               if (ret)
+                       dev_err(psp->adev->dev,
+                               "XGMI: Failed to initialize XGMI session\n");
+       }
        return 0;
 }
 
@@ -321,7 +529,7 @@ static int psp_np_fw_load(struct psp_context *psp)
                        return ret;
 
                ret = psp_cmd_submit_buf(psp, ucode, psp->cmd,
-                                        psp->fence_buf_mc_addr, i + 3);
+                                        psp->fence_buf_mc_addr);
                if (ret)
                        return ret;
 
@@ -340,8 +548,10 @@ static int psp_load_fw(struct amdgpu_device *adev)
        int ret;
        struct psp_context *psp = &adev->psp;
 
-       if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset != 0)
+       if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset) {
+               psp_ring_destroy(psp, PSP_RING_TYPE__KM);
                goto skip_memalloc;
+       }
 
        psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
        if (!psp->cmd)
@@ -452,6 +662,10 @@ static int psp_hw_fini(void *handle)
        if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
                return 0;
 
+       if (adev->gmc.xgmi.num_physical_nodes > 1 &&
+           psp->xgmi_context.initialized == 1)
+                psp_xgmi_terminate(psp);
+
        psp_ring_destroy(psp, PSP_RING_TYPE__KM);
 
        amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
@@ -479,6 +693,15 @@ static int psp_suspend(void *handle)
        if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
                return 0;
 
+       if (adev->gmc.xgmi.num_physical_nodes > 1 &&
+           psp->xgmi_context.initialized == 1) {
+               ret = psp_xgmi_terminate(psp);
+               if (ret) {
+                       DRM_ERROR("Failed to terminate xgmi ta\n");
+                       return ret;
+               }
+       }
+
        ret = psp_ring_stop(psp, PSP_RING_TYPE__KM);
        if (ret) {
                DRM_ERROR("PSP ring stop failed\n");
index 8b8720e9c3f0211b8e1aee4377aa787fb0e4dea0..10decf70c9aa33d1b32a31f7eabe9cbba30a06f1 100644 (file)
 
 #include "amdgpu.h"
 #include "psp_gfx_if.h"
+#include "ta_xgmi_if.h"
 
 #define PSP_FENCE_BUFFER_SIZE  0x1000
 #define PSP_CMD_BUFFER_SIZE    0x1000
-#define PSP_ASD_SHARED_MEM_SIZE        0x4000
+#define PSP_ASD_SHARED_MEM_SIZE 0x4000
+#define PSP_XGMI_SHARED_MEM_SIZE 0x4000
 #define PSP_1_MEG              0x100000
 #define PSP_TMR_SIZE   0x400000
 
 struct psp_context;
+struct psp_xgmi_node_info;
 struct psp_xgmi_topology_info;
 
 enum psp_ring_type
@@ -80,12 +83,20 @@ struct psp_funcs
                                  enum AMDGPU_UCODE_ID ucode_type);
        bool (*smu_reload_quirk)(struct psp_context *psp);
        int (*mode1_reset)(struct psp_context *psp);
-       uint64_t (*xgmi_get_device_id)(struct psp_context *psp);
+       uint64_t (*xgmi_get_node_id)(struct psp_context *psp);
        uint64_t (*xgmi_get_hive_id)(struct psp_context *psp);
        int (*xgmi_get_topology_info)(struct psp_context *psp, int number_devices,
-                       struct psp_xgmi_topology_info *topology);
+                                     struct psp_xgmi_topology_info *topology);
        int (*xgmi_set_topology_info)(struct psp_context *psp, int number_devices,
-                       struct psp_xgmi_topology_info *topology);
+                                     struct psp_xgmi_topology_info *topology);
+};
+
+struct psp_xgmi_context {
+       uint8_t                         initialized;
+       uint32_t                        session_id;
+       struct amdgpu_bo                *xgmi_shared_bo;
+       uint64_t                        xgmi_shared_mc_addr;
+       void                            *xgmi_shared_buf;
 };
 
 struct psp_context
@@ -96,7 +107,7 @@ struct psp_context
 
        const struct psp_funcs          *funcs;
 
-       /* fence buffer */
+       /* firmware buffer */
        struct amdgpu_bo                *fw_pri_bo;
        uint64_t                        fw_pri_mc_addr;
        void                            *fw_pri_buf;
@@ -134,6 +145,16 @@ struct psp_context
        struct amdgpu_bo                *cmd_buf_bo;
        uint64_t                        cmd_buf_mc_addr;
        struct psp_gfx_cmd_resp         *cmd_buf_mem;
+
+       /* fence value associated with cmd buffer */
+       atomic_t                        fence_value;
+
+       /* xgmi ta firmware and buffer */
+       const struct firmware           *ta_fw;
+       uint32_t                        ta_xgmi_ucode_version;
+       uint32_t                        ta_xgmi_ucode_size;
+       uint8_t                         *ta_xgmi_start_addr;
+       struct psp_xgmi_context         xgmi_context;
 };
 
 struct amdgpu_psp_funcs {
@@ -141,21 +162,17 @@ struct amdgpu_psp_funcs {
                                        enum AMDGPU_UCODE_ID);
 };
 
+#define AMDGPU_XGMI_MAX_CONNECTED_NODES                64
+struct psp_xgmi_node_info {
+       uint64_t                                node_id;
+       uint8_t                                 num_hops;
+       uint8_t                                 is_sharing_enabled;
+       enum ta_xgmi_assigned_sdma_engine       sdma_engine;
+};
+
 struct psp_xgmi_topology_info {
-       /* Generated by PSP to identify the GPU instance within xgmi connection */
-       uint64_t                        device_id;
-       /*
-        * If all bits set to 0 , driver indicates it wants to retrieve the xgmi
-        * connection vector topology, but not access enable the connections
-        * if some or all bits are set to 1, driver indicates it want to retrieve the
-        * current xgmi topology and  access enable the link to GPU[i] associated
-        * with the bit position in the  vector.
-        * On return,: bits indicated which xgmi links are present/active depending
-        * on the  value passed in. The relative bit offset for the  relative GPU index
-        * within the  hive is always marked active.
-        */
-       uint32_t                        connection_mask;
-       uint32_t                        reserved; /* must be  0 */
+       uint32_t                        num_nodes;
+       struct psp_xgmi_node_info       nodes[AMDGPU_XGMI_MAX_CONNECTED_NODES];
 };
 
 #define psp_prep_cmd_buf(ucode, type) (psp)->funcs->prep_cmd_buf((ucode), (type))
@@ -177,8 +194,8 @@ struct psp_xgmi_topology_info {
                ((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false)
 #define psp_mode1_reset(psp) \
                ((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false)
-#define psp_xgmi_get_device_id(psp) \
-               ((psp)->funcs->xgmi_get_device_id ? (psp)->funcs->xgmi_get_device_id((psp)) : 0)
+#define psp_xgmi_get_node_id(psp) \
+               ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp)) : 0)
 #define psp_xgmi_get_hive_id(psp) \
                ((psp)->funcs->xgmi_get_hive_id ? (psp)->funcs->xgmi_get_hive_id((psp)) : 0)
 #define psp_xgmi_get_topology_info(psp, num_device, topology) \
@@ -199,6 +216,9 @@ extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
 extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
 
 int psp_gpu_reset(struct amdgpu_device *adev);
+int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
+bool psp_support_vmr_ring(struct psp_context *psp);
+
 extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
 
 #endif
index b70e85ec147d54d4784be1b9b66639be9ff26d8a..335a0edf114b6d313091df85ed150782238c0a64 100644 (file)
@@ -338,7 +338,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
  */
 void amdgpu_ring_fini(struct amdgpu_ring *ring)
 {
-       ring->ready = false;
+       ring->sched.ready = false;
 
        /* Not to finish a ring which is not initialized */
        if (!(ring->adev) || !(ring->adev->rings[ring->idx]))
@@ -397,7 +397,7 @@ bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid,
 {
        ktime_t deadline = ktime_add_us(ktime_get(), 10000);
 
-       if (!ring->funcs->soft_recovery)
+       if (!ring->funcs->soft_recovery || !fence)
                return false;
 
        atomic_inc(&ring->adev->gpu_reset_counter);
@@ -500,3 +500,29 @@ static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring)
        debugfs_remove(ring->ent);
 #endif
 }
+
+/**
+ * amdgpu_ring_test_helper - tests ring and set sched readiness status
+ *
+ * @ring: ring to try the recovery on
+ *
+ * Tests ring and set sched readiness status
+ *
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       int r;
+
+       r = amdgpu_ring_test_ring(ring);
+       if (r)
+               DRM_DEV_ERROR(adev->dev, "ring %s test failed (%d)\n",
+                             ring->name, r);
+       else
+               DRM_DEV_DEBUG(adev->dev, "ring test on %s succeeded\n",
+                             ring->name);
+
+       ring->sched.ready = !r;
+       return r;
+}
index 4caa301ce454884b9ebe980b3b554c19e2932be0..0beb01fef83fd38c9b940c167fa7df7d25df1f71 100644 (file)
@@ -129,8 +129,9 @@ struct amdgpu_ring_funcs {
        unsigned emit_ib_size;
        /* command emit functions */
        void (*emit_ib)(struct amdgpu_ring *ring,
+                       struct amdgpu_job *job,
                        struct amdgpu_ib *ib,
-                       unsigned vmid, bool ctx_switch);
+                       bool ctx_switch);
        void (*emit_fence)(struct amdgpu_ring *ring, uint64_t addr,
                           uint64_t seq, unsigned flags);
        void (*emit_pipeline_sync)(struct amdgpu_ring *ring);
@@ -189,7 +190,6 @@ struct amdgpu_ring {
        uint64_t                gpu_addr;
        uint64_t                ptr_mask;
        uint32_t                buf_mask;
-       bool                    ready;
        u32                     idx;
        u32                     me;
        u32                     pipe;
@@ -229,7 +229,7 @@ struct amdgpu_ring {
 #define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r))
 #define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r))
 #define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r))
-#define amdgpu_ring_emit_ib(r, ib, vmid, c) (r)->funcs->emit_ib((r), (ib), (vmid), (c))
+#define amdgpu_ring_emit_ib(r, job, ib, c) ((r)->funcs->emit_ib((r), (job), (ib), (c)))
 #define amdgpu_ring_emit_pipeline_sync(r) (r)->funcs->emit_pipeline_sync((r))
 #define amdgpu_ring_emit_vm_flush(r, vmid, addr) (r)->funcs->emit_vm_flush((r), (vmid), (addr))
 #define amdgpu_ring_emit_fence(r, addr, seq, flags) (r)->funcs->emit_fence((r), (addr), (seq), (flags))
@@ -313,4 +313,6 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
        ring->count_dw -= count_dw;
 }
 
+int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
+
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
new file mode 100644 (file)
index 0000000..c8793e6
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "amdgpu.h"
+#include "amdgpu_gfx.h"
+#include "amdgpu_rlc.h"
+
+/**
+ * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode.
+ */
+void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev)
+{
+       if (adev->gfx.rlc.in_safe_mode)
+               return;
+
+       /* if RLC is not enabled, do nothing */
+       if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
+               return;
+
+       if (adev->cg_flags &
+           (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
+            AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+               adev->gfx.rlc.funcs->set_safe_mode(adev);
+               adev->gfx.rlc.in_safe_mode = true;
+       }
+}
+
+/**
+ * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set RLC exit safe mode if RLC is enabled and have entered into safe mode.
+ */
+void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev)
+{
+       if (!(adev->gfx.rlc.in_safe_mode))
+               return;
+
+       /* if RLC is not enabled, do nothing */
+       if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
+               return;
+
+       if (adev->cg_flags &
+           (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
+            AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+               adev->gfx.rlc.funcs->unset_safe_mode(adev);
+               adev->gfx.rlc.in_safe_mode = false;
+       }
+}
+
+/**
+ * amdgpu_gfx_rlc_init_sr - Init save restore block
+ *
+ * @adev: amdgpu_device pointer
+ * @dws: the size of save restore block
+ *
+ * Allocate and setup value to save restore block of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws)
+{
+       const u32 *src_ptr;
+       volatile u32 *dst_ptr;
+       u32 i;
+       int r;
+
+       /* allocate save restore block */
+       r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
+                                     AMDGPU_GEM_DOMAIN_VRAM,
+                                     &adev->gfx.rlc.save_restore_obj,
+                                     &adev->gfx.rlc.save_restore_gpu_addr,
+                                     (void **)&adev->gfx.rlc.sr_ptr);
+       if (r) {
+               dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
+               amdgpu_gfx_rlc_fini(adev);
+               return r;
+       }
+
+       /* write the sr buffer */
+       src_ptr = adev->gfx.rlc.reg_list;
+       dst_ptr = adev->gfx.rlc.sr_ptr;
+       for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
+               dst_ptr[i] = cpu_to_le32(src_ptr[i]);
+       amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
+       amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
+
+       return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_init_csb - Init clear state block
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate and setup value to clear state block of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
+{
+       volatile u32 *dst_ptr;
+       u32 dws;
+       int r;
+
+       /* allocate clear state block */
+       adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
+       r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
+                                     AMDGPU_GEM_DOMAIN_VRAM,
+                                     &adev->gfx.rlc.clear_state_obj,
+                                     &adev->gfx.rlc.clear_state_gpu_addr,
+                                     (void **)&adev->gfx.rlc.cs_ptr);
+       if (r) {
+               dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r);
+               amdgpu_gfx_rlc_fini(adev);
+               return r;
+       }
+
+       /* set up the cs buffer */
+       dst_ptr = adev->gfx.rlc.cs_ptr;
+       adev->gfx.rlc.funcs->get_csb_buffer(adev, dst_ptr);
+       amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
+       amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
+       amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
+
+       return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_init_cpt - Init cp table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate and setup value to cp table of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
+{
+       int r;
+
+       r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
+                                     PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+                                     &adev->gfx.rlc.cp_table_obj,
+                                     &adev->gfx.rlc.cp_table_gpu_addr,
+                                     (void **)&adev->gfx.rlc.cp_table_ptr);
+       if (r) {
+               dev_err(adev->dev, "(%d) failed to create cp table bo\n", r);
+               amdgpu_gfx_rlc_fini(adev);
+               return r;
+       }
+
+       /* set up the cp table */
+       amdgpu_gfx_rlc_setup_cp_table(adev);
+       amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
+       amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
+
+       return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Write cp firmware data into cp table.
+ */
+void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev)
+{
+       const __le32 *fw_data;
+       volatile u32 *dst_ptr;
+       int me, i, max_me;
+       u32 bo_offset = 0;
+       u32 table_offset, table_size;
+
+       max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev);
+
+       /* write the cp table buffer */
+       dst_ptr = adev->gfx.rlc.cp_table_ptr;
+       for (me = 0; me < max_me; me++) {
+               if (me == 0) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.ce_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 1) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.pfp_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 2) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.me_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else if (me == 3) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.mec_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               } else  if (me == 4) {
+                       const struct gfx_firmware_header_v1_0 *hdr =
+                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
+                       fw_data = (const __le32 *)
+                               (adev->gfx.mec2_fw->data +
+                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+                       table_offset = le32_to_cpu(hdr->jt_offset);
+                       table_size = le32_to_cpu(hdr->jt_size);
+               }
+
+               for (i = 0; i < table_size; i ++) {
+                       dst_ptr[bo_offset + i] =
+                               cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
+               }
+
+               bo_offset += table_size;
+       }
+}
+
+/**
+ * amdgpu_gfx_rlc_fini - Free BO which used for RLC
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block
+ * and rlc_jump_table_block.
+ */
+void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev)
+{
+       /* save restore block */
+       if (adev->gfx.rlc.save_restore_obj) {
+               amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj,
+                                     &adev->gfx.rlc.save_restore_gpu_addr,
+                                     (void **)&adev->gfx.rlc.sr_ptr);
+       }
+
+       /* clear state block */
+       amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
+                             &adev->gfx.rlc.clear_state_gpu_addr,
+                             (void **)&adev->gfx.rlc.cs_ptr);
+
+       /* jump table block */
+       amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
+                             &adev->gfx.rlc.cp_table_gpu_addr,
+                             (void **)&adev->gfx.rlc.cp_table_ptr);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
new file mode 100644 (file)
index 0000000..49a8ab5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_RLC_H__
+#define __AMDGPU_RLC_H__
+
+#include "clearstate_defs.h"
+
+struct amdgpu_rlc_funcs {
+       bool (*is_rlc_enabled)(struct amdgpu_device *adev);
+       void (*set_safe_mode)(struct amdgpu_device *adev);
+       void (*unset_safe_mode)(struct amdgpu_device *adev);
+       int  (*init)(struct amdgpu_device *adev);
+       u32  (*get_csb_size)(struct amdgpu_device *adev);
+       void (*get_csb_buffer)(struct amdgpu_device *adev, volatile u32 *buffer);
+       int  (*get_cp_table_num)(struct amdgpu_device *adev);
+       int  (*resume)(struct amdgpu_device *adev);
+       void (*stop)(struct amdgpu_device *adev);
+       void (*reset)(struct amdgpu_device *adev);
+       void (*start)(struct amdgpu_device *adev);
+};
+
+struct amdgpu_rlc {
+       /* for power gating */
+       struct amdgpu_bo        *save_restore_obj;
+       uint64_t                save_restore_gpu_addr;
+       volatile uint32_t       *sr_ptr;
+       const u32               *reg_list;
+       u32                     reg_list_size;
+       /* for clear state */
+       struct amdgpu_bo        *clear_state_obj;
+       uint64_t                clear_state_gpu_addr;
+       volatile uint32_t       *cs_ptr;
+       const struct cs_section_def   *cs_data;
+       u32                     clear_state_size;
+       /* for cp tables */
+       struct amdgpu_bo        *cp_table_obj;
+       uint64_t                cp_table_gpu_addr;
+       volatile uint32_t       *cp_table_ptr;
+       u32                     cp_table_size;
+
+       /* safe mode for updating CG/PG state */
+       bool in_safe_mode;
+       const struct amdgpu_rlc_funcs *funcs;
+
+       /* for firmware data */
+       u32 save_and_restore_offset;
+       u32 clear_state_descriptor_offset;
+       u32 avail_scratch_ram_locations;
+       u32 reg_restore_list_size;
+       u32 reg_list_format_start;
+       u32 reg_list_format_separate_start;
+       u32 starting_offsets_start;
+       u32 reg_list_format_size_bytes;
+       u32 reg_list_size_bytes;
+       u32 reg_list_format_direct_reg_list_length;
+       u32 save_restore_list_cntl_size_bytes;
+       u32 save_restore_list_gpm_size_bytes;
+       u32 save_restore_list_srm_size_bytes;
+
+       u32 *register_list_format;
+       u32 *register_restore;
+       u8 *save_restore_list_cntl;
+       u8 *save_restore_list_gpm;
+       u8 *save_restore_list_srm;
+
+       bool is_rlc_v2_1;
+};
+
+void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev);
+int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws);
+int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev);
+int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev);
+
+#endif
index bc9244b429ef11932b87ea96a191ad5af3e60d24..115bb0c99b0ff603ac0124280bf48e1a89f10d8e 100644 (file)
  * GPU SDMA IP block helpers function.
  */
 
-struct amdgpu_sdma_instance * amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
+struct amdgpu_sdma_instance *amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring)
 {
        struct amdgpu_device *adev = ring->adev;
        int i;
 
        for (i = 0; i < adev->sdma.num_instances; i++)
-               if (&adev->sdma.instance[i].ring == ring)
-                       break;
+               if (ring == &adev->sdma.instance[i].ring ||
+                   ring == &adev->sdma.instance[i].page)
+                       return &adev->sdma.instance[i];
 
-       if (i < AMDGPU_MAX_SDMA_INSTANCES)
-               return &adev->sdma.instance[i];
-       else
-               return NULL;
+       return NULL;
+}
+
+int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index)
+{
+       struct amdgpu_device *adev = ring->adev;
+       int i;
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               if (ring == &adev->sdma.instance[i].ring ||
+                       ring == &adev->sdma.instance[i].page) {
+                       *index = i;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
 }
index 500113ec65caaf63a3ba6cc6d1f385b211bf34dc..16b1a6ae5ba6bcb23b42069ccb27954d116a614b 100644 (file)
@@ -41,6 +41,7 @@ struct amdgpu_sdma_instance {
        uint32_t                feature_version;
 
        struct amdgpu_ring      ring;
+       struct amdgpu_ring      page;
        bool                    burst_nop;
 };
 
@@ -50,6 +51,7 @@ struct amdgpu_sdma {
        struct amdgpu_irq_src   illegal_inst_irq;
        int                     num_instances;
        uint32_t                    srbm_soft_reset;
+       bool                    has_page_queue;
 };
 
 /*
@@ -92,6 +94,7 @@ struct amdgpu_buffer_funcs {
 #define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
 
 struct amdgpu_sdma_instance *
-amdgpu_get_sdma_instance(struct amdgpu_ring *ring);
+amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring);
+int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index);
 
 #endif
index e9bf70e2ac5139152cf8e3596cb5713cbd0afd05..626abca770a0367b853000358b580fdc7c82ff22 100644 (file)
@@ -218,6 +218,7 @@ TRACE_EVENT(amdgpu_vm_grab_id,
            TP_ARGS(vm, ring, job),
            TP_STRUCT__entry(
                             __field(u32, pasid)
+                            __string(ring, ring->name)
                             __field(u32, ring)
                             __field(u32, vmid)
                             __field(u32, vm_hub)
@@ -227,14 +228,14 @@ TRACE_EVENT(amdgpu_vm_grab_id,
 
            TP_fast_assign(
                           __entry->pasid = vm->pasid;
-                          __entry->ring = ring->idx;
+                          __assign_str(ring, ring->name)
                           __entry->vmid = job->vmid;
                           __entry->vm_hub = ring->funcs->vmhub,
                           __entry->pd_addr = job->vm_pd_addr;
                           __entry->needs_flush = job->vm_needs_flush;
                           ),
-           TP_printk("pasid=%d, ring=%u, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u",
-                     __entry->pasid, __entry->ring, __entry->vmid,
+           TP_printk("pasid=%d, ring=%s, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u",
+                     __entry->pasid, __get_str(ring), __entry->vmid,
                      __entry->vm_hub, __entry->pd_addr, __entry->needs_flush)
 );
 
@@ -366,20 +367,20 @@ TRACE_EVENT(amdgpu_vm_flush,
                     uint64_t pd_addr),
            TP_ARGS(ring, vmid, pd_addr),
            TP_STRUCT__entry(
-                            __field(u32, ring)
+                            __string(ring, ring->name)
                             __field(u32, vmid)
                             __field(u32, vm_hub)
                             __field(u64, pd_addr)
                             ),
 
            TP_fast_assign(
-                          __entry->ring = ring->idx;
+                          __assign_str(ring, ring->name)
                           __entry->vmid = vmid;
                           __entry->vm_hub = ring->funcs->vmhub;
                           __entry->pd_addr = pd_addr;
                           ),
-           TP_printk("ring=%u, id=%u, hub=%u, pd_addr=%010Lx",
-                     __entry->ring, __entry->vmid,
+           TP_printk("ring=%s, id=%u, hub=%u, pd_addr=%010Lx",
+                     __get_str(ring), __entry->vmid,
                      __entry->vm_hub,__entry->pd_addr)
 );
 
index a44fc12ae1f9eba9eaa7460f536c00f008eaf481..c91ec3101d00b5d06e48db30c71b3cf938d95b63 100644 (file)
@@ -61,100 +61,6 @@ static int amdgpu_map_buffer(struct ttm_buffer_object *bo,
 static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
 static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev);
 
-/*
- * Global memory.
- */
-
-/**
- * amdgpu_ttm_mem_global_init - Initialize and acquire reference to
- * memory object
- *
- * @ref: Object for initialization.
- *
- * This is called by drm_global_item_ref() when an object is being
- * initialized.
- */
-static int amdgpu_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-/**
- * amdgpu_ttm_mem_global_release - Drop reference to a memory object
- *
- * @ref: Object being removed
- *
- * This is called by drm_global_item_unref() when an object is being
- * released.
- */
-static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-/**
- * amdgpu_ttm_global_init - Initialize global TTM memory reference structures.
- *
- * @adev: AMDGPU device for which the global structures need to be registered.
- *
- * This is called as part of the AMDGPU ttm init from amdgpu_ttm_init()
- * during bring up.
- */
-static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       /* ensure reference is false in case init fails */
-       adev->mman.mem_global_referenced = false;
-
-       global_ref = &adev->mman.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &amdgpu_ttm_mem_global_init;
-       global_ref->release = &amdgpu_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               goto error_mem;
-       }
-
-       adev->mman.bo_global_ref.mem_glob =
-               adev->mman.mem_global_ref.object;
-       global_ref = &adev->mman.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               goto error_bo;
-       }
-
-       mutex_init(&adev->mman.gtt_window_lock);
-
-       adev->mman.mem_global_referenced = true;
-
-       return 0;
-
-error_bo:
-       drm_global_item_unref(&adev->mman.mem_global_ref);
-error_mem:
-       return r;
-}
-
-static void amdgpu_ttm_global_fini(struct amdgpu_device *adev)
-{
-       if (adev->mman.mem_global_referenced) {
-               mutex_destroy(&adev->mman.gtt_window_lock);
-               drm_global_item_unref(&adev->mman.bo_global_ref.ref);
-               drm_global_item_unref(&adev->mman.mem_global_ref);
-               adev->mman.mem_global_referenced = false;
-       }
-}
-
 static int amdgpu_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
 {
        return 0;
@@ -1758,14 +1664,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
        int r;
        u64 vis_vram_limit;
 
-       /* initialize global references for vram/gtt */
-       r = amdgpu_ttm_global_init(adev);
-       if (r) {
-               return r;
-       }
+       mutex_init(&adev->mman.gtt_window_lock);
+
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&adev->mman.bdev,
-                              adev->mman.bo_global_ref.ref.object,
                               &amdgpu_bo_driver,
                               adev->ddev->anon_inode->i_mapping,
                               DRM_FILE_PAGE_OFFSET,
@@ -1922,7 +1824,6 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
        ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
        ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
        ttm_bo_device_release(&adev->mman.bdev);
-       amdgpu_ttm_global_fini(adev);
        adev->mman.initialized = false;
        DRM_INFO("amdgpu: ttm finalized\n");
 }
@@ -2069,7 +1970,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
        unsigned i;
        int r;
 
-       if (direct_submit && !ring->ready) {
+       if (direct_submit && !ring->sched.ready) {
                DRM_ERROR("Trying to move memory with ring turned off.\n");
                return -EINVAL;
        }
index fe8f276e9811c02e1bdee63c136e7bcf81afc876..b5b2d101f7db295bc36d7dd2493fbb95e0716d2e 100644 (file)
@@ -39,8 +39,6 @@
 #define AMDGPU_GTT_NUM_TRANSFER_WINDOWS        2
 
 struct amdgpu_mman {
-       struct ttm_bo_global_ref        bo_global_ref;
-       struct drm_global_reference     mem_global_ref;
        struct ttm_bo_device            bdev;
        bool                            mem_global_referenced;
        bool                            initialized;
index aa6641b944a085de9f70638e9d68410995de6680..7ac25a1c78530b67f0c013b75470abb9dd338010 100644 (file)
@@ -57,6 +57,17 @@ struct psp_firmware_header_v1_0 {
        uint32_t sos_size_bytes;
 };
 
+/* version_major=1, version_minor=0 */
+struct ta_firmware_header_v1_0 {
+       struct common_firmware_header header;
+       uint32_t ta_xgmi_ucode_version;
+       uint32_t ta_xgmi_offset_bytes;
+       uint32_t ta_xgmi_size_bytes;
+       uint32_t ta_ras_ucode_version;
+       uint32_t ta_ras_offset_bytes;
+       uint32_t ta_ras_size_bytes;
+};
+
 /* version_major=1, version_minor=0 */
 struct gfx_firmware_header_v1_0 {
        struct common_firmware_header header;
@@ -170,6 +181,7 @@ union amdgpu_firmware_header {
        struct mc_firmware_header_v1_0 mc;
        struct smc_firmware_header_v1_0 smc;
        struct psp_firmware_header_v1_0 psp;
+       struct ta_firmware_header_v1_0 ta;
        struct gfx_firmware_header_v1_0 gfx;
        struct rlc_firmware_header_v1_0 rlc;
        struct rlc_firmware_header_v2_0 rlc_v2_0;
index e5a6db6beab7acfa364fedac5d0ac538458a4570..4e5d13e41f6a75256f0e30c46d19fc80f780662d 100644 (file)
@@ -692,6 +692,8 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
        buf_sizes[0x1] = dpb_size;
        buf_sizes[0x2] = image_size;
        buf_sizes[0x4] = min_ctx_size;
+       /* store image width to adjust nb memory pstate */
+       adev->uvd.decode_image_width = width;
        return 0;
 }
 
@@ -1243,30 +1245,20 @@ int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 {
        struct dma_fence *fence;
        long r;
-       uint32_t ip_instance = ring->me;
 
        r = amdgpu_uvd_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: (%d)failed to get create msg (%ld).\n", ip_instance, r);
+       if (r)
                goto error;
-       }
 
        r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: (%d)failed to get destroy ib (%ld).\n", ip_instance, r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: (%d)IB test timed out.\n", ip_instance);
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: (%d)fence wait failed (%ld).\n", ip_instance, r);
-       } else {
-               DRM_DEBUG("ib test on (%d)ring %d succeeded\n", ip_instance, ring->idx);
+       else if (r > 0)
                r = 0;
-       }
 
        dma_fence_put(fence);
 
index a3ab1a41060f56654fe54ee8e38e2453610797bd..5eb63288d15743bd22d21e142f4184628d0d009f 100644 (file)
@@ -65,6 +65,8 @@ struct amdgpu_uvd {
        struct drm_sched_entity entity;
        struct delayed_work     idle_work;
        unsigned                harvest_config;
+       /* store image width to adjust nb memory state */
+       unsigned                decode_image_width;
 };
 
 int amdgpu_uvd_sw_init(struct amdgpu_device *adev);
index 5f3f540738187c6db03a7975bced71ea4163c9e0..98a1b2ce2b9d38cec778dc2c9a8097661eca27b0 100644 (file)
@@ -1032,8 +1032,10 @@ out:
  * @ib: the IB to execute
  *
  */
-void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
-                            unsigned vmid, bool ctx_switch)
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
+                               struct amdgpu_job *job,
+                               struct amdgpu_ib *ib,
+                               bool ctx_switch)
 {
        amdgpu_ring_write(ring, VCE_CMD_IB);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
@@ -1079,11 +1081,9 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
                return 0;
 
        r = amdgpu_ring_alloc(ring, 16);
-       if (r) {
-               DRM_ERROR("amdgpu: vce failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring, VCE_CMD_END);
        amdgpu_ring_commit(ring);
 
@@ -1093,14 +1093,8 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed\n",
-                         ring->idx);
+       if (i >= timeout)
                r = -ETIMEDOUT;
-       }
 
        return r;
 }
@@ -1121,27 +1115,19 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
                return 0;
 
        r = amdgpu_vce_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
-       } else {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       else if (r > 0)
                r = 0;
-       }
+
 error:
        dma_fence_put(fence);
        return r;
index a1f209eed4c477498ee932a0f02e47fdff993137..50293652af148cc3c8fa2d04d8b7723e8b744e32 100644 (file)
@@ -65,8 +65,8 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
 void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
 int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
 int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
-void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
-                            unsigned vmid, bool ctx_switch);
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
+                               struct amdgpu_ib *ib, bool ctx_switch);
 void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
                                unsigned flags);
 int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
index 27da13df2f113b72a959156f187c013252d3319e..e2e42e3fbcf3365c659fc6281626e0adc6cf40e0 100644 (file)
@@ -425,11 +425,9 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
 
        WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring,
                PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -441,14 +439,9 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
        return r;
 }
 
@@ -570,30 +563,20 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_vcn_dec_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
-       } else {
-               DRM_DEBUG("ib test on ring %d succeeded\n",  ring->idx);
+       else if (r > 0)
                r = 0;
-       }
 
        dma_fence_put(fence);
-
 error:
        return r;
 }
@@ -606,11 +589,9 @@ int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_ring_alloc(ring, 16);
-       if (r) {
-               DRM_ERROR("amdgpu: vcn enc failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring, VCN_ENC_CMD_END);
        amdgpu_ring_commit(ring);
 
@@ -620,14 +601,8 @@ int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed\n",
-                         ring->idx);
+       if (i >= adev->usec_timeout)
                r = -ETIMEDOUT;
-       }
 
        return r;
 }
@@ -742,27 +717,19 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_vcn_enc_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
-       } else {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       else if (r > 0)
                r = 0;
-       }
+
 error:
        dma_fence_put(fence);
        return r;
@@ -778,11 +745,8 @@ int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
        WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
 
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                                 ring->idx, r);
+       if (r)
                return r;
-       }
 
        amdgpu_ring_write(ring,
                PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0, 0, 0));
@@ -796,14 +760,8 @@ int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                                 ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                                 ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
        return r;
 }
@@ -856,21 +814,18 @@ int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r = 0;
 
        r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
                r = -ETIMEDOUT;
                goto error;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto error;
-       } else
+       } else {
                r = 0;
+       }
 
        for (i = 0; i < adev->usec_timeout; i++) {
                tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9));
@@ -879,15 +834,10 @@ int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout)
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
-       else {
-               DRM_ERROR("ib test failed (0x%08X)\n", tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
        dma_fence_put(fence);
-
 error:
        return r;
 }
index f2f358aa059717194fd02fe41fbfc0c04bc0b26a..462a04e0f5e6bab450d710eb718ba1cfe193b60f 100644 (file)
 
 #include "amdgpu.h"
 
-uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev)
-{
-       uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT;
-
-       addr -= AMDGPU_VA_RESERVED_SIZE;
-       addr = amdgpu_gmc_sign_extend(addr);
-
-       return addr;
-}
-
 bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
 {
        /* By now all MMIO pages except mailbox are blocked */
@@ -41,88 +31,6 @@ bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
        return RREG32_NO_KIQ(0xc040) == 0xffffffff;
 }
 
-int amdgpu_allocate_static_csa(struct amdgpu_device *adev)
-{
-       int r;
-       void *ptr;
-
-       r = amdgpu_bo_create_kernel(adev, AMDGPU_CSA_SIZE, PAGE_SIZE,
-                               AMDGPU_GEM_DOMAIN_VRAM, &adev->virt.csa_obj,
-                               &adev->virt.csa_vmid0_addr, &ptr);
-       if (r)
-               return r;
-
-       memset(ptr, 0, AMDGPU_CSA_SIZE);
-       return 0;
-}
-
-void amdgpu_free_static_csa(struct amdgpu_device *adev) {
-       amdgpu_bo_free_kernel(&adev->virt.csa_obj,
-                                               &adev->virt.csa_vmid0_addr,
-                                               NULL);
-}
-
-/*
- * amdgpu_map_static_csa should be called during amdgpu_vm_init
- * it maps virtual address amdgpu_csa_vaddr() to this VM, and each command
- * submission of GFX should use this virtual address within META_DATA init
- * package to support SRIOV gfx preemption.
- */
-int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
-                         struct amdgpu_bo_va **bo_va)
-{
-       uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_GMC_HOLE_MASK;
-       struct ww_acquire_ctx ticket;
-       struct list_head list;
-       struct amdgpu_bo_list_entry pd;
-       struct ttm_validate_buffer csa_tv;
-       int r;
-
-       INIT_LIST_HEAD(&list);
-       INIT_LIST_HEAD(&csa_tv.head);
-       csa_tv.bo = &adev->virt.csa_obj->tbo;
-       csa_tv.shared = true;
-
-       list_add(&csa_tv.head, &list);
-       amdgpu_vm_get_pd_bo(vm, &list, &pd);
-
-       r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
-       if (r) {
-               DRM_ERROR("failed to reserve CSA,PD BOs: err=%d\n", r);
-               return r;
-       }
-
-       *bo_va = amdgpu_vm_bo_add(adev, vm, adev->virt.csa_obj);
-       if (!*bo_va) {
-               ttm_eu_backoff_reservation(&ticket, &list);
-               DRM_ERROR("failed to create bo_va for static CSA\n");
-               return -ENOMEM;
-       }
-
-       r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, csa_addr,
-                               AMDGPU_CSA_SIZE);
-       if (r) {
-               DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r);
-               amdgpu_vm_bo_rmv(adev, *bo_va);
-               ttm_eu_backoff_reservation(&ticket, &list);
-               return r;
-       }
-
-       r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, AMDGPU_CSA_SIZE,
-                            AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
-                            AMDGPU_PTE_EXECUTABLE);
-
-       if (r) {
-               DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
-               amdgpu_vm_bo_rmv(adev, *bo_va);
-               ttm_eu_backoff_reservation(&ticket, &list);
-               return r;
-       }
-
-       ttm_eu_backoff_reservation(&ticket, &list);
-       return 0;
-}
-
 void amdgpu_virt_init_setting(struct amdgpu_device *adev)
 {
        /* enable virtual display */
@@ -162,9 +70,7 @@ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
        if (r < 1 && (adev->in_gpu_reset || in_interrupt()))
                goto failed_kiq_read;
 
-       if (in_interrupt())
-               might_sleep();
-
+       might_sleep();
        while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
                msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
                r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
@@ -210,9 +116,7 @@ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
        if (r < 1 && (adev->in_gpu_reset || in_interrupt()))
                goto failed_kiq_write;
 
-       if (in_interrupt())
-               might_sleep();
-
+       might_sleep();
        while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
 
                msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
@@ -228,6 +132,46 @@ failed_kiq_write:
        pr_err("failed to write reg:%x\n", reg);
 }
 
+void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
+                                       uint32_t reg0, uint32_t reg1,
+                                       uint32_t ref, uint32_t mask)
+{
+       struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+       struct amdgpu_ring *ring = &kiq->ring;
+       signed long r, cnt = 0;
+       unsigned long flags;
+       uint32_t seq;
+
+       spin_lock_irqsave(&kiq->ring_lock, flags);
+       amdgpu_ring_alloc(ring, 32);
+       amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1,
+                                           ref, mask);
+       amdgpu_fence_emit_polling(ring, &seq);
+       amdgpu_ring_commit(ring);
+       spin_unlock_irqrestore(&kiq->ring_lock, flags);
+
+       r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+
+       /* don't wait anymore for IRQ context */
+       if (r < 1 && in_interrupt())
+               goto failed_kiq;
+
+       might_sleep();
+       while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
+
+               msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
+               r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+       }
+
+       if (cnt > MAX_KIQ_REG_TRY)
+               goto failed_kiq;
+
+       return;
+
+failed_kiq:
+       pr_err("failed to write reg %x wait reg %x\n", reg0, reg1);
+}
+
 /**
  * amdgpu_virt_request_full_gpu() - request full gpu access
  * @amdgpu:    amdgpu device.
@@ -390,7 +334,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
 
        if (adev->fw_vram_usage.va != NULL) {
                adev->virt.fw_reserve.p_pf2vf =
-                       (struct amdgim_pf2vf_info_header *)(
+                       (struct amd_sriov_msg_pf2vf_info_header *)(
                        adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET);
                AMDGPU_FW_VRAM_PF2VF_READ(adev, header.size, &pf2vf_size);
                AMDGPU_FW_VRAM_PF2VF_READ(adev, checksum, &checksum);
index 880ac113a3a9f38d64179dc4311a981939564e4f..722deefc0a7ee0e9f0e613d2fa9e5b90438aaf6b 100644 (file)
@@ -63,8 +63,8 @@ struct amdgpu_virt_ops {
  * Firmware Reserve Frame buffer
  */
 struct amdgpu_virt_fw_reserve {
-       struct amdgim_pf2vf_info_header *p_pf2vf;
-       struct amdgim_vf2pf_info_header *p_vf2pf;
+       struct amd_sriov_msg_pf2vf_info_header *p_pf2vf;
+       struct amd_sriov_msg_vf2pf_info_header *p_vf2pf;
        unsigned int checksum_key;
 };
 /*
@@ -85,15 +85,17 @@ enum AMDGIM_FEATURE_FLAG {
        AMDGIM_FEATURE_GIM_FLR_VRAMLOST = 0x4,
 };
 
-struct amdgim_pf2vf_info_header {
+struct amd_sriov_msg_pf2vf_info_header {
        /* the total structure size in byte. */
        uint32_t size;
        /* version of this structure, written by the GIM */
        uint32_t version;
+       /* reserved */
+       uint32_t reserved[2];
 } __aligned(4);
 struct  amdgim_pf2vf_info_v1 {
        /* header contains size and version */
-       struct amdgim_pf2vf_info_header header;
+       struct amd_sriov_msg_pf2vf_info_header header;
        /* max_width * max_height */
        unsigned int uvd_enc_max_pixels_count;
        /* 16x16 pixels/sec, codec independent */
@@ -112,7 +114,7 @@ struct  amdgim_pf2vf_info_v1 {
 
 struct  amdgim_pf2vf_info_v2 {
        /* header contains size and version */
-       struct amdgim_pf2vf_info_header header;
+       struct amd_sriov_msg_pf2vf_info_header header;
        /* use private key from mailbox 2 to create chueksum */
        uint32_t checksum;
        /* The features flags of the GIM driver supports. */
@@ -137,20 +139,22 @@ struct  amdgim_pf2vf_info_v2 {
        uint64_t vcefw_kboffset;
        /* VCE FW size in KB */
        uint32_t vcefw_ksize;
-       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 0, 0, (9 + sizeof(struct amdgim_pf2vf_info_header)/sizeof(uint32_t)), 3)];
+       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 0, 0, (9 + sizeof(struct amd_sriov_msg_pf2vf_info_header)/sizeof(uint32_t)), 3)];
 } __aligned(4);
 
 
-struct amdgim_vf2pf_info_header {
+struct amd_sriov_msg_vf2pf_info_header {
        /* the total structure size in byte. */
        uint32_t size;
        /*version of this structure, written by the guest */
        uint32_t version;
+       /* reserved */
+       uint32_t reserved[2];
 } __aligned(4);
 
 struct amdgim_vf2pf_info_v1 {
        /* header contains size and version */
-       struct amdgim_vf2pf_info_header header;
+       struct amd_sriov_msg_vf2pf_info_header header;
        /* driver version */
        char driver_version[64];
        /* driver certification, 1=WHQL, 0=None */
@@ -180,7 +184,7 @@ struct amdgim_vf2pf_info_v1 {
 
 struct amdgim_vf2pf_info_v2 {
        /* header contains size and version */
-       struct amdgim_vf2pf_info_header header;
+       struct amd_sriov_msg_vf2pf_info_header header;
        uint32_t checksum;
        /* driver version */
        uint8_t driver_version[64];
@@ -206,7 +210,7 @@ struct amdgim_vf2pf_info_v2 {
        uint32_t uvd_enc_usage;
        /* guest uvd engine usage percentage. 0xffff means N/A. */
        uint32_t uvd_enc_health;
-       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, (12 + sizeof(struct amdgim_vf2pf_info_header)/sizeof(uint32_t)), 0)];
+       uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, (12 + sizeof(struct amd_sriov_msg_vf2pf_info_header)/sizeof(uint32_t)), 0)];
 } __aligned(4);
 
 #define AMDGPU_FW_VRAM_VF2PF_VER 2
@@ -238,7 +242,6 @@ typedef struct amdgim_vf2pf_info_v2 amdgim_vf2pf_info ;
 struct amdgpu_virt {
        uint32_t                        caps;
        struct amdgpu_bo                *csa_obj;
-       uint64_t                        csa_vmid0_addr;
        bool chained_ib_support;
        uint32_t                        reg_val_offs;
        struct amdgpu_irq_src           ack_irq;
@@ -251,8 +254,6 @@ struct amdgpu_virt {
        uint32_t gim_feature;
 };
 
-#define AMDGPU_CSA_SIZE                (8 * 1024)
-
 #define amdgpu_sriov_enabled(adev) \
 ((adev)->virt.caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
 
@@ -277,17 +278,13 @@ static inline bool is_virtual_machine(void)
 #endif
 }
 
-struct amdgpu_vm;
-
-uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev);
 bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev);
-int amdgpu_allocate_static_csa(struct amdgpu_device *adev);
-int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
-                         struct amdgpu_bo_va **bo_va);
-void amdgpu_free_static_csa(struct amdgpu_device *adev);
 void amdgpu_virt_init_setting(struct amdgpu_device *adev);
 uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg);
 void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v);
+void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
+                                       uint32_t reg0, uint32_t rreg1,
+                                       uint32_t ref, uint32_t mask);
 int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init);
 int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init);
 int amdgpu_virt_reset_gpu(struct amdgpu_device *adev);
index 0877ff9a959445ad77a263f2ba1105ec5e795822..e73d152659a2f236f83b38996290facc7981581c 100644 (file)
@@ -617,7 +617,8 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
 {
        entry->priority = 0;
        entry->tv.bo = &vm->root.base.bo->tbo;
-       entry->tv.shared = true;
+       /* One for the VM updates, one for TTM and one for the CS job */
+       entry->tv.num_shared = 3;
        entry->user_pages = NULL;
        list_add(&entry->tv.head, validated);
 }
@@ -773,10 +774,6 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
 
        ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched);
 
-       r = reservation_object_reserve_shared(bo->tbo.resv);
-       if (r)
-               return r;
-
        r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
        if (r)
                goto error;
@@ -1844,10 +1841,6 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
        if (r)
                goto error_free;
 
-       r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv);
-       if (r)
-               goto error_free;
-
        r = amdgpu_vm_update_ptes(&params, start, last + 1, addr, flags);
        if (r)
                goto error_free;
@@ -3028,6 +3021,10 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
        if (r)
                goto error_free_root;
 
+       r = reservation_object_reserve_shared(root->tbo.resv, 1);
+       if (r)
+               goto error_unreserve;
+
        r = amdgpu_vm_clear_bo(adev, vm, root,
                               adev->vm_manager.root_level,
                               vm->pte_support_ats);
@@ -3057,7 +3054,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
        }
 
        INIT_KFIFO(vm->faults);
-       vm->fault_credit = 16;
 
        return 0;
 
@@ -3269,42 +3265,6 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
                amdgpu_vmid_free_reserved(adev, vm, i);
 }
 
-/**
- * amdgpu_vm_pasid_fault_credit - Check fault credit for given PASID
- *
- * @adev: amdgpu_device pointer
- * @pasid: PASID do identify the VM
- *
- * This function is expected to be called in interrupt context.
- *
- * Returns:
- * True if there was fault credit, false otherwise
- */
-bool amdgpu_vm_pasid_fault_credit(struct amdgpu_device *adev,
-                                 unsigned int pasid)
-{
-       struct amdgpu_vm *vm;
-
-       spin_lock(&adev->vm_manager.pasid_lock);
-       vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
-       if (!vm) {
-               /* VM not found, can't track fault credit */
-               spin_unlock(&adev->vm_manager.pasid_lock);
-               return true;
-       }
-
-       /* No lock needed. only accessed by IRQ handler */
-       if (!vm->fault_credit) {
-               /* Too many faults in this VM */
-               spin_unlock(&adev->vm_manager.pasid_lock);
-               return false;
-       }
-
-       vm->fault_credit--;
-       spin_unlock(&adev->vm_manager.pasid_lock);
-       return true;
-}
-
 /**
  * amdgpu_vm_manager_init - init the VM manager
  *
index 2a8898d19c8b58076dd88526a4304e3104a67866..e8dcfd59fc93353468aaada4c42e6ab4ca6d85a5 100644 (file)
@@ -229,9 +229,6 @@ struct amdgpu_vm {
        /* Up to 128 pending retry page faults */
        DECLARE_KFIFO(faults, u64, 128);
 
-       /* Limit non-retry fault storms */
-       unsigned int            fault_credit;
-
        /* Points to the KFD process VM info */
        struct amdkfd_process_info *process_info;
 
@@ -299,8 +296,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
 int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned int pasid);
 void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm);
 void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-bool amdgpu_vm_pasid_fault_credit(struct amdgpu_device *adev,
-                                 unsigned int pasid);
 void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
                         struct list_head *validated,
                         struct amdgpu_bo_list_entry *entry);
index 897afbb348c1cb8db5e9164e16f019a36a3661b5..0b263a9857c6496d95a42d385099d897408e301d 100644 (file)
@@ -23,7 +23,7 @@
  */
 #include <linux/list.h>
 #include "amdgpu.h"
-#include "amdgpu_psp.h"
+#include "amdgpu_xgmi.h"
 
 
 static DEFINE_MUTEX(xgmi_mutex);
@@ -31,15 +31,16 @@ static DEFINE_MUTEX(xgmi_mutex);
 #define AMDGPU_MAX_XGMI_HIVE                   8
 #define AMDGPU_MAX_XGMI_DEVICE_PER_HIVE                4
 
-struct amdgpu_hive_info {
-       uint64_t                hive_id;
-       struct list_head        device_list;
-};
-
 static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE];
 static unsigned hive_count = 0;
 
-static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
+
+void *amdgpu_xgmi_hive_try_lock(struct amdgpu_hive_info *hive)
+{
+       return &hive->device_list;
+}
+
+struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
 {
        int i;
        struct amdgpu_hive_info *tmp;
@@ -58,62 +59,99 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
        tmp = &xgmi_hives[hive_count++];
        tmp->hive_id = adev->gmc.xgmi.hive_id;
        INIT_LIST_HEAD(&tmp->device_list);
+       mutex_init(&tmp->hive_lock);
+
        return tmp;
 }
 
+int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev)
+{
+       int ret = -EINVAL;
+
+       /* Each psp need to set the latest topology */
+       ret = psp_xgmi_set_topology_info(&adev->psp,
+                                        hive->number_devices,
+                                        &hive->topology_info);
+       if (ret)
+               dev_err(adev->dev,
+                       "XGMI: Set topology failure on device %llx, hive %llx, ret %d",
+                       adev->gmc.xgmi.node_id,
+                       adev->gmc.xgmi.hive_id, ret);
+       else
+               dev_info(adev->dev, "XGMI: Set topology for node %d, hive 0x%llx.\n",
+                        adev->gmc.xgmi.physical_node_id,
+                                adev->gmc.xgmi.hive_id);
+
+       return ret;
+}
+
 int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
 {
-       struct psp_xgmi_topology_info tmp_topology[AMDGPU_MAX_XGMI_DEVICE_PER_HIVE];
+       struct psp_xgmi_topology_info *hive_topology;
        struct amdgpu_hive_info *hive;
        struct amdgpu_xgmi      *entry;
-       struct amdgpu_device    *tmp_adev;
+       struct amdgpu_device *tmp_adev = NULL;
 
        int count = 0, ret = -EINVAL;
 
-       if ((adev->asic_type < CHIP_VEGA20) ||
-               (adev->flags & AMD_IS_APU) )
+       if (!adev->gmc.xgmi.supported)
                return 0;
-       adev->gmc.xgmi.device_id = psp_xgmi_get_device_id(&adev->psp);
+
+       adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp);
        adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp);
 
-       memset(&tmp_topology[0], 0, sizeof(tmp_topology));
        mutex_lock(&xgmi_mutex);
        hive = amdgpu_get_xgmi_hive(adev);
        if (!hive)
                goto exit;
 
+       hive_topology = &hive->topology_info;
+
        list_add_tail(&adev->gmc.xgmi.head, &hive->device_list);
        list_for_each_entry(entry, &hive->device_list, head)
-               tmp_topology[count++].device_id = entry->device_id;
+               hive_topology->nodes[count++].node_id = entry->node_id;
+       hive->number_devices = count;
 
-       ret = psp_xgmi_get_topology_info(&adev->psp, count, tmp_topology);
-       if (ret) {
-               dev_err(adev->dev,
-                       "XGMI: Get topology failure on device %llx, hive %llx, ret %d",
-                       adev->gmc.xgmi.device_id,
-                       adev->gmc.xgmi.hive_id, ret);
-               goto exit;
-       }
-       /* Each psp need to set the latest topology */
+       /* Each psp need to get the latest topology */
        list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
-               ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology);
+               ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, hive_topology);
                if (ret) {
                        dev_err(tmp_adev->dev,
-                               "XGMI: Set topology failure on device %llx, hive %llx, ret %d",
-                               tmp_adev->gmc.xgmi.device_id,
+                               "XGMI: Get topology failure on device %llx, hive %llx, ret %d",
+                               tmp_adev->gmc.xgmi.node_id,
                                tmp_adev->gmc.xgmi.hive_id, ret);
-                       /* To do : continue with some  node failed or disable the  whole  hive */
+                       /* To do : continue with some node failed or disable the whole hive */
                        break;
                }
        }
-       if (!ret)
-               dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n",
-                       adev->gmc.xgmi.physical_node_id,
-                       adev->gmc.xgmi.hive_id);
+
+       list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
+               ret = amdgpu_xgmi_update_topology(hive, tmp_adev);
+               if (ret)
+                       break;
+       }
 
 exit:
        mutex_unlock(&xgmi_mutex);
        return ret;
 }
 
+void amdgpu_xgmi_remove_device(struct amdgpu_device *adev)
+{
+       struct amdgpu_hive_info *hive;
 
+       if (!adev->gmc.xgmi.supported)
+               return;
+
+       mutex_lock(&xgmi_mutex);
+
+       hive = amdgpu_get_xgmi_hive(adev);
+       if (!hive)
+               goto exit;
+
+       if (!(hive->number_devices--))
+               mutex_destroy(&hive->hive_lock);
+
+exit:
+       mutex_unlock(&xgmi_mutex);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
new file mode 100644 (file)
index 0000000..6151eb9
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __AMDGPU_XGMI_H__
+#define __AMDGPU_XGMI_H__
+
+#include "amdgpu_psp.h"
+
+struct amdgpu_hive_info {
+       uint64_t                hive_id;
+       struct list_head        device_list;
+       struct psp_xgmi_topology_info   topology_info;
+       int number_devices;
+       struct mutex hive_lock;
+};
+
+struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev);
+int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev);
+int amdgpu_xgmi_add_device(struct amdgpu_device *adev);
+void amdgpu_xgmi_remove_device(struct amdgpu_device *adev);
+
+#endif
index 79220a91abe3d48c32ef68c007efc07ee98b1638..86e14c754dd4755163f88f97b7b8a89079bc3fbe 100644 (file)
@@ -743,19 +743,19 @@ static int ci_enable_didt(struct amdgpu_device *adev, bool enable)
 
        if (pi->caps_sq_ramping || pi->caps_db_ramping ||
            pi->caps_td_ramping || pi->caps_tcp_ramping) {
-               adev->gfx.rlc.funcs->enter_safe_mode(adev);
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
 
                if (enable) {
                        ret = ci_program_pt_config_registers(adev, didt_config_ci);
                        if (ret) {
-                               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+                               amdgpu_gfx_rlc_exit_safe_mode(adev);
                                return ret;
                        }
                }
 
                ci_do_enable_didt(adev, enable);
 
-               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
        }
 
        return 0;
index f41f5f57e9f3606d0f26c0fb134133daf7509198..71c50d8900e39137f7749c6a94f41426da32e711 100644 (file)
@@ -1755,6 +1755,7 @@ static const struct amdgpu_asic_funcs cik_asic_funcs =
        .flush_hdp = &cik_flush_hdp,
        .invalidate_hdp = &cik_invalidate_hdp,
        .need_full_reset = &cik_need_full_reset,
+       .init_doorbell_index = &legacy_doorbell_index_init,
 };
 
 static int cik_common_early_init(void *handle)
index e49c6f15a0a00f58891856dfd6e56a851268034e..54c625a2e57054568f3498236186822cc55ed2d3 100644 (file)
@@ -30,4 +30,5 @@ void cik_srbm_select(struct amdgpu_device *adev,
                     u32 me, u32 pipe, u32 queue, u32 vmid);
 int cik_set_ip_blocks(struct amdgpu_device *adev);
 
+void legacy_doorbell_index_init(struct amdgpu_device *adev);
 #endif
index b5775c6a857ba63148d21df914509263383326d0..8a8b4967a101fca3b8daca0908ce39fc2247ae4b 100644 (file)
@@ -228,34 +228,6 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
  * [127:96] - reserved
  */
 
-/**
- * cik_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool cik_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       u32 ring_index = adev->irq.ih.rptr >> 2;
-       u16 pasid;
-
-       switch (le32_to_cpu(adev->irq.ih.ring[ring_index]) & 0xff) {
-       case 146:
-       case 147:
-               pasid = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]) >> 16;
-               if (!pasid || amdgpu_vm_pasid_fault_credit(adev, pasid))
-                       return true;
-               break;
-       default:
-               /* Not a VM fault */
-               return true;
-       }
-
-       adev->irq.ih.rptr += 16;
-       return false;
-}
-
  /**
  * cik_ih_decode_iv - decode an interrupt vector
  *
@@ -461,7 +433,6 @@ static const struct amd_ip_funcs cik_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs cik_ih_funcs = {
        .get_wptr = cik_ih_get_wptr,
-       .prescreen_iv = cik_ih_prescreen_iv,
        .decode_iv = cik_ih_decode_iv,
        .set_rptr = cik_ih_set_rptr
 };
index b918c8886b75c4104d2fc5b03c7863bf9a4d6e41..45795191de1ff9865153ba04f926aef38500cc22 100644 (file)
@@ -198,7 +198,7 @@ static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring)
 
 static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        int i;
 
        for (i = 0; i < count; i++)
@@ -218,9 +218,11 @@ static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
  * Schedule an IB in the DMA ring (CIK).
  */
 static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 extra_bits = vmid & 0xf;
 
        /* IB packet must end on a 8 DW boundary */
@@ -316,8 +318,8 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev)
                WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl);
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], 0);
        }
-       sdma0->ready = false;
-       sdma1->ready = false;
+       sdma0->sched.ready = false;
+       sdma1->sched.ready = false;
 }
 
 /**
@@ -494,18 +496,16 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev)
                /* enable DMA IBs */
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
 
-               ring->ready = true;
+               ring->sched.ready = true;
        }
 
        cik_sdma_enable(adev, true);
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
                ring = &adev->sdma.instance[i].ring;
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
                        return r;
-               }
 
                if (adev->mman.buffer_funcs_ring == ring)
                        amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -618,21 +618,17 @@ static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
 
        r = amdgpu_ring_alloc(ring, 5);
-       if (r) {
-               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_device_wb_free(adev, index);
-               return r;
-       }
+       if (r)
+               goto error_free_wb;
+
        amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
        amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
        amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
@@ -647,15 +643,11 @@ static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       amdgpu_device_wb_free(adev, index);
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
+error_free_wb:
+       amdgpu_device_wb_free(adev, index);
        return r;
 }
 
@@ -678,20 +670,16 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err0;
-       }
 
        ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE,
                                SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
@@ -706,21 +694,16 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err1;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err1;
        }
        tmp = le32_to_cpu(adev->wb.wb[index]);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+       else
                r = -EINVAL;
-       }
 
 err1:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -822,7 +805,7 @@ static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
  */
 static void cik_sdma_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        u32 pad_count;
        int i;
 
@@ -1214,8 +1197,11 @@ static int cik_sdma_process_illegal_inst_irq(struct amdgpu_device *adev,
                                             struct amdgpu_irq_src *source,
                                             struct amdgpu_iv_entry *entry)
 {
+       u8 instance_id;
+
        DRM_ERROR("Illegal instruction in SDMA command stream\n");
-       schedule_work(&adev->reset_work);
+       instance_id = (entry->ring_id & 0x3) >> 0;
+       drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
        return 0;
 }
 
index df5ac4d85a00a5767011c398904a92ab11edce37..9d3ea298e116de7a0fa14e5858b50444ddd7dd46 100644 (file)
@@ -207,34 +207,6 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
        return (wptr & adev->irq.ih.ptr_mask);
 }
 
-/**
- * cz_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool cz_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       u32 ring_index = adev->irq.ih.rptr >> 2;
-       u16 pasid;
-
-       switch (le32_to_cpu(adev->irq.ih.ring[ring_index]) & 0xff) {
-       case 146:
-       case 147:
-               pasid = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]) >> 16;
-               if (!pasid || amdgpu_vm_pasid_fault_credit(adev, pasid))
-                       return true;
-               break;
-       default:
-               /* Not a VM fault */
-               return true;
-       }
-
-       adev->irq.ih.rptr += 16;
-       return false;
-}
-
 /**
  * cz_ih_decode_iv - decode an interrupt vector
  *
@@ -442,7 +414,6 @@ static const struct amd_ip_funcs cz_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs cz_ih_funcs = {
        .get_wptr = cz_ih_get_wptr,
-       .prescreen_iv = cz_ih_prescreen_iv,
        .decode_iv = cz_ih_decode_iv,
        .set_rptr = cz_ih_set_rptr
 };
index d76eb27945dc897230640e1727cc2b8def35f1cb..1dc3013ea1d5401120bb9f87393ca7875903d676 100644 (file)
@@ -1775,18 +1775,15 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
 
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_gfx_scratch_free(adev, scratch);
-               return r;
-       }
+       if (r)
+               goto error_free_scratch;
+
        amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
        amdgpu_ring_write(ring, (scratch - PACKET3_SET_CONFIG_REG_START));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -1798,13 +1795,11 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
                        break;
                DRM_UDELAY(1);
        }
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
-                         ring->idx, scratch, tmp);
-               r = -EINVAL;
-       }
+
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
+error_free_scratch:
        amdgpu_gfx_scratch_free(adev, scratch);
        return r;
 }
@@ -1845,9 +1840,11 @@ static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
 }
 
 static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 header, control = 0;
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
@@ -1892,17 +1889,15 @@ static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err1;
-       }
+
        ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
        ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_START));
        ib.ptr[2] = 0xDEADBEEF;
@@ -1914,22 +1909,16 @@ static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err2;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err2;
        }
        tmp = RREG32(scratch);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
-                         scratch, tmp);
+       else
                r = -EINVAL;
-       }
 
 err2:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -1950,9 +1939,9 @@ static void gfx_v6_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
                                      CP_ME_CNTL__CE_HALT_MASK));
                WREG32(mmSCRATCH_UMSK, 0);
                for (i = 0; i < adev->gfx.num_gfx_rings; i++)
-                       adev->gfx.gfx_ring[i].ready = false;
+                       adev->gfx.gfx_ring[i].sched.ready = false;
                for (i = 0; i < adev->gfx.num_compute_rings; i++)
-                       adev->gfx.compute_ring[i].ready = false;
+                       adev->gfx.compute_ring[i].sched.ready = false;
        }
        udelay(50);
 }
@@ -2124,12 +2113,9 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
 
        /* start the rings */
        gfx_v6_0_cp_gfx_start(adev);
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                return r;
-       }
 
        return 0;
 }
@@ -2227,14 +2213,11 @@ static int gfx_v6_0_cp_compute_resume(struct amdgpu_device *adev)
        WREG32(mmCP_RB2_CNTL, tmp);
        WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
 
-       adev->gfx.compute_ring[0].ready = false;
-       adev->gfx.compute_ring[1].ready = false;
 
        for (i = 0; i < 2; i++) {
-               r = amdgpu_ring_test_ring(&adev->gfx.compute_ring[i]);
+               r = amdgpu_ring_test_helper(&adev->gfx.compute_ring[i]);
                if (r)
                        return r;
-               adev->gfx.compute_ring[i].ready = true;
        }
 
        return 0;
@@ -2368,18 +2351,11 @@ static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, val);
 }
 
-static void gfx_v6_0_rlc_fini(struct amdgpu_device *adev)
-{
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, NULL, NULL);
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
-}
-
 static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
 {
        const u32 *src_ptr;
        volatile u32 *dst_ptr;
-       u32 dws, i;
+       u32 dws;
        u64 reg_list_mc_addr;
        const struct cs_section_def *cs_data;
        int r;
@@ -2394,26 +2370,10 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
        cs_data = adev->gfx.rlc.cs_data;
 
        if (src_ptr) {
-               /* save restore block */
-               r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
-                                             AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.save_restore_obj,
-                                             &adev->gfx.rlc.save_restore_gpu_addr,
-                                             (void **)&adev->gfx.rlc.sr_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create RLC sr bo failed\n",
-                                r);
-                       gfx_v6_0_rlc_fini(adev);
+               /* init save restore block */
+               r = amdgpu_gfx_rlc_init_sr(adev, dws);
+               if (r)
                        return r;
-               }
-
-               /* write the sr buffer */
-               dst_ptr = adev->gfx.rlc.sr_ptr;
-               for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
-                       dst_ptr[i] = cpu_to_le32(src_ptr[i]);
-
-               amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
        }
 
        if (cs_data) {
@@ -2428,7 +2388,7 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
                                              (void **)&adev->gfx.rlc.cs_ptr);
                if (r) {
                        dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
-                       gfx_v6_0_rlc_fini(adev);
+                       amdgpu_gfx_rlc_fini(adev);
                        return r;
                }
 
@@ -2549,8 +2509,8 @@ static int gfx_v6_0_rlc_resume(struct amdgpu_device *adev)
        if (!adev->gfx.rlc_fw)
                return -EINVAL;
 
-       gfx_v6_0_rlc_stop(adev);
-       gfx_v6_0_rlc_reset(adev);
+       adev->gfx.rlc.funcs->stop(adev);
+       adev->gfx.rlc.funcs->reset(adev);
        gfx_v6_0_init_pg(adev);
        gfx_v6_0_init_cg(adev);
 
@@ -2578,7 +2538,7 @@ static int gfx_v6_0_rlc_resume(struct amdgpu_device *adev)
        WREG32(mmRLC_UCODE_ADDR, 0);
 
        gfx_v6_0_enable_lbpw(adev, gfx_v6_0_lbpw_supported(adev));
-       gfx_v6_0_rlc_start(adev);
+       adev->gfx.rlc.funcs->start(adev);
 
        return 0;
 }
@@ -3075,6 +3035,14 @@ static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
        .select_me_pipe_q = &gfx_v6_0_select_me_pipe_q
 };
 
+static const struct amdgpu_rlc_funcs gfx_v6_0_rlc_funcs = {
+       .init = gfx_v6_0_rlc_init,
+       .resume = gfx_v6_0_rlc_resume,
+       .stop = gfx_v6_0_rlc_stop,
+       .reset = gfx_v6_0_rlc_reset,
+       .start = gfx_v6_0_rlc_start
+};
+
 static int gfx_v6_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -3082,6 +3050,7 @@ static int gfx_v6_0_early_init(void *handle)
        adev->gfx.num_gfx_rings = GFX6_NUM_GFX_RINGS;
        adev->gfx.num_compute_rings = GFX6_NUM_COMPUTE_RINGS;
        adev->gfx.funcs = &gfx_v6_0_gfx_funcs;
+       adev->gfx.rlc.funcs = &gfx_v6_0_rlc_funcs;
        gfx_v6_0_set_ring_funcs(adev);
        gfx_v6_0_set_irq_funcs(adev);
 
@@ -3114,7 +3083,7 @@ static int gfx_v6_0_sw_init(void *handle)
                return r;
        }
 
-       r = gfx_v6_0_rlc_init(adev);
+       r = adev->gfx.rlc.funcs->init(adev);
        if (r) {
                DRM_ERROR("Failed to init rlc BOs!\n");
                return r;
@@ -3165,7 +3134,7 @@ static int gfx_v6_0_sw_fini(void *handle)
        for (i = 0; i < adev->gfx.num_compute_rings; i++)
                amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
 
-       gfx_v6_0_rlc_fini(adev);
+       amdgpu_gfx_rlc_fini(adev);
 
        return 0;
 }
@@ -3177,7 +3146,7 @@ static int gfx_v6_0_hw_init(void *handle)
 
        gfx_v6_0_constants_init(adev);
 
-       r = gfx_v6_0_rlc_resume(adev);
+       r = adev->gfx.rlc.funcs->resume(adev);
        if (r)
                return r;
 
@@ -3195,7 +3164,7 @@ static int gfx_v6_0_hw_fini(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        gfx_v6_0_cp_enable(adev, false);
-       gfx_v6_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
        gfx_v6_0_fini_pg(adev);
 
        return 0;
@@ -3393,12 +3362,31 @@ static int gfx_v6_0_eop_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+static void gfx_v6_0_fault(struct amdgpu_device *adev,
+                          struct amdgpu_iv_entry *entry)
+{
+       struct amdgpu_ring *ring;
+
+       switch (entry->ring_id) {
+       case 0:
+               ring = &adev->gfx.gfx_ring[0];
+               break;
+       case 1:
+       case 2:
+               ring = &adev->gfx.compute_ring[entry->ring_id - 1];
+               break;
+       default:
+               return;
+       }
+       drm_sched_fault(&ring->sched);
+}
+
 static int gfx_v6_0_priv_reg_irq(struct amdgpu_device *adev,
                                 struct amdgpu_irq_src *source,
                                 struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal register access in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v6_0_fault(adev, entry);
        return 0;
 }
 
@@ -3407,7 +3395,7 @@ static int gfx_v6_0_priv_inst_irq(struct amdgpu_device *adev,
                                  struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal instruction in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v6_0_fault(adev, entry);
        return 0;
 }
 
index 0e72bc09939aca1415320b027d9f57380e6eebc4..3a9fb6018c1611e99bf5e07eb35a21c44dda27f7 100644 (file)
@@ -882,7 +882,6 @@ static const u32 kalindi_rlc_save_restore_register_list[] =
 
 static u32 gfx_v7_0_get_csb_size(struct amdgpu_device *adev);
 static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *buffer);
-static void gfx_v7_0_init_cp_pg_table(struct amdgpu_device *adev);
 static void gfx_v7_0_init_pg(struct amdgpu_device *adev);
 static void gfx_v7_0_get_cu_info(struct amdgpu_device *adev);
 
@@ -2064,17 +2063,14 @@ static int gfx_v7_0_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_gfx_scratch_free(adev, scratch);
-               return r;
-       }
+       if (r)
+               goto error_free_scratch;
+
        amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
        amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -2086,13 +2082,10 @@ static int gfx_v7_0_ring_test_ring(struct amdgpu_ring *ring)
                        break;
                DRM_UDELAY(1);
        }
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
-                         ring->idx, scratch, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
+error_free_scratch:
        amdgpu_gfx_scratch_free(adev, scratch);
        return r;
 }
@@ -2233,9 +2226,11 @@ static void gfx_v7_0_ring_emit_fence_compute(struct amdgpu_ring *ring,
  * on the gfx ring for execution by the GPU.
  */
 static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
-                                     struct amdgpu_ib *ib,
-                                     unsigned vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 header, control = 0;
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
@@ -2262,9 +2257,11 @@ static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
 }
 
 static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                         struct amdgpu_job *job,
                                          struct amdgpu_ib *ib,
-                                         unsigned vmid, bool ctx_switch)
+                                         bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
 
        amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
@@ -2316,17 +2313,15 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err1;
-       }
+
        ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
        ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START));
        ib.ptr[2] = 0xDEADBEEF;
@@ -2338,22 +2333,16 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err2;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err2;
        }
        tmp = RREG32(scratch);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
-                         scratch, tmp);
+       else
                r = -EINVAL;
-       }
 
 err2:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -2403,7 +2392,7 @@ static void gfx_v7_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
        } else {
                WREG32(mmCP_ME_CNTL, (CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK));
                for (i = 0; i < adev->gfx.num_gfx_rings; i++)
-                       adev->gfx.gfx_ring[i].ready = false;
+                       adev->gfx.gfx_ring[i].sched.ready = false;
        }
        udelay(50);
 }
@@ -2613,12 +2602,9 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
 
        /* start the ring */
        gfx_v7_0_cp_gfx_start(adev);
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                return r;
-       }
 
        return 0;
 }
@@ -2675,7 +2661,7 @@ static void gfx_v7_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
        } else {
                WREG32(mmCP_MEC_CNTL, (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
                for (i = 0; i < adev->gfx.num_compute_rings; i++)
-                       adev->gfx.compute_ring[i].ready = false;
+                       adev->gfx.compute_ring[i].sched.ready = false;
        }
        udelay(50);
 }
@@ -2781,7 +2767,7 @@ static int gfx_v7_0_mec_init(struct amdgpu_device *adev)
                * GFX7_MEC_HPD_SIZE * 2;
 
        r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
-                                     AMDGPU_GEM_DOMAIN_GTT,
+                                     AMDGPU_GEM_DOMAIN_VRAM,
                                      &adev->gfx.mec.hpd_eop_obj,
                                      &adev->gfx.mec.hpd_eop_gpu_addr,
                                      (void **)&hpd);
@@ -3106,10 +3092,7 @@ static int gfx_v7_0_cp_compute_resume(struct amdgpu_device *adev)
 
        for (i = 0; i < adev->gfx.num_compute_rings; i++) {
                ring = &adev->gfx.compute_ring[i];
-               ring->ready = true;
-               r = amdgpu_ring_test_ring(ring);
-               if (r)
-                       ring->ready = false;
+               amdgpu_ring_test_helper(ring);
        }
 
        return 0;
@@ -3268,18 +3251,10 @@ static void gfx_v7_0_ring_emit_wreg(struct amdgpu_ring *ring,
  * The RLC is a multi-purpose microengine that handles a
  * variety of functions.
  */
-static void gfx_v7_0_rlc_fini(struct amdgpu_device *adev)
-{
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, NULL, NULL);
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
-}
-
 static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)
 {
        const u32 *src_ptr;
-       volatile u32 *dst_ptr;
-       u32 dws, i;
+       u32 dws;
        const struct cs_section_def *cs_data;
        int r;
 
@@ -3306,66 +3281,23 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)
        cs_data = adev->gfx.rlc.cs_data;
 
        if (src_ptr) {
-               /* save restore block */
-               r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
-                                             AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.save_restore_obj,
-                                             &adev->gfx.rlc.save_restore_gpu_addr,
-                                             (void **)&adev->gfx.rlc.sr_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create, pin or map of RLC sr bo failed\n", r);
-                       gfx_v7_0_rlc_fini(adev);
+               /* init save restore block */
+               r = amdgpu_gfx_rlc_init_sr(adev, dws);
+               if (r)
                        return r;
-               }
-
-               /* write the sr buffer */
-               dst_ptr = adev->gfx.rlc.sr_ptr;
-               for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
-                       dst_ptr[i] = cpu_to_le32(src_ptr[i]);
-               amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
        }
 
        if (cs_data) {
-               /* clear state block */
-               adev->gfx.rlc.clear_state_size = dws = gfx_v7_0_get_csb_size(adev);
-
-               r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
-                                             AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.clear_state_obj,
-                                             &adev->gfx.rlc.clear_state_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cs_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
-                       gfx_v7_0_rlc_fini(adev);
+               /* init clear state block */
+               r = amdgpu_gfx_rlc_init_csb(adev);
+               if (r)
                        return r;
-               }
-
-               /* set up the cs buffer */
-               dst_ptr = adev->gfx.rlc.cs_ptr;
-               gfx_v7_0_get_csb_buffer(adev, dst_ptr);
-               amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
        }
 
        if (adev->gfx.rlc.cp_table_size) {
-
-               r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
-                                             PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.cp_table_obj,
-                                             &adev->gfx.rlc.cp_table_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cp_table_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r);
-                       gfx_v7_0_rlc_fini(adev);
+               r = amdgpu_gfx_rlc_init_cpt(adev);
+               if (r)
                        return r;
-               }
-
-               gfx_v7_0_init_cp_pg_table(adev);
-
-               amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
-
        }
 
        return 0;
@@ -3446,7 +3378,12 @@ static u32 gfx_v7_0_halt_rlc(struct amdgpu_device *adev)
        return orig;
 }
 
-static void gfx_v7_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v7_0_is_rlc_enabled(struct amdgpu_device *adev)
+{
+       return true;
+}
+
+static void gfx_v7_0_set_safe_mode(struct amdgpu_device *adev)
 {
        u32 tmp, i, mask;
 
@@ -3468,7 +3405,7 @@ static void gfx_v7_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
        }
 }
 
-static void gfx_v7_0_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v7_0_unset_safe_mode(struct amdgpu_device *adev)
 {
        u32 tmp;
 
@@ -3545,13 +3482,13 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
        adev->gfx.rlc_feature_version = le32_to_cpu(
                                        hdr->ucode_feature_version);
 
-       gfx_v7_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
 
        /* disable CG */
        tmp = RREG32(mmRLC_CGCG_CGLS_CTRL) & 0xfffffffc;
        WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
 
-       gfx_v7_0_rlc_reset(adev);
+       adev->gfx.rlc.funcs->reset(adev);
 
        gfx_v7_0_init_pg(adev);
 
@@ -3582,7 +3519,7 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
        if (adev->asic_type == CHIP_BONAIRE)
                WREG32(mmRLC_DRIVER_CPDMA_STATUS, 0);
 
-       gfx_v7_0_rlc_start(adev);
+       adev->gfx.rlc.funcs->start(adev);
 
        return 0;
 }
@@ -3784,72 +3721,12 @@ static void gfx_v7_0_enable_gds_pg(struct amdgpu_device *adev, bool enable)
                WREG32(mmRLC_PG_CNTL, data);
 }
 
-static void gfx_v7_0_init_cp_pg_table(struct amdgpu_device *adev)
+static int gfx_v7_0_cp_pg_table_num(struct amdgpu_device *adev)
 {
-       const __le32 *fw_data;
-       volatile u32 *dst_ptr;
-       int me, i, max_me = 4;
-       u32 bo_offset = 0;
-       u32 table_offset, table_size;
-
        if (adev->asic_type == CHIP_KAVERI)
-               max_me = 5;
-
-       if (adev->gfx.rlc.cp_table_ptr == NULL)
-               return;
-
-       /* write the cp table buffer */
-       dst_ptr = adev->gfx.rlc.cp_table_ptr;
-       for (me = 0; me < max_me; me++) {
-               if (me == 0) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.ce_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 1) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.pfp_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 2) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.me_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 3) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec2_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               }
-
-               for (i = 0; i < table_size; i ++) {
-                       dst_ptr[bo_offset + i] =
-                               cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
-               }
-
-               bo_offset += table_size;
-       }
+               return 5;
+       else
+               return 4;
 }
 
 static void gfx_v7_0_enable_gfx_cgpg(struct amdgpu_device *adev,
@@ -4288,8 +4165,17 @@ static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
 };
 
 static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = {
-       .enter_safe_mode = gfx_v7_0_enter_rlc_safe_mode,
-       .exit_safe_mode = gfx_v7_0_exit_rlc_safe_mode
+       .is_rlc_enabled = gfx_v7_0_is_rlc_enabled,
+       .set_safe_mode = gfx_v7_0_set_safe_mode,
+       .unset_safe_mode = gfx_v7_0_unset_safe_mode,
+       .init = gfx_v7_0_rlc_init,
+       .get_csb_size = gfx_v7_0_get_csb_size,
+       .get_csb_buffer = gfx_v7_0_get_csb_buffer,
+       .get_cp_table_num = gfx_v7_0_cp_pg_table_num,
+       .resume = gfx_v7_0_rlc_resume,
+       .stop = gfx_v7_0_rlc_stop,
+       .reset = gfx_v7_0_rlc_reset,
+       .start = gfx_v7_0_rlc_start
 };
 
 static int gfx_v7_0_early_init(void *handle)
@@ -4477,7 +4363,7 @@ static int gfx_v7_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
 
        ring->ring_obj = NULL;
        ring->use_doorbell = true;
-       ring->doorbell_index = AMDGPU_DOORBELL_MEC_RING0 + ring_id;
+       ring->doorbell_index = adev->doorbell_index.mec_ring0 + ring_id;
        sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue);
 
        irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP
@@ -4540,7 +4426,7 @@ static int gfx_v7_0_sw_init(void *handle)
                return r;
        }
 
-       r = gfx_v7_0_rlc_init(adev);
+       r = adev->gfx.rlc.funcs->init(adev);
        if (r) {
                DRM_ERROR("Failed to init rlc BOs!\n");
                return r;
@@ -4604,7 +4490,7 @@ static int gfx_v7_0_sw_fini(void *handle)
                amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
 
        gfx_v7_0_cp_compute_fini(adev);
-       gfx_v7_0_rlc_fini(adev);
+       amdgpu_gfx_rlc_fini(adev);
        gfx_v7_0_mec_fini(adev);
        amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
                                &adev->gfx.rlc.clear_state_gpu_addr,
@@ -4627,7 +4513,7 @@ static int gfx_v7_0_hw_init(void *handle)
        gfx_v7_0_constants_init(adev);
 
        /* init rlc */
-       r = gfx_v7_0_rlc_resume(adev);
+       r = adev->gfx.rlc.funcs->resume(adev);
        if (r)
                return r;
 
@@ -4645,7 +4531,7 @@ static int gfx_v7_0_hw_fini(void *handle)
        amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
        amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
        gfx_v7_0_cp_enable(adev, false);
-       gfx_v7_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
        gfx_v7_0_fini_pg(adev);
 
        return 0;
@@ -4730,7 +4616,7 @@ static int gfx_v7_0_soft_reset(void *handle)
                gfx_v7_0_update_cg(adev, false);
 
                /* stop the rlc */
-               gfx_v7_0_rlc_stop(adev);
+               adev->gfx.rlc.funcs->stop(adev);
 
                /* Disable GFX parsing/prefetching */
                WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK);
@@ -4959,12 +4845,36 @@ static int gfx_v7_0_eop_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+static void gfx_v7_0_fault(struct amdgpu_device *adev,
+                          struct amdgpu_iv_entry *entry)
+{
+       struct amdgpu_ring *ring;
+       u8 me_id, pipe_id;
+       int i;
+
+       me_id = (entry->ring_id & 0x0c) >> 2;
+       pipe_id = (entry->ring_id & 0x03) >> 0;
+       switch (me_id) {
+       case 0:
+               drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+               break;
+       case 1:
+       case 2:
+               for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+                       ring = &adev->gfx.compute_ring[i];
+                       if ((ring->me == me_id) && (ring->pipe == pipe_id))
+                               drm_sched_fault(&ring->sched);
+               }
+               break;
+       }
+}
+
 static int gfx_v7_0_priv_reg_irq(struct amdgpu_device *adev,
                                 struct amdgpu_irq_src *source,
                                 struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal register access in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v7_0_fault(adev, entry);
        return 0;
 }
 
@@ -4974,7 +4884,7 @@ static int gfx_v7_0_priv_inst_irq(struct amdgpu_device *adev,
 {
        DRM_ERROR("Illegal instruction in command stream\n");
        // XXX soft reset the gfx block only
-       schedule_work(&adev->reset_work);
+       gfx_v7_0_fault(adev, entry);
        return 0;
 }
 
index 617b0c8908a375aa0d132af1868f3eaf9e2067b1..381f593b0cda83bdda6f67f2d2b41cd8488583c4 100644 (file)
@@ -44,7 +44,6 @@
 #include "gca/gfx_8_0_d.h"
 #include "gca/gfx_8_0_enum.h"
 #include "gca/gfx_8_0_sh_mask.h"
-#include "gca/gfx_8_0_enum.h"
 
 #include "dce/dce_10_0_d.h"
 #include "dce/dce_10_0_sh_mask.h"
@@ -54,7 +53,7 @@
 #include "ivsrcid/ivsrcid_vislands30.h"
 
 #define GFX8_NUM_GFX_RINGS     1
-#define GFX8_MEC_HPD_SIZE 2048
+#define GFX8_MEC_HPD_SIZE 4096
 
 #define TOPAZ_GB_ADDR_CONFIG_GOLDEN 0x22010001
 #define CARRIZO_GB_ADDR_CONFIG_GOLDEN 0x22010001
@@ -839,18 +838,14 @@ static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
-               amdgpu_gfx_scratch_free(adev, scratch);
-               return r;
-       }
+       if (r)
+               goto error_free_scratch;
+
        amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
        amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -862,14 +857,11 @@ static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
                        break;
                DRM_UDELAY(1);
        }
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
-                         ring->idx, scratch, tmp);
-               r = -EINVAL;
-       }
+
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
+error_free_scratch:
        amdgpu_gfx_scratch_free(adev, scratch);
        return r;
 }
@@ -886,19 +878,16 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 16, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err1;
-       }
+
        ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
        ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
        ib.ptr[2] = lower_32_bits(gpu_addr);
@@ -912,22 +901,17 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
                r = -ETIMEDOUT;
                goto err2;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err2;
        }
 
        tmp = adev->wb.wb[index];
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("ib test on ring %d failed\n", ring->idx);
+       else
                r = -EINVAL;
-       }
 
 err2:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -1298,81 +1282,16 @@ static void gfx_v8_0_get_csb_buffer(struct amdgpu_device *adev,
        buffer[count++] = cpu_to_le32(0);
 }
 
-static void cz_init_cp_jump_table(struct amdgpu_device *adev)
+static int gfx_v8_0_cp_jump_table_num(struct amdgpu_device *adev)
 {
-       const __le32 *fw_data;
-       volatile u32 *dst_ptr;
-       int me, i, max_me = 4;
-       u32 bo_offset = 0;
-       u32 table_offset, table_size;
-
        if (adev->asic_type == CHIP_CARRIZO)
-               max_me = 5;
-
-       /* write the cp table buffer */
-       dst_ptr = adev->gfx.rlc.cp_table_ptr;
-       for (me = 0; me < max_me; me++) {
-               if (me == 0) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.ce_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 1) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.pfp_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 2) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.me_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 3) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else  if (me == 4) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec2_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               }
-
-               for (i = 0; i < table_size; i ++) {
-                       dst_ptr[bo_offset + i] =
-                               cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
-               }
-
-               bo_offset += table_size;
-       }
-}
-
-static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev)
-{
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
+               return 5;
+       else
+               return 4;
 }
 
 static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
 {
-       volatile u32 *dst_ptr;
-       u32 dws;
        const struct cs_section_def *cs_data;
        int r;
 
@@ -1381,44 +1300,18 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
        cs_data = adev->gfx.rlc.cs_data;
 
        if (cs_data) {
-               /* clear state block */
-               adev->gfx.rlc.clear_state_size = dws = gfx_v8_0_get_csb_size(adev);
-
-               r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
-                                             AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.clear_state_obj,
-                                             &adev->gfx.rlc.clear_state_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cs_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
-                       gfx_v8_0_rlc_fini(adev);
+               /* init clear state block */
+               r = amdgpu_gfx_rlc_init_csb(adev);
+               if (r)
                        return r;
-               }
-
-               /* set up the cs buffer */
-               dst_ptr = adev->gfx.rlc.cs_ptr;
-               gfx_v8_0_get_csb_buffer(adev, dst_ptr);
-               amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
        }
 
        if ((adev->asic_type == CHIP_CARRIZO) ||
            (adev->asic_type == CHIP_STONEY)) {
                adev->gfx.rlc.cp_table_size = ALIGN(96 * 5 * 4, 2048) + (64 * 1024); /* JT + GDS */
-               r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
-                                             PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.cp_table_obj,
-                                             &adev->gfx.rlc.cp_table_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cp_table_ptr);
-               if (r) {
-                       dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r);
+               r = amdgpu_gfx_rlc_init_cpt(adev);
+               if (r)
                        return r;
-               }
-
-               cz_init_cp_jump_table(adev);
-
-               amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
        }
 
        return 0;
@@ -1443,7 +1336,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
        mec_hpd_size = adev->gfx.num_compute_rings * GFX8_MEC_HPD_SIZE;
 
        r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
-                                     AMDGPU_GEM_DOMAIN_GTT,
+                                     AMDGPU_GEM_DOMAIN_VRAM,
                                      &adev->gfx.mec.hpd_eop_obj,
                                      &adev->gfx.mec.hpd_eop_gpu_addr,
                                      (void **)&hpd);
@@ -1629,7 +1522,7 @@ static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
                return 0;
 
        /* bail if the compute ring is not ready */
-       if (!ring->ready)
+       if (!ring->sched.ready)
                return 0;
 
        tmp = RREG32(mmGB_EDC_MODE);
@@ -1997,7 +1890,7 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
 
        ring->ring_obj = NULL;
        ring->use_doorbell = true;
-       ring->doorbell_index = AMDGPU_DOORBELL_MEC_RING0 + ring_id;
+       ring->doorbell_index = adev->doorbell_index.mec_ring0 + ring_id;
        ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr
                                + (ring_id * GFX8_MEC_HPD_SIZE);
        sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue);
@@ -2088,7 +1981,7 @@ static int gfx_v8_0_sw_init(void *handle)
                return r;
        }
 
-       r = gfx_v8_0_rlc_init(adev);
+       r = adev->gfx.rlc.funcs->init(adev);
        if (r) {
                DRM_ERROR("Failed to init rlc BOs!\n");
                return r;
@@ -2108,7 +2001,7 @@ static int gfx_v8_0_sw_init(void *handle)
                /* no gfx doorbells on iceland */
                if (adev->asic_type != CHIP_TOPAZ) {
                        ring->use_doorbell = true;
-                       ring->doorbell_index = AMDGPU_DOORBELL_GFX_RING0;
+                       ring->doorbell_index = adev->doorbell_index.gfx_ring0;
                }
 
                r = amdgpu_ring_init(adev, ring, 1024, &adev->gfx.eop_irq,
@@ -2181,7 +2074,7 @@ static int gfx_v8_0_sw_fini(void *handle)
        amdgpu_gfx_kiq_fini(adev);
 
        gfx_v8_0_mec_fini(adev);
-       gfx_v8_0_rlc_fini(adev);
+       amdgpu_gfx_rlc_fini(adev);
        amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
                                &adev->gfx.rlc.clear_state_gpu_addr,
                                (void **)&adev->gfx.rlc.cs_ptr);
@@ -4175,10 +4068,15 @@ static void gfx_v8_0_rlc_start(struct amdgpu_device *adev)
 
 static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
 {
-       gfx_v8_0_rlc_stop(adev);
-       gfx_v8_0_rlc_reset(adev);
+       if (amdgpu_sriov_vf(adev)) {
+               gfx_v8_0_init_csb(adev);
+               return 0;
+       }
+
+       adev->gfx.rlc.funcs->stop(adev);
+       adev->gfx.rlc.funcs->reset(adev);
        gfx_v8_0_init_pg(adev);
-       gfx_v8_0_rlc_start(adev);
+       adev->gfx.rlc.funcs->start(adev);
 
        return 0;
 }
@@ -4197,7 +4095,7 @@ static void gfx_v8_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
                tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_HALT, 1);
                tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_HALT, 1);
                for (i = 0; i < adev->gfx.num_gfx_rings; i++)
-                       adev->gfx.gfx_ring[i].ready = false;
+                       adev->gfx.gfx_ring[i].sched.ready = false;
        }
        WREG32(mmCP_ME_CNTL, tmp);
        udelay(50);
@@ -4322,7 +4220,7 @@ static void gfx_v8_0_set_cpg_door_bell(struct amdgpu_device *adev, struct amdgpu
 
        tmp = REG_SET_FIELD(0, CP_RB_DOORBELL_RANGE_LOWER,
                                        DOORBELL_RANGE_LOWER,
-                                       AMDGPU_DOORBELL_GFX_RING0);
+                                       adev->doorbell_index.gfx_ring0);
        WREG32(mmCP_RB_DOORBELL_RANGE_LOWER, tmp);
 
        WREG32(mmCP_RB_DOORBELL_RANGE_UPPER,
@@ -4379,10 +4277,8 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev)
        /* start the ring */
        amdgpu_ring_clear_ring(ring);
        gfx_v8_0_cp_gfx_start(adev);
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r)
-               ring->ready = false;
+       ring->sched.ready = true;
+       r = amdgpu_ring_test_helper(ring);
 
        return r;
 }
@@ -4396,8 +4292,8 @@ static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
        } else {
                WREG32(mmCP_MEC_CNTL, (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
                for (i = 0; i < adev->gfx.num_compute_rings; i++)
-                       adev->gfx.compute_ring[i].ready = false;
-               adev->gfx.kiq.ring.ready = false;
+                       adev->gfx.compute_ring[i].sched.ready = false;
+               adev->gfx.kiq.ring.sched.ready = false;
        }
        udelay(50);
 }
@@ -4473,11 +4369,9 @@ static int gfx_v8_0_kiq_kcq_enable(struct amdgpu_device *adev)
                amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
        }
 
-       r = amdgpu_ring_test_ring(kiq_ring);
-       if (r) {
+       r = amdgpu_ring_test_helper(kiq_ring);
+       if (r)
                DRM_ERROR("KCQ enable failed\n");
-               kiq_ring->ready = false;
-       }
        return r;
 }
 
@@ -4755,8 +4649,8 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring)
 static void gfx_v8_0_set_mec_doorbell_range(struct amdgpu_device *adev)
 {
        if (adev->asic_type > CHIP_TONGA) {
-               WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2);
-               WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, AMDGPU_DOORBELL_MEC_RING7 << 2);
+               WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, adev->doorbell_index.kiq << 2);
+               WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, adev->doorbell_index.mec_ring7 << 2);
        }
        /* enable doorbells */
        WREG32_FIELD(CP_PQ_STATUS, DOORBELL_ENABLE, 1);
@@ -4781,7 +4675,7 @@ static int gfx_v8_0_kiq_resume(struct amdgpu_device *adev)
        amdgpu_bo_kunmap(ring->mqd_obj);
        ring->mqd_ptr = NULL;
        amdgpu_bo_unreserve(ring->mqd_obj);
-       ring->ready = true;
+       ring->sched.ready = true;
        return 0;
 }
 
@@ -4820,10 +4714,7 @@ static int gfx_v8_0_kcq_resume(struct amdgpu_device *adev)
         */
        for (i = adev->gfx.num_compute_rings - 1; i >= 0; i--) {
                ring = &adev->gfx.compute_ring[i];
-               ring->ready = true;
-               r = amdgpu_ring_test_ring(ring);
-               if (r)
-                       ring->ready = false;
+               r = amdgpu_ring_test_helper(ring);
        }
 
 done:
@@ -4867,7 +4758,7 @@ static int gfx_v8_0_hw_init(void *handle)
        gfx_v8_0_init_golden_registers(adev);
        gfx_v8_0_constants_init(adev);
 
-       r = gfx_v8_0_rlc_resume(adev);
+       r = adev->gfx.rlc.funcs->resume(adev);
        if (r)
                return r;
 
@@ -4899,7 +4790,7 @@ static int gfx_v8_0_kcq_disable(struct amdgpu_device *adev)
                amdgpu_ring_write(kiq_ring, 0);
                amdgpu_ring_write(kiq_ring, 0);
        }
-       r = amdgpu_ring_test_ring(kiq_ring);
+       r = amdgpu_ring_test_helper(kiq_ring);
        if (r)
                DRM_ERROR("KCQ disable failed\n");
 
@@ -4973,16 +4864,16 @@ static int gfx_v8_0_hw_fini(void *handle)
                pr_debug("For SRIOV client, shouldn't do anything.\n");
                return 0;
        }
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
        if (!gfx_v8_0_wait_for_idle(adev))
                gfx_v8_0_cp_enable(adev, false);
        else
                pr_err("cp is busy, skip halt cp\n");
        if (!gfx_v8_0_wait_for_rlc_idle(adev))
-               gfx_v8_0_rlc_stop(adev);
+               adev->gfx.rlc.funcs->stop(adev);
        else
                pr_err("rlc is busy, skip halt rlc\n");
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
        return 0;
 }
 
@@ -5061,17 +4952,16 @@ static bool gfx_v8_0_check_soft_reset(void *handle)
 static int gfx_v8_0_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+       u32 grbm_soft_reset = 0;
 
        if ((!adev->gfx.grbm_soft_reset) &&
            (!adev->gfx.srbm_soft_reset))
                return 0;
 
        grbm_soft_reset = adev->gfx.grbm_soft_reset;
-       srbm_soft_reset = adev->gfx.srbm_soft_reset;
 
        /* stop the rlc */
-       gfx_v8_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
 
        if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
            REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
@@ -5165,14 +5055,13 @@ static int gfx_v8_0_soft_reset(void *handle)
 static int gfx_v8_0_post_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+       u32 grbm_soft_reset = 0;
 
        if ((!adev->gfx.grbm_soft_reset) &&
            (!adev->gfx.srbm_soft_reset))
                return 0;
 
        grbm_soft_reset = adev->gfx.grbm_soft_reset;
-       srbm_soft_reset = adev->gfx.srbm_soft_reset;
 
        if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
            REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) ||
@@ -5197,7 +5086,7 @@ static int gfx_v8_0_post_soft_reset(void *handle)
            REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
                gfx_v8_0_cp_gfx_resume(adev);
 
-       gfx_v8_0_rlc_start(adev);
+       adev->gfx.rlc.funcs->start(adev);
 
        return 0;
 }
@@ -5445,7 +5334,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
                                AMD_PG_SUPPORT_RLC_SMU_HS |
                                AMD_PG_SUPPORT_CP |
                                AMD_PG_SUPPORT_GFX_DMG))
-               adev->gfx.rlc.funcs->enter_safe_mode(adev);
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
        switch (adev->asic_type) {
        case CHIP_CARRIZO:
        case CHIP_STONEY:
@@ -5499,7 +5388,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
                                AMD_PG_SUPPORT_RLC_SMU_HS |
                                AMD_PG_SUPPORT_CP |
                                AMD_PG_SUPPORT_GFX_DMG))
-               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
        return 0;
 }
 
@@ -5593,57 +5482,53 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
 #define RLC_GPR_REG2__MESSAGE__SHIFT 0x00000001
 #define RLC_GPR_REG2__MESSAGE_MASK 0x0000001e
 
-static void iceland_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v8_0_is_rlc_enabled(struct amdgpu_device *adev)
 {
-       u32 data;
-       unsigned i;
+       uint32_t rlc_setting;
 
-       data = RREG32(mmRLC_CNTL);
-       if (!(data & RLC_CNTL__RLC_ENABLE_F32_MASK))
-               return;
+       rlc_setting = RREG32(mmRLC_CNTL);
+       if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
+               return false;
 
-       if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
-               data |= RLC_SAFE_MODE__CMD_MASK;
-               data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
-               data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
-               WREG32(mmRLC_SAFE_MODE, data);
+       return true;
+}
 
-               for (i = 0; i < adev->usec_timeout; i++) {
-                       if ((RREG32(mmRLC_GPM_STAT) &
-                            (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
-                             RLC_GPM_STAT__GFX_POWER_STATUS_MASK)) ==
-                           (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
-                            RLC_GPM_STAT__GFX_POWER_STATUS_MASK))
-                               break;
-                       udelay(1);
-               }
+static void gfx_v8_0_set_safe_mode(struct amdgpu_device *adev)
+{
+       uint32_t data;
+       unsigned i;
+       data = RREG32(mmRLC_CNTL);
+       data |= RLC_SAFE_MODE__CMD_MASK;
+       data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
+       data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
+       WREG32(mmRLC_SAFE_MODE, data);
 
-               for (i = 0; i < adev->usec_timeout; i++) {
-                       if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
-                               break;
-                       udelay(1);
-               }
-               adev->gfx.rlc.in_safe_mode = true;
+       /* wait for RLC_SAFE_MODE */
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if ((RREG32(mmRLC_GPM_STAT) &
+                    (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
+                     RLC_GPM_STAT__GFX_POWER_STATUS_MASK)) ==
+                   (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
+                    RLC_GPM_STAT__GFX_POWER_STATUS_MASK))
+                       break;
+               udelay(1);
+       }
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
+                       break;
+               udelay(1);
        }
 }
 
-static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v8_0_unset_safe_mode(struct amdgpu_device *adev)
 {
-       u32 data = 0;
+       uint32_t data;
        unsigned i;
 
        data = RREG32(mmRLC_CNTL);
-       if (!(data & RLC_CNTL__RLC_ENABLE_F32_MASK))
-               return;
-
-       if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
-               if (adev->gfx.rlc.in_safe_mode) {
-                       data |= RLC_SAFE_MODE__CMD_MASK;
-                       data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
-                       WREG32(mmRLC_SAFE_MODE, data);
-                       adev->gfx.rlc.in_safe_mode = false;
-               }
-       }
+       data |= RLC_SAFE_MODE__CMD_MASK;
+       data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
+       WREG32(mmRLC_SAFE_MODE, data);
 
        for (i = 0; i < adev->usec_timeout; i++) {
                if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
@@ -5653,8 +5538,17 @@ static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
 }
 
 static const struct amdgpu_rlc_funcs iceland_rlc_funcs = {
-       .enter_safe_mode = iceland_enter_rlc_safe_mode,
-       .exit_safe_mode = iceland_exit_rlc_safe_mode
+       .is_rlc_enabled = gfx_v8_0_is_rlc_enabled,
+       .set_safe_mode = gfx_v8_0_set_safe_mode,
+       .unset_safe_mode = gfx_v8_0_unset_safe_mode,
+       .init = gfx_v8_0_rlc_init,
+       .get_csb_size = gfx_v8_0_get_csb_size,
+       .get_csb_buffer = gfx_v8_0_get_csb_buffer,
+       .get_cp_table_num = gfx_v8_0_cp_jump_table_num,
+       .resume = gfx_v8_0_rlc_resume,
+       .stop = gfx_v8_0_rlc_stop,
+       .reset = gfx_v8_0_rlc_reset,
+       .start = gfx_v8_0_rlc_start
 };
 
 static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
@@ -5662,7 +5556,7 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
 {
        uint32_t temp, data;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        /* It is disabled by HW by default */
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
@@ -5758,7 +5652,7 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
                gfx_v8_0_wait_for_rlc_serdes(adev);
        }
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 }
 
 static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
@@ -5768,7 +5662,7 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
 
        temp = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
                temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
@@ -5851,7 +5745,7 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
 
        gfx_v8_0_wait_for_rlc_serdes(adev);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 }
 static int gfx_v8_0_update_gfx_clock_gating(struct amdgpu_device *adev,
                                            bool enable)
@@ -6131,9 +6025,11 @@ static void gfx_v8_0_ring_emit_vgt_flush(struct amdgpu_ring *ring)
 }
 
 static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
-                                     struct amdgpu_ib *ib,
-                                     unsigned vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 header, control = 0;
 
        if (ib->flags & AMDGPU_IB_FLAG_CE)
@@ -6161,9 +6057,11 @@ static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
 }
 
 static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                         struct amdgpu_job *job,
                                          struct amdgpu_ib *ib,
-                                         unsigned vmid, bool ctx_switch)
+                                         bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
 
        amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
@@ -6738,12 +6636,39 @@ static int gfx_v8_0_eop_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+static void gfx_v8_0_fault(struct amdgpu_device *adev,
+                          struct amdgpu_iv_entry *entry)
+{
+       u8 me_id, pipe_id, queue_id;
+       struct amdgpu_ring *ring;
+       int i;
+
+       me_id = (entry->ring_id & 0x0c) >> 2;
+       pipe_id = (entry->ring_id & 0x03) >> 0;
+       queue_id = (entry->ring_id & 0x70) >> 4;
+
+       switch (me_id) {
+       case 0:
+               drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+               break;
+       case 1:
+       case 2:
+               for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+                       ring = &adev->gfx.compute_ring[i];
+                       if (ring->me == me_id && ring->pipe == pipe_id &&
+                           ring->queue == queue_id)
+                               drm_sched_fault(&ring->sched);
+               }
+               break;
+       }
+}
+
 static int gfx_v8_0_priv_reg_irq(struct amdgpu_device *adev,
                                 struct amdgpu_irq_src *source,
                                 struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal register access in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v8_0_fault(adev, entry);
        return 0;
 }
 
@@ -6752,7 +6677,7 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
                                  struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal instruction in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v8_0_fault(adev, entry);
        return 0;
 }
 
@@ -6976,10 +6901,8 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = {
                17 + /* gfx_v8_0_ring_emit_vm_flush */
                7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_kiq x3 for user fence, vm fence */
        .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */
-       .emit_ib = gfx_v8_0_ring_emit_ib_compute,
        .emit_fence = gfx_v8_0_ring_emit_fence_kiq,
        .test_ring = gfx_v8_0_ring_test_ring,
-       .test_ib = gfx_v8_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .emit_rreg = gfx_v8_0_ring_emit_rreg,
index 21363b2b2ee5729e7807b9046aa2872438044ae1..7556716038d376b6e7dff5fcd27af537dc5346e3 100644 (file)
@@ -41,7 +41,7 @@
 #include "ivsrcid/gfx/irqsrcs_gfx_9_0.h"
 
 #define GFX9_NUM_GFX_RINGS     1
-#define GFX9_MEC_HPD_SIZE 2048
+#define GFX9_MEC_HPD_SIZE 4096
 #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
 #define RLC_SAVE_RESTORE_ADDR_STARTING_OFFSET 0x00000000L
 
@@ -86,6 +86,7 @@ MODULE_FIRMWARE("amdgpu/picasso_me.bin");
 MODULE_FIRMWARE("amdgpu/picasso_mec.bin");
 MODULE_FIRMWARE("amdgpu/picasso_mec2.bin");
 MODULE_FIRMWARE("amdgpu/picasso_rlc.bin");
+MODULE_FIRMWARE("amdgpu/picasso_rlc_am4.bin");
 
 MODULE_FIRMWARE("amdgpu/raven2_ce.bin");
 MODULE_FIRMWARE("amdgpu/raven2_pfp.bin");
@@ -396,18 +397,14 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_gfx_scratch_get(adev, &scratch);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+       if (r)
                return r;
-       }
+
        WREG32(scratch, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
-               amdgpu_gfx_scratch_free(adev, scratch);
-               return r;
-       }
+       if (r)
+               goto error_free_scratch;
+
        amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
        amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -419,14 +416,11 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring)
                        break;
                DRM_UDELAY(1);
        }
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
-                         ring->idx, scratch, tmp);
-               r = -EINVAL;
-       }
+
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
+error_free_scratch:
        amdgpu_gfx_scratch_free(adev, scratch);
        return r;
 }
@@ -443,19 +437,16 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 16, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err1;
-       }
+
        ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
        ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
        ib.ptr[2] = lower_32_bits(gpu_addr);
@@ -469,22 +460,17 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-                       DRM_ERROR("amdgpu: IB test timed out.\n");
-                       r = -ETIMEDOUT;
-                       goto err2;
+               r = -ETIMEDOUT;
+               goto err2;
        } else if (r < 0) {
-                       DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
-                       goto err2;
+               goto err2;
        }
 
        tmp = adev->wb.wb[index];
-       if (tmp == 0xDEADBEEF) {
-                       DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
-                       r = 0;
-       } else {
-                       DRM_ERROR("ib test on ring %d failed\n", ring->idx);
-                       r = -EINVAL;
-       }
+       if (tmp == 0xDEADBEEF)
+               r = 0;
+       else
+               r = -EINVAL;
 
 err2:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -660,7 +646,20 @@ static int gfx_v9_0_init_microcode(struct amdgpu_device *adev)
        adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
        adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
-       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
+       /*
+        * For Picasso && AM4 SOCKET board, we use picasso_rlc_am4.bin
+        * instead of picasso_rlc.bin.
+        * Judgment method:
+        * PCO AM4: revision >= 0xC8 && revision <= 0xCF
+        *          or revision >= 0xD8 && revision <= 0xDF
+        * otherwise is PCO FP5
+        */
+       if (!strcmp(chip_name, "picasso") &&
+               (((adev->pdev->revision >= 0xC8) && (adev->pdev->revision <= 0xCF)) ||
+               ((adev->pdev->revision >= 0xD8) && (adev->pdev->revision <= 0xDF))))
+               snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc_am4.bin", chip_name);
+       else
+               snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
        err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
        if (err)
                goto out;
@@ -1065,85 +1064,13 @@ static void gfx_v9_0_enable_lbpw(struct amdgpu_device *adev, bool enable)
        WREG32_FIELD15(GC, 0, RLC_LB_CNTL, LOAD_BALANCE_ENABLE, enable ? 1 : 0);
 }
 
-static void rv_init_cp_jump_table(struct amdgpu_device *adev)
+static int gfx_v9_0_cp_jump_table_num(struct amdgpu_device *adev)
 {
-       const __le32 *fw_data;
-       volatile u32 *dst_ptr;
-       int me, i, max_me = 5;
-       u32 bo_offset = 0;
-       u32 table_offset, table_size;
-
-       /* write the cp table buffer */
-       dst_ptr = adev->gfx.rlc.cp_table_ptr;
-       for (me = 0; me < max_me; me++) {
-               if (me == 0) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.ce_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 1) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.pfp_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 2) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.me_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else if (me == 3) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               } else  if (me == 4) {
-                       const struct gfx_firmware_header_v1_0 *hdr =
-                               (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
-                       fw_data = (const __le32 *)
-                               (adev->gfx.mec2_fw->data +
-                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
-                       table_offset = le32_to_cpu(hdr->jt_offset);
-                       table_size = le32_to_cpu(hdr->jt_size);
-               }
-
-               for (i = 0; i < table_size; i ++) {
-                       dst_ptr[bo_offset + i] =
-                               cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
-               }
-
-               bo_offset += table_size;
-       }
-}
-
-static void gfx_v9_0_rlc_fini(struct amdgpu_device *adev)
-{
-       /* clear state block */
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
-                       &adev->gfx.rlc.clear_state_gpu_addr,
-                       (void **)&adev->gfx.rlc.cs_ptr);
-
-       /* jump table block */
-       amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
-                       &adev->gfx.rlc.cp_table_gpu_addr,
-                       (void **)&adev->gfx.rlc.cp_table_ptr);
+       return 5;
 }
 
 static int gfx_v9_0_rlc_init(struct amdgpu_device *adev)
 {
-       volatile u32 *dst_ptr;
-       u32 dws;
        const struct cs_section_def *cs_data;
        int r;
 
@@ -1152,45 +1079,18 @@ static int gfx_v9_0_rlc_init(struct amdgpu_device *adev)
        cs_data = adev->gfx.rlc.cs_data;
 
        if (cs_data) {
-               /* clear state block */
-               adev->gfx.rlc.clear_state_size = dws = gfx_v9_0_get_csb_size(adev);
-               r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
-                                             AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.clear_state_obj,
-                                             &adev->gfx.rlc.clear_state_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cs_ptr);
-               if (r) {
-                       dev_err(adev->dev, "(%d) failed to create rlc csb bo\n",
-                               r);
-                       gfx_v9_0_rlc_fini(adev);
+               /* init clear state block */
+               r = amdgpu_gfx_rlc_init_csb(adev);
+               if (r)
                        return r;
-               }
-               /* set up the cs buffer */
-               dst_ptr = adev->gfx.rlc.cs_ptr;
-               gfx_v9_0_get_csb_buffer(adev, dst_ptr);
-               amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
-               amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
        }
 
        if (adev->asic_type == CHIP_RAVEN) {
                /* TODO: double check the cp_table_size for RV */
                adev->gfx.rlc.cp_table_size = ALIGN(96 * 5 * 4, 2048) + (64 * 1024); /* JT + GDS */
-               r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
-                                             PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
-                                             &adev->gfx.rlc.cp_table_obj,
-                                             &adev->gfx.rlc.cp_table_gpu_addr,
-                                             (void **)&adev->gfx.rlc.cp_table_ptr);
-               if (r) {
-                       dev_err(adev->dev,
-                               "(%d) failed to create cp table bo\n", r);
-                       gfx_v9_0_rlc_fini(adev);
+               r = amdgpu_gfx_rlc_init_cpt(adev);
+               if (r)
                        return r;
-               }
-
-               rv_init_cp_jump_table(adev);
-               amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
-               amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
        }
 
        switch (adev->asic_type) {
@@ -1264,7 +1164,7 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev)
        mec_hpd_size = adev->gfx.num_compute_rings * GFX9_MEC_HPD_SIZE;
 
        r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
-                                     AMDGPU_GEM_DOMAIN_GTT,
+                                     AMDGPU_GEM_DOMAIN_VRAM,
                                      &adev->gfx.mec.hpd_eop_obj,
                                      &adev->gfx.mec.hpd_eop_gpu_addr,
                                      (void **)&hpd);
@@ -1635,8 +1535,8 @@ static int gfx_v9_0_ngg_en(struct amdgpu_device *adev)
        /* Clear GDS reserved memory */
        r = amdgpu_ring_alloc(ring, 17);
        if (r) {
-               DRM_ERROR("amdgpu: NGG failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+               DRM_ERROR("amdgpu: NGG failed to lock ring %s (%d).\n",
+                         ring->name, r);
                return r;
        }
 
@@ -1680,7 +1580,7 @@ static int gfx_v9_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
 
        ring->ring_obj = NULL;
        ring->use_doorbell = true;
-       ring->doorbell_index = (AMDGPU_DOORBELL_MEC_RING0 + ring_id) << 1;
+       ring->doorbell_index = (adev->doorbell_index.mec_ring0 + ring_id) << 1;
        ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr
                                + (ring_id * GFX9_MEC_HPD_SIZE);
        sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue);
@@ -1748,7 +1648,7 @@ static int gfx_v9_0_sw_init(void *handle)
                return r;
        }
 
-       r = gfx_v9_0_rlc_init(adev);
+       r = adev->gfx.rlc.funcs->init(adev);
        if (r) {
                DRM_ERROR("Failed to init rlc BOs!\n");
                return r;
@@ -1769,7 +1669,7 @@ static int gfx_v9_0_sw_init(void *handle)
                else
                        sprintf(ring->name, "gfx_%d", i);
                ring->use_doorbell = true;
-               ring->doorbell_index = AMDGPU_DOORBELL64_GFX_RING0 << 1;
+               ring->doorbell_index = adev->doorbell_index.gfx_ring0 << 1;
                r = amdgpu_ring_init(adev, ring, 1024,
                                     &adev->gfx.eop_irq, AMDGPU_CP_IRQ_GFX_EOP);
                if (r)
@@ -2499,12 +2399,12 @@ static int gfx_v9_0_rlc_resume(struct amdgpu_device *adev)
                return 0;
        }
 
-       gfx_v9_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
 
        /* disable CG */
        WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, 0);
 
-       gfx_v9_0_rlc_reset(adev);
+       adev->gfx.rlc.funcs->reset(adev);
 
        gfx_v9_0_init_pg(adev);
 
@@ -2515,15 +2415,24 @@ static int gfx_v9_0_rlc_resume(struct amdgpu_device *adev)
                        return r;
        }
 
-       if (adev->asic_type == CHIP_RAVEN ||
-           adev->asic_type == CHIP_VEGA20) {
-               if (amdgpu_lbpw != 0)
+       switch (adev->asic_type) {
+       case CHIP_RAVEN:
+               if (amdgpu_lbpw == 0)
+                       gfx_v9_0_enable_lbpw(adev, false);
+               else
+                       gfx_v9_0_enable_lbpw(adev, true);
+               break;
+       case CHIP_VEGA20:
+               if (amdgpu_lbpw > 0)
                        gfx_v9_0_enable_lbpw(adev, true);
                else
                        gfx_v9_0_enable_lbpw(adev, false);
+               break;
+       default:
+               break;
        }
 
-       gfx_v9_0_rlc_start(adev);
+       adev->gfx.rlc.funcs->start(adev);
 
        return 0;
 }
@@ -2538,7 +2447,7 @@ static void gfx_v9_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
        tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_HALT, enable ? 0 : 1);
        if (!enable) {
                for (i = 0; i < adev->gfx.num_gfx_rings; i++)
-                       adev->gfx.gfx_ring[i].ready = false;
+                       adev->gfx.gfx_ring[i].sched.ready = false;
        }
        WREG32_SOC15(GC, 0, mmCP_ME_CNTL, tmp);
        udelay(50);
@@ -2728,7 +2637,7 @@ static int gfx_v9_0_cp_gfx_resume(struct amdgpu_device *adev)
 
        /* start the ring */
        gfx_v9_0_cp_gfx_start(adev);
-       ring->ready = true;
+       ring->sched.ready = true;
 
        return 0;
 }
@@ -2743,8 +2652,8 @@ static void gfx_v9_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
                WREG32_SOC15(GC, 0, mmCP_MEC_CNTL,
                        (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
                for (i = 0; i < adev->gfx.num_compute_rings; i++)
-                       adev->gfx.compute_ring[i].ready = false;
-               adev->gfx.kiq.ring.ready = false;
+                       adev->gfx.compute_ring[i].sched.ready = false;
+               adev->gfx.kiq.ring.sched.ready = false;
        }
        udelay(50);
 }
@@ -2867,11 +2776,9 @@ static int gfx_v9_0_kiq_kcq_enable(struct amdgpu_device *adev)
                amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
        }
 
-       r = amdgpu_ring_test_ring(kiq_ring);
-       if (r) {
+       r = amdgpu_ring_test_helper(kiq_ring);
+       if (r)
                DRM_ERROR("KCQ enable failed\n");
-               kiq_ring->ready = false;
-       }
 
        return r;
 }
@@ -3089,9 +2996,9 @@ static int gfx_v9_0_kiq_init_register(struct amdgpu_ring *ring)
        /* enable the doorbell if requested */
        if (ring->use_doorbell) {
                WREG32_SOC15(GC, 0, mmCP_MEC_DOORBELL_RANGE_LOWER,
-                                       (AMDGPU_DOORBELL64_KIQ *2) << 2);
+                                       (adev->doorbell_index.kiq * 2) << 2);
                WREG32_SOC15(GC, 0, mmCP_MEC_DOORBELL_RANGE_UPPER,
-                                       (AMDGPU_DOORBELL64_USERQUEUE_END * 2) << 2);
+                                       (adev->doorbell_index.userqueue_end * 2) << 2);
        }
 
        WREG32_SOC15(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL,
@@ -3250,7 +3157,7 @@ static int gfx_v9_0_kiq_resume(struct amdgpu_device *adev)
        amdgpu_bo_kunmap(ring->mqd_obj);
        ring->mqd_ptr = NULL;
        amdgpu_bo_unreserve(ring->mqd_obj);
-       ring->ready = true;
+       ring->sched.ready = true;
        return 0;
 }
 
@@ -3315,19 +3222,13 @@ static int gfx_v9_0_cp_resume(struct amdgpu_device *adev)
                return r;
 
        ring = &adev->gfx.gfx_ring[0];
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                return r;
-       }
 
        for (i = 0; i < adev->gfx.num_compute_rings; i++) {
                ring = &adev->gfx.compute_ring[i];
-
-               ring->ready = true;
-               r = amdgpu_ring_test_ring(ring);
-               if (r)
-                       ring->ready = false;
+               amdgpu_ring_test_helper(ring);
        }
 
        gfx_v9_0_enable_gui_idle_interrupt(adev, true);
@@ -3354,7 +3255,7 @@ static int gfx_v9_0_hw_init(void *handle)
        if (r)
                return r;
 
-       r = gfx_v9_0_rlc_resume(adev);
+       r = adev->gfx.rlc.funcs->resume(adev);
        if (r)
                return r;
 
@@ -3392,7 +3293,7 @@ static int gfx_v9_0_kcq_disable(struct amdgpu_device *adev)
                amdgpu_ring_write(kiq_ring, 0);
                amdgpu_ring_write(kiq_ring, 0);
        }
-       r = amdgpu_ring_test_ring(kiq_ring);
+       r = amdgpu_ring_test_helper(kiq_ring);
        if (r)
                DRM_ERROR("KCQ disable failed\n");
 
@@ -3434,7 +3335,7 @@ static int gfx_v9_0_hw_fini(void *handle)
        }
 
        gfx_v9_0_cp_enable(adev, false);
-       gfx_v9_0_rlc_stop(adev);
+       adev->gfx.rlc.funcs->stop(adev);
 
        gfx_v9_0_csb_vram_unpin(adev);
 
@@ -3509,7 +3410,7 @@ static int gfx_v9_0_soft_reset(void *handle)
 
        if (grbm_soft_reset) {
                /* stop the rlc */
-               gfx_v9_0_rlc_stop(adev);
+               adev->gfx.rlc.funcs->stop(adev);
 
                /* Disable GFX parsing/prefetching */
                gfx_v9_0_cp_gfx_enable(adev, false);
@@ -3608,64 +3509,47 @@ static int gfx_v9_0_late_init(void *handle)
        return 0;
 }
 
-static void gfx_v9_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v9_0_is_rlc_enabled(struct amdgpu_device *adev)
 {
-       uint32_t rlc_setting, data;
-       unsigned i;
-
-       if (adev->gfx.rlc.in_safe_mode)
-               return;
+       uint32_t rlc_setting;
 
        /* if RLC is not enabled, do nothing */
        rlc_setting = RREG32_SOC15(GC, 0, mmRLC_CNTL);
        if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
-               return;
-
-       if (adev->cg_flags &
-           (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
-            AMD_CG_SUPPORT_GFX_3D_CGCG)) {
-               data = RLC_SAFE_MODE__CMD_MASK;
-               data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
-               WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
+               return false;
 
-               /* wait for RLC_SAFE_MODE */
-               for (i = 0; i < adev->usec_timeout; i++) {
-                       if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
-                               break;
-                       udelay(1);
-               }
-               adev->gfx.rlc.in_safe_mode = true;
-       }
+       return true;
 }
 
-static void gfx_v9_0_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v9_0_set_safe_mode(struct amdgpu_device *adev)
 {
-       uint32_t rlc_setting, data;
+       uint32_t data;
+       unsigned i;
 
-       if (!adev->gfx.rlc.in_safe_mode)
-               return;
+       data = RLC_SAFE_MODE__CMD_MASK;
+       data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
+       WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
 
-       /* if RLC is not enabled, do nothing */
-       rlc_setting = RREG32_SOC15(GC, 0, mmRLC_CNTL);
-       if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
-               return;
-
-       if (adev->cg_flags &
-           (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
-               /*
-                * Try to exit safe mode only if it is already in safe
-                * mode.
-                */
-               data = RLC_SAFE_MODE__CMD_MASK;
-               WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
-               adev->gfx.rlc.in_safe_mode = false;
+       /* wait for RLC_SAFE_MODE */
+       for (i = 0; i < adev->usec_timeout; i++) {
+               if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
+                       break;
+               udelay(1);
        }
 }
 
+static void gfx_v9_0_unset_safe_mode(struct amdgpu_device *adev)
+{
+       uint32_t data;
+
+       data = RLC_SAFE_MODE__CMD_MASK;
+       WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
+}
+
 static void gfx_v9_0_update_gfx_cg_power_gating(struct amdgpu_device *adev,
                                                bool enable)
 {
-       gfx_v9_0_enter_rlc_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) && enable) {
                gfx_v9_0_enable_gfx_cg_power_gating(adev, true);
@@ -3676,7 +3560,7 @@ static void gfx_v9_0_update_gfx_cg_power_gating(struct amdgpu_device *adev,
                gfx_v9_0_enable_gfx_pipeline_powergating(adev, false);
        }
 
-       gfx_v9_0_exit_rlc_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 }
 
 static void gfx_v9_0_update_gfx_mg_power_gating(struct amdgpu_device *adev,
@@ -3774,7 +3658,7 @@ static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev,
 {
        uint32_t data, def;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        /* Enable 3D CGCG/CGLS */
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)) {
@@ -3814,7 +3698,7 @@ static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev,
                        WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data);
        }
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 }
 
 static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
@@ -3822,7 +3706,7 @@ static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
 {
        uint32_t def, data;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
                def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
@@ -3862,7 +3746,7 @@ static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
                        WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data);
        }
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 }
 
 static int gfx_v9_0_update_gfx_clock_gating(struct amdgpu_device *adev,
@@ -3891,8 +3775,17 @@ static int gfx_v9_0_update_gfx_clock_gating(struct amdgpu_device *adev,
 }
 
 static const struct amdgpu_rlc_funcs gfx_v9_0_rlc_funcs = {
-       .enter_safe_mode = gfx_v9_0_enter_rlc_safe_mode,
-       .exit_safe_mode = gfx_v9_0_exit_rlc_safe_mode
+       .is_rlc_enabled = gfx_v9_0_is_rlc_enabled,
+       .set_safe_mode = gfx_v9_0_set_safe_mode,
+       .unset_safe_mode = gfx_v9_0_unset_safe_mode,
+       .init = gfx_v9_0_rlc_init,
+       .get_csb_size = gfx_v9_0_get_csb_size,
+       .get_csb_buffer = gfx_v9_0_get_csb_buffer,
+       .get_cp_table_num = gfx_v9_0_cp_jump_table_num,
+       .resume = gfx_v9_0_rlc_resume,
+       .stop = gfx_v9_0_rlc_stop,
+       .reset = gfx_v9_0_rlc_reset,
+       .start = gfx_v9_0_rlc_start
 };
 
 static int gfx_v9_0_set_powergating_state(void *handle,
@@ -4073,9 +3966,11 @@ static void gfx_v9_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
 }
 
 static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
-                                      struct amdgpu_ib *ib,
-                                      unsigned vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        u32 header, control = 0;
 
        if (ib->flags & AMDGPU_IB_FLAG_CE)
@@ -4104,20 +3999,22 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
 }
 
 static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
-                                          struct amdgpu_ib *ib,
-                                          unsigned vmid, bool ctx_switch)
+                                         struct amdgpu_job *job,
+                                         struct amdgpu_ib *ib,
+                                         bool ctx_switch)
 {
-        u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+       u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
 
-        amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+       amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
        BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
-        amdgpu_ring_write(ring,
+       amdgpu_ring_write(ring,
 #ifdef __BIG_ENDIAN
-                                (2 << 0) |
+                               (2 << 0) |
 #endif
-                                lower_32_bits(ib->gpu_addr));
-        amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
-        amdgpu_ring_write(ring, control);
+                               lower_32_bits(ib->gpu_addr));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
+       amdgpu_ring_write(ring, control);
 }
 
 static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
@@ -4696,12 +4593,39 @@ static int gfx_v9_0_eop_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+static void gfx_v9_0_fault(struct amdgpu_device *adev,
+                          struct amdgpu_iv_entry *entry)
+{
+       u8 me_id, pipe_id, queue_id;
+       struct amdgpu_ring *ring;
+       int i;
+
+       me_id = (entry->ring_id & 0x0c) >> 2;
+       pipe_id = (entry->ring_id & 0x03) >> 0;
+       queue_id = (entry->ring_id & 0x70) >> 4;
+
+       switch (me_id) {
+       case 0:
+               drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+               break;
+       case 1:
+       case 2:
+               for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+                       ring = &adev->gfx.compute_ring[i];
+                       if (ring->me == me_id && ring->pipe == pipe_id &&
+                           ring->queue == queue_id)
+                               drm_sched_fault(&ring->sched);
+               }
+               break;
+       }
+}
+
 static int gfx_v9_0_priv_reg_irq(struct amdgpu_device *adev,
                                 struct amdgpu_irq_src *source,
                                 struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal register access in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v9_0_fault(adev, entry);
        return 0;
 }
 
@@ -4710,7 +4634,7 @@ static int gfx_v9_0_priv_inst_irq(struct amdgpu_device *adev,
                                  struct amdgpu_iv_entry *entry)
 {
        DRM_ERROR("Illegal instruction in command stream\n");
-       schedule_work(&adev->reset_work);
+       gfx_v9_0_fault(adev, entry);
        return 0;
 }
 
@@ -4837,10 +4761,8 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = {
                2 + /* gfx_v9_0_ring_emit_vm_flush */
                8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */
        .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */
-       .emit_ib = gfx_v9_0_ring_emit_ib_compute,
        .emit_fence = gfx_v9_0_ring_emit_fence_kiq,
        .test_ring = gfx_v9_0_ring_test_ring,
-       .test_ib = gfx_v9_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .emit_rreg = gfx_v9_0_ring_emit_rreg,
index bfa317ad20a956017273a7c1fe7ca2decd6491e1..f5edddf3b29d5310ce4e6474d1a04be5e248adbb 100644 (file)
@@ -35,20 +35,25 @@ u64 gfxhub_v1_0_get_mc_fb_offset(struct amdgpu_device *adev)
        return (u64)RREG32_SOC15(GC, 0, mmMC_VM_FB_OFFSET) << 24;
 }
 
-static void gfxhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev)
+void gfxhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+                               uint64_t page_table_base)
 {
-       uint64_t value = amdgpu_gmc_pd_addr(adev->gart.bo);
+       /* two registers distance between mmVM_CONTEXT0_* to mmVM_CONTEXT1_* */
+       int offset = mmVM_CONTEXT1_PAGE_TABLE_BASE_ADDR_LO32
+                       - mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32;
 
-       WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
-                    lower_32_bits(value));
+       WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
+                               offset * vmid, lower_32_bits(page_table_base));
 
-       WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
-                    upper_32_bits(value));
+       WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
+                               offset * vmid, upper_32_bits(page_table_base));
 }
 
 static void gfxhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev)
 {
-       gfxhub_v1_0_init_gart_pt_regs(adev);
+       uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
+
+       gfxhub_v1_0_setup_vm_pt_regs(adev, 0, pt_base);
 
        WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
                     (u32)(adev->gmc.gart_start >> 12));
index 206e29cad7533579f460f3964fc5c07326d50bf1..92d3a70cd9b15ca9b6a956e14d194e148913dc7e 100644 (file)
@@ -30,5 +30,7 @@ void gfxhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev,
                                          bool value);
 void gfxhub_v1_0_init(struct amdgpu_device *adev);
 u64 gfxhub_v1_0_get_mc_fb_offset(struct amdgpu_device *adev);
+void gfxhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+                               uint64_t page_table_base);
 
 #endif
index 73ad02aea2b2e802f0dbce340d70877bdc3b6ca1..9fc3296592fee928fda2ba4cbf960f8725a145fd 100644 (file)
@@ -359,7 +359,8 @@ static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
        return 0;
 }
 
-static void gmc_v6_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid)
+static void gmc_v6_0_flush_gpu_tlb(struct amdgpu_device *adev,
+                               uint32_t vmid, uint32_t flush_type)
 {
        WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
 }
@@ -581,7 +582,7 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev)
        else
                gmc_v6_0_set_fault_enable_default(adev, true);
 
-       gmc_v6_0_flush_gpu_tlb(adev, 0);
+       gmc_v6_0_flush_gpu_tlb(adev, 0, 0);
        dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n",
                 (unsigned)(adev->gmc.gart_size >> 20),
                 (unsigned long long)table_addr);
index 910c4ce19cb3b329e49217e9901c1da5840a829d..761dcfb2fec029e483cb7a90ae1fa004cbfe88eb 100644 (file)
@@ -430,7 +430,8 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
  *
  * Flush the TLB for the requested page table (CIK).
  */
-static void gmc_v7_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid)
+static void gmc_v7_0_flush_gpu_tlb(struct amdgpu_device *adev,
+                               uint32_t vmid, uint32_t flush_type)
 {
        /* bits 0-15 are the VM contexts0-15 */
        WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
@@ -698,7 +699,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
                WREG32(mmCHUB_CONTROL, tmp);
        }
 
-       gmc_v7_0_flush_gpu_tlb(adev, 0);
+       gmc_v7_0_flush_gpu_tlb(adev, 0, 0);
        DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
                 (unsigned)(adev->gmc.gart_size >> 20),
                 (unsigned long long)table_addr);
index 747c068379dc79b5408525dda7d2215b9b128043..1ad7e6b8ed1dcf3f8795eab178f672938e82d050 100644 (file)
@@ -633,7 +633,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
  * Flush the TLB for the requested page table (CIK).
  */
 static void gmc_v8_0_flush_gpu_tlb(struct amdgpu_device *adev,
-                                       uint32_t vmid)
+                               uint32_t vmid, uint32_t flush_type)
 {
        /* bits 0-15 are the VM contexts0-15 */
        WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
@@ -942,7 +942,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
        else
                gmc_v8_0_set_fault_enable_default(adev, true);
 
-       gmc_v8_0_flush_gpu_tlb(adev, 0);
+       gmc_v8_0_flush_gpu_tlb(adev, 0, 0);
        DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
                 (unsigned)(adev->gmc.gart_size >> 20),
                 (unsigned long long)table_addr);
index f35d7a554ad539af16c6dfc4864efcabcbd10980..ce150de723c98132511304944720629a8a9eb460 100644 (file)
@@ -244,6 +244,62 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
        return 0;
 }
 
+/**
+ * vega10_ih_prescreen_iv - prescreen an interrupt vector
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Returns true if the interrupt vector should be further processed.
+ */
+static bool gmc_v9_0_prescreen_iv(struct amdgpu_device *adev,
+                                 struct amdgpu_iv_entry *entry,
+                                 uint64_t addr)
+{
+       struct amdgpu_vm *vm;
+       u64 key;
+       int r;
+
+       /* No PASID, can't identify faulting process */
+       if (!entry->pasid)
+               return true;
+
+       /* Not a retry fault */
+       if (!(entry->src_data[1] & 0x80))
+               return true;
+
+       /* Track retry faults in per-VM fault FIFO. */
+       spin_lock(&adev->vm_manager.pasid_lock);
+       vm = idr_find(&adev->vm_manager.pasid_idr, entry->pasid);
+       if (!vm) {
+               /* VM not found, process it normally */
+               spin_unlock(&adev->vm_manager.pasid_lock);
+               return true;
+       }
+
+       key = AMDGPU_VM_FAULT(entry->pasid, addr);
+       r = amdgpu_vm_add_fault(vm->fault_hash, key);
+
+       /* Hash table is full or the fault is already being processed,
+        * ignore further page faults
+        */
+       if (r != 0) {
+               spin_unlock(&adev->vm_manager.pasid_lock);
+               return false;
+       }
+       /* No locking required with single writer and single reader */
+       r = kfifo_put(&vm->faults, key);
+       if (!r) {
+               /* FIFO is full. Ignore it until there is space */
+               amdgpu_vm_clear_fault(vm->fault_hash, key);
+               spin_unlock(&adev->vm_manager.pasid_lock);
+               return false;
+       }
+
+       spin_unlock(&adev->vm_manager.pasid_lock);
+       /* It's the first fault for this address, process it normally */
+       return true;
+}
+
 static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
                                struct amdgpu_irq_src *source,
                                struct amdgpu_iv_entry *entry)
@@ -255,6 +311,9 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
        addr = (u64)entry->src_data[0] << 12;
        addr |= ((u64)entry->src_data[1] & 0xf) << 44;
 
+       if (!gmc_v9_0_prescreen_iv(adev, entry, addr))
+               return 1; /* This also prevents sending it to KFD */
+
        if (!amdgpu_sriov_vf(adev)) {
                status = RREG32(hub->vm_l2_pro_fault_status);
                WREG32_P(hub->vm_l2_pro_fault_cntl, 1, ~1);
@@ -293,14 +352,14 @@ static void gmc_v9_0_set_irq_funcs(struct amdgpu_device *adev)
        adev->gmc.vm_fault.funcs = &gmc_v9_0_irq_funcs;
 }
 
-static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid)
+static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid,
+                                       uint32_t flush_type)
 {
        u32 req = 0;
 
-       /* invalidate using legacy mode on vmid*/
        req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ,
                            PER_VMID_INVALIDATE_REQ, 1 << vmid);
-       req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, 0);
+       req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type);
        req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1);
        req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1);
        req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1);
@@ -312,48 +371,6 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid)
        return req;
 }
 
-static signed long  amdgpu_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
-                                                 uint32_t reg0, uint32_t reg1,
-                                                 uint32_t ref, uint32_t mask)
-{
-       signed long r, cnt = 0;
-       unsigned long flags;
-       uint32_t seq;
-       struct amdgpu_kiq *kiq = &adev->gfx.kiq;
-       struct amdgpu_ring *ring = &kiq->ring;
-
-       spin_lock_irqsave(&kiq->ring_lock, flags);
-
-       amdgpu_ring_alloc(ring, 32);
-       amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1,
-                                           ref, mask);
-       amdgpu_fence_emit_polling(ring, &seq);
-       amdgpu_ring_commit(ring);
-       spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
-       r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
-
-       /* don't wait anymore for IRQ context */
-       if (r < 1 && in_interrupt())
-               goto failed_kiq;
-
-       might_sleep();
-
-       while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
-               msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
-               r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
-       }
-
-       if (cnt > MAX_KIQ_REG_TRY)
-               goto failed_kiq;
-
-       return 0;
-
-failed_kiq:
-       pr_err("failed to invalidate tlb with kiq\n");
-       return r;
-}
-
 /*
  * GART
  * VMID 0 is the physical GPU addresses as used by the kernel.
@@ -362,64 +379,50 @@ failed_kiq:
  */
 
 /**
- * gmc_v9_0_flush_gpu_tlb - gart tlb flush callback
+ * gmc_v9_0_flush_gpu_tlb - tlb flush with certain type
  *
  * @adev: amdgpu_device pointer
  * @vmid: vm instance to flush
+ * @flush_type: the flush type
  *
- * Flush the TLB for the requested page table.
+ * Flush the TLB for the requested page table using certain type.
  */
 static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev,
-                                       uint32_t vmid)
+                               uint32_t vmid, uint32_t flush_type)
 {
-       /* Use register 17 for GART */
        const unsigned eng = 17;
        unsigned i, j;
-       int r;
 
        for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
                struct amdgpu_vmhub *hub = &adev->vmhub[i];
-               u32 tmp = gmc_v9_0_get_invalidate_req(vmid);
+               u32 tmp = gmc_v9_0_get_invalidate_req(vmid, flush_type);
 
-               if (adev->gfx.kiq.ring.ready &&
+               /* This is necessary for a HW workaround under SRIOV as well
+                * as GFXOFF under bare metal
+                */
+               if (adev->gfx.kiq.ring.sched.ready &&
                    (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) &&
                    !adev->in_gpu_reset) {
-                       r = amdgpu_kiq_reg_write_reg_wait(adev, hub->vm_inv_eng0_req + eng,
-                               hub->vm_inv_eng0_ack + eng, tmp, 1 << vmid);
-                       if (!r)
-                               continue;
-               }
-
-               spin_lock(&adev->gmc.invalidate_lock);
-
-               WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
+                       uint32_t req = hub->vm_inv_eng0_req + eng;
+                       uint32_t ack = hub->vm_inv_eng0_ack + eng;
 
-               /* Busy wait for ACK.*/
-               for (j = 0; j < 100; j++) {
-                       tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + eng);
-                       tmp &= 1 << vmid;
-                       if (tmp)
-                               break;
-                       cpu_relax();
-               }
-               if (j < 100) {
-                       spin_unlock(&adev->gmc.invalidate_lock);
+                       amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, tmp,
+                                                          1 << vmid);
                        continue;
                }
 
-               /* Wait for ACK with a delay.*/
+               spin_lock(&adev->gmc.invalidate_lock);
+               WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
                for (j = 0; j < adev->usec_timeout; j++) {
                        tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + eng);
-                       tmp &= 1 << vmid;
-                       if (tmp)
+                       if (tmp & (1 << vmid))
                                break;
                        udelay(1);
                }
-               if (j < adev->usec_timeout) {
-                       spin_unlock(&adev->gmc.invalidate_lock);
-                       continue;
-               }
                spin_unlock(&adev->gmc.invalidate_lock);
+               if (j < adev->usec_timeout)
+                       continue;
+
                DRM_ERROR("Timeout waiting for VM flush ACK!\n");
        }
 }
@@ -429,7 +432,7 @@ static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
 {
        struct amdgpu_device *adev = ring->adev;
        struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub];
-       uint32_t req = gmc_v9_0_get_invalidate_req(vmid);
+       uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0);
        unsigned eng = ring->vm_inv_eng;
 
        amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
@@ -739,9 +742,8 @@ static int gmc_v9_0_late_init(void *handle)
                unsigned vmhub = ring->funcs->vmhub;
 
                ring->vm_inv_eng = vm_inv_eng[vmhub]++;
-               dev_info(adev->dev, "ring %u(%s) uses VM inv eng %u on hub %u\n",
-                        ring->idx, ring->name, ring->vm_inv_eng,
-                        ring->funcs->vmhub);
+               dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n",
+                        ring->name, ring->vm_inv_eng, ring->funcs->vmhub);
        }
 
        /* Engine 16 is used for KFD and 17 for GART flushes */
@@ -959,6 +961,9 @@ static int gmc_v9_0_sw_init(void *handle)
        /* This interrupt is VMC page fault.*/
        r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VMC, VMC_1_0__SRCID__VM_FAULT,
                                &adev->gmc.vm_fault);
+       if (r)
+               return r;
+
        r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UTCL2, UTCL2_1_0__SRCID__FAULT,
                                &adev->gmc.vm_fault);
 
@@ -991,7 +996,7 @@ static int gmc_v9_0_sw_init(void *handle)
        }
        adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
-       if (adev->asic_type == CHIP_VEGA20) {
+       if (adev->gmc.xgmi.supported) {
                r = gfxhub_v1_1_get_xgmi_info(adev);
                if (r)
                        return r;
@@ -1122,7 +1127,7 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev)
 
        gfxhub_v1_0_set_fault_enable_default(adev, value);
        mmhub_v1_0_set_fault_enable_default(adev, value);
-       gmc_v9_0_flush_gpu_tlb(adev, 0);
+       gmc_v9_0_flush_gpu_tlb(adev, 0, 0);
 
        DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
                 (unsigned)(adev->gmc.gart_size >> 20),
index cf0fc61aebe6d5f2de6f9217126dbb1fa94fe05b..a3984d10b604e1a4127009bf63f57cf3a964da7e 100644 (file)
@@ -207,34 +207,6 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev)
        return (wptr & adev->irq.ih.ptr_mask);
 }
 
-/**
- * iceland_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool iceland_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       u32 ring_index = adev->irq.ih.rptr >> 2;
-       u16 pasid;
-
-       switch (le32_to_cpu(adev->irq.ih.ring[ring_index]) & 0xff) {
-       case 146:
-       case 147:
-               pasid = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]) >> 16;
-               if (!pasid || amdgpu_vm_pasid_fault_credit(adev, pasid))
-                       return true;
-               break;
-       default:
-               /* Not a VM fault */
-               return true;
-       }
-
-       adev->irq.ih.rptr += 16;
-       return false;
-}
-
 /**
  * iceland_ih_decode_iv - decode an interrupt vector
  *
@@ -440,7 +412,6 @@ static const struct amd_ip_funcs iceland_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs iceland_ih_funcs = {
        .get_wptr = iceland_ih_get_wptr,
-       .prescreen_iv = iceland_ih_prescreen_iv,
        .decode_iv = iceland_ih_decode_iv,
        .set_rptr = iceland_ih_set_rptr
 };
index d0e478f434434b633be26692138042e896459714..0c9a2c03504e61be55109ba34c95266b8f9a422f 100644 (file)
@@ -508,19 +508,19 @@ static int kv_enable_didt(struct amdgpu_device *adev, bool enable)
            pi->caps_db_ramping ||
            pi->caps_td_ramping ||
            pi->caps_tcp_ramping) {
-               adev->gfx.rlc.funcs->enter_safe_mode(adev);
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
 
                if (enable) {
                        ret = kv_program_pt_config_registers(adev, didt_config_kv);
                        if (ret) {
-                               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+                               amdgpu_gfx_rlc_exit_safe_mode(adev);
                                return ret;
                        }
                }
 
                kv_do_enable_didt(adev, enable);
 
-               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
        }
 
        return 0;
index a0db67adc34cee3d1ee13ca97d8b333ff36dfdc6..d0d966d6080a6dda87d57d2d8ee1ed2b58a1444a 100644 (file)
@@ -52,20 +52,25 @@ u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev)
        return base;
 }
 
-static void mmhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev)
+void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+                               uint64_t page_table_base)
 {
-       uint64_t value = amdgpu_gmc_pd_addr(adev->gart.bo);
+       /* two registers distance between mmVM_CONTEXT0_* to mmVM_CONTEXT1_* */
+       int offset = mmVM_CONTEXT1_PAGE_TABLE_BASE_ADDR_LO32
+                       - mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32;
 
-       WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
-                    lower_32_bits(value));
+       WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
+                       offset * vmid, lower_32_bits(page_table_base));
 
-       WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
-                    upper_32_bits(value));
+       WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
+                       offset * vmid, upper_32_bits(page_table_base));
 }
 
 static void mmhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev)
 {
-       mmhub_v1_0_init_gart_pt_regs(adev);
+       uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
+
+       mmhub_v1_0_setup_vm_pt_regs(adev, 0, pt_base);
 
        WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
                     (u32)(adev->gmc.gart_start >> 12));
index bef3d0c0c117979928302c098dff95520f323e1b..0de0fdf98c00d9c6144536620afec44dc5e66228 100644 (file)
@@ -34,5 +34,7 @@ int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev,
 void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags);
 void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev,
                                 bool enable);
+void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+                               uint64_t page_table_base);
 
 #endif
index 64e875d528dd858bf2686368a77b95a57372bac9..6a0fcd67662af9a8e6cb3d6581bf0de3a4d2c4b6 100644 (file)
@@ -37,7 +37,6 @@
 #include "gmc/gmc_8_2_sh_mask.h"
 #include "oss/oss_3_0_d.h"
 #include "oss/oss_3_0_sh_mask.h"
-#include "gca/gfx_8_0_sh_mask.h"
 #include "dce/dce_10_0_d.h"
 #include "dce/dce_10_0_sh_mask.h"
 #include "smu/smu_7_1_3_d.h"
index 882bd83a28c4d2ff2a7b23221caab9a254bbbb77..0de00fbe9233843cedf3549e4f5cc8bb875094d5 100644 (file)
@@ -43,6 +43,8 @@ enum psp_gfx_crtl_cmd_id
     GFX_CTRL_CMD_ID_ENABLE_INT      = 0x00050000,   /* enable PSP-to-Gfx interrupt */
     GFX_CTRL_CMD_ID_DISABLE_INT     = 0x00060000,   /* disable PSP-to-Gfx interrupt */
     GFX_CTRL_CMD_ID_MODE1_RST       = 0x00070000,   /* trigger the Mode 1 reset */
+    GFX_CTRL_CMD_ID_CONSUME_CMD     = 0x000A0000,   /* send interrupt to psp for updating write pointer of vf */
+    GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */
 
     GFX_CTRL_CMD_ID_MAX             = 0x000F0000,   /* max command ID */
 };
@@ -89,7 +91,8 @@ enum psp_gfx_cmd_id
     GFX_CMD_ID_LOAD_IP_FW   = 0x00000006,   /* load HW IP FW */
     GFX_CMD_ID_DESTROY_TMR  = 0x00000007,   /* destroy TMR region */
     GFX_CMD_ID_SAVE_RESTORE = 0x00000008,   /* save/restore HW IP FW */
-
+    GFX_CMD_ID_SETUP_VMR    = 0x00000009,   /* setup VMR region */
+    GFX_CMD_ID_DESTROY_VMR  = 0x0000000A,   /* destroy VMR region */
 };
 
 
index 295c2205485a5e8d8a916ba7c7cae43f5092767c..d78b4306a36f33411dd95b12245eedfd2ba9f847 100644 (file)
@@ -240,12 +240,9 @@ static int psp_v10_0_ring_stop(struct psp_context *psp,
                               enum psp_ring_type ring_type)
 {
        int ret = 0;
-       struct psp_ring *ring;
        unsigned int psp_ring_reg = 0;
        struct amdgpu_device *adev = psp->adev;
 
-       ring = &psp->km_ring;
-
        /* Write the ring destroy command to C2PMSG_64 */
        psp_ring_reg = 3 << 16;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg);
index 3f3fac2d50cdf19e002a5ad7773d68003ab5aa57..6c9a1b748ca70dfb5eca172ecfc84ef429b16255 100644 (file)
@@ -34,6 +34,7 @@
 #include "nbio/nbio_7_4_offset.h"
 
 MODULE_FIRMWARE("amdgpu/vega20_sos.bin");
+MODULE_FIRMWARE("amdgpu/vega20_ta.bin");
 
 /* address block */
 #define smnMP1_FIRMWARE_FLAGS          0x3010024
@@ -98,7 +99,8 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
        const char *chip_name;
        char fw_name[30];
        int err = 0;
-       const struct psp_firmware_header_v1_0 *hdr;
+       const struct psp_firmware_header_v1_0 *sos_hdr;
+       const struct ta_firmware_header_v1_0 *ta_hdr;
 
        DRM_DEBUG("\n");
 
@@ -119,16 +121,32 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
        if (err)
                goto out;
 
-       hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
-       adev->psp.sos_fw_version = le32_to_cpu(hdr->header.ucode_version);
-       adev->psp.sos_feature_version = le32_to_cpu(hdr->ucode_feature_version);
-       adev->psp.sos_bin_size = le32_to_cpu(hdr->sos_size_bytes);
-       adev->psp.sys_bin_size = le32_to_cpu(hdr->header.ucode_size_bytes) -
-                                       le32_to_cpu(hdr->sos_size_bytes);
-       adev->psp.sys_start_addr = (uint8_t *)hdr +
-                               le32_to_cpu(hdr->header.ucode_array_offset_bytes);
+       sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
+       adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version);
+       adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->ucode_feature_version);
+       adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos_size_bytes);
+       adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->header.ucode_size_bytes) -
+                                       le32_to_cpu(sos_hdr->sos_size_bytes);
+       adev->psp.sys_start_addr = (uint8_t *)sos_hdr +
+                               le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes);
        adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr +
-                               le32_to_cpu(hdr->sos_offset_bytes);
+                               le32_to_cpu(sos_hdr->sos_offset_bytes);
+
+       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
+       err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+
+       err = amdgpu_ucode_validate(adev->psp.ta_fw);
+       if (err)
+               goto out;
+
+       ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
+       adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version);
+       adev->psp.ta_xgmi_ucode_size = le32_to_cpu(ta_hdr->ta_xgmi_size_bytes);
+       adev->psp.ta_xgmi_start_addr = (uint8_t *)ta_hdr +
+               le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
        return 0;
 out:
        if (err) {
@@ -153,8 +171,11 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
         * are already been loaded.
         */
        sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
-       if (sol_reg)
+       if (sol_reg) {
+               psp->sos_fw_version = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58);
+               printk("sos fw version = 0x%x.\n", psp->sos_fw_version);
                return 0;
+       }
 
        /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */
        ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
@@ -167,7 +188,7 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
        /* Copy PSP System Driver binary to memory */
        memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
 
-       /* Provide the sys driver to bootrom */
+       /* Provide the sys driver to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
        psp_gfxdrv_command_reg = 1 << 16;
@@ -208,7 +229,7 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
        /* Copy Secure OS binary to PSP memory */
        memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
 
-       /* Provide the PSP secure OS to bootrom */
+       /* Provide the PSP secure OS to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
        psp_gfxdrv_command_reg = 2 << 16;
@@ -278,26 +299,47 @@ static int psp_v11_0_ring_create(struct psp_context *psp,
        struct psp_ring *ring = &psp->km_ring;
        struct amdgpu_device *adev = psp->adev;
 
-       /* Write low address of the ring to C2PMSG_69 */
-       psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, psp_ring_reg);
-       /* Write high address of the ring to C2PMSG_70 */
-       psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, psp_ring_reg);
-       /* Write size of ring to C2PMSG_71 */
-       psp_ring_reg = ring->ring_size;
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_71, psp_ring_reg);
-       /* Write the ring initialization command to C2PMSG_64 */
-       psp_ring_reg = ring_type;
-       psp_ring_reg = psp_ring_reg << 16;
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg);
-
-       /* there might be handshake issue with hardware which needs delay */
-       mdelay(20);
-
-       /* Wait for response flag (bit 31) in C2PMSG_64 */
-       ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
-                          0x80000000, 0x8000FFFF, false);
+       if (psp_support_vmr_ring(psp)) {
+               /* Write low address of the ring to C2PMSG_102 */
+               psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_ring_reg);
+               /* Write high address of the ring to C2PMSG_103 */
+               psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_103, psp_ring_reg);
+
+               /* Write the ring initialization command to C2PMSG_101 */
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101,
+                                            GFX_CTRL_CMD_ID_INIT_GPCOM_RING);
+
+               /* there might be handshake issue with hardware which needs delay */
+               mdelay(20);
+
+               /* Wait for response flag (bit 31) in C2PMSG_101 */
+               ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+                                  0x80000000, 0x8000FFFF, false);
+
+       } else {
+               /* Write low address of the ring to C2PMSG_69 */
+               psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, psp_ring_reg);
+               /* Write high address of the ring to C2PMSG_70 */
+               psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, psp_ring_reg);
+               /* Write size of ring to C2PMSG_71 */
+               psp_ring_reg = ring->ring_size;
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_71, psp_ring_reg);
+               /* Write the ring initialization command to C2PMSG_64 */
+               psp_ring_reg = ring_type;
+               psp_ring_reg = psp_ring_reg << 16;
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg);
+
+               /* there might be handshake issue with hardware which needs delay */
+               mdelay(20);
+
+               /* Wait for response flag (bit 31) in C2PMSG_64 */
+               ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+                                  0x80000000, 0x8000FFFF, false);
+       }
 
        return ret;
 }
@@ -308,15 +350,24 @@ static int psp_v11_0_ring_stop(struct psp_context *psp,
        int ret = 0;
        struct amdgpu_device *adev = psp->adev;
 
-       /* Write the ring destroy command to C2PMSG_64 */
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, GFX_CTRL_CMD_ID_DESTROY_RINGS);
+       /* Write the ring destroy command*/
+       if (psp_support_vmr_ring(psp))
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101,
+                                    GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING);
+       else
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64,
+                                    GFX_CTRL_CMD_ID_DESTROY_RINGS);
 
        /* there might be handshake issue with hardware which needs delay */
        mdelay(20);
 
-       /* Wait for response flag (bit 31) in C2PMSG_64 */
-       ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
-                          0x80000000, 0x80000000, false);
+       /* Wait for response flag (bit 31) */
+       if (psp_support_vmr_ring(psp))
+               ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+                                  0x80000000, 0x80000000, false);
+       else
+               ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+                                  0x80000000, 0x80000000, false);
 
        return ret;
 }
@@ -355,7 +406,10 @@ static int psp_v11_0_cmd_submit(struct psp_context *psp,
        uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4;
 
        /* KM (GPCOM) prepare write pointer */
-       psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67);
+       if (psp_support_vmr_ring(psp))
+               psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102);
+       else
+               psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67);
 
        /* Update KM RB frame pointer to new frame */
        /* write_frame ptr increments by size of rb_frame in bytes */
@@ -384,7 +438,11 @@ static int psp_v11_0_cmd_submit(struct psp_context *psp,
 
        /* Update the write Pointer in DWORDs */
        psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw;
-       WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg);
+       if (psp_support_vmr_ring(psp)) {
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg);
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD);
+       } else
+               WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg);
 
        return 0;
 }
@@ -529,7 +587,7 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp)
        /*send the mode 1 reset command*/
        WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST);
 
-       mdelay(1000);
+       msleep(500);
 
        offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33);
 
@@ -552,24 +610,110 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp)
 static int psp_v11_0_xgmi_get_topology_info(struct psp_context *psp,
        int number_devices, struct psp_xgmi_topology_info *topology)
 {
+       struct ta_xgmi_shared_memory *xgmi_cmd;
+       struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
+       struct ta_xgmi_cmd_get_topology_info_output *topology_info_output;
+       int i;
+       int ret;
+
+       if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
+               return -EINVAL;
+
+       xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+       memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+       /* Fill in the shared memory with topology information as input */
+       topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
+       xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO;
+       topology_info_input->num_nodes = number_devices;
+
+       for (i = 0; i < topology_info_input->num_nodes; i++) {
+               topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
+               topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
+               topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
+               topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
+       }
+
+       /* Invoke xgmi ta to get the topology information */
+       ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO);
+       if (ret)
+               return ret;
+
+       /* Read the output topology information from the shared memory */
+       topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info;
+       topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes;
+       for (i = 0; i < topology->num_nodes; i++) {
+               topology->nodes[i].node_id = topology_info_output->nodes[i].node_id;
+               topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops;
+               topology->nodes[i].is_sharing_enabled = topology_info_output->nodes[i].is_sharing_enabled;
+               topology->nodes[i].sdma_engine = topology_info_output->nodes[i].sdma_engine;
+       }
+
        return 0;
 }
 
 static int psp_v11_0_xgmi_set_topology_info(struct psp_context *psp,
        int number_devices, struct psp_xgmi_topology_info *topology)
 {
-       return 0;
+       struct ta_xgmi_shared_memory *xgmi_cmd;
+       struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
+       int i;
+
+       if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
+               return -EINVAL;
+
+       xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+       memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+       topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
+       xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO;
+       topology_info_input->num_nodes = number_devices;
+
+       for (i = 0; i < topology_info_input->num_nodes; i++) {
+               topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
+               topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
+               topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
+               topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
+       }
+
+       /* Invoke xgmi ta to set topology information */
+       return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO);
 }
 
 static u64 psp_v11_0_xgmi_get_hive_id(struct psp_context *psp)
 {
-       u64 hive_id = 0;
+       struct ta_xgmi_shared_memory *xgmi_cmd;
+       int ret;
+
+       xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+       memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
 
-       /* Remove me when we can get correct hive_id through PSP */
-       if (psp->adev->gmc.xgmi.num_physical_nodes)
-               hive_id = 0x123456789abcdef;
+       xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID;
 
-       return hive_id;
+       /* Invoke xgmi ta to get hive id */
+       ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+       if (ret)
+               return 0;
+       else
+               return xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;
+}
+
+static u64 psp_v11_0_xgmi_get_node_id(struct psp_context *psp)
+{
+       struct ta_xgmi_shared_memory *xgmi_cmd;
+       int ret;
+
+       xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+       memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+       xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID;
+
+       /* Invoke xgmi ta to get the node id */
+       ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+       if (ret)
+               return 0;
+       else
+               return xgmi_cmd->xgmi_out_message.get_node_id.node_id;
 }
 
 static const struct psp_funcs psp_v11_0_funcs = {
@@ -587,6 +731,7 @@ static const struct psp_funcs psp_v11_0_funcs = {
        .xgmi_get_topology_info = psp_v11_0_xgmi_get_topology_info,
        .xgmi_set_topology_info = psp_v11_0_xgmi_set_topology_info,
        .xgmi_get_hive_id = psp_v11_0_xgmi_get_hive_id,
+       .xgmi_get_node_id = psp_v11_0_xgmi_get_node_id,
 };
 
 void psp_v11_0_set_psp_funcs(struct psp_context *psp)
index e1ebf770c30357323ca5d65f89cb29d3babd04a2..7357fd56e61445f18bd16b7a2553e9eaf4d1d960 100644 (file)
@@ -194,7 +194,7 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
        /* Copy PSP System Driver binary to memory */
        memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
 
-       /* Provide the sys driver to bootrom */
+       /* Provide the sys driver to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
        psp_gfxdrv_command_reg = 1 << 16;
@@ -254,7 +254,7 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
        /* Copy Secure OS binary to PSP memory */
        memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
 
-       /* Provide the PSP secure OS to bootrom */
+       /* Provide the PSP secure OS to bootloader */
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
               (uint32_t)(psp->fw_pri_mc_addr >> 20));
        psp_gfxdrv_command_reg = 2 << 16;
@@ -356,12 +356,9 @@ static int psp_v3_1_ring_stop(struct psp_context *psp,
                              enum psp_ring_type ring_type)
 {
        int ret = 0;
-       struct psp_ring *ring;
        unsigned int psp_ring_reg = 0;
        struct amdgpu_device *adev = psp->adev;
 
-       ring = &psp->km_ring;
-
        /* Write the ring destroy command to C2PMSG_64 */
        psp_ring_reg = 3 << 16;
        WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg);
@@ -593,9 +590,9 @@ static int psp_v3_1_mode1_reset(struct psp_context *psp)
        }
 
        /*send the mode 1 reset command*/
-       WREG32(offset, 0x70000);
+       WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST);
 
-       mdelay(1000);
+       msleep(500);
 
        offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33);
 
index 2d4770e173dd373f6ece0bc6c65f9a6b627fead5..9f3cb2aec7c2842beb64864188de3e9fe47ebc7a 100644 (file)
@@ -225,7 +225,7 @@ static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring)
 
 static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        int i;
 
        for (i = 0; i < count; i++)
@@ -245,9 +245,12 @@ static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
  * Schedule an IB in the DMA ring (VI).
  */
 static void sdma_v2_4_ring_emit_ib(struct amdgpu_ring *ring,
+                                  struct amdgpu_job *job,
                                   struct amdgpu_ib *ib,
-                                  unsigned vmid, bool ctx_switch)
+                                  bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        /* IB packet must end on a 8 DW boundary */
        sdma_v2_4_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
 
@@ -349,8 +352,8 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev)
                ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
        }
-       sdma0->ready = false;
-       sdma1->ready = false;
+       sdma0->sched.ready = false;
+       sdma1->sched.ready = false;
 }
 
 /**
@@ -471,17 +474,15 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev)
                /* enable DMA IBs */
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
 
-               ring->ready = true;
+               ring->sched.ready = true;
        }
 
        sdma_v2_4_enable(adev, true);
        for (i = 0; i < adev->sdma.num_instances; i++) {
                ring = &adev->sdma.instance[i].ring;
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
                        return r;
-               }
 
                if (adev->mman.buffer_funcs_ring == ring)
                        amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -550,21 +551,16 @@ static int sdma_v2_4_ring_test_ring(struct amdgpu_ring *ring)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
 
        r = amdgpu_ring_alloc(ring, 5);
-       if (r) {
-               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_device_wb_free(adev, index);
-               return r;
-       }
+       if (r)
+               goto error_free_wb;
 
        amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                          SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -581,15 +577,11 @@ static int sdma_v2_4_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       amdgpu_device_wb_free(adev, index);
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
+error_free_wb:
+       amdgpu_device_wb_free(adev, index);
        return r;
 }
 
@@ -612,20 +604,16 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err0;
-       }
 
        ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -644,21 +632,16 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err1;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err1;
        }
        tmp = le32_to_cpu(adev->wb.wb[index]);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+       else
                r = -EINVAL;
-       }
 
 err1:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -760,7 +743,7 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
  */
 static void sdma_v2_4_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        u32 pad_count;
        int i;
 
@@ -1105,8 +1088,14 @@ static int sdma_v2_4_process_illegal_inst_irq(struct amdgpu_device *adev,
                                              struct amdgpu_irq_src *source,
                                              struct amdgpu_iv_entry *entry)
 {
+       u8 instance_id, queue_id;
+
        DRM_ERROR("Illegal instruction in SDMA command stream\n");
-       schedule_work(&adev->reset_work);
+       instance_id = (entry->ring_id & 0x3) >> 0;
+       queue_id = (entry->ring_id & 0xc) >> 2;
+
+       if (instance_id <= 1 && queue_id == 0)
+               drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
        return 0;
 }
 
index 6fb3edaba0ec065fdd57f5af7866e93006bf39b2..1bccc5fe2d9d97865677a25e7c967ec0b3cbe46b 100644 (file)
@@ -399,7 +399,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
 
 static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        int i;
 
        for (i = 0; i < count; i++)
@@ -419,9 +419,12 @@ static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
  * Schedule an IB in the DMA ring (VI).
  */
 static void sdma_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                  struct amdgpu_job *job,
                                   struct amdgpu_ib *ib,
-                                  unsigned vmid, bool ctx_switch)
+                                  bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        /* IB packet must end on a 8 DW boundary */
        sdma_v3_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
 
@@ -523,8 +526,8 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev)
                ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
        }
-       sdma0->ready = false;
-       sdma1->ready = false;
+       sdma0->sched.ready = false;
+       sdma1->sched.ready = false;
 }
 
 /**
@@ -739,7 +742,7 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev)
                /* enable DMA IBs */
                WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
 
-               ring->ready = true;
+               ring->sched.ready = true;
        }
 
        /* unhalt the MEs */
@@ -749,11 +752,9 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev)
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
                ring = &adev->sdma.instance[i].ring;
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
                        return r;
-               }
 
                if (adev->mman.buffer_funcs_ring == ring)
                        amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -822,21 +823,16 @@ static int sdma_v3_0_ring_test_ring(struct amdgpu_ring *ring)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
 
        r = amdgpu_ring_alloc(ring, 5);
-       if (r) {
-               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_device_wb_free(adev, index);
-               return r;
-       }
+       if (r)
+               goto error_free_wb;
 
        amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                          SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -853,15 +849,11 @@ static int sdma_v3_0_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       amdgpu_device_wb_free(adev, index);
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
+error_free_wb:
+       amdgpu_device_wb_free(adev, index);
        return r;
 }
 
@@ -884,20 +876,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err0;
-       }
 
        ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -916,21 +904,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err1;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err1;
        }
        tmp = le32_to_cpu(adev->wb.wb[index]);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+       else
                r = -EINVAL;
-       }
 err1:
        amdgpu_ib_free(adev, &ib, NULL);
        dma_fence_put(f);
@@ -1031,7 +1014,7 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
  */
 static void sdma_v3_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        u32 pad_count;
        int i;
 
@@ -1163,7 +1146,7 @@ static int sdma_v3_0_sw_init(void *handle)
                if (!amdgpu_sriov_vf(adev)) {
                        ring->use_doorbell = true;
                        ring->doorbell_index = (i == 0) ?
-                               AMDGPU_DOORBELL_sDMA_ENGINE0 : AMDGPU_DOORBELL_sDMA_ENGINE1;
+                               adev->doorbell_index.sdma_engine0 : adev->doorbell_index.sdma_engine1;
                } else {
                        ring->use_pollmem = true;
                }
@@ -1440,8 +1423,14 @@ static int sdma_v3_0_process_illegal_inst_irq(struct amdgpu_device *adev,
                                              struct amdgpu_irq_src *source,
                                              struct amdgpu_iv_entry *entry)
 {
+       u8 instance_id, queue_id;
+
        DRM_ERROR("Illegal instruction in SDMA command stream\n");
-       schedule_work(&adev->reset_work);
+       instance_id = (entry->ring_id & 0x3) >> 0;
+       queue_id = (entry->ring_id & 0xc) >> 2;
+
+       if (instance_id <= 1 && queue_id == 0)
+               drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
        return 0;
 }
 
index 7a8c9172d30a946fd91d147f8c73267a51b1fb08..4b6d3e5c821fba1f12974a9b778c1b17eaa71906 100644 (file)
@@ -54,6 +54,11 @@ MODULE_FIRMWARE("amdgpu/raven2_sdma.bin");
 #define SDMA0_POWER_CNTL__ON_OFF_CONDITION_HOLD_TIME_MASK  0x000000F8L
 #define SDMA0_POWER_CNTL__ON_OFF_STATUS_DURATION_TIME_MASK 0xFC000000L
 
+#define WREG32_SDMA(instance, offset, value) \
+       WREG32(sdma_v4_0_get_reg_offset(adev, (instance), (offset)), value)
+#define RREG32_SDMA(instance, offset) \
+       RREG32(sdma_v4_0_get_reg_offset(adev, (instance), (offset)))
+
 static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev);
 static void sdma_v4_0_set_buffer_funcs(struct amdgpu_device *adev);
 static void sdma_v4_0_set_vm_pte_funcs(struct amdgpu_device *adev);
@@ -367,16 +372,11 @@ static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring)
                wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
                DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr);
        } else {
-               u32 lowbit, highbit;
-
-               lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR)) >> 2;
-               highbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2;
-
-               DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n",
-                               ring->me, highbit, lowbit);
-               wptr = highbit;
+               wptr = RREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR_HI);
                wptr = wptr << 32;
-               wptr |= lowbit;
+               wptr |= RREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR);
+               DRM_DEBUG("wptr before shift [%i] wptr == 0x%016llx\n",
+                               ring->me, wptr);
        }
 
        return wptr >> 2;
@@ -417,14 +417,67 @@ static void sdma_v4_0_ring_set_wptr(struct amdgpu_ring *ring)
                                lower_32_bits(ring->wptr << 2),
                                ring->me,
                                upper_32_bits(ring->wptr << 2));
-               WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2));
-               WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2));
+               WREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR,
+                           lower_32_bits(ring->wptr << 2));
+               WREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR_HI,
+                           upper_32_bits(ring->wptr << 2));
+       }
+}
+
+/**
+ * sdma_v4_0_page_ring_get_wptr - get the current write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Get the current wptr from the hardware (VEGA10+).
+ */
+static uint64_t sdma_v4_0_page_ring_get_wptr(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       u64 wptr;
+
+       if (ring->use_doorbell) {
+               /* XXX check if swapping is necessary on BE */
+               wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
+       } else {
+               wptr = RREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR_HI);
+               wptr = wptr << 32;
+               wptr |= RREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR);
+       }
+
+       return wptr >> 2;
+}
+
+/**
+ * sdma_v4_0_ring_set_wptr - commit the write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Write the wptr back to the hardware (VEGA10+).
+ */
+static void sdma_v4_0_page_ring_set_wptr(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+
+       if (ring->use_doorbell) {
+               u64 *wb = (u64 *)&adev->wb.wb[ring->wptr_offs];
+
+               /* XXX check if swapping is necessary on BE */
+               WRITE_ONCE(*wb, (ring->wptr << 2));
+               WDOORBELL64(ring->doorbell_index, ring->wptr << 2);
+       } else {
+               uint64_t wptr = ring->wptr << 2;
+
+               WREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR,
+                           lower_32_bits(wptr));
+               WREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR_HI,
+                           upper_32_bits(wptr));
        }
 }
 
 static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        int i;
 
        for (i = 0; i < count; i++)
@@ -444,9 +497,12 @@ static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
  * Schedule an IB in the DMA ring (VEGA10).
  */
 static void sdma_v4_0_ring_emit_ib(struct amdgpu_ring *ring,
-                                       struct amdgpu_ib *ib,
-                                       unsigned vmid, bool ctx_switch)
+                                  struct amdgpu_job *job,
+                                  struct amdgpu_ib *ib,
+                                  bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        /* IB packet must end on a 8 DW boundary */
        sdma_v4_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
 
@@ -568,16 +624,16 @@ static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev)
                        amdgpu_ttm_set_buffer_funcs_status(adev, false);
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
-               rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL));
+               rb_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL);
                rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
-               ib_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL));
+               WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
+               ib_cntl = RREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL);
                ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl);
+               WREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL, ib_cntl);
        }
 
-       sdma0->ready = false;
-       sdma1->ready = false;
+       sdma0->sched.ready = false;
+       sdma1->sched.ready = false;
 }
 
 /**
@@ -592,6 +648,39 @@ static void sdma_v4_0_rlc_stop(struct amdgpu_device *adev)
        /* XXX todo */
 }
 
+/**
+ * sdma_v4_0_page_stop - stop the page async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Stop the page async dma ring buffers (VEGA10).
+ */
+static void sdma_v4_0_page_stop(struct amdgpu_device *adev)
+{
+       struct amdgpu_ring *sdma0 = &adev->sdma.instance[0].page;
+       struct amdgpu_ring *sdma1 = &adev->sdma.instance[1].page;
+       u32 rb_cntl, ib_cntl;
+       int i;
+
+       if ((adev->mman.buffer_funcs_ring == sdma0) ||
+           (adev->mman.buffer_funcs_ring == sdma1))
+               amdgpu_ttm_set_buffer_funcs_status(adev, false);
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               rb_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL);
+               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL,
+                                       RB_ENABLE, 0);
+               WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
+               ib_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL);
+               ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL,
+                                       IB_ENABLE, 0);
+               WREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL, ib_cntl);
+       }
+
+       sdma0->sched.ready = false;
+       sdma1->sched.ready = false;
+}
+
 /**
  * sdma_v_0_ctx_switch_enable - stop the async dma engines context switch
  *
@@ -630,18 +719,15 @@ static void sdma_v4_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable)
        }
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
-               f32_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL));
+               f32_cntl = RREG32_SDMA(i, mmSDMA0_CNTL);
                f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL,
                                AUTO_CTXSW_ENABLE, enable ? 1 : 0);
                if (enable && amdgpu_sdma_phase_quantum) {
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE0_QUANTUM),
-                              phase_quantum);
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE1_QUANTUM),
-                              phase_quantum);
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE2_QUANTUM),
-                              phase_quantum);
+                       WREG32_SDMA(i, mmSDMA0_PHASE0_QUANTUM, phase_quantum);
+                       WREG32_SDMA(i, mmSDMA0_PHASE1_QUANTUM, phase_quantum);
+                       WREG32_SDMA(i, mmSDMA0_PHASE2_QUANTUM, phase_quantum);
                }
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL), f32_cntl);
+               WREG32_SDMA(i, mmSDMA0_CNTL, f32_cntl);
        }
 
 }
@@ -662,156 +748,215 @@ static void sdma_v4_0_enable(struct amdgpu_device *adev, bool enable)
        if (enable == false) {
                sdma_v4_0_gfx_stop(adev);
                sdma_v4_0_rlc_stop(adev);
+               if (adev->sdma.has_page_queue)
+                       sdma_v4_0_page_stop(adev);
        }
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
-               f32_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL));
+               f32_cntl = RREG32_SDMA(i, mmSDMA0_F32_CNTL);
                f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl);
+               WREG32_SDMA(i, mmSDMA0_F32_CNTL, f32_cntl);
        }
 }
 
+/**
+ * sdma_v4_0_rb_cntl - get parameters for rb_cntl
+ */
+static uint32_t sdma_v4_0_rb_cntl(struct amdgpu_ring *ring, uint32_t rb_cntl)
+{
+       /* Set ring buffer size in dwords */
+       uint32_t rb_bufsz = order_base_2(ring->ring_size / 4);
+
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz);
+#ifdef __BIG_ENDIAN
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1);
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
+                               RPTR_WRITEBACK_SWAP_ENABLE, 1);
+#endif
+       return rb_cntl;
+}
+
 /**
  * sdma_v4_0_gfx_resume - setup and start the async dma engines
  *
  * @adev: amdgpu_device pointer
+ * @i: instance to resume
  *
  * Set up the gfx DMA ring buffers and enable them (VEGA10).
  * Returns 0 for success, error for failure.
  */
-static int sdma_v4_0_gfx_resume(struct amdgpu_device *adev)
+static void sdma_v4_0_gfx_resume(struct amdgpu_device *adev, unsigned int i)
 {
-       struct amdgpu_ring *ring;
+       struct amdgpu_ring *ring = &adev->sdma.instance[i].ring;
        u32 rb_cntl, ib_cntl, wptr_poll_cntl;
-       u32 rb_bufsz;
        u32 wb_offset;
        u32 doorbell;
        u32 doorbell_offset;
-       u32 temp;
        u64 wptr_gpu_addr;
-       int i, r;
 
-       for (i = 0; i < adev->sdma.num_instances; i++) {
-               ring = &adev->sdma.instance[i].ring;
-               wb_offset = (ring->rptr_offs * 4);
+       wb_offset = (ring->rptr_offs * 4);
 
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0);
+       rb_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL);
+       rb_cntl = sdma_v4_0_rb_cntl(ring, rb_cntl);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
 
-               /* Set ring buffer size in dwords */
-               rb_bufsz = order_base_2(ring->ring_size / 4);
-               rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL));
-               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz);
-#ifdef __BIG_ENDIAN
-               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1);
-               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
-                                       RPTR_WRITEBACK_SWAP_ENABLE, 1);
-#endif
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
+       /* Initialize the ring buffer's read and write pointers */
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR, 0);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_HI, 0);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR, 0);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_HI, 0);
 
-               /* Initialize the ring buffer's read and write pointers */
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), 0);
+       /* set the wb address whether it's enabled or not */
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_ADDR_HI,
+              upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_ADDR_LO,
+              lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
 
-               /* set the wb address whether it's enabled or not */
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI),
-                      upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO),
-                      lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
+                               RPTR_WRITEBACK_ENABLE, 1);
 
-               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_BASE, ring->gpu_addr >> 8);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_BASE_HI, ring->gpu_addr >> 40);
 
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), ring->gpu_addr >> 8);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), ring->gpu_addr >> 40);
+       ring->wptr = 0;
 
-               ring->wptr = 0;
+       /* before programing wptr to a less value, need set minor_ptr_update first */
+       WREG32_SDMA(i, mmSDMA0_GFX_MINOR_PTR_UPDATE, 1);
 
-               /* before programing wptr to a less value, need set minor_ptr_update first */
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1);
-
-               if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr) << 2);
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr) << 2);
-               }
+       doorbell = RREG32_SDMA(i, mmSDMA0_GFX_DOORBELL);
+       doorbell_offset = RREG32_SDMA(i, mmSDMA0_GFX_DOORBELL_OFFSET);
 
-               doorbell = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL));
-               doorbell_offset = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET));
-
-               if (ring->use_doorbell) {
-                       doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1);
-                       doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET,
+       doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE,
+                                ring->use_doorbell);
+       doorbell_offset = REG_SET_FIELD(doorbell_offset,
+                                       SDMA0_GFX_DOORBELL_OFFSET,
                                        OFFSET, ring->doorbell_index);
-               } else {
-                       doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0);
-               }
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), doorbell_offset);
-               adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
-                                                     ring->doorbell_index);
+       WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL, doorbell);
+       WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL_OFFSET, doorbell_offset);
+       adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
+                                             ring->doorbell_index);
+
+       sdma_v4_0_ring_set_wptr(ring);
+
+       /* set minor_ptr_update to 0 after wptr programed */
+       WREG32_SDMA(i, mmSDMA0_GFX_MINOR_PTR_UPDATE, 0);
+
+       /* setup the wptr shadow polling */
+       wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO,
+                   lower_32_bits(wptr_gpu_addr));
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI,
+                   upper_32_bits(wptr_gpu_addr));
+       wptr_poll_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL);
+       wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl,
+                                      SDMA0_GFX_RB_WPTR_POLL_CNTL,
+                                      F32_POLL_ENABLE, amdgpu_sriov_vf(adev));
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL, wptr_poll_cntl);
+
+       /* enable DMA RB */
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1);
+       WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
+
+       ib_cntl = RREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL);
+       ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1);
+#ifdef __BIG_ENDIAN
+       ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1);
+#endif
+       /* enable DMA IBs */
+       WREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL, ib_cntl);
 
-               if (amdgpu_sriov_vf(adev))
-                       sdma_v4_0_ring_set_wptr(ring);
+       ring->sched.ready = true;
+}
 
-               /* set minor_ptr_update to 0 after wptr programed */
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0);
+/**
+ * sdma_v4_0_page_resume - setup and start the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ * @i: instance to resume
+ *
+ * Set up the page DMA ring buffers and enable them (VEGA10).
+ * Returns 0 for success, error for failure.
+ */
+static void sdma_v4_0_page_resume(struct amdgpu_device *adev, unsigned int i)
+{
+       struct amdgpu_ring *ring = &adev->sdma.instance[i].page;
+       u32 rb_cntl, ib_cntl, wptr_poll_cntl;
+       u32 wb_offset;
+       u32 doorbell;
+       u32 doorbell_offset;
+       u64 wptr_gpu_addr;
 
-               /* set utc l1 enable flag always to 1 */
-               temp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL));
-               temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL), temp);
+       wb_offset = (ring->rptr_offs * 4);
 
-               if (!amdgpu_sriov_vf(adev)) {
-                       /* unhalt engine */
-                       temp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL));
-                       temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0);
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp);
-               }
+       rb_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL);
+       rb_cntl = sdma_v4_0_rb_cntl(ring, rb_cntl);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
 
-               /* setup the wptr shadow polling */
-               wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO),
-                      lower_32_bits(wptr_gpu_addr));
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI),
-                      upper_32_bits(wptr_gpu_addr));
-               wptr_poll_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL));
-               if (amdgpu_sriov_vf(adev))
-                       wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, SDMA0_GFX_RB_WPTR_POLL_CNTL, F32_POLL_ENABLE, 1);
-               else
-                       wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, SDMA0_GFX_RB_WPTR_POLL_CNTL, F32_POLL_ENABLE, 0);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), wptr_poll_cntl);
+       /* Initialize the ring buffer's read and write pointers */
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR, 0);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_HI, 0);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR, 0);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_HI, 0);
 
-               /* enable DMA RB */
-               rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1);
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
+       /* set the wb address whether it's enabled or not */
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_ADDR_HI,
+              upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_ADDR_LO,
+              lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
 
-               ib_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL));
-               ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1);
-#ifdef __BIG_ENDIAN
-               ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1);
-#endif
-               /* enable DMA IBs */
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl);
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL,
+                               RPTR_WRITEBACK_ENABLE, 1);
 
-               ring->ready = true;
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_BASE, ring->gpu_addr >> 8);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_BASE_HI, ring->gpu_addr >> 40);
 
-               if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */
-                       sdma_v4_0_ctx_switch_enable(adev, true);
-                       sdma_v4_0_enable(adev, true);
-               }
+       ring->wptr = 0;
 
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
-                       return r;
-               }
+       /* before programing wptr to a less value, need set minor_ptr_update first */
+       WREG32_SDMA(i, mmSDMA0_PAGE_MINOR_PTR_UPDATE, 1);
 
-               if (adev->mman.buffer_funcs_ring == ring)
-                       amdgpu_ttm_set_buffer_funcs_status(adev, true);
+       doorbell = RREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL);
+       doorbell_offset = RREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL_OFFSET);
 
-       }
+       doorbell = REG_SET_FIELD(doorbell, SDMA0_PAGE_DOORBELL, ENABLE,
+                                ring->use_doorbell);
+       doorbell_offset = REG_SET_FIELD(doorbell_offset,
+                                       SDMA0_PAGE_DOORBELL_OFFSET,
+                                       OFFSET, ring->doorbell_index);
+       WREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL, doorbell);
+       WREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL_OFFSET, doorbell_offset);
+
+       /* paging queue doorbell range is setup at sdma_v4_0_gfx_resume */
+       sdma_v4_0_page_ring_set_wptr(ring);
+
+       /* set minor_ptr_update to 0 after wptr programed */
+       WREG32_SDMA(i, mmSDMA0_PAGE_MINOR_PTR_UPDATE, 0);
+
+       /* setup the wptr shadow polling */
+       wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_ADDR_LO,
+                   lower_32_bits(wptr_gpu_addr));
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_ADDR_HI,
+                   upper_32_bits(wptr_gpu_addr));
+       wptr_poll_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_CNTL);
+       wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl,
+                                      SDMA0_PAGE_RB_WPTR_POLL_CNTL,
+                                      F32_POLL_ENABLE, amdgpu_sriov_vf(adev));
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_CNTL, wptr_poll_cntl);
+
+       /* enable DMA RB */
+       rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL, RB_ENABLE, 1);
+       WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
+
+       ib_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL);
+       ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL, IB_ENABLE, 1);
+#ifdef __BIG_ENDIAN
+       ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL, IB_SWAP_ENABLE, 1);
+#endif
+       /* enable DMA IBs */
+       WREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL, ib_cntl);
 
-       return 0;
+       ring->sched.ready = true;
 }
 
 static void
@@ -922,12 +1067,14 @@ static int sdma_v4_0_load_microcode(struct amdgpu_device *adev)
                        (adev->sdma.instance[i].fw->data +
                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
 
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_ADDR), 0);
+               WREG32_SDMA(i, mmSDMA0_UCODE_ADDR, 0);
 
                for (j = 0; j < fw_size; j++)
-                       WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_DATA), le32_to_cpup(fw_data++));
+                       WREG32_SDMA(i, mmSDMA0_UCODE_DATA,
+                                   le32_to_cpup(fw_data++));
 
-               WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_ADDR), adev->sdma.instance[i].fw_version);
+               WREG32_SDMA(i, mmSDMA0_UCODE_ADDR,
+                           adev->sdma.instance[i].fw_version);
        }
 
        return 0;
@@ -943,33 +1090,78 @@ static int sdma_v4_0_load_microcode(struct amdgpu_device *adev)
  */
 static int sdma_v4_0_start(struct amdgpu_device *adev)
 {
-       int r = 0;
+       struct amdgpu_ring *ring;
+       int i, r;
 
        if (amdgpu_sriov_vf(adev)) {
                sdma_v4_0_ctx_switch_enable(adev, false);
                sdma_v4_0_enable(adev, false);
+       } else {
 
-               /* set RB registers */
-               r = sdma_v4_0_gfx_resume(adev);
-               return r;
+               if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
+                       r = sdma_v4_0_load_microcode(adev);
+                       if (r)
+                               return r;
+               }
+
+               /* unhalt the MEs */
+               sdma_v4_0_enable(adev, true);
+               /* enable sdma ring preemption */
+               sdma_v4_0_ctx_switch_enable(adev, true);
        }
 
-       if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
-               r = sdma_v4_0_load_microcode(adev);
+       /* start the gfx rings and rlc compute queues */
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               uint32_t temp;
+
+               WREG32_SDMA(i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL, 0);
+               sdma_v4_0_gfx_resume(adev, i);
+               if (adev->sdma.has_page_queue)
+                       sdma_v4_0_page_resume(adev, i);
+
+               /* set utc l1 enable flag always to 1 */
+               temp = RREG32_SDMA(i, mmSDMA0_CNTL);
+               temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1);
+               WREG32_SDMA(i, mmSDMA0_CNTL, temp);
+
+               if (!amdgpu_sriov_vf(adev)) {
+                       /* unhalt engine */
+                       temp = RREG32_SDMA(i, mmSDMA0_F32_CNTL);
+                       temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0);
+                       WREG32_SDMA(i, mmSDMA0_F32_CNTL, temp);
+               }
+       }
+
+       if (amdgpu_sriov_vf(adev)) {
+               sdma_v4_0_ctx_switch_enable(adev, true);
+               sdma_v4_0_enable(adev, true);
+       } else {
+               r = sdma_v4_0_rlc_resume(adev);
                if (r)
                        return r;
        }
 
-       /* unhalt the MEs */
-       sdma_v4_0_enable(adev, true);
-       /* enable sdma ring preemption */
-       sdma_v4_0_ctx_switch_enable(adev, true);
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               ring = &adev->sdma.instance[i].ring;
+
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
+                       return r;
 
-       /* start the gfx rings and rlc compute queues */
-       r = sdma_v4_0_gfx_resume(adev);
-       if (r)
-               return r;
-       r = sdma_v4_0_rlc_resume(adev);
+               if (adev->sdma.has_page_queue) {
+                       struct amdgpu_ring *page = &adev->sdma.instance[i].page;
+
+                       r = amdgpu_ring_test_helper(page);
+                       if (r)
+                               return r;
+
+                       if (adev->mman.buffer_funcs_ring == page)
+                               amdgpu_ttm_set_buffer_funcs_status(adev, true);
+               }
+
+               if (adev->mman.buffer_funcs_ring == ring)
+                       amdgpu_ttm_set_buffer_funcs_status(adev, true);
+       }
 
        return r;
 }
@@ -993,21 +1185,16 @@ static int sdma_v4_0_ring_test_ring(struct amdgpu_ring *ring)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
 
        r = amdgpu_ring_alloc(ring, 5);
-       if (r) {
-               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_device_wb_free(adev, index);
-               return r;
-       }
+       if (r)
+               goto error_free_wb;
 
        amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                          SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -1024,15 +1211,11 @@ static int sdma_v4_0_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       amdgpu_device_wb_free(adev, index);
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
+error_free_wb:
+       amdgpu_device_wb_free(adev, index);
        return r;
 }
 
@@ -1055,20 +1238,16 @@ static int sdma_v4_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err0;
-       }
 
        ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
                SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -1087,21 +1266,17 @@ static int sdma_v4_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err1;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err1;
        }
        tmp = le32_to_cpu(adev->wb.wb[index]);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+       else
                r = -EINVAL;
-       }
+
 err1:
        amdgpu_ib_free(adev, &ib, NULL);
        dma_fence_put(f);
@@ -1206,7 +1381,7 @@ static void sdma_v4_0_vm_set_pte_pde(struct amdgpu_ib *ib,
  */
 static void sdma_v4_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
 {
-       struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+       struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
        u32 pad_count;
        int i;
 
@@ -1272,15 +1447,46 @@ static void sdma_v4_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
        sdma_v4_0_wait_reg_mem(ring, 0, 0, reg, 0, val, mask, 10);
 }
 
+static bool sdma_v4_0_fw_support_paging_queue(struct amdgpu_device *adev)
+{
+       uint fw_version = adev->sdma.instance[0].fw_version;
+
+       switch (adev->asic_type) {
+       case CHIP_VEGA10:
+               return fw_version >= 430;
+       case CHIP_VEGA12:
+               /*return fw_version >= 31;*/
+               return false;
+       case CHIP_VEGA20:
+               /*return fw_version >= 115;*/
+               return false;
+       default:
+               return false;
+       }
+}
+
 static int sdma_v4_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int r;
 
        if (adev->asic_type == CHIP_RAVEN)
                adev->sdma.num_instances = 1;
        else
                adev->sdma.num_instances = 2;
 
+       r = sdma_v4_0_init_microcode(adev);
+       if (r) {
+               DRM_ERROR("Failed to load sdma firmware!\n");
+               return r;
+       }
+
+       /* TODO: Page queue breaks driver reload under SRIOV */
+       if ((adev->asic_type == CHIP_VEGA10) && amdgpu_sriov_vf((adev)))
+               adev->sdma.has_page_queue = false;
+       else if (sdma_v4_0_fw_support_paging_queue(adev))
+               adev->sdma.has_page_queue = true;
+
        sdma_v4_0_set_ring_funcs(adev);
        sdma_v4_0_set_buffer_funcs(adev);
        sdma_v4_0_set_vm_pte_funcs(adev);
@@ -1289,7 +1495,6 @@ static int sdma_v4_0_early_init(void *handle)
        return 0;
 }
 
-
 static int sdma_v4_0_sw_init(void *handle)
 {
        struct amdgpu_ring *ring;
@@ -1308,12 +1513,6 @@ static int sdma_v4_0_sw_init(void *handle)
        if (r)
                return r;
 
-       r = sdma_v4_0_init_microcode(adev);
-       if (r) {
-               DRM_ERROR("Failed to load sdma firmware!\n");
-               return r;
-       }
-
        for (i = 0; i < adev->sdma.num_instances; i++) {
                ring = &adev->sdma.instance[i].ring;
                ring->ring_obj = NULL;
@@ -1322,15 +1521,10 @@ static int sdma_v4_0_sw_init(void *handle)
                DRM_INFO("use_doorbell being set to: [%s]\n",
                                ring->use_doorbell?"true":"false");
 
-               if (adev->asic_type == CHIP_VEGA10)
-                       ring->doorbell_index = (i == 0) ?
-                               (AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE0 << 1) //get DWORD offset
-                               : (AMDGPU_VEGA10_DOORBELL64_sDMA_ENGINE1 << 1); // get DWORD offset
-               else
-                       ring->doorbell_index = (i == 0) ?
-                               (AMDGPU_DOORBELL64_sDMA_ENGINE0 << 1) //get DWORD offset
-                               : (AMDGPU_DOORBELL64_sDMA_ENGINE1 << 1); // get DWORD offset
-
+               /* doorbell size is 2 dwords, get DWORD offset */
+               ring->doorbell_index = (i == 0) ?
+                       (adev->doorbell_index.sdma_engine0 << 1)
+                       : (adev->doorbell_index.sdma_engine1 << 1);
 
                sprintf(ring->name, "sdma%d", i);
                r = amdgpu_ring_init(adev, ring, 1024,
@@ -1340,6 +1534,29 @@ static int sdma_v4_0_sw_init(void *handle)
                                     AMDGPU_SDMA_IRQ_TRAP1);
                if (r)
                        return r;
+
+               if (adev->sdma.has_page_queue) {
+                       ring = &adev->sdma.instance[i].page;
+                       ring->ring_obj = NULL;
+                       ring->use_doorbell = true;
+
+                       /* paging queue use same doorbell index/routing as gfx queue
+                        * with 0x400 (4096 dwords) offset on second doorbell page
+                        */
+                       ring->doorbell_index = (i == 0) ?
+                               (adev->doorbell_index.sdma_engine0 << 1)
+                               : (adev->doorbell_index.sdma_engine1 << 1);
+                       ring->doorbell_index += 0x400;
+
+                       sprintf(ring->name, "page%d", i);
+                       r = amdgpu_ring_init(adev, ring, 1024,
+                                            &adev->sdma.trap_irq,
+                                            (i == 0) ?
+                                            AMDGPU_SDMA_IRQ_TRAP0 :
+                                            AMDGPU_SDMA_IRQ_TRAP1);
+                       if (r)
+                               return r;
+               }
        }
 
        return r;
@@ -1350,8 +1567,11 @@ static int sdma_v4_0_sw_fini(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int i;
 
-       for (i = 0; i < adev->sdma.num_instances; i++)
+       for (i = 0; i < adev->sdma.num_instances; i++) {
                amdgpu_ring_fini(&adev->sdma.instance[i].ring);
+               if (adev->sdma.has_page_queue)
+                       amdgpu_ring_fini(&adev->sdma.instance[i].page);
+       }
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
                release_firmware(adev->sdma.instance[i].fw);
@@ -1414,7 +1634,7 @@ static bool sdma_v4_0_is_idle(void *handle)
        u32 i;
 
        for (i = 0; i < adev->sdma.num_instances; i++) {
-               u32 tmp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_STATUS_REG));
+               u32 tmp = RREG32_SDMA(i, mmSDMA0_STATUS_REG);
 
                if (!(tmp & SDMA0_STATUS_REG__IDLE_MASK))
                        return false;
@@ -1430,8 +1650,8 @@ static int sdma_v4_0_wait_for_idle(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        for (i = 0; i < adev->usec_timeout; i++) {
-               sdma0 = RREG32(sdma_v4_0_get_reg_offset(adev, 0, mmSDMA0_STATUS_REG));
-               sdma1 = RREG32(sdma_v4_0_get_reg_offset(adev, 1, mmSDMA0_STATUS_REG));
+               sdma0 = RREG32_SDMA(0, mmSDMA0_STATUS_REG);
+               sdma1 = RREG32_SDMA(1, mmSDMA0_STATUS_REG);
 
                if (sdma0 & sdma1 & SDMA0_STATUS_REG__IDLE_MASK)
                        return 0;
@@ -1452,16 +1672,13 @@ static int sdma_v4_0_set_trap_irq_state(struct amdgpu_device *adev,
                                        unsigned type,
                                        enum amdgpu_interrupt_state state)
 {
+       unsigned int instance = (type == AMDGPU_SDMA_IRQ_TRAP0) ? 0 : 1;
        u32 sdma_cntl;
 
-       u32 reg_offset = (type == AMDGPU_SDMA_IRQ_TRAP0) ?
-               sdma_v4_0_get_reg_offset(adev, 0, mmSDMA0_CNTL) :
-               sdma_v4_0_get_reg_offset(adev, 1, mmSDMA0_CNTL);
-
-       sdma_cntl = RREG32(reg_offset);
+       sdma_cntl = RREG32_SDMA(instance, mmSDMA0_CNTL);
        sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE,
                       state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
-       WREG32(reg_offset, sdma_cntl);
+       WREG32_SDMA(instance, mmSDMA0_CNTL, sdma_cntl);
 
        return 0;
 }
@@ -1470,39 +1687,32 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev,
                                      struct amdgpu_irq_src *source,
                                      struct amdgpu_iv_entry *entry)
 {
+       uint32_t instance;
+
        DRM_DEBUG("IH: SDMA trap\n");
        switch (entry->client_id) {
        case SOC15_IH_CLIENTID_SDMA0:
-               switch (entry->ring_id) {
-               case 0:
-                       amdgpu_fence_process(&adev->sdma.instance[0].ring);
-                       break;
-               case 1:
-                       /* XXX compute */
-                       break;
-               case 2:
-                       /* XXX compute */
-                       break;
-               case 3:
-                       /* XXX page queue*/
-                       break;
-               }
+               instance = 0;
                break;
        case SOC15_IH_CLIENTID_SDMA1:
-               switch (entry->ring_id) {
-               case 0:
-                       amdgpu_fence_process(&adev->sdma.instance[1].ring);
-                       break;
-               case 1:
-                       /* XXX compute */
-                       break;
-               case 2:
-                       /* XXX compute */
-                       break;
-               case 3:
-                       /* XXX page queue*/
-                       break;
-               }
+               instance = 1;
+               break;
+       default:
+               return 0;
+       }
+
+       switch (entry->ring_id) {
+       case 0:
+               amdgpu_fence_process(&adev->sdma.instance[instance].ring);
+               break;
+       case 1:
+               /* XXX compute */
+               break;
+       case 2:
+               /* XXX compute */
+               break;
+       case 3:
+               amdgpu_fence_process(&adev->sdma.instance[instance].page);
                break;
        }
        return 0;
@@ -1512,12 +1722,29 @@ static int sdma_v4_0_process_illegal_inst_irq(struct amdgpu_device *adev,
                                              struct amdgpu_irq_src *source,
                                              struct amdgpu_iv_entry *entry)
 {
+       int instance;
+
        DRM_ERROR("Illegal instruction in SDMA command stream\n");
-       schedule_work(&adev->reset_work);
+
+       switch (entry->client_id) {
+       case SOC15_IH_CLIENTID_SDMA0:
+               instance = 0;
+               break;
+       case SOC15_IH_CLIENTID_SDMA1:
+               instance = 1;
+               break;
+       default:
+               return 0;
+       }
+
+       switch (entry->ring_id) {
+       case 0:
+               drm_sched_fault(&adev->sdma.instance[instance].ring.sched);
+               break;
+       }
        return 0;
 }
 
-
 static void sdma_v4_0_update_medium_grain_clock_gating(
                struct amdgpu_device *adev,
                bool enable)
@@ -1730,6 +1957,38 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = {
        .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
 };
 
+static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs = {
+       .type = AMDGPU_RING_TYPE_SDMA,
+       .align_mask = 0xf,
+       .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
+       .support_64bit_ptrs = true,
+       .vmhub = AMDGPU_MMHUB,
+       .get_rptr = sdma_v4_0_ring_get_rptr,
+       .get_wptr = sdma_v4_0_page_ring_get_wptr,
+       .set_wptr = sdma_v4_0_page_ring_set_wptr,
+       .emit_frame_size =
+               6 + /* sdma_v4_0_ring_emit_hdp_flush */
+               3 + /* hdp invalidate */
+               6 + /* sdma_v4_0_ring_emit_pipeline_sync */
+               /* sdma_v4_0_ring_emit_vm_flush */
+               SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
+               SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 +
+               10 + 10 + 10, /* sdma_v4_0_ring_emit_fence x3 for user fence, vm fence */
+       .emit_ib_size = 7 + 6, /* sdma_v4_0_ring_emit_ib */
+       .emit_ib = sdma_v4_0_ring_emit_ib,
+       .emit_fence = sdma_v4_0_ring_emit_fence,
+       .emit_pipeline_sync = sdma_v4_0_ring_emit_pipeline_sync,
+       .emit_vm_flush = sdma_v4_0_ring_emit_vm_flush,
+       .emit_hdp_flush = sdma_v4_0_ring_emit_hdp_flush,
+       .test_ring = sdma_v4_0_ring_test_ring,
+       .test_ib = sdma_v4_0_ring_test_ib,
+       .insert_nop = sdma_v4_0_ring_insert_nop,
+       .pad_ib = sdma_v4_0_ring_pad_ib,
+       .emit_wreg = sdma_v4_0_ring_emit_wreg,
+       .emit_reg_wait = sdma_v4_0_ring_emit_reg_wait,
+       .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
+};
+
 static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev)
 {
        int i;
@@ -1737,6 +1996,10 @@ static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev)
        for (i = 0; i < adev->sdma.num_instances; i++) {
                adev->sdma.instance[i].ring.funcs = &sdma_v4_0_ring_funcs;
                adev->sdma.instance[i].ring.me = i;
+               if (adev->sdma.has_page_queue) {
+                       adev->sdma.instance[i].page.funcs = &sdma_v4_0_page_ring_funcs;
+                       adev->sdma.instance[i].page.me = i;
+               }
        }
 }
 
@@ -1818,7 +2081,10 @@ static const struct amdgpu_buffer_funcs sdma_v4_0_buffer_funcs = {
 static void sdma_v4_0_set_buffer_funcs(struct amdgpu_device *adev)
 {
        adev->mman.buffer_funcs = &sdma_v4_0_buffer_funcs;
-       adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring;
+       if (adev->sdma.has_page_queue)
+               adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].page;
+       else
+               adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring;
 }
 
 static const struct amdgpu_vm_pte_funcs sdma_v4_0_vm_pte_funcs = {
@@ -1836,7 +2102,10 @@ static void sdma_v4_0_set_vm_pte_funcs(struct amdgpu_device *adev)
 
        adev->vm_manager.vm_pte_funcs = &sdma_v4_0_vm_pte_funcs;
        for (i = 0; i < adev->sdma.num_instances; i++) {
-               sched = &adev->sdma.instance[i].ring.sched;
+               if (adev->sdma.has_page_queue)
+                       sched = &adev->sdma.instance[i].page.sched;
+               else
+                       sched = &adev->sdma.instance[i].ring.sched;
                adev->vm_manager.vm_pte_rqs[i] =
                        &sched->sched_rq[DRM_SCHED_PRIORITY_KERNEL];
        }
index adbaea6da0d71a28a5b2cc510614fcde9692d9b6..b6e473134e19fae3bb107fa9160676616ecd44fc 100644 (file)
@@ -61,9 +61,11 @@ static void si_dma_ring_set_wptr(struct amdgpu_ring *ring)
 }
 
 static void si_dma_ring_emit_ib(struct amdgpu_ring *ring,
+                               struct amdgpu_job *job,
                                struct amdgpu_ib *ib,
-                               unsigned vmid, bool ctx_switch)
+                               bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
        /* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
         * Pad as necessary with NOPs.
         */
@@ -122,7 +124,7 @@ static void si_dma_stop(struct amdgpu_device *adev)
 
                if (adev->mman.buffer_funcs_ring == ring)
                        amdgpu_ttm_set_buffer_funcs_status(adev, false);
-               ring->ready = false;
+               ring->sched.ready = false;
        }
 }
 
@@ -175,13 +177,11 @@ static int si_dma_start(struct amdgpu_device *adev)
                WREG32(DMA_RB_WPTR + sdma_offsets[i], lower_32_bits(ring->wptr) << 2);
                WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl | DMA_RB_ENABLE);
 
-               ring->ready = true;
+               ring->sched.ready = true;
 
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
                        return r;
-               }
 
                if (adev->mman.buffer_funcs_ring == ring)
                        amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -209,21 +209,16 @@ static int si_dma_ring_test_ring(struct amdgpu_ring *ring)
        u64 gpu_addr;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
 
        r = amdgpu_ring_alloc(ring, 4);
-       if (r) {
-               DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
-               amdgpu_device_wb_free(adev, index);
-               return r;
-       }
+       if (r)
+               goto error_free_wb;
 
        amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1));
        amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
@@ -238,15 +233,11 @@ static int si_dma_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
-       amdgpu_device_wb_free(adev, index);
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
 
+error_free_wb:
+       amdgpu_device_wb_free(adev, index);
        return r;
 }
 
@@ -269,20 +260,16 @@ static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = amdgpu_device_wb_get(adev, &index);
-       if (r) {
-               dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+       if (r)
                return r;
-       }
 
        gpu_addr = adev->wb.gpu_addr + (index * 4);
        tmp = 0xCAFEDEAD;
        adev->wb.wb[index] = cpu_to_le32(tmp);
        memset(&ib, 0, sizeof(ib));
        r = amdgpu_ib_get(adev, NULL, 256, &ib);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+       if (r)
                goto err0;
-       }
 
        ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1);
        ib.ptr[1] = lower_32_bits(gpu_addr);
@@ -295,21 +282,16 @@ static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 
        r = dma_fence_wait_timeout(f, false, timeout);
        if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out\n");
                r = -ETIMEDOUT;
                goto err1;
        } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
                goto err1;
        }
        tmp = le32_to_cpu(adev->wb.wb[index]);
-       if (tmp == 0xDEADBEEF) {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       if (tmp == 0xDEADBEEF)
                r = 0;
-       } else {
-               DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+       else
                r = -EINVAL;
-       }
 
 err1:
        amdgpu_ib_free(adev, &ib, NULL);
@@ -658,15 +640,6 @@ static int si_dma_process_trap_irq(struct amdgpu_device *adev,
        return 0;
 }
 
-static int si_dma_process_illegal_inst_irq(struct amdgpu_device *adev,
-                                             struct amdgpu_irq_src *source,
-                                             struct amdgpu_iv_entry *entry)
-{
-       DRM_ERROR("Illegal instruction in SDMA command stream\n");
-       schedule_work(&adev->reset_work);
-       return 0;
-}
-
 static int si_dma_set_clockgating_state(void *handle,
                                          enum amd_clockgating_state state)
 {
@@ -781,15 +754,10 @@ static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs = {
        .process = si_dma_process_trap_irq,
 };
 
-static const struct amdgpu_irq_src_funcs si_dma_illegal_inst_irq_funcs = {
-       .process = si_dma_process_illegal_inst_irq,
-};
-
 static void si_dma_set_irq_funcs(struct amdgpu_device *adev)
 {
        adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST;
        adev->sdma.trap_irq.funcs = &si_dma_trap_irq_funcs;
-       adev->sdma.illegal_inst_irq.funcs = &si_dma_illegal_inst_irq_funcs;
 }
 
 /**
index b3d7d9f83202d8a31379ef42288e2a2dc7f5f6af..2938fb9f17cc75c071ee0468434366fa68b39a4c 100644 (file)
@@ -118,19 +118,6 @@ static u32 si_ih_get_wptr(struct amdgpu_device *adev)
        return (wptr & adev->irq.ih.ptr_mask);
 }
 
-/**
- * si_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool si_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       /* Process all interrupts */
-       return true;
-}
-
 static void si_ih_decode_iv(struct amdgpu_device *adev,
                             struct amdgpu_iv_entry *entry)
 {
@@ -301,7 +288,6 @@ static const struct amd_ip_funcs si_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs si_ih_funcs = {
        .get_wptr = si_ih_get_wptr,
-       .prescreen_iv = si_ih_prescreen_iv,
        .decode_iv = si_ih_decode_iv,
        .set_rptr = si_ih_set_rptr
 };
index 4cc0dcb1a1875bfc559affd1f55e268a25e6282e..8849b74078d6e5373d82fba3f82980cf1bc4c8a7 100644 (file)
@@ -507,6 +507,9 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
                return -EINVAL;
        }
 
+       if (adev->asic_type == CHIP_VEGA20)
+               adev->gmc.xgmi.supported = true;
+
        if (adev->flags & AMD_IS_APU)
                adev->nbio_funcs = &nbio_v7_0_funcs;
        else if (adev->asic_type == CHIP_VEGA20)
@@ -613,6 +616,24 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =
        .flush_hdp = &soc15_flush_hdp,
        .invalidate_hdp = &soc15_invalidate_hdp,
        .need_full_reset = &soc15_need_full_reset,
+       .init_doorbell_index = &vega10_doorbell_index_init,
+};
+
+static const struct amdgpu_asic_funcs vega20_asic_funcs =
+{
+       .read_disabled_bios = &soc15_read_disabled_bios,
+       .read_bios_from_rom = &soc15_read_bios_from_rom,
+       .read_register = &soc15_read_register,
+       .reset = &soc15_asic_reset,
+       .set_vga_state = &soc15_vga_set_state,
+       .get_xclk = &soc15_get_xclk,
+       .set_uvd_clocks = &soc15_set_uvd_clocks,
+       .set_vce_clocks = &soc15_set_vce_clocks,
+       .get_config_memsize = &soc15_get_config_memsize,
+       .flush_hdp = &soc15_flush_hdp,
+       .invalidate_hdp = &soc15_invalidate_hdp,
+       .need_full_reset = &soc15_need_full_reset,
+       .init_doorbell_index = &vega20_doorbell_index_init,
 };
 
 static int soc15_common_early_init(void *handle)
@@ -632,11 +653,11 @@ static int soc15_common_early_init(void *handle)
        adev->se_cac_rreg = &soc15_se_cac_rreg;
        adev->se_cac_wreg = &soc15_se_cac_wreg;
 
-       adev->asic_funcs = &soc15_asic_funcs;
 
        adev->external_rev_id = 0xFF;
        switch (adev->asic_type) {
        case CHIP_VEGA10:
+               adev->asic_funcs = &soc15_asic_funcs;
                adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
                        AMD_CG_SUPPORT_GFX_MGLS |
                        AMD_CG_SUPPORT_GFX_RLC_LS |
@@ -660,6 +681,7 @@ static int soc15_common_early_init(void *handle)
                adev->external_rev_id = 0x1;
                break;
        case CHIP_VEGA12:
+               adev->asic_funcs = &soc15_asic_funcs;
                adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
                        AMD_CG_SUPPORT_GFX_MGLS |
                        AMD_CG_SUPPORT_GFX_CGCG |
@@ -682,6 +704,7 @@ static int soc15_common_early_init(void *handle)
                adev->external_rev_id = adev->rev_id + 0x14;
                break;
        case CHIP_VEGA20:
+               adev->asic_funcs = &vega20_asic_funcs;
                adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
                        AMD_CG_SUPPORT_GFX_MGLS |
                        AMD_CG_SUPPORT_GFX_CGCG |
@@ -704,6 +727,7 @@ static int soc15_common_early_init(void *handle)
                adev->external_rev_id = adev->rev_id + 0x28;
                break;
        case CHIP_RAVEN:
+               adev->asic_funcs = &soc15_asic_funcs;
                if (adev->rev_id >= 0x8)
                        adev->external_rev_id = adev->rev_id + 0x81;
                else if (adev->pdev->device == 0x15d8)
index f8ad7804dc406a3b22e8fb30ae30334dba656fbc..a66c8bfbbaa6d87f89b5e799dfa881a2e7bf0201 100644 (file)
@@ -58,4 +58,6 @@ void soc15_program_register_sequence(struct amdgpu_device *adev,
 int vega10_reg_base_init(struct amdgpu_device *adev);
 int vega20_reg_base_init(struct amdgpu_device *adev);
 
+void vega10_doorbell_index_init(struct amdgpu_device *adev);
+void vega20_doorbell_index_init(struct amdgpu_device *adev);
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h b/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h
new file mode 100644 (file)
index 0000000..ac2c27b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _TA_XGMI_IF_H
+#define _TA_XGMI_IF_H
+
+/* Responses have bit 31 set */
+#define RSP_ID_MASK (1U << 31)
+#define RSP_ID(cmdId) (((uint32_t)(cmdId)) | RSP_ID_MASK)
+
+enum ta_command_xgmi {
+       TA_COMMAND_XGMI__INITIALIZE                     = 0x00,
+       TA_COMMAND_XGMI__GET_NODE_ID                    = 0x01,
+       TA_COMMAND_XGMI__GET_HIVE_ID                    = 0x02,
+       TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO          = 0x03,
+       TA_COMMAND_XGMI__SET_TOPOLOGY_INFO              = 0x04
+};
+
+/* XGMI related enumerations */
+/**********************************************************/;
+enum ta_xgmi_connected_nodes {
+       TA_XGMI__MAX_CONNECTED_NODES                    = 64
+};
+
+enum ta_xgmi_status {
+       TA_XGMI_STATUS__SUCCESS                         = 0x00,
+       TA_XGMI_STATUS__GENERIC_FAILURE                 = 0x01,
+       TA_XGMI_STATUS__NULL_POINTER                    = 0x02,
+       TA_XGMI_STATUS__INVALID_PARAMETER               = 0x03,
+       TA_XGMI_STATUS__NOT_INITIALIZED                 = 0x04,
+       TA_XGMI_STATUS__INVALID_NODE_NUM                = 0x05,
+       TA_XGMI_STATUS__INVALID_NODE_ID                 = 0x06,
+       TA_XGMI_STATUS__INVALID_TOPOLOGY                = 0x07,
+       TA_XGMI_STATUS__FAILED_ID_GEN                   = 0x08,
+       TA_XGMI_STATUS__FAILED_TOPOLOGY_INIT            = 0x09,
+       TA_XGMI_STATUS__SET_SHARING_ERROR               = 0x0A
+};
+
+enum ta_xgmi_assigned_sdma_engine {
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__NOT_ASSIGNED      = -1,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA0             = 0,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA1             = 1,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA2             = 2,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA3             = 3,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA4             = 4,
+       TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA5             = 5
+};
+
+/* input/output structures for XGMI commands */
+/**********************************************************/
+struct ta_xgmi_node_info {
+       uint64_t                                node_id;
+       uint8_t                                 num_hops;
+       uint8_t                                 is_sharing_enabled;
+       enum ta_xgmi_assigned_sdma_engine       sdma_engine;
+};
+
+struct ta_xgmi_cmd_initialize_output {
+       uint32_t        status;
+};
+
+struct ta_xgmi_cmd_get_node_id_output {
+       uint64_t        node_id;
+};
+
+struct ta_xgmi_cmd_get_hive_id_output {
+       uint64_t        hive_id;
+};
+
+struct ta_xgmi_cmd_get_topology_info_input {
+       uint32_t                        num_nodes;
+       struct ta_xgmi_node_info        nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+struct ta_xgmi_cmd_get_topology_info_output {
+       uint32_t                        num_nodes;
+       struct ta_xgmi_node_info        nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+struct ta_xgmi_cmd_set_topology_info_input {
+       uint32_t                        num_nodes;
+       struct ta_xgmi_node_info        nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+/**********************************************************/
+/* Common input structure for XGMI callbacks */
+union ta_xgmi_cmd_input {
+       struct ta_xgmi_cmd_get_topology_info_input      get_topology_info;
+       struct ta_xgmi_cmd_set_topology_info_input      set_topology_info;
+};
+
+/* Common output structure for XGMI callbacks */
+union ta_xgmi_cmd_output {
+       struct ta_xgmi_cmd_initialize_output            initialize;
+       struct ta_xgmi_cmd_get_node_id_output           get_node_id;
+       struct ta_xgmi_cmd_get_hive_id_output           get_hive_id;
+       struct ta_xgmi_cmd_get_topology_info_output     get_topology_info;
+};
+/**********************************************************/
+
+struct ta_xgmi_shared_memory {
+       uint32_t                        cmd_id;
+       uint32_t                        resp_id;
+       enum ta_xgmi_status             xgmi_status;
+       uint32_t                        reserved;
+       union ta_xgmi_cmd_input         xgmi_in_message;
+       union ta_xgmi_cmd_output        xgmi_out_message;
+};
+
+#endif   //_TA_XGMI_IF_H
index 3abffd06b5c785488795a952ece19680e4d559d1..15da06ddeb751d9f20e1a461d5a0e4276186a3dc 100644 (file)
@@ -218,34 +218,6 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev)
        return (wptr & adev->irq.ih.ptr_mask);
 }
 
-/**
- * tonga_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool tonga_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       u32 ring_index = adev->irq.ih.rptr >> 2;
-       u16 pasid;
-
-       switch (le32_to_cpu(adev->irq.ih.ring[ring_index]) & 0xff) {
-       case 146:
-       case 147:
-               pasid = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]) >> 16;
-               if (!pasid || amdgpu_vm_pasid_fault_credit(adev, pasid))
-                       return true;
-               break;
-       default:
-               /* Not a VM fault */
-               return true;
-       }
-
-       adev->irq.ih.rptr += 16;
-       return false;
-}
-
 /**
  * tonga_ih_decode_iv - decode an interrupt vector
  *
@@ -322,7 +294,7 @@ static int tonga_ih_sw_init(void *handle)
                return r;
 
        adev->irq.ih.use_doorbell = true;
-       adev->irq.ih.doorbell_index = AMDGPU_DOORBELL_IH;
+       adev->irq.ih.doorbell_index = adev->doorbell_index.ih;
 
        r = amdgpu_irq_init(adev);
 
@@ -506,7 +478,6 @@ static const struct amd_ip_funcs tonga_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs tonga_ih_funcs = {
        .get_wptr = tonga_ih_get_wptr,
-       .prescreen_iv = tonga_ih_prescreen_iv,
        .decode_iv = tonga_ih_decode_iv,
        .set_rptr = tonga_ih_set_rptr
 };
index 1fc17bf39fed710f77c8ff94d741af579965639d..d69c8f6daaf80a0b062287cc7c4cf4ec3de2a356 100644 (file)
@@ -116,16 +116,16 @@ static int uvd_v4_2_sw_init(void *handle)
        if (r)
                return r;
 
-       r = amdgpu_uvd_resume(adev);
-       if (r)
-               return r;
-
        ring = &adev->uvd.inst->ring;
        sprintf(ring->name, "uvd");
        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst->irq, 0);
        if (r)
                return r;
 
+       r = amdgpu_uvd_resume(adev);
+       if (r)
+               return r;
+
        r = amdgpu_uvd_entity_init(adev);
 
        return r;
@@ -162,12 +162,9 @@ static int uvd_v4_2_hw_init(void *handle)
        uvd_v4_2_enable_mgcg(adev, true);
        amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
 
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                goto done;
-       }
 
        r = amdgpu_ring_alloc(ring, 10);
        if (r) {
@@ -218,7 +215,7 @@ static int uvd_v4_2_hw_fini(void *handle)
        if (RREG32(mmUVD_STATUS) != 0)
                uvd_v4_2_stop(adev);
 
-       ring->ready = false;
+       ring->sched.ready = false;
 
        return 0;
 }
@@ -484,11 +481,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
 
        WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
        amdgpu_ring_write(ring, 0xDEADBEEF);
        amdgpu_ring_commit(ring);
@@ -499,14 +494,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
        return r;
 }
 
@@ -519,8 +509,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
  * Write ring commands to execute the indirect buffer
  */
 static void uvd_v4_2_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
        amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_BASE, 0));
        amdgpu_ring_write(ring, ib->gpu_addr);
index fde6ad5ac9ab3ff8dc640a5a73cfb32dd99976e6..ee8cd06ddc385f08deb8271b3751696ecd1200b3 100644 (file)
@@ -113,16 +113,16 @@ static int uvd_v5_0_sw_init(void *handle)
        if (r)
                return r;
 
-       r = amdgpu_uvd_resume(adev);
-       if (r)
-               return r;
-
        ring = &adev->uvd.inst->ring;
        sprintf(ring->name, "uvd");
        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst->irq, 0);
        if (r)
                return r;
 
+       r = amdgpu_uvd_resume(adev);
+       if (r)
+               return r;
+
        r = amdgpu_uvd_entity_init(adev);
 
        return r;
@@ -158,12 +158,9 @@ static int uvd_v5_0_hw_init(void *handle)
        uvd_v5_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
        uvd_v5_0_enable_mgcg(adev, true);
 
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                goto done;
-       }
 
        r = amdgpu_ring_alloc(ring, 10);
        if (r) {
@@ -215,7 +212,7 @@ static int uvd_v5_0_hw_fini(void *handle)
        if (RREG32(mmUVD_STATUS) != 0)
                uvd_v5_0_stop(adev);
 
-       ring->ready = false;
+       ring->sched.ready = false;
 
        return 0;
 }
@@ -500,11 +497,8 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
 
        WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
        amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
        amdgpu_ring_write(ring, 0xDEADBEEF);
        amdgpu_ring_commit(ring);
@@ -515,14 +509,9 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
        return r;
 }
 
@@ -535,8 +524,9 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
  * Write ring commands to execute the indirect buffer
  */
 static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
        amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_64BIT_BAR_LOW, 0));
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
index 7a5b40275e8e7b0ffa7600c99af464dfe5031a23..d4f4a66f8324131f1e8d925026ee9ad39471d25e 100644 (file)
@@ -175,11 +175,8 @@ static int uvd_v6_0_enc_ring_test_ring(struct amdgpu_ring *ring)
        int r;
 
        r = amdgpu_ring_alloc(ring, 16);
-       if (r) {
-               DRM_ERROR("amdgpu: uvd enc failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
        amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
        amdgpu_ring_commit(ring);
 
@@ -189,14 +186,8 @@ static int uvd_v6_0_enc_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed\n",
-                         ring->idx);
+       if (i >= adev->usec_timeout)
                r = -ETIMEDOUT;
-       }
 
        return r;
 }
@@ -336,31 +327,24 @@ static int uvd_v6_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = uvd_v6_0_enc_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = uvd_v6_0_enc_get_destroy_msg(ring, 1, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: IB test timed out.\n");
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
-       } else {
-               DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+       else if (r > 0)
                r = 0;
-       }
+
 error:
        dma_fence_put(fence);
        return r;
 }
+
 static int uvd_v6_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -416,16 +400,16 @@ static int uvd_v6_0_sw_init(void *handle)
                DRM_INFO("UVD ENC is disabled\n");
        }
 
-       r = amdgpu_uvd_resume(adev);
-       if (r)
-               return r;
-
        ring = &adev->uvd.inst->ring;
        sprintf(ring->name, "uvd");
        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst->irq, 0);
        if (r)
                return r;
 
+       r = amdgpu_uvd_resume(adev);
+       if (r)
+               return r;
+
        if (uvd_v6_0_enc_support(adev)) {
                for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
                        ring = &adev->uvd.inst->ring_enc[i];
@@ -476,12 +460,9 @@ static int uvd_v6_0_hw_init(void *handle)
        uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
        uvd_v6_0_enable_mgcg(adev, true);
 
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                goto done;
-       }
 
        r = amdgpu_ring_alloc(ring, 10);
        if (r) {
@@ -513,12 +494,9 @@ static int uvd_v6_0_hw_init(void *handle)
        if (uvd_v6_0_enc_support(adev)) {
                for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
                        ring = &adev->uvd.inst->ring_enc[i];
-                       ring->ready = true;
-                       r = amdgpu_ring_test_ring(ring);
-                       if (r) {
-                               ring->ready = false;
+                       r = amdgpu_ring_test_helper(ring);
+                       if (r)
                                goto done;
-                       }
                }
        }
 
@@ -548,7 +526,7 @@ static int uvd_v6_0_hw_fini(void *handle)
        if (RREG32(mmUVD_STATUS) != 0)
                uvd_v6_0_stop(adev);
 
-       ring->ready = false;
+       ring->sched.ready = false;
 
        return 0;
 }
@@ -969,11 +947,9 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
 
        WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
-                         ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
        amdgpu_ring_write(ring, 0xDEADBEEF);
        amdgpu_ring_commit(ring);
@@ -984,14 +960,9 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
-                        ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
        return r;
 }
 
@@ -1004,9 +975,12 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
  * Write ring commands to execute the indirect buffer
  */
 static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_VMID, 0));
        amdgpu_ring_write(ring, vmid);
 
@@ -1027,8 +1001,12 @@ static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
  * Write enc ring commands to execute the indirect buffer
  */
 static void uvd_v6_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
-               struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, HEVC_ENC_CMD_IB_VM);
        amdgpu_ring_write(ring, vmid);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
index 58b39afcfb86461d68e47496578184d2c7b74317..089645e78f987485042009d80f9f0228a6091e99 100644 (file)
@@ -183,11 +183,8 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring)
                return 0;
 
        r = amdgpu_ring_alloc(ring, 16);
-       if (r) {
-               DRM_ERROR("amdgpu: uvd enc failed to lock (%d)ring %d (%d).\n",
-                         ring->me, ring->idx, r);
+       if (r)
                return r;
-       }
        amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
        amdgpu_ring_commit(ring);
 
@@ -197,14 +194,8 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("(%d)ring test on %d succeeded in %d usecs\n",
-                        ring->me, ring->idx, i);
-       } else {
-               DRM_ERROR("amdgpu: (%d)ring %d test failed\n",
-                         ring->me, ring->idx);
+       if (i >= adev->usec_timeout)
                r = -ETIMEDOUT;
-       }
 
        return r;
 }
@@ -343,27 +334,19 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
        long r;
 
        r = uvd_v7_0_enc_get_create_msg(ring, 1, NULL);
-       if (r) {
-               DRM_ERROR("amdgpu: (%d)failed to get create msg (%ld).\n", ring->me, r);
+       if (r)
                goto error;
-       }
 
        r = uvd_v7_0_enc_get_destroy_msg(ring, 1, &fence);
-       if (r) {
-               DRM_ERROR("amdgpu: (%d)failed to get destroy ib (%ld).\n", ring->me, r);
+       if (r)
                goto error;
-       }
 
        r = dma_fence_wait_timeout(fence, false, timeout);
-       if (r == 0) {
-               DRM_ERROR("amdgpu: (%d)IB test timed out.\n", ring->me);
+       if (r == 0)
                r = -ETIMEDOUT;
-       } else if (r < 0) {
-               DRM_ERROR("amdgpu: (%d)fence wait failed (%ld).\n", ring->me, r);
-       } else {
-               DRM_DEBUG("ib test on (%d)ring %d succeeded\n", ring->me, ring->idx);
+       else if (r > 0)
                r = 0;
-       }
+
 error:
        dma_fence_put(fence);
        return r;
@@ -447,10 +430,6 @@ static int uvd_v7_0_sw_init(void *handle)
                DRM_INFO("PSP loading UVD firmware\n");
        }
 
-       r = amdgpu_uvd_resume(adev);
-       if (r)
-               return r;
-
        for (j = 0; j < adev->uvd.num_uvd_inst; j++) {
                if (adev->uvd.harvest_config & (1 << j))
                        continue;
@@ -472,9 +451,9 @@ static int uvd_v7_0_sw_init(void *handle)
                                 * sriov, so set unused location for other unused rings.
                                 */
                                if (i == 0)
-                                       ring->doorbell_index = AMDGPU_DOORBELL64_UVD_RING0_1 * 2;
+                                       ring->doorbell_index = adev->doorbell_index.uvd_vce.uvd_ring0_1 * 2;
                                else
-                                       ring->doorbell_index = AMDGPU_DOORBELL64_UVD_RING2_3 * 2 + 1;
+                                       ring->doorbell_index = adev->doorbell_index.uvd_vce.uvd_ring2_3 * 2 + 1;
                        }
                        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.inst[j].irq, 0);
                        if (r)
@@ -482,6 +461,10 @@ static int uvd_v7_0_sw_init(void *handle)
                }
        }
 
+       r = amdgpu_uvd_resume(adev);
+       if (r)
+               return r;
+
        r = amdgpu_uvd_entity_init(adev);
        if (r)
                return r;
@@ -540,12 +523,9 @@ static int uvd_v7_0_hw_init(void *handle)
                ring = &adev->uvd.inst[j].ring;
 
                if (!amdgpu_sriov_vf(adev)) {
-                       ring->ready = true;
-                       r = amdgpu_ring_test_ring(ring);
-                       if (r) {
-                               ring->ready = false;
+                       r = amdgpu_ring_test_helper(ring);
+                       if (r)
                                goto done;
-                       }
 
                        r = amdgpu_ring_alloc(ring, 10);
                        if (r) {
@@ -582,12 +562,9 @@ static int uvd_v7_0_hw_init(void *handle)
 
                for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
                        ring = &adev->uvd.inst[j].ring_enc[i];
-                       ring->ready = true;
-                       r = amdgpu_ring_test_ring(ring);
-                       if (r) {
-                               ring->ready = false;
+                       r = amdgpu_ring_test_helper(ring);
+                       if (r)
                                goto done;
-                       }
                }
        }
 done:
@@ -619,7 +596,7 @@ static int uvd_v7_0_hw_fini(void *handle)
        for (i = 0; i < adev->uvd.num_uvd_inst; ++i) {
                if (adev->uvd.harvest_config & (1 << i))
                        continue;
-               adev->uvd.inst[i].ring.ready = false;
+               adev->uvd.inst[i].ring.sched.ready = false;
        }
 
        return 0;
@@ -1235,11 +1212,9 @@ static int uvd_v7_0_ring_test_ring(struct amdgpu_ring *ring)
 
        WREG32_SOC15(UVD, ring->me, mmUVD_CONTEXT_ID, 0xCAFEDEAD);
        r = amdgpu_ring_alloc(ring, 3);
-       if (r) {
-               DRM_ERROR("amdgpu: (%d)cp failed to lock ring %d (%d).\n",
-                         ring->me, ring->idx, r);
+       if (r)
                return r;
-       }
+
        amdgpu_ring_write(ring,
                PACKET0(SOC15_REG_OFFSET(UVD, ring->me, mmUVD_CONTEXT_ID), 0));
        amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -1251,14 +1226,9 @@ static int uvd_v7_0_ring_test_ring(struct amdgpu_ring *ring)
                DRM_UDELAY(1);
        }
 
-       if (i < adev->usec_timeout) {
-               DRM_DEBUG("(%d)ring test on %d succeeded in %d usecs\n",
-                        ring->me, ring->idx, i);
-       } else {
-               DRM_ERROR("(%d)amdgpu: ring %d test failed (0x%08X)\n",
-                         ring->me, ring->idx, tmp);
-               r = -EINVAL;
-       }
+       if (i >= adev->usec_timeout)
+               r = -ETIMEDOUT;
+
        return r;
 }
 
@@ -1300,10 +1270,12 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
  * Write ring commands to execute the indirect buffer
  */
 static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
+                                 struct amdgpu_job *job,
                                  struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                 bool ctx_switch)
 {
        struct amdgpu_device *adev = ring->adev;
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
        amdgpu_ring_write(ring,
                PACKET0(SOC15_REG_OFFSET(UVD, ring->me, mmUVD_LMI_RBC_IB_VMID), 0));
@@ -1329,8 +1301,12 @@ static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
  * Write enc ring commands to execute the indirect buffer
  */
 static void uvd_v7_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
-               struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, HEVC_ENC_CMD_IB_VM);
        amdgpu_ring_write(ring, vmid);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
index ea28828360d3b3c1d181d0214134b33f8dba7704..bed78a778e3f1f546e30e18dc67f709751d87fc6 100644 (file)
@@ -463,15 +463,11 @@ static int vce_v2_0_hw_init(void *handle)
 
        amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
        vce_v2_0_enable_mgcg(adev, true, false);
-       for (i = 0; i < adev->vce.num_rings; i++)
-               adev->vce.ring[i].ready = false;
 
        for (i = 0; i < adev->vce.num_rings; i++) {
-               r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+               r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
                if (r)
                        return r;
-               else
-                       adev->vce.ring[i].ready = true;
        }
 
        DRM_INFO("VCE initialized successfully.\n");
index 6dbd39730070a30132f7841a1e7dc18a8e54a35a..2668effadd271a3cfc1d6cd35d631975716b5689 100644 (file)
@@ -37,7 +37,6 @@
 #include "gca/gfx_8_0_d.h"
 #include "smu/smu_7_1_2_d.h"
 #include "smu/smu_7_1_2_sh_mask.h"
-#include "gca/gfx_8_0_d.h"
 #include "gca/gfx_8_0_sh_mask.h"
 #include "ivsrcid/ivsrcid_vislands30.h"
 
@@ -474,15 +473,10 @@ static int vce_v3_0_hw_init(void *handle)
 
        amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
 
-       for (i = 0; i < adev->vce.num_rings; i++)
-               adev->vce.ring[i].ready = false;
-
        for (i = 0; i < adev->vce.num_rings; i++) {
-               r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+               r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
                if (r)
                        return r;
-               else
-                       adev->vce.ring[i].ready = true;
        }
 
        DRM_INFO("VCE initialized successfully.\n");
@@ -838,8 +832,12 @@ out:
 }
 
 static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
-               struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+                                 struct amdgpu_job *job,
+                                 struct amdgpu_ib *ib,
+                                 bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, VCE_CMD_IB_VM);
        amdgpu_ring_write(ring, vmid);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
index 1c9471890bf71b9ce94a5eecb96f4594eba01bc0..9fb34b7d8e03e88f411dcf369a79d4853aaef897 100644 (file)
@@ -466,9 +466,9 @@ static int vce_v4_0_sw_init(void *handle)
                         * so set unused location for other unused rings.
                         */
                        if (i == 0)
-                               ring->doorbell_index = AMDGPU_DOORBELL64_VCE_RING0_1 * 2;
+                               ring->doorbell_index = adev->doorbell_index.uvd_vce.vce_ring0_1 * 2;
                        else
-                               ring->doorbell_index = AMDGPU_DOORBELL64_VCE_RING2_3 * 2 + 1;
+                               ring->doorbell_index = adev->doorbell_index.uvd_vce.vce_ring2_3 * 2 + 1;
                }
                r = amdgpu_ring_init(adev, ring, 512, &adev->vce.irq, 0);
                if (r)
@@ -519,15 +519,10 @@ static int vce_v4_0_hw_init(void *handle)
        if (r)
                return r;
 
-       for (i = 0; i < adev->vce.num_rings; i++)
-               adev->vce.ring[i].ready = false;
-
        for (i = 0; i < adev->vce.num_rings; i++) {
-               r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+               r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
                if (r)
                        return r;
-               else
-                       adev->vce.ring[i].ready = true;
        }
 
        DRM_INFO("VCE initialized successfully.\n");
@@ -549,7 +544,7 @@ static int vce_v4_0_hw_fini(void *handle)
        }
 
        for (i = 0; i < adev->vce.num_rings; i++)
-               adev->vce.ring[i].ready = false;
+               adev->vce.ring[i].sched.ready = false;
 
        return 0;
 }
@@ -951,9 +946,11 @@ static int vce_v4_0_set_powergating_state(void *handle,
 }
 #endif
 
-static void vce_v4_0_ring_emit_ib(struct amdgpu_ring *ring,
-               struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+static void vce_v4_0_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib, bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, VCE_CMD_IB_VM);
        amdgpu_ring_write(ring, vmid);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
index 322e09b5b44894183d2c8aab92b1319f634a4fd5..4f8352044563415876ea80de0f00a6b02ddbb79b 100644 (file)
@@ -177,30 +177,22 @@ static int vcn_v1_0_hw_init(void *handle)
        struct amdgpu_ring *ring = &adev->vcn.ring_dec;
        int i, r;
 
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                goto done;
-       }
 
        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
                ring = &adev->vcn.ring_enc[i];
-               ring->ready = true;
-               r = amdgpu_ring_test_ring(ring);
-               if (r) {
-                       ring->ready = false;
+               ring->sched.ready = true;
+               r = amdgpu_ring_test_helper(ring);
+               if (r)
                        goto done;
-               }
        }
 
        ring = &adev->vcn.ring_jpeg;
-       ring->ready = true;
-       r = amdgpu_ring_test_ring(ring);
-       if (r) {
-               ring->ready = false;
+       r = amdgpu_ring_test_helper(ring);
+       if (r)
                goto done;
-       }
 
 done:
        if (!r)
@@ -225,7 +217,7 @@ static int vcn_v1_0_hw_fini(void *handle)
        if (RREG32_SOC15(VCN, 0, mmUVD_STATUS))
                vcn_v1_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
 
-       ring->ready = false;
+       ring->sched.ready = false;
 
        return 0;
 }
@@ -1367,10 +1359,12 @@ static void vcn_v1_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64
  * Write ring commands to execute the indirect buffer
  */
 static void vcn_v1_0_dec_ring_emit_ib(struct amdgpu_ring *ring,
-                                 struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
        struct amdgpu_device *adev = ring->adev;
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
        amdgpu_ring_write(ring,
                PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_RBC_IB_VMID), 0));
@@ -1525,8 +1519,12 @@ static void vcn_v1_0_enc_ring_insert_end(struct amdgpu_ring *ring)
  * Write enc ring commands to execute the indirect buffer
  */
 static void vcn_v1_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
-               struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
        amdgpu_ring_write(ring, VCN_ENC_CMD_IB);
        amdgpu_ring_write(ring, vmid);
        amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
@@ -1726,10 +1724,12 @@ static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u6
  * Write ring commands to execute the indirect buffer.
  */
 static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring,
-                                 struct amdgpu_ib *ib,
-                                 unsigned vmid, bool ctx_switch)
+                                       struct amdgpu_job *job,
+                                       struct amdgpu_ib *ib,
+                                       bool ctx_switch)
 {
        struct amdgpu_device *adev = ring->adev;
+       unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
        amdgpu_ring_write(ring,
                PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0));
index a0fda6f9252a52979b5c90569d48b4212f4ea27a..2c250b01a903eb62e6724384c4816a701f0eabe4 100644 (file)
@@ -219,90 +219,6 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev)
        return (wptr & adev->irq.ih.ptr_mask);
 }
 
-/**
- * vega10_ih_prescreen_iv - prescreen an interrupt vector
- *
- * @adev: amdgpu_device pointer
- *
- * Returns true if the interrupt vector should be further processed.
- */
-static bool vega10_ih_prescreen_iv(struct amdgpu_device *adev)
-{
-       u32 ring_index = adev->irq.ih.rptr >> 2;
-       u32 dw0, dw3, dw4, dw5;
-       u16 pasid;
-       u64 addr, key;
-       struct amdgpu_vm *vm;
-       int r;
-
-       dw0 = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
-       dw3 = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
-       dw4 = le32_to_cpu(adev->irq.ih.ring[ring_index + 4]);
-       dw5 = le32_to_cpu(adev->irq.ih.ring[ring_index + 5]);
-
-       /* Filter retry page faults, let only the first one pass. If
-        * there are too many outstanding faults, ignore them until
-        * some faults get cleared.
-        */
-       switch (dw0 & 0xff) {
-       case SOC15_IH_CLIENTID_VMC:
-       case SOC15_IH_CLIENTID_UTCL2:
-               break;
-       default:
-               /* Not a VM fault */
-               return true;
-       }
-
-       pasid = dw3 & 0xffff;
-       /* No PASID, can't identify faulting process */
-       if (!pasid)
-               return true;
-
-       /* Not a retry fault, check fault credit */
-       if (!(dw5 & 0x80)) {
-               if (!amdgpu_vm_pasid_fault_credit(adev, pasid))
-                       goto ignore_iv;
-               return true;
-       }
-
-       /* Track retry faults in per-VM fault FIFO. */
-       spin_lock(&adev->vm_manager.pasid_lock);
-       vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
-       addr = ((u64)(dw5 & 0xf) << 44) | ((u64)dw4 << 12);
-       key = AMDGPU_VM_FAULT(pasid, addr);
-       if (!vm) {
-               /* VM not found, process it normally */
-               spin_unlock(&adev->vm_manager.pasid_lock);
-               return true;
-       } else {
-               r = amdgpu_vm_add_fault(vm->fault_hash, key);
-
-               /* Hash table is full or the fault is already being processed,
-                * ignore further page faults
-                */
-               if (r != 0) {
-                       spin_unlock(&adev->vm_manager.pasid_lock);
-                       goto ignore_iv;
-               }
-       }
-       /* No locking required with single writer and single reader */
-       r = kfifo_put(&vm->faults, key);
-       if (!r) {
-               /* FIFO is full. Ignore it until there is space */
-               amdgpu_vm_clear_fault(vm->fault_hash, key);
-               spin_unlock(&adev->vm_manager.pasid_lock);
-               goto ignore_iv;
-       }
-
-       spin_unlock(&adev->vm_manager.pasid_lock);
-       /* It's the first fault for this address, process it normally */
-       return true;
-
-ignore_iv:
-       adev->irq.ih.rptr += 32;
-       return false;
-}
-
 /**
  * vega10_ih_decode_iv - decode an interrupt vector
  *
@@ -385,7 +301,7 @@ static int vega10_ih_sw_init(void *handle)
                return r;
 
        adev->irq.ih.use_doorbell = true;
-       adev->irq.ih.doorbell_index = AMDGPU_DOORBELL64_IH << 1;
+       adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
 
        r = amdgpu_irq_init(adev);
 
@@ -487,7 +403,6 @@ const struct amd_ip_funcs vega10_ih_ip_funcs = {
 
 static const struct amdgpu_ih_funcs vega10_ih_funcs = {
        .get_wptr = vega10_ih_get_wptr,
-       .prescreen_iv = vega10_ih_prescreen_iv,
        .decode_iv = vega10_ih_decode_iv,
        .set_rptr = vega10_ih_set_rptr
 };
index c5c9b2bc190d5cdd679e2fd7252d235816cbb166..422674bb3cdfdd8d2864003177b8704280feb0ad 100644 (file)
@@ -56,4 +56,32 @@ int vega10_reg_base_init(struct amdgpu_device *adev)
        return 0;
 }
 
+void vega10_doorbell_index_init(struct amdgpu_device *adev)
+{
+       adev->doorbell_index.kiq = AMDGPU_DOORBELL64_KIQ;
+       adev->doorbell_index.mec_ring0 = AMDGPU_DOORBELL64_MEC_RING0;
+       adev->doorbell_index.mec_ring1 = AMDGPU_DOORBELL64_MEC_RING1;
+       adev->doorbell_index.mec_ring2 = AMDGPU_DOORBELL64_MEC_RING2;
+       adev->doorbell_index.mec_ring3 = AMDGPU_DOORBELL64_MEC_RING3;
+       adev->doorbell_index.mec_ring4 = AMDGPU_DOORBELL64_MEC_RING4;
+       adev->doorbell_index.mec_ring5 = AMDGPU_DOORBELL64_MEC_RING5;
+       adev->doorbell_index.mec_ring6 = AMDGPU_DOORBELL64_MEC_RING6;
+       adev->doorbell_index.mec_ring7 = AMDGPU_DOORBELL64_MEC_RING7;
+       adev->doorbell_index.userqueue_start = AMDGPU_DOORBELL64_USERQUEUE_START;
+       adev->doorbell_index.userqueue_end = AMDGPU_DOORBELL64_USERQUEUE_END;
+       adev->doorbell_index.gfx_ring0 = AMDGPU_DOORBELL64_GFX_RING0;
+       adev->doorbell_index.sdma_engine0 = AMDGPU_DOORBELL64_sDMA_ENGINE0;
+       adev->doorbell_index.sdma_engine1 = AMDGPU_DOORBELL64_sDMA_ENGINE1;
+       adev->doorbell_index.ih = AMDGPU_DOORBELL64_IH;
+       adev->doorbell_index.uvd_vce.uvd_ring0_1 = AMDGPU_DOORBELL64_UVD_RING0_1;
+       adev->doorbell_index.uvd_vce.uvd_ring2_3 = AMDGPU_DOORBELL64_UVD_RING2_3;
+       adev->doorbell_index.uvd_vce.uvd_ring4_5 = AMDGPU_DOORBELL64_UVD_RING4_5;
+       adev->doorbell_index.uvd_vce.uvd_ring6_7 = AMDGPU_DOORBELL64_UVD_RING6_7;
+       adev->doorbell_index.uvd_vce.vce_ring0_1 = AMDGPU_DOORBELL64_VCE_RING0_1;
+       adev->doorbell_index.uvd_vce.vce_ring2_3 = AMDGPU_DOORBELL64_VCE_RING2_3;
+       adev->doorbell_index.uvd_vce.vce_ring4_5 = AMDGPU_DOORBELL64_VCE_RING4_5;
+       adev->doorbell_index.uvd_vce.vce_ring6_7 = AMDGPU_DOORBELL64_VCE_RING6_7;
+       /* In unit of dword doorbell */
+       adev->doorbell_index.max_assignment = AMDGPU_DOORBELL64_MAX_ASSIGNMENT << 1;
+}
 
index d13fc4fcb51790859f03aefb14f4bd90067c8fd8..edce413fda9a0256d8efa29f9f3c8e48b3c404c8 100644 (file)
@@ -54,4 +54,37 @@ int vega20_reg_base_init(struct amdgpu_device *adev)
        return 0;
 }
 
+void vega20_doorbell_index_init(struct amdgpu_device *adev)
+{
+       adev->doorbell_index.kiq = AMDGPU_VEGA20_DOORBELL_KIQ;
+       adev->doorbell_index.mec_ring0 = AMDGPU_VEGA20_DOORBELL_MEC_RING0;
+       adev->doorbell_index.mec_ring1 = AMDGPU_VEGA20_DOORBELL_MEC_RING1;
+       adev->doorbell_index.mec_ring2 = AMDGPU_VEGA20_DOORBELL_MEC_RING2;
+       adev->doorbell_index.mec_ring3 = AMDGPU_VEGA20_DOORBELL_MEC_RING3;
+       adev->doorbell_index.mec_ring4 = AMDGPU_VEGA20_DOORBELL_MEC_RING4;
+       adev->doorbell_index.mec_ring5 = AMDGPU_VEGA20_DOORBELL_MEC_RING5;
+       adev->doorbell_index.mec_ring6 = AMDGPU_VEGA20_DOORBELL_MEC_RING6;
+       adev->doorbell_index.mec_ring7 = AMDGPU_VEGA20_DOORBELL_MEC_RING7;
+       adev->doorbell_index.userqueue_start = AMDGPU_VEGA20_DOORBELL_USERQUEUE_START;
+       adev->doorbell_index.userqueue_end = AMDGPU_VEGA20_DOORBELL_USERQUEUE_END;
+       adev->doorbell_index.gfx_ring0 = AMDGPU_VEGA20_DOORBELL_GFX_RING0;
+       adev->doorbell_index.sdma_engine0 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE0;
+       adev->doorbell_index.sdma_engine1 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE1;
+       adev->doorbell_index.sdma_engine2 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE2;
+       adev->doorbell_index.sdma_engine3 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE3;
+       adev->doorbell_index.sdma_engine4 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE4;
+       adev->doorbell_index.sdma_engine5 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE5;
+       adev->doorbell_index.sdma_engine6 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE6;
+       adev->doorbell_index.sdma_engine7 = AMDGPU_VEGA20_DOORBELL_sDMA_ENGINE7;
+       adev->doorbell_index.ih = AMDGPU_VEGA20_DOORBELL_IH;
+       adev->doorbell_index.uvd_vce.uvd_ring0_1 = AMDGPU_VEGA20_DOORBELL64_UVD_RING0_1;
+       adev->doorbell_index.uvd_vce.uvd_ring2_3 = AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3;
+       adev->doorbell_index.uvd_vce.uvd_ring4_5 = AMDGPU_VEGA20_DOORBELL64_UVD_RING4_5;
+       adev->doorbell_index.uvd_vce.uvd_ring6_7 = AMDGPU_VEGA20_DOORBELL64_UVD_RING6_7;
+       adev->doorbell_index.uvd_vce.vce_ring0_1 = AMDGPU_VEGA20_DOORBELL64_VCE_RING0_1;
+       adev->doorbell_index.uvd_vce.vce_ring2_3 = AMDGPU_VEGA20_DOORBELL64_VCE_RING2_3;
+       adev->doorbell_index.uvd_vce.vce_ring4_5 = AMDGPU_VEGA20_DOORBELL64_VCE_RING4_5;
+       adev->doorbell_index.uvd_vce.vce_ring6_7 = AMDGPU_VEGA20_DOORBELL64_VCE_RING6_7;
+       adev->doorbell_index.max_assignment = AMDGPU_VEGA20_DOORBELL_MAX_ASSIGNMENT << 1;
+}
 
index 07880d35e9de8600d1ea23f9f539790177e91cda..ff2906c215fa8be32dd53e6e6899b3c780c850f4 100644 (file)
@@ -955,6 +955,7 @@ static const struct amdgpu_asic_funcs vi_asic_funcs =
        .flush_hdp = &vi_flush_hdp,
        .invalidate_hdp = &vi_invalidate_hdp,
        .need_full_reset = &vi_need_full_reset,
+       .init_doorbell_index = &legacy_doorbell_index_init,
 };
 
 #define CZ_REV_BRISTOL(rev)     \
@@ -1712,3 +1713,21 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
 
        return 0;
 }
+
+void legacy_doorbell_index_init(struct amdgpu_device *adev)
+{
+       adev->doorbell_index.kiq = AMDGPU_DOORBELL_KIQ;
+       adev->doorbell_index.mec_ring0 = AMDGPU_DOORBELL_MEC_RING0;
+       adev->doorbell_index.mec_ring1 = AMDGPU_DOORBELL_MEC_RING1;
+       adev->doorbell_index.mec_ring2 = AMDGPU_DOORBELL_MEC_RING2;
+       adev->doorbell_index.mec_ring3 = AMDGPU_DOORBELL_MEC_RING3;
+       adev->doorbell_index.mec_ring4 = AMDGPU_DOORBELL_MEC_RING4;
+       adev->doorbell_index.mec_ring5 = AMDGPU_DOORBELL_MEC_RING5;
+       adev->doorbell_index.mec_ring6 = AMDGPU_DOORBELL_MEC_RING6;
+       adev->doorbell_index.mec_ring7 = AMDGPU_DOORBELL_MEC_RING7;
+       adev->doorbell_index.gfx_ring0 = AMDGPU_DOORBELL_GFX_RING0;
+       adev->doorbell_index.sdma_engine0 = AMDGPU_DOORBELL_sDMA_ENGINE0;
+       adev->doorbell_index.sdma_engine1 = AMDGPU_DOORBELL_sDMA_ENGINE1;
+       adev->doorbell_index.ih = AMDGPU_DOORBELL_IH;
+       adev->doorbell_index.max_assignment = AMDGPU_DOORBELL_MAX_ASSIGNMENT;
+}
index 0429fe33226940d1c52cfb556ee6b78ef94f2728..8de0772f986c53ea469d2cffe5c4ddb098f9f302 100644 (file)
@@ -30,4 +30,5 @@ void vi_srbm_select(struct amdgpu_device *adev,
                    u32 me, u32 pipe, u32 queue, u32 vmid);
 int vi_set_ip_blocks(struct amdgpu_device *adev);
 
+void legacy_doorbell_index_init(struct amdgpu_device *adev);
 #endif
index 5d2475d5392ce25cbb719c0fa519e0c0d94777fc..177d1e5329a5723482c437381253700c224aeb90 100644 (file)
@@ -23,6 +23,7 @@
 #include "kfd_priv.h"
 #include "kfd_events.h"
 #include "cik_int.h"
+#include "amdgpu_amdkfd.h"
 
 static bool cik_event_interrupt_isr(struct kfd_dev *dev,
                                        const uint32_t *ih_ring_entry,
@@ -107,7 +108,7 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
                kfd_process_vm_fault(dev->dqm, pasid);
 
                memset(&info, 0, sizeof(info));
-               dev->kfd2kgd->get_vm_fault_info(dev->kgd, &info);
+               amdgpu_amdkfd_gpuvm_get_vm_fault_info(dev->kgd, &info);
                if (!info.page_addr && !info.status)
                        return;
 
index 37ce6dd653917cb441958a3fbacef9463a611b9a..8e2a1663c4db6e41ec6d35f59dc40f289fbd83d9 100644 (file)
@@ -68,6 +68,4 @@
 
 #define GRBM_GFX_INDEX                                 0x30800
 
-#define        ATC_VMID_PASID_MAPPING_VALID                    (1U << 31)
-
 #endif
index 14d5b5fa822d4e8722cc2d6a3e6cc1cba0b1b7bd..3623538baf6fc9c20dd79167826ded7d52acbc9e 100644 (file)
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/dma-buf.h>
 #include <asm/processor.h>
 #include "kfd_priv.h"
 #include "kfd_device_queue_manager.h"
 #include "kfd_dbgmgr.h"
+#include "amdgpu_amdkfd.h"
 
 static long kfd_ioctl(struct file *, unsigned int, unsigned long);
 static int kfd_open(struct inode *, struct file *);
@@ -834,8 +836,7 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
        dev = kfd_device_by_id(args->gpu_id);
        if (dev)
                /* Reading GPU clock counter from KGD */
-               args->gpu_clock_counter =
-                       dev->kfd2kgd->get_gpu_clock_counter(dev->kgd);
+               args->gpu_clock_counter = amdgpu_amdkfd_get_gpu_clock_counter(dev->kgd);
        else
                /* Node without GPU resource */
                args->gpu_clock_counter = 0;
@@ -1042,7 +1043,7 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p,
                }
                mutex_unlock(&p->mutex);
 
-               err = kfd->kfd2kgd->map_gtt_bo_to_kernel(kfd->kgd,
+               err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kfd->kgd,
                                                mem, &kern_addr, &size);
                if (err) {
                        pr_err("Failed to map event page to kernel\n");
@@ -1240,7 +1241,7 @@ bool kfd_dev_is_large_bar(struct kfd_dev *dev)
        if (dev->device_info->needs_iommu_device)
                return false;
 
-       dev->kfd2kgd->get_local_mem_info(dev->kgd, &mem_info);
+       amdgpu_amdkfd_get_local_mem_info(dev->kgd, &mem_info);
        if (mem_info.local_mem_size_private == 0 &&
                        mem_info.local_mem_size_public > 0)
                return true;
@@ -1273,6 +1274,12 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
                return -EINVAL;
        }
 
+       if (flags & KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL) {
+               if (args->size != kfd_doorbell_process_slice(dev))
+                       return -EINVAL;
+               offset = kfd_get_process_doorbells(dev, p);
+       }
+
        mutex_lock(&p->mutex);
 
        pdd = kfd_bind_process_to_device(dev, p);
@@ -1281,7 +1288,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
                goto err_unlock;
        }
 
-       err = dev->kfd2kgd->alloc_memory_of_gpu(
+       err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
                dev->kgd, args->va_addr, args->size,
                pdd->vm, (struct kgd_mem **) &mem, &offset,
                flags);
@@ -1303,7 +1310,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
        return 0;
 
 err_free:
-       dev->kfd2kgd->free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
+       amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
 err_unlock:
        mutex_unlock(&p->mutex);
        return err;
@@ -1338,7 +1345,8 @@ static int kfd_ioctl_free_memory_of_gpu(struct file *filep,
                goto err_unlock;
        }
 
-       ret = dev->kfd2kgd->free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
+       ret = amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd,
+                                               (struct kgd_mem *)mem);
 
        /* If freeing the buffer failed, leave the handle in place for
         * clean-up during process tear-down.
@@ -1418,7 +1426,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
                        err = PTR_ERR(peer_pdd);
                        goto get_mem_obj_from_handle_failed;
                }
-               err = peer->kfd2kgd->map_memory_to_gpu(
+               err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
                        peer->kgd, (struct kgd_mem *)mem, peer_pdd->vm);
                if (err) {
                        pr_err("Failed to map to gpu %d/%d\n",
@@ -1430,7 +1438,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
 
        mutex_unlock(&p->mutex);
 
-       err = dev->kfd2kgd->sync_memory(dev->kgd, (struct kgd_mem *) mem, true);
+       err = amdgpu_amdkfd_gpuvm_sync_memory(dev->kgd, (struct kgd_mem *) mem, true);
        if (err) {
                pr_debug("Sync memory failed, wait interrupted by user signal\n");
                goto sync_memory_failed;
@@ -1525,7 +1533,7 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
                        err = -ENODEV;
                        goto get_mem_obj_from_handle_failed;
                }
-               err = dev->kfd2kgd->unmap_memory_to_gpu(
+               err = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
                        peer->kgd, (struct kgd_mem *)mem, peer_pdd->vm);
                if (err) {
                        pr_err("Failed to unmap from gpu %d/%d\n",
@@ -1549,6 +1557,115 @@ copy_from_user_failed:
        return err;
 }
 
+static int kfd_ioctl_get_dmabuf_info(struct file *filep,
+               struct kfd_process *p, void *data)
+{
+       struct kfd_ioctl_get_dmabuf_info_args *args = data;
+       struct kfd_dev *dev = NULL;
+       struct kgd_dev *dma_buf_kgd;
+       void *metadata_buffer = NULL;
+       uint32_t flags;
+       unsigned int i;
+       int r;
+
+       /* Find a KFD GPU device that supports the get_dmabuf_info query */
+       for (i = 0; kfd_topology_enum_kfd_devices(i, &dev) == 0; i++)
+               if (dev)
+                       break;
+       if (!dev)
+               return -EINVAL;
+
+       if (args->metadata_ptr) {
+               metadata_buffer = kzalloc(args->metadata_size, GFP_KERNEL);
+               if (!metadata_buffer)
+                       return -ENOMEM;
+       }
+
+       /* Get dmabuf info from KGD */
+       r = amdgpu_amdkfd_get_dmabuf_info(dev->kgd, args->dmabuf_fd,
+                                         &dma_buf_kgd, &args->size,
+                                         metadata_buffer, args->metadata_size,
+                                         &args->metadata_size, &flags);
+       if (r)
+               goto exit;
+
+       /* Reverse-lookup gpu_id from kgd pointer */
+       dev = kfd_device_by_kgd(dma_buf_kgd);
+       if (!dev) {
+               r = -EINVAL;
+               goto exit;
+       }
+       args->gpu_id = dev->id;
+       args->flags = flags;
+
+       /* Copy metadata buffer to user mode */
+       if (metadata_buffer) {
+               r = copy_to_user((void __user *)args->metadata_ptr,
+                                metadata_buffer, args->metadata_size);
+               if (r != 0)
+                       r = -EFAULT;
+       }
+
+exit:
+       kfree(metadata_buffer);
+
+       return r;
+}
+
+static int kfd_ioctl_import_dmabuf(struct file *filep,
+                                  struct kfd_process *p, void *data)
+{
+       struct kfd_ioctl_import_dmabuf_args *args = data;
+       struct kfd_process_device *pdd;
+       struct dma_buf *dmabuf;
+       struct kfd_dev *dev;
+       int idr_handle;
+       uint64_t size;
+       void *mem;
+       int r;
+
+       dev = kfd_device_by_id(args->gpu_id);
+       if (!dev)
+               return -EINVAL;
+
+       dmabuf = dma_buf_get(args->dmabuf_fd);
+       if (!dmabuf)
+               return -EINVAL;
+
+       mutex_lock(&p->mutex);
+
+       pdd = kfd_bind_process_to_device(dev, p);
+       if (IS_ERR(pdd)) {
+               r = PTR_ERR(pdd);
+               goto err_unlock;
+       }
+
+       r = amdgpu_amdkfd_gpuvm_import_dmabuf(dev->kgd, dmabuf,
+                                             args->va_addr, pdd->vm,
+                                             (struct kgd_mem **)&mem, &size,
+                                             NULL);
+       if (r)
+               goto err_unlock;
+
+       idr_handle = kfd_process_device_create_obj_handle(pdd, mem);
+       if (idr_handle < 0) {
+               r = -EFAULT;
+               goto err_free;
+       }
+
+       mutex_unlock(&p->mutex);
+
+       args->handle = MAKE_HANDLE(args->gpu_id, idr_handle);
+
+       return 0;
+
+err_free:
+       amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
+err_unlock:
+       mutex_unlock(&p->mutex);
+       return r;
+}
+
 #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
        [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \
                            .cmd_drv = 0, .name = #ioctl}
@@ -1634,7 +1751,13 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
                        kfd_ioctl_set_cu_mask, 0),
 
        AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_QUEUE_WAVE_STATE,
-                       kfd_ioctl_get_queue_wave_state, 0)
+                       kfd_ioctl_get_queue_wave_state, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_DMABUF_INFO,
+                               kfd_ioctl_get_dmabuf_info, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_IMPORT_DMABUF,
+                               kfd_ioctl_import_dmabuf, 0),
 
 };
 
index 56412b0e7e1c73d79ff2a701b5da7a54affb258a..c02adbbeef2a645f2bfbe98da652b9694b9afec3 100644 (file)
@@ -26,6 +26,7 @@
 #include "kfd_priv.h"
 #include "kfd_topology.h"
 #include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
 
 /* GPU Processor ID base for dGPUs for which VCRAT needs to be created.
  * GPU processor ID are expressed with Bit[31]=1.
@@ -132,6 +133,7 @@ static struct kfd_gpu_cache_info carrizo_cache_info[] = {
 #define fiji_cache_info  carrizo_cache_info
 #define polaris10_cache_info carrizo_cache_info
 #define polaris11_cache_info carrizo_cache_info
+#define polaris12_cache_info carrizo_cache_info
 /* TODO - check & update Vega10 cache details */
 #define vega10_cache_info carrizo_cache_info
 #define raven_cache_info carrizo_cache_info
@@ -646,7 +648,12 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev,
                pcache_info = polaris11_cache_info;
                num_of_cache_types = ARRAY_SIZE(polaris11_cache_info);
                break;
+       case CHIP_POLARIS12:
+               pcache_info = polaris12_cache_info;
+               num_of_cache_types = ARRAY_SIZE(polaris12_cache_info);
+               break;
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
                pcache_info = vega10_cache_info;
                num_of_cache_types = ARRAY_SIZE(vega10_cache_info);
@@ -753,12 +760,10 @@ int kfd_create_crat_image_acpi(void **crat_image, size_t *size)
                return -ENODATA;
        }
 
-       pcrat_image = kmalloc(crat_table->length, GFP_KERNEL);
+       pcrat_image = kmemdup(crat_table, crat_table->length, GFP_KERNEL);
        if (!pcrat_image)
                return -ENOMEM;
 
-       memcpy(pcrat_image, crat_table, crat_table->length);
-
        *crat_image = pcrat_image;
        *size = crat_table->length;
 
@@ -1161,7 +1166,7 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
        cu->flags |= CRAT_CU_FLAGS_GPU_PRESENT;
        cu->proximity_domain = proximity_domain;
 
-       kdev->kfd2kgd->get_cu_info(kdev->kgd, &cu_info);
+       amdgpu_amdkfd_get_cu_info(kdev->kgd, &cu_info);
        cu->num_simd_per_cu = cu_info.simd_per_cu;
        cu->num_simd_cores = cu_info.simd_per_cu * cu_info.cu_active_number;
        cu->max_waves_simd = cu_info.max_waves_per_simd;
@@ -1192,7 +1197,7 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
         * report the total FB size (public+private) as a single
         * private heap.
         */
-       kdev->kfd2kgd->get_local_mem_info(kdev->kgd, &local_mem_info);
+       amdgpu_amdkfd_get_local_mem_info(kdev->kgd, &local_mem_info);
        sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
                        sub_type_hdr->length);
 
index e4ded890b1cbcc950e68288d7bafa1dbfdcaf456..8be9677c0c07dae65e3c69dafab241e3b16ff975 100644 (file)
@@ -28,6 +28,7 @@
 #include "kfd_pm4_headers_vi.h"
 #include "cwsr_trap_handler.h"
 #include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
 
 #define MQD_SIZE_ALIGNED 768
 
@@ -204,6 +205,22 @@ static const struct kfd_device_info polaris11_device_info = {
        .num_sdma_queues_per_engine = 2,
 };
 
+static const struct kfd_device_info polaris12_device_info = {
+       .asic_family = CHIP_POLARIS12,
+       .max_pasid_bits = 16,
+       .max_no_of_hqd  = 24,
+       .doorbell_size  = 4,
+       .ih_ring_entry_size = 4 * sizeof(uint32_t),
+       .event_interrupt_class = &event_interrupt_class_cik,
+       .num_of_watch_points = 4,
+       .mqd_size_aligned = MQD_SIZE_ALIGNED,
+       .supports_cwsr = true,
+       .needs_iommu_device = false,
+       .needs_pci_atomics = true,
+       .num_sdma_engines = 2,
+       .num_sdma_queues_per_engine = 2,
+};
+
 static const struct kfd_device_info vega10_device_info = {
        .asic_family = CHIP_VEGA10,
        .max_pasid_bits = 16,
@@ -236,6 +253,22 @@ static const struct kfd_device_info vega10_vf_device_info = {
        .num_sdma_queues_per_engine = 2,
 };
 
+static const struct kfd_device_info vega12_device_info = {
+       .asic_family = CHIP_VEGA12,
+       .max_pasid_bits = 16,
+       .max_no_of_hqd  = 24,
+       .doorbell_size  = 8,
+       .ih_ring_entry_size = 8 * sizeof(uint32_t),
+       .event_interrupt_class = &event_interrupt_class_v9,
+       .num_of_watch_points = 4,
+       .mqd_size_aligned = MQD_SIZE_ALIGNED,
+       .supports_cwsr = true,
+       .needs_iommu_device = false,
+       .needs_pci_atomics = false,
+       .num_sdma_engines = 2,
+       .num_sdma_queues_per_engine = 2,
+};
+
 static const struct kfd_device_info vega20_device_info = {
        .asic_family = CHIP_VEGA20,
        .max_pasid_bits = 16,
@@ -330,6 +363,14 @@ static const struct kfd_deviceid supported_devices[] = {
        { 0x67EB, &polaris11_device_info },     /* Polaris11 */
        { 0x67EF, &polaris11_device_info },     /* Polaris11 */
        { 0x67FF, &polaris11_device_info },     /* Polaris11 */
+       { 0x6980, &polaris12_device_info },     /* Polaris12 */
+       { 0x6981, &polaris12_device_info },     /* Polaris12 */
+       { 0x6985, &polaris12_device_info },     /* Polaris12 */
+       { 0x6986, &polaris12_device_info },     /* Polaris12 */
+       { 0x6987, &polaris12_device_info },     /* Polaris12 */
+       { 0x6995, &polaris12_device_info },     /* Polaris12 */
+       { 0x6997, &polaris12_device_info },     /* Polaris12 */
+       { 0x699F, &polaris12_device_info },     /* Polaris12 */
        { 0x6860, &vega10_device_info },        /* Vega10 */
        { 0x6861, &vega10_device_info },        /* Vega10 */
        { 0x6862, &vega10_device_info },        /* Vega10 */
@@ -345,6 +386,11 @@ static const struct kfd_deviceid supported_devices[] = {
        { 0x686E, &vega10_device_info },        /* Vega10 */
        { 0x686F, &vega10_device_info },        /* Vega10 */
        { 0x687F, &vega10_device_info },        /* Vega10 */
+       { 0x69A0, &vega12_device_info },        /* Vega12 */
+       { 0x69A1, &vega12_device_info },        /* Vega12 */
+       { 0x69A2, &vega12_device_info },        /* Vega12 */
+       { 0x69A3, &vega12_device_info },        /* Vega12 */
+       { 0x69AF, &vega12_device_info },        /* Vega12 */
        { 0x66a0, &vega20_device_info },        /* Vega20 */
        { 0x66a1, &vega20_device_info },        /* Vega20 */
        { 0x66a2, &vega20_device_info },        /* Vega20 */
@@ -485,7 +531,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
        /* add another 512KB for all other allocations on gart (HPD, fences) */
        size += 512 * 1024;
 
-       if (kfd->kfd2kgd->init_gtt_mem_allocation(
+       if (amdgpu_amdkfd_alloc_gtt_mem(
                        kfd->kgd, size, &kfd->gtt_mem,
                        &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr,
                        false)) {
@@ -559,7 +605,7 @@ kfd_topology_add_device_error:
 kfd_doorbell_error:
        kfd_gtt_sa_fini(kfd);
 kfd_gtt_sa_init_error:
-       kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+       amdgpu_amdkfd_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);
@@ -576,7 +622,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
                kfd_topology_remove_device(kfd);
                kfd_doorbell_fini(kfd);
                kfd_gtt_sa_fini(kfd);
-               kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+               amdgpu_amdkfd_free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        }
 
        kfree(kfd);
@@ -688,6 +734,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
 {
        uint32_t patched_ihre[KFD_MAX_RING_ENTRY_SIZE];
        bool is_patched = false;
+       unsigned long flags;
 
        if (!kfd->init_complete)
                return;
@@ -697,7 +744,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
                return;
        }
 
-       spin_lock(&kfd->interrupt_lock);
+       spin_lock_irqsave(&kfd->interrupt_lock, flags);
 
        if (kfd->interrupts_active
            && interrupt_is_wanted(kfd, ih_ring_entry,
@@ -706,7 +753,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
                                     is_patched ? patched_ihre : ih_ring_entry))
                queue_work(kfd->ih_wq, &kfd->interrupt_work);
 
-       spin_unlock(&kfd->interrupt_lock);
+       spin_unlock_irqrestore(&kfd->interrupt_lock, flags);
 }
 
 int kgd2kfd_quiesce_mm(struct mm_struct *mm)
index a3b9339671713cbbbb4ade0fb049f5a786607a2f..8372556b52eb72d755c09052a6df715c28c7c312 100644 (file)
@@ -33,6 +33,7 @@
 #include "kfd_mqd_manager.h"
 #include "cik_regs.h"
 #include "kfd_kernel_queue.h"
+#include "amdgpu_amdkfd.h"
 
 /* Size of the per-pipe EOP queue */
 #define CIK_HPD_EOP_BYTES_LOG2 11
@@ -219,7 +220,7 @@ static int flush_texture_cache_nocpsch(struct kfd_dev *kdev,
        if (ret)
                return ret;
 
-       return kdev->kfd2kgd->submit_ib(kdev->kgd, KGD_ENGINE_MEC1, qpd->vmid,
+       return amdgpu_amdkfd_submit_ib(kdev->kgd, KGD_ENGINE_MEC1, qpd->vmid,
                                qpd->ib_base, (uint32_t *)qpd->ib_kaddr,
                                pmf->release_mem_size / sizeof(uint32_t));
 }
@@ -672,7 +673,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
 
        pdd = qpd_to_pdd(qpd);
        /* Retrieve PD base */
-       pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+       pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
 
        dqm_lock(dqm);
        if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
@@ -743,7 +744,7 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
 
        pdd = qpd_to_pdd(qpd);
        /* Retrieve PD base */
-       pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+       pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
 
        dqm_lock(dqm);
        if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
@@ -793,7 +794,7 @@ static int register_process(struct device_queue_manager *dqm,
 
        pdd = qpd_to_pdd(qpd);
        /* Retrieve PD base */
-       pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+       pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
 
        dqm_lock(dqm);
        list_add(&n->list, &dqm->queues);
@@ -805,7 +806,7 @@ static int register_process(struct device_queue_manager *dqm,
        retval = dqm->asic_ops.update_qpd(dqm, qpd);
 
        if (dqm->processes_count++ == 0)
-               dqm->dev->kfd2kgd->set_compute_idle(dqm->dev->kgd, false);
+               amdgpu_amdkfd_set_compute_idle(dqm->dev->kgd, false);
 
        dqm_unlock(dqm);
 
@@ -829,7 +830,7 @@ static int unregister_process(struct device_queue_manager *dqm,
                        list_del(&cur->list);
                        kfree(cur);
                        if (--dqm->processes_count == 0)
-                               dqm->dev->kfd2kgd->set_compute_idle(
+                               amdgpu_amdkfd_set_compute_idle(
                                        dqm->dev->kgd, true);
                        goto out;
                }
@@ -845,15 +846,8 @@ static int
 set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
                        unsigned int vmid)
 {
-       uint32_t pasid_mapping;
-
-       pasid_mapping = (pasid == 0) ? 0 :
-               (uint32_t)pasid |
-               ATC_VMID_PASID_MAPPING_VALID;
-
        return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
-                                               dqm->dev->kgd, pasid_mapping,
-                                               vmid);
+                                               dqm->dev->kgd, pasid, vmid);
 }
 
 static void init_interrupts(struct device_queue_manager *dqm)
@@ -1553,7 +1547,7 @@ static int get_wave_state(struct device_queue_manager *dqm,
                          u32 *ctl_stack_used_size,
                          u32 *save_area_used_size)
 {
-       struct mqd_manager *mqd;
+       struct mqd_manager *mqd_mgr;
        int r;
 
        dqm_lock(dqm);
@@ -1564,19 +1558,19 @@ static int get_wave_state(struct device_queue_manager *dqm,
                goto dqm_unlock;
        }
 
-       mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
-       if (!mqd) {
+       mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
+       if (!mqd_mgr) {
                r = -ENOMEM;
                goto dqm_unlock;
        }
 
-       if (!mqd->get_wave_state) {
+       if (!mqd_mgr->get_wave_state) {
                r = -EINVAL;
                goto dqm_unlock;
        }
 
-       r = mqd->get_wave_state(mqd, q->mqd, ctl_stack, ctl_stack_used_size,
-                               save_area_used_size);
+       r = mqd_mgr->get_wave_state(mqd_mgr, q->mqd, ctl_stack,
+                       ctl_stack_used_size, save_area_used_size);
 
 dqm_unlock:
        dqm_unlock(dqm);
@@ -1747,10 +1741,12 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                device_queue_manager_init_vi_tonga(&dqm->asic_ops);
                break;
 
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                device_queue_manager_init_v9(&dqm->asic_ops);
@@ -1796,7 +1792,7 @@ static void kfd_process_hw_exception(struct work_struct *work)
 {
        struct device_queue_manager *dqm = container_of(work,
                        struct device_queue_manager, hw_exception_work);
-       dqm->dev->kfd2kgd->gpu_recover(dqm->dev->kgd);
+       amdgpu_amdkfd_gpu_reset(dqm->dev->kgd);
 }
 
 #if defined(CONFIG_DEBUG_FS)
index fd60a116be3733775fcedb27d1a7bb9afdb908ae..c3a5dcfe877ade0c32fb4e901aa6fd29c462581d 100644 (file)
@@ -24,7 +24,6 @@
 #include "kfd_device_queue_manager.h"
 #include "gca/gfx_8_0_enum.h"
 #include "gca/gfx_8_0_sh_mask.h"
-#include "gca/gfx_8_0_enum.h"
 #include "oss/oss_3_0_sh_mask.h"
 
 static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
index 3d66cec414affb22a8bb15441314ac27d08adc80..213ea5454d11d36a506bf322f414298325aa7f3b 100644 (file)
@@ -397,9 +397,11 @@ int kfd_init_apertures(struct kfd_process *process)
                        case CHIP_FIJI:
                        case CHIP_POLARIS10:
                        case CHIP_POLARIS11:
+                       case CHIP_POLARIS12:
                                kfd_init_apertures_vi(pdd, id);
                                break;
                        case CHIP_VEGA10:
+                       case CHIP_VEGA12:
                        case CHIP_VEGA20:
                        case CHIP_RAVEN:
                                kfd_init_apertures_v9(pdd, id);
index f836897bbf5833799e7cb94e45be4c10975b9c8c..a85904ad0d5f4d56fc2bc437a92b3e59c5c1a1e6 100644 (file)
@@ -23,7 +23,7 @@
 #include "kfd_priv.h"
 #include "kfd_events.h"
 #include "soc15_int.h"
-
+#include "kfd_device_queue_manager.h"
 
 static bool event_interrupt_isr_v9(struct kfd_dev *dev,
                                        const uint32_t *ih_ring_entry,
@@ -39,20 +39,39 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev,
            vmid > dev->vm_info.last_vmid_kfd)
                return 0;
 
-       /* If there is no valid PASID, it's likely a firmware bug */
-       pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
-       if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt"))
-               return 0;
-
        source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry);
        client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
+       pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
+
+       /* This is a known issue for gfx9. Under non HWS, pasid is not set
+        * in the interrupt payload, so we need to find out the pasid on our
+        * own.
+        */
+       if (!pasid && dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
+               const uint32_t pasid_mask = 0xffff;
 
-       pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n",
-                client_id, source_id, pasid);
+               *patched_flag = true;
+               memcpy(patched_ihre, ih_ring_entry,
+                               dev->device_info->ih_ring_entry_size);
+
+               pasid = dev->kfd2kgd->get_atc_vmid_pasid_mapping_pasid(
+                               dev->kgd, vmid);
+
+               /* Patch the pasid field */
+               patched_ihre[3] = cpu_to_le32((le32_to_cpu(patched_ihre[3])
+                                       & ~pasid_mask) | pasid);
+       }
+
+       pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n",
+                client_id, source_id, vmid, pasid);
        pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
                 data[0], data[1], data[2], data[3],
                 data[4], data[5], data[6], data[7]);
 
+       /* If there is no valid PASID, it's likely a bug */
+       if (WARN_ONCE(pasid == 0, "Bug: No PASID in KFD interrupt"))
+               return 0;
+
        /* Interrupt types we care about: various signals and faults.
         * They will be forwarded to a work queue (see below).
         */
index 6c31f7370193c561653a170a61c0d51657892584..f1596881f20a473384b6d9f01684e5d1a71bec3a 100644 (file)
@@ -313,6 +313,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                kernel_queue_init_vi(&kq->ops_asic_specific);
                break;
 
@@ -322,6 +323,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
                break;
 
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                kernel_queue_init_v9(&kq->ops_asic_specific);
index e33019a7a883cc1d2df8410ea141257d71297adb..aed9b9b82213ddcf97014fee1ec96ac0ebc2a265 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "kfd_mqd_manager.h"
+#include "amdgpu_amdkfd.h"
 
 struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
                                        struct kfd_dev *dev)
@@ -37,8 +38,10 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                return mqd_manager_init_vi_tonga(type, dev);
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                return mqd_manager_init_v9(type, dev);
@@ -58,7 +61,7 @@ void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm,
        uint32_t cu_per_sh[4] = {0};
        int i, se, cu = 0;
 
-       mm->dev->kfd2kgd->get_cu_info(mm->dev->kgd, &cu_info);
+       amdgpu_amdkfd_get_cu_info(mm->dev->kgd, &cu_info);
 
        if (cu_mask_count > cu_info.cu_active_number)
                cu_mask_count = cu_info.cu_active_number;
index f381c1cb27bdc867d67308e4f0cc2176e777dc5c..9dbba609450e73a7e2c4702bc7c3d59c1274cf01 100644 (file)
@@ -30,6 +30,7 @@
 #include "gc/gc_9_0_offset.h"
 #include "gc/gc_9_0_sh_mask.h"
 #include "sdma0/sdma0_4_0_sh_mask.h"
+#include "amdgpu_amdkfd.h"
 
 static inline struct v9_mqd *get_mqd(void *mqd)
 {
@@ -83,7 +84,7 @@ static int init_mqd(struct mqd_manager *mm, void **mqd,
                *mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
                if (!*mqd_mem_obj)
                        return -ENOMEM;
-               retval = kfd->kfd2kgd->init_gtt_mem_allocation(kfd->kgd,
+               retval = amdgpu_amdkfd_alloc_gtt_mem(kfd->kgd,
                        ALIGN(q->ctl_stack_size, PAGE_SIZE) +
                                ALIGN(sizeof(struct v9_mqd), PAGE_SIZE),
                        &((*mqd_mem_obj)->gtt_mem),
@@ -250,7 +251,7 @@ static void uninit_mqd(struct mqd_manager *mm, void *mqd,
        struct kfd_dev *kfd = mm->dev;
 
        if (mqd_mem_obj->gtt_mem) {
-               kfd->kfd2kgd->free_gtt_mem(kfd->kgd, mqd_mem_obj->gtt_mem);
+               amdgpu_amdkfd_free_gtt_mem(kfd->kgd, mqd_mem_obj->gtt_mem);
                kfree(mqd_mem_obj);
        } else {
                kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
index c6080ed3b6a771aa7a672c9da81c94bc9e9ea6c5..045a229436a09ee64f3f6a4b905930899e395500 100644 (file)
@@ -226,9 +226,11 @@ int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm)
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                pm->pmf = &kfd_vi_pm_funcs;
                break;
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                pm->pmf = &kfd_v9_pm_funcs;
index 15fff4420e534fbd79c1cc1844244f715d348935..33b08ff00b5012f9741209e43d0c5d21e644e6ec 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/types.h>
 #include "kfd_priv.h"
+#include "amdgpu_ids.h"
 
 static unsigned int pasid_bits = 16;
 static const struct kfd2kgd_calls *kfd2kgd;
@@ -71,7 +72,7 @@ unsigned int kfd_pasid_alloc(void)
                        return false;
        }
 
-       r = kfd2kgd->alloc_pasid(pasid_bits);
+       r = amdgpu_pasid_alloc(pasid_bits);
 
        return r > 0 ? r : 0;
 }
@@ -79,5 +80,5 @@ unsigned int kfd_pasid_alloc(void)
 void kfd_pasid_free(unsigned int pasid)
 {
        if (kfd2kgd)
-               kfd2kgd->free_pasid(pasid);
+               amdgpu_pasid_free(pasid);
 }
index 53ff86d45d918d7e465309b9e476641332b241ef..0689d4ccbbc0f6fd59164f5ebab76246fca396e6 100644 (file)
@@ -507,6 +507,7 @@ struct qcm_process_device {
         * All the memory management data should be here too
         */
        uint64_t gds_context_area;
+       /* Contains page table flags such as AMDGPU_PTE_VALID since gfx9 */
        uint64_t page_table_base;
        uint32_t sh_mem_config;
        uint32_t sh_mem_bases;
@@ -792,6 +793,7 @@ struct kfd_topology_device *kfd_topology_device_by_proximity_domain(
 struct kfd_topology_device *kfd_topology_device_by_id(uint32_t gpu_id);
 struct kfd_dev *kfd_device_by_id(uint32_t gpu_id);
 struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev);
+struct kfd_dev *kfd_device_by_kgd(const struct kgd_dev *kgd);
 int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev);
 int kfd_numa_node_to_apic_id(int numa_node_id);
 
index 0039e451d9af2a7e816dafb64559595b22a3d8a4..80b36e860a0a8de2d30f4475b4802db3028b6cf2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/compat.h>
 #include <linux/mman.h>
 #include <linux/file.h>
+#include "amdgpu_amdkfd.h"
 
 struct mm_struct;
 
@@ -100,8 +101,8 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem,
 {
        struct kfd_dev *dev = pdd->dev;
 
-       dev->kfd2kgd->unmap_memory_to_gpu(dev->kgd, mem, pdd->vm);
-       dev->kfd2kgd->free_memory_of_gpu(dev->kgd, mem);
+       amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->kgd, mem, pdd->vm);
+       amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, mem);
 }
 
 /* kfd_process_alloc_gpuvm - Allocate GPU VM for the KFD process
@@ -119,16 +120,16 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
        int handle;
        int err;
 
-       err = kdev->kfd2kgd->alloc_memory_of_gpu(kdev->kgd, gpu_va, size,
+       err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(kdev->kgd, gpu_va, size,
                                                 pdd->vm, &mem, NULL, flags);
        if (err)
                goto err_alloc_mem;
 
-       err = kdev->kfd2kgd->map_memory_to_gpu(kdev->kgd, mem, pdd->vm);
+       err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, mem, pdd->vm);
        if (err)
                goto err_map_mem;
 
-       err = kdev->kfd2kgd->sync_memory(kdev->kgd, mem, true);
+       err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, mem, true);
        if (err) {
                pr_debug("Sync memory failed, wait interrupted by user signal\n");
                goto sync_memory_failed;
@@ -147,7 +148,7 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
        }
 
        if (kptr) {
-               err = kdev->kfd2kgd->map_gtt_bo_to_kernel(kdev->kgd,
+               err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kdev->kgd,
                                (struct kgd_mem *)mem, kptr, NULL);
                if (err) {
                        pr_debug("Map GTT BO to kernel failed\n");
@@ -165,7 +166,7 @@ sync_memory_failed:
        return err;
 
 err_map_mem:
-       kdev->kfd2kgd->free_memory_of_gpu(kdev->kgd, mem);
+       amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, mem);
 err_alloc_mem:
        *kptr = NULL;
        return err;
@@ -296,11 +297,11 @@ static void kfd_process_device_free_bos(struct kfd_process_device *pdd)
                                    per_device_list) {
                        if (!peer_pdd->vm)
                                continue;
-                       peer_pdd->dev->kfd2kgd->unmap_memory_to_gpu(
+                       amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
                                peer_pdd->dev->kgd, mem, peer_pdd->vm);
                }
 
-               pdd->dev->kfd2kgd->free_memory_of_gpu(pdd->dev->kgd, mem);
+               amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->kgd, mem);
                kfd_process_device_remove_obj_handle(pdd, id);
        }
 }
@@ -323,11 +324,12 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
                                pdd->dev->id, p->pasid);
 
                if (pdd->drm_file) {
-                       pdd->dev->kfd2kgd->release_process_vm(pdd->dev->kgd, pdd->vm);
+                       amdgpu_amdkfd_gpuvm_release_process_vm(
+                                       pdd->dev->kgd, pdd->vm);
                        fput(pdd->drm_file);
                }
                else if (pdd->vm)
-                       pdd->dev->kfd2kgd->destroy_process_vm(
+                       amdgpu_amdkfd_gpuvm_destroy_process_vm(
                                pdd->dev->kgd, pdd->vm);
 
                list_del(&pdd->per_device_list);
@@ -688,12 +690,12 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
        dev = pdd->dev;
 
        if (drm_file)
-               ret = dev->kfd2kgd->acquire_process_vm(
+               ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(
                        dev->kgd, drm_file, p->pasid,
                        &pdd->vm, &p->kgd_process_info, &p->ef);
        else
-               ret = dev->kfd2kgd->create_process_vm(
-                       dev->kgd, p->pasid, &pdd->vm, &p->kgd_process_info, &p->ef);
+               ret = amdgpu_amdkfd_gpuvm_create_process_vm(dev->kgd, p->pasid,
+                       &pdd->vm, &p->kgd_process_info, &p->ef);
        if (ret) {
                pr_err("Failed to create process VM object\n");
                return ret;
@@ -714,7 +716,7 @@ err_init_cwsr:
 err_reserve_ib_mem:
        kfd_process_device_free_bos(pdd);
        if (!drm_file)
-               dev->kfd2kgd->destroy_process_vm(dev->kgd, pdd->vm);
+               amdgpu_amdkfd_gpuvm_destroy_process_vm(dev->kgd, pdd->vm);
        pdd->vm = NULL;
 
        return ret;
@@ -972,7 +974,7 @@ static void restore_process_worker(struct work_struct *work)
         */
 
        p->last_restore_timestamp = get_jiffies_64();
-       ret = pdd->dev->kfd2kgd->restore_process_bos(p->kgd_process_info,
+       ret = amdgpu_amdkfd_gpuvm_restore_process_bos(p->kgd_process_info,
                                                     &p->ef);
        if (ret) {
                pr_debug("Failed to restore BOs of pasid %d, retry after %d ms\n",
index e3843c5929edffdf2d0bb45969e7818302c50336..5f5b2acedbac3bf0e15d8727d5327af37e3f7a79 100644 (file)
@@ -36,6 +36,7 @@
 #include "kfd_topology.h"
 #include "kfd_device_queue_manager.h"
 #include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
 
 /* topology_device_list - Master list of all topology devices */
 static struct list_head topology_device_list;
@@ -100,7 +101,25 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev)
        down_read(&topology_lock);
 
        list_for_each_entry(top_dev, &topology_device_list, list)
-               if (top_dev->gpu->pdev == pdev) {
+               if (top_dev->gpu && top_dev->gpu->pdev == pdev) {
+                       device = top_dev->gpu;
+                       break;
+               }
+
+       up_read(&topology_lock);
+
+       return device;
+}
+
+struct kfd_dev *kfd_device_by_kgd(const struct kgd_dev *kgd)
+{
+       struct kfd_topology_device *top_dev;
+       struct kfd_dev *device = NULL;
+
+       down_read(&topology_lock);
+
+       list_for_each_entry(top_dev, &topology_device_list, list)
+               if (top_dev->gpu && top_dev->gpu->kgd == kgd) {
                        device = top_dev->gpu;
                        break;
                }
@@ -1052,7 +1071,7 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
        if (!gpu)
                return 0;
 
-       gpu->kfd2kgd->get_local_mem_info(gpu->kgd, &local_mem_info);
+       amdgpu_amdkfd_get_local_mem_info(gpu->kgd, &local_mem_info);
 
        local_mem_size = local_mem_info.local_mem_size_private +
                        local_mem_info.local_mem_size_public;
@@ -1118,8 +1137,7 @@ static void kfd_fill_mem_clk_max_info(struct kfd_topology_device *dev)
         * for APUs - If CRAT from ACPI reports more than one bank, then
         *      all the banks will report the same mem_clk_max information
         */
-       dev->gpu->kfd2kgd->get_local_mem_info(dev->gpu->kgd,
-               &local_mem_info);
+       amdgpu_amdkfd_get_local_mem_info(dev->gpu->kgd, &local_mem_info);
 
        list_for_each_entry(mem, &dev->mem_props, list)
                mem->mem_clk_max = local_mem_info.mem_clk_max;
@@ -1240,7 +1258,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
         * needed for the topology
         */
 
-       dev->gpu->kfd2kgd->get_cu_info(dev->gpu->kgd, &cu_info);
+       amdgpu_amdkfd_get_cu_info(dev->gpu->kgd, &cu_info);
        dev->node_props.simd_arrays_per_engine =
                cu_info.num_shader_arrays_per_engine;
 
@@ -1249,7 +1267,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
        dev->node_props.location_id = PCI_DEVID(gpu->pdev->bus->number,
                gpu->pdev->devfn);
        dev->node_props.max_engine_clk_fcompute =
-               dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(dev->gpu->kgd);
+               amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->kgd);
        dev->node_props.max_engine_clk_ccompute =
                cpufreq_quick_get_max(0) / 1000;
        dev->node_props.drm_render_minor =
@@ -1272,12 +1290,14 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
        case CHIP_FIJI:
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
                pr_debug("Adding doorbell packet type capability\n");
                dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_1_0 <<
                        HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) &
                        HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK);
                break;
        case CHIP_VEGA10:
+       case CHIP_VEGA12:
        case CHIP_VEGA20:
        case CHIP_RAVEN:
                dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_2_0 <<
index c97dc9613325c07f7b5d3165dfc9127bb05575d4..cfde1568c79af8425170d6ff7429cfb691d29477 100644 (file)
@@ -32,11 +32,12 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/info_packet
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/power
 
 #TODO: remove when Timing Sync feature is complete
 subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0
 
-DAL_LIBS = amdgpu_dm dc        modules/freesync modules/color modules/info_packet
+DAL_LIBS = amdgpu_dm dc        modules/freesync modules/color modules/info_packet modules/power
 
 AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS)))
 
index 5a6edf65c9eaebd958104d4d0dd8216281ffaccc..d01315965af06c1b6d82c38fb796faaf61d3ba2c 100644 (file)
@@ -23,6 +23,9 @@
  *
  */
 
+/* The caprices of the preprocessor require that this be declared right here */
+#define CREATE_TRACE_POINTS
+
 #include "dm_services_types.h"
 #include "dc.h"
 #include "dc/inc/core_types.h"
@@ -38,7 +41,6 @@
 #include "amd_shared.h"
 #include "amdgpu_dm_irq.h"
 #include "dm_helpers.h"
-#include "dm_services_types.h"
 #include "amdgpu_dm_mst_types.h"
 #if defined(CONFIG_DEBUG_FS)
 #include "amdgpu_dm_debugfs.h"
@@ -55,6 +57,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_fb_helper.h>
 #endif
 
 #include "modules/inc/mod_freesync.h"
+#include "modules/power/power_helpers.h"
+#include "modules/inc/mod_info_packet.h"
 
 #define FIRMWARE_RAVEN_DMCU            "amdgpu/raven_dmcu.bin"
 MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU);
 
+/**
+ * DOC: overview
+ *
+ * The AMDgpu display manager, **amdgpu_dm** (or even simpler,
+ * **dm**) sits between DRM and DC. It acts as a liason, converting DRM
+ * requests into DC requests, and DC responses into DRM responses.
+ *
+ * The root control structure is &struct amdgpu_display_manager.
+ */
+
 /* basic init/fini API */
 static int amdgpu_dm_init(struct amdgpu_device *adev);
 static void amdgpu_dm_fini(struct amdgpu_device *adev);
@@ -95,7 +110,7 @@ static void
 amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector);
 
 static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
-                               struct amdgpu_plane *aplane,
+                               struct drm_plane *plane,
                                unsigned long possible_crtcs);
 static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
                               struct drm_plane *plane,
@@ -119,6 +134,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
 static int amdgpu_dm_atomic_check(struct drm_device *dev,
                                  struct drm_atomic_state *state);
 
+static void handle_cursor_update(struct drm_plane *plane,
+                                struct drm_plane_state *old_plane_state);
 
 
 
@@ -379,11 +396,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
 
 }
 
-/*
- * Init display KMS
- *
- * Returns 0 on success
- */
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -393,6 +405,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        /* Zero all the fields */
        memset(&init_data, 0, sizeof(init_data));
 
+       mutex_init(&adev->dm.dc_lock);
+
        if(amdgpu_dm_irq_init(adev)) {
                DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
                goto error;
@@ -507,6 +521,9 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
        /* DC Destroy TODO: Replace destroy DAL */
        if (adev->dm.dc)
                dc_destroy(&adev->dm.dc);
+
+       mutex_destroy(&adev->dm.dc_lock);
+
        return;
 }
 
@@ -638,6 +655,26 @@ static int dm_late_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       struct dmcu_iram_parameters params;
+       unsigned int linear_lut[16];
+       int i;
+       struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
+       bool ret;
+
+       for (i = 0; i < 16; i++)
+               linear_lut[i] = 0xFFFF * i / 15;
+
+       params.set = 0;
+       params.backlight_ramping_start = 0xCCCC;
+       params.backlight_ramping_reduction = 0xCCCCCCCC;
+       params.backlight_lut_array_size = 16;
+       params.backlight_lut_array = linear_lut;
+
+       ret = dmcu_load_iram(dmcu, params);
+
+       if (!ret)
+               return -EINVAL;
+
        return detect_mst_link_for_all_connectors(adev->ddev);
 }
 
@@ -663,6 +700,26 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
 }
 
+/**
+ * dm_hw_init() - Initialize DC device
+ * @handle: The base driver device containing the amdpgu_dm device.
+ *
+ * Initialize the &struct amdgpu_display_manager device. This involves calling
+ * the initializers of each DM component, then populating the struct with them.
+ *
+ * Although the function implies hardware initialization, both hardware and
+ * software are initialized here. Splitting them out to their relevant init
+ * hooks is a future TODO item.
+ *
+ * Some notable things that are initialized here:
+ *
+ * - Display Core, both software and hardware
+ * - DC modules that we need (freesync and color management)
+ * - DRM software states
+ * - Interrupt sources and handlers
+ * - Vblank support
+ * - Debug FS entries, if enabled
+ */
 static int dm_hw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -673,6 +730,14 @@ static int dm_hw_init(void *handle)
        return 0;
 }
 
+/**
+ * dm_hw_fini() - Teardown DC device
+ * @handle: The base driver device containing the amdpgu_dm device.
+ *
+ * Teardown components within &struct amdgpu_display_manager that require
+ * cleanup. This involves cleaning up the DRM device, DC, and any modules that
+ * were loaded. Also flush IRQ workqueues and disable them.
+ */
 static int dm_hw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -898,6 +963,16 @@ static int dm_resume(void *handle)
        return ret;
 }
 
+/**
+ * DOC: DM Lifecycle
+ *
+ * DM (and consequently DC) is registered in the amdgpu base driver as a IP
+ * block. When CONFIG_DRM_AMD_DC is enabled, the DM device IP block is added to
+ * the base driver's device list to be initialized and torn down accordingly.
+ *
+ * The functions to do so are provided as hooks in &struct amd_ip_funcs.
+ */
+
 static const struct amd_ip_funcs amdgpu_dm_funcs = {
        .name = "dm",
        .early_init = dm_early_init,
@@ -926,53 +1001,17 @@ const struct amdgpu_ip_block_version dm_ip_block =
 };
 
 
-static struct drm_atomic_state *
-dm_atomic_state_alloc(struct drm_device *dev)
-{
-       struct dm_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
-
-       if (!state)
-               return NULL;
-
-       if (drm_atomic_state_init(dev, &state->base) < 0)
-               goto fail;
-
-       return &state->base;
-
-fail:
-       kfree(state);
-       return NULL;
-}
-
-static void
-dm_atomic_state_clear(struct drm_atomic_state *state)
-{
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
-
-       if (dm_state->context) {
-               dc_release_state(dm_state->context);
-               dm_state->context = NULL;
-       }
-
-       drm_atomic_state_default_clear(state);
-}
-
-static void
-dm_atomic_state_alloc_free(struct drm_atomic_state *state)
-{
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
-       drm_atomic_state_default_release(state);
-       kfree(dm_state);
-}
+/**
+ * DOC: atomic
+ *
+ * *WIP*
+ */
 
 static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
        .fb_create = amdgpu_display_user_framebuffer_create,
        .output_poll_changed = drm_fb_helper_output_poll_changed,
        .atomic_check = amdgpu_dm_atomic_check,
        .atomic_commit = amdgpu_dm_atomic_commit,
-       .atomic_state_alloc = dm_atomic_state_alloc,
-       .atomic_state_clear = dm_atomic_state_clear,
-       .atomic_state_free = dm_atomic_state_alloc_free
 };
 
 static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
@@ -1494,8 +1533,117 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
 }
 #endif
 
+/*
+ * Acquires the lock for the atomic state object and returns
+ * the new atomic state.
+ *
+ * This should only be called during atomic check.
+ */
+static int dm_atomic_get_state(struct drm_atomic_state *state,
+                              struct dm_atomic_state **dm_state)
+{
+       struct drm_device *dev = state->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       struct drm_private_state *priv_state;
+       int ret;
+
+       if (*dm_state)
+               return 0;
+
+       ret = drm_modeset_lock(&dm->atomic_obj_lock, state->acquire_ctx);
+       if (ret)
+               return ret;
+
+       priv_state = drm_atomic_get_private_obj_state(state, &dm->atomic_obj);
+       if (IS_ERR(priv_state))
+               return PTR_ERR(priv_state);
+
+       *dm_state = to_dm_atomic_state(priv_state);
+
+       return 0;
+}
+
+struct dm_atomic_state *
+dm_atomic_get_new_state(struct drm_atomic_state *state)
+{
+       struct drm_device *dev = state->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       struct drm_private_obj *obj;
+       struct drm_private_state *new_obj_state;
+       int i;
+
+       for_each_new_private_obj_in_state(state, obj, new_obj_state, i) {
+               if (obj->funcs == dm->atomic_obj.funcs)
+                       return to_dm_atomic_state(new_obj_state);
+       }
+
+       return NULL;
+}
+
+struct dm_atomic_state *
+dm_atomic_get_old_state(struct drm_atomic_state *state)
+{
+       struct drm_device *dev = state->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       struct drm_private_obj *obj;
+       struct drm_private_state *old_obj_state;
+       int i;
+
+       for_each_old_private_obj_in_state(state, obj, old_obj_state, i) {
+               if (obj->funcs == dm->atomic_obj.funcs)
+                       return to_dm_atomic_state(old_obj_state);
+       }
+
+       return NULL;
+}
+
+static struct drm_private_state *
+dm_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+       struct dm_atomic_state *old_state, *new_state;
+
+       new_state = kzalloc(sizeof(*new_state), GFP_KERNEL);
+       if (!new_state)
+               return NULL;
+
+       __drm_atomic_helper_private_obj_duplicate_state(obj, &new_state->base);
+
+       new_state->context = dc_create_state();
+       if (!new_state->context) {
+               kfree(new_state);
+               return NULL;
+       }
+
+       old_state = to_dm_atomic_state(obj->state);
+       if (old_state && old_state->context)
+               dc_resource_state_copy_construct(old_state->context,
+                                                new_state->context);
+
+       return &new_state->base;
+}
+
+static void dm_atomic_destroy_state(struct drm_private_obj *obj,
+                                   struct drm_private_state *state)
+{
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+
+       if (dm_state && dm_state->context)
+               dc_release_state(dm_state->context);
+
+       kfree(dm_state);
+}
+
+static struct drm_private_state_funcs dm_atomic_state_funcs = {
+       .atomic_duplicate_state = dm_atomic_duplicate_state,
+       .atomic_destroy_state = dm_atomic_destroy_state,
+};
+
 static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
 {
+       struct dm_atomic_state *state;
        int r;
 
        adev->mode_info.mode_config_initialized = true;
@@ -1513,6 +1661,24 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
 
        adev->ddev->mode_config.fb_base = adev->gmc.aper_base;
 
+       drm_modeset_lock_init(&adev->dm.atomic_obj_lock);
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->context = dc_create_state();
+       if (!state->context) {
+               kfree(state);
+               return -ENOMEM;
+       }
+
+       dc_resource_state_copy_construct_current(adev->dm.dc, state->context);
+
+       drm_atomic_private_obj_init(&adev->dm.atomic_obj,
+                                   &state->base,
+                                   &dm_atomic_state_funcs);
+
        r = amdgpu_display_modeset_create_props(adev);
        if (r)
                return r;
@@ -1520,15 +1686,63 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        return 0;
 }
 
+#define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12
+#define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
+
 #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
        defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
 
+static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm)
+{
+#if defined(CONFIG_ACPI)
+       struct amdgpu_dm_backlight_caps caps;
+
+       if (dm->backlight_caps.caps_valid)
+               return;
+
+       amdgpu_acpi_get_backlight_caps(dm->adev, &caps);
+       if (caps.caps_valid) {
+               dm->backlight_caps.min_input_signal = caps.min_input_signal;
+               dm->backlight_caps.max_input_signal = caps.max_input_signal;
+               dm->backlight_caps.caps_valid = true;
+       } else {
+               dm->backlight_caps.min_input_signal =
+                               AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
+               dm->backlight_caps.max_input_signal =
+                               AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
+       }
+#else
+       dm->backlight_caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
+       dm->backlight_caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
+#endif
+}
+
 static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
 {
        struct amdgpu_display_manager *dm = bl_get_data(bd);
+       struct amdgpu_dm_backlight_caps caps;
+       uint32_t brightness = bd->props.brightness;
+
+       amdgpu_dm_update_backlight_caps(dm);
+       caps = dm->backlight_caps;
+       /*
+        * The brightness input is in the range 0-255
+        * It needs to be rescaled to be between the
+        * requested min and max input signal
+        *
+        * It also needs to be scaled up by 0x101 to
+        * match the DC interface which has a range of
+        * 0 to 0xffff
+        */
+       brightness =
+               brightness
+               * 0x101
+               * (caps.max_input_signal - caps.min_input_signal)
+               / AMDGPU_MAX_BL_LEVEL
+               + caps.min_input_signal * 0x101;
 
        if (dc_link_set_backlight_level(dm->backlight_link,
-                       bd->props.brightness, 0, 0))
+                       brightness, 0, 0))
                return 0;
        else
                return 1;
@@ -1555,6 +1769,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
        char bl_name[16];
        struct backlight_properties props = { 0 };
 
+       amdgpu_dm_update_backlight_caps(dm);
+
        props.max_brightness = AMDGPU_MAX_BL_LEVEL;
        props.brightness = AMDGPU_MAX_BL_LEVEL;
        props.type = BACKLIGHT_RAW;
@@ -1580,18 +1796,18 @@ static int initialize_plane(struct amdgpu_display_manager *dm,
                             struct amdgpu_mode_info *mode_info,
                             int plane_id)
 {
-       struct amdgpu_plane *plane;
+       struct drm_plane *plane;
        unsigned long possible_crtcs;
        int ret = 0;
 
-       plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL);
+       plane = kzalloc(sizeof(struct drm_plane), GFP_KERNEL);
        mode_info->planes[plane_id] = plane;
 
        if (!plane) {
                DRM_ERROR("KMS: Failed to allocate plane\n");
                return -ENOMEM;
        }
-       plane->base.type = mode_info->plane_type[plane_id];
+       plane->type = mode_info->plane_type[plane_id];
 
        /*
         * HACK: IGT tests expect that each plane can only have
@@ -1682,7 +1898,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
        }
 
        for (i = 0; i < dm->dc->caps.max_streams; i++)
-               if (amdgpu_dm_crtc_init(dm, &mode_info->planes[i]->base, i)) {
+               if (amdgpu_dm_crtc_init(dm, mode_info->planes[i], i)) {
                        DRM_ERROR("KMS: Failed to initialize crtc\n");
                        goto fail;
                }
@@ -1786,6 +2002,7 @@ fail:
 static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm)
 {
        drm_mode_config_cleanup(dm->ddev);
+       drm_atomic_private_obj_fini(&dm->atomic_obj);
        return;
 }
 
@@ -1805,73 +2022,6 @@ static void dm_bandwidth_update(struct amdgpu_device *adev)
        /* TODO: implement later */
 }
 
-static int amdgpu_notify_freesync(struct drm_device *dev, void *data,
-                               struct drm_file *filp)
-{
-       struct drm_atomic_state *state;
-       struct drm_modeset_acquire_ctx ctx;
-       struct drm_crtc *crtc;
-       struct drm_connector *connector;
-       struct drm_connector_state *old_con_state, *new_con_state;
-       int ret = 0;
-       uint8_t i;
-       bool enable = false;
-
-       drm_modeset_acquire_init(&ctx, 0);
-
-       state = drm_atomic_state_alloc(dev);
-       if (!state) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       state->acquire_ctx = &ctx;
-
-retry:
-       drm_for_each_crtc(crtc, dev) {
-               ret = drm_atomic_add_affected_connectors(state, crtc);
-               if (ret)
-                       goto fail;
-
-               /* TODO rework amdgpu_dm_commit_planes so we don't need this */
-               ret = drm_atomic_add_affected_planes(state, crtc);
-               if (ret)
-                       goto fail;
-       }
-
-       for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
-               struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
-               struct drm_crtc_state *new_crtc_state;
-               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
-               struct dm_crtc_state *dm_new_crtc_state;
-
-               if (!acrtc) {
-                       ASSERT(0);
-                       continue;
-               }
-
-               new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
-               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
-
-               dm_new_crtc_state->freesync_enabled = enable;
-       }
-
-       ret = drm_atomic_commit(state);
-
-fail:
-       if (ret == -EDEADLK) {
-               drm_atomic_state_clear(state);
-               drm_modeset_backoff(&ctx);
-               goto retry;
-       }
-
-       drm_atomic_state_put(state);
-
-out:
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-       return ret;
-}
-
 static const struct amdgpu_display_funcs dm_display_funcs = {
        .bandwidth_update = dm_bandwidth_update, /* called unconditionally */
        .vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */
@@ -1884,8 +2034,6 @@ static const struct amdgpu_display_funcs dm_display_funcs = {
                dm_crtc_get_scanoutpos,/* called unconditionally */
        .add_encoder = NULL, /* VBIOS parsing. DAL does it. */
        .add_connector = NULL, /* VBIOS parsing. DAL does it. */
-       .notify_freesync = amdgpu_notify_freesync,
-
 };
 
 #if defined(CONFIG_DEBUG_KERNEL_DC)
@@ -2486,7 +2634,8 @@ static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_
 static void
 fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
                                             const struct drm_display_mode *mode_in,
-                                            const struct drm_connector *connector)
+                                            const struct drm_connector *connector,
+                                            const struct dc_stream_state *old_stream)
 {
        struct dc_crtc_timing *timing_out = &stream->timing;
        const struct drm_display_info *info = &connector->display_info;
@@ -2512,7 +2661,18 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
                        connector);
        timing_out->scan_type = SCANNING_TYPE_NODATA;
        timing_out->hdmi_vic = 0;
-       timing_out->vic = drm_match_cea_mode(mode_in);
+
+       if(old_stream) {
+               timing_out->vic = old_stream->timing.vic;
+               timing_out->flags.HSYNC_POSITIVE_POLARITY = old_stream->timing.flags.HSYNC_POSITIVE_POLARITY;
+               timing_out->flags.VSYNC_POSITIVE_POLARITY = old_stream->timing.flags.VSYNC_POSITIVE_POLARITY;
+       } else {
+               timing_out->vic = drm_match_cea_mode(mode_in);
+               if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
+                       timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
+               if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
+                       timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
+       }
 
        timing_out->h_addressable = mode_in->crtc_hdisplay;
        timing_out->h_total = mode_in->crtc_htotal;
@@ -2528,10 +2688,6 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
                mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
        timing_out->pix_clk_khz = mode_in->crtc_clock;
        timing_out->aspect_ratio = get_aspect_ratio(mode_in);
-       if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
-               timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
-       if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
-               timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
 
        stream->output_color_space = get_output_color_space(timing_out);
 
@@ -2694,13 +2850,18 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
 static struct dc_stream_state *
 create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                       const struct drm_display_mode *drm_mode,
-                      const struct dm_connector_state *dm_state)
+                      const struct dm_connector_state *dm_state,
+                      const struct dc_stream_state *old_stream)
 {
        struct drm_display_mode *preferred_mode = NULL;
        struct drm_connector *drm_connector;
        struct dc_stream_state *stream = NULL;
        struct drm_display_mode mode = *drm_mode;
        bool native_mode_found = false;
+       bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false;
+       int mode_refresh;
+       int preferred_refresh = 0;
+
        struct dc_sink *sink = NULL;
        if (aconnector == NULL) {
                DRM_ERROR("aconnector is NULL!\n");
@@ -2739,6 +2900,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                                struct drm_display_mode,
                                head);
 
+       mode_refresh = drm_mode_vrefresh(&mode);
+
        if (preferred_mode == NULL) {
                /*
                 * This may not be an error, the use case is when we have no
@@ -2751,13 +2914,23 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                decide_crtc_timing_for_drm_display_mode(
                                &mode, preferred_mode,
                                dm_state ? (dm_state->scaling != RMX_OFF) : false);
+               preferred_refresh = drm_mode_vrefresh(preferred_mode);
        }
 
        if (!dm_state)
                drm_mode_set_crtcinfo(&mode, 0);
 
-       fill_stream_properties_from_drm_display_mode(stream,
-                       &mode, &aconnector->base);
+       /*
+       * If scaling is enabled and refresh rate didn't change
+       * we copy the vic and polarities of the old timings
+       */
+       if (!scale || mode_refresh != preferred_refresh)
+               fill_stream_properties_from_drm_display_mode(stream,
+                       &mode, &aconnector->base, NULL);
+       else
+               fill_stream_properties_from_drm_display_mode(stream,
+                       &mode, &aconnector->base, old_stream);
+
        update_stream_scaling_settings(&mode, dm_state, stream);
 
        fill_audio_info(
@@ -2769,6 +2942,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 
        if (dm_state && dm_state->freesync_capable)
                stream->ignore_msa_timing_param = true;
+
 finish:
        if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON)
                dc_sink_release(sink);
@@ -2837,7 +3011,10 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
 
        state->adjust = cur->adjust;
        state->vrr_infopacket = cur->vrr_infopacket;
-       state->freesync_enabled = cur->freesync_enabled;
+       state->abm_level = cur->abm_level;
+       state->vrr_supported = cur->vrr_supported;
+       state->freesync_config = cur->freesync_config;
+       state->crc_enabled = cur->crc_enabled;
 
        /* TODO Duplicate dc_stream after objects are stream object is flattened */
 
@@ -2953,6 +3130,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
        } else if (property == adev->mode_info.max_bpc_property) {
                dm_new_state->max_bpc = val;
                ret = 0;
+       } else if (property == adev->mode_info.abm_level_property) {
+               dm_new_state->abm_level = val;
+               ret = 0;
        }
 
        return ret;
@@ -2998,7 +3178,11 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
        } else if (property == adev->mode_info.max_bpc_property) {
                *val = dm_state->max_bpc;
                ret = 0;
+       } else if (property == adev->mode_info.abm_level_property) {
+               *val = dm_state->abm_level;
+               ret = 0;
        }
+
        return ret;
 }
 
@@ -3063,7 +3247,11 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
        __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
 
        new_state->freesync_capable = state->freesync_capable;
-       new_state->freesync_enable = state->freesync_enable;
+       new_state->abm_level = state->abm_level;
+       new_state->scaling = state->scaling;
+       new_state->underscan_enable = state->underscan_enable;
+       new_state->underscan_hborder = state->underscan_hborder;
+       new_state->underscan_vborder = state->underscan_vborder;
        new_state->max_bpc = state->max_bpc;
 
        return &new_state->base;
@@ -3166,7 +3354,7 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
                goto fail;
        }
 
-       stream = create_stream_for_sink(aconnector, mode, NULL);
+       stream = create_stream_for_sink(aconnector, mode, NULL, NULL);
        if (stream == NULL) {
                DRM_ERROR("Failed to create stream for sink!\n");
                goto fail;
@@ -3200,7 +3388,6 @@ amdgpu_dm_connector_helper_funcs = {
         */
        .get_modes = get_modes,
        .mode_valid = amdgpu_dm_connector_mode_valid,
-       .best_encoder = drm_atomic_helper_best_encoder
 };
 
 static void dm_crtc_helper_disable(struct drm_crtc *crtc)
@@ -3438,10 +3625,43 @@ static int dm_plane_atomic_check(struct drm_plane *plane,
        return -EINVAL;
 }
 
+static int dm_plane_atomic_async_check(struct drm_plane *plane,
+                                      struct drm_plane_state *new_plane_state)
+{
+       /* Only support async updates on cursor planes. */
+       if (plane->type != DRM_PLANE_TYPE_CURSOR)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void dm_plane_atomic_async_update(struct drm_plane *plane,
+                                        struct drm_plane_state *new_state)
+{
+       struct drm_plane_state *old_state =
+               drm_atomic_get_old_plane_state(new_state->state, plane);
+
+       if (plane->state->fb != new_state->fb)
+               drm_atomic_set_fb_for_plane(plane->state, new_state->fb);
+
+       plane->state->src_x = new_state->src_x;
+       plane->state->src_y = new_state->src_y;
+       plane->state->src_w = new_state->src_w;
+       plane->state->src_h = new_state->src_h;
+       plane->state->crtc_x = new_state->crtc_x;
+       plane->state->crtc_y = new_state->crtc_y;
+       plane->state->crtc_w = new_state->crtc_w;
+       plane->state->crtc_h = new_state->crtc_h;
+
+       handle_cursor_update(plane, old_state);
+}
+
 static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
        .prepare_fb = dm_plane_helper_prepare_fb,
        .cleanup_fb = dm_plane_helper_cleanup_fb,
        .atomic_check = dm_plane_atomic_check,
+       .atomic_async_check = dm_plane_atomic_async_check,
+       .atomic_async_update = dm_plane_atomic_async_update
 };
 
 /*
@@ -3473,49 +3693,49 @@ static const u32 cursor_formats[] = {
 };
 
 static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
-                               struct amdgpu_plane *aplane,
+                               struct drm_plane *plane,
                                unsigned long possible_crtcs)
 {
        int res = -EPERM;
 
-       switch (aplane->base.type) {
+       switch (plane->type) {
        case DRM_PLANE_TYPE_PRIMARY:
                res = drm_universal_plane_init(
                                dm->adev->ddev,
-                               &aplane->base,
+                               plane,
                                possible_crtcs,
                                &dm_plane_funcs,
                                rgb_formats,
                                ARRAY_SIZE(rgb_formats),
-                               NULL, aplane->base.type, NULL);
+                               NULL, plane->type, NULL);
                break;
        case DRM_PLANE_TYPE_OVERLAY:
                res = drm_universal_plane_init(
                                dm->adev->ddev,
-                               &aplane->base,
+                               plane,
                                possible_crtcs,
                                &dm_plane_funcs,
                                yuv_formats,
                                ARRAY_SIZE(yuv_formats),
-                               NULL, aplane->base.type, NULL);
+                               NULL, plane->type, NULL);
                break;
        case DRM_PLANE_TYPE_CURSOR:
                res = drm_universal_plane_init(
                                dm->adev->ddev,
-                               &aplane->base,
+                               plane,
                                possible_crtcs,
                                &dm_plane_funcs,
                                cursor_formats,
                                ARRAY_SIZE(cursor_formats),
-                               NULL, aplane->base.type, NULL);
+                               NULL, plane->type, NULL);
                break;
        }
 
-       drm_plane_helper_add(&aplane->base, &dm_plane_helper_funcs);
+       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
 
        /* Create (reset) the plane state */
-       if (aplane->base.funcs->reset)
-               aplane->base.funcs->reset(&aplane->base);
+       if (plane->funcs->reset)
+               plane->funcs->reset(plane);
 
 
        return res;
@@ -3526,7 +3746,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
                               uint32_t crtc_index)
 {
        struct amdgpu_crtc *acrtc = NULL;
-       struct amdgpu_plane *cursor_plane;
+       struct drm_plane *cursor_plane;
 
        int res = -ENOMEM;
 
@@ -3534,7 +3754,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
        if (!cursor_plane)
                goto fail;
 
-       cursor_plane->base.type = DRM_PLANE_TYPE_CURSOR;
+       cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
        res = amdgpu_dm_plane_init(dm, cursor_plane, 0);
 
        acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
@@ -3545,7 +3765,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
                        dm->ddev,
                        &acrtc->base,
                        plane,
-                       &cursor_plane->base,
+                       cursor_plane,
                        &amdgpu_dm_crtc_funcs, NULL);
 
        if (res)
@@ -3603,14 +3823,17 @@ static int to_drm_connector_type(enum signal_type st)
        }
 }
 
+static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
+{
+       return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
+}
+
 static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
 {
-       const struct drm_connector_helper_funcs *helper =
-               connector->helper_private;
        struct drm_encoder *encoder;
        struct amdgpu_encoder *amdgpu_encoder;
 
-       encoder = helper->best_encoder(connector);
+       encoder = amdgpu_dm_connector_to_encoder(connector);
 
        if (encoder == NULL)
                return;
@@ -3737,14 +3960,12 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
 
 static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
 {
-       const struct drm_connector_helper_funcs *helper =
-                       connector->helper_private;
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                        to_amdgpu_dm_connector(connector);
        struct drm_encoder *encoder;
        struct edid *edid = amdgpu_dm_connector->edid;
 
-       encoder = helper->best_encoder(connector);
+       encoder = amdgpu_dm_connector_to_encoder(connector);
 
        if (!edid || !drm_edid_is_valid(edid)) {
                amdgpu_dm_connector->num_modes =
@@ -3783,12 +4004,12 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
        case DRM_MODE_CONNECTOR_HDMIA:
                aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
                aconnector->base.ycbcr_420_allowed =
-                       link->link_enc->features.ycbcr420_supported ? true : false;
+                       link->link_enc->features.hdmi_ycbcr420_supported ? true : false;
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
                aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
                aconnector->base.ycbcr_420_allowed =
-                       link->link_enc->features.ycbcr420_supported ? true : false;
+                       link->link_enc->features.dp_ycbcr420_supported ? true : false;
                break;
        case DRM_MODE_CONNECTOR_DVID:
                aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
@@ -3814,6 +4035,17 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.max_bpc_property,
                                0);
 
+       if (connector_type == DRM_MODE_CONNECTOR_eDP &&
+           dc_is_dmcu_initialized(adev->dm.dc)) {
+               drm_object_attach_property(&aconnector->base.base,
+                               adev->mode_info.abm_level_property, 0);
+       }
+
+       if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+           connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               drm_connector_attach_vrr_capable_property(
+                       &aconnector->base);
+       }
 }
 
 static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -4118,6 +4350,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
 static void handle_cursor_update(struct drm_plane *plane,
                                 struct drm_plane_state *old_plane_state)
 {
+       struct amdgpu_device *adev = plane->dev->dev_private;
        struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
        struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
        struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
@@ -4142,9 +4375,12 @@ static void handle_cursor_update(struct drm_plane *plane,
 
        if (!position.enable) {
                /* turn off cursor */
-               if (crtc_state && crtc_state->stream)
+               if (crtc_state && crtc_state->stream) {
+                       mutex_lock(&adev->dm.dc_lock);
                        dc_stream_set_cursor_position(crtc_state->stream,
                                                      &position);
+                       mutex_unlock(&adev->dm.dc_lock);
+               }
                return;
        }
 
@@ -4162,6 +4398,7 @@ static void handle_cursor_update(struct drm_plane *plane,
        attributes.pitch = attributes.width;
 
        if (crtc_state->stream) {
+               mutex_lock(&adev->dm.dc_lock);
                if (!dc_stream_set_cursor_attributes(crtc_state->stream,
                                                         &attributes))
                        DRM_ERROR("DC failed to set cursor attributes\n");
@@ -4169,6 +4406,7 @@ static void handle_cursor_update(struct drm_plane *plane,
                if (!dc_stream_set_cursor_position(crtc_state->stream,
                                                   &position))
                        DRM_ERROR("DC failed to set cursor position\n");
+               mutex_unlock(&adev->dm.dc_lock);
        }
 }
 
@@ -4190,6 +4428,91 @@ static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
                                                 acrtc->crtc_id);
 }
 
+struct dc_stream_status *dc_state_get_stream_status(
+       struct dc_state *state,
+       struct dc_stream_state *stream)
+{
+       uint8_t i;
+
+       for (i = 0; i < state->stream_count; i++) {
+               if (stream == state->streams[i])
+                       return &state->stream_status[i];
+       }
+
+       return NULL;
+}
+
+static void update_freesync_state_on_stream(
+       struct amdgpu_display_manager *dm,
+       struct dm_crtc_state *new_crtc_state,
+       struct dc_stream_state *new_stream)
+{
+       struct mod_vrr_params vrr = {0};
+       struct dc_info_packet vrr_infopacket = {0};
+       struct mod_freesync_config config = new_crtc_state->freesync_config;
+
+       if (!new_stream)
+               return;
+
+       /*
+        * TODO: Determine why min/max totals and vrefresh can be 0 here.
+        * For now it's sufficient to just guard against these conditions.
+        */
+
+       if (!new_stream->timing.h_total || !new_stream->timing.v_total)
+               return;
+
+       if (new_crtc_state->vrr_supported &&
+           config.min_refresh_in_uhz &&
+           config.max_refresh_in_uhz) {
+               config.state = new_crtc_state->base.vrr_enabled ?
+                       VRR_STATE_ACTIVE_VARIABLE :
+                       VRR_STATE_INACTIVE;
+       } else {
+               config.state = VRR_STATE_UNSUPPORTED;
+       }
+
+       mod_freesync_build_vrr_params(dm->freesync_module,
+                                     new_stream,
+                                     &config, &vrr);
+
+       mod_freesync_build_vrr_infopacket(
+               dm->freesync_module,
+               new_stream,
+               &vrr,
+               PACKET_TYPE_VRR,
+               TRANSFER_FUNC_UNKNOWN,
+               &vrr_infopacket);
+
+       new_crtc_state->freesync_timing_changed =
+               (memcmp(&new_crtc_state->adjust,
+                       &vrr.adjust,
+                       sizeof(vrr.adjust)) != 0);
+
+       new_crtc_state->freesync_vrr_info_changed =
+               (memcmp(&new_crtc_state->vrr_infopacket,
+                       &vrr_infopacket,
+                       sizeof(vrr_infopacket)) != 0);
+
+       new_crtc_state->adjust = vrr.adjust;
+       new_crtc_state->vrr_infopacket = vrr_infopacket;
+
+       new_stream->adjust = new_crtc_state->adjust;
+       new_stream->vrr_infopacket = vrr_infopacket;
+
+       if (new_crtc_state->freesync_vrr_info_changed)
+               DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
+                             new_crtc_state->base.crtc->base.id,
+                             (int)new_crtc_state->base.vrr_enabled,
+                             (int)vrr.state);
+
+       if (new_crtc_state->freesync_timing_changed)
+               DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n",
+                             new_crtc_state->base.crtc->base.id,
+                             vrr.adjust.v_total_min,
+                             vrr.adjust.v_total_max);
+}
+
 /*
  * Executes flip
  *
@@ -4211,6 +4534,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
        struct dc_flip_addrs addr = { {0} };
        /* TODO eliminate or rename surface_update */
        struct dc_surface_update surface_updates[1] = { {0} };
+       struct dc_stream_update stream_update = {0};
        struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
        struct dc_stream_status *stream_status;
 
@@ -4283,13 +4607,30 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
        }
        surface_updates->flip_addr = &addr;
 
+       if (acrtc_state->stream) {
+               update_freesync_state_on_stream(
+                       &adev->dm,
+                       acrtc_state,
+                       acrtc_state->stream);
+
+               if (acrtc_state->freesync_timing_changed)
+                       stream_update.adjust =
+                               &acrtc_state->stream->adjust;
+
+               if (acrtc_state->freesync_vrr_info_changed)
+                       stream_update.vrr_infopacket =
+                               &acrtc_state->stream->vrr_infopacket;
+       }
+
+       mutex_lock(&adev->dm.dc_lock);
        dc_commit_updates_for_stream(adev->dm.dc,
                                             surface_updates,
                                             1,
                                             acrtc_state->stream,
-                                            NULL,
+                                            &stream_update,
                                             &surface_updates->surface,
                                             state);
+       mutex_unlock(&adev->dm.dc_lock);
 
        DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
                         __func__,
@@ -4304,6 +4645,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
  * with a dc_plane_state and follow the atomic model a bit more closely here.
  */
 static bool commit_planes_to_stream(
+               struct amdgpu_display_manager *dm,
                struct dc *dc,
                struct dc_plane_state **plane_states,
                uint8_t new_plane_count,
@@ -4320,6 +4662,7 @@ static bool commit_planes_to_stream(
        struct dc_stream_state *dc_stream = dm_new_crtc_state->stream;
        struct dc_stream_update *stream_update =
                        kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
+       unsigned int abm_level;
 
        if (!stream_update) {
                BREAK_TO_DEBUGGER();
@@ -4347,9 +4690,9 @@ static bool commit_planes_to_stream(
        stream_update->dst = dc_stream->dst;
        stream_update->out_transfer_func = dc_stream->out_transfer_func;
 
-       if (dm_new_crtc_state->freesync_enabled != dm_old_crtc_state->freesync_enabled) {
-               stream_update->vrr_infopacket = &dc_stream->vrr_infopacket;
-               stream_update->adjust = &dc_stream->adjust;
+       if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
+               abm_level = dm_new_crtc_state->abm_level;
+               stream_update->abm_level = &abm_level;
        }
 
        for (i = 0; i < new_plane_count; i++) {
@@ -4379,11 +4722,13 @@ static bool commit_planes_to_stream(
                updates[i].scaling_info = &scaling_info[i];
        }
 
+       mutex_lock(&dm->dc_lock);
        dc_commit_updates_for_stream(
                        dc,
                        updates,
                        new_plane_count,
                        dc_stream, stream_update, plane_states, state);
+       mutex_unlock(&dm->dc_lock);
 
        kfree(flip_addr);
        kfree(plane_info);
@@ -4393,6 +4738,7 @@ static bool commit_planes_to_stream(
 }
 
 static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+                                   struct dc_state *dc_state,
                                    struct drm_device *dev,
                                    struct amdgpu_display_manager *dm,
                                    struct drm_crtc *pcrtc,
@@ -4409,7 +4755,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
        struct dm_crtc_state *dm_old_crtc_state =
                        to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
        int planes_count = 0;
        unsigned long flags;
 
@@ -4470,7 +4815,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                crtc,
                                fb,
                                (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
-                               dm_state->context);
+                               dc_state);
                }
 
        }
@@ -4487,15 +4832,15 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
                }
 
-               dc_stream_attach->adjust = acrtc_state->adjust;
-               dc_stream_attach->vrr_infopacket = acrtc_state->vrr_infopacket;
+               dc_stream_attach->abm_level = acrtc_state->abm_level;
 
-               if (false == commit_planes_to_stream(dm->dc,
+               if (false == commit_planes_to_stream(dm,
+                                                       dm->dc,
                                                        plane_states_constructed,
                                                        planes_count,
                                                        acrtc_state,
                                                        dm_old_crtc_state,
-                                                       dm_state->context))
+                                                       dc_state))
                        dm_error("%s: Failed to attach plane!\n", __func__);
        } else {
                /*TODO BUG Here should go disable planes on CRTC. */
@@ -4549,12 +4894,21 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
        /*TODO Handle EINTR, reenable IRQ*/
 }
 
+/**
+ * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
+ * @state: The atomic state to commit
+ *
+ * This will tell DC to commit the constructed DC state from atomic_check,
+ * programming the hardware. Any failures here implies a hardware failure, since
+ * atomic check should have filtered anything non-kosher.
+ */
 static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_display_manager *dm = &adev->dm;
        struct dm_atomic_state *dm_state;
+       struct dc_state *dc_state = NULL, *dc_state_temp = NULL;
        uint32_t i, j;
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
@@ -4567,7 +4921,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_update_legacy_modeset_state(dev, state);
 
-       dm_state = to_dm_atomic_state(state);
+       dm_state = dm_atomic_get_new_state(state);
+       if (dm_state && dm_state->context) {
+               dc_state = dm_state->context;
+       } else {
+               /* No state changes, retain current state. */
+               dc_state_temp = dc_create_state();
+               ASSERT(dc_state_temp);
+               dc_state = dc_state_temp;
+               dc_resource_state_copy_construct_current(dm->dc, dc_state);
+       }
 
        /* update changed items */
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -4640,9 +5003,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                }
        } /* for_each_crtc_in_state() */
 
-       if (dm_state->context) {
-               dm_enable_per_frame_crtc_master_sync(dm_state->context);
-               WARN_ON(!dc_commit_state(dm->dc, dm_state->context));
+       if (dc_state) {
+               dm_enable_per_frame_crtc_master_sync(dc_state);
+               mutex_lock(&dm->dc_lock);
+               WARN_ON(!dc_commit_state(dm->dc, dc_state));
+               mutex_unlock(&dm->dc_lock);
        }
 
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
@@ -4654,6 +5019,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                        const struct dc_stream_status *status =
                                        dc_stream_get_status(dm_new_crtc_state->stream);
 
+                       if (!status)
+                               status = dc_state_get_stream_status(dc_state,
+                                                                   dm_new_crtc_state->stream);
+
                        if (!status)
                                DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);
                        else
@@ -4661,7 +5030,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                }
        }
 
-       /* Handle scaling and underscan changes*/
+       /* Handle scaling, underscan, and abm changes*/
        for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
                struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
                struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
@@ -4677,11 +5046,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state))
                        continue;
 
-               /* Skip anything that is not scaling or underscan changes */
-               if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
-                       continue;
 
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+               /* Skip anything that is not scaling or underscan changes */
+               if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) &&
+                               (dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level))
+                       continue;
 
                update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
                                dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
@@ -4693,17 +5065,17 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                WARN_ON(!status);
                WARN_ON(!status->plane_count);
 
-               dm_new_crtc_state->stream->adjust = dm_new_crtc_state->adjust;
-               dm_new_crtc_state->stream->vrr_infopacket = dm_new_crtc_state->vrr_infopacket;
+               dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level;
 
                /*TODO How it works with MPO ?*/
                if (!commit_planes_to_stream(
+                               dm,
                                dm->dc,
                                status->plane_states,
                                status->plane_count,
                                dm_new_crtc_state,
                                to_dm_crtc_state(old_crtc_state),
-                               dm_state->context))
+                               dc_state))
                        dm_error("%s: Failed to update stream scaling!\n", __func__);
        }
 
@@ -4736,7 +5108,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
 
                if (dm_new_crtc_state->stream)
-                       amdgpu_dm_commit_planes(state, dev, dm, crtc, &wait_for_vblank);
+                       amdgpu_dm_commit_planes(state, dc_state, dev,
+                                               dm, crtc, &wait_for_vblank);
        }
 
 
@@ -4776,6 +5149,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
        for (i = 0; i < crtc_disable_count; i++)
                pm_runtime_put_autosuspend(dev->dev);
        pm_runtime_mark_last_busy(dev->dev);
+
+       if (dc_state_temp)
+               dc_release_state(dc_state_temp);
 }
 
 
@@ -4919,20 +5295,18 @@ static int do_aquire_global_lock(struct drm_device *dev,
        return ret < 0 ? ret : 0;
 }
 
-void set_freesync_on_stream(struct amdgpu_display_manager *dm,
-                           struct dm_crtc_state *new_crtc_state,
-                           struct dm_connector_state *new_con_state,
-                           struct dc_stream_state *new_stream)
+static void get_freesync_config_for_crtc(
+       struct dm_crtc_state *new_crtc_state,
+       struct dm_connector_state *new_con_state)
 {
        struct mod_freesync_config config = {0};
-       struct mod_vrr_params vrr = {0};
-       struct dc_info_packet vrr_infopacket = {0};
        struct amdgpu_dm_connector *aconnector =
                        to_amdgpu_dm_connector(new_con_state->base.connector);
 
-       if (new_con_state->freesync_capable &&
-           new_con_state->freesync_enable) {
-               config.state = new_crtc_state->freesync_enabled ?
+       new_crtc_state->vrr_supported = new_con_state->freesync_capable;
+
+       if (new_con_state->freesync_capable) {
+               config.state = new_crtc_state->base.vrr_enabled ?
                                VRR_STATE_ACTIVE_VARIABLE :
                                VRR_STATE_INACTIVE;
                config.min_refresh_in_uhz =
@@ -4942,19 +5316,18 @@ void set_freesync_on_stream(struct amdgpu_display_manager *dm,
                config.vsif_supported = true;
        }
 
-       mod_freesync_build_vrr_params(dm->freesync_module,
-                                     new_stream,
-                                     &config, &vrr);
+       new_crtc_state->freesync_config = config;
+}
 
-       mod_freesync_build_vrr_infopacket(dm->freesync_module,
-                                         new_stream,
-                                         &vrr,
-                                         packet_type_fs1,
-                                         NULL,
-                                         &vrr_infopacket);
+static void reset_freesync_config_for_crtc(
+       struct dm_crtc_state *new_crtc_state)
+{
+       new_crtc_state->vrr_supported = false;
 
-       new_crtc_state->adjust = vrr.adjust;
-       new_crtc_state->vrr_infopacket = vrr_infopacket;
+       memset(&new_crtc_state->adjust, 0,
+              sizeof(new_crtc_state->adjust));
+       memset(&new_crtc_state->vrr_infopacket, 0,
+              sizeof(new_crtc_state->vrr_infopacket));
 }
 
 static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
@@ -4962,11 +5335,11 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                                 bool enable,
                                 bool *lock_and_validation_needed)
 {
+       struct dm_atomic_state *dm_state = NULL;
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
        int i;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
        struct dc_stream_state *new_stream;
        int ret = 0;
 
@@ -5014,7 +5387,8 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
 
                        new_stream = create_stream_for_sink(aconnector,
                                                             &new_crtc_state->mode,
-                                                           dm_new_conn_state);
+                                                           dm_new_conn_state,
+                                                           dm_old_crtc_state->stream);
 
                        /*
                         * we can have no stream on ACTION_SET if a display
@@ -5029,8 +5403,7 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                                break;
                        }
 
-                       set_freesync_on_stream(dm, dm_new_crtc_state,
-                                              dm_new_conn_state, new_stream);
+                       dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
 
                        if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
                            dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
@@ -5040,9 +5413,6 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                        }
                }
 
-               if (dm_old_crtc_state->freesync_enabled != dm_new_crtc_state->freesync_enabled)
-                       new_crtc_state->mode_changed = true;
-
                if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
                        goto next_crtc;
 
@@ -5064,6 +5434,10 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                        if (!dm_old_crtc_state->stream)
                                goto next_crtc;
 
+                       ret = dm_atomic_get_state(state, &dm_state);
+                       if (ret)
+                               goto fail;
+
                        DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n",
                                        crtc->base.id);
 
@@ -5079,6 +5453,8 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                        dc_stream_release(dm_old_crtc_state->stream);
                        dm_new_crtc_state->stream = NULL;
 
+                       reset_freesync_config_for_crtc(dm_new_crtc_state);
+
                        *lock_and_validation_needed = true;
 
                } else {/* Add stream for any updated/enabled CRTC */
@@ -5098,6 +5474,10 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
 
                                WARN_ON(dm_new_crtc_state->stream);
 
+                               ret = dm_atomic_get_state(state, &dm_state);
+                               if (ret)
+                                       goto fail;
+
                                dm_new_crtc_state->stream = new_stream;
 
                                dc_stream_retain(new_stream);
@@ -5156,7 +5536,9 @@ next_crtc:
                        amdgpu_dm_set_ctm(dm_new_crtc_state);
                }
 
-
+               /* Update Freesync settings. */
+               get_freesync_config_for_crtc(dm_new_crtc_state,
+                                            dm_new_conn_state);
        }
 
        return ret;
@@ -5172,12 +5554,13 @@ static int dm_update_planes_state(struct dc *dc,
                                  bool enable,
                                  bool *lock_and_validation_needed)
 {
+
+       struct dm_atomic_state *dm_state = NULL;
        struct drm_crtc *new_plane_crtc, *old_plane_crtc;
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
        struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
        int i ;
        /* TODO return page_flip_needed() function */
@@ -5215,6 +5598,10 @@ static int dm_update_planes_state(struct dc *dc,
                        DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n",
                                        plane->base.id, old_plane_crtc->base.id);
 
+                       ret = dm_atomic_get_state(state, &dm_state);
+                       if (ret)
+                               return ret;
+
                        if (!dc_remove_plane_from_context(
                                        dc,
                                        dm_old_crtc_state->stream,
@@ -5269,6 +5656,12 @@ static int dm_update_planes_state(struct dc *dc,
                                return ret;
                        }
 
+                       ret = dm_atomic_get_state(state, &dm_state);
+                       if (ret) {
+                               dc_plane_state_release(dc_new_plane_state);
+                               return ret;
+                       }
+
                        /*
                         * Any atomic check errors that occur after this will
                         * not need a release. The plane state will be attached
@@ -5300,11 +5693,14 @@ static int dm_update_planes_state(struct dc *dc,
 
        return ret;
 }
-enum surface_update_type dm_determine_update_type_for_commit(struct dc *dc, struct drm_atomic_state *state)
-{
 
-
-       int i, j, num_plane;
+static int
+dm_determine_update_type_for_commit(struct dc *dc,
+                                   struct drm_atomic_state *state,
+                                   enum surface_update_type *out_type)
+{
+       struct dm_atomic_state *dm_state = NULL, *old_dm_state = NULL;
+       int i, j, num_plane, ret = 0;
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct dm_plane_state *new_dm_plane_state, *old_dm_plane_state;
        struct drm_crtc *new_plane_crtc, *old_plane_crtc;
@@ -5320,6 +5716,12 @@ enum surface_update_type dm_determine_update_type_for_commit(struct dc *dc, stru
        struct dc_stream_update stream_update;
        enum surface_update_type update_type = UPDATE_TYPE_FAST;
 
+       if (!updates || !surface) {
+               DRM_ERROR("Plane or surface update failed to allocate");
+               /* Set type to FULL to avoid crashing in DC*/
+               update_type = UPDATE_TYPE_FULL;
+               goto cleanup;
+       }
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
@@ -5372,35 +5774,73 @@ enum surface_update_type dm_determine_update_type_for_commit(struct dc *dc, stru
                        }
 
                        if (num_plane > 0) {
-                               status = dc_stream_get_status(new_dm_crtc_state->stream);
+                               ret = dm_atomic_get_state(state, &dm_state);
+                               if (ret)
+                                       goto cleanup;
+
+                               old_dm_state = dm_atomic_get_old_state(state);
+                               if (!old_dm_state) {
+                                       ret = -EINVAL;
+                                       goto cleanup;
+                               }
+
+                               status = dc_state_get_stream_status(old_dm_state->context,
+                                                                   new_dm_crtc_state->stream);
+
                                update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane,
                                                                                  &stream_update, status);
 
                                if (update_type > UPDATE_TYPE_MED) {
                                        update_type = UPDATE_TYPE_FULL;
-                                       goto ret;
+                                       goto cleanup;
                                }
                        }
 
                } else if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) {
                        update_type = UPDATE_TYPE_FULL;
-                       goto ret;
+                       goto cleanup;
                }
        }
 
-ret:
+cleanup:
        kfree(updates);
        kfree(surface);
 
-       return update_type;
+       *out_type = update_type;
+       return ret;
 }
 
+/**
+ * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
+ * @dev: The DRM device
+ * @state: The atomic state to commit
+ *
+ * Validate that the given atomic state is programmable by DC into hardware.
+ * This involves constructing a &struct dc_state reflecting the new hardware
+ * state we wish to commit, then querying DC to see if it is programmable. It's
+ * important not to modify the existing DC state. Otherwise, atomic_check
+ * may unexpectedly commit hardware changes.
+ *
+ * When validating the DC state, it's important that the right locks are
+ * acquired. For full updates case which removes/adds/updates streams on one
+ * CRTC while flipping on another CRTC, acquiring global lock will guarantee
+ * that any such full update commit will wait for completion of any outstanding
+ * flip using DRMs synchronization events. See
+ * dm_determine_update_type_for_commit()
+ *
+ * Note that DM adds the affected connectors for all CRTCs in state, when that
+ * might not seem necessary. This is because DC stream creation requires the
+ * DC sink, which is tied to the DRM connector state. Cleaning this up should
+ * be possible but non-trivial - a possible TODO item.
+ *
+ * Return: -Error code if validation failed.
+ */
 static int amdgpu_dm_atomic_check(struct drm_device *dev,
                                  struct drm_atomic_state *state)
 {
        struct amdgpu_device *adev = dev->dev_private;
+       struct dm_atomic_state *dm_state = NULL;
        struct dc *dc = adev->dm.dc;
-       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
        struct drm_connector *connector;
        struct drm_connector_state *old_con_state, *new_con_state;
        struct drm_crtc *crtc;
@@ -5421,12 +5861,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                goto fail;
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
-               struct dm_crtc_state *dm_old_crtc_state  = to_dm_crtc_state(old_crtc_state);
-
                if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
                    !new_crtc_state->color_mgmt_changed &&
-                   (dm_old_crtc_state->freesync_enabled == dm_new_crtc_state->freesync_enabled))
+                   !new_crtc_state->vrr_enabled)
                        continue;
 
                if (!new_crtc_state->enable)
@@ -5441,10 +5878,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                        goto fail;
        }
 
-       dm_state->context = dc_create_state();
-       ASSERT(dm_state->context);
-       dc_resource_state_copy_construct_current(dc, dm_state->context);
-
        /* Remove exiting planes if they are modified */
        ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed);
        if (ret) {
@@ -5497,16 +5930,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                lock_and_validation_needed = true;
        }
 
-       /*
-        * For full updates case when
-        * removing/adding/updating streams on one CRTC while flipping
-        * on another CRTC,
-        * acquiring global lock  will guarantee that any such full
-        * update commit
-        * will wait for completion of any outstanding flip using DRMs
-        * synchronization events.
-        */
-       update_type = dm_determine_update_type_for_commit(dc, state);
+       ret = dm_determine_update_type_for_commit(dc, state, &update_type);
+       if (ret)
+               goto fail;
 
        if (overall_update_type < update_type)
                overall_update_type = update_type;
@@ -5524,6 +5950,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 
 
        if (overall_update_type > UPDATE_TYPE_FAST) {
+               ret = dm_atomic_get_state(state, &dm_state);
+               if (ret)
+                       goto fail;
 
                ret = do_aquire_global_lock(dev, state);
                if (ret)
@@ -5533,6 +5962,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                        ret = -EINVAL;
                        goto fail;
                }
+       } else if (state->legacy_cursor_update) {
+               /*
+                * This is a fast cursor update coming from the plane update
+                * helper, check if it can be done asynchronously for better
+                * performance.
+                */
+               state->async_update = !drm_atomic_helper_async_check(dev, state);
        }
 
        /* Must be success */
@@ -5578,14 +6014,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
        struct detailed_data_monitor_range *range;
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                        to_amdgpu_dm_connector(connector);
-       struct dm_connector_state *dm_con_state;
+       struct dm_connector_state *dm_con_state = NULL;
 
        struct drm_device *dev = connector->dev;
        struct amdgpu_device *adev = dev->dev_private;
+       bool freesync_capable = false;
 
        if (!connector->state) {
                DRM_ERROR("%s - Connector has no state", __func__);
-               return;
+               goto update;
        }
 
        if (!edid) {
@@ -5595,9 +6032,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
                amdgpu_dm_connector->max_vfreq = 0;
                amdgpu_dm_connector->pixel_clock_mhz = 0;
 
-               dm_con_state->freesync_capable = false;
-               dm_con_state->freesync_enable = false;
-               return;
+               goto update;
        }
 
        dm_con_state = to_dm_connector_state(connector->state);
@@ -5605,10 +6040,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
        edid_check_required = false;
        if (!amdgpu_dm_connector->dc_sink) {
                DRM_ERROR("dc_sink NULL, could not add free_sync module.\n");
-               return;
+               goto update;
        }
        if (!adev->dm.freesync_module)
-               return;
+               goto update;
        /*
         * if edid non zero restrict freesync only for dp and edp
         */
@@ -5620,7 +6055,6 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
                                                amdgpu_dm_connector);
                }
        }
-       dm_con_state->freesync_capable = false;
        if (edid_check_required == true && (edid->version > 1 ||
           (edid->version == 1 && edid->revision > 1))) {
                for (i = 0; i < 4; i++) {
@@ -5652,8 +6086,16 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
                if (amdgpu_dm_connector->max_vfreq -
                    amdgpu_dm_connector->min_vfreq > 10) {
 
-                       dm_con_state->freesync_capable = true;
+                       freesync_capable = true;
                }
        }
+
+update:
+       if (dm_con_state)
+               dm_con_state->freesync_capable = freesync_capable;
+
+       if (connector->vrr_capable_property)
+               drm_connector_set_vrr_capable_property(connector,
+                                                      freesync_capable);
 }
 
index 6e069d777ab22d0e733bb7bc1c62d3d3370cc265..25bb91ee80ba4b4b9e402ba58d75eb82a9d13458 100644 (file)
@@ -59,60 +59,140 @@ struct common_irq_params {
        enum dc_irq_source irq_src;
 };
 
+/**
+ * struct irq_list_head - Linked-list for low context IRQ handlers.
+ *
+ * @head: The list_head within &struct handler_data
+ * @work: A work_struct containing the deferred handler work
+ */
 struct irq_list_head {
        struct list_head head;
        /* In case this interrupt needs post-processing, 'work' will be queued*/
        struct work_struct work;
 };
 
+/**
+ * struct dm_compressor_info - Buffer info used by frame buffer compression
+ * @cpu_addr: MMIO cpu addr
+ * @bo_ptr: Pointer to the buffer object
+ * @gpu_addr: MMIO gpu addr
+ */
 struct dm_comressor_info {
        void *cpu_addr;
        struct amdgpu_bo *bo_ptr;
        uint64_t gpu_addr;
 };
 
+/**
+ * struct amdgpu_dm_backlight_caps - Usable range of backlight values from ACPI
+ * @min_input_signal: minimum possible input in range 0-255
+ * @max_input_signal: maximum possible input in range 0-255
+ * @caps_valid: true if these values are from the ACPI interface
+ */
+struct amdgpu_dm_backlight_caps {
+       int min_input_signal;
+       int max_input_signal;
+       bool caps_valid;
+};
+
+/**
+ * struct amdgpu_display_manager - Central amdgpu display manager device
+ *
+ * @dc: Display Core control structure
+ * @adev: AMDGPU base driver structure
+ * @ddev: DRM base driver structure
+ * @display_indexes_num: Max number of display streams supported
+ * @irq_handler_list_table_lock: Synchronizes access to IRQ tables
+ * @backlight_dev: Backlight control device
+ * @cached_state: Caches device atomic state for suspend/resume
+ * @compressor: Frame buffer compression buffer. See &struct dm_comressor_info
+ */
 struct amdgpu_display_manager {
+
        struct dc *dc;
+
+       /**
+        * @cgs_device:
+        *
+        * The Common Graphics Services device. It provides an interface for
+        * accessing registers.
+        */
        struct cgs_device *cgs_device;
 
-       struct amdgpu_device *adev;     /*AMD base driver*/
-       struct drm_device *ddev;        /*DRM base driver*/
+       struct amdgpu_device *adev;
+       struct drm_device *ddev;
        u16 display_indexes_num;
 
-       /*
-        * 'irq_source_handler_table' holds a list of handlers
-        * per (DAL) IRQ source.
+       /**
+        * @atomic_obj
+        *
+        * In combination with &dm_atomic_state it helps manage
+        * global atomic state that doesn't map cleanly into existing
+        * drm resources, like &dc_context.
+        */
+       struct drm_private_obj atomic_obj;
+
+       struct drm_modeset_lock atomic_obj_lock;
+
+       /**
+        * @dc_lock:
+        *
+        * Guards access to DC functions that can issue register write
+        * sequences.
+        */
+       struct mutex dc_lock;
+
+       /**
+        * @irq_handler_list_low_tab:
+        *
+        * Low priority IRQ handler table.
         *
-        * Each IRQ source may need to be handled at different contexts.
-        * By 'context' we mean, for example:
-        * - The ISR context, which is the direct interrupt handler.
-        * - The 'deferred' context - this is the post-processing of the
-        *      interrupt, but at a lower priority.
+        * It is a n*m table consisting of n IRQ sources, and m handlers per IRQ
+        * source. Low priority IRQ handlers are deferred to a workqueue to be
+        * processed. Hence, they can sleep.
         *
         * Note that handlers are called in the same order as they were
         * registered (FIFO).
         */
        struct irq_list_head irq_handler_list_low_tab[DAL_IRQ_SOURCES_NUMBER];
+
+       /**
+        * @irq_handler_list_high_tab:
+        *
+        * High priority IRQ handler table.
+        *
+        * It is a n*m table, same as &irq_handler_list_low_tab. However,
+        * handlers in this table are not deferred and are called immediately.
+        */
        struct list_head irq_handler_list_high_tab[DAL_IRQ_SOURCES_NUMBER];
 
+       /**
+        * @pflip_params:
+        *
+        * Page flip IRQ parameters, passed to registered handlers when
+        * triggered.
+        */
        struct common_irq_params
        pflip_params[DC_IRQ_SOURCE_PFLIP_LAST - DC_IRQ_SOURCE_PFLIP_FIRST + 1];
 
+       /**
+        * @vblank_params:
+        *
+        * Vertical blanking IRQ parameters, passed to registered handlers when
+        * triggered.
+        */
        struct common_irq_params
        vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1];
 
-       /* this spin lock synchronizes access to 'irq_handler_list_table' */
        spinlock_t irq_handler_list_table_lock;
 
        struct backlight_device *backlight_dev;
 
        const struct dc_link *backlight_link;
+       struct amdgpu_dm_backlight_caps backlight_caps;
 
        struct mod_freesync *freesync_module;
 
-       /**
-        * Caches device atomic state for suspend/resume
-        */
        struct drm_atomic_state *cached_state;
 
        struct dm_comressor_info compressor;
@@ -183,15 +263,21 @@ struct dm_crtc_state {
        int crc_skip_count;
        bool crc_enabled;
 
-       bool freesync_enabled;
+       bool freesync_timing_changed;
+       bool freesync_vrr_info_changed;
+
+       bool vrr_supported;
+       struct mod_freesync_config freesync_config;
        struct dc_crtc_timing_adjust adjust;
        struct dc_info_packet vrr_infopacket;
+
+       int abm_level;
 };
 
 #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base)
 
 struct dm_atomic_state {
-       struct drm_atomic_state base;
+       struct drm_private_state base;
 
        struct dc_state *context;
 };
@@ -206,8 +292,8 @@ struct dm_connector_state {
        uint8_t underscan_hborder;
        uint8_t max_bpc;
        bool underscan_enable;
-       bool freesync_enable;
        bool freesync_capable;
+       uint8_t abm_level;
 };
 
 #define to_dm_connector_state(x)\
index be19e6861189c63e0fe85d16ad1a2bedc14cf58c..216e48cec71664f67eb7325b3dd0fc876d228a6a 100644 (file)
@@ -164,7 +164,7 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
         */
        stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
        ret = mod_color_calculate_regamma_params(stream->out_transfer_func,
-                                                gamma, true, adev->asic_type <= CHIP_RAVEN);
+                                                gamma, true, adev->asic_type <= CHIP_RAVEN, NULL);
        dc_gamma_release(&gamma);
        if (!ret) {
                stream->out_transfer_func->type = old_type;
index 01fc5717b657fb73ecb5b5d41ca03d511ba358a3..f088ac58597803d3c257ccdeaea656eb0dfd723f 100644 (file)
@@ -75,6 +75,11 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
                return -EINVAL;
        }
 
+       if (!stream_state) {
+               DRM_ERROR("No stream state for CRTC%d\n", crtc->index);
+               return -EINVAL;
+       }
+
        /* When enabling CRC, we should also disable dithering. */
        if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) {
                if (dc_stream_configure_crc(stream_state->ctx->dc,
index a212178f2edc21906e0609cdcc9d7a836bbee8b3..cd10f77cdeb062f57d646400d1ce63a23771cd59 100644 (file)
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_irq.h"
 
+/**
+ * DOC: overview
+ *
+ * DM provides another layer of IRQ management on top of what the base driver
+ * already provides. This is something that could be cleaned up, and is a
+ * future TODO item.
+ *
+ * The base driver provides IRQ source registration with DRM, handler
+ * registration into the base driver's IRQ table, and a handler callback
+ * amdgpu_irq_handler(), with which DRM calls on interrupts. This generic
+ * handler looks up the IRQ table, and calls the respective
+ * &amdgpu_irq_src_funcs.process hookups.
+ *
+ * What DM provides on top are two IRQ tables specifically for top-half and
+ * bottom-half IRQ handling, with the bottom-half implementing workqueues:
+ *
+ * - &amdgpu_display_manager.irq_handler_list_high_tab
+ * - &amdgpu_display_manager.irq_handler_list_low_tab
+ *
+ * They override the base driver's IRQ table, and the effect can be seen
+ * in the hooks that DM provides for &amdgpu_irq_src_funcs.process. They
+ * are all set to the DM generic handler amdgpu_dm_irq_handler(), which looks up
+ * DM's IRQ tables. However, in order for base driver to recognize this hook, DM
+ * still needs to register the IRQ with the base driver. See
+ * dce110_register_irq_handlers() and dcn10_register_irq_handlers().
+ *
+ * To expose DC's hardware interrupt toggle to the base driver, DM implements
+ * &amdgpu_irq_src_funcs.set hooks. Base driver calls it through
+ * amdgpu_irq_update() to enable or disable the interrupt.
+ */
+
 /******************************************************************************
  * Private declarations.
  *****************************************************************************/
 
+/**
+ * struct amdgpu_dm_irq_handler_data - Data for DM interrupt handlers.
+ *
+ * @list: Linked list entry referencing the next/previous handler
+ * @handler: Handler function
+ * @handler_arg: Argument passed to the handler when triggered
+ * @dm: DM which this handler belongs to
+ * @irq_source: DC interrupt source that this handler is registered for
+ */
 struct amdgpu_dm_irq_handler_data {
        struct list_head list;
        interrupt_handler handler;
        void *handler_arg;
 
-       /* DM which this handler belongs to */
        struct amdgpu_display_manager *dm;
        /* DAL irq source which registered for this interrupt. */
        enum dc_irq_source irq_source;
@@ -68,7 +107,7 @@ static void init_handler_common_data(struct amdgpu_dm_irq_handler_data *hcd,
 }
 
 /**
- * dm_irq_work_func - Handle an IRQ outside of the interrupt handler proper.
+ * dm_irq_work_func() - Handle an IRQ outside of the interrupt handler proper.
  *
  * @work: work struct
  */
@@ -99,8 +138,8 @@ static void dm_irq_work_func(struct work_struct *work)
         * (The most common use is HPD interrupt) */
 }
 
-/**
- * Remove a handler and return a pointer to hander list from which the
+/*
+ * Remove a handler and return a pointer to handler list from which the
  * handler was removed.
  */
 static struct list_head *remove_irq_handler(struct amdgpu_device *adev,
@@ -203,6 +242,24 @@ static bool validate_irq_unregistration_params(enum dc_irq_source irq_source,
  * Note: caller is responsible for input validation.
  *****************************************************************************/
 
+/**
+ * amdgpu_dm_irq_register_interrupt() - Register a handler within DM.
+ * @adev: The base driver device containing the DM device.
+ * @int_params: Interrupt parameters containing the source, and handler context
+ * @ih: Function pointer to the interrupt handler to register
+ * @handler_args: Arguments passed to the handler when the interrupt occurs
+ *
+ * Register an interrupt handler for the given IRQ source, under the given
+ * context. The context can either be high or low. High context handlers are
+ * executed directly within ISR context, while low context is executed within a
+ * workqueue, thereby allowing operations that sleep.
+ *
+ * Registered handlers are called in a FIFO manner, i.e. the most recently
+ * registered handler will be called first.
+ *
+ * Return: Handler data &struct amdgpu_dm_irq_handler_data containing the IRQ
+ *         source, handler function, and args
+ */
 void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev,
                                       struct dc_interrupt_params *int_params,
                                       void (*ih)(void *),
@@ -261,6 +318,15 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev,
        return handler_data;
 }
 
+/**
+ * amdgpu_dm_irq_unregister_interrupt() - Remove a handler from the DM IRQ table
+ * @adev: The base driver device containing the DM device
+ * @irq_source: IRQ source to remove the given handler from
+ * @ih: Function pointer to the interrupt handler to unregister
+ *
+ * Go through both low and high context IRQ tables, and find the given handler
+ * for the given irq source. If found, remove it. Otherwise, do nothing.
+ */
 void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
                                        enum dc_irq_source irq_source,
                                        void *ih)
@@ -295,6 +361,20 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
        }
 }
 
+/**
+ * amdgpu_dm_irq_init() - Initialize DM IRQ management
+ * @adev:  The base driver device containing the DM device
+ *
+ * Initialize DM's high and low context IRQ tables.
+ *
+ * The N by M table contains N IRQ sources, with M
+ * &struct amdgpu_dm_irq_handler_data hooked together in a linked list. The
+ * list_heads are initialized here. When an interrupt n is triggered, all m
+ * handlers are called in sequence, FIFO according to registration order.
+ *
+ * The low context table requires special steps to initialize, since handlers
+ * will be deferred to a workqueue. See &struct irq_list_head.
+ */
 int amdgpu_dm_irq_init(struct amdgpu_device *adev)
 {
        int src;
@@ -317,7 +397,12 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
        return 0;
 }
 
-/* DM IRQ and timer resource release */
+/**
+ * amdgpu_dm_irq_fini() - Tear down DM IRQ management
+ * @adev: The base driver device containing the DM device
+ *
+ * Flush all work within the low context IRQ table.
+ */
 void amdgpu_dm_irq_fini(struct amdgpu_device *adev)
 {
        int src;
@@ -414,7 +499,7 @@ int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
        return 0;
 }
 
-/**
+/*
  * amdgpu_dm_irq_schedule_work - schedule all work items registered for the
  * "irq_source".
  */
@@ -439,8 +524,9 @@ static void amdgpu_dm_irq_schedule_work(struct amdgpu_device *adev,
 
 }
 
-/** amdgpu_dm_irq_immediate_work
- *  Callback high irq work immediately, don't send to work queue
+/*
+ * amdgpu_dm_irq_immediate_work
+ * Callback high irq work immediately, don't send to work queue
  */
 static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
                                         enum dc_irq_source irq_source)
@@ -467,11 +553,14 @@ static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
        DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
 }
 
-/*
- * amdgpu_dm_irq_handler
+/**
+ * amdgpu_dm_irq_handler - Generic DM IRQ handler
+ * @adev: amdgpu base driver device containing the DM device
+ * @source: Unused
+ * @entry: Data about the triggered interrupt
  *
- * Generic IRQ handler, calls all registered high irq work immediately, and
- * schedules work for low irq
+ * Calls all registered high irq work immediately, and schedules work for low
+ * irq. The DM IRQ table is used to find the corresponding handlers.
  */
 static int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
                                 struct amdgpu_irq_src *source,
@@ -613,7 +702,7 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
        adev->hpd_irq.funcs = &dm_hpd_irq_funcs;
 }
 
-/*
+/**
  * amdgpu_dm_hpd_init - hpd setup callback.
  *
  * @adev: amdgpu_device pointer
index 12001a006b2d8e1d0b5f3734c189e9faf23d94e5..9d2d6986b98394be67d038f0d0abdff2ef1cef83 100644 (file)
@@ -485,11 +485,11 @@ void pp_rv_set_display_requirement(struct pp_smu *pp,
                return;
 
        clock.clock_type = amd_pp_dcf_clock;
-       clock.clock_freq_in_khz = req->hard_min_dcefclk_khz;
+       clock.clock_freq_in_khz = req->hard_min_dcefclk_mhz * 1000;
        pp_funcs->display_clock_voltage_request(pp_handle, &clock);
 
        clock.clock_type = amd_pp_f_clock;
-       clock.clock_freq_in_khz = req->hard_min_fclk_khz;
+       clock.clock_freq_in_khz = req->hard_min_fclk_mhz * 1000;
        pp_funcs->display_clock_voltage_request(pp_handle, &clock);
 }
 
@@ -518,13 +518,13 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
                        wm_dce_clocks[i].wm_set_id =
                                        ranges->reader_wm_sets[i].wm_inst;
                wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz =
-                               ranges->reader_wm_sets[i].max_drain_clk_khz;
+                               ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000;
                wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz =
-                               ranges->reader_wm_sets[i].min_drain_clk_khz;
+                               ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000;
                wm_dce_clocks[i].wm_max_mem_clk_in_khz =
-                               ranges->reader_wm_sets[i].max_fill_clk_khz;
+                               ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000;
                wm_dce_clocks[i].wm_min_mem_clk_in_khz =
-                               ranges->reader_wm_sets[i].min_fill_clk_khz;
+                               ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000;
        }
 
        for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) {
@@ -534,13 +534,13 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
                        wm_soc_clocks[i].wm_set_id =
                                        ranges->writer_wm_sets[i].wm_inst;
                wm_soc_clocks[i].wm_max_socclk_clk_in_khz =
-                               ranges->writer_wm_sets[i].max_fill_clk_khz;
+                               ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000;
                wm_soc_clocks[i].wm_min_socclk_clk_in_khz =
-                               ranges->writer_wm_sets[i].min_fill_clk_khz;
+                               ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000;
                wm_soc_clocks[i].wm_max_mem_clk_in_khz =
-                               ranges->writer_wm_sets[i].max_drain_clk_khz;
+                               ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000;
                wm_soc_clocks[i].wm_min_mem_clk_in_khz =
-                               ranges->writer_wm_sets[i].min_drain_clk_khz;
+                               ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
        }
 
        pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h
new file mode 100644 (file)
index 0000000..d898981
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM amdgpu_dm
+
+#if !defined(_AMDGPU_DM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _AMDGPU_DM_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(amdgpu_dc_rreg,
+       TP_PROTO(unsigned long *read_count, uint32_t reg, uint32_t value),
+       TP_ARGS(read_count, reg, value),
+       TP_STRUCT__entry(
+                       __field(uint32_t, reg)
+                       __field(uint32_t, value)
+               ),
+       TP_fast_assign(
+                       __entry->reg = reg;
+                       __entry->value = value;
+                       *read_count = *read_count + 1;
+               ),
+       TP_printk("reg=0x%08lx, value=0x%08lx",
+                       (unsigned long)__entry->reg,
+                       (unsigned long)__entry->value)
+);
+
+TRACE_EVENT(amdgpu_dc_wreg,
+       TP_PROTO(unsigned long *write_count, uint32_t reg, uint32_t value),
+       TP_ARGS(write_count, reg, value),
+       TP_STRUCT__entry(
+                       __field(uint32_t, reg)
+                       __field(uint32_t, value)
+               ),
+       TP_fast_assign(
+                       __entry->reg = reg;
+                       __entry->value = value;
+                       *write_count = *write_count + 1;
+               ),
+       TP_printk("reg=0x%08lx, value=0x%08lx",
+                       (unsigned long)__entry->reg,
+                       (unsigned long)__entry->value)
+);
+
+
+TRACE_EVENT(amdgpu_dc_performance,
+       TP_PROTO(unsigned long read_count, unsigned long write_count,
+               unsigned long *last_read, unsigned long *last_write,
+               const char *func, unsigned int line),
+       TP_ARGS(read_count, write_count, last_read, last_write, func, line),
+       TP_STRUCT__entry(
+                       __field(uint32_t, reads)
+                       __field(uint32_t, writes)
+                       __field(uint32_t, read_delta)
+                       __field(uint32_t, write_delta)
+                       __string(func, func)
+                       __field(uint32_t, line)
+                       ),
+       TP_fast_assign(
+                       __entry->reads = read_count;
+                       __entry->writes = write_count;
+                       __entry->read_delta = read_count - *last_read;
+                       __entry->write_delta = write_count - *last_write;
+                       __assign_str(func, func);
+                       __entry->line = line;
+                       *last_read = read_count;
+                       *last_write = write_count;
+                       ),
+       TP_printk("%s:%d reads=%08ld (%08ld total), writes=%08ld (%08ld total)",
+                       __get_str(func), __entry->line,
+                       (unsigned long)__entry->read_delta,
+                       (unsigned long)__entry->reads,
+                       (unsigned long)__entry->write_delta,
+                       (unsigned long)__entry->writes)
+);
+#endif /* _AMDGPU_DM_TRACE_H_ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE amdgpu_dm_trace
+#include <trace/define_trace.h>
index 0e1dc1b1a48d9af59129e207d5b6ca1a1baf11c8..c2ab026aee91f31d22970d29c169f61ef0eff8a0 100644 (file)
@@ -2030,7 +2030,7 @@ static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
 static struct device_id device_type_from_device_id(uint16_t device_id)
 {
 
-       struct device_id result_device_id;
+       struct device_id result_device_id = {0};
 
        switch (device_id) {
        case ATOM_DEVICE_LCD1_SUPPORT:
index ff764da21b6ffd9cbf2a86e7543e8e09069189bf..751bb614fc0eae6b8b26647bc4f31b0893562431 100644 (file)
@@ -1884,6 +1884,8 @@ static const struct dc_vbios_funcs vbios_funcs = {
 
        .is_accelerated_mode = bios_parser_is_accelerated_mode,
 
+       .is_active_display = bios_is_active_display,
+
        .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
 
 
index d4589470985c72cc5d649ad9e615c815ee0ceda7..fdda8aa8e3031f7f667da7e931d34de8f849f847 100644 (file)
@@ -88,3 +88,96 @@ uint32_t bios_get_vga_enabled_displays(
        return active_disp;
 }
 
+bool bios_is_active_display(
+               struct dc_bios *bios,
+               enum signal_type signal,
+               const struct connector_device_tag_info *device_tag)
+{
+       uint32_t active = 0;
+       uint32_t connected = 0;
+       uint32_t bios_scratch_0 = 0;
+       uint32_t bios_scratch_3 = 0;
+
+       switch (signal) {
+       case SIGNAL_TYPE_DVI_SINGLE_LINK:
+       case SIGNAL_TYPE_DVI_DUAL_LINK:
+       case SIGNAL_TYPE_HDMI_TYPE_A:
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+               {
+                       if (device_tag->dev_id.device_type == DEVICE_TYPE_DFP) {
+                               switch (device_tag->dev_id.enum_id)     {
+                               case 1:
+                                       {
+                                               active    = ATOM_S3_DFP1_ACTIVE;
+                                               connected = 0x0008;     //ATOM_DISPLAY_DFP1_CONNECT
+                                       }
+                                       break;
+
+                               case 2:
+                                       {
+                                               active    = ATOM_S3_DFP2_ACTIVE;
+                                               connected = 0x0080; //ATOM_DISPLAY_DFP2_CONNECT
+                                       }
+                                       break;
+
+                               case 3:
+                                       {
+                                               active    = ATOM_S3_DFP3_ACTIVE;
+                                               connected = 0x0200; //ATOM_DISPLAY_DFP3_CONNECT
+                                       }
+                                       break;
+
+                               case 4:
+                                       {
+                                               active    = ATOM_S3_DFP4_ACTIVE;
+                                               connected = 0x0400;     //ATOM_DISPLAY_DFP4_CONNECT
+                                       }
+                                       break;
+
+                               case 5:
+                                       {
+                                               active    = ATOM_S3_DFP5_ACTIVE;
+                                               connected = 0x0800; //ATOM_DISPLAY_DFP5_CONNECT
+                                       }
+                                       break;
+
+                               case 6:
+                                       {
+                                               active    = ATOM_S3_DFP6_ACTIVE;
+                                               connected = 0x0040; //ATOM_DISPLAY_DFP6_CONNECT
+                                       }
+                                       break;
+
+                               default:
+                                       break;
+                               }
+                               }
+                       }
+                       break;
+
+       case SIGNAL_TYPE_LVDS:
+       case SIGNAL_TYPE_EDP:
+               {
+                       active    = ATOM_S3_LCD1_ACTIVE;
+                       connected = 0x0002;     //ATOM_DISPLAY_LCD1_CONNECT
+               }
+               break;
+
+       default:
+               break;
+       }
+
+
+       if (bios->regs->BIOS_SCRATCH_0) /*follow up with other asic, todo*/
+               bios_scratch_0 = REG_READ(BIOS_SCRATCH_0);
+       if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/
+               bios_scratch_3 = REG_READ(BIOS_SCRATCH_3);
+
+       bios_scratch_3 &= ATOM_S3_DEVICE_ACTIVE_MASK;
+       if ((active & bios_scratch_3) && (connected & bios_scratch_0))
+               return true;
+
+       return false;
+}
+
index 75a29e68fb2782ad667f858b4f235aeccdcc8ace..f33cac2147e32cc182d33aefabc09422be1af28b 100644 (file)
@@ -35,6 +35,10 @@ bool bios_is_accelerated_mode(struct dc_bios *bios);
 void bios_set_scratch_acc_mode_change(struct dc_bios *bios);
 void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
 uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios);
+bool bios_is_active_display(
+       struct dc_bios *bios,
+       enum signal_type signal,
+       const struct connector_device_tag_info *device_tag);
 
 #define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
 
index 3208188b7ed48208ec97c1d391e8637270bd693d..43e4a2be0fa677f9630799826c3fcb2b6adae477 100644 (file)
@@ -1423,27 +1423,27 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
        ranges.num_reader_wm_sets = WM_SET_COUNT;
        ranges.num_writer_wm_sets = WM_SET_COUNT;
        ranges.reader_wm_sets[0].wm_inst = WM_A;
-       ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz;
-       ranges.reader_wm_sets[0].max_drain_clk_khz = overdrive;
-       ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz;
-       ranges.reader_wm_sets[0].max_fill_clk_khz = overdrive;
+       ranges.reader_wm_sets[0].min_drain_clk_mhz = min_dcfclk_khz / 1000;
+       ranges.reader_wm_sets[0].max_drain_clk_mhz = overdrive / 1000;
+       ranges.reader_wm_sets[0].min_fill_clk_mhz = min_fclk_khz / 1000;
+       ranges.reader_wm_sets[0].max_fill_clk_mhz = overdrive / 1000;
        ranges.writer_wm_sets[0].wm_inst = WM_A;
-       ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz;
-       ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive;
-       ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz;
-       ranges.writer_wm_sets[0].max_drain_clk_khz = overdrive;
+       ranges.writer_wm_sets[0].min_fill_clk_mhz = socclk_khz / 1000;
+       ranges.writer_wm_sets[0].max_fill_clk_mhz = overdrive / 1000;
+       ranges.writer_wm_sets[0].min_drain_clk_mhz = min_fclk_khz / 1000;
+       ranges.writer_wm_sets[0].max_drain_clk_mhz = overdrive / 1000;
 
        if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
                ranges.reader_wm_sets[0].wm_inst = WM_A;
-               ranges.reader_wm_sets[0].min_drain_clk_khz = 300000;
-               ranges.reader_wm_sets[0].max_drain_clk_khz = 5000000;
-               ranges.reader_wm_sets[0].min_fill_clk_khz = 800000;
-               ranges.reader_wm_sets[0].max_fill_clk_khz = 5000000;
+               ranges.reader_wm_sets[0].min_drain_clk_mhz = 300;
+               ranges.reader_wm_sets[0].max_drain_clk_mhz = 5000;
+               ranges.reader_wm_sets[0].min_fill_clk_mhz = 800;
+               ranges.reader_wm_sets[0].max_fill_clk_mhz = 5000;
                ranges.writer_wm_sets[0].wm_inst = WM_A;
-               ranges.writer_wm_sets[0].min_fill_clk_khz = 200000;
-               ranges.writer_wm_sets[0].max_fill_clk_khz = 5000000;
-               ranges.writer_wm_sets[0].min_drain_clk_khz = 800000;
-               ranges.writer_wm_sets[0].max_drain_clk_khz = 5000000;
+               ranges.writer_wm_sets[0].min_fill_clk_mhz = 200;
+               ranges.writer_wm_sets[0].max_fill_clk_mhz = 5000;
+               ranges.writer_wm_sets[0].min_drain_clk_mhz = 800;
+               ranges.writer_wm_sets[0].max_drain_clk_mhz = 5000;
        }
 
        ranges.reader_wm_sets[1] = ranges.writer_wm_sets[0];
index 7c491c91465fc5a86973931cd11abe7808f1d8b8..d9c57984394bdceb4640452d5d0bde8a39feeb82 100644 (file)
 
 const static char DC_BUILD_ID[] = "production-build";
 
+/**
+ * DOC: Overview
+ *
+ * DC is the OS-agnostic component of the amdgpu DC driver.
+ *
+ * DC maintains and validates a set of structs representing the state of the
+ * driver and writes that state to AMD hardware
+ *
+ * Main DC HW structs:
+ *
+ * struct dc - The central struct.  One per driver.  Created on driver load,
+ * destroyed on driver unload.
+ *
+ * struct dc_context - One per driver.
+ * Used as a backpointer by most other structs in dc.
+ *
+ * struct dc_link - One per connector (the physical DP, HDMI, miniDP, or eDP
+ * plugpoints).  Created on driver load, destroyed on driver unload.
+ *
+ * struct dc_sink - One per display.  Created on boot or hotplug.
+ * Destroyed on shutdown or hotunplug.  A dc_link can have a local sink
+ * (the display directly attached).  It may also have one or more remote
+ * sinks (in the Multi-Stream Transport case)
+ *
+ * struct resource_pool - One per driver.  Represents the hw blocks not in the
+ * main pipeline.  Not directly accessible by dm.
+ *
+ * Main dc state structs:
+ *
+ * These structs can be created and destroyed as needed.  There is a full set of
+ * these structs in dc->current_state representing the currently programmed state.
+ *
+ * struct dc_state - The global DC state to track global state information,
+ * such as bandwidth values.
+ *
+ * struct dc_stream_state - Represents the hw configuration for the pipeline from
+ * a framebuffer to a display.  Maps one-to-one with dc_sink.
+ *
+ * struct dc_plane_state - Represents a framebuffer.  Each stream has at least one,
+ * and may have more in the Multi-Plane Overlay case.
+ *
+ * struct resource_context - Represents the programmable state of everything in
+ * the resource_pool.  Not directly accessible by dm.
+ *
+ * struct pipe_ctx - A member of struct resource_context.  Represents the
+ * internal hardware pipeline components.  Each dc_plane_state has either
+ * one or two (in the pipe-split case).
+ */
+
 /*******************************************************************************
  * Private functions
  ******************************************************************************/
@@ -175,6 +224,17 @@ failed_alloc:
        return false;
 }
 
+static struct dc_perf_trace *dc_perf_trace_create(void)
+{
+       return kzalloc(sizeof(struct dc_perf_trace), GFP_KERNEL);
+}
+
+static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace)
+{
+       kfree(*perf_trace);
+       *perf_trace = NULL;
+}
+
 /**
  *****************************************************************************
  *  Function: dc_stream_adjust_vmin_vmax
@@ -240,7 +300,7 @@ bool dc_stream_get_crtc_position(struct dc *dc,
 }
 
 /**
- * dc_stream_configure_crc: Configure CRC capture for the given stream.
+ * dc_stream_configure_crc() - Configure CRC capture for the given stream.
  * @dc: DC Object
  * @stream: The stream to configure CRC on.
  * @enable: Enable CRC if true, disable otherwise.
@@ -292,7 +352,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
 }
 
 /**
- * dc_stream_get_crc: Get CRC values for the given stream.
+ * dc_stream_get_crc() - Get CRC values for the given stream.
  * @dc: DC object
  * @stream: The DC stream state of the stream to get CRCs from.
  * @r_cr, g_y, b_cb: CRC values for the three channels are stored here.
@@ -328,7 +388,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream,
                enum dc_dither_option option)
 {
        struct bit_depth_reduction_params params;
-       struct dc_link *link = stream->status.link;
+       struct dc_link *link = stream->sink->link;
        struct pipe_ctx *pipes = NULL;
        int i;
 
@@ -391,9 +451,11 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
                                == stream) {
 
                        pipes = &dc->current_state->res_ctx.pipe_ctx[i];
-                       dc->hwss.program_csc_matrix(pipes,
-                       stream->output_color_space,
-                       stream->csc_color_matrix.matrix);
+                       dc->hwss.program_output_csc(dc,
+                                       pipes,
+                                       stream->output_color_space,
+                                       stream->csc_color_matrix.matrix,
+                                       pipes->plane_res.hubp->opp_id);
                        ret = true;
                }
        }
@@ -534,6 +596,8 @@ static void destruct(struct dc *dc)
        if (dc->ctx->created_bios)
                dal_bios_parser_destroy(&dc->ctx->dc_bios);
 
+       dc_perf_trace_destroy(&dc->ctx->perf_trace);
+
        kfree(dc->ctx);
        dc->ctx = NULL;
 
@@ -657,6 +721,12 @@ static bool construct(struct dc *dc,
                goto fail;
        }
 
+       dc_ctx->perf_trace = dc_perf_trace_create();
+       if (!dc_ctx->perf_trace) {
+               ASSERT_CRITICAL(false);
+               goto fail;
+       }
+
        /* Create GPIO service */
        dc_ctx->gpio_service = dal_gpio_service_create(
                        dc_version,
@@ -941,7 +1011,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        if (!dcb->funcs->is_accelerated_mode(dcb))
                dc->hwss.enable_accelerated_mode(dc, context);
 
-       dc->hwss.set_bandwidth(dc, context, false);
+       dc->hwss.prepare_bandwidth(dc, context);
 
        /* re-program planes for existing stream, in case we need to
         * free up plane resource for later use
@@ -957,8 +1027,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        }
 
        /* Program hardware */
-       dc->hwss.ready_shared_resources(dc, context);
-
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                pipe = &context->res_ctx.pipe_ctx[i];
                dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
@@ -1012,7 +1080,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        dc_enable_stereo(dc, context, dc_streams, context->stream_count);
 
        /* pplib is notified if disp_num changed */
-       dc->hwss.set_bandwidth(dc, context, true);
+       dc->hwss.optimize_bandwidth(dc, context);
 
        dc_release_state(dc->current_state);
 
@@ -1020,8 +1088,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
 
        dc_retain_state(dc->current_state);
 
-       dc->hwss.optimize_shared_resources(dc);
-
        return result;
 }
 
@@ -1063,7 +1129,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
 
        dc->optimized_required = false;
 
-       dc->hwss.set_bandwidth(dc, context, true);
+       dc->hwss.optimize_bandwidth(dc, context);
        return true;
 }
 
@@ -1331,6 +1397,11 @@ static enum surface_update_type check_update_surfaces_for_stream(
        return overall_type;
 }
 
+/**
+ * dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
+ *
+ * See :c:type:`enum surface_update_type <surface_update_type>` for explanation of update types
+ */
 enum surface_update_type dc_check_update_surfaces_for_stream(
                struct dc *dc,
                struct dc_surface_update *updates,
@@ -1369,35 +1440,6 @@ static struct dc_stream_status *stream_get_status(
 
 static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
 
-static void notify_display_count_to_smu(
-               struct dc *dc,
-               struct dc_state *context)
-{
-       int i, display_count;
-       struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
-
-       /*
-        * if function pointer not set up, this message is
-        * sent as part of pplib_apply_display_requirements.
-        * So just return.
-        */
-       if (!pp_smu || !pp_smu->set_display_count)
-               return;
-
-       display_count = 0;
-       for (i = 0; i < context->stream_count; i++) {
-               const struct dc_stream_state *stream = context->streams[i];
-
-               /* only notify active stream */
-               if (stream->dpms_off)
-                       continue;
-
-               display_count++;
-       }
-
-       pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
-}
-
 static void commit_planes_do_stream_update(struct dc *dc,
                struct dc_stream_state *stream,
                struct dc_stream_update *stream_update,
@@ -1422,7 +1464,6 @@ static void commit_planes_do_stream_update(struct dc *dc,
                                        stream_update->adjust->v_total_max);
 
                        if (stream_update->periodic_fn_vsync_delta &&
-                                       pipe_ctx->stream_res.tg &&
                                        pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
                                pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
                                        pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing,
@@ -1441,6 +1482,14 @@ static void commit_planes_do_stream_update(struct dc *dc,
                        if (stream_update->output_csc_transform)
                                dc_stream_program_csc_matrix(dc, stream);
 
+                       if (stream_update->dither_option) {
+                               resource_build_bit_depth_reduction_params(pipe_ctx->stream,
+                                                                       &pipe_ctx->stream->bit_depth_params);
+                               pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp,
+                                               &stream->bit_depth_params,
+                                               &stream->clamping);
+                       }
+
                        /* Full fe update*/
                        if (update_type == UPDATE_TYPE_FAST)
                                continue;
@@ -1448,19 +1497,13 @@ static void commit_planes_do_stream_update(struct dc *dc,
                        if (stream_update->dpms_off) {
                                if (*stream_update->dpms_off) {
                                        core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE);
-                                       dc->hwss.pplib_apply_display_requirements(
-                                               dc, dc->current_state);
-                                       notify_display_count_to_smu(dc, dc->current_state);
+                                       dc->hwss.optimize_bandwidth(dc, dc->current_state);
                                } else {
-                                       dc->hwss.pplib_apply_display_requirements(
-                                               dc, dc->current_state);
-                                       notify_display_count_to_smu(dc, dc->current_state);
+                                       dc->hwss.prepare_bandwidth(dc, dc->current_state);
                                        core_link_enable_stream(dc->current_state, pipe_ctx);
                                }
                        }
 
-
-
                        if (stream_update->abm_level && pipe_ctx->stream_res.abm) {
                                if (pipe_ctx->stream_res.tg->funcs->is_blanked) {
                                        // if otg funcs defined check if blanked before programming
@@ -1487,7 +1530,7 @@ static void commit_planes_for_stream(struct dc *dc,
        struct pipe_ctx *top_pipe_to_program = NULL;
 
        if (update_type == UPDATE_TYPE_FULL) {
-               dc->hwss.set_bandwidth(dc, context, false);
+               dc->hwss.prepare_bandwidth(dc, context);
                context_clock_trace(dc, context);
        }
 
@@ -1669,6 +1712,9 @@ enum dc_irq_source dc_interrupt_to_irq_source(
        return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id);
 }
 
+/**
+ * dc_interrupt_set() - Enable/disable an AMD hw interrupt source
+ */
 bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)
 {
 
@@ -1724,6 +1770,15 @@ void dc_resume(struct dc *dc)
                core_link_resume(dc->links[i]);
 }
 
+bool dc_is_dmcu_initialized(struct dc *dc)
+{
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+
+       if (dmcu)
+               return dmcu->funcs->is_dmcu_initialized(dmcu);
+       return false;
+}
+
 bool dc_submit_i2c(
                struct dc *dc,
                uint32_t link_index,
@@ -1753,6 +1808,11 @@ static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink
        return true;
 }
 
+/**
+ * dc_link_add_remote_sink() - Create a sink and attach it to an existing link
+ *
+ * EDID length is in bytes
+ */
 struct dc_sink *dc_link_add_remote_sink(
                struct dc_link *link,
                const uint8_t *edid,
@@ -1811,6 +1871,12 @@ fail_add_sink:
        return NULL;
 }
 
+/**
+ * dc_link_remove_remote_sink() - Remove a remote sink from a dc_link
+ *
+ * Note that this just removes the struct dc_sink - it doesn't
+ * program hardware or alter other members of dc_link
+ */
 void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink)
 {
        int i;
@@ -1848,4 +1914,4 @@ void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx
        info->dcfClockDeepSleep                 = (unsigned int)state->bw.dcn.clk.dcfclk_deep_sleep_khz;
        info->fClock                                    = (unsigned int)state->bw.dcn.clk.fclk_khz;
        info->phyClock                                  = (unsigned int)state->bw.dcn.clk.phyclk_khz;
-}
\ No newline at end of file
+}
index e1ebdf7b5eaf3080882e5c3ea99de0278d9acdb0..73d0495066189f990976d0e1cfbd9d9cea29f1dc 100644 (file)
@@ -311,7 +311,7 @@ void context_timing_trace(
 {
        int i;
        struct dc  *core_dc = dc;
-       int h_pos[MAX_PIPES], v_pos[MAX_PIPES];
+       int h_pos[MAX_PIPES] = {0}, v_pos[MAX_PIPES] = {0};
        struct crtc_position position;
        unsigned int underlay_idx = core_dc->res_pool->underlay_pipe_index;
        DC_LOGGER_INIT(dc->ctx->logger);
@@ -322,8 +322,7 @@ void context_timing_trace(
                /* get_position() returns CRTC vertical/horizontal counter
                 * hence not applicable for underlay pipe
                 */
-               if (pipe_ctx->stream == NULL
-                                || pipe_ctx->pipe_idx == underlay_idx)
+               if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx)
                        continue;
 
                pipe_ctx->stream_res.tg->funcs->get_position(pipe_ctx->stream_res.tg, &position);
@@ -333,7 +332,7 @@ void context_timing_trace(
        for (i = 0; i < core_dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
 
-               if (pipe_ctx->stream == NULL)
+               if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx)
                        continue;
 
                TIMING_TRACE("OTG_%d   H_tot:%d  V_tot:%d   H_pos:%d  V_pos:%d\n",
index 5da2186b3615ff97b3bc54a68b3849ad6c85856f..4dc5846de5c4b24f8d7f71d2f2c2bbe2b821d661 100644 (file)
@@ -198,6 +198,13 @@ static bool program_hpd_filter(
        return result;
 }
 
+/**
+ * dc_link_detect_sink() - Determine if there is a sink connected
+ *
+ * @type: Returned connection type
+ * Does not detect downstream devices, such as MST sinks
+ * or display connected through active dongles
+ */
 bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
 {
        uint32_t is_hpd_high = 0;
@@ -324,9 +331,9 @@ static enum signal_type get_basic_signal_type(
        return SIGNAL_TYPE_NONE;
 }
 
-/*
- * @brief
- * Check whether there is a dongle on DP connector
+/**
+ * dc_link_is_dp_sink_present() - Check if there is a native DP
+ * or passive DP-HDMI dongle connected
  */
 bool dc_link_is_dp_sink_present(struct dc_link *link)
 {
@@ -593,6 +600,14 @@ static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid)
        return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0);
 }
 
+/**
+ * dc_link_detect() - Detect if a sink is attached to a given link
+ *
+ * link->local_sink is created or destroyed as needed.
+ *
+ * This does not create remote sinks but will trigger DM
+ * to start MST detection if a branch is detected.
+ */
 bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
 {
        struct dc_sink_init_data sink_init_data = { 0 };
@@ -1357,28 +1372,13 @@ static enum dc_status enable_link_dp(
        struct dc_link *link = stream->sink->link;
        struct dc_link_settings link_settings = {0};
        enum dp_panel_mode panel_mode;
-       enum dc_link_rate max_link_rate = LINK_RATE_HIGH2;
 
        /* get link settings for video mode timing */
        decide_link_settings(stream, &link_settings);
 
-       /* raise clock state for HBR3 if required. Confirmed with HW DCE/DPCS
-        * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
-        */
-       if (link->link_enc->features.flags.bits.IS_HBR3_CAPABLE)
-               max_link_rate = LINK_RATE_HIGH3;
-
-       if (link_settings.link_rate == max_link_rate) {
-               struct dc_clocks clocks = state->bw.dcn.clk;
-
-               /* dce/dcn compat, do not update dispclk */
-               clocks.dispclk_khz = 0;
-               /* 27mhz = 27000000hz= 27000khz */
-               clocks.phyclk_khz = link_settings.link_rate * 27000;
-
-               state->dis_clk->funcs->update_clocks(
-                               state->dis_clk, &clocks, false);
-       }
+       pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
+                       link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+       state->dccg->funcs->update_clocks(state->dccg, state, false);
 
        dp_enable_link_phy(
                link,
@@ -1411,8 +1411,6 @@ static enum dc_status enable_link_dp(
        else
                status = DC_FAIL_DP_LINK_TRAINING;
 
-       enable_stream_features(pipe_ctx);
-
        return status;
 }
 
@@ -2156,14 +2154,16 @@ int dc_link_get_backlight_level(const struct dc_link *link)
 {
        struct abm *abm = link->ctx->dc->res_pool->abm;
 
-       if (abm == NULL || abm->funcs->get_current_backlight_8_bit == NULL)
+       if (abm == NULL || abm->funcs->get_current_backlight == NULL)
                return DC_ERROR_UNEXPECTED;
 
-       return (int) abm->funcs->get_current_backlight_8_bit(abm);
+       return (int) abm->funcs->get_current_backlight(abm);
 }
 
-bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
-               uint32_t frame_ramp, const struct dc_stream_state *stream)
+bool dc_link_set_backlight_level(const struct dc_link *link,
+               uint32_t backlight_pwm_u16_16,
+               uint32_t frame_ramp,
+               const struct dc_stream_state *stream)
 {
        struct dc  *core_dc = link->ctx->dc;
        struct abm *abm = core_dc->res_pool->abm;
@@ -2175,26 +2175,24 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
 
        if ((dmcu == NULL) ||
                (abm == NULL) ||
-               (abm->funcs->set_backlight_level == NULL))
+               (abm->funcs->set_backlight_level_pwm == NULL))
                return false;
 
-       if (stream) {
-               if (stream->bl_pwm_level == EDP_BACKLIGHT_RAMP_DISABLE_LEVEL)
-                       frame_ramp = 0;
-
-               ((struct dc_stream_state *)stream)->bl_pwm_level = level;
-       }
+       if (stream)
+               ((struct dc_stream_state *)stream)->bl_pwm_level =
+                               backlight_pwm_u16_16;
 
        use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
 
-       DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level);
+       DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
+                       backlight_pwm_u16_16, backlight_pwm_u16_16);
 
        if (dc_is_embedded_signal(link->connector_signal)) {
-               if (stream != NULL) {
-                       for (i = 0; i < MAX_PIPES; i++) {
+               for (i = 0; i < MAX_PIPES; i++) {
+                       if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) {
                                if (core_dc->current_state->res_ctx.
-                                               pipe_ctx[i].stream
-                                               == stream)
+                                               pipe_ctx[i].stream->sink->link
+                                               == link)
                                        /* DMCU -1 for all controller id values,
                                         * therefore +1 here
                                         */
@@ -2204,9 +2202,9 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
                                                1;
                        }
                }
-               abm->funcs->set_backlight_level(
+               abm->funcs->set_backlight_level_pwm(
                                abm,
-                               level,
+                               backlight_pwm_u16_16,
                                frame_ramp,
                                controller_id,
                                use_smooth_brightness);
@@ -2220,7 +2218,7 @@ bool dc_link_set_abm_disable(const struct dc_link *link)
        struct dc  *core_dc = link->ctx->dc;
        struct abm *abm = core_dc->res_pool->abm;
 
-       if ((abm == NULL) || (abm->funcs->set_backlight_level == NULL))
+       if ((abm == NULL) || (abm->funcs->set_backlight_level_pwm == NULL))
                return false;
 
        abm->funcs->set_abm_immediate_disable(abm);
@@ -2233,7 +2231,7 @@ bool dc_link_set_psr_enable(const struct dc_link *link, bool enable, bool wait)
        struct dc  *core_dc = link->ctx->dc;
        struct dmcu *dmcu = core_dc->res_pool->dmcu;
 
-       if (dmcu != NULL && link->psr_enabled)
+       if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && link->psr_enabled)
                dmcu->funcs->set_psr_enable(dmcu, enable, wait);
 
        return true;
@@ -2609,6 +2607,13 @@ void core_link_enable_stream(
                core_dc->hwss.unblank_stream(pipe_ctx,
                        &pipe_ctx->stream->sink->link->cur_link_settings);
 
+               if (dc_is_dp_signal(pipe_ctx->stream->signal))
+                       enable_stream_features(pipe_ctx);
+
+               dc_link_set_backlight_level(pipe_ctx->stream->sink->link,
+                               pipe_ctx->stream->bl_pwm_level,
+                               0,
+                               pipe_ctx->stream);
        }
 
 }
index d91df5ef0cb34bfd8e565449c3982ef3a3a5aedd..849a3a3032f7cb71aea38dac834dc60461846998 100644 (file)
@@ -2196,7 +2196,7 @@ static void get_active_converter_info(
        }
 
        if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
-               uint8_t det_caps[4];
+               uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
                union dwnstream_port_caps_byte0 *port_caps =
                        (union dwnstream_port_caps_byte0 *)det_caps;
                core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
@@ -2371,11 +2371,22 @@ static bool retrieve_link_cap(struct dc_link *link)
                        dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
 
                if (aux_rd_interval.bits.EXT_RECIEVER_CAP_FIELD_PRESENT == 1) {
-                       core_link_read_dpcd(
+                       uint8_t ext_cap_data[16];
+
+                       memset(ext_cap_data, '\0', sizeof(ext_cap_data));
+                       for (i = 0; i < read_dpcd_retry_cnt; i++) {
+                               status = core_link_read_dpcd(
                                link,
                                DP_DP13_DPCD_REV,
-                               dpcd_data,
-                               sizeof(dpcd_data));
+                               ext_cap_data,
+                               sizeof(ext_cap_data));
+                               if (status == DC_OK) {
+                                       memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
+                                       break;
+                               }
+                       }
+                       if (status != DC_OK)
+                               dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
                }
        }
 
index b6fe29b9fb65730ed44fe5f76c12f92605a5dfe0..c347afd1030f8e15e44e55888f48cdbe06f6fd34 100644 (file)
@@ -478,10 +478,29 @@ static enum pixel_format convert_pixel_format_to_dalsurface(
        return dal_pixel_format;
 }
 
-static void rect_swap_helper(struct rect *rect)
-{
-       swap(rect->height, rect->width);
-       swap(rect->x, rect->y);
+static inline void get_vp_scan_direction(
+       enum dc_rotation_angle rotation,
+       bool horizontal_mirror,
+       bool *orthogonal_rotation,
+       bool *flip_vert_scan_dir,
+       bool *flip_horz_scan_dir)
+{
+       *orthogonal_rotation = false;
+       *flip_vert_scan_dir = false;
+       *flip_horz_scan_dir = false;
+       if (rotation == ROTATION_ANGLE_180) {
+               *flip_vert_scan_dir = true;
+               *flip_horz_scan_dir = true;
+       } else if (rotation == ROTATION_ANGLE_90) {
+               *orthogonal_rotation = true;
+               *flip_horz_scan_dir = true;
+       } else if (rotation == ROTATION_ANGLE_270) {
+               *orthogonal_rotation = true;
+               *flip_vert_scan_dir = true;
+       }
+
+       if (horizontal_mirror)
+               *flip_horz_scan_dir = !*flip_horz_scan_dir;
 }
 
 static void calculate_viewport(struct pipe_ctx *pipe_ctx)
@@ -490,25 +509,14 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
        const struct dc_stream_state *stream = pipe_ctx->stream;
        struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
        struct rect surf_src = plane_state->src_rect;
-       struct rect clip = { 0 };
+       struct rect clip, dest;
        int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
                        || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
        bool pri_split = pipe_ctx->bottom_pipe &&
                        pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state;
        bool sec_split = pipe_ctx->top_pipe &&
                        pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
-       bool flip_vert_scan_dir = false, flip_horz_scan_dir = false;
-
-       /*
-        * Need to calculate the scan direction for viewport to properly determine offset
-        */
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) {
-               flip_vert_scan_dir = true;
-               flip_horz_scan_dir = true;
-       } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90)
-               flip_vert_scan_dir = true;
-       else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
-               flip_horz_scan_dir = true;
+       bool orthogonal_rotation, flip_y_start, flip_x_start;
 
        if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE ||
                stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
@@ -516,13 +524,10 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
                sec_split = false;
        }
 
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
-                       pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
-               rect_swap_helper(&surf_src);
-
        /* The actual clip is an intersection between stream
         * source and surface clip
         */
+       dest = plane_state->dst_rect;
        clip.x = stream->src.x > plane_state->clip_rect.x ?
                        stream->src.x : plane_state->clip_rect.x;
 
@@ -539,84 +544,77 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
                        stream->src.y + stream->src.height - clip.y :
                        plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ;
 
+       /*
+        * Need to calculate how scan origin is shifted in vp space
+        * to correctly rotate clip and dst
+        */
+       get_vp_scan_direction(
+                       plane_state->rotation,
+                       plane_state->horizontal_mirror,
+                       &orthogonal_rotation,
+                       &flip_y_start,
+                       &flip_x_start);
+
+       if (orthogonal_rotation) {
+               swap(clip.x, clip.y);
+               swap(clip.width, clip.height);
+               swap(dest.x, dest.y);
+               swap(dest.width, dest.height);
+       }
+       if (flip_x_start) {
+               clip.x = dest.x + dest.width - clip.x - clip.width;
+               dest.x = 0;
+       }
+       if (flip_y_start) {
+               clip.y = dest.y + dest.height - clip.y - clip.height;
+               dest.y = 0;
+       }
+
        /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio
         * num_pixels = clip.num_pix * scl_ratio
         */
-       data->viewport.x = surf_src.x + (clip.x - plane_state->dst_rect.x) *
-                       surf_src.width / plane_state->dst_rect.width;
-       data->viewport.width = clip.width *
-                       surf_src.width / plane_state->dst_rect.width;
-
-       data->viewport.y = surf_src.y + (clip.y - plane_state->dst_rect.y) *
-                       surf_src.height / plane_state->dst_rect.height;
-       data->viewport.height = clip.height *
-                       surf_src.height / plane_state->dst_rect.height;
-
-       /* To transfer the x, y to correct coordinate on mirror image (camera).
-        * deg  0 : transfer x,
-        * deg 90 : don't need to transfer,
-        * deg180 : transfer y,
-        * deg270 : transfer x and y.
-        * To transfer the x, y to correct coordinate on non-mirror image (video).
-        * deg  0 : don't need to transfer,
-        * deg 90 : transfer y,
-        * deg180 : transfer x and y,
-        * deg270 : transfer x.
-        */
-       if (pipe_ctx->plane_state->horizontal_mirror) {
-               if (flip_horz_scan_dir && !flip_vert_scan_dir) {
-                       data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
-                       data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
-               } else if (flip_horz_scan_dir && flip_vert_scan_dir)
-                       data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
-               else {
-                       if (!flip_horz_scan_dir && !flip_vert_scan_dir)
-                               data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
+       data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width;
+       data->viewport.width = clip.width * surf_src.width / dest.width;
+
+       data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height;
+       data->viewport.height = clip.height * surf_src.height / dest.height;
+
+       /* Handle split */
+       if (pri_split || sec_split) {
+               if (orthogonal_rotation) {
+                       if (flip_y_start != pri_split)
+                               data->viewport.height /= 2;
+                       else {
+                               data->viewport.y +=  data->viewport.height / 2;
+                               /* Ceil offset pipe */
+                               data->viewport.height = (data->viewport.height + 1) / 2;
+                       }
+               } else {
+                       if (flip_x_start != pri_split)
+                               data->viewport.width /= 2;
+                       else {
+                               data->viewport.x +=  data->viewport.width / 2;
+                               /* Ceil offset pipe */
+                               data->viewport.width = (data->viewport.width + 1) / 2;
+                       }
                }
-       } else {
-               if (flip_horz_scan_dir)
-                       data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
-               if (flip_vert_scan_dir)
-                       data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
        }
 
        /* Round down, compensate in init */
        data->viewport_c.x = data->viewport.x / vpc_div;
        data->viewport_c.y = data->viewport.y / vpc_div;
-       data->inits.h_c = (data->viewport.x % vpc_div) != 0 ?
-                       dc_fixpt_half : dc_fixpt_zero;
-       data->inits.v_c = (data->viewport.y % vpc_div) != 0 ?
-                       dc_fixpt_half : dc_fixpt_zero;
+       data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero;
+       data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero;
+
        /* Round up, assume original video size always even dimensions */
        data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div;
        data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div;
-
-       /* Handle hsplit */
-       if (sec_split) {
-               data->viewport.x +=  data->viewport.width / 2;
-               data->viewport_c.x +=  data->viewport_c.width / 2;
-               /* Ceil offset pipe */
-               data->viewport.width = (data->viewport.width + 1) / 2;
-               data->viewport_c.width = (data->viewport_c.width + 1) / 2;
-       } else if (pri_split) {
-               if (data->viewport.width > 1)
-                       data->viewport.width /= 2;
-               if (data->viewport_c.width > 1)
-                       data->viewport_c.width /= 2;
-       }
-
-       if (plane_state->rotation == ROTATION_ANGLE_90 ||
-                       plane_state->rotation == ROTATION_ANGLE_270) {
-               rect_swap_helper(&data->viewport_c);
-               rect_swap_helper(&data->viewport);
-       }
 }
 
-static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
+static void calculate_recout(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        const struct dc_stream_state *stream = pipe_ctx->stream;
-       struct rect surf_src = plane_state->src_rect;
        struct rect surf_clip = plane_state->clip_rect;
        bool pri_split = pipe_ctx->bottom_pipe &&
                        pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state;
@@ -624,10 +622,6 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
                        pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
        bool top_bottom_split = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
 
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
-                       pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
-               rect_swap_helper(&surf_src);
-
        pipe_ctx->plane_res.scl_data.recout.x = stream->dst.x;
        if (stream->src.x < surf_clip.x)
                pipe_ctx->plane_res.scl_data.recout.x += (surf_clip.x
@@ -656,7 +650,7 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
                        stream->dst.y + stream->dst.height
                                                - pipe_ctx->plane_res.scl_data.recout.y;
 
-       /* Handle h & vsplit */
+       /* Handle h & v split, handle rotation using viewport */
        if (sec_split && top_bottom_split) {
                pipe_ctx->plane_res.scl_data.recout.y +=
                                pipe_ctx->plane_res.scl_data.recout.height / 2;
@@ -665,44 +659,14 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full
                                (pipe_ctx->plane_res.scl_data.recout.height + 1) / 2;
        } else if (pri_split && top_bottom_split)
                pipe_ctx->plane_res.scl_data.recout.height /= 2;
-       else if (pri_split || sec_split) {
-               /* HMirror XOR Secondary_pipe XOR Rotation_180 */
-               bool right_view = (sec_split != plane_state->horizontal_mirror) !=
-                                       (plane_state->rotation == ROTATION_ANGLE_180);
-
-               if (plane_state->rotation == ROTATION_ANGLE_90
-                               || plane_state->rotation == ROTATION_ANGLE_270)
-                       /* Secondary_pipe XOR Rotation_270 */
-                       right_view = (plane_state->rotation == ROTATION_ANGLE_270) != sec_split;
-
-               if (right_view) {
-                       pipe_ctx->plane_res.scl_data.recout.x +=
-                                       pipe_ctx->plane_res.scl_data.recout.width / 2;
-                       /* Ceil offset pipe */
-                       pipe_ctx->plane_res.scl_data.recout.width =
-                                       (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2;
-               } else {
-                       if (pipe_ctx->plane_res.scl_data.recout.width > 1)
-                               pipe_ctx->plane_res.scl_data.recout.width /= 2;
-               }
-       }
-       /* Unclipped recout offset = stream dst offset + ((surf dst offset - stream surf_src offset)
-        *                      * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl
-        *                      ratio)
-        */
-       recout_full->x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
-                                       * stream->dst.width / stream->src.width -
-                       surf_src.x * plane_state->dst_rect.width / surf_src.width
-                                       * stream->dst.width / stream->src.width;
-       recout_full->y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
-                                       * stream->dst.height / stream->src.height -
-                       surf_src.y * plane_state->dst_rect.height / surf_src.height
-                                       * stream->dst.height / stream->src.height;
-
-       recout_full->width = plane_state->dst_rect.width
-                                       * stream->dst.width / stream->src.width;
-       recout_full->height = plane_state->dst_rect.height
-                                       * stream->dst.height / stream->src.height;
+       else if (sec_split) {
+               pipe_ctx->plane_res.scl_data.recout.x +=
+                               pipe_ctx->plane_res.scl_data.recout.width / 2;
+               /* Ceil offset pipe */
+               pipe_ctx->plane_res.scl_data.recout.width =
+                               (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2;
+       } else if (pri_split)
+               pipe_ctx->plane_res.scl_data.recout.width /= 2;
 }
 
 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
@@ -715,9 +679,10 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
        const int out_w = stream->dst.width;
        const int out_h = stream->dst.height;
 
+       /*Swap surf_src height and width since scaling ratios are in recout rotation*/
        if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
                        pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
-               rect_swap_helper(&surf_src);
+               swap(surf_src.height, surf_src.width);
 
        pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
                                        surf_src.width,
@@ -754,358 +719,202 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
                        pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
 }
 
-static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full)
+static inline void adjust_vp_and_init_for_seamless_clip(
+               bool flip_scan_dir,
+               int recout_skip,
+               int src_size,
+               int taps,
+               struct fixed31_32 ratio,
+               struct fixed31_32 *init,
+               int *vp_offset,
+               int *vp_size)
 {
-       struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
-       struct rect src = pipe_ctx->plane_state->src_rect;
-       int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
-                       || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
-       bool flip_vert_scan_dir = false, flip_horz_scan_dir = false;
-
-       /*
-        * Need to calculate the scan direction for viewport to make adjustments
-        */
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) {
-               flip_vert_scan_dir = true;
-               flip_horz_scan_dir = true;
-       } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90)
-               flip_vert_scan_dir = true;
-       else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
-               flip_horz_scan_dir = true;
-
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
-                       pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
-               rect_swap_helper(&src);
-               rect_swap_helper(&data->viewport_c);
-               rect_swap_helper(&data->viewport);
-
-               if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270 &&
-                       pipe_ctx->plane_state->horizontal_mirror) {
-                       flip_vert_scan_dir = true;
-               }
-               if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 &&
-                       pipe_ctx->plane_state->horizontal_mirror) {
-                       flip_vert_scan_dir = false;
-               }
-       } else if (pipe_ctx->plane_state->horizontal_mirror)
-                       flip_horz_scan_dir = !flip_horz_scan_dir;
-
-       /*
-        * Init calculated according to formula:
-        *      init = (scaling_ratio + number_of_taps + 1) / 2
-        *      init_bot = init + scaling_ratio
-        *      init_c = init + truncated_vp_c_offset(from calculate viewport)
-        */
-       data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int(
-                       dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19);
-
-       data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int(
-                       dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19);
-
-       data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int(
-                       dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19);
-
-       data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int(
-                       dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19);
-
-       if (!flip_horz_scan_dir) {
+       if (!flip_scan_dir) {
                /* Adjust for viewport end clip-off */
-               if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
-                       int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x;
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.h, data->ratios.horz));
-
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport.width += int_part < vp_clip ? int_part : vp_clip;
-               }
-               if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
-                       int vp_clip = (src.x + src.width) / vpc_div -
-                                       data->viewport_c.width - data->viewport_c.x;
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c));
+               if ((*vp_offset + *vp_size) < src_size) {
+                       int vp_clip = src_size - *vp_size - *vp_offset;
+                       int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio));
 
                        int_part = int_part > 0 ? int_part : 0;
-                       data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip;
+                       *vp_size += int_part < vp_clip ? int_part : vp_clip;
                }
 
                /* Adjust for non-0 viewport offset */
-               if (data->viewport.x) {
+               if (*vp_offset) {
                        int int_part;
 
-                       data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
-                                       data->ratios.horz, data->recout.x - recout_full->x));
-                       int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x;
-                       if (int_part < data->taps.h_taps) {
-                               int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ?
-                                                       (data->taps.h_taps - int_part) : data->viewport.x;
-                               data->viewport.x -= int_adj;
-                               data->viewport.width += int_adj;
+                       *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip));
+                       int_part = dc_fixpt_floor(*init) - *vp_offset;
+                       if (int_part < taps) {
+                               int int_adj = *vp_offset >= (taps - int_part) ?
+                                                       (taps - int_part) : *vp_offset;
+                               *vp_offset -= int_adj;
+                               *vp_size += int_adj;
                                int_part += int_adj;
-                       } else if (int_part > data->taps.h_taps) {
-                               data->viewport.x += int_part - data->taps.h_taps;
-                               data->viewport.width -= int_part - data->taps.h_taps;
-                               int_part = data->taps.h_taps;
+                       } else if (int_part > taps) {
+                               *vp_offset += int_part - taps;
+                               *vp_size -= int_part - taps;
+                               int_part = taps;
                        }
-                       data->inits.h.value &= 0xffffffff;
-                       data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
-               }
-
-               if (data->viewport_c.x) {
-                       int int_part;
-
-                       data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
-                                       data->ratios.horz_c, data->recout.x - recout_full->x));
-                       int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x;
-                       if (int_part < data->taps.h_taps_c) {
-                               int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ?
-                                               (data->taps.h_taps_c - int_part) : data->viewport_c.x;
-                               data->viewport_c.x -= int_adj;
-                               data->viewport_c.width += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.h_taps_c) {
-                               data->viewport_c.x += int_part - data->taps.h_taps_c;
-                               data->viewport_c.width -= int_part - data->taps.h_taps_c;
-                               int_part = data->taps.h_taps_c;
-                       }
-                       data->inits.h_c.value &= 0xffffffff;
-                       data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
+                       init->value &= 0xffffffff;
+                       *init = dc_fixpt_add_int(*init, int_part);
                }
        } else {
                /* Adjust for non-0 viewport offset */
-               if (data->viewport.x) {
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.h, data->ratios.horz));
-
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport.width += int_part < data->viewport.x ? int_part : data->viewport.x;
-                       data->viewport.x -= int_part < data->viewport.x ? int_part : data->viewport.x;
-               }
-               if (data->viewport_c.x) {
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c));
+               if (*vp_offset) {
+                       int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio));
 
                        int_part = int_part > 0 ? int_part : 0;
-                       data->viewport_c.width += int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
-                       data->viewport_c.x -= int_part < data->viewport_c.x ? int_part : data->viewport_c.x;
+                       *vp_size += int_part < *vp_offset ? int_part : *vp_offset;
+                       *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset;
                }
 
                /* Adjust for viewport end clip-off */
-               if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
+               if ((*vp_offset + *vp_size) < src_size) {
                        int int_part;
-                       int end_offset = src.x + src.width
-                                       - data->viewport.x - data->viewport.width;
+                       int end_offset = src_size - *vp_offset - *vp_size;
 
                        /*
                         * this is init if vp had no offset, keep in mind this is from the
                         * right side of vp due to scan direction
                         */
-                       data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int(
-                                       data->ratios.horz, data->recout.x - recout_full->x));
+                       *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip));
                        /*
                         * this is the difference between first pixel of viewport available to read
                         * and init position, takning into account scan direction
                         */
-                       int_part = dc_fixpt_floor(data->inits.h) - end_offset;
-                       if (int_part < data->taps.h_taps) {
-                               int int_adj = end_offset >= (data->taps.h_taps - int_part) ?
-                                                       (data->taps.h_taps - int_part) : end_offset;
-                               data->viewport.width += int_adj;
+                       int_part = dc_fixpt_floor(*init) - end_offset;
+                       if (int_part < taps) {
+                               int int_adj = end_offset >= (taps - int_part) ?
+                                                       (taps - int_part) : end_offset;
+                               *vp_size += int_adj;
                                int_part += int_adj;
-                       } else if (int_part > data->taps.h_taps) {
-                               data->viewport.width += int_part - data->taps.h_taps;
-                               int_part = data->taps.h_taps;
+                       } else if (int_part > taps) {
+                               *vp_size += int_part - taps;
+                               int_part = taps;
                        }
-                       data->inits.h.value &= 0xffffffff;
-                       data->inits.h = dc_fixpt_add_int(data->inits.h, int_part);
+                       init->value &= 0xffffffff;
+                       *init = dc_fixpt_add_int(*init, int_part);
                }
-
-               if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
-                       int int_part;
-                       int end_offset = (src.x + src.width) / vpc_div
-                                       - data->viewport_c.x - data->viewport_c.width;
-
-                       /*
-                        * this is init if vp had no offset, keep in mind this is from the
-                        * right side of vp due to scan direction
-                        */
-                       data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int(
-                                       data->ratios.horz_c, data->recout.x - recout_full->x));
-                       /*
-                        * this is the difference between first pixel of viewport available to read
-                        * and init position, takning into account scan direction
-                        */
-                       int_part = dc_fixpt_floor(data->inits.h_c) - end_offset;
-                       if (int_part < data->taps.h_taps_c) {
-                               int int_adj = end_offset >= (data->taps.h_taps_c - int_part) ?
-                                                       (data->taps.h_taps_c - int_part) : end_offset;
-                               data->viewport_c.width += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.h_taps_c) {
-                               data->viewport_c.width += int_part - data->taps.h_taps_c;
-                               int_part = data->taps.h_taps_c;
-                       }
-                       data->inits.h_c.value &= 0xffffffff;
-                       data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part);
-               }
-
        }
-       if (!flip_vert_scan_dir) {
-               /* Adjust for viewport end clip-off */
-               if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
-                       int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y;
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.v, data->ratios.vert));
-
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport.height += int_part < vp_clip ? int_part : vp_clip;
-               }
-               if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
-                       int vp_clip = (src.y + src.height) / vpc_div -
-                                       data->viewport_c.height - data->viewport_c.y;
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
-
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip;
-               }
-
-               /* Adjust for non-0 viewport offset */
-               if (data->viewport.y) {
-                       int int_part;
-
-                       data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
-                                       data->ratios.vert, data->recout.y - recout_full->y));
-                       int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y;
-                       if (int_part < data->taps.v_taps) {
-                               int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ?
-                                                       (data->taps.v_taps - int_part) : data->viewport.y;
-                               data->viewport.y -= int_adj;
-                               data->viewport.height += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.v_taps) {
-                               data->viewport.y += int_part - data->taps.v_taps;
-                               data->viewport.height -= int_part - data->taps.v_taps;
-                               int_part = data->taps.v_taps;
-                       }
-                       data->inits.v.value &= 0xffffffff;
-                       data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
-               }
-
-               if (data->viewport_c.y) {
-                       int int_part;
-
-                       data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
-                                       data->ratios.vert_c, data->recout.y - recout_full->y));
-                       int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y;
-                       if (int_part < data->taps.v_taps_c) {
-                               int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ?
-                                               (data->taps.v_taps_c - int_part) : data->viewport_c.y;
-                               data->viewport_c.y -= int_adj;
-                               data->viewport_c.height += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.v_taps_c) {
-                               data->viewport_c.y += int_part - data->taps.v_taps_c;
-                               data->viewport_c.height -= int_part - data->taps.v_taps_c;
-                               int_part = data->taps.v_taps_c;
-                       }
-                       data->inits.v_c.value &= 0xffffffff;
-                       data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
-               }
-       } else {
-               /* Adjust for non-0 viewport offset */
-               if (data->viewport.y) {
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.v, data->ratios.vert));
+}
 
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport.height += int_part < data->viewport.y ? int_part : data->viewport.y;
-                       data->viewport.y -= int_part < data->viewport.y ? int_part : data->viewport.y;
-               }
-               if (data->viewport_c.y) {
-                       int int_part = dc_fixpt_floor(
-                                       dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c));
+static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx)
+{
+       const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
+       const struct dc_stream_state *stream = pipe_ctx->stream;
+       struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
+       struct rect src = pipe_ctx->plane_state->src_rect;
+       int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v;
+       int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
+                       || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
+       bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
 
-                       int_part = int_part > 0 ? int_part : 0;
-                       data->viewport_c.height += int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
-                       data->viewport_c.y -= int_part < data->viewport_c.y ? int_part : data->viewport_c.y;
-               }
+       /*
+        * Need to calculate the scan direction for viewport to make adjustments
+        */
+       get_vp_scan_direction(
+                       plane_state->rotation,
+                       plane_state->horizontal_mirror,
+                       &orthogonal_rotation,
+                       &flip_vert_scan_dir,
+                       &flip_horz_scan_dir);
+
+       /* Calculate src rect rotation adjusted to recout space */
+       surf_size_h = src.x + src.width;
+       surf_size_v = src.y + src.height;
+       if (flip_horz_scan_dir)
+               src.x = 0;
+       if (flip_vert_scan_dir)
+               src.y = 0;
+       if (orthogonal_rotation) {
+               swap(src.x, src.y);
+               swap(src.width, src.height);
+       }
+
+       /* Recout matching initial vp offset = recout_offset - (stream dst offset +
+        *                      ((surf dst offset - stream src offset) * 1/ stream scaling ratio)
+        *                      - (surf surf_src offset * 1/ full scl ratio))
+        */
+       recout_skip_h = data->recout.x - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
+                                       * stream->dst.width / stream->src.width -
+                                       src.x * plane_state->dst_rect.width / src.width
+                                       * stream->dst.width / stream->src.width);
+       recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
+                                       * stream->dst.height / stream->src.height -
+                                       src.y * plane_state->dst_rect.height / src.height
+                                       * stream->dst.height / stream->src.height);
+       if (orthogonal_rotation)
+               swap(recout_skip_h, recout_skip_v);
+       /*
+        * Init calculated according to formula:
+        *      init = (scaling_ratio + number_of_taps + 1) / 2
+        *      init_bot = init + scaling_ratio
+        *      init_c = init + truncated_vp_c_offset(from calculate viewport)
+        */
+       data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int(
+                       dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19);
 
-               /* Adjust for viewport end clip-off */
-               if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
-                       int int_part;
-                       int end_offset = src.y + src.height
-                                       - data->viewport.y - data->viewport.height;
+       data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int(
+                       dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19);
 
-                       /*
-                        * this is init if vp had no offset, keep in mind this is from the
-                        * right side of vp due to scan direction
-                        */
-                       data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int(
-                                       data->ratios.vert, data->recout.y - recout_full->y));
-                       /*
-                        * this is the difference between first pixel of viewport available to read
-                        * and init position, taking into account scan direction
-                        */
-                       int_part = dc_fixpt_floor(data->inits.v) - end_offset;
-                       if (int_part < data->taps.v_taps) {
-                               int int_adj = end_offset >= (data->taps.v_taps - int_part) ?
-                                                       (data->taps.v_taps - int_part) : end_offset;
-                               data->viewport.height += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.v_taps) {
-                               data->viewport.height += int_part - data->taps.v_taps;
-                               int_part = data->taps.v_taps;
-                       }
-                       data->inits.v.value &= 0xffffffff;
-                       data->inits.v = dc_fixpt_add_int(data->inits.v, int_part);
-               }
+       data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int(
+                       dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19);
 
-               if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
-                       int int_part;
-                       int end_offset = (src.y + src.height) / vpc_div
-                                       - data->viewport_c.y - data->viewport_c.height;
+       data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int(
+                       dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19);
 
-                       /*
-                        * this is init if vp had no offset, keep in mind this is from the
-                        * right side of vp due to scan direction
-                        */
-                       data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int(
-                                       data->ratios.vert_c, data->recout.y - recout_full->y));
-                       /*
-                        * this is the difference between first pixel of viewport available to read
-                        * and init position, taking into account scan direction
-                        */
-                       int_part = dc_fixpt_floor(data->inits.v_c) - end_offset;
-                       if (int_part < data->taps.v_taps_c) {
-                               int int_adj = end_offset >= (data->taps.v_taps_c - int_part) ?
-                                                       (data->taps.v_taps_c - int_part) : end_offset;
-                               data->viewport_c.height += int_adj;
-                               int_part += int_adj;
-                       } else if (int_part > data->taps.v_taps_c) {
-                               data->viewport_c.height += int_part - data->taps.v_taps_c;
-                               int_part = data->taps.v_taps_c;
-                       }
-                       data->inits.v_c.value &= 0xffffffff;
-                       data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part);
-               }
-       }
+       /*
+        * Taps, inits and scaling ratios are in recout space need to rotate
+        * to viewport rotation before adjustment
+        */
+       adjust_vp_and_init_for_seamless_clip(
+                       flip_horz_scan_dir,
+                       recout_skip_h,
+                       surf_size_h,
+                       orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps,
+                       orthogonal_rotation ? data->ratios.vert : data->ratios.horz,
+                       orthogonal_rotation ? &data->inits.v : &data->inits.h,
+                       &data->viewport.x,
+                       &data->viewport.width);
+       adjust_vp_and_init_for_seamless_clip(
+                       flip_horz_scan_dir,
+                       recout_skip_h,
+                       surf_size_h / vpc_div,
+                       orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c,
+                       orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c,
+                       orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c,
+                       &data->viewport_c.x,
+                       &data->viewport_c.width);
+       adjust_vp_and_init_for_seamless_clip(
+                       flip_vert_scan_dir,
+                       recout_skip_v,
+                       surf_size_v,
+                       orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps,
+                       orthogonal_rotation ? data->ratios.horz : data->ratios.vert,
+                       orthogonal_rotation ? &data->inits.h : &data->inits.v,
+                       &data->viewport.y,
+                       &data->viewport.height);
+       adjust_vp_and_init_for_seamless_clip(
+                       flip_vert_scan_dir,
+                       recout_skip_v,
+                       surf_size_v / vpc_div,
+                       orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c,
+                       orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c,
+                       orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c,
+                       &data->viewport_c.y,
+                       &data->viewport_c.height);
 
        /* Interlaced inits based on final vert inits */
        data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert);
        data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c);
 
-       if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
-                       pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
-               rect_swap_helper(&data->viewport_c);
-               rect_swap_helper(&data->viewport);
-       }
 }
 
 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
-       struct rect recout_full = { 0 };
        bool res = false;
        DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
        /* Important: scaling ratio calculation requires pixel format,
@@ -1115,9 +924,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
        pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
                        pipe_ctx->plane_state->format);
 
-       if (pipe_ctx->stream->timing.flags.INTERLACE)
-               pipe_ctx->stream->dst.height *= 2;
-
        calculate_scaling_ratios(pipe_ctx);
 
        calculate_viewport(pipe_ctx);
@@ -1125,7 +931,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
        if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16)
                return false;
 
-       calculate_recout(pipe_ctx, &recout_full);
+       calculate_recout(pipe_ctx);
 
        /**
         * Setting line buffer pixel depth to 24bpp yields banding
@@ -1138,9 +944,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
 
        pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
        pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
-       if (pipe_ctx->stream->timing.flags.INTERLACE)
-               pipe_ctx->plane_res.scl_data.v_active *= 2;
-
 
        /* Taps calculations */
        if (pipe_ctx->plane_res.xfm != NULL)
@@ -1169,7 +972,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
 
        if (res)
                /* May need to re-check lb size after this in some obscure scenario */
-               calculate_inits_and_adj_vp(pipe_ctx, &recout_full);
+               calculate_inits_and_adj_vp(pipe_ctx);
 
        DC_LOG_SCALER(
                                "%s: Viewport:\nheight:%d width:%d x:%d "
@@ -1185,9 +988,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
                                plane_state->dst_rect.x,
                                plane_state->dst_rect.y);
 
-       if (pipe_ctx->stream->timing.flags.INTERLACE)
-               pipe_ctx->stream->dst.height /= 2;
-
        return res;
 }
 
@@ -1382,6 +1182,9 @@ bool dc_add_plane_to_context(
                return false;
        }
 
+       tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
+       ASSERT(tail_pipe);
+
        free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
 
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@@ -1399,10 +1202,6 @@ bool dc_add_plane_to_context(
        free_pipe->plane_state = plane_state;
 
        if (head_pipe != free_pipe) {
-
-               tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
-               ASSERT(tail_pipe);
-
                free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
                free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
                free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
@@ -1648,6 +1447,14 @@ static bool are_stream_backends_same(
        return true;
 }
 
+/**
+ * dc_is_stream_unchanged() - Compare two stream states for equivalence.
+ *
+ * Checks if there a difference between the two states
+ * that would require a mode change.
+ *
+ * Does not compare cursor position or attributes.
+ */
 bool dc_is_stream_unchanged(
        struct dc_stream_state *old_stream, struct dc_stream_state *stream)
 {
@@ -1658,6 +1465,9 @@ bool dc_is_stream_unchanged(
        return true;
 }
 
+/**
+ * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
+ */
 bool dc_is_stream_scaling_unchanged(
        struct dc_stream_state *old_stream, struct dc_stream_state *stream)
 {
@@ -1817,16 +1627,19 @@ bool resource_is_stream_unchanged(
        return false;
 }
 
+/**
+ * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
+ */
 enum dc_status dc_add_stream_to_ctx(
                struct dc *dc,
                struct dc_state *new_ctx,
                struct dc_stream_state *stream)
 {
-       struct dc_context *dc_ctx = dc->ctx;
        enum dc_status res;
+       DC_LOGGER_INIT(dc->ctx->logger);
 
        if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) {
-               DC_ERROR("Max streams reached, can't add stream %p !\n", stream);
+               DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
                return DC_ERROR_UNEXPECTED;
        }
 
@@ -1836,11 +1649,14 @@ enum dc_status dc_add_stream_to_ctx(
 
        res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
        if (res != DC_OK)
-               DC_ERROR("Adding stream %p to context failed with err %d!\n", stream, res);
+               DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
 
        return res;
 }
 
+/**
+ * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
+ */
 enum dc_status dc_remove_stream_from_ctx(
                        struct dc *dc,
                        struct dc_state *new_ctx,
@@ -2002,6 +1818,8 @@ enum dc_status resource_map_pool_resources(
                }
        */
 
+       calculate_phy_pix_clks(stream);
+
        /* acquire new resources */
        pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
 
@@ -2059,6 +1877,12 @@ enum dc_status resource_map_pool_resources(
        return DC_ERROR_UNEXPECTED;
 }
 
+/**
+ * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
+ * Is a shallow copy.  Increments refcounts on existing streams and planes.
+ * @dc: copy out of dc->current_state
+ * @dst_ctx: copy into this
+ */
 void dc_resource_state_copy_construct_current(
                const struct dc *dc,
                struct dc_state *dst_ctx)
@@ -2071,9 +1895,17 @@ void dc_resource_state_construct(
                const struct dc *dc,
                struct dc_state *dst_ctx)
 {
-       dst_ctx->dis_clk = dc->res_pool->dccg;
+       dst_ctx->dccg = dc->res_pool->clk_mgr;
 }
 
+/**
+ * dc_validate_global_state() - Determine if HW can support a given state
+ * Checks HW resource availability and bandwidth requirement.
+ * @dc: dc struct for this driver
+ * @new_ctx: state to be validated
+ *
+ * Return: DC_OK if the result can be programmed.  Otherwise, an error code.
+ */
 enum dc_status dc_validate_global_state(
                struct dc *dc,
                struct dc_state *new_ctx)
@@ -2401,113 +2233,15 @@ static void set_vendor_info_packet(
                struct dc_info_packet *info_packet,
                struct dc_stream_state *stream)
 {
-       uint32_t length = 0;
-       bool hdmi_vic_mode = false;
-       uint8_t checksum = 0;
-       uint32_t i = 0;
-       enum dc_timing_3d_format format;
-       // Can be different depending on packet content /*todo*/
-       // unsigned int length = pPathMode->dolbyVision ? 24 : 5;
-
-       info_packet->valid = false;
-
-       format = stream->timing.timing_3d_format;
-       if (stream->view_format == VIEW_3D_FORMAT_NONE)
-               format = TIMING_3D_FORMAT_NONE;
-
-       /* Can be different depending on packet content */
-       length = 5;
-
-       if (stream->timing.hdmi_vic != 0
-                       && stream->timing.h_total >= 3840
-                       && stream->timing.v_total >= 2160)
-               hdmi_vic_mode = true;
-
-       /* According to HDMI 1.4a CTS, VSIF should be sent
-        * for both 3D stereo and HDMI VIC modes.
-        * For all other modes, there is no VSIF sent.  */
+       /* SPD info packet for FreeSync */
 
-       if (format == TIMING_3D_FORMAT_NONE && !hdmi_vic_mode)
+       /* Check if Freesync is supported. Return if false. If true,
+        * set the corresponding bit in the info packet
+        */
+       if (!stream->vsp_infopacket.valid)
                return;
 
-       /* 24bit IEEE Registration identifier (0x000c03). LSB first. */
-       info_packet->sb[1] = 0x03;
-       info_packet->sb[2] = 0x0C;
-       info_packet->sb[3] = 0x00;
-
-       /*PB4: 5 lower bytes = 0 (reserved). 3 higher bits = HDMI_Video_Format.
-        * The value for HDMI_Video_Format are:
-        * 0x0 (0b000) - No additional HDMI video format is presented in this
-        * packet
-        * 0x1 (0b001) - Extended resolution format present. 1 byte of HDMI_VIC
-        * parameter follows
-        * 0x2 (0b010) - 3D format indication present. 3D_Structure and
-        * potentially 3D_Ext_Data follows
-        * 0x3..0x7 (0b011..0b111) - reserved for future use */
-       if (format != TIMING_3D_FORMAT_NONE)
-               info_packet->sb[4] = (2 << 5);
-       else if (hdmi_vic_mode)
-               info_packet->sb[4] = (1 << 5);
-
-       /* PB5: If PB4 claims 3D timing (HDMI_Video_Format = 0x2):
-        * 4 lower bites = 0 (reserved). 4 higher bits = 3D_Structure.
-        * The value for 3D_Structure are:
-        * 0x0 - Frame Packing
-        * 0x1 - Field Alternative
-        * 0x2 - Line Alternative
-        * 0x3 - Side-by-Side (full)
-        * 0x4 - L + depth
-        * 0x5 - L + depth + graphics + graphics-depth
-        * 0x6 - Top-and-Bottom
-        * 0x7 - Reserved for future use
-        * 0x8 - Side-by-Side (Half)
-        * 0x9..0xE - Reserved for future use
-        * 0xF - Not used */
-       switch (format) {
-       case TIMING_3D_FORMAT_HW_FRAME_PACKING:
-       case TIMING_3D_FORMAT_SW_FRAME_PACKING:
-               info_packet->sb[5] = (0x0 << 4);
-               break;
-
-       case TIMING_3D_FORMAT_SIDE_BY_SIDE:
-       case TIMING_3D_FORMAT_SBS_SW_PACKED:
-               info_packet->sb[5] = (0x8 << 4);
-               length = 6;
-               break;
-
-       case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
-       case TIMING_3D_FORMAT_TB_SW_PACKED:
-               info_packet->sb[5] = (0x6 << 4);
-               break;
-
-       default:
-               break;
-       }
-
-       /*PB5: If PB4 is set to 0x1 (extended resolution format)
-        * fill PB5 with the correct HDMI VIC code */
-       if (hdmi_vic_mode)
-               info_packet->sb[5] = stream->timing.hdmi_vic;
-
-       /* Header */
-       info_packet->hb0 = HDMI_INFOFRAME_TYPE_VENDOR; /* VSIF packet type. */
-       info_packet->hb1 = 0x01; /* Version */
-
-       /* 4 lower bits = Length, 4 higher bits = 0 (reserved) */
-       info_packet->hb2 = (uint8_t) (length);
-
-       /* Calculate checksum */
-       checksum = 0;
-       checksum += info_packet->hb0;
-       checksum += info_packet->hb1;
-       checksum += info_packet->hb2;
-
-       for (i = 1; i <= length; i++)
-               checksum += info_packet->sb[i];
-
-       info_packet->sb[0] = (uint8_t) (0x100 - checksum);
-
-       info_packet->valid = true;
+       *info_packet = stream->vsp_infopacket;
 }
 
 static void set_spd_info_packet(
@@ -2563,10 +2297,6 @@ void dc_resource_state_destruct(struct dc_state *context)
        }
 }
 
-/*
- * Copy src_ctx into dst_ctx and retain all surfaces and streams referenced
- * by the src_ctx
- */
 void dc_resource_state_copy_construct(
                const struct dc_state *src_ctx,
                struct dc_state *dst_ctx)
index 2ac848a106bafc2a4588bcca1b02c23d409757a9..66e5c4623a49f8be5210ca782b6724728d3a7da4 100644 (file)
@@ -100,12 +100,11 @@ static void construct(struct dc_stream_state *stream,
        /* EDID CAP translation for HDMI 2.0 */
        stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
 
-       stream->status.link = stream->sink->link;
-
        update_stream_signal(stream);
 
        stream->out_transfer_func = dc_create_transfer_func();
        stream->out_transfer_func->type = TF_TYPE_BYPASS;
+       stream->out_transfer_func->ctx = stream->ctx;
 }
 
 static void destruct(struct dc_stream_state *stream)
@@ -171,7 +170,7 @@ struct dc_stream_status *dc_stream_get_status(
 }
 
 /**
- * Update the cursor attributes and set cursor surface address
+ * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address
  */
 bool dc_stream_set_cursor_attributes(
        struct dc_stream_state *stream,
index 8fb3aefd195ca3e384babcac8e002106f5cb9e1a..c60c9b4c307531e118ecd4f986985dfa4388ad00 100644 (file)
@@ -44,6 +44,7 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state
 
        plane_state->in_transfer_func = dc_create_transfer_func();
        plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
+       plane_state->in_transfer_func->ctx = ctx;
 }
 
 static void destruct(struct dc_plane_state *plane_state)
index b57fa61b3034a14869a2cee91423b7f7e0fa11e0..4b5bbb13ce7fedcbd8d1d9d1b1be39c2478a9634 100644 (file)
 
 #include "inc/hw_sequencer.h"
 #include "inc/compressor.h"
+#include "inc/hw/dmcu.h"
 #include "dml/display_mode_lib.h"
 
-#define DC_VER "3.1.68"
+#define DC_VER "3.2.08"
 
 #define MAX_SURFACES 3
 #define MAX_STREAMS 6
 /*******************************************************************************
  * Display Core Interfaces
  ******************************************************************************/
-struct dmcu_version {
-       unsigned int date;
-       unsigned int month;
-       unsigned int year;
-       unsigned int interface_version;
-};
-
 struct dc_versions {
        const char *dc_ver;
        struct dmcu_version dmcu_version;
@@ -250,8 +244,6 @@ struct dc_debug_options {
        bool disable_dmcu;
        bool disable_psr;
        bool force_abm_enable;
-       bool disable_hbup_pg;
-       bool disable_dpp_pg;
        bool disable_stereo_support;
        bool vsr_support;
        bool performance_trace;
@@ -305,11 +297,6 @@ struct dc {
        struct hw_sequencer_funcs hwss;
        struct dce_hwseq *hwseq;
 
-       /* temp store of dm_pp_display_configuration
-        * to compare to see if display config changed
-        */
-       struct dm_pp_display_configuration prev_display_config;
-
        bool optimized_required;
 
        /* FBC compressor */
@@ -755,5 +742,6 @@ void dc_set_power_state(
                struct dc *dc,
                enum dc_acpi_cm_power_state power_state);
 void dc_resume(struct dc *dc);
+bool dc_is_dmcu_initialized(struct dc *dc);
 
 #endif /* DC_INTERFACE_H_ */
index 8130b95ccc5349a18856cc0fd8b426444ef27ad0..a8b3cedf943171fbcdfbb9848f07e9edd5fa1875 100644 (file)
@@ -86,6 +86,10 @@ struct dc_vbios_funcs {
 
        bool (*is_accelerated_mode)(
                struct dc_bios *bios);
+       bool (*is_active_display)(
+               struct dc_bios *bios,
+               enum signal_type signal,
+               const struct connector_device_tag_info *device_tag);
        void (*set_scratch_critical_state)(
                struct dc_bios *bios,
                bool state);
@@ -141,6 +145,7 @@ struct dc_vbios_funcs {
 };
 
 struct bios_registers {
+       uint32_t BIOS_SCRATCH_0;
        uint32_t BIOS_SCRATCH_3;
        uint32_t BIOS_SCRATCH_6;
 };
index 7825e4b5e97c4c888c59dc55a7ee42c0472fb01c..9ddfe4c6938b5a1f65e65eb4e196e9899f4ad008 100644 (file)
@@ -358,15 +358,16 @@ union dc_tiling_info {
        } gfx8;
 
        struct {
+               enum swizzle_mode_values swizzle;
                unsigned int num_pipes;
-               unsigned int num_banks;
+               unsigned int max_compressed_frags;
                unsigned int pipe_interleave;
+
+               unsigned int num_banks;
                unsigned int num_shader_engines;
                unsigned int num_rb_per_se;
-               unsigned int max_compressed_frags;
                bool shaderEnable;
 
-               enum swizzle_mode_values swizzle;
                bool meta_linear;
                bool rb_aligned;
                bool pipe_aligned;
index 3bfdccceb524427c40ac0a2b063710c2bb66bbe3..29f19d57ff7abd1e132ba89e65caa5d4f6bb2161 100644 (file)
@@ -128,8 +128,10 @@ struct dc_link {
 
 const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link);
 
-/*
- * Return an enumerated dc_link.  dc_link order is constant and determined at
+/**
+ * dc_get_link_at_index() - Return an enumerated dc_link.
+ *
+ * dc_link order is constant and determined at
  * boot time.  They cannot be created or destroyed.
  * Use dc_get_caps() to get number of links.
  */
@@ -138,9 +140,14 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_
        return dc->links[link_index];
 }
 
-/* Set backlight level of an embedded panel (eDP, LVDS). */
-bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level,
-               uint32_t frame_ramp, const struct dc_stream_state *stream);
+/* Set backlight level of an embedded panel (eDP, LVDS).
+ * backlight_pwm_u16_16 is unsigned 32 bit with 16 bit integer
+ * and 16 bit fractional, where 1.0 is max backlight value.
+ */
+bool dc_link_set_backlight_level(const struct dc_link *dc_link,
+               uint32_t backlight_pwm_u16_16,
+               uint32_t frame_ramp,
+               const struct dc_stream_state *stream);
 
 int dc_link_get_backlight_level(const struct dc_link *dc_link);
 
index c5bd1fbb698241507b0561f4572f8c183845466a..be34d638e15dfee01416e82e38d209d102403fde 100644 (file)
@@ -56,6 +56,7 @@ struct dc_stream_state {
        struct dc_crtc_timing_adjust adjust;
        struct dc_info_packet vrr_infopacket;
        struct dc_info_packet vsc_infopacket;
+       struct dc_info_packet vsp_infopacket;
 
        struct rect src; /* composition area */
        struct rect dst; /* stream addressable area */
@@ -104,8 +105,6 @@ struct dc_stream_state {
        bool dpms_off;
        bool apply_edp_fast_boot_optimization;
 
-       struct dc_stream_status status;
-
        struct dc_cursor_attributes cursor_attributes;
        struct dc_cursor_position cursor_position;
        uint32_t sdr_white_level; // for boosting (SDR) cursor in HDR mode
@@ -131,11 +130,13 @@ struct dc_stream_update {
        struct dc_crtc_timing_adjust *adjust;
        struct dc_info_packet *vrr_infopacket;
        struct dc_info_packet *vsc_infopacket;
+       struct dc_info_packet *vsp_infopacket;
 
        bool *dpms_off;
 
        struct colorspace_transform *gamut_remap;
        enum dc_color_space *output_color_space;
+       enum dc_dither_option *dither_option;
 
        struct dc_csc_transform *output_csc_transform;
 
index 6e12d640d020940d887a66bf5d6c4037a7888735..0b20ae23f169241aae3368470a339ad32a5d7255 100644 (file)
@@ -73,10 +73,18 @@ struct hw_asic_id {
        void *atombios_base_address;
 };
 
+struct dc_perf_trace {
+       unsigned long read_count;
+       unsigned long write_count;
+       unsigned long last_entry_read;
+       unsigned long last_entry_write;
+};
+
 struct dc_context {
        struct dc *dc;
 
        void *driver_context; /* e.g. amdgpu_device */
+       struct dc_perf_trace *perf_trace;
        void *cgs_device;
 
        enum dce_environment dce_environment;
@@ -191,7 +199,6 @@ union display_content_support {
 };
 
 struct dc_panel_patch {
-       unsigned int disconnect_delay;
        unsigned int dppowerup_delay;
        unsigned int extra_t12_ms;
 };
index 8f7f0e8b341f234a0a30207718d111687bedc743..6d7b64a743cab77c98ff8595e702884cd090b659 100644 (file)
@@ -28,7 +28,7 @@
 
 DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \
 dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \
-dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \
+dce_clk_mgr.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \
 dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o
 
 AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE))
index 29294db1a96b775013635d080725e392cda4766b..2a342eae80fd2bd1cab42f25740a98df9a51d5ea 100644 (file)
@@ -54,7 +54,7 @@
 #define MCP_DISABLE_ABM_IMMEDIATELY 255
 
 
-static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
+static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_abm *abm_dce)
 {
        uint64_t current_backlight;
        uint32_t round_result;
@@ -103,45 +103,21 @@ static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
        return (uint32_t)(current_backlight);
 }
 
-static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
+static void driver_set_backlight_level(struct dce_abm *abm_dce,
+               uint32_t backlight_pwm_u16_16)
 {
-       uint32_t backlight_24bit;
-       uint32_t backlight_17bit;
        uint32_t backlight_16bit;
        uint32_t masked_pwm_period;
-       uint8_t rounding_bit;
        uint8_t bit_count;
        uint64_t active_duty_cycle;
        uint32_t pwm_period_bitcnt;
 
        /*
-        * 1. Convert 8-bit value to 17 bit U1.16 format
-        * (1 integer, 16 fractional bits)
-        */
-
-       /* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
-        * effectively multiplying value by 256/255
-        * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
-        */
-       backlight_24bit = level * 0x10101;
-
-       /* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
-        * used for rounding, take most significant bit of fraction for
-        * rounding, e.g. for 0xEFEFEF, rounding bit is 1
-        */
-       rounding_bit = (backlight_24bit >> 7) & 1;
-
-       /* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
-        * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
-        */
-       backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
-
-       /*
-        * 2. Find  16 bit backlight active duty cycle, where 0 <= backlight
+        * 1. Find  16 bit backlight active duty cycle, where 0 <= backlight
         * active duty cycle <= backlight period
         */
 
-       /* 2.1 Apply bitmask for backlight period value based on value of BITCNT
+       /* 1.1 Apply bitmask for backlight period value based on value of BITCNT
         */
        REG_GET_2(BL_PWM_PERIOD_CNTL,
                        BL_PWM_PERIOD_BITCNT, &pwm_period_bitcnt,
@@ -155,13 +131,13 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
        /* e.g. maskedPwmPeriod = 0x24 when bitCount is 6 */
        masked_pwm_period = masked_pwm_period & ((1 << bit_count) - 1);
 
-       /* 2.2 Calculate integer active duty cycle required upper 16 bits
+       /* 1.2 Calculate integer active duty cycle required upper 16 bits
         * contain integer component, lower 16 bits contain fractional component
         * of active duty cycle e.g. 0x21BDC0 = 0xEFF0 * 0x24
         */
-       active_duty_cycle = backlight_17bit * masked_pwm_period;
+       active_duty_cycle = backlight_pwm_u16_16 * masked_pwm_period;
 
-       /* 2.3 Calculate 16 bit active duty cycle from integer and fractional
+       /* 1.3 Calculate 16 bit active duty cycle from integer and fractional
         * components shift by bitCount then mask 16 bits and add rounding bit
         * from MSB of fraction e.g. 0x86F7 = ((0x21BDC0 >> 6) & 0xFFF) + 0
         */
@@ -170,23 +146,23 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
        backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;
 
        /*
-        * 3. Program register with updated value
+        * 2. Program register with updated value
         */
 
-       /* 3.1 Lock group 2 backlight registers */
+       /* 2.1 Lock group 2 backlight registers */
 
        REG_UPDATE_2(BL_PWM_GRP1_REG_LOCK,
                        BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN, 1,
                        BL_PWM_GRP1_REG_LOCK, 1);
 
-       // 3.2 Write new active duty cycle
+       // 2.2 Write new active duty cycle
        REG_UPDATE(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, backlight_16bit);
 
-       /* 3.3 Unlock group 2 backlight registers */
+       /* 2.3 Unlock group 2 backlight registers */
        REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
                        BL_PWM_GRP1_REG_LOCK, 0);
 
-       /* 5.4.4 Wait for pending bit to be cleared */
+       /* 3 Wait for pending bit to be cleared */
        REG_WAIT(BL_PWM_GRP1_REG_LOCK,
                        BL_PWM_GRP1_REG_UPDATE_PENDING, 0,
                        1, 10000);
@@ -194,16 +170,21 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
 
 static void dmcu_set_backlight_level(
        struct dce_abm *abm_dce,
-       uint32_t level,
+       uint32_t backlight_pwm_u16_16,
        uint32_t frame_ramp,
        uint32_t controller_id)
 {
-       unsigned int backlight_16_bit = (level * 0x10101) >> 8;
-       unsigned int backlight_17_bit = backlight_16_bit +
-                               (((backlight_16_bit & 0x80) >> 7) & 1);
+       unsigned int backlight_8_bit = 0;
        uint32_t rampingBoundary = 0xFFFF;
        uint32_t s2;
 
+       if (backlight_pwm_u16_16 & 0x10000)
+               // Check for max backlight condition
+               backlight_8_bit = 0xFF;
+       else
+               // Take MSB of fractional part since backlight is not max
+               backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
+
        /* set ramping boundary */
        REG_WRITE(MASTER_COMM_DATA_REG1, rampingBoundary);
 
@@ -220,7 +201,7 @@ static void dmcu_set_backlight_level(
                        0, 1, 80000);
 
        /* setDMCUParam_BL */
-       REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_17_bit);
+       REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16);
 
        /* write ramp */
        if (controller_id == 0)
@@ -237,9 +218,9 @@ static void dmcu_set_backlight_level(
        s2 = REG_READ(BIOS_SCRATCH_2);
 
        s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
-       level &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
+       backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
                                ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
-       s2 |= (level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
+       s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
 
        REG_WRITE(BIOS_SCRATCH_2, s2);
 }
@@ -247,7 +228,7 @@ static void dmcu_set_backlight_level(
 static void dce_abm_init(struct abm *abm)
 {
        struct dce_abm *abm_dce = TO_DCE_ABM(abm);
-       unsigned int backlight = get_current_backlight_16_bit(abm_dce);
+       unsigned int backlight = calculate_16_bit_backlight_from_pwm(abm_dce);
 
        REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
        REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
@@ -284,12 +265,26 @@ static void dce_abm_init(struct abm *abm)
                        ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
 }
 
-static unsigned int dce_abm_get_current_backlight_8_bit(struct abm *abm)
+static unsigned int dce_abm_get_current_backlight(struct abm *abm)
 {
        struct dce_abm *abm_dce = TO_DCE_ABM(abm);
        unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
 
-       return (backlight >> 8);
+       /* return backlight in hardware format which is unsigned 17 bits, with
+        * 1 bit integer and 16 bit fractional
+        */
+       return backlight;
+}
+
+static unsigned int dce_abm_get_target_backlight(struct abm *abm)
+{
+       struct dce_abm *abm_dce = TO_DCE_ABM(abm);
+       unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
+
+       /* return backlight in hardware format which is unsigned 17 bits, with
+        * 1 bit integer and 16 bit fractional
+        */
+       return backlight;
 }
 
 static bool dce_abm_set_level(struct abm *abm, uint32_t level)
@@ -396,9 +391,9 @@ static bool dce_abm_init_backlight(struct abm *abm)
        return true;
 }
 
-static bool dce_abm_set_backlight_level(
+static bool dce_abm_set_backlight_level_pwm(
                struct abm *abm,
-               unsigned int backlight_level,
+               unsigned int backlight_pwm_u16_16,
                unsigned int frame_ramp,
                unsigned int controller_id,
                bool use_smooth_brightness)
@@ -406,16 +401,16 @@ static bool dce_abm_set_backlight_level(
        struct dce_abm *abm_dce = TO_DCE_ABM(abm);
 
        DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
-                       backlight_level, backlight_level);
+                       backlight_pwm_u16_16, backlight_pwm_u16_16);
 
        /* If DMCU is in reset state, DMCU is uninitialized */
        if (use_smooth_brightness)
                dmcu_set_backlight_level(abm_dce,
-                               backlight_level,
+                               backlight_pwm_u16_16,
                                frame_ramp,
                                controller_id);
        else
-               driver_set_backlight_level(abm_dce, backlight_level);
+               driver_set_backlight_level(abm_dce, backlight_pwm_u16_16);
 
        return true;
 }
@@ -424,8 +419,9 @@ static const struct abm_funcs dce_funcs = {
        .abm_init = dce_abm_init,
        .set_abm_level = dce_abm_set_level,
        .init_backlight = dce_abm_init_backlight,
-       .set_backlight_level = dce_abm_set_backlight_level,
-       .get_current_backlight_8_bit = dce_abm_get_current_backlight_8_bit,
+       .set_backlight_level_pwm = dce_abm_set_backlight_level_pwm,
+       .get_current_backlight = dce_abm_get_current_backlight,
+       .get_target_backlight = dce_abm_get_target_backlight,
        .set_abm_immediate_disable = dce_abm_immediate_disable
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
new file mode 100644 (file)
index 0000000..bd22f51
--- /dev/null
@@ -0,0 +1,884 @@
+/*
+ * Copyright 2012-16 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dce_clk_mgr.h"
+
+#include "reg_helper.h"
+#include "dmcu.h"
+#include "core_types.h"
+#include "dal_asic_id.h"
+
+#define TO_DCE_CLK_MGR(clocks)\
+       container_of(clocks, struct dce_clk_mgr, base)
+
+#define REG(reg) \
+       (clk_mgr_dce->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+       clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name
+
+#define CTX \
+       clk_mgr_dce->base.ctx
+#define DC_LOGGER \
+       clk_mgr->ctx->logger
+
+/* Max clock values for each state indexed by "enum clocks_state": */
+static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
+/* ClocksStateInvalid - should not be used */
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/* ClocksStateLow */
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
+/* ClocksStateNominal */
+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
+/* ClocksStatePerformance */
+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
+
+static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
+
+static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
+
+static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
+
+int dentist_get_divider_from_did(int did)
+{
+       if (did < DENTIST_BASE_DID_1)
+               did = DENTIST_BASE_DID_1;
+       if (did > DENTIST_MAX_DID)
+               did = DENTIST_MAX_DID;
+
+       if (did < DENTIST_BASE_DID_2) {
+               return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
+                                                       * (did - DENTIST_BASE_DID_1);
+       } else if (did < DENTIST_BASE_DID_3) {
+               return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
+                                                       * (did - DENTIST_BASE_DID_2);
+       } else if (did < DENTIST_BASE_DID_4) {
+               return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
+                                                       * (did - DENTIST_BASE_DID_3);
+       } else {
+               return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
+                                                       * (did - DENTIST_BASE_DID_4);
+       }
+}
+
+/* SW will adjust DP REF Clock average value for all purposes
+ * (DP DTO / DP Audio DTO and DP GTC)
+ if clock is spread for all cases:
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
+ calculations for DS_INCR/DS_MODULO (this is planned to be default case)
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
+ calculations (not planned to be used, but average clock should still
+ be valid)
+ -if SS enabled on DP Ref clock and HW de-spreading disabled
+ (should not be case with CIK) then SW should program all rates
+ generated according to average value (case as with previous ASICs)
+  */
+static int clk_mgr_adjust_dp_ref_freq_for_ss(struct dce_clk_mgr *clk_mgr_dce, int dp_ref_clk_khz)
+{
+       if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
+               struct fixed31_32 ss_percentage = dc_fixpt_div_int(
+                               dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
+                                                       clk_mgr_dce->dprefclk_ss_divider), 200);
+               struct fixed31_32 adj_dp_ref_clk_khz;
+
+               ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
+               adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
+               dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
+       }
+       return dp_ref_clk_khz;
+}
+
+static int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       int dprefclk_wdivider;
+       int dprefclk_src_sel;
+       int dp_ref_clk_khz = 600000;
+       int target_div;
+
+       /* ASSERT DP Reference Clock source is from DFS*/
+       REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
+       ASSERT(dprefclk_src_sel == 0);
+
+       /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
+        * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
+       REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
+
+       /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
+       target_div = dentist_get_divider_from_did(dprefclk_wdivider);
+
+       /* Calculate the current DFS clock, in kHz.*/
+       dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+               * clk_mgr_dce->dentist_vco_freq_khz) / target_div;
+
+       return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, dp_ref_clk_khz);
+}
+
+int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+
+       return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_dce->dprefclk_khz);
+}
+
+/* unit: in_khz before mode set, get pixel clock from context. ASIC register
+ * may not be programmed yet
+ */
+static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context)
+{
+       uint32_t max_pix_clk = 0;
+       int i;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               if (pipe_ctx->stream == NULL)
+                       continue;
+
+               /* do not check under lay */
+               if (pipe_ctx->top_pipe)
+                       continue;
+
+               if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
+                       max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+
+               /* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
+                * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
+                */
+               if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
+                               pipe_ctx->stream_res.pix_clk_params.requested_sym_clk > max_pix_clk)
+                       max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_sym_clk;
+       }
+
+       return max_pix_clk;
+}
+
+static enum dm_pp_clocks_state dce_get_required_clocks_state(
+       struct clk_mgr *clk_mgr,
+       struct dc_state *context)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       int i;
+       enum dm_pp_clocks_state low_req_clk;
+       int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
+
+       /* Iterate from highest supported to lowest valid state, and update
+        * lowest RequiredState with the lowest state that satisfies
+        * all required clocks
+        */
+       for (i = clk_mgr_dce->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
+               if (context->bw.dce.dispclk_khz >
+                               clk_mgr_dce->max_clks_by_state[i].display_clk_khz
+                       || max_pix_clk >
+                               clk_mgr_dce->max_clks_by_state[i].pixel_clk_khz)
+                       break;
+
+       low_req_clk = i + 1;
+       if (low_req_clk > clk_mgr_dce->max_clks_state) {
+               /* set max clock state for high phyclock, invalid on exceeding display clock */
+               if (clk_mgr_dce->max_clks_by_state[clk_mgr_dce->max_clks_state].display_clk_khz
+                               < context->bw.dce.dispclk_khz)
+                       low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
+               else
+                       low_req_clk = clk_mgr_dce->max_clks_state;
+       }
+
+       return low_req_clk;
+}
+
+static int dce_set_clock(
+       struct clk_mgr *clk_mgr,
+       int requested_clk_khz)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
+       struct dc_bios *bp = clk_mgr->ctx->dc_bios;
+       int actual_clock = requested_clk_khz;
+       struct dmcu *dmcu = clk_mgr_dce->base.ctx->dc->res_pool->dmcu;
+
+       /* Make sure requested clock isn't lower than minimum threshold*/
+       if (requested_clk_khz > 0)
+               requested_clk_khz = max(requested_clk_khz,
+                               clk_mgr_dce->dentist_vco_freq_khz / 64);
+
+       /* Prepare to program display clock*/
+       pxl_clk_params.target_pixel_clock = requested_clk_khz;
+       pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+
+       if (clk_mgr_dce->dfs_bypass_active)
+               pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
+
+       bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
+
+       if (clk_mgr_dce->dfs_bypass_active) {
+               /* Cache the fixed display clock*/
+               clk_mgr_dce->dfs_bypass_disp_clk =
+                       pxl_clk_params.dfs_bypass_display_clock;
+               actual_clock = pxl_clk_params.dfs_bypass_display_clock;
+       }
+
+       /* from power down, we need mark the clock state as ClocksStateNominal
+        * from HWReset, so when resume we will call pplib voltage regulator.*/
+       if (requested_clk_khz == 0)
+               clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+
+       if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
+               dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7);
+
+       return actual_clock;
+}
+
+int dce112_set_clock(struct clk_mgr *clk_mgr, int requested_clk_khz)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct bp_set_dce_clock_parameters dce_clk_params;
+       struct dc_bios *bp = clk_mgr->ctx->dc_bios;
+       struct dc *core_dc = clk_mgr->ctx->dc;
+       struct dmcu *dmcu = core_dc->res_pool->dmcu;
+       int actual_clock = requested_clk_khz;
+       /* Prepare to program display clock*/
+       memset(&dce_clk_params, 0, sizeof(dce_clk_params));
+
+       /* Make sure requested clock isn't lower than minimum threshold*/
+       if (requested_clk_khz > 0)
+               requested_clk_khz = max(requested_clk_khz,
+                               clk_mgr_dce->dentist_vco_freq_khz / 62);
+
+       dce_clk_params.target_clock_frequency = requested_clk_khz;
+       dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+       dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
+
+       bp->funcs->set_dce_clock(bp, &dce_clk_params);
+       actual_clock = dce_clk_params.target_clock_frequency;
+
+       /* from power down, we need mark the clock state as ClocksStateNominal
+        * from HWReset, so when resume we will call pplib voltage regulator.*/
+       if (requested_clk_khz == 0)
+               clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+
+       /*Program DP ref Clock*/
+       /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
+       dce_clk_params.target_clock_frequency = 0;
+       dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
+       if (!ASICREV_IS_VEGA20_P(clk_mgr->ctx->asic_id.hw_internal_rev))
+               dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
+                       (dce_clk_params.pll_id ==
+                                       CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
+       else
+               dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
+
+       bp->funcs->set_dce_clock(bp, &dce_clk_params);
+
+       if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+               if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
+                       if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock)
+                               dmcu->funcs->set_psr_wait_loop(dmcu,
+                                               actual_clock / 1000 / 7);
+               }
+       }
+
+       clk_mgr_dce->dfs_bypass_disp_clk = actual_clock;
+       return actual_clock;
+}
+
+static void dce_clock_read_integrated_info(struct dce_clk_mgr *clk_mgr_dce)
+{
+       struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug;
+       struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+       struct integrated_info info = { { { 0 } } };
+       struct dc_firmware_info fw_info = { { 0 } };
+       int i;
+
+       if (bp->integrated_info)
+               info = *bp->integrated_info;
+
+       clk_mgr_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
+       if (clk_mgr_dce->dentist_vco_freq_khz == 0) {
+               bp->funcs->get_firmware_info(bp, &fw_info);
+               clk_mgr_dce->dentist_vco_freq_khz =
+                       fw_info.smu_gpu_pll_output_freq;
+               if (clk_mgr_dce->dentist_vco_freq_khz == 0)
+                       clk_mgr_dce->dentist_vco_freq_khz = 3600000;
+       }
+
+       /*update the maximum display clock for each power state*/
+       for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
+               enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
+
+               switch (i) {
+               case 0:
+                       clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
+                       break;
+
+               case 1:
+                       clk_state = DM_PP_CLOCKS_STATE_LOW;
+                       break;
+
+               case 2:
+                       clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
+                       break;
+
+               case 3:
+                       clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
+                       break;
+
+               default:
+                       clk_state = DM_PP_CLOCKS_STATE_INVALID;
+                       break;
+               }
+
+               /*Do not allow bad VBIOS/SBIOS to override with invalid values,
+                * check for > 100MHz*/
+               if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
+                       clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz =
+                               info.disp_clk_voltage[i].max_supported_clk;
+       }
+
+       if (!debug->disable_dfs_bypass && bp->integrated_info)
+               if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
+                       clk_mgr_dce->dfs_bypass_enabled = true;
+}
+
+void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
+{
+       struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+       int ss_info_num = bp->funcs->get_ss_entry_number(
+                       bp, AS_SIGNAL_TYPE_GPU_PLL);
+
+       if (ss_info_num) {
+               struct spread_spectrum_info info = { { 0 } };
+               enum bp_result result = bp->funcs->get_spread_spectrum_info(
+                               bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
+
+               /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
+                * even if SS not enabled and in that case
+                * SSInfo.spreadSpectrumPercentage !=0 would be sign
+                * that SS is enabled
+                */
+               if (result == BP_RESULT_OK &&
+                               info.spread_spectrum_percentage != 0) {
+                       clk_mgr_dce->ss_on_dprefclk = true;
+                       clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+                       if (info.type.CENTER_MODE == 0) {
+                               /* TODO: Currently for DP Reference clock we
+                                * need only SS percentage for
+                                * downspread */
+                               clk_mgr_dce->dprefclk_ss_percentage =
+                                               info.spread_spectrum_percentage;
+                       }
+
+                       return;
+               }
+
+               result = bp->funcs->get_spread_spectrum_info(
+                               bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
+
+               /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
+                * even if SS not enabled and in that case
+                * SSInfo.spreadSpectrumPercentage !=0 would be sign
+                * that SS is enabled
+                */
+               if (result == BP_RESULT_OK &&
+                               info.spread_spectrum_percentage != 0) {
+                       clk_mgr_dce->ss_on_dprefclk = true;
+                       clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+                       if (info.type.CENTER_MODE == 0) {
+                               /* Currently for DP Reference clock we
+                                * need only SS percentage for
+                                * downspread */
+                               clk_mgr_dce->dprefclk_ss_percentage =
+                                               info.spread_spectrum_percentage;
+                       }
+               }
+       }
+}
+
+void dce110_fill_display_configs(
+       const struct dc_state *context,
+       struct dm_pp_display_configuration *pp_display_cfg)
+{
+       int j;
+       int num_cfgs = 0;
+
+       for (j = 0; j < context->stream_count; j++) {
+               int k;
+
+               const struct dc_stream_state *stream = context->streams[j];
+               struct dm_pp_single_disp_config *cfg =
+                       &pp_display_cfg->disp_configs[num_cfgs];
+               const struct pipe_ctx *pipe_ctx = NULL;
+
+               for (k = 0; k < MAX_PIPES; k++)
+                       if (stream == context->res_ctx.pipe_ctx[k].stream) {
+                               pipe_ctx = &context->res_ctx.pipe_ctx[k];
+                               break;
+                       }
+
+               ASSERT(pipe_ctx != NULL);
+
+               /* only notify active stream */
+               if (stream->dpms_off)
+                       continue;
+
+               num_cfgs++;
+               cfg->signal = pipe_ctx->stream->signal;
+               cfg->pipe_idx = pipe_ctx->stream_res.tg->inst;
+               cfg->src_height = stream->src.height;
+               cfg->src_width = stream->src.width;
+               cfg->ddi_channel_mapping =
+                       stream->sink->link->ddi_channel_mapping.raw;
+               cfg->transmitter =
+                       stream->sink->link->link_enc->transmitter;
+               cfg->link_settings.lane_count =
+                       stream->sink->link->cur_link_settings.lane_count;
+               cfg->link_settings.link_rate =
+                       stream->sink->link->cur_link_settings.link_rate;
+               cfg->link_settings.link_spread =
+                       stream->sink->link->cur_link_settings.link_spread;
+               cfg->sym_clock = stream->phy_pix_clk;
+               /* Round v_refresh*/
+               cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
+               cfg->v_refresh /= stream->timing.h_total;
+               cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
+                                                       / stream->timing.v_total;
+       }
+
+       pp_display_cfg->display_count = num_cfgs;
+}
+
+static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
+{
+       uint8_t j;
+       uint32_t min_vertical_blank_time = -1;
+
+       for (j = 0; j < context->stream_count; j++) {
+               struct dc_stream_state *stream = context->streams[j];
+               uint32_t vertical_blank_in_pixels = 0;
+               uint32_t vertical_blank_time = 0;
+
+               vertical_blank_in_pixels = stream->timing.h_total *
+                       (stream->timing.v_total
+                        - stream->timing.v_addressable);
+
+               vertical_blank_time = vertical_blank_in_pixels
+                       * 1000 / stream->timing.pix_clk_khz;
+
+               if (min_vertical_blank_time > vertical_blank_time)
+                       min_vertical_blank_time = vertical_blank_time;
+       }
+
+       return min_vertical_blank_time;
+}
+
+static int determine_sclk_from_bounding_box(
+               const struct dc *dc,
+               int required_sclk)
+{
+       int i;
+
+       /*
+        * Some asics do not give us sclk levels, so we just report the actual
+        * required sclk
+        */
+       if (dc->sclk_lvls.num_levels == 0)
+               return required_sclk;
+
+       for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
+               if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
+                       return dc->sclk_lvls.clocks_in_khz[i];
+       }
+       /*
+        * even maximum level could not satisfy requirement, this
+        * is unexpected at this stage, should have been caught at
+        * validation time
+        */
+       ASSERT(0);
+       return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
+}
+
+static void dce_pplib_apply_display_requirements(
+       struct dc *dc,
+       struct dc_state *context)
+{
+       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+       pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
+
+       dce110_fill_display_configs(context, pp_display_cfg);
+
+       if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) !=  0)
+               dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static void dce11_pplib_apply_display_requirements(
+       struct dc *dc,
+       struct dc_state *context)
+{
+       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+       pp_display_cfg->all_displays_in_sync =
+               context->bw.dce.all_displays_in_sync;
+       pp_display_cfg->nb_pstate_switch_disable =
+                       context->bw.dce.nbp_state_change_enable == false;
+       pp_display_cfg->cpu_cc6_disable =
+                       context->bw.dce.cpuc_state_change_enable == false;
+       pp_display_cfg->cpu_pstate_disable =
+                       context->bw.dce.cpup_state_change_enable == false;
+       pp_display_cfg->cpu_pstate_separation_time =
+                       context->bw.dce.blackout_recovery_time_us;
+
+       pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
+               / MEMORY_TYPE_MULTIPLIER_CZ;
+
+       pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
+                       dc,
+                       context->bw.dce.sclk_khz);
+
+       pp_display_cfg->min_dcfclock_khz = pp_display_cfg->min_engine_clock_khz;
+
+       pp_display_cfg->min_engine_clock_deep_sleep_khz
+                       = context->bw.dce.sclk_deep_sleep_khz;
+
+       pp_display_cfg->avail_mclk_switch_time_us =
+                                               dce110_get_min_vblank_time_us(context);
+       /* TODO: dce11.2*/
+       pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
+
+       pp_display_cfg->disp_clk_khz = dc->res_pool->clk_mgr->clks.dispclk_khz;
+
+       dce110_fill_display_configs(context, pp_display_cfg);
+
+       /* TODO: is this still applicable?*/
+       if (pp_display_cfg->display_count == 1) {
+               const struct dc_crtc_timing *timing =
+                       &context->streams[0]->timing;
+
+               pp_display_cfg->crtc_index =
+                       pp_display_cfg->disp_configs[0].pipe_idx;
+               pp_display_cfg->line_time_in_us = timing->h_total * 1000 / timing->pix_clk_khz;
+       }
+
+       if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) !=  0)
+               dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static void dce_update_clocks(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct dm_pp_power_level_change_request level_change_req;
+       int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+
+       /*TODO: W/A for dal3 linux, investigate why this works */
+       if (!clk_mgr_dce->dfs_bypass_active)
+               context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+
+       level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+       /* get max clock state from PPLIB */
+       if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+                       || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+               if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+                       clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+       }
+
+       if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+               context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+               clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz; 
+       }
+       dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+
+       context->bw.dce.dispclk_khz = unpatched_disp_clk;
+}
+
+static void dce11_update_clocks(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct dm_pp_power_level_change_request level_change_req;
+
+       level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+       /* get max clock state from PPLIB */
+       if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+                       || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+               if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+                       clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+       }
+
+       if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+               context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+               clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+       }
+       dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+}
+
+static void dce112_update_clocks(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct dm_pp_power_level_change_request level_change_req;
+
+       level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+       /* get max clock state from PPLIB */
+       if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+                       || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+               if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+                       clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+       }
+
+       if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+               context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+               clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+       }
+       dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+}
+
+static void dce12_update_clocks(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+       struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
+       int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
+       int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+
+       /*TODO: W/A for dal3 linux, investigate why this works */
+       if (!clk_mgr_dce->dfs_bypass_active)
+               context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+
+       if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
+               clock_voltage_req.clocks_in_khz = context->bw.dce.dispclk_khz;
+               context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+               clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+
+               dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
+       }
+
+       if (should_set_clock(safe_to_lower, max_pix_clk, clk_mgr->clks.phyclk_khz)) {
+               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK;
+               clock_voltage_req.clocks_in_khz = max_pix_clk;
+               clk_mgr->clks.phyclk_khz = max_pix_clk;
+
+               dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
+       }
+       dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+
+       context->bw.dce.dispclk_khz = unpatched_disp_clk;
+}
+
+static const struct clk_mgr_funcs dce120_funcs = {
+       .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+       .update_clocks = dce12_update_clocks
+};
+
+static const struct clk_mgr_funcs dce112_funcs = {
+       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+       .update_clocks = dce112_update_clocks
+};
+
+static const struct clk_mgr_funcs dce110_funcs = {
+       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+       .update_clocks = dce11_update_clocks,
+};
+
+static const struct clk_mgr_funcs dce_funcs = {
+       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+       .update_clocks = dce_update_clocks
+};
+
+static void dce_clk_mgr_construct(
+       struct dce_clk_mgr *clk_mgr_dce,
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask)
+{
+       struct clk_mgr *base = &clk_mgr_dce->base;
+       struct dm_pp_static_clock_info static_clk_info = {0};
+
+       base->ctx = ctx;
+       base->funcs = &dce_funcs;
+
+       clk_mgr_dce->regs = regs;
+       clk_mgr_dce->clk_mgr_shift = clk_shift;
+       clk_mgr_dce->clk_mgr_mask = clk_mask;
+
+       clk_mgr_dce->dfs_bypass_disp_clk = 0;
+
+       clk_mgr_dce->dprefclk_ss_percentage = 0;
+       clk_mgr_dce->dprefclk_ss_divider = 1000;
+       clk_mgr_dce->ss_on_dprefclk = false;
+
+
+       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
+               clk_mgr_dce->max_clks_state = static_clk_info.max_clocks_state;
+       else
+               clk_mgr_dce->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+       clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
+
+       dce_clock_read_integrated_info(clk_mgr_dce);
+       dce_clock_read_ss_info(clk_mgr_dce);
+}
+
+struct clk_mgr *dce_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask)
+{
+       struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+       if (clk_mgr_dce == NULL) {
+               BREAK_TO_DEBUGGER();
+               return NULL;
+       }
+
+       memcpy(clk_mgr_dce->max_clks_by_state,
+               dce80_max_clks_by_state,
+               sizeof(dce80_max_clks_by_state));
+
+       dce_clk_mgr_construct(
+               clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+       return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce110_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask)
+{
+       struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+       if (clk_mgr_dce == NULL) {
+               BREAK_TO_DEBUGGER();
+               return NULL;
+       }
+
+       memcpy(clk_mgr_dce->max_clks_by_state,
+               dce110_max_clks_by_state,
+               sizeof(dce110_max_clks_by_state));
+
+       dce_clk_mgr_construct(
+               clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+       clk_mgr_dce->base.funcs = &dce110_funcs;
+
+       return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce112_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask)
+{
+       struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+       if (clk_mgr_dce == NULL) {
+               BREAK_TO_DEBUGGER();
+               return NULL;
+       }
+
+       memcpy(clk_mgr_dce->max_clks_by_state,
+               dce112_max_clks_by_state,
+               sizeof(dce112_max_clks_by_state));
+
+       dce_clk_mgr_construct(
+               clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+       clk_mgr_dce->base.funcs = &dce112_funcs;
+
+       return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx)
+{
+       struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+       if (clk_mgr_dce == NULL) {
+               BREAK_TO_DEBUGGER();
+               return NULL;
+       }
+
+       memcpy(clk_mgr_dce->max_clks_by_state,
+               dce120_max_clks_by_state,
+               sizeof(dce120_max_clks_by_state));
+
+       dce_clk_mgr_construct(
+               clk_mgr_dce, ctx, NULL, NULL, NULL);
+
+       clk_mgr_dce->dprefclk_khz = 600000;
+       clk_mgr_dce->base.funcs = &dce120_funcs;
+
+       return &clk_mgr_dce->base;
+}
+
+void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr)
+{
+       struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr);
+
+       kfree(clk_mgr_dce);
+       *clk_mgr = NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
new file mode 100644 (file)
index 0000000..3bceb31
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2012-16 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef _DCE_CLK_MGR_H_
+#define _DCE_CLK_MGR_H_
+
+#include "clk_mgr.h"
+#include "dccg.h"
+
+#define MEMORY_TYPE_MULTIPLIER_CZ 4
+
+#define CLK_COMMON_REG_LIST_DCE_BASE() \
+       .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \
+       .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL
+
+#define CLK_COMMON_REG_LIST_DCN_BASE() \
+       SR(DENTIST_DISPCLK_CNTL)
+
+#define CLK_SF(reg_name, field_name, post_fix)\
+       .field_name = reg_name ## __ ## field_name ## post_fix
+
+#define CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) \
+       CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \
+       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh)
+
+#define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \
+       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\
+       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh)
+
+#define CLK_REG_FIELD_LIST(type) \
+       type DPREFCLK_SRC_SEL; \
+       type DENTIST_DPREFCLK_WDIVIDER; \
+       type DENTIST_DISPCLK_WDIVIDER; \
+       type DENTIST_DISPCLK_CHG_DONE;
+
+struct clk_mgr_shift {
+       CLK_REG_FIELD_LIST(uint8_t)
+};
+
+struct clk_mgr_mask {
+       CLK_REG_FIELD_LIST(uint32_t)
+};
+
+struct clk_mgr_registers {
+       uint32_t DPREFCLK_CNTL;
+       uint32_t DENTIST_DISPCLK_CNTL;
+};
+
+struct state_dependent_clocks {
+       int display_clk_khz;
+       int pixel_clk_khz;
+};
+
+struct dce_clk_mgr {
+       struct clk_mgr base;
+       const struct clk_mgr_registers *regs;
+       const struct clk_mgr_shift *clk_mgr_shift;
+       const struct clk_mgr_mask *clk_mgr_mask;
+
+       struct dccg *dccg;
+
+       struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES];
+
+       int dentist_vco_freq_khz;
+
+       /* Cache the status of DFS-bypass feature*/
+       bool dfs_bypass_enabled;
+       /* True if the DFS-bypass feature is enabled and active. */
+       bool dfs_bypass_active;
+       /* Cache the display clock returned by VBIOS if DFS-bypass is enabled.
+        * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
+       int dfs_bypass_disp_clk;
+
+       /* Flag for Enabled SS on DPREFCLK */
+       bool ss_on_dprefclk;
+       /* DPREFCLK SS percentage (if down-spread enabled) */
+       int dprefclk_ss_percentage;
+       /* DPREFCLK SS percentage Divider (100 or 1000) */
+       int dprefclk_ss_divider;
+       int dprefclk_khz;
+
+       enum dm_pp_clocks_state max_clks_state;
+       enum dm_pp_clocks_state cur_min_clks_state;
+};
+
+/* Starting DID for each range */
+enum dentist_base_divider_id {
+       DENTIST_BASE_DID_1 = 0x08,
+       DENTIST_BASE_DID_2 = 0x40,
+       DENTIST_BASE_DID_3 = 0x60,
+       DENTIST_BASE_DID_4 = 0x7e,
+       DENTIST_MAX_DID = 0x7f
+};
+
+/* Starting point and step size for each divider range.*/
+enum dentist_divider_range {
+       DENTIST_DIVIDER_RANGE_1_START = 8,   /* 2.00  */
+       DENTIST_DIVIDER_RANGE_1_STEP  = 1,   /* 0.25  */
+       DENTIST_DIVIDER_RANGE_2_START = 64,  /* 16.00 */
+       DENTIST_DIVIDER_RANGE_2_STEP  = 2,   /* 0.50  */
+       DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
+       DENTIST_DIVIDER_RANGE_3_STEP  = 4,   /* 1.00  */
+       DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
+       DENTIST_DIVIDER_RANGE_4_STEP  = 264, /* 66.00 */
+       DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
+};
+
+static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk)
+{
+       return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk);
+}
+
+void dce_clock_read_ss_info(struct dce_clk_mgr *dccg_dce);
+
+int dce12_get_dp_ref_freq_khz(struct clk_mgr *dccg);
+
+void dce110_fill_display_configs(
+       const struct dc_state *context,
+       struct dm_pp_display_configuration *pp_display_cfg);
+
+int dce112_set_clock(struct clk_mgr *dccg, int requested_clk_khz);
+
+struct clk_mgr *dce_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask);
+
+struct clk_mgr *dce110_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask);
+
+struct clk_mgr *dce112_clk_mgr_create(
+       struct dc_context *ctx,
+       const struct clk_mgr_registers *regs,
+       const struct clk_mgr_shift *clk_shift,
+       const struct clk_mgr_mask *clk_mask);
+
+struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx);
+
+void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr);
+
+int dentist_get_divider_from_did(int did);
+
+#endif /* _DCE_CLK_MGR_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c
deleted file mode 100644 (file)
index d89a097..0000000
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#include "dce_clocks.h"
-#include "dm_services.h"
-#include "reg_helper.h"
-#include "fixed31_32.h"
-#include "bios_parser_interface.h"
-#include "dc.h"
-#include "dmcu.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-#include "dcn_calcs.h"
-#endif
-#include "core_types.h"
-#include "dc_types.h"
-#include "dal_asic_id.h"
-
-#define TO_DCE_CLOCKS(clocks)\
-       container_of(clocks, struct dce_dccg, base)
-
-#define REG(reg) \
-       (clk_dce->regs->reg)
-
-#undef FN
-#define FN(reg_name, field_name) \
-       clk_dce->clk_shift->field_name, clk_dce->clk_mask->field_name
-
-#define CTX \
-       clk_dce->base.ctx
-#define DC_LOGGER \
-       clk->ctx->logger
-
-/* Max clock values for each state indexed by "enum clocks_state": */
-static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
-/* ClocksStateInvalid - should not be used */
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/* ClocksStateLow */
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
-/* ClocksStateNominal */
-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
-/* ClocksStatePerformance */
-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
-
-static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
-
-static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
-
-static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
-
-/* Starting DID for each range */
-enum dentist_base_divider_id {
-       DENTIST_BASE_DID_1 = 0x08,
-       DENTIST_BASE_DID_2 = 0x40,
-       DENTIST_BASE_DID_3 = 0x60,
-       DENTIST_BASE_DID_4 = 0x7e,
-       DENTIST_MAX_DID = 0x7f
-};
-
-/* Starting point and step size for each divider range.*/
-enum dentist_divider_range {
-       DENTIST_DIVIDER_RANGE_1_START = 8,   /* 2.00  */
-       DENTIST_DIVIDER_RANGE_1_STEP  = 1,   /* 0.25  */
-       DENTIST_DIVIDER_RANGE_2_START = 64,  /* 16.00 */
-       DENTIST_DIVIDER_RANGE_2_STEP  = 2,   /* 0.50  */
-       DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
-       DENTIST_DIVIDER_RANGE_3_STEP  = 4,   /* 1.00  */
-       DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
-       DENTIST_DIVIDER_RANGE_4_STEP  = 264, /* 66.00 */
-       DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
-};
-
-static int dentist_get_divider_from_did(int did)
-{
-       if (did < DENTIST_BASE_DID_1)
-               did = DENTIST_BASE_DID_1;
-       if (did > DENTIST_MAX_DID)
-               did = DENTIST_MAX_DID;
-
-       if (did < DENTIST_BASE_DID_2) {
-               return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
-                                                       * (did - DENTIST_BASE_DID_1);
-       } else if (did < DENTIST_BASE_DID_3) {
-               return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
-                                                       * (did - DENTIST_BASE_DID_2);
-       } else if (did < DENTIST_BASE_DID_4) {
-               return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
-                                                       * (did - DENTIST_BASE_DID_3);
-       } else {
-               return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
-                                                       * (did - DENTIST_BASE_DID_4);
-       }
-}
-
-/* SW will adjust DP REF Clock average value for all purposes
- * (DP DTO / DP Audio DTO and DP GTC)
- if clock is spread for all cases:
- -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
- calculations for DS_INCR/DS_MODULO (this is planned to be default case)
- -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
- calculations (not planned to be used, but average clock should still
- be valid)
- -if SS enabled on DP Ref clock and HW de-spreading disabled
- (should not be case with CIK) then SW should program all rates
- generated according to average value (case as with previous ASICs)
-  */
-static int dccg_adjust_dp_ref_freq_for_ss(struct dce_dccg *clk_dce, int dp_ref_clk_khz)
-{
-       if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
-               struct fixed31_32 ss_percentage = dc_fixpt_div_int(
-                               dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage,
-                                                       clk_dce->dprefclk_ss_divider), 200);
-               struct fixed31_32 adj_dp_ref_clk_khz;
-
-               ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
-               adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
-               dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
-       }
-       return dp_ref_clk_khz;
-}
-
-static int dce_get_dp_ref_freq_khz(struct dccg *clk)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-       int dprefclk_wdivider;
-       int dprefclk_src_sel;
-       int dp_ref_clk_khz = 600000;
-       int target_div;
-
-       /* ASSERT DP Reference Clock source is from DFS*/
-       REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
-       ASSERT(dprefclk_src_sel == 0);
-
-       /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
-        * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
-       REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
-
-       /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
-       target_div = dentist_get_divider_from_did(dprefclk_wdivider);
-
-       /* Calculate the current DFS clock, in kHz.*/
-       dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
-               * clk_dce->dentist_vco_freq_khz) / target_div;
-
-       return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz);
-}
-
-static int dce12_get_dp_ref_freq_khz(struct dccg *clk)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-
-       return dccg_adjust_dp_ref_freq_for_ss(clk_dce, clk_dce->dprefclk_khz);
-}
-
-static enum dm_pp_clocks_state dce_get_required_clocks_state(
-       struct dccg *clk,
-       struct dc_clocks *req_clocks)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-       int i;
-       enum dm_pp_clocks_state low_req_clk;
-
-       /* Iterate from highest supported to lowest valid state, and update
-        * lowest RequiredState with the lowest state that satisfies
-        * all required clocks
-        */
-       for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
-               if (req_clocks->dispclk_khz >
-                               clk_dce->max_clks_by_state[i].display_clk_khz
-                       || req_clocks->phyclk_khz >
-                               clk_dce->max_clks_by_state[i].pixel_clk_khz)
-                       break;
-
-       low_req_clk = i + 1;
-       if (low_req_clk > clk->max_clks_state) {
-               /* set max clock state for high phyclock, invalid on exceeding display clock */
-               if (clk_dce->max_clks_by_state[clk->max_clks_state].display_clk_khz
-                               < req_clocks->dispclk_khz)
-                       low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
-               else
-                       low_req_clk = clk->max_clks_state;
-       }
-
-       return low_req_clk;
-}
-
-static int dce_set_clock(
-       struct dccg *clk,
-       int requested_clk_khz)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-       struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
-       struct dc_bios *bp = clk->ctx->dc_bios;
-       int actual_clock = requested_clk_khz;
-
-       /* Make sure requested clock isn't lower than minimum threshold*/
-       if (requested_clk_khz > 0)
-               requested_clk_khz = max(requested_clk_khz,
-                               clk_dce->dentist_vco_freq_khz / 64);
-
-       /* Prepare to program display clock*/
-       pxl_clk_params.target_pixel_clock = requested_clk_khz;
-       pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
-
-       if (clk_dce->dfs_bypass_active)
-               pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
-
-       bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
-
-       if (clk_dce->dfs_bypass_active) {
-               /* Cache the fixed display clock*/
-               clk_dce->dfs_bypass_disp_clk =
-                       pxl_clk_params.dfs_bypass_display_clock;
-               actual_clock = pxl_clk_params.dfs_bypass_display_clock;
-       }
-
-       /* from power down, we need mark the clock state as ClocksStateNominal
-        * from HWReset, so when resume we will call pplib voltage regulator.*/
-       if (requested_clk_khz == 0)
-               clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
-       return actual_clock;
-}
-
-static int dce_psr_set_clock(
-       struct dccg *clk,
-       int requested_clk_khz)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-       struct dc_context *ctx = clk_dce->base.ctx;
-       struct dc *core_dc = ctx->dc;
-       struct dmcu *dmcu = core_dc->res_pool->dmcu;
-       int actual_clk_khz = requested_clk_khz;
-
-       actual_clk_khz = dce_set_clock(clk, requested_clk_khz);
-
-       dmcu->funcs->set_psr_wait_loop(dmcu, actual_clk_khz / 1000 / 7);
-       return actual_clk_khz;
-}
-
-static int dce112_set_clock(
-       struct dccg *clk,
-       int requested_clk_khz)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-       struct bp_set_dce_clock_parameters dce_clk_params;
-       struct dc_bios *bp = clk->ctx->dc_bios;
-       struct dc *core_dc = clk->ctx->dc;
-       struct dmcu *dmcu = core_dc->res_pool->dmcu;
-       int actual_clock = requested_clk_khz;
-       /* Prepare to program display clock*/
-       memset(&dce_clk_params, 0, sizeof(dce_clk_params));
-
-       /* Make sure requested clock isn't lower than minimum threshold*/
-       if (requested_clk_khz > 0)
-               requested_clk_khz = max(requested_clk_khz,
-                               clk_dce->dentist_vco_freq_khz / 62);
-
-       dce_clk_params.target_clock_frequency = requested_clk_khz;
-       dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
-       dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
-
-       bp->funcs->set_dce_clock(bp, &dce_clk_params);
-       actual_clock = dce_clk_params.target_clock_frequency;
-
-       /* from power down, we need mark the clock state as ClocksStateNominal
-        * from HWReset, so when resume we will call pplib voltage regulator.*/
-       if (requested_clk_khz == 0)
-               clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
-
-       /*Program DP ref Clock*/
-       /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
-       dce_clk_params.target_clock_frequency = 0;
-       dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
-       if (!ASICREV_IS_VEGA20_P(clk->ctx->asic_id.hw_internal_rev))
-               dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
-                       (dce_clk_params.pll_id ==
-                                       CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
-       else
-               dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
-
-       bp->funcs->set_dce_clock(bp, &dce_clk_params);
-
-       if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
-               if (clk_dce->dfs_bypass_disp_clk != actual_clock)
-                       dmcu->funcs->set_psr_wait_loop(dmcu,
-                                       actual_clock / 1000 / 7);
-       }
-
-       clk_dce->dfs_bypass_disp_clk = actual_clock;
-       return actual_clock;
-}
-
-static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce)
-{
-       struct dc_debug_options *debug = &clk_dce->base.ctx->dc->debug;
-       struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
-       struct integrated_info info = { { { 0 } } };
-       struct dc_firmware_info fw_info = { { 0 } };
-       int i;
-
-       if (bp->integrated_info)
-               info = *bp->integrated_info;
-
-       clk_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
-       if (clk_dce->dentist_vco_freq_khz == 0) {
-               bp->funcs->get_firmware_info(bp, &fw_info);
-               clk_dce->dentist_vco_freq_khz =
-                       fw_info.smu_gpu_pll_output_freq;
-               if (clk_dce->dentist_vco_freq_khz == 0)
-                       clk_dce->dentist_vco_freq_khz = 3600000;
-       }
-
-       /*update the maximum display clock for each power state*/
-       for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
-               enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
-
-               switch (i) {
-               case 0:
-                       clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
-                       break;
-
-               case 1:
-                       clk_state = DM_PP_CLOCKS_STATE_LOW;
-                       break;
-
-               case 2:
-                       clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
-                       break;
-
-               case 3:
-                       clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
-                       break;
-
-               default:
-                       clk_state = DM_PP_CLOCKS_STATE_INVALID;
-                       break;
-               }
-
-               /*Do not allow bad VBIOS/SBIOS to override with invalid values,
-                * check for > 100MHz*/
-               if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
-                       clk_dce->max_clks_by_state[clk_state].display_clk_khz =
-                               info.disp_clk_voltage[i].max_supported_clk;
-       }
-
-       if (!debug->disable_dfs_bypass && bp->integrated_info)
-               if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
-                       clk_dce->dfs_bypass_enabled = true;
-}
-
-static void dce_clock_read_ss_info(struct dce_dccg *clk_dce)
-{
-       struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
-       int ss_info_num = bp->funcs->get_ss_entry_number(
-                       bp, AS_SIGNAL_TYPE_GPU_PLL);
-
-       if (ss_info_num) {
-               struct spread_spectrum_info info = { { 0 } };
-               enum bp_result result = bp->funcs->get_spread_spectrum_info(
-                               bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
-
-               /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
-                * even if SS not enabled and in that case
-                * SSInfo.spreadSpectrumPercentage !=0 would be sign
-                * that SS is enabled
-                */
-               if (result == BP_RESULT_OK &&
-                               info.spread_spectrum_percentage != 0) {
-                       clk_dce->ss_on_dprefclk = true;
-                       clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
-
-                       if (info.type.CENTER_MODE == 0) {
-                               /* TODO: Currently for DP Reference clock we
-                                * need only SS percentage for
-                                * downspread */
-                               clk_dce->dprefclk_ss_percentage =
-                                               info.spread_spectrum_percentage;
-                       }
-
-                       return;
-               }
-
-               result = bp->funcs->get_spread_spectrum_info(
-                               bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
-
-               /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
-                * even if SS not enabled and in that case
-                * SSInfo.spreadSpectrumPercentage !=0 would be sign
-                * that SS is enabled
-                */
-               if (result == BP_RESULT_OK &&
-                               info.spread_spectrum_percentage != 0) {
-                       clk_dce->ss_on_dprefclk = true;
-                       clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
-
-                       if (info.type.CENTER_MODE == 0) {
-                               /* Currently for DP Reference clock we
-                                * need only SS percentage for
-                                * downspread */
-                               clk_dce->dprefclk_ss_percentage =
-                                               info.spread_spectrum_percentage;
-                       }
-               }
-       }
-}
-
-static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk)
-{
-       return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk);
-}
-
-static void dce12_update_clocks(struct dccg *dccg,
-                       struct dc_clocks *new_clocks,
-                       bool safe_to_lower)
-{
-       struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
-
-       /* TODO: Investigate why this is needed to fix display corruption. */
-       new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100;
-
-       if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) {
-               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
-               clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz;
-               new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
-               dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-
-               dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
-       }
-
-       if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) {
-               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK;
-               clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz;
-               dccg->clks.phyclk_khz = new_clocks->phyclk_khz;
-
-               dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
-       }
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks)
-{
-       bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
-       bool dispclk_increase = new_clocks->dispclk_khz > dccg->clks.dispclk_khz;
-       int disp_clk_threshold = new_clocks->max_supported_dppclk_khz;
-       bool cur_dpp_div = dccg->clks.dispclk_khz > dccg->clks.dppclk_khz;
-
-       /* increase clock, looking for div is 0 for current, request div is 1*/
-       if (dispclk_increase) {
-               /* already divided by 2, no need to reach target clk with 2 steps*/
-               if (cur_dpp_div)
-                       return new_clocks->dispclk_khz;
-
-               /* request disp clk is lower than maximum supported dpp clk,
-                * no need to reach target clk with two steps.
-                */
-               if (new_clocks->dispclk_khz <= disp_clk_threshold)
-                       return new_clocks->dispclk_khz;
-
-               /* target dpp clk not request divided by 2, still within threshold */
-               if (!request_dpp_div)
-                       return new_clocks->dispclk_khz;
-
-       } else {
-               /* decrease clock, looking for current dppclk divided by 2,
-                * request dppclk not divided by 2.
-                */
-
-               /* current dpp clk not divided by 2, no need to ramp*/
-               if (!cur_dpp_div)
-                       return new_clocks->dispclk_khz;
-
-               /* current disp clk is lower than current maximum dpp clk,
-                * no need to ramp
-                */
-               if (dccg->clks.dispclk_khz <= disp_clk_threshold)
-                       return new_clocks->dispclk_khz;
-
-               /* request dpp clk need to be divided by 2 */
-               if (request_dpp_div)
-                       return new_clocks->dispclk_khz;
-       }
-
-       return disp_clk_threshold;
-}
-
-static void dcn1_ramp_up_dispclk_with_dpp(struct dccg *dccg, struct dc_clocks *new_clocks)
-{
-       struct dc *dc = dccg->ctx->dc;
-       int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(dccg, new_clocks);
-       bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
-       int i;
-
-       /* set disp clk to dpp clk threshold */
-       dccg->funcs->set_dispclk(dccg, dispclk_to_dpp_threshold);
-
-       /* update request dpp clk division option */
-       for (i = 0; i < dc->res_pool->pipe_count; i++) {
-               struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
-
-               if (!pipe_ctx->plane_state)
-                       continue;
-
-               pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control(
-                               pipe_ctx->plane_res.dpp,
-                               request_dpp_div,
-                               true);
-       }
-
-       /* If target clk not same as dppclk threshold, set to target clock */
-       if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz)
-               dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
-
-       dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-       dccg->clks.dppclk_khz = new_clocks->dppclk_khz;
-       dccg->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz;
-}
-
-static void dcn1_update_clocks(struct dccg *dccg,
-                       struct dc_clocks *new_clocks,
-                       bool safe_to_lower)
-{
-       struct dc *dc = dccg->ctx->dc;
-       struct pp_smu_display_requirement_rv *smu_req_cur =
-                       &dc->res_pool->pp_smu_req;
-       struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
-       struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
-       struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
-       bool send_request_to_increase = false;
-       bool send_request_to_lower = false;
-
-       if (new_clocks->phyclk_khz)
-               smu_req.display_count = 1;
-       else
-               smu_req.display_count = 0;
-
-       if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz
-                       || new_clocks->phyclk_khz > dccg->clks.phyclk_khz
-                       || new_clocks->fclk_khz > dccg->clks.fclk_khz
-                       || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz)
-               send_request_to_increase = true;
-
-       if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) {
-               dccg->clks.phyclk_khz = new_clocks->phyclk_khz;
-
-               send_request_to_lower = true;
-       }
-
-       if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) {
-               dccg->clks.fclk_khz = new_clocks->fclk_khz;
-               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK;
-               clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz;
-               smu_req.hard_min_fclk_khz = new_clocks->fclk_khz;
-
-               dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
-               send_request_to_lower = true;
-       }
-
-       if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) {
-               dccg->clks.dcfclk_khz = new_clocks->dcfclk_khz;
-               smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz;
-
-               send_request_to_lower = true;
-       }
-
-       if (should_set_clock(safe_to_lower,
-                       new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) {
-               dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
-               smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz;
-
-               send_request_to_lower = true;
-       }
-
-       /* make sure dcf clk is before dpp clk to
-        * make sure we have enough voltage to run dpp clk
-        */
-       if (send_request_to_increase) {
-               /*use dcfclk to request voltage*/
-               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
-               clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
-               dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
-               if (pp_smu->set_display_requirement)
-                       pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
-       }
-
-       /* dcn1 dppclk is tied to dispclk */
-       /* program dispclk on = as a w/a for sleep resume clock ramping issues */
-       if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)
-                       || new_clocks->dispclk_khz == dccg->clks.dispclk_khz) {
-               dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks);
-               dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-
-               send_request_to_lower = true;
-       }
-
-       if (!send_request_to_increase && send_request_to_lower) {
-               /*use dcfclk to request voltage*/
-               clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
-               clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
-               dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
-               if (pp_smu->set_display_requirement)
-                       pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
-       }
-
-
-       *smu_req_cur = smu_req;
-}
-#endif
-
-static void dce_update_clocks(struct dccg *dccg,
-                       struct dc_clocks *new_clocks,
-                       bool safe_to_lower)
-{
-       struct dm_pp_power_level_change_request level_change_req;
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg);
-
-       /* TODO: Investigate why this is needed to fix display corruption. */
-       if (!clk_dce->dfs_bypass_active)
-               new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100;
-
-       level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks);
-       /* get max clock state from PPLIB */
-       if ((level_change_req.power_level < dccg->cur_min_clks_state && safe_to_lower)
-                       || level_change_req.power_level > dccg->cur_min_clks_state) {
-               if (dm_pp_apply_power_level_change_request(dccg->ctx, &level_change_req))
-                       dccg->cur_min_clks_state = level_change_req.power_level;
-       }
-
-       if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) {
-               new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
-               dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-       }
-}
-
-static bool dce_update_dfs_bypass(
-       struct dccg *dccg,
-       struct dc *dc,
-       struct dc_state *context,
-       int requested_clock_khz)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg);
-       struct resource_context *res_ctx = &context->res_ctx;
-       enum signal_type signal_type = SIGNAL_TYPE_NONE;
-       bool was_active = clk_dce->dfs_bypass_active;
-       int i;
-
-       /* Disable DFS bypass by default. */
-       clk_dce->dfs_bypass_active = false;
-
-       /* Check that DFS bypass is available. */
-       if (!clk_dce->dfs_bypass_enabled)
-               goto update;
-
-       /* Check if the requested display clock is below the threshold. */
-       if (requested_clock_khz >= 400000)
-               goto update;
-
-       /* DFS-bypass should only be enabled on single stream setups */
-       if (context->stream_count != 1)
-               goto update;
-
-       /* Check that the stream's signal type is an embedded panel */
-       for (i = 0; i < dc->res_pool->pipe_count; i++) {
-               if (res_ctx->pipe_ctx[i].stream) {
-                       struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
-
-                       signal_type = pipe_ctx->stream->sink->link->connector_signal;
-                       break;
-               }
-       }
-
-       if (signal_type == SIGNAL_TYPE_EDP ||
-               signal_type == SIGNAL_TYPE_LVDS)
-               clk_dce->dfs_bypass_active = true;
-
-update:
-       /* Update the clock state. We don't need to respect safe_to_lower
-        * because DFS bypass should always be greater than the current
-        * display clock frequency.
-        */
-       if (was_active != clk_dce->dfs_bypass_active) {
-               dccg->clks.dispclk_khz =
-                       dccg->funcs->set_dispclk(dccg, dccg->clks.dispclk_khz);
-               return true;
-       }
-
-       return false;
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-static const struct display_clock_funcs dcn1_funcs = {
-       .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
-       .set_dispclk = dce112_set_clock,
-       .update_clocks = dcn1_update_clocks
-};
-#endif
-
-static const struct display_clock_funcs dce120_funcs = {
-       .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
-       .set_dispclk = dce112_set_clock,
-       .update_clocks = dce12_update_clocks
-};
-
-static const struct display_clock_funcs dce112_funcs = {
-       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
-       .set_dispclk = dce112_set_clock,
-       .update_clocks = dce_update_clocks
-};
-
-static const struct display_clock_funcs dce110_funcs = {
-       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
-       .set_dispclk = dce_psr_set_clock,
-       .update_clocks = dce_update_clocks,
-       .update_dfs_bypass = dce_update_dfs_bypass
-};
-
-static const struct display_clock_funcs dce_funcs = {
-       .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
-       .set_dispclk = dce_set_clock,
-       .update_clocks = dce_update_clocks
-};
-
-static void dce_dccg_construct(
-       struct dce_dccg *clk_dce,
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask)
-{
-       struct dccg *base = &clk_dce->base;
-
-       base->ctx = ctx;
-       base->funcs = &dce_funcs;
-
-       clk_dce->regs = regs;
-       clk_dce->clk_shift = clk_shift;
-       clk_dce->clk_mask = clk_mask;
-
-       clk_dce->dfs_bypass_disp_clk = 0;
-
-       clk_dce->dprefclk_ss_percentage = 0;
-       clk_dce->dprefclk_ss_divider = 1000;
-       clk_dce->ss_on_dprefclk = false;
-
-       base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
-       base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
-
-       dce_clock_read_integrated_info(clk_dce);
-       dce_clock_read_ss_info(clk_dce);
-}
-
-struct dccg *dce_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask)
-{
-       struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
-       if (clk_dce == NULL) {
-               BREAK_TO_DEBUGGER();
-               return NULL;
-       }
-
-       memcpy(clk_dce->max_clks_by_state,
-               dce80_max_clks_by_state,
-               sizeof(dce80_max_clks_by_state));
-
-       dce_dccg_construct(
-               clk_dce, ctx, regs, clk_shift, clk_mask);
-
-       return &clk_dce->base;
-}
-
-struct dccg *dce110_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask)
-{
-       struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
-       if (clk_dce == NULL) {
-               BREAK_TO_DEBUGGER();
-               return NULL;
-       }
-
-       memcpy(clk_dce->max_clks_by_state,
-               dce110_max_clks_by_state,
-               sizeof(dce110_max_clks_by_state));
-
-       dce_dccg_construct(
-               clk_dce, ctx, regs, clk_shift, clk_mask);
-
-       clk_dce->base.funcs = &dce110_funcs;
-
-       return &clk_dce->base;
-}
-
-struct dccg *dce112_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask)
-{
-       struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
-       if (clk_dce == NULL) {
-               BREAK_TO_DEBUGGER();
-               return NULL;
-       }
-
-       memcpy(clk_dce->max_clks_by_state,
-               dce112_max_clks_by_state,
-               sizeof(dce112_max_clks_by_state));
-
-       dce_dccg_construct(
-               clk_dce, ctx, regs, clk_shift, clk_mask);
-
-       clk_dce->base.funcs = &dce112_funcs;
-
-       return &clk_dce->base;
-}
-
-struct dccg *dce120_dccg_create(struct dc_context *ctx)
-{
-       struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
-       if (clk_dce == NULL) {
-               BREAK_TO_DEBUGGER();
-               return NULL;
-       }
-
-       memcpy(clk_dce->max_clks_by_state,
-               dce120_max_clks_by_state,
-               sizeof(dce120_max_clks_by_state));
-
-       dce_dccg_construct(
-               clk_dce, ctx, NULL, NULL, NULL);
-
-       clk_dce->dprefclk_khz = 600000;
-       clk_dce->base.funcs = &dce120_funcs;
-
-       return &clk_dce->base;
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-struct dccg *dcn1_dccg_create(struct dc_context *ctx)
-{
-       struct dc_debug_options *debug = &ctx->dc->debug;
-       struct dc_bios *bp = ctx->dc_bios;
-       struct dc_firmware_info fw_info = { { 0 } };
-       struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
-       if (clk_dce == NULL) {
-               BREAK_TO_DEBUGGER();
-               return NULL;
-       }
-
-       clk_dce->base.ctx = ctx;
-       clk_dce->base.funcs = &dcn1_funcs;
-
-       clk_dce->dfs_bypass_disp_clk = 0;
-
-       clk_dce->dprefclk_ss_percentage = 0;
-       clk_dce->dprefclk_ss_divider = 1000;
-       clk_dce->ss_on_dprefclk = false;
-
-       clk_dce->dprefclk_khz = 600000;
-       if (bp->integrated_info)
-               clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
-       if (clk_dce->dentist_vco_freq_khz == 0) {
-               bp->funcs->get_firmware_info(bp, &fw_info);
-               clk_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq;
-               if (clk_dce->dentist_vco_freq_khz == 0)
-                       clk_dce->dentist_vco_freq_khz = 3600000;
-       }
-
-       if (!debug->disable_dfs_bypass && bp->integrated_info)
-               if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
-                       clk_dce->dfs_bypass_enabled = true;
-
-       dce_clock_read_ss_info(clk_dce);
-
-       return &clk_dce->base;
-}
-#endif
-
-void dce_dccg_destroy(struct dccg **dccg)
-{
-       struct dce_dccg *clk_dce = TO_DCE_CLOCKS(*dccg);
-
-       kfree(clk_dce);
-       *dccg = NULL;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h
deleted file mode 100644 (file)
index 34fdb38..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef _DCE_CLOCKS_H_
-#define _DCE_CLOCKS_H_
-
-#include "display_clock.h"
-
-#define CLK_COMMON_REG_LIST_DCE_BASE() \
-       .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \
-       .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL
-
-#define CLK_COMMON_REG_LIST_DCN_BASE() \
-       SR(DENTIST_DISPCLK_CNTL)
-
-#define CLK_SF(reg_name, field_name, post_fix)\
-       .field_name = reg_name ## __ ## field_name ## post_fix
-
-#define CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) \
-       CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \
-       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh)
-
-#define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \
-       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\
-       CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh)
-
-#define CLK_REG_FIELD_LIST(type) \
-       type DPREFCLK_SRC_SEL; \
-       type DENTIST_DPREFCLK_WDIVIDER; \
-       type DENTIST_DISPCLK_WDIVIDER; \
-       type DENTIST_DISPCLK_CHG_DONE;
-
-struct dccg_shift {
-       CLK_REG_FIELD_LIST(uint8_t)
-};
-
-struct dccg_mask {
-       CLK_REG_FIELD_LIST(uint32_t)
-};
-
-struct dccg_registers {
-       uint32_t DPREFCLK_CNTL;
-       uint32_t DENTIST_DISPCLK_CNTL;
-};
-
-struct dce_dccg {
-       struct dccg base;
-       const struct dccg_registers *regs;
-       const struct dccg_shift *clk_shift;
-       const struct dccg_mask *clk_mask;
-
-       struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES];
-
-       int dentist_vco_freq_khz;
-
-       /* Cache the status of DFS-bypass feature*/
-       bool dfs_bypass_enabled;
-       /* True if the DFS-bypass feature is enabled and active. */
-       bool dfs_bypass_active;
-       /* Cache the display clock returned by VBIOS if DFS-bypass is enabled.
-        * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
-       int dfs_bypass_disp_clk;
-
-       /* Flag for Enabled SS on DPREFCLK */
-       bool ss_on_dprefclk;
-       /* DPREFCLK SS percentage (if down-spread enabled) */
-       int dprefclk_ss_percentage;
-       /* DPREFCLK SS percentage Divider (100 or 1000) */
-       int dprefclk_ss_divider;
-       int dprefclk_khz;
-};
-
-
-struct dccg *dce_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask);
-
-struct dccg *dce110_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask);
-
-struct dccg *dce112_dccg_create(
-       struct dc_context *ctx,
-       const struct dccg_registers *regs,
-       const struct dccg_shift *clk_shift,
-       const struct dccg_mask *clk_mask);
-
-struct dccg *dce120_dccg_create(struct dc_context *ctx);
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-struct dccg *dcn1_dccg_create(struct dc_context *ctx);
-#endif
-
-void dce_dccg_destroy(struct dccg **dccg);
-
-#endif /* _DCE_CLOCKS_H_ */
index 64dc75378541539028b7333f22d00329240a3166..c83a7f05f14c11090b90d081f0e338af9c95bc63 100644 (file)
@@ -233,6 +233,16 @@ struct dce_hwseq_registers {
        uint32_t DOMAIN5_PG_CONFIG;
        uint32_t DOMAIN6_PG_CONFIG;
        uint32_t DOMAIN7_PG_CONFIG;
+       uint32_t DOMAIN8_PG_CONFIG;
+       uint32_t DOMAIN9_PG_CONFIG;
+       uint32_t DOMAIN10_PG_CONFIG;
+       uint32_t DOMAIN11_PG_CONFIG;
+       uint32_t DOMAIN16_PG_CONFIG;
+       uint32_t DOMAIN17_PG_CONFIG;
+       uint32_t DOMAIN18_PG_CONFIG;
+       uint32_t DOMAIN19_PG_CONFIG;
+       uint32_t DOMAIN20_PG_CONFIG;
+       uint32_t DOMAIN21_PG_CONFIG;
        uint32_t DOMAIN0_PG_STATUS;
        uint32_t DOMAIN1_PG_STATUS;
        uint32_t DOMAIN2_PG_STATUS;
@@ -241,6 +251,16 @@ struct dce_hwseq_registers {
        uint32_t DOMAIN5_PG_STATUS;
        uint32_t DOMAIN6_PG_STATUS;
        uint32_t DOMAIN7_PG_STATUS;
+       uint32_t DOMAIN8_PG_STATUS;
+       uint32_t DOMAIN9_PG_STATUS;
+       uint32_t DOMAIN10_PG_STATUS;
+       uint32_t DOMAIN11_PG_STATUS;
+       uint32_t DOMAIN16_PG_STATUS;
+       uint32_t DOMAIN17_PG_STATUS;
+       uint32_t DOMAIN18_PG_STATUS;
+       uint32_t DOMAIN19_PG_STATUS;
+       uint32_t DOMAIN20_PG_STATUS;
+       uint32_t DOMAIN21_PG_STATUS;
        uint32_t DIO_MEM_PWR_CTRL;
        uint32_t DCCG_GATE_DISABLE_CNTL;
        uint32_t DCCG_GATE_DISABLE_CNTL2;
@@ -262,6 +282,8 @@ struct dce_hwseq_registers {
        uint32_t D2VGA_CONTROL;
        uint32_t D3VGA_CONTROL;
        uint32_t D4VGA_CONTROL;
+       uint32_t D5VGA_CONTROL;
+       uint32_t D6VGA_CONTROL;
        uint32_t VGA_TEST_CONTROL;
        /* MMHUB registers. read only. temporary hack */
        uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32;
@@ -489,6 +511,26 @@ struct dce_hwseq_registers {
        type DOMAIN6_POWER_GATE; \
        type DOMAIN7_POWER_FORCEON; \
        type DOMAIN7_POWER_GATE; \
+       type DOMAIN8_POWER_FORCEON; \
+       type DOMAIN8_POWER_GATE; \
+       type DOMAIN9_POWER_FORCEON; \
+       type DOMAIN9_POWER_GATE; \
+       type DOMAIN10_POWER_FORCEON; \
+       type DOMAIN10_POWER_GATE; \
+       type DOMAIN11_POWER_FORCEON; \
+       type DOMAIN11_POWER_GATE; \
+       type DOMAIN16_POWER_FORCEON; \
+       type DOMAIN16_POWER_GATE; \
+       type DOMAIN17_POWER_FORCEON; \
+       type DOMAIN17_POWER_GATE; \
+       type DOMAIN18_POWER_FORCEON; \
+       type DOMAIN18_POWER_GATE; \
+       type DOMAIN19_POWER_FORCEON; \
+       type DOMAIN19_POWER_GATE; \
+       type DOMAIN20_POWER_FORCEON; \
+       type DOMAIN20_POWER_GATE; \
+       type DOMAIN21_POWER_FORCEON; \
+       type DOMAIN21_POWER_GATE; \
        type DOMAIN0_PGFSM_PWR_STATUS; \
        type DOMAIN1_PGFSM_PWR_STATUS; \
        type DOMAIN2_PGFSM_PWR_STATUS; \
@@ -497,6 +539,16 @@ struct dce_hwseq_registers {
        type DOMAIN5_PGFSM_PWR_STATUS; \
        type DOMAIN6_PGFSM_PWR_STATUS; \
        type DOMAIN7_PGFSM_PWR_STATUS; \
+       type DOMAIN8_PGFSM_PWR_STATUS; \
+       type DOMAIN9_PGFSM_PWR_STATUS; \
+       type DOMAIN10_PGFSM_PWR_STATUS; \
+       type DOMAIN11_PGFSM_PWR_STATUS; \
+       type DOMAIN16_PGFSM_PWR_STATUS; \
+       type DOMAIN17_PGFSM_PWR_STATUS; \
+       type DOMAIN18_PGFSM_PWR_STATUS; \
+       type DOMAIN19_PGFSM_PWR_STATUS; \
+       type DOMAIN20_PGFSM_PWR_STATUS; \
+       type DOMAIN21_PGFSM_PWR_STATUS; \
        type DCFCLK_GATE_DIS; \
        type DCHUBBUB_GLOBAL_TIMER_REFDIV; \
        type VGA_TEST_ENABLE; \
index 366bc8c2c643dd0383a4f5643daf06f64da164f3..3e18ea84b1f961ef7ddfd5b701e91e62f5e8852c 100644 (file)
@@ -645,7 +645,7 @@ static bool dce110_link_encoder_validate_hdmi_output(
                return false;
 
        /* DCE11 HW does not support 420 */
-       if (!enc110->base.features.ycbcr420_supported &&
+       if (!enc110->base.features.hdmi_ycbcr420_supported &&
                        crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
                return false;
 
index c47c81883d3cc64bbe950e614705ca0b7833c18a..cce0d18f91da66ea5a3c641eba20ee524d5798a7 100644 (file)
@@ -908,7 +908,6 @@ static void dce110_stream_encoder_dp_blank(
        struct stream_encoder *enc)
 {
        struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
-       uint32_t retries = 0;
        uint32_t  reg1 = 0;
        uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
 
@@ -926,30 +925,28 @@ static void dce110_stream_encoder_dp_blank(
         * (2 = start of the next vertical blank) */
        REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2);
        /* Larger delay to wait until VBLANK - use max retry of
-       * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
-       * a little more because we may not trust delay accuracy.
-       */
+        * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
+        * a little more because we may not trust delay accuracy.
+        */
        max_retries = DP_BLANK_MAX_RETRY * 150;
 
        /* disable DP stream */
        REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0);
 
        /* the encoder stops sending the video stream
-       * at the start of the vertical blanking.
-       * Poll for DP_VID_STREAM_STATUS == 0
-       */
+        * at the start of the vertical blanking.
+        * Poll for DP_VID_STREAM_STATUS == 0
+        */
 
        REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS,
                        0,
                        10, max_retries);
 
-       ASSERT(retries <= max_retries);
-
        /* Tell the DP encoder to ignore timing from CRTC, must be done after
-       * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
-       * complete, stream status will be stuck in video stream enabled state,
-       * i.e. DP_VID_STREAM_STATUS stuck at 1.
-       */
+        * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
+        * complete, stream status will be stuck in video stream enabled state,
+        * i.e. DP_VID_STREAM_STATUS stuck at 1.
+        */
 
        REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true);
 }
index 74c05e8788073433895536f856ae451e77a37fe8..87771676acacacccb303b3b504a0964172a8924d 100644 (file)
@@ -105,74 +105,30 @@ bool dce100_enable_display_power_gating(
                return false;
 }
 
-static void dce100_pplib_apply_display_requirements(
-       struct dc *dc,
-       struct dc_state *context)
-{
-       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
-
-       pp_display_cfg->avail_mclk_switch_time_us =
-                                               dce110_get_min_vblank_time_us(context);
-       /*pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
-               / MEMORY_TYPE_MULTIPLIER;*/
-
-       dce110_fill_display_configs(context, pp_display_cfg);
-
-       if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
-                       struct dm_pp_display_configuration)) !=  0)
-               dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
-       dc->prev_display_config = *pp_display_cfg;
-}
-
-/* unit: in_khz before mode set, get pixel clock from context. ASIC register
- * may not be programmed yet
- */
-static uint32_t get_max_pixel_clock_for_all_paths(
-       struct dc *dc,
-       struct dc_state *context)
+void dce100_prepare_bandwidth(
+               struct dc *dc,
+               struct dc_state *context)
 {
-       uint32_t max_pix_clk = 0;
-       int i;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
-               if (pipe_ctx->stream == NULL)
-                       continue;
-
-               /* do not check under lay */
-               if (pipe_ctx->top_pipe)
-                       continue;
+       dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
 
-               if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
-                       max_pix_clk =
-                               pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
-       }
-       return max_pix_clk;
+       dc->res_pool->clk_mgr->funcs->update_clocks(
+                       dc->res_pool->clk_mgr,
+                       context,
+                       false);
 }
 
-void dce100_set_bandwidth(
+void dce100_optimize_bandwidth(
                struct dc *dc,
-               struct dc_state *context,
-               bool decrease_allowed)
+               struct dc_state *context)
 {
-       struct dc_clocks req_clks;
-
-       req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
-       req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context);
-
        dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
 
-       dc->res_pool->dccg->funcs->update_clocks(
-                       dc->res_pool->dccg,
-                       &req_clks,
-                       decrease_allowed);
-
-       dce100_pplib_apply_display_requirements(dc, context);
+       dc->res_pool->clk_mgr->funcs->update_clocks(
+                       dc->res_pool->clk_mgr,
+                       context,
+                       true);
 }
 
-
 /**************************************************************************/
 
 void dce100_hw_sequencer_construct(struct dc *dc)
@@ -180,8 +136,7 @@ void dce100_hw_sequencer_construct(struct dc *dc)
        dce110_hw_sequencer_construct(dc);
 
        dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
-       dc->hwss.set_bandwidth = dce100_set_bandwidth;
-       dc->hwss.pplib_apply_display_requirements =
-                       dce100_pplib_apply_display_requirements;
+       dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
+       dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth;
 }
 
index c6ec0ed6ec3de0d59fe0a99edee7ae4e14a8391c..acd418515346c49fb263f98ae27995f957f959db 100644 (file)
@@ -33,10 +33,9 @@ struct dc_state;
 
 void dce100_hw_sequencer_construct(struct dc *dc);
 
-void dce100_set_bandwidth(
+void dce100_prepare_bandwidth(
                struct dc *dc,
-               struct dc_state *context,
-               bool decrease_allowed);
+               struct dc_state *context);
 
 bool dce100_enable_display_power_gating(struct dc *dc, uint8_t controller_id,
                                        struct dc_bios *dcb,
index 14754a87156c53fe70269aaa9f883b4074bdfd79..6ae51a5dfc049da69d8530879c54eab38225e9c8 100644 (file)
 #include "dce/dce_link_encoder.h"
 #include "dce/dce_stream_encoder.h"
 
+#include "dce/dce_clk_mgr.h"
 #include "dce/dce_mem_input.h"
 #include "dce/dce_ipp.h"
 #include "dce/dce_transform.h"
 #include "dce/dce_opp.h"
-#include "dce/dce_clocks.h"
 #include "dce/dce_clock_source.h"
 #include "dce/dce_audio.h"
 #include "dce/dce_hwseq.h"
@@ -137,15 +137,15 @@ static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = {
        .reg_name = mm ## block ## id ## _ ## reg_name
 
 
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
                CLK_COMMON_REG_LIST_DCE_BASE()
 };
 
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
 };
 
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
 };
 
@@ -722,8 +722,8 @@ static void destruct(struct dce110_resource_pool *pool)
                        dce_aud_destroy(&pool->base.audios[i]);
        }
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 
        if (pool->base.abm != NULL)
                                dce_abm_destroy(&pool->base.abm);
@@ -767,7 +767,7 @@ bool dce100_validate_bandwidth(
        if (at_least_one_pipe) {
                /* TODO implement when needed but for now hardcode max value*/
                context->bw.dce.dispclk_khz = 681000;
-               context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER;
+               context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ;
        } else {
                context->bw.dce.dispclk_khz = 0;
                context->bw.dce.yclk_khz = 0;
@@ -860,7 +860,6 @@ static bool construct(
        struct dc_context *ctx = dc->ctx;
        struct dc_firmware_info info;
        struct dc_bios *bp;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -908,11 +907,11 @@ static bool construct(
                }
        }
 
-       pool->base.dccg = dce_dccg_create(ctx,
+       pool->base.clk_mgr = dce_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -938,12 +937,6 @@ static bool construct(
                goto res_create_fail;
        }
 
-       /* get static clock information for PPLIB or firmware, save
-        * max_clock_state
-        */
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                                       static_clk_info.max_clocks_state;
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
index 1f7f25013217dfad9226ed55a98aee0461b500a0..52d50e24a99538ac04cafaf58b1446ab71cc5385 100644 (file)
@@ -64,65 +64,37 @@ static const struct dce110_compressor_reg_offsets reg_offsets[] = {
 
 static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600;
 
-enum fbc_idle_force {
-       /* Bit 0 - Display registers updated */
-       FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001,
-
-       /* Bit 2 - FBC_GRPH_COMP_EN register updated */
-       FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002,
-       /* Bit 3 - FBC_SRC_SEL register updated */
-       FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004,
-       /* Bit 4 - FBC_MIN_COMPRESSION register updated */
-       FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008,
-       /* Bit 5 - FBC_ALPHA_COMP_EN register updated */
-       FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010,
-       /* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */
-       FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020,
-       /* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */
-       FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040,
-
-       /* Bit 24 - Memory write to region 0 defined by MC registers. */
-       FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000,
-       /* Bit 25 - Memory write to region 1 defined by MC registers */
-       FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000,
-       /* Bit 26 - Memory write to region 2 defined by MC registers */
-       FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000,
-       /* Bit 27 - Memory write to region 3 defined by MC registers. */
-       FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000,
-
-       /* Bit 28 - Memory write from any client other than MCIF */
-       FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000,
-       /* Bit 29 - CG statics screen signal is inactive */
-       FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000,
-};
-
-
 static uint32_t align_to_chunks_number_per_line(uint32_t pixels)
 {
        return 256 * ((pixels + 255) / 256);
 }
 
-static void reset_lb_on_vblank(struct dc_context *ctx)
+static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst)
 {
-       uint32_t value, frame_count;
+       uint32_t value;
+       uint32_t frame_count;
+       uint32_t status_pos;
        uint32_t retry = 0;
-       uint32_t status_pos =
-                       dm_read_reg(ctx, mmCRTC_STATUS_POSITION);
+       struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
+
+       cp110->offsets = reg_offsets[crtc_inst];
+
+       status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION));
 
 
        /* Only if CRTC is enabled and counter is moving we wait for one frame. */
-       if (status_pos != dm_read_reg(ctx, mmCRTC_STATUS_POSITION)) {
+       if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) {
                /* Resetting LB on VBlank */
-               value = dm_read_reg(ctx, mmLB_SYNC_RESET_SEL);
+               value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
                set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
                set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
-               dm_write_reg(ctx, mmLB_SYNC_RESET_SEL, value);
+               dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
 
-               frame_count = dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT);
+               frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT));
 
 
                for (retry = 10000; retry > 0; retry--) {
-                       if (frame_count != dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT))
+                       if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)))
                                break;
                        udelay(10);
                }
@@ -130,13 +102,11 @@ static void reset_lb_on_vblank(struct dc_context *ctx)
                        dm_error("Frame count did not increase for 100ms.\n");
 
                /* Resetting LB on VBlank */
-               value = dm_read_reg(ctx, mmLB_SYNC_RESET_SEL);
+               value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
                set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
                set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
-               dm_write_reg(ctx, mmLB_SYNC_RESET_SEL, value);
-
+               dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
        }
-
 }
 
 static void wait_for_fbc_state_changed(
@@ -226,10 +196,10 @@ void dce110_compressor_enable_fbc(
                uint32_t addr;
                uint32_t value, misc_value;
 
-
                addr = mmFBC_CNTL;
                value = dm_read_reg(compressor->ctx, addr);
                set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
+               /* params->inst is valid HW CRTC instance start from 0 */
                set_reg_field_value(
                        value,
                        params->inst,
@@ -238,8 +208,10 @@ void dce110_compressor_enable_fbc(
 
                /* Keep track of enum controller_id FBC is attached to */
                compressor->is_enabled = true;
-               compressor->attached_inst = params->inst;
-               cp110->offsets = reg_offsets[params->inst];
+               /* attached_inst is SW CRTC instance start from 1
+                * 0 = CONTROLLER_ID_UNDEFINED means not attached crtc
+                */
+               compressor->attached_inst = params->inst + CONTROLLER_ID_D0;
 
                /* Toggle it as there is bug in HW */
                set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
@@ -268,9 +240,10 @@ void dce110_compressor_enable_fbc(
 void dce110_compressor_disable_fbc(struct compressor *compressor)
 {
        struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
+       uint32_t crtc_inst = 0;
 
        if (compressor->options.bits.FBC_SUPPORT) {
-               if (dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL)) {
+               if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) {
                        uint32_t reg_data;
                        /* Turn off compression */
                        reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
@@ -284,8 +257,10 @@ void dce110_compressor_disable_fbc(struct compressor *compressor)
                        wait_for_fbc_state_changed(cp110, false);
                }
 
-               /* Sync line buffer  - dce100/110 only*/
-               reset_lb_on_vblank(compressor->ctx);
+               /* Sync line buffer which fbc was attached to dce100/110 only */
+               if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3)
+                       reset_lb_on_vblank(compressor,
+                                       crtc_inst - CONTROLLER_ID_D0);
        }
 }
 
@@ -328,6 +303,8 @@ void dce110_compressor_program_compressed_surface_address_and_pitch(
        uint32_t compressed_surf_address_low_part =
                compressor->compr_surface_address.addr.low_part;
 
+       cp110->offsets = reg_offsets[params->inst];
+
        /* Clear content first. */
        dm_write_reg(
                compressor->ctx,
@@ -410,13 +387,7 @@ void dce110_compressor_set_fbc_invalidation_triggers(
        value = dm_read_reg(compressor->ctx, addr);
        set_reg_field_value(
                value,
-               fbc_trigger |
-               FBC_IDLE_FORCE_GRPH_COMP_EN |
-               FBC_IDLE_FORCE_SRC_SEL_CHANGE |
-               FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE |
-               FBC_IDLE_FORCE_ALPHA_COMP_EN |
-               FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN |
-               FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF,
+               fbc_trigger,
                FBC_IDLE_FORCE_CLEAR_MASK,
                FBC_IDLE_FORCE_CLEAR_MASK);
        dm_write_reg(compressor->ctx, addr, value);
@@ -549,7 +520,7 @@ void dce110_compressor_construct(struct dce110_compressor *compressor,
        compressor->base.channel_interleave_size = 0;
        compressor->base.dram_channels_num = 0;
        compressor->base.lpt_channels_num = 0;
-       compressor->base.attached_inst = 0;
+       compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED;
        compressor->base.is_enabled = false;
        compressor->base.funcs = &dce110_compressor_funcs;
 
index a6bcb90e8419af401bbe4650dc1515f32681cda8..6349ba7bec7c3bc317af484e2cf84c76f24ec29a 100644 (file)
@@ -548,14 +548,14 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf,
 
        regamma_params->hw_points_num = hw_points;
 
-       i = 1;
-       for (k = 0; k < 16 && i < 16; k++) {
+       k = 0;
+       for (i = 1; i < 16; i++) {
                if (seg_distr[k] != -1) {
                        regamma_params->arr_curve_points[k].segments_num = seg_distr[k];
                        regamma_params->arr_curve_points[i].offset =
                                        regamma_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
                }
-               i++;
+               k++;
        }
 
        if (seg_distr[k] != -1)
@@ -1085,7 +1085,6 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
 
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
                link->dc->hwss.edp_backlight_control(link, true);
-               stream->bl_pwm_level = EDP_BACKLIGHT_RAMP_DISABLE_LEVEL;
        }
 }
 void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
@@ -1192,8 +1191,8 @@ static void build_audio_output(
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
                        pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
                audio_output->pll_info.dp_dto_source_clock_in_khz =
-                               state->dis_clk->funcs->get_dp_ref_clk_frequency(
-                                               state->dis_clk);
+                               state->dccg->funcs->get_dp_ref_clk_frequency(
+                                               state->dccg);
        }
 
        audio_output->pll_info.feed_back_divider =
@@ -1547,6 +1546,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
        int i;
        struct dc_link *edp_link_to_turnoff = NULL;
        struct dc_link *edp_link = get_link_for_edp(dc);
+       struct dc_bios *bios = dc->ctx->dc_bios;
        bool can_edp_fast_boot_optimize = false;
        bool apply_edp_fast_boot_optimization = false;
 
@@ -1573,6 +1573,20 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
                        if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
                                context->streams[i]->apply_edp_fast_boot_optimization = true;
                                apply_edp_fast_boot_optimization = true;
+
+                               /* When after S4 and S5, vbios may post edp and previous dpms_off
+                                * doesn't make sense.
+                                * Update dpms_off state to align hw and sw state via check
+                                * vBios scratch register.
+                                */
+                               if (bios->funcs->is_active_display)     {
+                                       const struct connector_device_tag_info *device_tag = &(edp_link->device_tag);
+
+                                       if (bios->funcs->is_active_display(bios,
+                                                       context->streams[i]->signal,
+                                                       device_tag))
+                                               context->streams[i]->dpms_off = false;
+                               }
                        }
                }
        }
@@ -1748,44 +1762,17 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
                        set_static_screen_control(pipe_ctx[i]->stream_res.tg, value);
 }
 
-/* unit: in_khz before mode set, get pixel clock from context. ASIC register
- * may not be programmed yet
- */
-static uint32_t get_max_pixel_clock_for_all_paths(
-       struct dc *dc,
-       struct dc_state *context)
-{
-       uint32_t max_pix_clk = 0;
-       int i;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
-               if (pipe_ctx->stream == NULL)
-                       continue;
-
-               /* do not check under lay */
-               if (pipe_ctx->top_pipe)
-                       continue;
-
-               if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
-                       max_pix_clk =
-                               pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
-       }
-
-       return max_pix_clk;
-}
-
 /*
  *  Check if FBC can be enabled
  */
 static bool should_enable_fbc(struct dc *dc,
-                             struct dc_state *context,
-                             uint32_t *pipe_idx)
+               struct dc_state *context,
+               uint32_t *pipe_idx)
 {
        uint32_t i;
        struct pipe_ctx *pipe_ctx = NULL;
        struct resource_context *res_ctx = &context->res_ctx;
+       unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
 
 
        ASSERT(dc->fbc_compressor);
@@ -1800,14 +1787,28 @@ static bool should_enable_fbc(struct dc *dc,
 
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                if (res_ctx->pipe_ctx[i].stream) {
+
                        pipe_ctx = &res_ctx->pipe_ctx[i];
-                       *pipe_idx = i;
-                       break;
+
+                       if (!pipe_ctx)
+                               continue;
+
+                       /* fbc not applicable on underlay pipe */
+                       if (pipe_ctx->pipe_idx != underlay_idx) {
+                               *pipe_idx = i;
+                               break;
+                       }
                }
        }
 
-       /* Pipe context should be found */
-       ASSERT(pipe_ctx);
+       if (i == dc->res_pool->pipe_count)
+               return false;
+
+       if (!pipe_ctx->stream->sink)
+               return false;
+
+       if (!pipe_ctx->stream->sink->link)
+               return false;
 
        /* Only supports eDP */
        if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP)
@@ -1831,8 +1832,9 @@ static bool should_enable_fbc(struct dc *dc,
 /*
  *  Enable FBC
  */
-static void enable_fbc(struct dc *dc,
-                      struct dc_state *context)
+static void enable_fbc(
+               struct dc *dc,
+               struct dc_state *context)
 {
        uint32_t pipe_idx = 0;
 
@@ -1842,10 +1844,9 @@ static void enable_fbc(struct dc *dc,
                struct compressor *compr = dc->fbc_compressor;
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
 
-
                params.source_view_width = pipe_ctx->stream->timing.h_addressable;
                params.source_view_height = pipe_ctx->stream->timing.v_addressable;
-
+               params.inst = pipe_ctx->stream_res.tg->inst;
                compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr;
 
                compr->funcs->surface_address_and_pitch(compr, &params);
@@ -2060,10 +2061,10 @@ enum dc_status dce110_apply_ctx_to_hw(
                        return status;
        }
 
-       dcb->funcs->set_scratch_critical_state(dcb, false);
-
        if (dc->fbc_compressor)
-               enable_fbc(dc, context);
+               enable_fbc(dc, dc->current_state);
+
+       dcb->funcs->set_scratch_critical_state(dcb, false);
 
        return DC_OK;
 }
@@ -2296,7 +2297,7 @@ static void dce110_enable_per_frame_crtc_position_reset(
        int i;
 
        gsl_params.gsl_group = 0;
-       gsl_params.gsl_master = grouped_pipes[0]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst;
+       gsl_params.gsl_master = 0;
 
        for (i = 0; i < group_size; i++)
                grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock(
@@ -2385,193 +2386,33 @@ static void init_hw(struct dc *dc)
 
 }
 
-void dce110_fill_display_configs(
-       const struct dc_state *context,
-       struct dm_pp_display_configuration *pp_display_cfg)
-{
-       int j;
-       int num_cfgs = 0;
-
-       for (j = 0; j < context->stream_count; j++) {
-               int k;
-
-               const struct dc_stream_state *stream = context->streams[j];
-               struct dm_pp_single_disp_config *cfg =
-                       &pp_display_cfg->disp_configs[num_cfgs];
-               const struct pipe_ctx *pipe_ctx = NULL;
-
-               for (k = 0; k < MAX_PIPES; k++)
-                       if (stream == context->res_ctx.pipe_ctx[k].stream) {
-                               pipe_ctx = &context->res_ctx.pipe_ctx[k];
-                               break;
-                       }
-
-               ASSERT(pipe_ctx != NULL);
-
-               /* only notify active stream */
-               if (stream->dpms_off)
-                       continue;
-
-               num_cfgs++;
-               cfg->signal = pipe_ctx->stream->signal;
-               cfg->pipe_idx = pipe_ctx->stream_res.tg->inst;
-               cfg->src_height = stream->src.height;
-               cfg->src_width = stream->src.width;
-               cfg->ddi_channel_mapping =
-                       stream->sink->link->ddi_channel_mapping.raw;
-               cfg->transmitter =
-                       stream->sink->link->link_enc->transmitter;
-               cfg->link_settings.lane_count =
-                       stream->sink->link->cur_link_settings.lane_count;
-               cfg->link_settings.link_rate =
-                       stream->sink->link->cur_link_settings.link_rate;
-               cfg->link_settings.link_spread =
-                       stream->sink->link->cur_link_settings.link_spread;
-               cfg->sym_clock = stream->phy_pix_clk;
-               /* Round v_refresh*/
-               cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
-               cfg->v_refresh /= stream->timing.h_total;
-               cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
-                                                       / stream->timing.v_total;
-       }
-
-       pp_display_cfg->display_count = num_cfgs;
-}
-
-uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
-{
-       uint8_t j;
-       uint32_t min_vertical_blank_time = -1;
-
-       for (j = 0; j < context->stream_count; j++) {
-               struct dc_stream_state *stream = context->streams[j];
-               uint32_t vertical_blank_in_pixels = 0;
-               uint32_t vertical_blank_time = 0;
-
-               vertical_blank_in_pixels = stream->timing.h_total *
-                       (stream->timing.v_total
-                        - stream->timing.v_addressable);
-
-               vertical_blank_time = vertical_blank_in_pixels
-                       * 1000 / stream->timing.pix_clk_khz;
-
-               if (min_vertical_blank_time > vertical_blank_time)
-                       min_vertical_blank_time = vertical_blank_time;
-       }
 
-       return min_vertical_blank_time;
-}
-
-static int determine_sclk_from_bounding_box(
-               const struct dc *dc,
-               int required_sclk)
-{
-       int i;
-
-       /*
-        * Some asics do not give us sclk levels, so we just report the actual
-        * required sclk
-        */
-       if (dc->sclk_lvls.num_levels == 0)
-               return required_sclk;
-
-       for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
-               if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
-                       return dc->sclk_lvls.clocks_in_khz[i];
-       }
-       /*
-        * even maximum level could not satisfy requirement, this
-        * is unexpected at this stage, should have been caught at
-        * validation time
-        */
-       ASSERT(0);
-       return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
-}
-
-static void pplib_apply_display_requirements(
-       struct dc *dc,
-       struct dc_state *context)
+void dce110_prepare_bandwidth(
+               struct dc *dc,
+               struct dc_state *context)
 {
-       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
-
-       pp_display_cfg->all_displays_in_sync =
-               context->bw.dce.all_displays_in_sync;
-       pp_display_cfg->nb_pstate_switch_disable =
-                       context->bw.dce.nbp_state_change_enable == false;
-       pp_display_cfg->cpu_cc6_disable =
-                       context->bw.dce.cpuc_state_change_enable == false;
-       pp_display_cfg->cpu_pstate_disable =
-                       context->bw.dce.cpup_state_change_enable == false;
-       pp_display_cfg->cpu_pstate_separation_time =
-                       context->bw.dce.blackout_recovery_time_us;
-
-       pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
-               / MEMORY_TYPE_MULTIPLIER;
-
-       pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
-                       dc,
-                       context->bw.dce.sclk_khz);
-
-       pp_display_cfg->min_dcfclock_khz = pp_display_cfg->min_engine_clock_khz;
-
-       pp_display_cfg->min_engine_clock_deep_sleep_khz
-                       = context->bw.dce.sclk_deep_sleep_khz;
-
-       pp_display_cfg->avail_mclk_switch_time_us =
-                                               dce110_get_min_vblank_time_us(context);
-       /* TODO: dce11.2*/
-       pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
-
-       pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz;
+       struct clk_mgr *dccg = dc->res_pool->clk_mgr;
 
-       dce110_fill_display_configs(context, pp_display_cfg);
+       dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
 
-       /* TODO: is this still applicable?*/
-       if (pp_display_cfg->display_count == 1) {
-               const struct dc_crtc_timing *timing =
-                       &context->streams[0]->timing;
-
-               pp_display_cfg->crtc_index =
-                       pp_display_cfg->disp_configs[0].pipe_idx;
-               pp_display_cfg->line_time_in_us = timing->h_total * 1000
-                                                       / timing->pix_clk_khz;
-       }
-
-       if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
-                       struct dm_pp_display_configuration)) !=  0)
-               dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
-       dc->prev_display_config = *pp_display_cfg;
+       dccg->funcs->update_clocks(
+                       dccg,
+                       context,
+                       false);
 }
 
-static void dce110_set_bandwidth(
+void dce110_optimize_bandwidth(
                struct dc *dc,
-               struct dc_state *context,
-               bool decrease_allowed)
+               struct dc_state *context)
 {
-       struct dc_clocks req_clks;
-       struct dccg *dccg = dc->res_pool->dccg;
-
-       req_clks.dispclk_khz = context->bw.dce.dispclk_khz;
-       req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context);
+       struct clk_mgr *dccg = dc->res_pool->clk_mgr;
 
-       if (decrease_allowed)
-               dce110_set_displaymarks(dc, context);
-       else
-               dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
-
-       if (dccg->funcs->update_dfs_bypass)
-               dccg->funcs->update_dfs_bypass(
-                       dccg,
-                       dc,
-                       context,
-                       req_clks.dispclk_khz);
+       dce110_set_displaymarks(dc, context);
 
        dccg->funcs->update_clocks(
                        dccg,
-                       &req_clks,
-                       decrease_allowed);
-       pplib_apply_display_requirements(dc, context);
+                       context,
+                       true);
 }
 
 static void dce110_program_front_end_for_pipe(
@@ -2582,7 +2423,6 @@ static void dce110_program_front_end_for_pipe(
        struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        struct xfm_grph_csc_adjustment adjust;
        struct out_csc_color_matrix tbl_entry;
-       unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
        unsigned int i;
        DC_LOGGER_INIT();
        memset(&tbl_entry, 0, sizeof(tbl_entry));
@@ -2623,15 +2463,6 @@ static void dce110_program_front_end_for_pipe(
 
        program_scaler(dc, pipe_ctx);
 
-       /* fbc not applicable on Underlay pipe */
-       if (dc->fbc_compressor && old_pipe->stream &&
-           pipe_ctx->pipe_idx != underlay_idx) {
-               if (plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)
-                       dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
-               else
-                       enable_fbc(dc, dc->current_state);
-       }
-
        mi->funcs->mem_input_program_surface_config(
                        mi,
                        plane_state->format,
@@ -2708,6 +2539,9 @@ static void dce110_apply_ctx_for_surface(
        if (num_planes == 0)
                return;
 
+       if (dc->fbc_compressor)
+               dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
+
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
                struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
@@ -2750,6 +2584,9 @@ static void dce110_apply_ctx_for_surface(
                        (pipe_ctx->plane_state || old_pipe_ctx->plane_state))
                        dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
        }
+
+       if (dc->fbc_compressor)
+               enable_fbc(dc, dc->current_state);
 }
 
 static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx)
@@ -2776,28 +2613,6 @@ static void dce110_wait_for_mpcc_disconnect(
        /* do nothing*/
 }
 
-static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
-               enum dc_color_space colorspace,
-               uint16_t *matrix)
-{
-       int i;
-       struct out_csc_color_matrix tbl_entry;
-
-       if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
-                               == true) {
-                       enum dc_color_space color_space =
-                               pipe_ctx->stream->output_color_space;
-
-                       //uint16_t matrix[12];
-                       for (i = 0; i < 12; i++)
-                               tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
-
-                       tbl_entry.color_space = color_space;
-                       //tbl_entry.regval = matrix;
-                       pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment(pipe_ctx->plane_res.xfm, &tbl_entry);
-       }
-}
-
 void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
 {
        struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
@@ -2846,13 +2661,8 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
                                pipe_ctx->plane_res.xfm, attributes);
 }
 
-static void ready_shared_resources(struct dc *dc, struct dc_state *context) {}
-
-static void optimize_shared_resources(struct dc *dc) {}
-
 static const struct hw_sequencer_funcs dce110_funcs = {
        .program_gamut_remap = program_gamut_remap,
-       .program_csc_matrix = program_csc_matrix,
        .init_hw = init_hw,
        .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
        .apply_ctx_for_surface = dce110_apply_ctx_for_surface,
@@ -2875,7 +2685,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
        .enable_display_power_gating = dce110_enable_display_power_gating,
        .disable_plane = dce110_power_down_fe,
        .pipe_control_lock = dce_pipe_control_lock,
-       .set_bandwidth = dce110_set_bandwidth,
+       .prepare_bandwidth = dce110_prepare_bandwidth,
+       .optimize_bandwidth = dce110_optimize_bandwidth,
        .set_drr = set_drr,
        .get_position = get_position,
        .set_static_screen_control = set_static_screen_control,
@@ -2884,9 +2695,6 @@ static const struct hw_sequencer_funcs dce110_funcs = {
        .setup_stereo = NULL,
        .set_avmute = dce110_set_avmute,
        .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
-       .ready_shared_resources = ready_shared_resources,
-       .optimize_shared_resources = optimize_shared_resources,
-       .pplib_apply_display_requirements = pplib_apply_display_requirements,
        .edp_backlight_control = hwss_edp_backlight_control,
        .edp_power_control = hwss_edp_power_control,
        .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
index d6db3dbd90153ba4a3f9511eb494552b143b4255..cd3e36d52a5239512fd2d7edbcfbbe53743b0fa4 100644 (file)
@@ -40,7 +40,6 @@ enum dc_status dce110_apply_ctx_to_hw(
                struct dc_state *context);
 
 
-
 void dce110_enable_stream(struct pipe_ctx *pipe_ctx);
 
 void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option);
@@ -64,11 +63,13 @@ void dce110_set_safe_displaymarks(
                struct resource_context *res_ctx,
                const struct resource_pool *pool);
 
-void dce110_fill_display_configs(
-       const struct dc_state *context,
-       struct dm_pp_display_configuration *pp_display_cfg);
+void dce110_prepare_bandwidth(
+               struct dc *dc,
+               struct dc_state *context);
 
-uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context);
+void dce110_optimize_bandwidth(
+               struct dc *dc,
+               struct dc_state *context);
 
 void dp_receiver_power_ctrl(struct dc_link *link, bool on);
 
index 7c9fd9052ee233f2c91d5a2c5cd4c91765603335..e33d11785b1fd11300c45579178887e95d223a6b 100644 (file)
@@ -31,6 +31,7 @@
 #include "resource.h"
 #include "dce110/dce110_resource.h"
 
+#include "dce/dce_clk_mgr.h"
 #include "include/irq_service_interface.h"
 #include "dce/dce_audio.h"
 #include "dce110/dce110_timing_generator.h"
@@ -45,7 +46,6 @@
 #include "dce110/dce110_transform_v.h"
 #include "dce/dce_opp.h"
 #include "dce110/dce110_opp_v.h"
-#include "dce/dce_clocks.h"
 #include "dce/dce_clock_source.h"
 #include "dce/dce_hwseq.h"
 #include "dce110/dce110_hw_sequencer.h"
@@ -148,15 +148,15 @@ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = {
 #define SRI(reg_name, block, id)\
        .reg_name = mm ## block ## id ## _ ## reg_name
 
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
                CLK_COMMON_REG_LIST_DCE_BASE()
 };
 
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
 };
 
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
 };
 
@@ -760,8 +760,8 @@ static void destruct(struct dce110_resource_pool *pool)
        if (pool->base.dmcu != NULL)
                dce_dmcu_destroy(&pool->base.dmcu);
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 
        if (pool->base.irqs != NULL) {
                dal_irq_service_destroy(&pool->base.irqs);
@@ -1173,12 +1173,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
                        &clks);
 
        dc->bw_vbios->low_yclk = bw_frc_to_fixed(
-               clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
+               clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
        dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
-               clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
+               clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
        dc->bw_vbios->high_yclk = bw_frc_to_fixed(
-               clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
+               clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
 }
 
@@ -1201,7 +1201,6 @@ static bool construct(
        struct dc_context *ctx = dc->ctx;
        struct dc_firmware_info info;
        struct dc_bios *bp;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -1257,11 +1256,11 @@ static bool construct(
                }
        }
 
-       pool->base.dccg = dce110_dccg_create(ctx,
+       pool->base.clk_mgr = dce110_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -1287,13 +1286,6 @@ static bool construct(
                goto res_create_fail;
        }
 
-       /* get static clock information for PPLIB or firmware, save
-        * max_clock_state
-        */
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                               static_clk_info.max_clocks_state;
-
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
index 3ce79c208ddfb8297766e9453da3097a78e022f6..969d4e72dc94266a77b601f94d6ffba7035f4a50 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "irq/dce110/irq_service_dce110.h"
 
+#include "dce/dce_clk_mgr.h"
 #include "dce/dce_mem_input.h"
 #include "dce/dce_transform.h"
 #include "dce/dce_link_encoder.h"
@@ -42,7 +43,6 @@
 #include "dce/dce_audio.h"
 #include "dce/dce_opp.h"
 #include "dce/dce_ipp.h"
-#include "dce/dce_clocks.h"
 #include "dce/dce_clock_source.h"
 
 #include "dce/dce_hwseq.h"
@@ -148,15 +148,15 @@ static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = {
        .reg_name = mm ## block ## id ## _ ## reg_name
 
 
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
                CLK_COMMON_REG_LIST_DCE_BASE()
 };
 
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
 };
 
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
 };
 
@@ -551,7 +551,8 @@ static struct transform *dce112_transform_create(
 static const struct encoder_feature_support link_enc_feature = {
                .max_hdmi_deep_color = COLOR_DEPTH_121212,
                .max_hdmi_pixel_clock = 600000,
-               .ycbcr420_supported = true,
+               .hdmi_ycbcr420_supported = true,
+               .dp_ycbcr420_supported = false,
                .flags.bits.IS_HBR2_CAPABLE = true,
                .flags.bits.IS_HBR3_CAPABLE = true,
                .flags.bits.IS_TPS3_CAPABLE = true,
@@ -749,8 +750,8 @@ static void destruct(struct dce110_resource_pool *pool)
        if (pool->base.dmcu != NULL)
                dce_dmcu_destroy(&pool->base.dmcu);
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 
        if (pool->base.irqs != NULL) {
                dal_irq_service_destroy(&pool->base.irqs);
@@ -1015,12 +1016,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
                                &clks);
 
                dc->bw_vbios->low_yclk = bw_frc_to_fixed(
-                       clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
+                       clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
                dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
-                       clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
+                       clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ,
                        1000);
                dc->bw_vbios->high_yclk = bw_frc_to_fixed(
-                       clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
+                       clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ,
                        1000);
 
                return;
@@ -1056,12 +1057,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
         * YCLK = UMACLK*m_memoryTypeMultiplier
         */
        dc->bw_vbios->low_yclk = bw_frc_to_fixed(
-               mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000);
+               mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
        dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
-               mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+               mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
        dc->bw_vbios->high_yclk = bw_frc_to_fixed(
-               mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+               mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
 
        /* Now notify PPLib/SMU about which Watermarks sets they should select
@@ -1131,7 +1132,6 @@ static bool construct(
 {
        unsigned int i;
        struct dc_context *ctx = dc->ctx;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -1199,11 +1199,11 @@ static bool construct(
                }
        }
 
-       pool->base.dccg = dce112_dccg_create(ctx,
+       pool->base.clk_mgr = dce112_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -1229,13 +1229,6 @@ static bool construct(
                goto res_create_fail;
        }
 
-       /* get static clock information for PPLIB or firmware, save
-        * max_clock_state
-        */
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                               static_clk_info.max_clocks_state;
-
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
index 79ab5f9f9115640fa85b4b079e8887b0f3a61232..f12696674eb0cb779f481ad4569ecca85825b069 100644 (file)
@@ -31,6 +31,7 @@
 #include "resource.h"
 #include "include/irq_service_interface.h"
 #include "dce120_resource.h"
+
 #include "dce112/dce112_resource.h"
 
 #include "dce110/dce110_resource.h"
@@ -39,7 +40,6 @@
 #include "irq/dce120/irq_service_dce120.h"
 #include "dce/dce_opp.h"
 #include "dce/dce_clock_source.h"
-#include "dce/dce_clocks.h"
 #include "dce/dce_ipp.h"
 #include "dce/dce_mem_input.h"
 
@@ -47,6 +47,7 @@
 #include "dce120/dce120_hw_sequencer.h"
 #include "dce/dce_transform.h"
 
+#include "dce/dce_clk_mgr.h"
 #include "dce/dce_audio.h"
 #include "dce/dce_link_encoder.h"
 #include "dce/dce_stream_encoder.h"
@@ -573,8 +574,8 @@ static void destruct(struct dce110_resource_pool *pool)
        if (pool->base.dmcu != NULL)
                dce_dmcu_destroy(&pool->base.dmcu);
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 }
 
 static void read_dce_straps(
@@ -606,7 +607,8 @@ static struct audio *create_audio(
 static const struct encoder_feature_support link_enc_feature = {
                .max_hdmi_deep_color = COLOR_DEPTH_121212,
                .max_hdmi_pixel_clock = 600000,
-               .ycbcr420_supported = true,
+               .hdmi_ycbcr420_supported = true,
+               .dp_ycbcr420_supported = false,
                .flags.bits.IS_HBR2_CAPABLE = true,
                .flags.bits.IS_HBR3_CAPABLE = true,
                .flags.bits.IS_TPS3_CAPABLE = true,
@@ -834,12 +836,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
         * YCLK = UMACLK*m_memoryTypeMultiplier
         */
        dc->bw_vbios->low_yclk = bw_frc_to_fixed(
-               mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000);
+               mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
        dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
-               mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+               mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
        dc->bw_vbios->high_yclk = bw_frc_to_fixed(
-               mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+               mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
                1000);
 
        /* Now notify PPLib/SMU about which Watermarks sets they should select
@@ -973,8 +975,8 @@ static bool construct(
                }
        }
 
-       pool->base.dccg = dce120_dccg_create(ctx);
-       if (pool->base.dccg == NULL) {
+       pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto dccg_create_fail;
index 6c6a1a16af19f0377fe78dfa2af4aa69416aba21..a60a90e68d91837d67c9331217f7bdbada9f7b07 100644 (file)
@@ -76,6 +76,7 @@ void dce80_hw_sequencer_construct(struct dc *dc)
 
        dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
        dc->hwss.pipe_control_lock = dce_pipe_control_lock;
-       dc->hwss.set_bandwidth = dce100_set_bandwidth;
+       dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
+       dc->hwss.optimize_bandwidth = dce100_prepare_bandwidth;
 }
 
index d68f951f98694b5e68c27152e7728d7c549ffab8..cdd1d6b7b9f2eb18cc1491bfe4b8ff9e5f470936 100644 (file)
 #include "dce110/dce110_timing_generator.h"
 #include "dce110/dce110_resource.h"
 #include "dce80/dce80_timing_generator.h"
+#include "dce/dce_clk_mgr.h"
 #include "dce/dce_mem_input.h"
 #include "dce/dce_link_encoder.h"
 #include "dce/dce_stream_encoder.h"
-#include "dce/dce_mem_input.h"
 #include "dce/dce_ipp.h"
 #include "dce/dce_transform.h"
 #include "dce/dce_opp.h"
-#include "dce/dce_clocks.h"
 #include "dce/dce_clock_source.h"
 #include "dce/dce_audio.h"
 #include "dce/dce_hwseq.h"
@@ -155,15 +154,15 @@ static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = {
        .reg_name = mm ## block ## id ## _ ## reg_name
 
 
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
                CLK_COMMON_REG_LIST_DCE_BASE()
 };
 
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
 };
 
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
 };
 
@@ -779,8 +778,8 @@ static void destruct(struct dce110_resource_pool *pool)
                }
        }
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 
        if (pool->base.irqs != NULL) {
                dal_irq_service_destroy(&pool->base.irqs);
@@ -793,7 +792,7 @@ bool dce80_validate_bandwidth(
 {
        /* TODO implement when needed but for now hardcode max value*/
        context->bw.dce.dispclk_khz = 681000;
-       context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER;
+       context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ;
 
        return true;
 }
@@ -855,7 +854,6 @@ static bool dce80_construct(
        struct dc_context *ctx = dc->ctx;
        struct dc_firmware_info info;
        struct dc_bios *bp;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -918,11 +916,11 @@ static bool dce80_construct(
                }
        }
 
-       pool->base.dccg = dce_dccg_create(ctx,
+       pool->base.clk_mgr = dce_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -948,10 +946,6 @@ static bool dce80_construct(
                goto res_create_fail;
        }
 
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                                       static_clk_info.max_clocks_state;
-
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
@@ -1065,7 +1059,6 @@ static bool dce81_construct(
        struct dc_context *ctx = dc->ctx;
        struct dc_firmware_info info;
        struct dc_bios *bp;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -1128,11 +1121,11 @@ static bool dce81_construct(
                }
        }
 
-       pool->base.dccg = dce_dccg_create(ctx,
+       pool->base.clk_mgr = dce_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -1158,10 +1151,6 @@ static bool dce81_construct(
                goto res_create_fail;
        }
 
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                                       static_clk_info.max_clocks_state;
-
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
@@ -1275,7 +1264,6 @@ static bool dce83_construct(
        struct dc_context *ctx = dc->ctx;
        struct dc_firmware_info info;
        struct dc_bios *bp;
-       struct dm_pp_static_clock_info static_clk_info = {0};
 
        ctx->dc_bios->regs = &bios_regs;
 
@@ -1334,11 +1322,11 @@ static bool dce83_construct(
                }
        }
 
-       pool->base.dccg = dce_dccg_create(ctx,
+       pool->base.clk_mgr = dce_clk_mgr_create(ctx,
                        &disp_clk_regs,
                        &disp_clk_shift,
                        &disp_clk_mask);
-       if (pool->base.dccg == NULL) {
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto res_create_fail;
@@ -1364,10 +1352,6 @@ static bool dce83_construct(
                goto res_create_fail;
        }
 
-       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
-               pool->base.dccg->max_clks_state =
-                                       static_clk_info.max_clocks_state;
-
        {
                struct irq_service_init_data init_data;
                init_data.ctx = dc->ctx;
index 032f872be89c8bd72b38959f773c04d0e988091c..55f293c8a3c057ecc6b79fb93bc40c6a4deb2572 100644 (file)
@@ -24,7 +24,7 @@
 
 DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o dcn10_hw_sequencer_debug.o \
                dcn10_dpp.o dcn10_opp.o dcn10_optc.o \
-               dcn10_hubp.o dcn10_mpc.o \
+               dcn10_hubp.o dcn10_mpc.o dcn10_clk_mgr.o \
                dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \
                dcn10_hubbub.o dcn10_stream_encoder.o dcn10_link_encoder.o
 
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
new file mode 100644 (file)
index 0000000..54abedb
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dcn10_clk_mgr.h"
+
+#include "reg_helper.h"
+#include "core_types.h"
+
+#define TO_DCE_CLK_MGR(clocks)\
+       container_of(clocks, struct dce_clk_mgr, base)
+
+#define REG(reg) \
+       (clk_mgr_dce->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+       clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name
+
+#define CTX \
+       clk_mgr_dce->base.ctx
+#define DC_LOGGER \
+       clk_mgr->ctx->logger
+
+void dcn1_pplib_apply_display_requirements(
+       struct dc *dc,
+       struct dc_state *context)
+{
+       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+       pp_display_cfg->min_engine_clock_khz = dc->res_pool->clk_mgr->clks.dcfclk_khz;
+       pp_display_cfg->min_memory_clock_khz = dc->res_pool->clk_mgr->clks.fclk_khz;
+       pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->clk_mgr->clks.dcfclk_deep_sleep_khz;
+       pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->clk_mgr->clks.dcfclk_deep_sleep_khz;
+       pp_display_cfg->min_dcfclock_khz = dc->res_pool->clk_mgr->clks.dcfclk_khz;
+       pp_display_cfg->disp_clk_khz = dc->res_pool->clk_mgr->clks.dispclk_khz;
+       dce110_fill_display_configs(context, pp_display_cfg);
+
+       dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static int dcn1_determine_dppclk_threshold(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks)
+{
+       bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
+       bool dispclk_increase = new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz;
+       int disp_clk_threshold = new_clocks->max_supported_dppclk_khz;
+       bool cur_dpp_div = clk_mgr->clks.dispclk_khz > clk_mgr->clks.dppclk_khz;
+
+       /* increase clock, looking for div is 0 for current, request div is 1*/
+       if (dispclk_increase) {
+               /* already divided by 2, no need to reach target clk with 2 steps*/
+               if (cur_dpp_div)
+                       return new_clocks->dispclk_khz;
+
+               /* request disp clk is lower than maximum supported dpp clk,
+                * no need to reach target clk with two steps.
+                */
+               if (new_clocks->dispclk_khz <= disp_clk_threshold)
+                       return new_clocks->dispclk_khz;
+
+               /* target dpp clk not request divided by 2, still within threshold */
+               if (!request_dpp_div)
+                       return new_clocks->dispclk_khz;
+
+       } else {
+               /* decrease clock, looking for current dppclk divided by 2,
+                * request dppclk not divided by 2.
+                */
+
+               /* current dpp clk not divided by 2, no need to ramp*/
+               if (!cur_dpp_div)
+                       return new_clocks->dispclk_khz;
+
+               /* current disp clk is lower than current maximum dpp clk,
+                * no need to ramp
+                */
+               if (clk_mgr->clks.dispclk_khz <= disp_clk_threshold)
+                       return new_clocks->dispclk_khz;
+
+               /* request dpp clk need to be divided by 2 */
+               if (request_dpp_div)
+                       return new_clocks->dispclk_khz;
+       }
+
+       return disp_clk_threshold;
+}
+
+static void dcn1_ramp_up_dispclk_with_dpp(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks)
+{
+       struct dc *dc = clk_mgr->ctx->dc;
+       int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(clk_mgr, new_clocks);
+       bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
+       int i;
+
+       /* set disp clk to dpp clk threshold */
+       dce112_set_clock(clk_mgr, dispclk_to_dpp_threshold);
+
+       /* update request dpp clk division option */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               if (!pipe_ctx->plane_state)
+                       continue;
+
+               pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control(
+                               pipe_ctx->plane_res.dpp,
+                               request_dpp_div,
+                               true);
+       }
+
+       /* If target clk not same as dppclk threshold, set to target clock */
+       if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz)
+               dce112_set_clock(clk_mgr, new_clocks->dispclk_khz);
+
+       clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
+       clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
+       clk_mgr->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz;
+}
+
+static int get_active_display_cnt(
+               struct dc *dc,
+               struct dc_state *context)
+{
+       int i, display_count;
+
+       display_count = 0;
+       for (i = 0; i < context->stream_count; i++) {
+               const struct dc_stream_state *stream = context->streams[i];
+
+               /*
+                * Only notify active stream or virtual stream.
+                * Need to notify virtual stream to work around
+                * headless case. HPD does not fire when system is in
+                * S0i2.
+                */
+               if (!stream->dpms_off || stream->signal == SIGNAL_TYPE_VIRTUAL)
+                       display_count++;
+       }
+
+       return display_count;
+}
+
+static void notify_deep_sleep_dcfclk_to_smu(
+               struct pp_smu_funcs_rv *pp_smu, int min_dcef_deep_sleep_clk_khz)
+{
+       int min_dcef_deep_sleep_clk_mhz; //minimum required DCEF Deep Sleep clock in mhz
+       /*
+        * if function pointer not set up, this message is
+        * sent as part of pplib_apply_display_requirements.
+        * So just return.
+        */
+       if (!pp_smu || !pp_smu->set_min_deep_sleep_dcfclk)
+               return;
+
+       min_dcef_deep_sleep_clk_mhz = (min_dcef_deep_sleep_clk_khz + 999) / 1000; //Round up
+       pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, min_dcef_deep_sleep_clk_mhz);
+}
+
+static void notify_hard_min_dcfclk_to_smu(
+               struct pp_smu_funcs_rv *pp_smu, int min_dcf_clk_khz)
+{
+       int min_dcf_clk_mhz; //minimum required DCF clock in mhz
+
+       /*
+        * if function pointer not set up, this message is
+        * sent as part of pplib_apply_display_requirements.
+        * So just return.
+        */
+       if (!pp_smu || !pp_smu->set_hard_min_dcfclk_by_freq)
+               return;
+
+       min_dcf_clk_mhz = min_dcf_clk_khz / 1000;
+
+       pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, min_dcf_clk_mhz);
+}
+
+static void notify_hard_min_fclk_to_smu(
+               struct pp_smu_funcs_rv *pp_smu, int min_f_clk_khz)
+{
+       int min_f_clk_mhz; //minimum required F clock in mhz
+
+       /*
+        * if function pointer not set up, this message is
+        * sent as part of pplib_apply_display_requirements.
+        * So just return.
+        */
+       if (!pp_smu || !pp_smu->set_hard_min_fclk_by_freq)
+               return;
+
+       min_f_clk_mhz = min_f_clk_khz / 1000;
+
+       pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, min_f_clk_mhz);
+}
+
+static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower)
+{
+       struct dc *dc = clk_mgr->ctx->dc;
+       struct dc_clocks *new_clocks = &context->bw.dcn.clk;
+       struct pp_smu_display_requirement_rv *smu_req_cur =
+                       &dc->res_pool->pp_smu_req;
+       struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
+       struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
+       uint32_t requested_dcf_clock_in_khz = 0;
+       bool send_request_to_increase = false;
+       bool send_request_to_lower = false;
+       int display_count;
+
+       bool enter_display_off = false;
+
+       display_count = get_active_display_cnt(dc, context);
+
+       if (display_count == 0)
+               enter_display_off = true;
+
+       if (enter_display_off == safe_to_lower) {
+               /*
+                * Notify SMU active displays
+                * if function pointer not set up, this message is
+                * sent as part of pplib_apply_display_requirements.
+                */
+               if (pp_smu->set_display_count)
+                       pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
+               else
+                       smu_req.display_count = display_count;
+
+       }
+
+       if (new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz
+                       || new_clocks->phyclk_khz > clk_mgr->clks.phyclk_khz
+                       || new_clocks->fclk_khz > clk_mgr->clks.fclk_khz
+                       || new_clocks->dcfclk_khz > clk_mgr->clks.dcfclk_khz)
+               send_request_to_increase = true;
+
+       if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) {
+               clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz;
+
+               send_request_to_lower = true;
+       }
+
+       // F Clock
+       if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) {
+               clk_mgr->clks.fclk_khz = new_clocks->fclk_khz;
+               smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000;
+
+               notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz);
+
+               send_request_to_lower = true;
+       }
+
+       //DCF Clock
+       if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) {
+               clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz;
+               smu_req.hard_min_dcefclk_mhz = new_clocks->dcfclk_khz / 1000;
+
+               send_request_to_lower = true;
+       }
+
+       if (should_set_clock(safe_to_lower,
+                       new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) {
+               clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
+               smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz / 1000;
+
+               send_request_to_lower = true;
+       }
+
+       /* make sure dcf clk is before dpp clk to
+        * make sure we have enough voltage to run dpp clk
+        */
+       if (send_request_to_increase) {
+               /*use dcfclk to request voltage*/
+               requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
+
+               notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz);
+
+               if (pp_smu->set_display_requirement)
+                       pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+
+               notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
+               dcn1_pplib_apply_display_requirements(dc, context);
+       }
+
+       /* dcn1 dppclk is tied to dispclk */
+       /* program dispclk on = as a w/a for sleep resume clock ramping issues */
+       if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)
+                       || new_clocks->dispclk_khz == clk_mgr->clks.dispclk_khz) {
+               dcn1_ramp_up_dispclk_with_dpp(clk_mgr, new_clocks);
+               clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
+
+               send_request_to_lower = true;
+       }
+
+       if (!send_request_to_increase && send_request_to_lower) {
+               /*use dcfclk to request voltage*/
+               requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
+
+               notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz);
+
+               if (pp_smu->set_display_requirement)
+                       pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+
+               notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
+               dcn1_pplib_apply_display_requirements(dc, context);
+       }
+
+
+       *smu_req_cur = smu_req;
+}
+static const struct clk_mgr_funcs dcn1_funcs = {
+       .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+       .update_clocks = dcn1_update_clocks
+};
+struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx)
+{
+       struct dc_debug_options *debug = &ctx->dc->debug;
+       struct dc_bios *bp = ctx->dc_bios;
+       struct dc_firmware_info fw_info = { { 0 } };
+       struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+       if (clk_mgr_dce == NULL) {
+               BREAK_TO_DEBUGGER();
+               return NULL;
+       }
+
+       clk_mgr_dce->base.ctx = ctx;
+       clk_mgr_dce->base.funcs = &dcn1_funcs;
+
+       clk_mgr_dce->dfs_bypass_disp_clk = 0;
+
+       clk_mgr_dce->dprefclk_ss_percentage = 0;
+       clk_mgr_dce->dprefclk_ss_divider = 1000;
+       clk_mgr_dce->ss_on_dprefclk = false;
+
+       clk_mgr_dce->dprefclk_khz = 600000;
+       if (bp->integrated_info)
+               clk_mgr_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
+       if (clk_mgr_dce->dentist_vco_freq_khz == 0) {
+               bp->funcs->get_firmware_info(bp, &fw_info);
+               clk_mgr_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq;
+               if (clk_mgr_dce->dentist_vco_freq_khz == 0)
+                       clk_mgr_dce->dentist_vco_freq_khz = 3600000;
+       }
+
+       if (!debug->disable_dfs_bypass && bp->integrated_info)
+               if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
+                       clk_mgr_dce->dfs_bypass_enabled = true;
+
+       dce_clock_read_ss_info(clk_mgr_dce);
+
+       return &clk_mgr_dce->base;
+}
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h
new file mode 100644 (file)
index 0000000..a995eda
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN10_CLK_MGR_H__
+#define __DCN10_CLK_MGR_H__
+
+#include "../dce/dce_clk_mgr.h"
+
+struct clk_bypass {
+       uint32_t dcfclk_bypass;
+       uint32_t dispclk_pypass;
+       uint32_t dprefclk_bypass;
+};
+
+void dcn1_pplib_apply_display_requirements(
+       struct dc *dc,
+       struct dc_state *context);
+
+struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx);
+
+#endif //__DCN10_CLK_MGR_H__
index 5d95a997fd9f96e5539cf6e91fa3d05483cf9a8f..7469333a2c8a5166800e9db7b830c20cbc788818 100644 (file)
@@ -71,39 +71,39 @@ void cm_helper_program_xfer_func(
        unsigned int i = 0;
 
        REG_SET_2(reg->start_cntl_b, 0,
-                       exp_region_start, params->arr_points[0].custom_float_x,
+                       exp_region_start, params->corner_points[0].blue.custom_float_x,
                        exp_resion_start_segment, 0);
        REG_SET_2(reg->start_cntl_g, 0,
-                       exp_region_start, params->arr_points[0].custom_float_x,
+                       exp_region_start, params->corner_points[0].green.custom_float_x,
                        exp_resion_start_segment, 0);
        REG_SET_2(reg->start_cntl_r, 0,
-                       exp_region_start, params->arr_points[0].custom_float_x,
+                       exp_region_start, params->corner_points[0].red.custom_float_x,
                        exp_resion_start_segment, 0);
 
        REG_SET(reg->start_slope_cntl_b, 0,
-                       field_region_linear_slope, params->arr_points[0].custom_float_slope);
+                       field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
        REG_SET(reg->start_slope_cntl_g, 0,
-                       field_region_linear_slope, params->arr_points[0].custom_float_slope);
+                       field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
        REG_SET(reg->start_slope_cntl_r, 0,
-                       field_region_linear_slope, params->arr_points[0].custom_float_slope);
+                       field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
 
        REG_SET(reg->start_end_cntl1_b, 0,
-                       field_region_end, params->arr_points[1].custom_float_x);
+                       field_region_end, params->corner_points[1].blue.custom_float_x);
        REG_SET_2(reg->start_end_cntl2_b, 0,
-                       field_region_end_slope, params->arr_points[1].custom_float_slope,
-                       field_region_end_base, params->arr_points[1].custom_float_y);
+                       field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
+                       field_region_end_base, params->corner_points[1].blue.custom_float_y);
 
        REG_SET(reg->start_end_cntl1_g, 0,
-                       field_region_end, params->arr_points[1].custom_float_x);
+                       field_region_end, params->corner_points[1].green.custom_float_x);
        REG_SET_2(reg->start_end_cntl2_g, 0,
-                       field_region_end_slope, params->arr_points[1].custom_float_slope,
-               field_region_end_base, params->arr_points[1].custom_float_y);
+                       field_region_end_slope, params->corner_points[1].green.custom_float_slope,
+               field_region_end_base, params->corner_points[1].green.custom_float_y);
 
        REG_SET(reg->start_end_cntl1_r, 0,
-                       field_region_end, params->arr_points[1].custom_float_x);
+                       field_region_end, params->corner_points[1].red.custom_float_x);
        REG_SET_2(reg->start_end_cntl2_r, 0,
-                       field_region_end_slope, params->arr_points[1].custom_float_slope,
-               field_region_end_base, params->arr_points[1].custom_float_y);
+                       field_region_end_slope, params->corner_points[1].red.custom_float_slope,
+               field_region_end_base, params->corner_points[1].red.custom_float_y);
 
        for (reg_region_cur = reg->region_start;
                        reg_region_cur <= reg->region_end;
@@ -127,7 +127,7 @@ void cm_helper_program_xfer_func(
 
 bool cm_helper_convert_to_custom_float(
                struct pwl_result_data *rgb_resulted,
-               struct curve_points *arr_points,
+               struct curve_points3 *corner_points,
                uint32_t hw_points_num,
                bool fixpoint)
 {
@@ -141,20 +141,53 @@ bool cm_helper_convert_to_custom_float(
        fmt.mantissa_bits = 12;
        fmt.sign = false;
 
-       if (!convert_to_custom_float_format(arr_points[0].x, &fmt,
-                                           &arr_points[0].custom_float_x)) {
+       /* corner_points[0] - beginning base, slope offset for R,G,B
+        * corner_points[1] - end base, slope offset for R,G,B
+        */
+       if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
+                               &corner_points[0].red.custom_float_x)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
+                               &corner_points[0].green.custom_float_x)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
+                               &corner_points[0].blue.custom_float_x)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
 
-       if (!convert_to_custom_float_format(arr_points[0].offset, &fmt,
-                                           &arr_points[0].custom_float_offset)) {
+       if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
+                               &corner_points[0].red.custom_float_offset)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
+                               &corner_points[0].green.custom_float_offset)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
+                               &corner_points[0].blue.custom_float_offset)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
 
-       if (!convert_to_custom_float_format(arr_points[0].slope, &fmt,
-                                           &arr_points[0].custom_float_slope)) {
+       if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
+                               &corner_points[0].red.custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
+                               &corner_points[0].green.custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
+                               &corner_points[0].blue.custom_float_slope)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
@@ -162,22 +195,59 @@ bool cm_helper_convert_to_custom_float(
        fmt.mantissa_bits = 10;
        fmt.sign = false;
 
-       if (!convert_to_custom_float_format(arr_points[1].x, &fmt,
-                                           &arr_points[1].custom_float_x)) {
+       if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
+                               &corner_points[1].red.custom_float_x)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
-
-       if (fixpoint == true)
-               arr_points[1].custom_float_y = dc_fixpt_clamp_u0d14(arr_points[1].y);
-       else if (!convert_to_custom_float_format(arr_points[1].y, &fmt,
-               &arr_points[1].custom_float_y)) {
+       if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
+                               &corner_points[1].green.custom_float_x)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
+                               &corner_points[1].blue.custom_float_x)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
 
-       if (!convert_to_custom_float_format(arr_points[1].slope, &fmt,
-                                           &arr_points[1].custom_float_slope)) {
+       if (fixpoint == true) {
+               corner_points[1].red.custom_float_y =
+                               dc_fixpt_clamp_u0d14(corner_points[1].red.y);
+               corner_points[1].green.custom_float_y =
+                               dc_fixpt_clamp_u0d14(corner_points[1].green.y);
+               corner_points[1].blue.custom_float_y =
+                               dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
+       } else {
+               if (!convert_to_custom_float_format(corner_points[1].red.y,
+                               &fmt, &corner_points[1].red.custom_float_y)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+               if (!convert_to_custom_float_format(corner_points[1].green.y,
+                               &fmt, &corner_points[1].green.custom_float_y)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+               if (!convert_to_custom_float_format(corner_points[1].blue.y,
+                               &fmt, &corner_points[1].blue.custom_float_y)) {
+                       BREAK_TO_DEBUGGER();
+                       return false;
+               }
+       }
+
+       if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
+                               &corner_points[1].red.custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
+                               &corner_points[1].green.custom_float_slope)) {
+               BREAK_TO_DEBUGGER();
+               return false;
+       }
+       if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
+                               &corner_points[1].blue.custom_float_slope)) {
                BREAK_TO_DEBUGGER();
                return false;
        }
@@ -242,15 +312,10 @@ bool cm_helper_translate_curve_to_hw_format(
                                const struct dc_transfer_func *output_tf,
                                struct pwl_params *lut_params, bool fixpoint)
 {
-       struct curve_points *arr_points;
+       struct curve_points3 *corner_points;
        struct pwl_result_data *rgb_resulted;
        struct pwl_result_data *rgb;
        struct pwl_result_data *rgb_plus_1;
-       struct fixed31_32 y_r;
-       struct fixed31_32 y_g;
-       struct fixed31_32 y_b;
-       struct fixed31_32 y1_min;
-       struct fixed31_32 y3_max;
 
        int32_t region_start, region_end;
        int32_t i;
@@ -259,16 +324,16 @@ bool cm_helper_translate_curve_to_hw_format(
        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
                return false;
 
-       PERF_TRACE();
+       PERF_TRACE_CTX(output_tf->ctx);
 
-       arr_points = lut_params->arr_points;
+       corner_points = lut_params->corner_points;
        rgb_resulted = lut_params->rgb_resulted;
        hw_points = 0;
 
        memset(lut_params, 0, sizeof(struct pwl_params));
        memset(seg_distr, 0, sizeof(seg_distr));
 
-       if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
+       if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
                /* 32 segments
                 * segments are from 2^-25 to 2^7
                 */
@@ -327,31 +392,37 @@ bool cm_helper_translate_curve_to_hw_format(
        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 
-       arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+       // All 3 color channels have same x
+       corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
                                             dc_fixpt_from_int(region_start));
-       arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
-                                            dc_fixpt_from_int(region_end));
+       corner_points[0].green.x = corner_points[0].red.x;
+       corner_points[0].blue.x = corner_points[0].red.x;
 
-       y_r = rgb_resulted[0].red;
-       y_g = rgb_resulted[0].green;
-       y_b = rgb_resulted[0].blue;
+       corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
+                                            dc_fixpt_from_int(region_end));
+       corner_points[1].green.x = corner_points[1].red.x;
+       corner_points[1].blue.x = corner_points[1].red.x;
 
-       y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
+       corner_points[0].red.y = rgb_resulted[0].red;
+       corner_points[0].green.y = rgb_resulted[0].green;
+       corner_points[0].blue.y = rgb_resulted[0].blue;
 
-       arr_points[0].y = y1_min;
-       arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
-       y_r = rgb_resulted[hw_points - 1].red;
-       y_g = rgb_resulted[hw_points - 1].green;
-       y_b = rgb_resulted[hw_points - 1].blue;
+       corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
+                       corner_points[0].red.x);
+       corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
+                       corner_points[0].green.x);
+       corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
+                       corner_points[0].blue.x);
 
        /* see comment above, m_arrPoints[1].y should be the Y value for the
         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
         */
-       y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
-
-       arr_points[1].y = y3_max;
-
-       arr_points[1].slope = dc_fixpt_zero;
+       corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
+       corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
+       corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
+       corner_points[1].red.slope = dc_fixpt_zero;
+       corner_points[1].green.slope = dc_fixpt_zero;
+       corner_points[1].blue.slope = dc_fixpt_zero;
 
        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
                /* for PQ, we want to have a straight line from last HW X point,
@@ -360,9 +431,15 @@ bool cm_helper_translate_curve_to_hw_format(
                const struct fixed31_32 end_value =
                                dc_fixpt_from_int(125);
 
-               arr_points[1].slope = dc_fixpt_div(
-                       dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
-                       dc_fixpt_sub(end_value, arr_points[1].x));
+               corner_points[1].red.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
+                       dc_fixpt_sub(end_value, corner_points[1].red.x));
+               corner_points[1].green.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
+                       dc_fixpt_sub(end_value, corner_points[1].green.x));
+               corner_points[1].blue.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
+                       dc_fixpt_sub(end_value, corner_points[1].blue.x));
        }
 
        lut_params->hw_points_num = hw_points;
@@ -411,7 +488,7 @@ bool cm_helper_translate_curve_to_hw_format(
                ++i;
        }
        cm_helper_convert_to_custom_float(rgb_resulted,
-                                               lut_params->arr_points,
+                                               lut_params->corner_points,
                                                hw_points, fixpoint);
 
        return true;
@@ -424,15 +501,10 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
                                const struct dc_transfer_func *output_tf,
                                struct pwl_params *lut_params)
 {
-       struct curve_points *arr_points;
+       struct curve_points3 *corner_points;
        struct pwl_result_data *rgb_resulted;
        struct pwl_result_data *rgb;
        struct pwl_result_data *rgb_plus_1;
-       struct fixed31_32 y_r;
-       struct fixed31_32 y_g;
-       struct fixed31_32 y_b;
-       struct fixed31_32 y1_min;
-       struct fixed31_32 y3_max;
 
        int32_t region_start, region_end;
        int32_t i;
@@ -441,9 +513,9 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
                return false;
 
-       PERF_TRACE();
+       PERF_TRACE_CTX(output_tf->ctx);
 
-       arr_points = lut_params->arr_points;
+       corner_points = lut_params->corner_points;
        rgb_resulted = lut_params->rgb_resulted;
        hw_points = 0;
 
@@ -489,31 +561,28 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 
-       arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+       corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
                                             dc_fixpt_from_int(region_start));
-       arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+       corner_points[0].green.x = corner_points[0].red.x;
+       corner_points[0].blue.x = corner_points[0].red.x;
+       corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
                                             dc_fixpt_from_int(region_end));
+       corner_points[1].green.x = corner_points[1].red.x;
+       corner_points[1].blue.x = corner_points[1].red.x;
 
-       y_r = rgb_resulted[0].red;
-       y_g = rgb_resulted[0].green;
-       y_b = rgb_resulted[0].blue;
-
-       y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
-
-       arr_points[0].y = y1_min;
-       arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
-       y_r = rgb_resulted[hw_points - 1].red;
-       y_g = rgb_resulted[hw_points - 1].green;
-       y_b = rgb_resulted[hw_points - 1].blue;
+       corner_points[0].red.y = rgb_resulted[0].red;
+       corner_points[0].green.y = rgb_resulted[0].green;
+       corner_points[0].blue.y = rgb_resulted[0].blue;
 
        /* see comment above, m_arrPoints[1].y should be the Y value for the
         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
         */
-       y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
-
-       arr_points[1].y = y3_max;
-
-       arr_points[1].slope = dc_fixpt_zero;
+       corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
+       corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
+       corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
+       corner_points[1].red.slope = dc_fixpt_zero;
+       corner_points[1].green.slope = dc_fixpt_zero;
+       corner_points[1].blue.slope = dc_fixpt_zero;
 
        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
                /* for PQ, we want to have a straight line from last HW X point,
@@ -522,9 +591,15 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
                const struct fixed31_32 end_value =
                                dc_fixpt_from_int(125);
 
-               arr_points[1].slope = dc_fixpt_div(
-                       dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
-                       dc_fixpt_sub(end_value, arr_points[1].x));
+               corner_points[1].red.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
+                       dc_fixpt_sub(end_value, corner_points[1].red.x));
+               corner_points[1].green.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
+                       dc_fixpt_sub(end_value, corner_points[1].green.x));
+               corner_points[1].blue.slope = dc_fixpt_div(
+                       dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
+                       dc_fixpt_sub(end_value, corner_points[1].blue.x));
        }
 
        lut_params->hw_points_num = hw_points;
@@ -564,7 +639,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
                ++i;
        }
        cm_helper_convert_to_custom_float(rgb_resulted,
-                                               lut_params->arr_points,
+                                               lut_params->corner_points,
                                                hw_points, false);
 
        return true;
index 7a531b02871f89bdfbd36a1a4279cb23fd24d775..5ae4d69391a568548cca47d9acb1a495fa61ee6c 100644 (file)
@@ -98,7 +98,7 @@ void cm_helper_program_xfer_func(
 
 bool cm_helper_convert_to_custom_float(
                struct pwl_result_data *rgb_resulted,
-               struct curve_points *arr_points,
+               struct curve_points3 *corner_points,
                uint32_t hw_points_num,
                bool fixpoint);
 
index 4254e7e1a509674efef528d5f647c00740caa0c3..c7d1e678ebf5b1a22d2fc35e8b83e05d2ea50159 100644 (file)
@@ -100,7 +100,7 @@ bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
        REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
                        DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable);
 
-       return true ? false : enable;
+       return enable ? true : false;
 }
 
 
index 74132a1f3046bfb8dc617ff27c136632ea329705..345af015d061f0850ccf64b633a9404293d7f381 100644 (file)
@@ -99,6 +99,14 @@ static unsigned int hubp1_get_underflow_status(struct hubp *hubp)
        return hubp_underflow;
 }
 
+
+void hubp1_clear_underflow(struct hubp *hubp)
+{
+       struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+
+       REG_UPDATE(DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, 1);
+}
+
 static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank)
 {
        struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
@@ -565,19 +573,6 @@ void hubp1_program_deadline(
                REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler,
                DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler);
 
-       if (REG(PREFETCH_SETTINS))
-               REG_SET_2(PREFETCH_SETTINS, 0,
-                       DST_Y_PREFETCH, dlg_attr->dst_y_prefetch,
-                       VRATIO_PREFETCH, dlg_attr->vratio_prefetch);
-       else
-               REG_SET_2(PREFETCH_SETTINGS, 0,
-                       DST_Y_PREFETCH, dlg_attr->dst_y_prefetch,
-                       VRATIO_PREFETCH, dlg_attr->vratio_prefetch);
-
-       REG_SET_2(VBLANK_PARAMETERS_0, 0,
-               DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank,
-               DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank);
-
        REG_SET(REF_FREQ_TO_PIX_FREQ, 0,
                REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq);
 
@@ -585,9 +580,6 @@ void hubp1_program_deadline(
        REG_SET(VBLANK_PARAMETERS_1, 0,
                REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l);
 
-       REG_SET(VBLANK_PARAMETERS_3, 0,
-               REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l);
-
        if (REG(NOM_PARAMETERS_0))
                REG_SET(NOM_PARAMETERS_0, 0,
                        DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l);
@@ -602,27 +594,13 @@ void hubp1_program_deadline(
        REG_SET(NOM_PARAMETERS_5, 0,
                REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l);
 
-       REG_SET_2(PER_LINE_DELIVERY_PRE, 0,
-               REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l,
-               REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c);
-
        REG_SET_2(PER_LINE_DELIVERY, 0,
                REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l,
                REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c);
 
-       if (REG(PREFETCH_SETTINS_C))
-               REG_SET(PREFETCH_SETTINS_C, 0,
-                       VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c);
-       else
-               REG_SET(PREFETCH_SETTINGS_C, 0,
-                       VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c);
-
        REG_SET(VBLANK_PARAMETERS_2, 0,
                REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c);
 
-       REG_SET(VBLANK_PARAMETERS_4, 0,
-               REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c);
-
        if (REG(NOM_PARAMETERS_2))
                REG_SET(NOM_PARAMETERS_2, 0,
                        DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c);
@@ -642,10 +620,6 @@ void hubp1_program_deadline(
                QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm,
                QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm);
 
-       REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0,
-               MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank,
-               QoS_LEVEL_FLIP, ttu_attr->qos_level_flip);
-
        /* TTU - per luma/chroma */
        /* Assumed surf0 is luma and 1 is chroma */
 
@@ -654,25 +628,15 @@ void hubp1_program_deadline(
                QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l,
                QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l);
 
-       REG_SET(DCN_SURF0_TTU_CNTL1, 0,
-               REFCYC_PER_REQ_DELIVERY_PRE,
-               ttu_attr->refcyc_per_req_delivery_pre_l);
-
        REG_SET_3(DCN_SURF1_TTU_CNTL0, 0,
                REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c,
                QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c,
                QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c);
 
-       REG_SET(DCN_SURF1_TTU_CNTL1, 0,
-               REFCYC_PER_REQ_DELIVERY_PRE,
-               ttu_attr->refcyc_per_req_delivery_pre_c);
-
        REG_SET_3(DCN_CUR0_TTU_CNTL0, 0,
                REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0,
                QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0,
                QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0);
-       REG_SET(DCN_CUR0_TTU_CNTL1, 0,
-               REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0);
 }
 
 static void hubp1_setup(
@@ -690,6 +654,48 @@ static void hubp1_setup(
        hubp1_vready_workaround(hubp, pipe_dest);
 }
 
+static void hubp1_setup_interdependent(
+               struct hubp *hubp,
+               struct _vcs_dpi_display_dlg_regs_st *dlg_attr,
+               struct _vcs_dpi_display_ttu_regs_st *ttu_attr)
+{
+       struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+
+       REG_SET_2(PREFETCH_SETTINS, 0,
+               DST_Y_PREFETCH, dlg_attr->dst_y_prefetch,
+               VRATIO_PREFETCH, dlg_attr->vratio_prefetch);
+
+       REG_SET(PREFETCH_SETTINS_C, 0,
+               VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c);
+
+       REG_SET_2(VBLANK_PARAMETERS_0, 0,
+               DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank,
+               DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank);
+
+       REG_SET(VBLANK_PARAMETERS_3, 0,
+               REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l);
+
+       REG_SET(VBLANK_PARAMETERS_4, 0,
+               REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c);
+
+       REG_SET_2(PER_LINE_DELIVERY_PRE, 0,
+               REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l,
+               REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c);
+
+       REG_SET(DCN_SURF0_TTU_CNTL1, 0,
+               REFCYC_PER_REQ_DELIVERY_PRE,
+               ttu_attr->refcyc_per_req_delivery_pre_l);
+       REG_SET(DCN_SURF1_TTU_CNTL1, 0,
+               REFCYC_PER_REQ_DELIVERY_PRE,
+               ttu_attr->refcyc_per_req_delivery_pre_c);
+       REG_SET(DCN_CUR0_TTU_CNTL1, 0,
+               REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0);
+
+       REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0,
+               MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank,
+               QoS_LEVEL_FLIP, ttu_attr->qos_level_flip);
+}
+
 bool hubp1_is_flip_pending(struct hubp *hubp)
 {
        uint32_t flip_pending = 0;
@@ -1178,6 +1184,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = {
                        hubp1_program_surface_config,
        .hubp_is_flip_pending = hubp1_is_flip_pending,
        .hubp_setup = hubp1_setup,
+       .hubp_setup_interdependent = hubp1_setup_interdependent,
        .hubp_set_vm_system_aperture_settings = hubp1_set_vm_system_aperture_settings,
        .hubp_set_vm_context0_settings = hubp1_set_vm_context0_settings,
        .set_blank = hubp1_set_blank,
@@ -1190,6 +1197,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = {
        .hubp_clk_cntl = hubp1_clk_cntl,
        .hubp_vtg_sel = hubp1_vtg_sel,
        .hubp_read_state = hubp1_read_state,
+       .hubp_clear_underflow = hubp1_clear_underflow,
        .hubp_disable_control =  hubp1_disable_control,
        .hubp_get_underflow_status = hubp1_get_underflow_status,
 
index 4890273b632b576388d7532cbdf86b9bf4bd308f..62d4232e7796cfa2d2064f088083c4500e687510 100644 (file)
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\
+       HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, mask_sh),\
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\
        HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE, mask_sh),\
        type HUBP_NO_OUTSTANDING_REQ;\
        type HUBP_VTG_SEL;\
        type HUBP_UNDERFLOW_STATUS;\
+       type HUBP_UNDERFLOW_CLEAR;\
        type NUM_PIPES;\
        type NUM_BANKS;\
        type PIPE_INTERLEAVE;\
@@ -739,6 +741,7 @@ void dcn10_hubp_construct(
        const struct dcn_mi_mask *hubp_mask);
 
 void hubp1_read_state(struct hubp *hubp);
+void hubp1_clear_underflow(struct hubp *hubp);
 
 enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch);
 
index 193184affefbebc7c555411e881195675526d3d8..0bd33a713836b6b1b0bd8c828517fc73d055a777 100644 (file)
@@ -45,6 +45,7 @@
 #include "dcn10_hubbub.h"
 #include "dcn10_cm_common.h"
 #include "dc_link_dp.h"
+#include "dccg.h"
 
 #define DC_LOGGER_INIT(logger)
 
@@ -786,7 +787,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
                        &dc->current_state->res_ctx.pipe_ctx[i];
                if (pipe_ctx != NULL) {
                        hubp = pipe_ctx->plane_res.hubp;
-                       if (hubp != NULL) {
+                       if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) {
                                if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
                                        /* one pipe underflow, we will reset all the pipes*/
                                        need_recover = true;
@@ -812,7 +813,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
                if (pipe_ctx != NULL) {
                        hubp = pipe_ctx->plane_res.hubp;
                        /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
-                       if (hubp != NULL)
+                       if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
                                hubp->funcs->set_hubp_blank_en(hubp, true);
                }
        }
@@ -825,7 +826,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
                if (pipe_ctx != NULL) {
                        hubp = pipe_ctx->plane_res.hubp;
                        /*DCHUBP_CNTL:HUBP_DISABLE=1*/
-                       if (hubp != NULL)
+                       if (hubp != NULL && hubp->funcs->hubp_disable_control)
                                hubp->funcs->hubp_disable_control(hubp, true);
                }
        }
@@ -835,7 +836,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
                if (pipe_ctx != NULL) {
                        hubp = pipe_ctx->plane_res.hubp;
                        /*DCHUBP_CNTL:HUBP_DISABLE=0*/
-                       if (hubp != NULL)
+                       if (hubp != NULL && hubp->funcs->hubp_disable_control)
                                hubp->funcs->hubp_disable_control(hubp, true);
                }
        }
@@ -847,7 +848,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
                if (pipe_ctx != NULL) {
                        hubp = pipe_ctx->plane_res.hubp;
                        /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
-                       if (hubp != NULL)
+                       if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
                                hubp->funcs->set_hubp_blank_en(hubp, true);
                }
        }
@@ -1126,7 +1127,7 @@ static void dcn10_init_hw(struct dc *dc)
 
        enable_power_gating_plane(dc->hwseq, true);
 
-       memset(&dc->res_pool->dccg->clks, 0, sizeof(dc->res_pool->dccg->clks));
+       memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks));
 }
 
 static void reset_hw_ctx_wrap(
@@ -1226,7 +1227,8 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx,
                tf = plane_state->in_transfer_func;
 
        if (plane_state->gamma_correction &&
-               !plane_state->gamma_correction->is_identity
+               !dpp_base->ctx->dc->debug.always_use_regamma
+               && !plane_state->gamma_correction->is_identity
                        && dce_use_lut(plane_state->format))
                dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction);
 
@@ -1399,7 +1401,7 @@ static void dcn10_enable_per_frame_crtc_position_reset(
                if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset)
                        grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
                                        grouped_pipes[i]->stream_res.tg,
-                                       grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst,
+                                       0,
                                        &grouped_pipes[i]->stream->triggered_crtc_reset);
 
        DC_SYNC_INFO("Waiting for trigger\n");
@@ -1603,7 +1605,7 @@ static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1,
 }
 
 
-static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
+void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
 {
        struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
        struct vm_system_aperture_param apt = { {{ 0 } } };
@@ -1703,33 +1705,22 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
        pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
 }
 
-
-static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
+static void dcn10_program_output_csc(struct dc *dc,
+               struct pipe_ctx *pipe_ctx,
                enum dc_color_space colorspace,
-               uint16_t *matrix)
+               uint16_t *matrix,
+               int opp_id)
 {
        if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
-                       if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
-                               pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
+               if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
+                       pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
        } else {
                if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL)
                        pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);
        }
 }
 
-static void dcn10_program_output_csc(struct dc *dc,
-               struct pipe_ctx *pipe_ctx,
-               enum dc_color_space colorspace,
-               uint16_t *matrix,
-               int opp_id)
-{
-       if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
-               program_csc_matrix(pipe_ctx,
-                               colorspace,
-                               matrix);
-}
-
-static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
 {
        if (pipe_ctx->plane_state->visible)
                return true;
@@ -1738,7 +1729,7 @@ static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
        return false;
 }
 
-static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
 {
        if (pipe_ctx->plane_state->visible)
                return true;
@@ -1747,7 +1738,7 @@ static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
        return false;
 }
 
-static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
 {
        if (pipe_ctx->plane_state->visible)
                return true;
@@ -1780,7 +1771,7 @@ bool is_rgb_cspace(enum dc_color_space output_color_space)
        }
 }
 
-static void dcn10_get_surface_visual_confirm_color(
+void dcn10_get_surface_visual_confirm_color(
                const struct pipe_ctx *pipe_ctx,
                struct tg_color *color)
 {
@@ -1816,7 +1807,7 @@ static void dcn10_get_surface_visual_confirm_color(
        }
 }
 
-static void dcn10_get_hdr_visual_confirm_color(
+void dcn10_get_hdr_visual_confirm_color(
                struct pipe_ctx *pipe_ctx,
                struct tg_color *color)
 {
@@ -1943,10 +1934,6 @@ static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
        struct mpc *mpc = dc->res_pool->mpc;
        struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
 
-
-
-       /* TODO: proper fix once fpga works */
-
        if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
                dcn10_get_hdr_visual_confirm_color(
                                pipe_ctx, &blnd_cfg.black_color);
@@ -2026,8 +2013,6 @@ static void update_scaler(struct pipe_ctx *pipe_ctx)
        bool per_pixel_alpha =
                        pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
 
-       /* TODO: proper fix once fpga works */
-
        pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
        pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
        /* scaler configuration */
@@ -2035,7 +2020,7 @@ static void update_scaler(struct pipe_ctx *pipe_ctx)
                        pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
 }
 
-static void update_dchubp_dpp(
+void update_dchubp_dpp(
        struct dc *dc,
        struct pipe_ctx *pipe_ctx,
        struct dc_state *context)
@@ -2052,16 +2037,22 @@ static void update_dchubp_dpp(
         */
        if (plane_state->update_flags.bits.full_update) {
                bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <=
-                               dc->res_pool->dccg->clks.dispclk_khz / 2;
+                               dc->res_pool->clk_mgr->clks.dispclk_khz / 2;
 
                dpp->funcs->dpp_dppclk_control(
                                dpp,
                                should_divided_by_2,
                                true);
 
-               dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ?
-                                               dc->res_pool->dccg->clks.dispclk_khz / 2 :
-                                                       dc->res_pool->dccg->clks.dispclk_khz;
+               if (dc->res_pool->dccg)
+                       dc->res_pool->dccg->funcs->update_dpp_dto(
+                                       dc->res_pool->dccg,
+                                       dpp->inst,
+                                       pipe_ctx->plane_res.bw.calc.dppclk_khz);
+               else
+                       dc->res_pool->clk_mgr->clks.dppclk_khz = should_divided_by_2 ?
+                                               dc->res_pool->clk_mgr->clks.dispclk_khz / 2 :
+                                                       dc->res_pool->clk_mgr->clks.dispclk_khz;
        }
 
        /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
@@ -2077,6 +2068,10 @@ static void update_dchubp_dpp(
                        &pipe_ctx->ttu_regs,
                        &pipe_ctx->rq_regs,
                        &pipe_ctx->pipe_dlg_param);
+               hubp->funcs->hubp_setup_interdependent(
+                       hubp,
+                       &pipe_ctx->dlg_regs,
+                       &pipe_ctx->ttu_regs);
        }
 
        size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport;
@@ -2182,7 +2177,7 @@ static void dcn10_blank_pixel_data(
        }
 }
 
-static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
+void set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
 {
        struct fixed31_32 multiplier = dc_fixpt_from_fraction(
                        pipe_ctx->plane_state->sdr_white_level, 80);
@@ -2257,47 +2252,7 @@ static void program_all_pipe_in_tree(
        }
 }
 
-static void dcn10_pplib_apply_display_requirements(
-       struct dc *dc,
-       struct dc_state *context)
-{
-       struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
-
-       pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz;
-       pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz;
-       pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz;
-       pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz;
-       pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz;
-       pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz;
-       dce110_fill_display_configs(context, pp_display_cfg);
-
-       if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
-                       struct dm_pp_display_configuration)) !=  0)
-               dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
-       dc->prev_display_config = *pp_display_cfg;
-}
-
-static void optimize_shared_resources(struct dc *dc)
-{
-       if (dc->current_state->stream_count == 0) {
-               /* S0i2 message */
-               dcn10_pplib_apply_display_requirements(dc, dc->current_state);
-       }
-
-       if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
-               dcn_bw_notify_pplib_of_wm_ranges(dc);
-}
-
-static void ready_shared_resources(struct dc *dc, struct dc_state *context)
-{
-       /* S0i2 message */
-       if (dc->current_state->stream_count == 0 &&
-                       context->stream_count != 0)
-               dcn10_pplib_apply_display_requirements(dc, context);
-}
-
-static struct pipe_ctx *find_top_pipe_for_stream(
+struct pipe_ctx *find_top_pipe_for_stream(
                struct dc *dc,
                struct dc_state *context,
                const struct dc_stream_state *stream)
@@ -2387,6 +2342,32 @@ static void dcn10_apply_ctx_for_surface(
 
        dcn10_pipe_control_lock(dc, top_pipe_to_program, false);
 
+       if (top_pipe_to_program->plane_state &&
+                       top_pipe_to_program->plane_state->update_flags.bits.full_update)
+               for (i = 0; i < dc->res_pool->pipe_count; i++) {
+                       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+                       /* Skip inactive pipes and ones already updated */
+                       if (!pipe_ctx->stream || pipe_ctx->stream == stream)
+                               continue;
+
+                       pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
+
+                       pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent(
+                               pipe_ctx->plane_res.hubp,
+                               &pipe_ctx->dlg_regs,
+                               &pipe_ctx->ttu_regs);
+               }
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe_ctx->stream || pipe_ctx->stream == stream)
+                       continue;
+
+               dcn10_pipe_control_lock(dc, pipe_ctx, false);
+       }
+
        if (num_planes == 0)
                false_optc_underflow_wa(dc, stream, tg);
 
@@ -2398,10 +2379,9 @@ static void dcn10_apply_ctx_for_surface(
                hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
 }
 
-static void dcn10_set_bandwidth(
+static void dcn10_prepare_bandwidth(
                struct dc *dc,
-               struct dc_state *context,
-               bool safe_to_lower)
+               struct dc_state *context)
 {
        if (dc->debug.sanity_checks)
                dcn10_verify_allow_pstate_change_high(dc);
@@ -2410,12 +2390,39 @@ static void dcn10_set_bandwidth(
                if (context->stream_count == 0)
                        context->bw.dcn.clk.phyclk_khz = 0;
 
-               dc->res_pool->dccg->funcs->update_clocks(
-                               dc->res_pool->dccg,
-                               &context->bw.dcn.clk,
-                               safe_to_lower);
+               dc->res_pool->clk_mgr->funcs->update_clocks(
+                               dc->res_pool->clk_mgr,
+                               context,
+                               false);
+       }
+
+       hubbub1_program_watermarks(dc->res_pool->hubbub,
+                       &context->bw.dcn.watermarks,
+                       dc->res_pool->ref_clock_inKhz / 1000,
+                       true);
+
+       if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+               dcn_bw_notify_pplib_of_wm_ranges(dc);
+
+       if (dc->debug.sanity_checks)
+               dcn10_verify_allow_pstate_change_high(dc);
+}
+
+static void dcn10_optimize_bandwidth(
+               struct dc *dc,
+               struct dc_state *context)
+{
+       if (dc->debug.sanity_checks)
+               dcn10_verify_allow_pstate_change_high(dc);
+
+       if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+               if (context->stream_count == 0)
+                       context->bw.dcn.clk.phyclk_khz = 0;
 
-               dcn10_pplib_apply_display_requirements(dc, context);
+               dc->res_pool->clk_mgr->funcs->update_clocks(
+                               dc->res_pool->clk_mgr,
+                               context,
+                               true);
        }
 
        hubbub1_program_watermarks(dc->res_pool->hubbub,
@@ -2423,6 +2430,9 @@ static void dcn10_set_bandwidth(
                        dc->res_pool->ref_clock_inKhz / 1000,
                        true);
 
+       if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+               dcn_bw_notify_pplib_of_wm_ranges(dc);
+
        if (dc->debug.sanity_checks)
                dcn10_verify_allow_pstate_change_high(dc);
 }
@@ -2694,7 +2704,6 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
 
 static const struct hw_sequencer_funcs dcn10_funcs = {
        .program_gamut_remap = program_gamut_remap,
-       .program_csc_matrix = program_csc_matrix,
        .init_hw = dcn10_init_hw,
        .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
        .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
@@ -2721,7 +2730,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
        .disable_plane = dcn10_disable_plane,
        .blank_pixel_data = dcn10_blank_pixel_data,
        .pipe_control_lock = dcn10_pipe_control_lock,
-       .set_bandwidth = dcn10_set_bandwidth,
+       .prepare_bandwidth = dcn10_prepare_bandwidth,
+       .optimize_bandwidth = dcn10_optimize_bandwidth,
        .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
        .enable_stream_timing = dcn10_enable_stream_timing,
        .set_drr = set_drr,
@@ -2731,11 +2741,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
        .set_avmute = dce110_set_avmute,
        .log_hw_state = dcn10_log_hw_state,
        .get_hw_state = dcn10_get_hw_state,
+       .clear_status_bits = dcn10_clear_status_bits,
        .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
-       .ready_shared_resources = ready_shared_resources,
-       .optimize_shared_resources = optimize_shared_resources,
-       .pplib_apply_display_requirements =
-                       dcn10_pplib_apply_display_requirements,
        .edp_backlight_control = hwss_edp_backlight_control,
        .edp_power_control = hwss_edp_power_control,
        .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
index 84d461e0ed3e2523e8bcf3238547dbd43fe5e13e..f8eea10e4c6453412a8dd22f763227dd76351142 100644 (file)
@@ -51,4 +51,34 @@ void dcn10_get_hw_state(
                char *pBuf, unsigned int bufSize,
                unsigned int mask);
 
+void dcn10_clear_status_bits(struct dc *dc, unsigned int mask);
+
+bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp);
+
+void set_hdr_multiplier(struct pipe_ctx *pipe_ctx);
+
+void dcn10_get_surface_visual_confirm_color(
+               const struct pipe_ctx *pipe_ctx,
+               struct tg_color *color);
+
+void dcn10_get_hdr_visual_confirm_color(
+               struct pipe_ctx *pipe_ctx,
+               struct tg_color *color);
+
+void update_dchubp_dpp(
+       struct dc *dc,
+       struct pipe_ctx *pipe_ctx,
+       struct dc_state *context);
+
+struct pipe_ctx *find_top_pipe_for_stream(
+               struct dc *dc,
+               struct dc_state *context,
+               const struct dc_stream_state *stream);
+
 #endif /* __DC_HWSS_DCN10_H__ */
index 64158900730f3a8b7357785d3942e295b04ee24c..cd469014baa39f2ce505c7006f09a44e6e6ee9f5 100644 (file)
@@ -44,6 +44,7 @@
 #include "dcn10_hubp.h"
 #include "dcn10_hubbub.h"
 #include "dcn10_cm_common.h"
+#include "dcn10_clk_mgr.h"
 
 static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...)
 {
@@ -454,12 +455,6 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int
 
                        remaining_buffer -= chars_printed;
                        pBuf += chars_printed;
-
-                       // Clear underflow for debug purposes
-                       // We want to keep underflow sticky bit on for the longevity tests outside of test environment.
-                       // This function is called only from Windows or Diags test environment, hence it's safe to clear
-                       // it from here without affecting the original intent.
-                       tg->funcs->clear_optc_underflow(tg);
                }
        }
 
@@ -469,19 +464,75 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int
 static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned int bufSize)
 {
        unsigned int chars_printed = 0;
+       unsigned int remaining_buffer = bufSize;
 
-       chars_printed = snprintf_count(pBuf, bufSize, "dcfclk_khz,dcfclk_deep_sleep_khz,dispclk_khz,"
-               "dppclk_khz,max_supported_dppclk_khz,fclk_khz,socclk_khz\n"
-               "%d,%d,%d,%d,%d,%d,%d\n",
+       chars_printed = snprintf_count(pBuf, bufSize, "dcfclk,dcfclk_deep_sleep,dispclk,"
+               "dppclk,fclk,socclk\n"
+               "%d,%d,%d,%d,%d,%d\n",
                dc->current_state->bw.dcn.clk.dcfclk_khz,
                dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz,
                dc->current_state->bw.dcn.clk.dispclk_khz,
                dc->current_state->bw.dcn.clk.dppclk_khz,
-               dc->current_state->bw.dcn.clk.max_supported_dppclk_khz,
                dc->current_state->bw.dcn.clk.fclk_khz,
                dc->current_state->bw.dcn.clk.socclk_khz);
 
-       return chars_printed;
+       remaining_buffer -= chars_printed;
+       pBuf += chars_printed;
+
+       return bufSize - remaining_buffer;
+}
+
+static void dcn10_clear_otpc_underflow(struct dc *dc)
+{
+       struct resource_pool *pool = dc->res_pool;
+       int i;
+
+       for (i = 0; i < pool->timing_generator_count; i++) {
+               struct timing_generator *tg = pool->timing_generators[i];
+               struct dcn_otg_state s = {0};
+
+               optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+
+               if (s.otg_enabled & 1)
+                       tg->funcs->clear_optc_underflow(tg);
+       }
+}
+
+static void dcn10_clear_hubp_underflow(struct dc *dc)
+{
+       struct resource_pool *pool = dc->res_pool;
+       int i;
+
+       for (i = 0; i < pool->pipe_count; i++) {
+               struct hubp *hubp = pool->hubps[i];
+               struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
+
+               hubp->funcs->hubp_read_state(hubp);
+
+               if (!s->blank_en)
+                       hubp->funcs->hubp_clear_underflow(hubp);
+       }
+}
+
+void dcn10_clear_status_bits(struct dc *dc, unsigned int mask)
+{
+       /*
+        *  Mask Format
+        *  Bit 0 - 31: Status bit to clear
+        *
+        *  Mask = 0x0 means clear all status bits
+        */
+       const unsigned int DC_HW_STATE_MASK_HUBP_UNDERFLOW      = 0x1;
+       const unsigned int DC_HW_STATE_MASK_OTPC_UNDERFLOW      = 0x2;
+
+       if (mask == 0x0)
+               mask = 0xFFFFFFFF;
+
+       if (mask & DC_HW_STATE_MASK_HUBP_UNDERFLOW)
+               dcn10_clear_hubp_underflow(dc);
+
+       if (mask & DC_HW_STATE_MASK_OTPC_UNDERFLOW)
+               dcn10_clear_otpc_underflow(dc);
 }
 
 void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask)
@@ -491,16 +542,16 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne
         *  Bit 0 - 15: Hardware block mask
         *  Bit 15: 1 = Invariant Only, 0 = All
         */
-       const unsigned int DC_HW_STATE_MASK_HUBBUB      = 0x1;
-       const unsigned int DC_HW_STATE_MASK_HUBP        = 0x2;
-       const unsigned int DC_HW_STATE_MASK_RQ          = 0x4;
-       const unsigned int DC_HW_STATE_MASK_DLG         = 0x8;
-       const unsigned int DC_HW_STATE_MASK_TTU         = 0x10;
-       const unsigned int DC_HW_STATE_MASK_CM          = 0x20;
-       const unsigned int DC_HW_STATE_MASK_MPCC        = 0x40;
-       const unsigned int DC_HW_STATE_MASK_OTG         = 0x80;
-       const unsigned int DC_HW_STATE_MASK_CLOCKS      = 0x100;
-       const unsigned int DC_HW_STATE_INVAR_ONLY       = 0x8000;
+       const unsigned int DC_HW_STATE_MASK_HUBBUB                      = 0x1;
+       const unsigned int DC_HW_STATE_MASK_HUBP                        = 0x2;
+       const unsigned int DC_HW_STATE_MASK_RQ                          = 0x4;
+       const unsigned int DC_HW_STATE_MASK_DLG                         = 0x8;
+       const unsigned int DC_HW_STATE_MASK_TTU                         = 0x10;
+       const unsigned int DC_HW_STATE_MASK_CM                          = 0x20;
+       const unsigned int DC_HW_STATE_MASK_MPCC                        = 0x40;
+       const unsigned int DC_HW_STATE_MASK_OTG                         = 0x80;
+       const unsigned int DC_HW_STATE_MASK_CLOCKS                      = 0x100;
+       const unsigned int DC_HW_STATE_INVAR_ONLY                       = 0x8000;
 
        unsigned int chars_printed = 0;
        unsigned int remaining_buf_size = bufSize;
@@ -556,6 +607,9 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne
                remaining_buf_size -= chars_printed;
        }
 
-       if ((mask & DC_HW_STATE_MASK_CLOCKS) && remaining_buf_size > 0)
+       if ((mask & DC_HW_STATE_MASK_CLOCKS) && remaining_buf_size > 0) {
                chars_printed = dcn10_get_clock_states(dc, pBuf, remaining_buf_size);
+               pBuf += chars_printed;
+               remaining_buf_size -= chars_printed;
+       }
 }
index ba6a8686062f27e235799e44eaf95d4d03d39778..477ab922221626dd47026d1874383418d0542cc9 100644 (file)
@@ -589,7 +589,7 @@ static bool dcn10_link_encoder_validate_hdmi_output(
                return false;
 
        /* DCE11 HW does not support 420 */
-       if (!enc10->base.features.ycbcr420_supported &&
+       if (!enc10->base.features.hdmi_ycbcr420_supported &&
                        crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
                return false;
 
@@ -606,8 +606,10 @@ bool dcn10_link_encoder_validate_dp_output(
        const struct dcn10_link_encoder *enc10,
        const struct dc_crtc_timing *crtc_timing)
 {
-       if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
-               return false;
+       if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+               if (!enc10->base.features.dp_ycbcr420_supported)
+                       return false;
+       }
 
        return true;
 }
index 54626682bab23bed0a299c06d3a51b34f868c3e0..7c138615f17d7020909a7b2b599c09d8ccee9aac 100644 (file)
@@ -87,9 +87,8 @@ static void optc1_disable_stereo(struct timing_generator *optc)
        REG_SET(OTG_STEREO_CONTROL, 0,
                OTG_STEREO_EN, 0);
 
-       REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0,
+       REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0,
                OTG_3D_STRUCTURE_EN, 0,
-               OTG_3D_STRUCTURE_V_UPDATE_MODE, 0,
                OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
 }
 
@@ -274,10 +273,12 @@ void optc1_program_timing(
         * program the reg for interrupt postition.
         */
        vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
-       if (vertical_line_start < 0) {
-               ASSERT(0);
+       v_fp2 = 0;
+       if (vertical_line_start < 0)
+               v_fp2 = -vertical_line_start;
+       if (vertical_line_start < 0)
                vertical_line_start = 0;
-       }
+
        REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
                        OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
 
@@ -296,9 +297,6 @@ void optc1_program_timing(
                if (patched_crtc_timing.flags.INTERLACE == 1)
                        field_num = 1;
        }
-       v_fp2 = 0;
-       if (optc->dlg_otg_param.vstartup_start > asic_blank_end)
-               v_fp2 = optc->dlg_otg_param.vstartup_start > asic_blank_end;
 
        /* Interlace */
        if (patched_crtc_timing.flags.INTERLACE == 1) {
@@ -337,9 +335,8 @@ void optc1_program_timing(
        /* Enable stereo - only when we need to pack 3D frame. Other types
         * of stereo handled in explicit call
         */
-       h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ?
-                       1 : 0;
 
+       h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing);
        REG_UPDATE(OTG_H_TIMING_CNTL,
                        OTG_H_TIMING_DIV_BY2, h_div_2);
 
@@ -362,20 +359,19 @@ void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enab
 static void optc1_unblank_crtc(struct timing_generator *optc)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       uint32_t vertical_interrupt_enable = 0;
-
-       REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL,
-                       OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable);
-
-       /* temporary work around for vertical interrupt, once vertical interrupt enabled,
-        * this check will be removed.
-        */
-       if (vertical_interrupt_enable)
-               optc1_set_blank_data_double_buffer(optc, true);
 
        REG_UPDATE_2(OTG_BLANK_CONTROL,
                        OTG_BLANK_DATA_EN, 0,
                        OTG_BLANK_DE_MODE, 0);
+
+       /* W/A for automated testing
+        * Automated testing will fail underflow test as there
+        * sporadic underflows which occur during the optc blank
+        * sequence.  As a w/a, clear underflow on unblank.
+        * This prevents the failure, but will not mask actual
+        * underflow that affect real use cases.
+        */
+       optc1_clear_optc_underflow(optc);
 }
 
 /**
@@ -1155,9 +1151,8 @@ static void optc1_enable_stereo(struct timing_generator *optc,
                                OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
 
                if (flags->PROGRAM_STEREO)
-                       REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL,
+                       REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL,
                                OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED,
-                               OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED,
                                OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED);
 
        }
@@ -1425,3 +1420,9 @@ void dcn10_timing_generator_init(struct optc *optc1)
        optc1->min_h_sync_width = 8;
        optc1->min_v_sync_width = 1;
 }
+
+bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
+{
+       return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
+}
+
index c1b114209fe8da2f1e5499660548f4db855f889c..8bacf0b6e27e6896d7dc5a2764ccefd4c2d5a631 100644 (file)
@@ -565,4 +565,6 @@ bool optc1_configure_crc(struct timing_generator *optc,
 bool optc1_get_crc(struct timing_generator *optc,
                    uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
 
+bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
+
 #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */
index a71453a15ae352df758831d00274ea2ca2636a6d..5d4772dec0ba5454267b6fcfeae1b55d6b6cf049 100644 (file)
 
 #include "resource.h"
 #include "include/irq_service_interface.h"
-#include "dcn10/dcn10_resource.h"
+#include "dcn10_resource.h"
 
-#include "dcn10/dcn10_ipp.h"
-#include "dcn10/dcn10_mpc.h"
+#include "dcn10_ipp.h"
+#include "dcn10_mpc.h"
 #include "irq/dcn10/irq_service_dcn10.h"
-#include "dcn10/dcn10_dpp.h"
+#include "dcn10_dpp.h"
 #include "dcn10_optc.h"
-#include "dcn10/dcn10_hw_sequencer.h"
+#include "dcn10_hw_sequencer.h"
 #include "dce110/dce110_hw_sequencer.h"
-#include "dcn10/dcn10_opp.h"
-#include "dcn10/dcn10_link_encoder.h"
-#include "dcn10/dcn10_stream_encoder.h"
-#include "dce/dce_clocks.h"
+#include "dcn10_opp.h"
+#include "dcn10_link_encoder.h"
+#include "dcn10_stream_encoder.h"
+#include "dcn10_clk_mgr.h"
 #include "dce/dce_clock_source.h"
 #include "dce/dce_audio.h"
 #include "dce/dce_hwseq.h"
-#include "../virtual/virtual_stream_encoder.h"
+#include "virtual/virtual_stream_encoder.h"
 #include "dce110/dce110_resource.h"
 #include "dce112/dce112_resource.h"
 #include "dcn10_hubp.h"
@@ -202,7 +202,6 @@ enum dcn10_clk_src_array_id {
 #define MMHUB_SR(reg_name)\
                .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) +  \
                                        mm ## reg_name
-
 /* macros to expend register list macro defined in HW object header file
  * end *********************/
 
@@ -436,8 +435,8 @@ static const struct dcn_optc_mask tg_mask = {
        TG_COMMON_MASK_SH_LIST_DCN1_0(_MASK)
 };
 
-
 static const struct bios_registers bios_regs = {
+               NBIO_SR(BIOS_SCRATCH_0),
                NBIO_SR(BIOS_SCRATCH_3),
                NBIO_SR(BIOS_SCRATCH_6)
 };
@@ -496,7 +495,6 @@ static const struct dce110_clk_src_mask cs_mask = {
                CS_COMMON_MASK_SH_LIST_DCN1_0(_MASK)
 };
 
-
 static const struct resource_caps res_cap = {
                .num_timing_generator = 4,
                .num_opp = 4,
@@ -719,7 +717,8 @@ static struct timing_generator *dcn10_timing_generator_create(
 static const struct encoder_feature_support link_enc_feature = {
                .max_hdmi_deep_color = COLOR_DEPTH_121212,
                .max_hdmi_pixel_clock = 600000,
-               .ycbcr420_supported = true,
+               .hdmi_ycbcr420_supported = true,
+               .dp_ycbcr420_supported = false,
                .flags.bits.IS_HBR2_CAPABLE = true,
                .flags.bits.IS_HBR3_CAPABLE = true,
                .flags.bits.IS_TPS3_CAPABLE = true,
@@ -949,8 +948,8 @@ static void destruct(struct dcn10_resource_pool *pool)
        if (pool->base.dmcu != NULL)
                dce_dmcu_destroy(&pool->base.dmcu);
 
-       if (pool->base.dccg != NULL)
-               dce_dccg_destroy(&pool->base.dccg);
+       if (pool->base.clk_mgr != NULL)
+               dce_clk_mgr_destroy(&pool->base.clk_mgr);
 
        kfree(pool->base.pp_smu);
 }
@@ -1275,9 +1274,8 @@ static bool construct(
                        goto fail;
                }
        }
-
-       pool->base.dccg = dcn1_dccg_create(ctx);
-       if (pool->base.dccg == NULL) {
+       pool->base.clk_mgr = dcn1_clk_mgr_create(ctx);
+       if (pool->base.clk_mgr == NULL) {
                dm_error("DC: failed to create display clock!\n");
                BREAK_TO_DEBUGGER();
                goto fail;
index 6f9078f3c4d39a353686ec9b5380cc27c63ba922..b8b5525a389abf0926d94e9c20b5522b63ba06be 100644 (file)
@@ -766,7 +766,6 @@ void enc1_stream_encoder_dp_blank(
        struct stream_encoder *enc)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-       uint32_t retries = 0;
        uint32_t  reg1 = 0;
        uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
 
@@ -803,8 +802,6 @@ void enc1_stream_encoder_dp_blank(
                        0,
                        10, max_retries);
 
-       ASSERT(retries <= max_retries);
-
        /* Tell the DP encoder to ignore timing from CRTC, must be done after
         * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
         * complete, stream status will be stuck in video stream enabled state,
index 34a701ca879e725a3993b679e9bbeb362044f491..65663f4d93e10ad3e7905efbdb70b275f27aaf5b 100644 (file)
@@ -33,6 +33,7 @@
 
 #define EVENT_LOG_AUX_REQ(ddc, type, action, address, len, data)
 #define EVENT_LOG_AUX_REP(ddc, type, replyStatus, len, data)
+#define EVENT_LOG_CUST_MSG(tag, a, ...)
 
 #endif
 
index f2ea8452d48fe0bb2297d991deb95246998bd6a3..0029a39efb1cb5ffe09e6d775af18cfcdfbfd2be 100644 (file)
@@ -55,10 +55,10 @@ struct pp_smu {
 
 struct pp_smu_wm_set_range {
        unsigned int wm_inst;
-       uint32_t min_fill_clk_khz;
-       uint32_t max_fill_clk_khz;
-       uint32_t min_drain_clk_khz;
-       uint32_t max_drain_clk_khz;
+       uint32_t min_fill_clk_mhz;
+       uint32_t max_fill_clk_mhz;
+       uint32_t min_drain_clk_mhz;
+       uint32_t max_drain_clk_mhz;
 };
 
 #define MAX_WATERMARK_SETS 4
@@ -77,15 +77,15 @@ struct pp_smu_display_requirement_rv {
         */
        unsigned int display_count;
 
-       /* PPSMC_MSG_SetHardMinFclkByFreq: khz
+       /* PPSMC_MSG_SetHardMinFclkByFreq: mhz
         *  FCLK will vary with DPM, but never below requested hard min
         */
-       unsigned int hard_min_fclk_khz;
+       unsigned int hard_min_fclk_mhz;
 
-       /* PPSMC_MSG_SetHardMinDcefclkByFreq: khz
+       /* PPSMC_MSG_SetHardMinDcefclkByFreq: mhz
         *  fixed clock at requested freq, either from FCH bypass or DFS
         */
-       unsigned int hard_min_dcefclk_khz;
+       unsigned int hard_min_dcefclk_mhz;
 
        /* PPSMC_MSG_SetMinDeepSleepDcefclk: mhz
         *  when DF is in cstate, dcf clock is further divided down
@@ -102,14 +102,20 @@ struct pp_smu_funcs_rv {
         */
        void (*set_display_count)(struct pp_smu *pp, int count);
 
-       /* which SMU message?  are reader and writer WM separate SMU msg? */
+       /* reader and writer WM's are sent together as part of one table*/
+       /*
+        * PPSMC_MSG_SetDriverDramAddrHigh
+        * PPSMC_MSG_SetDriverDramAddrLow
+        * PPSMC_MSG_TransferTableDram2Smu
+        *
+        * */
        void (*set_wm_ranges)(struct pp_smu *pp,
                        struct pp_smu_wm_range_sets *ranges);
 
        /* PPSMC_MSG_SetHardMinDcfclkByFreq
         * fixed clock at requested freq, either from FCH bypass or DFS
         */
-       void (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int khz);
+       void (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int mhz);
 
        /* PPSMC_MSG_SetMinDeepSleepDcfclk
         * when DF is in cstate, dcf clock is further divided down
@@ -120,12 +126,12 @@ struct pp_smu_funcs_rv {
        /* PPSMC_MSG_SetHardMinFclkByFreq
         * FCLK will vary with DPM, but never below requested hard min
         */
-       void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int khz);
+       void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int mhz);
 
        /* PPSMC_MSG_SetHardMinSocclkByFreq
         * Needed for DWB support
         */
-       void (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int khz);
+       void (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int mhz);
 
        /* PME w/a */
        void (*set_pme_wa_enable)(struct pp_smu *pp);
index 28128c02de00417d4d1ca6b5c43a87f4649ca01c..1961cc6d91439bafbfdfec845ffcdd650c13bc58 100644 (file)
@@ -31,6 +31,8 @@
 
 #define __DM_SERVICES_H__
 
+#include "amdgpu_dm_trace.h"
+
 /* TODO: remove when DC is complete. */
 #include "dm_services_types.h"
 #include "logger_interface.h"
@@ -70,6 +72,7 @@ static inline uint32_t dm_read_reg_func(
        }
 #endif
        value = cgs_read_register(ctx->cgs_device, address);
+       trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value);
 
        return value;
 }
@@ -90,6 +93,7 @@ static inline void dm_write_reg_func(
        }
 #endif
        cgs_write_register(ctx->cgs_device, address, value);
+       trace_amdgpu_dc_wreg(&ctx->perf_trace->write_count, address, value);
 }
 
 static inline uint32_t dm_read_index_reg(
@@ -351,8 +355,12 @@ unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx,
 /*
  * performance tracing
  */
-void dm_perf_trace_timestamp(const char *func_name, unsigned int line);
-#define PERF_TRACE()   dm_perf_trace_timestamp(__func__, __LINE__)
+#define PERF_TRACE()   trace_amdgpu_dc_performance(CTX->perf_trace->read_count,\
+               CTX->perf_trace->write_count, &CTX->perf_trace->last_entry_read,\
+               &CTX->perf_trace->last_entry_write, __func__, __LINE__)
+#define PERF_TRACE_CTX(__CTX)  trace_amdgpu_dc_performance(__CTX->perf_trace->read_count,\
+               __CTX->perf_trace->write_count, &__CTX->perf_trace->last_entry_read,\
+               &__CTX->perf_trace->last_entry_write, __func__, __LINE__)
 
 
 /*
index 2b83f922ac02667239756e54b5ec30fd7ed65f15..1af8c777b3acbc15a3e7113af89a130bc9f8c134 100644 (file)
@@ -208,22 +208,20 @@ struct dm_bl_data_point {
                /* Brightness level as effective value in range 0-255,
                 * corresponding to above percentage
                 */
-               uint8_t signalLevel;
+               uint8_t signal_level;
 };
 
 /* Total size of the structure should not exceed 256 bytes */
 struct dm_acpi_atif_backlight_caps {
-
-
        uint16_t size; /* Bytes 0-1 (2 bytes) */
        uint16_t flags; /* Byted 2-3 (2 bytes) */
-       uint8_t  errorCode; /* Byte 4 */
-       uint8_t  acLevelPercentage; /* Byte 5 */
-       uint8_t  dcLevelPercentage; /* Byte 6 */
-       uint8_t  minInputSignal; /* Byte 7 */
-       uint8_t  maxInputSignal; /* Byte 8 */
-       uint8_t  numOfDataPoints; /* Byte 9 */
-       struct dm_bl_data_point dataPoints[99]; /* Bytes 10-207 (198 bytes)*/
+       uint8_t  error_code; /* Byte 4 */
+       uint8_t  ac_level_percentage; /* Byte 5 */
+       uint8_t  dc_level_percentage; /* Byte 6 */
+       uint8_t  min_input_signal; /* Byte 7 */
+       uint8_t  max_input_signal; /* Byte 8 */
+       uint8_t  num_data_points; /* Byte 9 */
+       struct dm_bl_data_point data_points[99]; /* Bytes 10-207 (198 bytes)*/
 };
 
 enum dm_acpi_display_type {
index cbafce649e3334e9e834fb0d9492a7d10ae07c46..5dd04520ceca5fa1ad0d52c74ee055087c660cb9 100644 (file)
@@ -113,7 +113,8 @@ struct _vcs_dpi_soc_bounding_box_st {
        int use_urgent_burst_bw;
        double max_hscl_ratio;
        double max_vscl_ratio;
-       struct _vcs_dpi_voltage_scaling_st clock_limits[7];
+       unsigned int num_states;
+       struct _vcs_dpi_voltage_scaling_st clock_limits[8];
 };
 
 struct _vcs_dpi_ip_params_st {
index f20161c5706d7278cc0c48f92eedebf0bdf0ce73..dada0429602585837cd9566ffe5262e3f2dcf86d 100644 (file)
@@ -56,7 +56,6 @@ struct gpio_service *dal_gpio_service_create(
        struct dc_context *ctx)
 {
        struct gpio_service *service;
-
        uint32_t index_of_id;
 
        service = kzalloc(sizeof(struct gpio_service), GFP_KERNEL);
@@ -78,44 +77,33 @@ struct gpio_service *dal_gpio_service_create(
                goto failure_1;
        }
 
-       /* allocate and initialize business storage */
+       /* allocate and initialize busyness storage */
        {
-               const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
-
                index_of_id = 0;
                service->ctx = ctx;
 
                do {
                        uint32_t number_of_bits =
                                service->factory.number_of_pins[index_of_id];
+                       uint32_t i = 0;
 
-                       uint32_t number_of_uints =
-                               (number_of_bits + bits_per_uint - 1) /
-                               bits_per_uint;
-
-                       uint32_t *slot;
-
-                       if (number_of_bits) {
-                               uint32_t index_of_uint = 0;
+                       if (number_of_bits)  {
+                               service->busyness[index_of_id] =
+                                       kcalloc(number_of_bits, sizeof(char),
+                                               GFP_KERNEL);
 
-                               slot = kcalloc(number_of_uints,
-                                              sizeof(uint32_t),
-                                              GFP_KERNEL);
-
-                               if (!slot) {
+                               if (!service->busyness[index_of_id]) {
                                        BREAK_TO_DEBUGGER();
                                        goto failure_2;
                                }
 
                                do {
-                                       slot[index_of_uint] = 0;
-
-                                       ++index_of_uint;
-                               } while (index_of_uint < number_of_uints);
-                       } else
-                               slot = NULL;
-
-                       service->busyness[index_of_id] = slot;
+                                       service->busyness[index_of_id][i] = 0;
+                                       ++i;
+                               } while (i < number_of_bits);
+                       } else {
+                               service->busyness[index_of_id] = NULL;
+                       }
 
                        ++index_of_id;
                } while (index_of_id < GPIO_ID_COUNT);
@@ -125,13 +113,8 @@ struct gpio_service *dal_gpio_service_create(
 
 failure_2:
        while (index_of_id) {
-               uint32_t *slot;
-
                --index_of_id;
-
-               slot = service->busyness[index_of_id];
-
-               kfree(slot);
+               kfree(service->busyness[index_of_id]);
        }
 
 failure_1:
@@ -169,9 +152,7 @@ void dal_gpio_service_destroy(
                uint32_t index_of_id = 0;
 
                do {
-                       uint32_t *slot = (*ptr)->busyness[index_of_id];
-
-                       kfree(slot);
+                       kfree((*ptr)->busyness[index_of_id]);
 
                        ++index_of_id;
                } while (index_of_id < GPIO_ID_COUNT);
@@ -192,11 +173,7 @@ static bool is_pin_busy(
        enum gpio_id id,
        uint32_t en)
 {
-       const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
-
-       const uint32_t *slot = service->busyness[id] + (en / bits_per_uint);
-
-       return 0 != (*slot & (1 << (en % bits_per_uint)));
+       return service->busyness[id][en];
 }
 
 static void set_pin_busy(
@@ -204,10 +181,7 @@ static void set_pin_busy(
        enum gpio_id id,
        uint32_t en)
 {
-       const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
-
-       service->busyness[id][en / bits_per_uint] |=
-               (1 << (en % bits_per_uint));
+       service->busyness[id][en] = true;
 }
 
 static void set_pin_free(
@@ -215,10 +189,7 @@ static void set_pin_free(
        enum gpio_id id,
        uint32_t en)
 {
-       const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
-
-       service->busyness[id][en / bits_per_uint] &=
-               ~(1 << (en % bits_per_uint));
+       service->busyness[id][en] = false;
 }
 
 enum gpio_result dal_gpio_service_open(
index c7f3081f59ccf470b3759bf59f538cabf67b9711..1d501a43d13b44505f2a7dc08868b82cfbb01f28 100644 (file)
@@ -36,10 +36,9 @@ struct gpio_service {
        /*
         * @brief
         * Business storage.
-        * For each member of 'enum gpio_id',
-        * store array of bits (packed into uint32_t slots),
-        * index individual bit by 'en' value */
-       uint32_t *busyness[GPIO_ID_COUNT];
+        * one byte For each member of 'enum gpio_id'
+        */
+       char *busyness[GPIO_ID_COUNT];
 };
 
 enum gpio_result dal_gpio_service_open(
index 39ee8eba3c31ae886b34b96db767a292c79a6f4d..d1656c9d50dfe88d3896adbe92b00f0adddbc2b8 100644 (file)
@@ -126,7 +126,7 @@ static inline struct bw_fixed bw_div(const struct bw_fixed arg1, const struct bw
 static inline struct bw_fixed bw_mod(const struct bw_fixed arg1, const struct bw_fixed arg2)
 {
        struct bw_fixed res;
-       div64_u64_rem(arg1.value, arg2.value, &res.value);
+       div64_u64_rem(arg1.value, arg2.value, (uint64_t *)&res.value);
        return res;
 }
 
index bcb18f5e1e60246f6bee825a3e028bbad8561fa2..7a147a9762a01425a42a64dc75cd91580eaf5f55 100644 (file)
@@ -77,6 +77,7 @@ struct compressor_funcs {
 };
 struct compressor {
        struct dc_context *ctx;
+       /* CONTROLLER_ID_D0 + instance, CONTROLLER_ID_UNDEFINED = 0 */
        uint32_t attached_inst;
        bool is_enabled;
        const struct compressor_funcs *funcs;
index c1976c175b5781afe3d5972215352dfd4d4dd686..b168a5e9dd9dcef7fa9c0ae2e95b05505300e938 100644 (file)
@@ -82,7 +82,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option);
 
 void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
 /********** DAL Core*********************/
-#include "display_clock.h"
+#include "hw/clk_mgr.h"
 #include "transform.h"
 #include "dpp.h"
 
@@ -169,6 +169,7 @@ struct resource_pool {
        unsigned int audio_count;
        struct audio_support audio_support;
 
+       struct clk_mgr *clk_mgr;
        struct dccg *dccg;
        struct irq_service *irqs;
 
@@ -271,6 +272,17 @@ union bw_context {
        struct dce_bw_output dce;
 };
 
+/**
+ * struct dc_state - The full description of a state requested by a user
+ *
+ * @streams: Stream properties
+ * @stream_status: The planes on a given stream
+ * @res_ctx: Persistent state of resources
+ * @bw: The output from bandwidth and watermark calculations
+ * @pp_display_cfg: PowerPlay clocks and settings
+ * @dcn_bw_vars: non-stack memory to support bandwidth calculations
+ *
+ */
 struct dc_state {
        struct dc_stream_state *streams[MAX_PIPES];
        struct dc_stream_status stream_status[MAX_PIPES];
@@ -278,7 +290,6 @@ struct dc_state {
 
        struct resource_context res_ctx;
 
-       /* The output from BW and WM calculations. */
        union bw_context bw;
 
        /* Note: these are big structures, do *not* put on stack! */
@@ -287,7 +298,7 @@ struct dc_state {
        struct dcn_bw_internal_vars dcn_bw_vars;
 #endif
 
-       struct dccg *dis_clk;
+       struct clk_mgr *dccg;
 
        struct kref refcount;
 };
index e688eb9b975c25cd2c0d15481872a9e73924ac95..ece954a40a8e3d2a1712925f47e4954218250c10 100644 (file)
@@ -31,8 +31,8 @@
 #define __DCN_CALCS_H__
 
 #include "bw_fixed.h"
-#include "display_clock.h"
 #include "../dml/display_mode_lib.h"
+#include "hw/clk_mgr.h"
 
 struct dc;
 struct dc_state;
index a83a484946133d00311c8f1219ba2bcf17527805..abc961c0906ea7729d49f0606dcfe6150d1a584e 100644 (file)
@@ -47,12 +47,18 @@ struct abm_funcs {
        bool (*set_abm_level)(struct abm *abm, unsigned int abm_level);
        bool (*set_abm_immediate_disable)(struct abm *abm);
        bool (*init_backlight)(struct abm *abm);
-       bool (*set_backlight_level)(struct abm *abm,
-                       unsigned int backlight_level,
+
+       /* backlight_pwm_u16_16 is unsigned 32 bit,
+        * 16 bit integer + 16 fractional, where 1.0 is max backlight value.
+        */
+       bool (*set_backlight_level_pwm)(struct abm *abm,
+                       unsigned int backlight_pwm_u16_16,
                        unsigned int frame_ramp,
                        unsigned int controller_id,
                        bool use_smooth_brightness);
-       unsigned int (*get_current_backlight_8_bit)(struct abm *abm);
+
+       unsigned int (*get_current_backlight)(struct abm *abm);
+       unsigned int (*get_target_backlight)(struct abm *abm);
 };
 
 #endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
new file mode 100644 (file)
index 0000000..23a4b18
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-16 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_CLK_MGR_H__
+#define __DAL_CLK_MGR_H__
+
+#include "dm_services_types.h"
+#include "dc.h"
+
+struct clk_mgr {
+       struct dc_context *ctx;
+       const struct clk_mgr_funcs *funcs;
+
+       struct dc_clocks clks;
+};
+
+struct clk_mgr_funcs {
+       void (*update_clocks)(struct clk_mgr *clk_mgr,
+                       struct dc_state *context,
+                       bool safe_to_lower);
+
+       int (*get_dp_ref_clk_frequency)(struct clk_mgr *clk_mgr);
+};
+
+#endif /* __DAL_CLK_MGR_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
new file mode 100644 (file)
index 0000000..95a56d0
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_DCCG_H__
+#define __DAL_DCCG_H__
+
+#include "dc_types.h"
+
+struct dccg {
+       struct dc_context *ctx;
+       const struct dccg_funcs *funcs;
+
+       int ref_dppclk;
+};
+
+struct dccg_funcs {
+       void (*update_dpp_dto)(struct dccg *dccg,
+                       int dpp_inst,
+                       int req_dppclk);
+};
+
+#endif //__DAL_DCCG_H__
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h
deleted file mode 100644 (file)
index 689faa1..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-16 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DISPLAY_CLOCK_H__
-#define __DISPLAY_CLOCK_H__
-
-#include "dm_services_types.h"
-#include "dc.h"
-
-/* Structure containing all state-dependent clocks
- * (dependent on "enum clocks_state") */
-struct state_dependent_clocks {
-       int display_clk_khz;
-       int pixel_clk_khz;
-};
-
-struct dccg {
-       struct dc_context *ctx;
-       const struct display_clock_funcs *funcs;
-
-       enum dm_pp_clocks_state max_clks_state;
-       enum dm_pp_clocks_state cur_min_clks_state;
-       struct dc_clocks clks;
-};
-
-struct display_clock_funcs {
-       void (*update_clocks)(struct dccg *dccg,
-                       struct dc_clocks *new_clocks,
-                       bool safe_to_lower);
-       int (*set_dispclk)(struct dccg *dccg,
-               int requested_clock_khz);
-
-       int (*get_dp_ref_clk_frequency)(struct dccg *dccg);
-
-       bool (*update_dfs_bypass)(struct dccg *dccg,
-               struct dc *dc,
-               struct dc_state *context,
-               int requested_clock_khz);
-};
-
-#endif /* __DISPLAY_CLOCK_H__ */
index 4550747fb61c24039cb2941c8823339ecd7573c3..cb85eaa9857f84e878115934dc00fb10f92b80ea 100644 (file)
@@ -32,6 +32,13 @@ enum dmcu_state {
        DMCU_RUNNING = 1
 };
 
+struct dmcu_version {
+       unsigned int date;
+       unsigned int month;
+       unsigned int year;
+       unsigned int interface_version;
+};
+
 struct dmcu {
        struct dc_context *ctx;
        const struct dmcu_funcs *funcs;
index 334c48cdafdc29cb347dcecbd44b6ae7a9a7ec6f..04c6989aac58dd002288ef669d6e8f372a3f7c84 100644 (file)
@@ -63,6 +63,11 @@ struct hubp_funcs {
                        struct _vcs_dpi_display_rq_regs_st *rq_regs,
                        struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest);
 
+       void (*hubp_setup_interdependent)(
+                       struct hubp *hubp,
+                       struct _vcs_dpi_display_dlg_regs_st *dlg_regs,
+                       struct _vcs_dpi_display_ttu_regs_st *ttu_regs);
+
        void (*dcc_control)(struct hubp *hubp, bool enable,
                        bool independent_64b_blks);
        void (*mem_program_viewport)(
@@ -121,6 +126,7 @@ struct hubp_funcs {
        void (*hubp_clk_cntl)(struct hubp *hubp, bool enable);
        void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst);
        void (*hubp_read_state)(struct hubp *hubp);
+       void (*hubp_clear_underflow)(struct hubp *hubp);
        void (*hubp_disable_control)(struct hubp *hubp, bool disable_hubp);
        unsigned int (*hubp_get_underflow_status)(struct hubp *hubp);
 
index cf7433ebf91a07557b1f4328980ba4bdcf15ab07..da85537a448881689b8333a7d33f2d477172c21f 100644 (file)
@@ -53,6 +53,12 @@ struct curve_points {
        uint32_t custom_float_slope;
 };
 
+struct curve_points3 {
+       struct curve_points red;
+       struct curve_points green;
+       struct curve_points blue;
+};
+
 struct pwl_result_data {
        struct fixed31_32 red;
        struct fixed31_32 green;
@@ -71,9 +77,17 @@ struct pwl_result_data {
        uint32_t delta_blue_reg;
 };
 
+/* arr_curve_points - regamma regions/segments specification
+ * arr_points - beginning and end point specified separately (only one on DCE)
+ * corner_points - beginning and end point for all 3 colors (DCN)
+ * rgb_resulted - final curve
+ */
 struct pwl_params {
        struct gamma_curve arr_curve_points[34];
-       struct curve_points arr_points[2];
+       union {
+               struct curve_points arr_points[2];
+               struct curve_points3 corner_points[2];
+       };
        struct pwl_result_data rgb_resulted[256 + 3];
        uint32_t hw_points_num;
 };
index e28e9770e0a3638cca907b213a63aceb5787588e..c20fdcaac53bb7e29e51ad7eccdbb58d0292e65a 100644 (file)
@@ -65,7 +65,8 @@ struct encoder_feature_support {
 
        enum dc_color_depth max_hdmi_deep_color;
        unsigned int max_hdmi_pixel_clock;
-       bool ycbcr420_supported;
+       bool hdmi_ycbcr420_supported;
+       bool dp_ycbcr420_supported;
 };
 
 union dpcd_psr_configuration {
index da89c2edb07c758034d640045201465833dfa245..06df02ddff6a045a9f201e78a504b57453f33717 100644 (file)
@@ -31,7 +31,7 @@
 #include "dml/display_mode_structs.h"
 
 struct dchub_init_data;
-struct cstate_pstate_watermarks_st {
+struct cstate_pstate_watermarks_st1 {
        uint32_t cstate_exit_ns;
        uint32_t cstate_enter_plus_exit_ns;
        uint32_t pstate_change_ns;
@@ -40,7 +40,7 @@ struct cstate_pstate_watermarks_st {
 struct dcn_watermarks {
        uint32_t pte_meta_urgent_ns;
        uint32_t urgent_ns;
-       struct cstate_pstate_watermarks_st cstate_pstate;
+       struct cstate_pstate_watermarks_st1 cstate_pstate;
 };
 
 struct dcn_watermark_set {
index 26f29d5da3d8c098ed695b17476a7bc6c9d77826..d6a85f48b6d17434cc62b07629c17463ad1fac18 100644 (file)
@@ -32,8 +32,6 @@
 #include "inc/hw/link_encoder.h"
 #include "core_status.h"
 
-#define EDP_BACKLIGHT_RAMP_DISABLE_LEVEL 0xFFFFFFFF
-
 enum pipe_gating_control {
        PIPE_GATING_CONTROL_DISABLE = 0,
        PIPE_GATING_CONTROL_ENABLE,
@@ -87,11 +85,6 @@ struct hw_sequencer_funcs {
        void (*program_gamut_remap)(
                        struct pipe_ctx *pipe_ctx);
 
-       void (*program_csc_matrix)(
-                       struct pipe_ctx *pipe_ctx,
-                       enum dc_color_space colorspace,
-                       uint16_t *matrix);
-
        void (*program_output_csc)(struct dc *dc,
                        struct pipe_ctx *pipe_ctx,
                        enum dc_color_space colorspace,
@@ -177,10 +170,12 @@ struct hw_sequencer_funcs {
                        struct pipe_ctx *pipe_ctx,
                        bool blank);
 
-       void (*set_bandwidth)(
+       void (*prepare_bandwidth)(
                        struct dc *dc,
-                       struct dc_state *context,
-                       bool safe_to_lower);
+                       struct dc_state *context);
+       void (*optimize_bandwidth)(
+                       struct dc *dc,
+                       struct dc_state *context);
 
        void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes,
                        int vmin, int vmax);
@@ -205,16 +200,12 @@ struct hw_sequencer_funcs {
        void (*log_hw_state)(struct dc *dc,
                struct dc_log_buffer_ctx *log_ctx);
        void (*get_hw_state)(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask);
+       void (*clear_status_bits)(struct dc *dc, unsigned int mask);
 
        void (*wait_for_mpcc_disconnect)(struct dc *dc,
                        struct resource_pool *res_pool,
                        struct pipe_ctx *pipe_ctx);
 
-       void (*ready_shared_resources)(struct dc *dc, struct dc_state *context);
-       void (*optimize_shared_resources)(struct dc *dc);
-       void (*pplib_apply_display_requirements)(
-                       struct dc *dc,
-                       struct dc_state *context);
        void (*edp_power_control)(
                        struct dc_link *link,
                        bool enable);
index 33b99e3ab10d59bb63dc43cc38bd67f66005ef48..0086a2f1d21a1983d30bfd6509bdfc65ed731845 100644 (file)
@@ -30,9 +30,6 @@
 #include "dal_asic_id.h"
 #include "dm_pp_smu.h"
 
-/* TODO unhardcode, 4 for CZ*/
-#define MEMORY_TYPE_MULTIPLIER 4
-
 enum dce_version resource_parse_asic_id(
                struct hw_asic_id asic_id);
 
index cdcefd08748784b353bed088aab4ed642213b8c9..479b77c2e89e222467753209ebf40524a07bd7c1 100644 (file)
@@ -306,6 +306,18 @@ static struct fixed31_32 translate_from_linear_space(
                        a1);
 }
 
+static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
+{
+       struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
+
+       return translate_from_linear_space(arg,
+                       dc_fixpt_zero,
+                       dc_fixpt_zero,
+                       dc_fixpt_zero,
+                       dc_fixpt_zero,
+                       gamma);
+}
+
 static struct fixed31_32 translate_to_linear_space(
        struct fixed31_32 arg,
        struct fixed31_32 a0,
@@ -709,6 +721,175 @@ static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
        }
 }
 
+static void hermite_spline_eetf(struct fixed31_32 input_x,
+                               struct fixed31_32 max_display,
+                               struct fixed31_32 min_display,
+                               struct fixed31_32 max_content,
+                               struct fixed31_32 *out_x)
+{
+       struct fixed31_32 min_lum_pq;
+       struct fixed31_32 max_lum_pq;
+       struct fixed31_32 max_content_pq;
+       struct fixed31_32 ks;
+       struct fixed31_32 E1;
+       struct fixed31_32 E2;
+       struct fixed31_32 E3;
+       struct fixed31_32 t;
+       struct fixed31_32 t2;
+       struct fixed31_32 t3;
+       struct fixed31_32 two;
+       struct fixed31_32 three;
+       struct fixed31_32 temp1;
+       struct fixed31_32 temp2;
+       struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
+       struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
+       struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small
+
+       if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
+               *out_x = dc_fixpt_zero;
+               return;
+       }
+
+       compute_pq(input_x, &E1);
+       compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
+       compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
+       compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird
+       a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent
+       ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b
+
+       if (dc_fixpt_lt(E1, ks))
+               E2 = E1;
+       else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
+               if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
+                       // t = (E1 - ks) / (1 - ks)
+                       t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
+                                       dc_fixpt_sub(dc_fixpt_one, ks));
+               else
+                       t = dc_fixpt_zero;
+
+               two = dc_fixpt_from_int(2);
+               three = dc_fixpt_from_int(3);
+
+               t2 = dc_fixpt_mul(t, t);
+               t3 = dc_fixpt_mul(t2, t);
+               temp1 = dc_fixpt_mul(two, t3);
+               temp2 = dc_fixpt_mul(three, t2);
+
+               // (2t^3 - 3t^2 + 1) * ks
+               E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
+                               dc_fixpt_sub(temp1, temp2)));
+
+               // (-2t^3 + 3t^2) * max_lum_pq
+               E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
+                               dc_fixpt_sub(temp2, temp1)));
+
+               temp1 = dc_fixpt_mul(two, t2);
+               temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
+
+               // (t^3 - 2t^2 + t) * (1-ks)
+               E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
+                               dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
+       } else
+               E2 = dc_fixpt_one;
+
+       temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
+       temp2 = dc_fixpt_mul(temp1, temp1);
+       temp2 = dc_fixpt_mul(temp2, temp2);
+       // temp2 = (1-E2)^4
+
+       E3 =  dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
+       compute_de_pq(E3, out_x);
+
+       *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
+}
+
+static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
+               uint32_t hw_points_num,
+               const struct hw_x_point *coordinate_x,
+               const struct freesync_hdr_tf_params *fs_params)
+{
+       uint32_t i;
+       struct pwl_float_data_ex *rgb = rgb_regamma;
+       const struct hw_x_point *coord_x = coordinate_x;
+       struct fixed31_32 scaledX = dc_fixpt_zero;
+       struct fixed31_32 scaledX1 = dc_fixpt_zero;
+       struct fixed31_32 max_display;
+       struct fixed31_32 min_display;
+       struct fixed31_32 max_content;
+       struct fixed31_32 min_content;
+       struct fixed31_32 clip = dc_fixpt_one;
+       struct fixed31_32 output;
+       bool use_eetf = false;
+       bool is_clipped = false;
+       struct fixed31_32 sdr_white_level;
+
+       if (fs_params == NULL || fs_params->max_content == 0 ||
+                       fs_params->max_display == 0)
+               return false;
+
+       max_display = dc_fixpt_from_int(fs_params->max_display);
+       min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
+       max_content = dc_fixpt_from_int(fs_params->max_content);
+       min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
+       sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
+
+       if (fs_params->min_display > 1000) // cap at 0.1 at the bottom
+               min_display = dc_fixpt_from_fraction(1, 10);
+       if (fs_params->max_display < 100) // cap at 100 at the top
+               max_display = dc_fixpt_from_int(100);
+
+       if (fs_params->min_content < fs_params->min_display)
+               use_eetf = true;
+       else
+               min_content = min_display;
+
+       if (fs_params->max_content > fs_params->max_display)
+               use_eetf = true;
+       else
+               max_content = max_display;
+
+       rgb += 32; // first 32 points have problems with fixed point, too small
+       coord_x += 32;
+       for (i = 32; i <= hw_points_num; i++) {
+               if (!is_clipped) {
+                       if (use_eetf) {
+                               /*max content is equal 1 */
+                               scaledX1 = dc_fixpt_div(coord_x->x,
+                                               dc_fixpt_div(max_content, sdr_white_level));
+                               hermite_spline_eetf(scaledX1, max_display, min_display,
+                                               max_content, &scaledX);
+                       } else
+                               scaledX = dc_fixpt_div(coord_x->x,
+                                               dc_fixpt_div(max_display, sdr_white_level));
+
+                       if (dc_fixpt_lt(scaledX, clip)) {
+                               if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
+                                       output = dc_fixpt_zero;
+                               else
+                                       output = calculate_gamma22(scaledX);
+
+                               rgb->r = output;
+                               rgb->g = output;
+                               rgb->b = output;
+                       } else {
+                               is_clipped = true;
+                               rgb->r = clip;
+                               rgb->g = clip;
+                               rgb->b = clip;
+                       }
+               } else {
+                       rgb->r = clip;
+                       rgb->g = clip;
+                       rgb->b = clip;
+               }
+
+               ++coord_x;
+               ++rgb;
+       }
+
+       return true;
+}
+
 static void build_degamma(struct pwl_float_data_ex *curve,
                uint32_t hw_points_num,
                const struct hw_x_point *coordinate_x, bool is_2_4)
@@ -1356,7 +1537,8 @@ static bool map_regamma_hw_to_x_user(
 #define _EXTRA_POINTS 3
 
 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
-               const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed)
+               const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
+               const struct freesync_hdr_tf_params *fs_params)
 {
        struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
        struct dividers dividers;
@@ -1374,7 +1556,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
        /* we can use hardcoded curve for plain SRGB TF */
        if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
                        output_tf->tf == TRANSFER_FUNCTION_SRGB &&
-                       (!mapUserRamp && ramp->type == GAMMA_RGB_256))
+                       (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256)))
                return true;
 
        output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
@@ -1424,6 +1606,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
                                MAX_HW_POINTS,
                                coordinates_x,
                                output_tf->sdr_ref_white_level);
+       } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
+                       fs_params != NULL) {
+               build_freesync_hdr(rgb_regamma,
+                               MAX_HW_POINTS,
+                               coordinates_x,
+                               fs_params);
        } else {
                tf_pts->end_exponent = 0;
                tf_pts->x_point_at_y1_red = 1;
@@ -1573,7 +1761,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
 
        struct pwl_float_data *rgb_user = NULL;
        struct pwl_float_data_ex *curve = NULL;
-       struct gamma_pixel *axix_x = NULL;
+       struct gamma_pixel *axis_x = NULL;
        struct pixel_gamma_point *coeff = NULL;
        enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
        bool ret = false;
@@ -1599,10 +1787,10 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
                         GFP_KERNEL);
        if (!curve)
                goto curve_alloc_fail;
-       axix_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axix_x),
+       axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x),
                          GFP_KERNEL);
-       if (!axix_x)
-               goto axix_x_alloc_fail;
+       if (!axis_x)
+               goto axis_x_alloc_fail;
        coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
                         GFP_KERNEL);
        if (!coeff)
@@ -1615,7 +1803,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
        tf = input_tf->tf;
 
        build_evenly_distributed_points(
-                       axix_x,
+                       axis_x,
                        ramp->num_entries,
                        dividers);
 
@@ -1640,7 +1828,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
        tf_pts->x_point_at_y1_blue = 1;
 
        map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
-                       coordinates_x, axix_x, curve,
+                       coordinates_x, axis_x, curve,
                        MAX_HW_POINTS, tf_pts,
                        mapUserRamp && ramp->type != GAMMA_CUSTOM);
        if (ramp->type == GAMMA_CUSTOM)
@@ -1650,8 +1838,8 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
 
        kvfree(coeff);
 coeff_alloc_fail:
-       kvfree(axix_x);
-axix_x_alloc_fail:
+       kvfree(axis_x);
+axis_x_alloc_fail:
        kvfree(curve);
 curve_alloc_fail:
        kvfree(rgb_user);
index 63ccb9c91224796fbce9e78ab2b241f28c64514d..a6e164df090a669542cb195ee43552cffab2c23d 100644 (file)
@@ -73,12 +73,21 @@ struct regamma_lut {
        };
 };
 
+struct freesync_hdr_tf_params {
+       unsigned int sdr_white_level;
+       unsigned int min_content; // luminance in 1/10000 nits
+       unsigned int max_content; // luminance in nits
+       unsigned int min_display; // luminance in 1/10000 nits
+       unsigned int max_display; // luminance in nits
+};
+
 void setup_x_points_distribution(void);
 void precompute_pq(void);
 void precompute_de_pq(void);
 
 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
-               const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed);
+               const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
+               const struct freesync_hdr_tf_params *fs_params);
 
 bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf,
                const struct dc_gamma *ramp, bool mapUserRamp);
index 4018c7180d007a8a83ee549a99d6f3f02b07cb7f..1544ed3f17473cb80c0009c338bccd60f245a52c 100644 (file)
@@ -37,6 +37,8 @@
 #define RENDER_TIMES_MAX_COUNT 10
 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
 #define BTR_EXIT_MARGIN 2000
+/*Threshold to exit fixed refresh rate*/
+#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4
 /* Number of consecutive frames to check before entering/exiting fixed refresh*/
 #define FIXED_REFRESH_ENTER_FRAME_COUNT 5
 #define FIXED_REFRESH_EXIT_FRAME_COUNT 5
@@ -257,40 +259,14 @@ static void apply_below_the_range(struct core_freesync *core_freesync,
                if (in_out_vrr->btr.btr_active) {
                        in_out_vrr->btr.frame_counter = 0;
                        in_out_vrr->btr.btr_active = false;
-
-               /* Exit Fixed Refresh mode */
-               } else if (in_out_vrr->fixed.fixed_active) {
-
-                       in_out_vrr->fixed.frame_counter++;
-
-                       if (in_out_vrr->fixed.frame_counter >
-                                       FIXED_REFRESH_EXIT_FRAME_COUNT) {
-                               in_out_vrr->fixed.frame_counter = 0;
-                               in_out_vrr->fixed.fixed_active = false;
-                       }
                }
        } else if (last_render_time_in_us > max_render_time_in_us) {
                /* Enter Below the Range */
-               if (!in_out_vrr->btr.btr_active &&
-                               in_out_vrr->btr.btr_enabled) {
-                       in_out_vrr->btr.btr_active = true;
-
-               /* Enter Fixed Refresh mode */
-               } else if (!in_out_vrr->fixed.fixed_active &&
-                               !in_out_vrr->btr.btr_enabled) {
-                       in_out_vrr->fixed.frame_counter++;
-
-                       if (in_out_vrr->fixed.frame_counter >
-                                       FIXED_REFRESH_ENTER_FRAME_COUNT) {
-                               in_out_vrr->fixed.frame_counter = 0;
-                               in_out_vrr->fixed.fixed_active = true;
-                       }
-               }
+               in_out_vrr->btr.btr_active = true;
        }
 
        /* BTR set to "not active" so disengage */
        if (!in_out_vrr->btr.btr_active) {
-               in_out_vrr->btr.btr_active = false;
                in_out_vrr->btr.inserted_duration_in_us = 0;
                in_out_vrr->btr.frames_to_insert = 0;
                in_out_vrr->btr.frame_counter = 0;
@@ -375,7 +351,12 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
        bool update = false;
        unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
 
-       if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
+       //Compute the exit refresh rate and exit frame duration
+       unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
+                       + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
+       unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
+
+       if (last_render_time_in_us < exit_frame_duration_in_us) {
                /* Exit Fixed Refresh mode */
                if (in_out_vrr->fixed.fixed_active) {
                        in_out_vrr->fixed.frame_counter++;
@@ -627,12 +608,12 @@ static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr,
 static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf,
                struct dc_info_packet *infopacket)
 {
-       if (app_tf != transfer_func_unknown) {
+       if (app_tf != TRANSFER_FUNC_UNKNOWN) {
                infopacket->valid = true;
 
                infopacket->sb[6] |= 0x08;  // PB6 = [Bit 3 = Native Color Active]
 
-               if (app_tf == transfer_func_gamma_22) {
+               if (app_tf == TRANSFER_FUNC_GAMMA_22) {
                        infopacket->sb[9] |= 0x04;  // PB6 = [Bit 2 = Gamma 2.2 EOTF Active]
                }
        }
@@ -707,11 +688,11 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
                return;
 
        switch (packet_type) {
-       case packet_type_fs2:
+       case PACKET_TYPE_FS2:
                build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket);
                break;
-       case packet_type_vrr:
-       case packet_type_fs1:
+       case PACKET_TYPE_VRR:
+       case PACKET_TYPE_FS1:
        default:
                build_vrr_infopacket_v1(stream->signal, vrr, infopacket);
        }
index 786b34380f852eff3fc456eed8f05ed3154b60d8..5b1c9a4c764302e57d27830721f3c3bc6072357d 100644 (file)
 #ifndef MOD_INFO_PACKET_H_
 #define MOD_INFO_PACKET_H_
 
-struct info_packet_inputs {
-       const struct dc_stream_state *pStream;
-};
+#include "mod_shared.h"
 
-struct info_packets {
-       struct dc_info_packet *pVscInfoPacket;
-};
+//Forward Declarations
+struct dc_stream_state;
+struct dc_info_packet;
 
-void mod_build_infopackets(struct info_packet_inputs *inputs,
-               struct info_packets *info_packets);
+void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
+               struct dc_info_packet *info_packet);
 
 #endif
index 238c431ae4834c3fcb0cc27f935b7179c6fcb489..1bd02c0ac30c3f0bde291918146d60a7e7ecfcba 100644 (file)
  *
  */
 
-
 #ifndef MOD_SHARED_H_
 #define MOD_SHARED_H_
 
 enum color_transfer_func {
-       transfer_func_unknown,
-       transfer_func_srgb,
-       transfer_func_bt709,
-       transfer_func_pq2084,
-       transfer_func_pq2084_interim,
-       transfer_func_linear_0_1,
-       transfer_func_linear_0_125,
-       transfer_func_dolbyvision,
-       transfer_func_gamma_22,
-       transfer_func_gamma_26
+       TRANSFER_FUNC_UNKNOWN,
+       TRANSFER_FUNC_SRGB,
+       TRANSFER_FUNC_BT709,
+       TRANSFER_FUNC_PQ2084,
+       TRANSFER_FUNC_PQ2084_INTERIM,
+       TRANSFER_FUNC_LINEAR_0_1,
+       TRANSFER_FUNC_LINEAR_0_125,
+       TRANSFER_FUNC_GAMMA_22,
+       TRANSFER_FUNC_GAMMA_26
 };
 
 enum vrr_packet_type {
-       packet_type_vrr,
-       packet_type_fs1,
-       packet_type_fs2
+       PACKET_TYPE_VRR,
+       PACKET_TYPE_FS1,
+       PACKET_TYPE_FS2
 };
 
+
 #endif /* MOD_SHARED_H_ */
index ff8bfb9b43b0c944743fa5f9b956e430ad57bef6..db06fab2ad5cd06c8c9834429c841e4281fffb5a 100644 (file)
 
 #include "mod_info_packet.h"
 #include "core_types.h"
+#include "dc_types.h"
+#include "mod_shared.h"
+
+#define HDMI_INFOFRAME_TYPE_VENDOR 0x81
 
 enum ColorimetryRGBDP {
        ColorimetryRGB_DP_sRGB               = 0,
@@ -41,7 +45,7 @@ enum ColorimetryYCCDP {
        ColorimetryYCC_DP_ITU2020YCbCr  = 7,
 };
 
-static void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
+void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
                struct dc_info_packet *info_packet)
 {
        unsigned int vscPacketRevision = 0;
@@ -159,7 +163,7 @@ static void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
         *   DPCD register is exposed in the new Extended Receiver Capability field for DPCD Rev. 1.4
         *   (and higher). When MISC1. bit 6. is Set to 1, a Source device uses a VSC SDP to indicate
         *   the Pixel Encoding/Colorimetry Format and that a Sink device must ignore MISC1, bit 7, and
-        *   MISC0, bits 7:1 (MISC1, bit 7. and MISC0, bits 7:1 become “don’t care”).)
+        *   MISC0, bits 7:1 (MISC1, bit 7. and MISC0, bits 7:1 become "don't care").)
         */
        if (vscPacketRevision == 0x5) {
                /* Secondary-data Packet ID = 0 */
@@ -320,10 +324,3 @@ static void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 
 }
 
-void mod_build_infopackets(struct info_packet_inputs *inputs,
-               struct info_packets *info_packets)
-{
-       if (info_packets->pVscInfoPacket != NULL)
-               mod_build_vsc_infopacket(inputs->pStream, info_packets->pVscInfoPacket);
-}
-
diff --git a/drivers/gpu/drm/amd/display/modules/power/Makefile b/drivers/gpu/drm/amd/display/modules/power/Makefile
new file mode 100644 (file)
index 0000000..87851f8
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Copyright 2017 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+#
+# Makefile for the 'power' sub-module of DAL.
+#
+
+MOD_POWER = power_helpers.o
+
+AMD_DAL_MOD_POWER = $(addprefix $(AMDDALPATH)/modules/power/,$(MOD_POWER))
+#$(info ************  DAL POWER MODULE MAKEFILE ************)
+
+AMD_DISPLAY_FILES += $(AMD_DAL_MOD_POWER)
\ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
new file mode 100644 (file)
index 0000000..00f63b7
--- /dev/null
@@ -0,0 +1,326 @@
+/* Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "power_helpers.h"
+#include "dc/inc/hw/dmcu.h"
+
+#define DIV_ROUNDUP(a, b) (((a)+((b)/2))/(b))
+
+/* Possible Min Reduction config from least aggressive to most aggressive
+ *  0    1     2     3     4     5     6     7     8     9     10    11   12
+ * 100  98.0 94.1  94.1  85.1  80.3  75.3  69.4  60.0  57.6  50.2  49.8  40.0 %
+ */
+static const unsigned char min_reduction_table[13] = {
+0xff, 0xfa, 0xf0, 0xf0, 0xd9, 0xcd, 0xc0, 0xb1, 0x99, 0x93, 0x80, 0x82, 0x66};
+
+/* Possible Max Reduction configs from least aggressive to most aggressive
+ *  0    1     2     3     4     5     6     7     8     9     10    11   12
+ * 96.1 89.8 85.1  80.3  69.4  64.7  64.7  50.2  39.6  30.2  30.2  30.2  19.6 %
+ */
+static const unsigned char max_reduction_table[13] = {
+0xf5, 0xe5, 0xd9, 0xcd, 0xb1, 0xa5, 0xa5, 0x80, 0x65, 0x4d, 0x4d, 0x4d, 0x32};
+
+/* Predefined ABM configuration sets. We may have different configuration sets
+ * in order to satisfy different power/quality requirements.
+ */
+static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_level] = {
+/*  ABM Level 1,    ABM Level 2,    ABM Level 3,    ABM Level 4 */
+{       2,              5,              7,              8       },     /* Default - Medium aggressiveness */
+{       2,              5,              8,              11      },     /* Alt #1  - Increased aggressiveness */
+{       0,              2,              4,              8       },     /* Alt #2  - Minimal aggressiveness */
+{       3,              6,              10,             12      },     /* Alt #3  - Super aggressiveness */
+};
+
+#define NUM_AMBI_LEVEL    5
+#define NUM_AGGR_LEVEL    4
+#define NUM_POWER_FN_SEGS 8
+#define NUM_BL_CURVE_SEGS 16
+
+/* NOTE: iRAM is 256B in size */
+struct iram_table_v_2 {
+       /* flags                      */
+       uint16_t flags;                                                 /* 0x00 U16  */
+
+       /* parameters for ABM2.0 algorithm */
+       uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];          /* 0x02 U0.8 */
+       uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];          /* 0x16 U0.8 */
+       uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];        /* 0x2a U2.6 */
+       uint8_t bright_neg_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];        /* 0x3e U2.6 */
+       uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];          /* 0x52 U2.6 */
+       uint8_t dark_neg_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];          /* 0x66 U2.6 */
+       uint8_t iir_curve[NUM_AMBI_LEVEL];                              /* 0x7a U0.8 */
+       uint8_t deviation_gain;                                         /* 0x7f U0.8 */
+
+       /* parameters for crgb conversion */
+       uint16_t crgb_thresh[NUM_POWER_FN_SEGS];                        /* 0x80 U3.13 */
+       uint16_t crgb_offset[NUM_POWER_FN_SEGS];                        /* 0x90 U1.15 */
+       uint16_t crgb_slope[NUM_POWER_FN_SEGS];                         /* 0xa0 U4.12 */
+
+       /* parameters for custom curve */
+       /* thresholds for brightness --> backlight */
+       uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS];               /* 0xb0 U16.0 */
+       /* offsets for brightness --> backlight */
+       uint16_t backlight_offsets[NUM_BL_CURVE_SEGS];                  /* 0xd0 U16.0 */
+
+       /* For reading PSR State directly from IRAM */
+       uint8_t psr_state;                                              /* 0xf0       */
+       uint8_t dmcu_interface_version;                                 /* 0xf1       */
+       uint8_t dmcu_date_version_year_b0;                              /* 0xf2       */
+       uint8_t dmcu_date_version_year_b1;                              /* 0xf3       */
+       uint8_t dmcu_date_version_month;                                /* 0xf4       */
+       uint8_t dmcu_date_version_day;                                  /* 0xf5       */
+       uint8_t dmcu_state;                                             /* 0xf6       */
+
+       uint16_t blRampReduction;                                       /* 0xf7       */
+       uint16_t blRampStart;                                           /* 0xf9       */
+       uint8_t dummy5;                                                 /* 0xfb       */
+       uint8_t dummy6;                                                 /* 0xfc       */
+       uint8_t dummy7;                                                 /* 0xfd       */
+       uint8_t dummy8;                                                 /* 0xfe       */
+       uint8_t dummy9;                                                 /* 0xff       */
+};
+
+static uint16_t backlight_8_to_16(unsigned int backlight_8bit)
+{
+       return (uint16_t)(backlight_8bit * 0x101);
+}
+
+static void fill_backlight_transform_table(struct dmcu_iram_parameters params,
+               struct iram_table_v_2 *table)
+{
+       unsigned int i;
+       unsigned int num_entries = NUM_BL_CURVE_SEGS;
+       unsigned int query_input_8bit;
+       unsigned int query_output_8bit;
+       unsigned int lut_index;
+
+       table->backlight_thresholds[0] = 0;
+       table->backlight_offsets[0] = params.backlight_lut_array[0];
+       table->backlight_thresholds[num_entries-1] = 0xFFFF;
+       table->backlight_offsets[num_entries-1] =
+               params.backlight_lut_array[params.backlight_lut_array_size - 1];
+
+       /* Setup all brightness levels between 0% and 100% exclusive
+        * Fills brightness-to-backlight transform table. Backlight custom curve
+        * describes transform from brightness to backlight. It will be defined
+        * as set of thresholds and set of offsets, together, implying
+        * extrapolation of custom curve into 16 uniformly spanned linear
+        * segments.  Each threshold/offset represented by 16 bit entry in
+        * format U4.10.
+        */
+       for (i = 1; i+1 < num_entries; i++) {
+               query_input_8bit = DIV_ROUNDUP((i * 256), num_entries);
+
+               lut_index = (params.backlight_lut_array_size - 1) * i / (num_entries - 1);
+               ASSERT(lut_index < params.backlight_lut_array_size);
+               query_output_8bit = params.backlight_lut_array[lut_index] >> 8;
+
+               table->backlight_thresholds[i] =
+                               backlight_8_to_16(query_input_8bit);
+               table->backlight_offsets[i] =
+                               backlight_8_to_16(query_output_8bit);
+       }
+}
+
+bool dmcu_load_iram(struct dmcu *dmcu,
+       struct dmcu_iram_parameters params)
+{
+       struct iram_table_v_2 ram_table;
+       unsigned int set = params.set;
+
+       if (dmcu == NULL)
+               return false;
+
+       if (!dmcu->funcs->is_dmcu_initialized(dmcu))
+               return true;
+
+       memset(&ram_table, 0, sizeof(ram_table));
+
+       ram_table.flags = 0x0;
+       ram_table.deviation_gain = 0xb3;
+
+       ram_table.blRampReduction =
+               cpu_to_be16(params.backlight_ramping_reduction);
+       ram_table.blRampStart =
+               cpu_to_be16(params.backlight_ramping_start);
+
+       ram_table.min_reduction[0][0] = min_reduction_table[abm_config[set][0]];
+       ram_table.min_reduction[1][0] = min_reduction_table[abm_config[set][0]];
+       ram_table.min_reduction[2][0] = min_reduction_table[abm_config[set][0]];
+       ram_table.min_reduction[3][0] = min_reduction_table[abm_config[set][0]];
+       ram_table.min_reduction[4][0] = min_reduction_table[abm_config[set][0]];
+       ram_table.max_reduction[0][0] = max_reduction_table[abm_config[set][0]];
+       ram_table.max_reduction[1][0] = max_reduction_table[abm_config[set][0]];
+       ram_table.max_reduction[2][0] = max_reduction_table[abm_config[set][0]];
+       ram_table.max_reduction[3][0] = max_reduction_table[abm_config[set][0]];
+       ram_table.max_reduction[4][0] = max_reduction_table[abm_config[set][0]];
+
+       ram_table.min_reduction[0][1] = min_reduction_table[abm_config[set][1]];
+       ram_table.min_reduction[1][1] = min_reduction_table[abm_config[set][1]];
+       ram_table.min_reduction[2][1] = min_reduction_table[abm_config[set][1]];
+       ram_table.min_reduction[3][1] = min_reduction_table[abm_config[set][1]];
+       ram_table.min_reduction[4][1] = min_reduction_table[abm_config[set][1]];
+       ram_table.max_reduction[0][1] = max_reduction_table[abm_config[set][1]];
+       ram_table.max_reduction[1][1] = max_reduction_table[abm_config[set][1]];
+       ram_table.max_reduction[2][1] = max_reduction_table[abm_config[set][1]];
+       ram_table.max_reduction[3][1] = max_reduction_table[abm_config[set][1]];
+       ram_table.max_reduction[4][1] = max_reduction_table[abm_config[set][1]];
+
+       ram_table.min_reduction[0][2] = min_reduction_table[abm_config[set][2]];
+       ram_table.min_reduction[1][2] = min_reduction_table[abm_config[set][2]];
+       ram_table.min_reduction[2][2] = min_reduction_table[abm_config[set][2]];
+       ram_table.min_reduction[3][2] = min_reduction_table[abm_config[set][2]];
+       ram_table.min_reduction[4][2] = min_reduction_table[abm_config[set][2]];
+       ram_table.max_reduction[0][2] = max_reduction_table[abm_config[set][2]];
+       ram_table.max_reduction[1][2] = max_reduction_table[abm_config[set][2]];
+       ram_table.max_reduction[2][2] = max_reduction_table[abm_config[set][2]];
+       ram_table.max_reduction[3][2] = max_reduction_table[abm_config[set][2]];
+       ram_table.max_reduction[4][2] = max_reduction_table[abm_config[set][2]];
+
+       ram_table.min_reduction[0][3] = min_reduction_table[abm_config[set][3]];
+       ram_table.min_reduction[1][3] = min_reduction_table[abm_config[set][3]];
+       ram_table.min_reduction[2][3] = min_reduction_table[abm_config[set][3]];
+       ram_table.min_reduction[3][3] = min_reduction_table[abm_config[set][3]];
+       ram_table.min_reduction[4][3] = min_reduction_table[abm_config[set][3]];
+       ram_table.max_reduction[0][3] = max_reduction_table[abm_config[set][3]];
+       ram_table.max_reduction[1][3] = max_reduction_table[abm_config[set][3]];
+       ram_table.max_reduction[2][3] = max_reduction_table[abm_config[set][3]];
+       ram_table.max_reduction[3][3] = max_reduction_table[abm_config[set][3]];
+       ram_table.max_reduction[4][3] = max_reduction_table[abm_config[set][3]];
+
+       ram_table.bright_pos_gain[0][0] = 0x20;
+       ram_table.bright_pos_gain[0][1] = 0x20;
+       ram_table.bright_pos_gain[0][2] = 0x20;
+       ram_table.bright_pos_gain[0][3] = 0x20;
+       ram_table.bright_pos_gain[1][0] = 0x20;
+       ram_table.bright_pos_gain[1][1] = 0x20;
+       ram_table.bright_pos_gain[1][2] = 0x20;
+       ram_table.bright_pos_gain[1][3] = 0x20;
+       ram_table.bright_pos_gain[2][0] = 0x20;
+       ram_table.bright_pos_gain[2][1] = 0x20;
+       ram_table.bright_pos_gain[2][2] = 0x20;
+       ram_table.bright_pos_gain[2][3] = 0x20;
+       ram_table.bright_pos_gain[3][0] = 0x20;
+       ram_table.bright_pos_gain[3][1] = 0x20;
+       ram_table.bright_pos_gain[3][2] = 0x20;
+       ram_table.bright_pos_gain[3][3] = 0x20;
+       ram_table.bright_pos_gain[4][0] = 0x20;
+       ram_table.bright_pos_gain[4][1] = 0x20;
+       ram_table.bright_pos_gain[4][2] = 0x20;
+       ram_table.bright_pos_gain[4][3] = 0x20;
+       ram_table.bright_neg_gain[0][1] = 0x00;
+       ram_table.bright_neg_gain[0][2] = 0x00;
+       ram_table.bright_neg_gain[0][3] = 0x00;
+       ram_table.bright_neg_gain[1][0] = 0x00;
+       ram_table.bright_neg_gain[1][1] = 0x00;
+       ram_table.bright_neg_gain[1][2] = 0x00;
+       ram_table.bright_neg_gain[1][3] = 0x00;
+       ram_table.bright_neg_gain[2][0] = 0x00;
+       ram_table.bright_neg_gain[2][1] = 0x00;
+       ram_table.bright_neg_gain[2][2] = 0x00;
+       ram_table.bright_neg_gain[2][3] = 0x00;
+       ram_table.bright_neg_gain[3][0] = 0x00;
+       ram_table.bright_neg_gain[3][1] = 0x00;
+       ram_table.bright_neg_gain[3][2] = 0x00;
+       ram_table.bright_neg_gain[3][3] = 0x00;
+       ram_table.bright_neg_gain[4][0] = 0x00;
+       ram_table.bright_neg_gain[4][1] = 0x00;
+       ram_table.bright_neg_gain[4][2] = 0x00;
+       ram_table.bright_neg_gain[4][3] = 0x00;
+       ram_table.dark_pos_gain[0][0] = 0x00;
+       ram_table.dark_pos_gain[0][1] = 0x00;
+       ram_table.dark_pos_gain[0][2] = 0x00;
+       ram_table.dark_pos_gain[0][3] = 0x00;
+       ram_table.dark_pos_gain[1][0] = 0x00;
+       ram_table.dark_pos_gain[1][1] = 0x00;
+       ram_table.dark_pos_gain[1][2] = 0x00;
+       ram_table.dark_pos_gain[1][3] = 0x00;
+       ram_table.dark_pos_gain[2][0] = 0x00;
+       ram_table.dark_pos_gain[2][1] = 0x00;
+       ram_table.dark_pos_gain[2][2] = 0x00;
+       ram_table.dark_pos_gain[2][3] = 0x00;
+       ram_table.dark_pos_gain[3][0] = 0x00;
+       ram_table.dark_pos_gain[3][1] = 0x00;
+       ram_table.dark_pos_gain[3][2] = 0x00;
+       ram_table.dark_pos_gain[3][3] = 0x00;
+       ram_table.dark_pos_gain[4][0] = 0x00;
+       ram_table.dark_pos_gain[4][1] = 0x00;
+       ram_table.dark_pos_gain[4][2] = 0x00;
+       ram_table.dark_pos_gain[4][3] = 0x00;
+       ram_table.dark_neg_gain[0][0] = 0x00;
+       ram_table.dark_neg_gain[0][1] = 0x00;
+       ram_table.dark_neg_gain[0][2] = 0x00;
+       ram_table.dark_neg_gain[0][3] = 0x00;
+       ram_table.dark_neg_gain[1][0] = 0x00;
+       ram_table.dark_neg_gain[1][1] = 0x00;
+       ram_table.dark_neg_gain[1][2] = 0x00;
+       ram_table.dark_neg_gain[1][3] = 0x00;
+       ram_table.dark_neg_gain[2][0] = 0x00;
+       ram_table.dark_neg_gain[2][1] = 0x00;
+       ram_table.dark_neg_gain[2][2] = 0x00;
+       ram_table.dark_neg_gain[2][3] = 0x00;
+       ram_table.dark_neg_gain[3][0] = 0x00;
+       ram_table.dark_neg_gain[3][1] = 0x00;
+       ram_table.dark_neg_gain[3][2] = 0x00;
+       ram_table.dark_neg_gain[3][3] = 0x00;
+       ram_table.dark_neg_gain[4][0] = 0x00;
+       ram_table.dark_neg_gain[4][1] = 0x00;
+       ram_table.dark_neg_gain[4][2] = 0x00;
+       ram_table.dark_neg_gain[4][3] = 0x00;
+       ram_table.iir_curve[0] = 0x65;
+       ram_table.iir_curve[1] = 0x65;
+       ram_table.iir_curve[2] = 0x65;
+       ram_table.iir_curve[3] = 0x65;
+       ram_table.iir_curve[4] = 0x65;
+       ram_table.crgb_thresh[0] = cpu_to_be16(0x13b6);
+       ram_table.crgb_thresh[1] = cpu_to_be16(0x1648);
+       ram_table.crgb_thresh[2] = cpu_to_be16(0x18e3);
+       ram_table.crgb_thresh[3] = cpu_to_be16(0x1b41);
+       ram_table.crgb_thresh[4] = cpu_to_be16(0x1d46);
+       ram_table.crgb_thresh[5] = cpu_to_be16(0x1f21);
+       ram_table.crgb_thresh[6] = cpu_to_be16(0x2167);
+       ram_table.crgb_thresh[7] = cpu_to_be16(0x2384);
+       ram_table.crgb_offset[0] = cpu_to_be16(0x2999);
+       ram_table.crgb_offset[1] = cpu_to_be16(0x3999);
+       ram_table.crgb_offset[2] = cpu_to_be16(0x4666);
+       ram_table.crgb_offset[3] = cpu_to_be16(0x5999);
+       ram_table.crgb_offset[4] = cpu_to_be16(0x6333);
+       ram_table.crgb_offset[5] = cpu_to_be16(0x7800);
+       ram_table.crgb_offset[6] = cpu_to_be16(0x8c00);
+       ram_table.crgb_offset[7] = cpu_to_be16(0xa000);
+       ram_table.crgb_slope[0]  = cpu_to_be16(0x3147);
+       ram_table.crgb_slope[1]  = cpu_to_be16(0x2978);
+       ram_table.crgb_slope[2]  = cpu_to_be16(0x23a2);
+       ram_table.crgb_slope[3]  = cpu_to_be16(0x1f55);
+       ram_table.crgb_slope[4]  = cpu_to_be16(0x1c63);
+       ram_table.crgb_slope[5]  = cpu_to_be16(0x1a0f);
+       ram_table.crgb_slope[6]  = cpu_to_be16(0x178d);
+       ram_table.crgb_slope[7]  = cpu_to_be16(0x15ab);
+
+       fill_backlight_transform_table(
+                       params, &ram_table);
+
+       return dmcu->funcs->load_iram(
+                       dmcu, 0, (char *)(&ram_table), sizeof(ram_table));
+}
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
new file mode 100644 (file)
index 0000000..da5df00
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef MODULES_POWER_POWER_HELPERS_H_
+#define MODULES_POWER_POWER_HELPERS_H_
+
+#include "dc/inc/hw/dmcu.h"
+
+
+enum abm_defines {
+       abm_defines_max_level = 4,
+       abm_defines_max_config = 4,
+};
+
+struct dmcu_iram_parameters {
+       unsigned int *backlight_lut_array;
+       unsigned int backlight_lut_array_size;
+       unsigned int backlight_ramping_reduction;
+       unsigned int backlight_ramping_start;
+       unsigned int set;
+};
+
+bool dmcu_load_iram(struct dmcu *dmcu,
+               struct dmcu_iram_parameters params);
+
+#endif /* MODULES_POWER_POWER_HELPERS_H_ */
index 9b9699fc433fba529ef03311622873d3c82c9b27..c72cbfe8f684b926bd149e8a58581c6951d9d18f 100644 (file)
@@ -52,6 +52,30 @@ struct atif_sbios_requests {
        u8 backlight_level;     /* panel backlight level (0-255) */
 } __packed;
 
+struct atif_qbtc_arguments {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u8 requested_display;   /* which display is requested */
+} __packed;
+
+#define ATIF_QBTC_MAX_DATA_POINTS 99
+
+struct atif_qbtc_data_point {
+       u8 luminance;           /* luminance in percent */
+       u8 ipnut_signal;        /* input signal in range 0-255 */
+} __packed;
+
+struct atif_qbtc_output {
+       u16 size;               /* structure size in bytes (includes size field) */
+       u16 flags;              /* all zeroes */
+       u8 error_code;          /* error code */
+       u8 ac_level;            /* default brightness on AC power */
+       u8 dc_level;            /* default brightness on DC power */
+       u8 min_input_signal;    /* max input signal in range 0-255 */
+       u8 max_input_signal;    /* min input signal in range 0-255 */
+       u8 number_of_points;    /* number of data points */
+       struct atif_qbtc_data_point data_points[ATIF_QBTC_MAX_DATA_POINTS];
+} __packed;
+
 #define ATIF_NOTIFY_MASK       0x3
 #define ATIF_NOTIFY_NONE       0
 #define ATIF_NOTIFY_81         1
@@ -126,26 +150,18 @@ struct atcs_pref_req_output {
  * DWORD - supported functions bit vector
  */
 /* Notifications mask */
-#       define ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED               (1 << 0)
-#       define ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED        (1 << 1)
 #       define ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED         (1 << 2)
 #       define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED    (1 << 3)
 #       define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED   (1 << 4)
-#       define ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED          (1 << 5)
-#       define ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED                (1 << 6)
 #       define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED      (1 << 7)
 #       define ATIF_DGPU_DISPLAY_EVENT_SUPPORTED                   (1 << 8)
+#       define ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST_SUPPORTED      (1 << 12)
 /* supported functions vector */
 #       define ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED               (1 << 0)
 #       define ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED            (1 << 1)
-#       define ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED              (1 << 2)
-#       define ATIF_GET_LID_STATE_SUPPORTED                       (1 << 3)
-#       define ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED           (1 << 4)
-#       define ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED             (1 << 5)
-#       define ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED  (1 << 6)
-#       define ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED    (1 << 7)
 #       define ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED     (1 << 12)
-#       define ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED           (1 << 14)
+#       define ATIF_QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS_SUPPORTED (1 << 15)
+#       define ATIF_READY_TO_UNDOCK_NOTIFICATION_SUPPORTED        (1 << 16)
 #       define ATIF_GET_EXTERNAL_GPU_INFORMATION_SUPPORTED        (1 << 20)
 #define ATIF_FUNCTION_GET_SYSTEM_PARAMETERS                        0x1
 /* ARG0: ATIF_FUNCTION_GET_SYSTEM_PARAMETERS
@@ -170,6 +186,10 @@ struct atcs_pref_req_output {
  * n (0xd0-0xd9) is specified in notify command code.
  * bit 2:
  * 1 - lid changes not reported though int10
+ * bit 3:
+ * 1 - system bios controls overclocking
+ * bit 4:
+ * 1 - enable overclocking
  */
 #define ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS                     0x2
 /* ARG0: ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS
@@ -177,28 +197,23 @@ struct atcs_pref_req_output {
  * OUTPUT:
  * WORD  - structure size in bytes (includes size field)
  * DWORD - pending sbios requests
- * BYTE  - panel expansion mode
+ * BYTE  - reserved (all zeroes)
  * BYTE  - thermal state: target gfx controller
  * BYTE  - thermal state: state id (0: exit state, non-0: state)
  * BYTE  - forced power state: target gfx controller
- * BYTE  - forced power state: state id
+ * BYTE  - forced power state: state id (0: forced state, non-0: state)
  * BYTE  - system power source
  * BYTE  - panel backlight level (0-255)
+ * BYTE  - GPU package power limit: target gfx controller
+ * DWORD - GPU package power limit: value (24:8 fractional format, Watts)
  */
 /* pending sbios requests */
-#       define ATIF_DISPLAY_SWITCH_REQUEST                         (1 << 0)
-#       define ATIF_EXPANSION_MODE_CHANGE_REQUEST                  (1 << 1)
 #       define ATIF_THERMAL_STATE_CHANGE_REQUEST                   (1 << 2)
 #       define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST              (1 << 3)
 #       define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST             (1 << 4)
-#       define ATIF_DISPLAY_CONF_CHANGE_REQUEST                    (1 << 5)
-#       define ATIF_PX_GFX_SWITCH_REQUEST                          (1 << 6)
 #       define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST                (1 << 7)
 #       define ATIF_DGPU_DISPLAY_EVENT                             (1 << 8)
-/* panel expansion mode */
-#       define ATIF_PANEL_EXPANSION_DISABLE                        0
-#       define ATIF_PANEL_EXPANSION_FULL                           1
-#       define ATIF_PANEL_EXPANSION_ASPECT                         2
+#       define ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST                (1 << 12)
 /* target gfx controller */
 #       define ATIF_TARGET_GFX_SINGLE                              0
 #       define ATIF_TARGET_GFX_PX_IGPU                             1
@@ -208,76 +223,6 @@ struct atcs_pref_req_output {
 #       define ATIF_POWER_SOURCE_DC                                2
 #       define ATIF_POWER_SOURCE_RESTRICTED_AC_1                   3
 #       define ATIF_POWER_SOURCE_RESTRICTED_AC_2                   4
-#define ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS                       0x3
-/* ARG0: ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS
- * ARG1:
- * WORD  - structure size in bytes (includes size field)
- * WORD  - selected displays
- * WORD  - connected displays
- * OUTPUT:
- * WORD  - structure size in bytes (includes size field)
- * WORD  - selected displays
- */
-#       define ATIF_LCD1                                           (1 << 0)
-#       define ATIF_CRT1                                           (1 << 1)
-#       define ATIF_TV                                             (1 << 2)
-#       define ATIF_DFP1                                           (1 << 3)
-#       define ATIF_CRT2                                           (1 << 4)
-#       define ATIF_LCD2                                           (1 << 5)
-#       define ATIF_DFP2                                           (1 << 7)
-#       define ATIF_CV                                             (1 << 8)
-#       define ATIF_DFP3                                           (1 << 9)
-#       define ATIF_DFP4                                           (1 << 10)
-#       define ATIF_DFP5                                           (1 << 11)
-#       define ATIF_DFP6                                           (1 << 12)
-#define ATIF_FUNCTION_GET_LID_STATE                                0x4
-/* ARG0: ATIF_FUNCTION_GET_LID_STATE
- * ARG1: none
- * OUTPUT:
- * WORD  - structure size in bytes (includes size field)
- * BYTE  - lid state (0: open, 1: closed)
- *
- * GET_LID_STATE only works at boot and resume, for general lid
- * status, use the kernel provided status
- */
-#define ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS                    0x5
-/* ARG0: ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS
- * ARG1: none
- * OUTPUT:
- * WORD  - structure size in bytes (includes size field)
- * BYTE  - 0
- * BYTE  - TV standard
- */
-#       define ATIF_TV_STD_NTSC                                    0
-#       define ATIF_TV_STD_PAL                                     1
-#       define ATIF_TV_STD_PALM                                    2
-#       define ATIF_TV_STD_PAL60                                   3
-#       define ATIF_TV_STD_NTSCJ                                   4
-#       define ATIF_TV_STD_PALCN                                   5
-#       define ATIF_TV_STD_PALN                                    6
-#       define ATIF_TV_STD_SCART_RGB                               9
-#define ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS                      0x6
-/* ARG0: ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS
- * ARG1:
- * WORD  - structure size in bytes (includes size field)
- * BYTE  - 0
- * BYTE  - TV standard
- * OUTPUT: none
- */
-#define ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS           0x7
-/* ARG0: ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS
- * ARG1: none
- * OUTPUT:
- * WORD  - structure size in bytes (includes size field)
- * BYTE  - panel expansion mode
- */
-#define ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS             0x8
-/* ARG0: ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS
- * ARG1:
- * WORD  - structure size in bytes (includes size field)
- * BYTE  - panel expansion mode
- * OUTPUT: none
- */
 #define ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION              0xD
 /* ARG0: ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION
  * ARG1:
@@ -286,21 +231,43 @@ struct atcs_pref_req_output {
  * BYTE  - current temperature (degress Celsius)
  * OUTPUT: none
  */
-#define ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES                    0xF
-/* ARG0: ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES
- * ARG1: none
+#define ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS    0x10
+/* ARG0: ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS
+ * ARG1:
+ * WORD  - structure size in bytes (includes size field)
+ * BYTE  - requested display
  * OUTPUT:
- * WORD  - number of gfx devices
- * WORD  - device structure size in bytes (excludes device size field)
- * DWORD - flags         \
- * WORD  - bus number     } repeated structure
- * WORD  - device number /
+ * WORD  - structure size in bytes (includes size field)
+ * WORD  - flags (currently all 16 bits are reserved)
+ * BYTE  - error code (on failure, disregard all below fields)
+ * BYTE  - AC level (default brightness in percent when machine has full power)
+ * BYTE  - DC level (default brightness in percent when machine is on battery)
+ * BYTE  - min input signal, in range 0-255, corresponding to 0% backlight
+ * BYTE  - max input signal, in range 0-255, corresponding to 100% backlight
+ * BYTE  - number of reported data points
+ * BYTE  - luminance level in percent  \ repeated structure
+ * BYTE  - input signal in range 0-255 / does not have entries for 0% and 100%
+ */
+/* requested display */
+#       define ATIF_QBTC_REQUEST_LCD1                              0
+#       define ATIF_QBTC_REQUEST_CRT1                              1
+#       define ATIF_QBTC_REQUEST_DFP1                              3
+#       define ATIF_QBTC_REQUEST_CRT2                              4
+#       define ATIF_QBTC_REQUEST_LCD2                              5
+#       define ATIF_QBTC_REQUEST_DFP2                              7
+#       define ATIF_QBTC_REQUEST_DFP3                              9
+#       define ATIF_QBTC_REQUEST_DFP4                              10
+#       define ATIF_QBTC_REQUEST_DFP5                              11
+#       define ATIF_QBTC_REQUEST_DFP6                              12
+/* error code */
+#       define ATIF_QBTC_ERROR_CODE_SUCCESS                        0
+#       define ATIF_QBTC_ERROR_CODE_FAILURE                        1
+#       define ATIF_QBTC_ERROR_CODE_DEVICE_NOT_SUPPORTED           2
+#define ATIF_FUNCTION_READY_TO_UNDOCK_NOTIFICATION                 0x11
+/* ARG0: ATIF_FUNCTION_READY_TO_UNDOCK_NOTIFICATION
+ * ARG1: none
+ * OUTPUT: none
  */
-/* flags */
-#       define ATIF_PX_REMOVABLE_GRAPHICS_DEVICE                   (1 << 0)
-#       define ATIF_XGP_PORT                                       (1 << 1)
-#       define ATIF_VGA_ENABLED_GRAPHICS_DEVICE                    (1 << 2)
-#       define ATIF_XGP_PORT_IN_DOCK                               (1 << 3)
 #define ATIF_FUNCTION_GET_EXTERNAL_GPU_INFORMATION                 0x15
 /* ARG0: ATIF_FUNCTION_GET_EXTERNAL_GPU_INFORMATION
  * ARG1: none
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h
new file mode 100644 (file)
index 0000000..8f51587
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _mmhub_9_4_0_OFFSET_HEADER
+#define _mmhub_9_4_0_OFFSET_HEADER
+
+
+// addressBlock: mmhub_utcl2_vmsharedpfdec
+// base address: 0x6a040
+#define mmMC_VM_XGMI_LFB_CNTL                                                                          0x0823
+#define mmMC_VM_XGMI_LFB_CNTL_BASE_IDX                                                                 0
+#define mmMC_VM_XGMI_LFB_SIZE                                                                          0x0824
+#define mmMC_VM_XGMI_LFB_SIZE_BASE_IDX                                                                 0
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h
new file mode 100644 (file)
index 0000000..0a6b072
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _mmhub_9_4_0_SH_MASK_HEADER
+#define _mmhub_9_4_0_SH_MASK_HEADER
+
+
+// addressBlock: mmhub_utcl2_vmsharedpfdec
+//MC_VM_XGMI_LFB_CNTL
+#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION__SHIFT                                                             0x0
+#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION__SHIFT                                                             0x4
+#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION_MASK                                                               0x00000007L
+#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION_MASK                                                               0x00000070L
+//MC_VM_XGMI_LFB_SIZE
+#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE__SHIFT                                                               0x0
+#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE_MASK                                                                 0x0000FFFFL
+
+#endif
index 64ecffd5212663c4d1ba9c90181f7df320289db8..8154d67388ccef99185431ce8d04b7b16af59762 100644 (file)
@@ -188,8 +188,8 @@ struct tile_config {
  */
 #define ALLOC_MEM_FLAGS_VRAM           (1 << 0)
 #define ALLOC_MEM_FLAGS_GTT            (1 << 1)
-#define ALLOC_MEM_FLAGS_USERPTR                (1 << 2) /* TODO */
-#define ALLOC_MEM_FLAGS_DOORBELL       (1 << 3) /* TODO */
+#define ALLOC_MEM_FLAGS_USERPTR                (1 << 2)
+#define ALLOC_MEM_FLAGS_DOORBELL       (1 << 3)
 
 /*
  * Allocation flags attributes/access options.
@@ -205,20 +205,6 @@ struct tile_config {
 /**
  * struct kfd2kgd_calls
  *
- * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
- * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
- *
- * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
- *
- * @get_local_mem_info: Retrieves information about GPU local memory
- *
- * @get_gpu_clock_counter: Retrieves GPU clock counter
- *
- * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz
- *
- * @alloc_pasid: Allocate a PASID
- * @free_pasid: Free a PASID
- *
  * @program_sh_mem_settings: A function that should initiate the memory
  * properties such as main aperture memory type (cache / non cached) and
  * secondary aperture base address, size and memory type.
@@ -255,64 +241,16 @@ struct tile_config {
  *
  * @get_tile_config: Returns GPU-specific tiling mode information
  *
- * @get_cu_info: Retrieves activated cu info
- *
- * @get_vram_usage: Returns current VRAM usage
- *
- * @create_process_vm: Create a VM address space for a given process and GPU
- *
- * @destroy_process_vm: Destroy a VM
- *
- * @get_process_page_dir: Get physical address of a VM page directory
- *
  * @set_vm_context_page_table_base: Program page table base for a VMID
  *
- * @alloc_memory_of_gpu: Allocate GPUVM memory
- *
- * @free_memory_of_gpu: Free GPUVM memory
- *
- * @map_memory_to_gpu: Map GPUVM memory into a specific VM address
- * space. Allocates and updates page tables and page directories as
- * needed. This function may return before all page table updates have
- * completed. This allows multiple map operations (on multiple GPUs)
- * to happen concurrently. Use sync_memory to synchronize with all
- * pending updates.
- *
- * @unmap_memor_to_gpu: Unmap GPUVM memory from a specific VM address space
- *
- * @sync_memory: Wait for pending page table updates to complete
- *
- * @map_gtt_bo_to_kernel: Map a GTT BO for kernel access
- * Pins the BO, maps it to kernel address space. Such BOs are never evicted.
- * The kernel virtual address remains valid until the BO is freed.
- *
- * @restore_process_bos: Restore all BOs that belong to the
- * process. This is intended for restoring memory mappings after a TTM
- * eviction.
- *
  * @invalidate_tlbs: Invalidate TLBs for a specific PASID
  *
  * @invalidate_tlbs_vmid: Invalidate TLBs for a specific VMID
  *
- * @submit_ib: Submits an IB to the engine specified by inserting the
- * IB to the corresponding ring (ring type). The IB is executed with the
- * specified VMID in a user mode context.
- *
- * @get_vm_fault_info: Return information about a recent VM fault on
- * GFXv7 and v8. If multiple VM faults occurred since the last call of
- * this function, it will return information about the first of those
- * faults. On GFXv9 VM fault information is fully contained in the IH
- * packet and this function is not needed.
- *
  * @read_vmid_from_vmfault_reg: On Hawaii the VMID is not set in the
  * IH ring entry. This function allows the KFD ISR to get the VMID
  * from the fault status register as early as possible.
  *
- * @gpu_recover: let kgd reset gpu after kfd detect CPC hang
- *
- * @set_compute_idle: Indicates that compute is idle on a device. This
- * can be used to change power profiles depending on compute activity.
- *
  * @get_hive_id: Returns hive id of current  device,  0 if xgmi is not enabled
  *
  * This structure contains function pointers to services that the kgd driver
@@ -320,21 +258,6 @@ struct tile_config {
  *
  */
 struct kfd2kgd_calls {
-       int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
-                                       void **mem_obj, uint64_t *gpu_addr,
-                                       void **cpu_ptr, bool mqd_gfx9);
-
-       void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
-
-       void (*get_local_mem_info)(struct kgd_dev *kgd,
-                       struct kfd_local_mem_info *mem_info);
-       uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
-
-       uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd);
-
-       int (*alloc_pasid)(unsigned int bits);
-       void (*free_pasid)(unsigned int pasid);
-
        /* Register access functions */
        void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid,
                        uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
@@ -398,49 +321,11 @@ struct kfd2kgd_calls {
                                uint64_t va, uint32_t vmid);
        int (*get_tile_config)(struct kgd_dev *kgd, struct tile_config *config);
 
-       void (*get_cu_info)(struct kgd_dev *kgd,
-                       struct kfd_cu_info *cu_info);
-       uint64_t (*get_vram_usage)(struct kgd_dev *kgd);
-
-       int (*create_process_vm)(struct kgd_dev *kgd, unsigned int pasid, void **vm,
-                       void **process_info, struct dma_fence **ef);
-       int (*acquire_process_vm)(struct kgd_dev *kgd, struct file *filp,
-                       unsigned int pasid, void **vm, void **process_info,
-                       struct dma_fence **ef);
-       void (*destroy_process_vm)(struct kgd_dev *kgd, void *vm);
-       void (*release_process_vm)(struct kgd_dev *kgd, void *vm);
-       uint64_t (*get_process_page_dir)(void *vm);
        void (*set_vm_context_page_table_base)(struct kgd_dev *kgd,
                        uint32_t vmid, uint64_t page_table_base);
-       int (*alloc_memory_of_gpu)(struct kgd_dev *kgd, uint64_t va,
-                       uint64_t size, void *vm,
-                       struct kgd_mem **mem, uint64_t *offset,
-                       uint32_t flags);
-       int (*free_memory_of_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem);
-       int (*map_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem,
-                       void *vm);
-       int (*unmap_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem,
-                       void *vm);
-       int (*sync_memory)(struct kgd_dev *kgd, struct kgd_mem *mem, bool intr);
-       int (*map_gtt_bo_to_kernel)(struct kgd_dev *kgd, struct kgd_mem *mem,
-                       void **kptr, uint64_t *size);
-       int (*restore_process_bos)(void *process_info, struct dma_fence **ef);
-
        int (*invalidate_tlbs)(struct kgd_dev *kgd, uint16_t pasid);
        int (*invalidate_tlbs_vmid)(struct kgd_dev *kgd, uint16_t vmid);
-
-       int (*submit_ib)(struct kgd_dev *kgd, enum kgd_engine_type engine,
-                       uint32_t vmid, uint64_t gpu_addr,
-                       uint32_t *ib_cmd, uint32_t ib_len);
-
-       int (*get_vm_fault_info)(struct kgd_dev *kgd,
-                       struct kfd_vm_fault_info *info);
        uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd);
-
-       void (*gpu_recover)(struct kgd_dev *kgd);
-
-       void (*set_compute_idle)(struct kgd_dev *kgd, bool idle);
-
        uint64_t (*get_hive_id)(struct kgd_dev *kgd);
 
 };
index 980e696989b13444b31e25c5debafb1e571f9323..1479ea1dc3e7166fe96c7e759bf06c33aaba2683 100644 (file)
@@ -276,6 +276,10 @@ struct amd_pm_funcs {
                struct amd_pp_simple_clock_info *clocks);
        int (*notify_smu_enable_pwe)(void *handle);
        int (*enable_mgpu_fan_boost)(void *handle);
+       int (*set_active_display_count)(void *handle, uint32_t count);
+       int (*set_hard_min_dcefclk_by_freq)(void *handle, uint32_t clock);
+       int (*set_hard_min_fclk_by_freq)(void *handle, uint32_t clock);
+       int (*set_min_deep_sleep_dcefclk)(void *handle, uint32_t clock);
 };
 
 #endif
index d6aa1d414320bf1d63bb84ffb490ac8e8b6417e6..9bc27f468d5be578fe4f014d1439698703eb4972 100644 (file)
@@ -300,7 +300,7 @@ static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
@@ -387,7 +387,7 @@ static uint32_t pp_dpm_get_sclk(void *handle, bool low)
                return 0;
 
        if (hwmgr->hwmgr_func->get_sclk == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -405,7 +405,7 @@ static uint32_t pp_dpm_get_mclk(void *handle, bool low)
                return 0;
 
        if (hwmgr->hwmgr_func->get_mclk == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -422,7 +422,7 @@ static void pp_dpm_powergate_vce(void *handle, bool gate)
                return;
 
        if (hwmgr->hwmgr_func->powergate_vce == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -438,7 +438,7 @@ static void pp_dpm_powergate_uvd(void *handle, bool gate)
                return;
 
        if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -505,7 +505,7 @@ static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
                return;
 
        if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -522,7 +522,7 @@ static uint32_t pp_dpm_get_fan_control_mode(void *handle)
                return 0;
 
        if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -540,7 +540,7 @@ static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -558,7 +558,7 @@ static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
@@ -594,7 +594,7 @@ static int pp_dpm_set_fan_speed_rpm(void *handle, uint32_t rpm)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_fan_speed_rpm == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -720,12 +720,12 @@ static int pp_dpm_force_clock_level(void *handle,
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->force_clock_level == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
        if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
-               pr_info("force clock level is for dpm manual mode only.\n");
+               pr_debug("force clock level is for dpm manual mode only.\n");
                return -EINVAL;
        }
 
@@ -745,7 +745,7 @@ static int pp_dpm_print_clock_levels(void *handle,
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -763,7 +763,7 @@ static int pp_dpm_get_sclk_od(void *handle)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -781,7 +781,7 @@ static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
@@ -800,7 +800,7 @@ static int pp_dpm_get_mclk_od(void *handle)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -818,7 +818,7 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
        mutex_lock(&hwmgr->smu_lock);
@@ -878,7 +878,7 @@ static int pp_get_power_profile_mode(void *handle, char *buf)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return snprintf(buf, PAGE_SIZE, "\n");
        }
 
@@ -894,12 +894,12 @@ static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size)
                return ret;
 
        if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return ret;
        }
 
        if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
-               pr_info("power profile setting is for manual dpm mode only.\n");
+               pr_debug("power profile setting is for manual dpm mode only.\n");
                return ret;
        }
 
@@ -917,7 +917,7 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return -EINVAL;
        }
 
@@ -935,7 +935,7 @@ static int pp_dpm_switch_power_profile(void *handle,
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return -EINVAL;
        }
 
@@ -972,7 +972,7 @@ static int pp_set_power_limit(void *handle, uint32_t limit)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->set_power_limit == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return -EINVAL;
        }
 
@@ -1072,7 +1072,7 @@ static int pp_get_current_clocks(void *handle,
                                        &hw_clocks, PHM_PerformanceLevelDesignation_Activity);
 
        if (ret) {
-               pr_info("Error in phm_get_clock_info \n");
+               pr_debug("Error in phm_get_clock_info \n");
                mutex_unlock(&hwmgr->smu_lock);
                return -EINVAL;
        }
@@ -1212,7 +1212,7 @@ static int pp_dpm_powergate_mmhub(void *handle)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->powergate_mmhub == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
@@ -1227,7 +1227,7 @@ static int pp_dpm_powergate_gfx(void *handle, bool gate)
                return 0;
 
        if (hwmgr->hwmgr_func->powergate_gfx == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return 0;
        }
 
@@ -1242,7 +1242,7 @@ static void pp_dpm_powergate_acp(void *handle, bool gate)
                return;
 
        if (hwmgr->hwmgr_func->powergate_acp == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return;
        }
 
@@ -1257,7 +1257,7 @@ static void pp_dpm_powergate_sdma(void *handle, bool gate)
                return;
 
        if (hwmgr->hwmgr_func->powergate_sdma == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return;
        }
 
@@ -1303,7 +1303,7 @@ static int pp_notify_smu_enable_pwe(void *handle)
                return -EINVAL;
 
        if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
                return -EINVAL;;
        }
 
@@ -1332,6 +1332,78 @@ static int pp_enable_mgpu_fan_boost(void *handle)
        return 0;
 }
 
+static int pp_set_min_deep_sleep_dcefclk(void *handle, uint32_t clock)
+{
+       struct pp_hwmgr *hwmgr = handle;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk == NULL) {
+               pr_debug("%s was not implemented.\n", __func__);
+               return -EINVAL;;
+       }
+
+       mutex_lock(&hwmgr->smu_lock);
+       hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, clock);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return 0;
+}
+
+static int pp_set_hard_min_dcefclk_by_freq(void *handle, uint32_t clock)
+{
+       struct pp_hwmgr *hwmgr = handle;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq == NULL) {
+               pr_debug("%s was not implemented.\n", __func__);
+               return -EINVAL;;
+       }
+
+       mutex_lock(&hwmgr->smu_lock);
+       hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq(hwmgr, clock);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return 0;
+}
+
+static int pp_set_hard_min_fclk_by_freq(void *handle, uint32_t clock)
+{
+       struct pp_hwmgr *hwmgr = handle;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->set_hard_min_fclk_by_freq == NULL) {
+               pr_debug("%s was not implemented.\n", __func__);
+               return -EINVAL;;
+       }
+
+       mutex_lock(&hwmgr->smu_lock);
+       hwmgr->hwmgr_func->set_hard_min_fclk_by_freq(hwmgr, clock);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return 0;
+}
+
+static int pp_set_active_display_count(void *handle, uint32_t count)
+{
+       struct pp_hwmgr *hwmgr = handle;
+       int ret = 0;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       mutex_lock(&hwmgr->smu_lock);
+       ret = phm_set_active_display_count(hwmgr, count);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return ret;
+}
+
 static const struct amd_pm_funcs pp_dpm_funcs = {
        .load_firmware = pp_dpm_load_fw,
        .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
@@ -1378,4 +1450,8 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
        .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks,
        .notify_smu_enable_pwe = pp_notify_smu_enable_pwe,
        .enable_mgpu_fan_boost = pp_enable_mgpu_fan_boost,
+       .set_active_display_count = pp_set_active_display_count,
+       .set_min_deep_sleep_dcefclk = pp_set_min_deep_sleep_dcefclk,
+       .set_hard_min_dcefclk_by_freq = pp_set_hard_min_dcefclk_by_freq,
+       .set_hard_min_fclk_by_freq = pp_set_hard_min_fclk_by_freq,
 };
index a2a7e0e94aa6b704b015122d413c06d6045b1d00..1f92a9f4c9e3414e756ed181947ac97f5a9f9611 100644 (file)
@@ -288,8 +288,8 @@ int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
        if (display_config == NULL)
                return -EINVAL;
 
-       if (NULL != hwmgr->hwmgr_func->set_deep_sleep_dcefclk)
-               hwmgr->hwmgr_func->set_deep_sleep_dcefclk(hwmgr, display_config->min_dcef_deep_sleep_set_clk);
+       if (NULL != hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk)
+               hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, display_config->min_dcef_deep_sleep_set_clk);
 
        for (index = 0; index < display_config->num_path_including_non_display; index++) {
                if (display_config->displays[index].controller_id != 0)
@@ -480,3 +480,44 @@ int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr)
 
        return hwmgr->hwmgr_func->disable_smc_firmware_ctf(hwmgr);
 }
+
+int phm_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
+{
+       PHM_FUNC_CHECK(hwmgr);
+
+       if (!hwmgr->hwmgr_func->set_active_display_count)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->set_active_display_count(hwmgr, count);
+}
+
+int phm_set_min_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       PHM_FUNC_CHECK(hwmgr);
+
+       if (!hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, clock);
+}
+
+int phm_set_hard_min_dcefclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       PHM_FUNC_CHECK(hwmgr);
+
+       if (!hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->set_hard_min_dcefclk_by_freq(hwmgr, clock);
+}
+
+int phm_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       PHM_FUNC_CHECK(hwmgr);
+
+       if (!hwmgr->hwmgr_func->set_hard_min_fclk_by_freq)
+               return -EINVAL;
+
+       return hwmgr->hwmgr_func->set_hard_min_fclk_by_freq(hwmgr, clock);
+}
+
index dd18cb710391a1f2caa304f81f487743bc5a2db4..f95c5f50eb0f0cfda70912aaa6d1805d93306976 100644 (file)
@@ -216,12 +216,12 @@ static inline uint32_t convert_10k_to_mhz(uint32_t clock)
        return (clock + 99) / 100;
 }
 
-static int smu10_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock)
+static int smu10_set_min_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock)
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
        if (smu10_data->need_min_deep_sleep_dcefclk &&
-           smu10_data->deep_sleep_dcefclk != convert_10k_to_mhz(clock)) {
+               smu10_data->deep_sleep_dcefclk != convert_10k_to_mhz(clock)) {
                smu10_data->deep_sleep_dcefclk = convert_10k_to_mhz(clock);
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SetMinDeepSleepDcefclk,
@@ -230,6 +230,34 @@ static int smu10_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock)
        return 0;
 }
 
+static int smu10_set_hard_min_dcefclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
+
+       if (smu10_data->dcf_actual_hard_min_freq &&
+               smu10_data->dcf_actual_hard_min_freq != convert_10k_to_mhz(clock)) {
+               smu10_data->dcf_actual_hard_min_freq = convert_10k_to_mhz(clock);
+               smum_send_msg_to_smc_with_parameter(hwmgr,
+                                       PPSMC_MSG_SetHardMinDcefclkByFreq,
+                                       smu10_data->dcf_actual_hard_min_freq);
+       }
+       return 0;
+}
+
+static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t clock)
+{
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
+
+       if (smu10_data->f_actual_hard_min_freq &&
+               smu10_data->f_actual_hard_min_freq != convert_10k_to_mhz(clock)) {
+               smu10_data->f_actual_hard_min_freq = convert_10k_to_mhz(clock);
+               smum_send_msg_to_smc_with_parameter(hwmgr,
+                                       PPSMC_MSG_SetHardMinFclkByFreq,
+                                       smu10_data->f_actual_hard_min_freq);
+       }
+       return 0;
+}
+
 static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
@@ -1206,7 +1234,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
        .get_max_high_clocks = smu10_get_max_high_clocks,
        .read_sensor = smu10_read_sensor,
        .set_active_display_count = smu10_set_active_display_count,
-       .set_deep_sleep_dcefclk = smu10_set_deep_sleep_dcefclk,
+       .set_min_deep_sleep_dcefclk = smu10_set_min_deep_sleep_dcefclk,
        .dynamic_state_management_enable = smu10_enable_dpm_tasks,
        .power_off_asic = smu10_power_off_asic,
        .asic_setup = smu10_setup_asic_task,
@@ -1217,6 +1245,8 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
        .display_clock_voltage_request = smu10_display_clock_voltage_request,
        .powergate_gfx = smu10_gfx_off_control,
        .powergate_sdma = smu10_powergate_sdma,
+       .set_hard_min_dcefclk_by_freq = smu10_set_hard_min_dcefclk_by_freq,
+       .set_hard_min_fclk_by_freq = smu10_set_hard_min_fclk_by_freq,
 };
 
 int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)
index b61a01f552840d39a0ce7113de3d6e035d84354f..d913904593267439c78824149e40dc64d5d32eb4 100644 (file)
@@ -269,7 +269,7 @@ static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr)
                                        hwmgr->dyn_state.mvdd_dependency_on_mclk);
 
                PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 MVDD table from dependancy table.",
+                               "Failed to retrieve SVI2 MVDD table from dependency table.",
                                return result;);
        }
 
@@ -288,7 +288,7 @@ static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr)
                        result = phm_get_svi2_voltage_table_v0(&(data->vddci_voltage_table),
                                        hwmgr->dyn_state.vddci_dependency_on_mclk);
                PP_ASSERT_WITH_CODE((0 == result),
-                               "Failed to retrieve SVI2 VDDCI table from dependancy table.",
+                               "Failed to retrieve SVI2 VDDCI table from dependency table.",
                                return result);
        }
 
@@ -317,7 +317,7 @@ static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr)
                                table_info->vddc_lookup_table);
 
                PP_ASSERT_WITH_CODE((0 == result),
-                       "Failed to retrieve SVI2 VDDC table from dependancy table.", return result;);
+                       "Failed to retrieve SVI2 VDDC table from dependency table.", return result;);
        }
 
        tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDC);
@@ -2859,7 +2859,10 @@ static int smu7_vblank_too_short(struct pp_hwmgr *hwmgr,
        case CHIP_POLARIS10:
        case CHIP_POLARIS11:
        case CHIP_POLARIS12:
-               switch_limit_us = data->is_memory_gddr5 ? 190 : 150;
+               if (hwmgr->is_kicker)
+                       switch_limit_us = data->is_memory_gddr5 ? 450 : 150;
+               else
+                       switch_limit_us = data->is_memory_gddr5 ? 190 : 150;
                break;
        case CHIP_VEGAM:
                switch_limit_us = 30;
@@ -4223,9 +4226,17 @@ static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr)
        if (tmp & (1 << 23)) {
                data->mem_latency_high = MEM_LATENCY_HIGH;
                data->mem_latency_low = MEM_LATENCY_LOW;
+               if ((hwmgr->chip_id == CHIP_POLARIS10) ||
+                   (hwmgr->chip_id == CHIP_POLARIS11) ||
+                   (hwmgr->chip_id == CHIP_POLARIS12))
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableFFC);
        } else {
                data->mem_latency_high = 330;
                data->mem_latency_low = 330;
+               if ((hwmgr->chip_id == CHIP_POLARIS10) ||
+                   (hwmgr->chip_id == CHIP_POLARIS11) ||
+                   (hwmgr->chip_id == CHIP_POLARIS12))
+                       smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableFFC);
        }
 
        return 0;
index 5e19f5977eb19e551eecad7f72f9966bfbe8c768..d138ddae563d2cfdf6ff9c878a42e971612509fb 100644 (file)
@@ -967,7 +967,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
            PP_CAP(PHM_PlatformCaps_TDRamping) ||
            PP_CAP(PHM_PlatformCaps_TCPRamping)) {
 
-               adev->gfx.rlc.funcs->enter_safe_mode(adev);
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
                mutex_lock(&adev->grbm_idx_mutex);
                value = 0;
                value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
@@ -1014,13 +1014,13 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
                                        "Failed to enable DPM DIDT.", goto error);
                }
                mutex_unlock(&adev->grbm_idx_mutex);
-               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
        }
 
        return 0;
 error:
        mutex_unlock(&adev->grbm_idx_mutex);
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
        return result;
 }
 
@@ -1034,7 +1034,7 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
            PP_CAP(PHM_PlatformCaps_TDRamping) ||
            PP_CAP(PHM_PlatformCaps_TCPRamping)) {
 
-               adev->gfx.rlc.funcs->enter_safe_mode(adev);
+               amdgpu_gfx_rlc_enter_safe_mode(adev);
 
                result = smu7_enable_didt(hwmgr, false);
                PP_ASSERT_WITH_CODE((result == 0),
@@ -1046,12 +1046,12 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
                        PP_ASSERT_WITH_CODE((0 == result),
                                        "Failed to disable DPM DIDT.", goto error);
                }
-               adev->gfx.rlc.funcs->exit_safe_mode(adev);
+               amdgpu_gfx_rlc_exit_safe_mode(adev);
        }
 
        return 0;
 error:
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
        return result;
 }
 
index fef111ddb7363b74beab3be2ecc0e49efd1681f6..553a203ac47c4766f7664d46d972ce254ba3fce0 100644 (file)
@@ -1228,17 +1228,14 @@ static int smu8_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
 
 static int smu8_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
 {
-       if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) {
-               smu8_nbdpm_pstate_enable_disable(hwmgr, true, true);
+       if (PP_CAP(PHM_PlatformCaps_UVDPowerGating))
                return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_UVDPowerOFF);
-       }
        return 0;
 }
 
 static int smu8_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
 {
        if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) {
-               smu8_nbdpm_pstate_enable_disable(hwmgr, false, true);
                return smum_send_msg_to_smc_with_parameter(
                        hwmgr,
                        PPSMC_MSG_UVDPowerON,
@@ -1995,6 +1992,7 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
        .power_state_set = smu8_set_power_state_tasks,
        .dynamic_state_management_disable = smu8_disable_dpm_tasks,
        .notify_cac_buffer_info = smu8_notify_cac_buffer_info,
+       .update_nbdpm_pstate = smu8_nbdpm_pstate_enable_disable,
        .get_thermal_temperature_range = smu8_get_thermal_temperature_range,
 };
 
index 2d88abf97e7b4a69f21581af8bf2a5dda8b3ce1f..6f26cb241ecce5ddbef2c37b248ce3b3b0c59435 100644 (file)
@@ -937,7 +937,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
 
        num_se = adev->gfx.config.max_shader_engines;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (count = 0; count < num_se; count++) {
@@ -962,7 +962,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
 
        vega10_didt_set_mask(hwmgr, true);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        return 0;
 }
@@ -971,11 +971,11 @@ static int vega10_disable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
 {
        struct amdgpu_device *adev = hwmgr->adev;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        vega10_didt_set_mask(hwmgr, false);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        return 0;
 }
@@ -988,7 +988,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
 
        num_se = adev->gfx.config.max_shader_engines;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (count = 0; count < num_se; count++) {
@@ -1007,7 +1007,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
 
        vega10_didt_set_mask(hwmgr, true);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        vega10_program_gc_didt_config_registers(hwmgr, GCDiDtDroopCtrlConfig_vega10);
        if (PP_CAP(PHM_PlatformCaps_GCEDC))
@@ -1024,11 +1024,11 @@ static int vega10_disable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
        struct amdgpu_device *adev = hwmgr->adev;
        uint32_t data;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        vega10_didt_set_mask(hwmgr, false);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        if (PP_CAP(PHM_PlatformCaps_GCEDC)) {
                data = 0x00000000;
@@ -1049,7 +1049,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)
 
        num_se = adev->gfx.config.max_shader_engines;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (count = 0; count < num_se; count++) {
@@ -1070,7 +1070,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)
 
        vega10_didt_set_mask(hwmgr, true);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        return 0;
 }
@@ -1079,11 +1079,11 @@ static int vega10_disable_se_edc_config(struct pp_hwmgr *hwmgr)
 {
        struct amdgpu_device *adev = hwmgr->adev;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        vega10_didt_set_mask(hwmgr, false);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        return 0;
 }
@@ -1097,7 +1097,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
 
        num_se = adev->gfx.config.max_shader_engines;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        vega10_program_gc_didt_config_registers(hwmgr, AvfsPSMResetConfig_vega10);
 
@@ -1118,7 +1118,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
 
        vega10_didt_set_mask(hwmgr, true);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        vega10_program_gc_didt_config_registers(hwmgr, PSMGCEDCDroopCtrlConfig_vega10);
 
@@ -1138,11 +1138,11 @@ static int vega10_disable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
        struct amdgpu_device *adev = hwmgr->adev;
        uint32_t data;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        vega10_didt_set_mask(hwmgr, false);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        if (PP_CAP(PHM_PlatformCaps_GCEDC)) {
                data = 0x00000000;
@@ -1160,7 +1160,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)
        struct amdgpu_device *adev = hwmgr->adev;
        int result;
 
-       adev->gfx.rlc.funcs->enter_safe_mode(adev);
+       amdgpu_gfx_rlc_enter_safe_mode(adev);
 
        mutex_lock(&adev->grbm_idx_mutex);
        WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, 0xE0000000);
@@ -1173,7 +1173,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)
 
        vega10_didt_set_mask(hwmgr, false);
 
-       adev->gfx.rlc.funcs->exit_safe_mode(adev);
+       amdgpu_gfx_rlc_exit_safe_mode(adev);
 
        return 0;
 }
index 3b7fce5d7258eb71f2b8fbfa01c82c7143124ae9..2e99ecf4ab76272e569f1023dae04626d568a959 100644 (file)
@@ -2777,7 +2777,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                for (i = 0; i < clocks.num_levels; i++)
                        size += sprintf(buf + size, "%d: %uMhz %s\n",
                                i, clocks.data[i].clocks_in_khz / 1000,
-                               (clocks.data[i].clocks_in_khz == now) ? "*" : "");
+                               (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
                break;
 
        case PP_MCLK:
@@ -2794,7 +2794,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                for (i = 0; i < clocks.num_levels; i++)
                        size += sprintf(buf + size, "%d: %uMhz %s\n",
                                i, clocks.data[i].clocks_in_khz / 1000,
-                               (clocks.data[i].clocks_in_khz == now) ? "*" : "");
+                               (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
                break;
 
        case PP_PCIE:
@@ -3476,109 +3476,64 @@ static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
 
 static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
        /* init/fini related */
-       .backend_init =
-               vega20_hwmgr_backend_init,
-       .backend_fini =
-               vega20_hwmgr_backend_fini,
-       .asic_setup =
-               vega20_setup_asic_task,
-       .power_off_asic =
-               vega20_power_off_asic,
-       .dynamic_state_management_enable =
-               vega20_enable_dpm_tasks,
-       .dynamic_state_management_disable =
-               vega20_disable_dpm_tasks,
+       .backend_init = vega20_hwmgr_backend_init,
+       .backend_fini = vega20_hwmgr_backend_fini,
+       .asic_setup = vega20_setup_asic_task,
+       .power_off_asic = vega20_power_off_asic,
+       .dynamic_state_management_enable = vega20_enable_dpm_tasks,
+       .dynamic_state_management_disable = vega20_disable_dpm_tasks,
        /* power state related */
-       .apply_clocks_adjust_rules =
-               vega20_apply_clocks_adjust_rules,
-       .pre_display_config_changed =
-               vega20_pre_display_configuration_changed_task,
-       .display_config_changed =
-               vega20_display_configuration_changed_task,
+       .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
+       .pre_display_config_changed = vega20_pre_display_configuration_changed_task,
+       .display_config_changed = vega20_display_configuration_changed_task,
        .check_smc_update_required_for_display_configuration =
                vega20_check_smc_update_required_for_display_configuration,
        .notify_smc_display_config_after_ps_adjustment =
                vega20_notify_smc_display_config_after_ps_adjustment,
        /* export to DAL */
-       .get_sclk =
-               vega20_dpm_get_sclk,
-       .get_mclk =
-               vega20_dpm_get_mclk,
-       .get_dal_power_level =
-               vega20_get_dal_power_level,
-       .get_clock_by_type_with_latency =
-               vega20_get_clock_by_type_with_latency,
-       .get_clock_by_type_with_voltage =
-               vega20_get_clock_by_type_with_voltage,
-       .set_watermarks_for_clocks_ranges =
-               vega20_set_watermarks_for_clocks_ranges,
-       .display_clock_voltage_request =
-               vega20_display_clock_voltage_request,
-       .get_performance_level =
-               vega20_get_performance_level,
+       .get_sclk = vega20_dpm_get_sclk,
+       .get_mclk = vega20_dpm_get_mclk,
+       .get_dal_power_level = vega20_get_dal_power_level,
+       .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
+       .get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
+       .set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
+       .display_clock_voltage_request = vega20_display_clock_voltage_request,
+       .get_performance_level = vega20_get_performance_level,
        /* UMD pstate, profile related */
-       .force_dpm_level =
-               vega20_dpm_force_dpm_level,
-       .get_power_profile_mode =
-               vega20_get_power_profile_mode,
-       .set_power_profile_mode =
-               vega20_set_power_profile_mode,
+       .force_dpm_level = vega20_dpm_force_dpm_level,
+       .get_power_profile_mode = vega20_get_power_profile_mode,
+       .set_power_profile_mode = vega20_set_power_profile_mode,
        /* od related */
-       .set_power_limit =
-               vega20_set_power_limit,
-       .get_sclk_od =
-               vega20_get_sclk_od,
-       .set_sclk_od =
-               vega20_set_sclk_od,
-       .get_mclk_od =
-               vega20_get_mclk_od,
-       .set_mclk_od =
-               vega20_set_mclk_od,
-       .odn_edit_dpm_table =
-               vega20_odn_edit_dpm_table,
+       .set_power_limit = vega20_set_power_limit,
+       .get_sclk_od = vega20_get_sclk_od,
+       .set_sclk_od = vega20_set_sclk_od,
+       .get_mclk_od = vega20_get_mclk_od,
+       .set_mclk_od = vega20_set_mclk_od,
+       .odn_edit_dpm_table = vega20_odn_edit_dpm_table,
        /* for sysfs to retrive/set gfxclk/memclk */
-       .force_clock_level =
-               vega20_force_clock_level,
-       .print_clock_levels =
-               vega20_print_clock_levels,
-       .read_sensor =
-               vega20_read_sensor,
+       .force_clock_level = vega20_force_clock_level,
+       .print_clock_levels = vega20_print_clock_levels,
+       .read_sensor = vega20_read_sensor,
        /* powergate related */
-       .powergate_uvd =
-               vega20_power_gate_uvd,
-       .powergate_vce =
-               vega20_power_gate_vce,
+       .powergate_uvd = vega20_power_gate_uvd,
+       .powergate_vce = vega20_power_gate_vce,
        /* thermal related */
-       .start_thermal_controller =
-               vega20_start_thermal_controller,
-       .stop_thermal_controller =
-               vega20_thermal_stop_thermal_controller,
-       .get_thermal_temperature_range =
-               vega20_get_thermal_temperature_range,
-       .register_irq_handlers =
-               smu9_register_irq_handlers,
-       .disable_smc_firmware_ctf =
-               vega20_thermal_disable_alert,
+       .start_thermal_controller = vega20_start_thermal_controller,
+       .stop_thermal_controller = vega20_thermal_stop_thermal_controller,
+       .get_thermal_temperature_range = vega20_get_thermal_temperature_range,
+       .register_irq_handlers = smu9_register_irq_handlers,
+       .disable_smc_firmware_ctf = vega20_thermal_disable_alert,
        /* fan control related */
-       .get_fan_speed_percent =
-               vega20_fan_ctrl_get_fan_speed_percent,
-       .set_fan_speed_percent =
-               vega20_fan_ctrl_set_fan_speed_percent,
-       .get_fan_speed_info =
-               vega20_fan_ctrl_get_fan_speed_info,
-       .get_fan_speed_rpm =
-               vega20_fan_ctrl_get_fan_speed_rpm,
-       .set_fan_speed_rpm =
-               vega20_fan_ctrl_set_fan_speed_rpm,
-       .get_fan_control_mode =
-               vega20_get_fan_control_mode,
-       .set_fan_control_mode =
-               vega20_set_fan_control_mode,
+       .get_fan_speed_percent = vega20_fan_ctrl_get_fan_speed_percent,
+       .set_fan_speed_percent = vega20_fan_ctrl_set_fan_speed_percent,
+       .get_fan_speed_info = vega20_fan_ctrl_get_fan_speed_info,
+       .get_fan_speed_rpm = vega20_fan_ctrl_get_fan_speed_rpm,
+       .set_fan_speed_rpm = vega20_fan_ctrl_set_fan_speed_rpm,
+       .get_fan_control_mode = vega20_get_fan_control_mode,
+       .set_fan_control_mode = vega20_set_fan_control_mode,
        /* smu memory related */
-       .notify_cac_buffer_info =
-               vega20_notify_cac_buffer_info,
-       .enable_mgpu_fan_boost =
-               vega20_enable_mgpu_fan_boost,
+       .notify_cac_buffer_info = vega20_notify_cac_buffer_info,
+       .enable_mgpu_fan_boost = vega20_enable_mgpu_fan_boost,
 };
 
 int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
index 54fd0125d9cf799b850c3a4904c09c71bb5ba22b..f4dab979a3a120dd87cea6a9e9e59a03b4e06f6e 100644 (file)
@@ -463,5 +463,8 @@ extern int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
 
 extern int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks);
 extern int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr);
+
+extern int phm_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count);
+
 #endif /* _HARDWARE_MANAGER_H_ */
 
index e5a60aa44b5d6be780ca0a19ca5dd6b853f9bcd0..0d298a0409f578b6942a9594362890f381e6f8e2 100644 (file)
@@ -28,7 +28,6 @@
 #include "hardwaremanager.h"
 #include "hwmgr_ppt.h"
 #include "ppatomctrl.h"
-#include "hwmgr_ppt.h"
 #include "power_state.h"
 #include "smu_helper.h"
 
@@ -310,7 +309,7 @@ struct pp_hwmgr_func {
        int (*avfs_control)(struct pp_hwmgr *hwmgr, bool enable);
        int (*disable_smc_firmware_ctf)(struct pp_hwmgr *hwmgr);
        int (*set_active_display_count)(struct pp_hwmgr *hwmgr, uint32_t count);
-       int (*set_deep_sleep_dcefclk)(struct pp_hwmgr *hwmgr, uint32_t clock);
+       int (*set_min_deep_sleep_dcefclk)(struct pp_hwmgr *hwmgr, uint32_t clock);
        int (*start_thermal_controller)(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *range);
        int (*notify_cac_buffer_info)(struct pp_hwmgr *hwmgr,
                                        uint32_t virtual_addr_low,
@@ -318,6 +317,9 @@ struct pp_hwmgr_func {
                                        uint32_t mc_addr_low,
                                        uint32_t mc_addr_hi,
                                        uint32_t size);
+       int (*update_nbdpm_pstate)(struct pp_hwmgr *hwmgr,
+                                       bool enable,
+                                       bool lock);
        int (*get_thermal_temperature_range)(struct pp_hwmgr *hwmgr,
                                        struct PP_TemperatureRange *range);
        int (*get_power_profile_mode)(struct pp_hwmgr *hwmgr, char *buf);
@@ -330,6 +332,8 @@ struct pp_hwmgr_func {
        int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr);
        int (*powergate_sdma)(struct pp_hwmgr *hwmgr, bool bgate);
        int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr);
+       int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
+       int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock);
 };
 
 struct pp_table_func {
index 65eb630bfea339cc75829aea7fc72d2def865e6c..94bf7b649c20b7ae1c1651c23820b8f5fd46929d 100644 (file)
 #include "gmc/gmc_8_1_d.h"
 #include "gmc/gmc_8_1_sh_mask.h"
 
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-
-
 #include "bif/bif_5_0_d.h"
 #include "bif/bif_5_0_sh_mask.h"
 
index c1a99dfe4913f247d20ce8cafab4dd5e0499715f..6e19f4c7cf8f9eb7bbd0e7328a8621c34f45d650 100644 (file)
@@ -397,6 +397,9 @@ typedef uint16_t PPSMC_Result;
 
 #define PPSMC_MSG_SetVBITimeout               ((uint16_t) 0x306)
 
+#define PPSMC_MSG_EnableFFC                   ((uint16_t) 0x307)
+#define PPSMC_MSG_DisableFFC                  ((uint16_t) 0x308)
+
 #define PPSMC_MSG_EnableDpmDidt               ((uint16_t) 0x309)
 #define PPSMC_MSG_DisableDpmDidt              ((uint16_t) 0x30A)
 
index a1e0ac9ae2482a776416aa987e0787e65dd3fe9a..52abca065764ad1ef440328d2392cd16a9d9b2ad 100644 (file)
@@ -44,7 +44,6 @@
 
 #include "smu7_hwmgr.h"
 #include "hardwaremanager.h"
-#include "ppatomctrl.h"
 #include "atombios.h"
 #include "pppcielanes.h"
 
@@ -1529,8 +1528,21 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
        efuse = efuse >> 24;
 
        if (hwmgr->chip_id == CHIP_POLARIS10) {
-               min = 1000;
-               max = 2300;
+               if (hwmgr->is_kicker) {
+                       min = 1200;
+                       max = 2500;
+               } else {
+                       min = 1000;
+                       max = 2300;
+               }
+       } else if (hwmgr->chip_id == CHIP_POLARIS11) {
+               if (hwmgr->is_kicker) {
+                       min = 900;
+                       max = 2100;
+               } else {
+                       min = 1100;
+                       max = 2100;
+               }
        } else {
                min = 1100;
                max = 2100;
@@ -1627,6 +1639,7 @@ static int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
 {
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
        struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend);
+       struct amdgpu_device *adev = hwmgr->adev;
 
        SMU74_Discrete_DpmTable  *table = &(smu_data->smc_state_table);
        int result = 0;
@@ -1646,6 +1659,59 @@ static int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr)
 
        result = atomctrl_get_avfs_information(hwmgr, &avfs_params);
 
+       if (0 == result) {
+               if (((adev->pdev->device == 0x67ef) &&
+                    ((adev->pdev->revision == 0xe0) ||
+                     (adev->pdev->revision == 0xe5))) ||
+                   ((adev->pdev->device == 0x67ff) &&
+                    ((adev->pdev->revision == 0xcf) ||
+                     (adev->pdev->revision == 0xef) ||
+                     (adev->pdev->revision == 0xff)))) {
+                       avfs_params.ucEnableApplyAVFS_CKS_OFF_Voltage = 1;
+                       if ((adev->pdev->device == 0x67ef && adev->pdev->revision == 0xe5) ||
+                           (adev->pdev->device == 0x67ff && adev->pdev->revision == 0xef)) {
+                               if ((avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0 == 0xEA522DD3) &&
+                                   (avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1 == 0x5645A) &&
+                                   (avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2 == 0x33F9E) &&
+                                   (avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1 == 0xFFFFC5CC) &&
+                                   (avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2 == 0x1B1A) &&
+                                   (avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b == 0xFFFFFCED)) {
+                                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0   = 0xF718F1D4;
+                                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1   = 0x323FD;
+                                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2   = 0x1E455;
+                                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = 0;
+                                       avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2 = 0;
+                                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b  = 0x23;
+                               }
+                       }
+               } else if (hwmgr->chip_id == CHIP_POLARIS12 && !hwmgr->is_kicker) {
+                       avfs_params.ucEnableApplyAVFS_CKS_OFF_Voltage = 1;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0   = 0xF6B024DD;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1   = 0x3005E;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2   = 0x18A5F;
+                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = 0x315;
+                       avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2 = 0xFED1;
+                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b  = 0x3B;
+               } else if (((adev->pdev->device == 0x67df) &&
+                           ((adev->pdev->revision == 0xe0) ||
+                            (adev->pdev->revision == 0xe3) ||
+                            (adev->pdev->revision == 0xe4) ||
+                            (adev->pdev->revision == 0xe5) ||
+                            (adev->pdev->revision == 0xe7) ||
+                            (adev->pdev->revision == 0xef))) ||
+                          ((adev->pdev->device == 0x6fdf) &&
+                           ((adev->pdev->revision == 0xef) ||
+                            (adev->pdev->revision == 0xff)))) {
+                       avfs_params.ucEnableApplyAVFS_CKS_OFF_Voltage = 1;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a0   = 0xF843B66B;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a1   = 0x59CB5;
+                       avfs_params.ulGB_VDROOP_TABLE_CKSOFF_a2   = 0xFFFF287F;
+                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = 0;
+                       avfs_params.usAVFSGB_FUSE_TABLE_CKSOFF_m2 = 0xFF23;
+                       avfs_params.ulAVFSGB_FUSE_TABLE_CKSOFF_b  = 0x58;
+               }
+       }
+
        if (0 == result) {
                table->BTCGB_VDROOP_TABLE[0].a0  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a0);
                table->BTCGB_VDROOP_TABLE[0].a1  = PP_HOST_TO_SMC_UL(avfs_params.ulGB_VDROOP_TABLE_CKSON_a1);
index d0eb8ab5014812c490efcdb7c0181687e6371bbd..d111dd4e03d7d2442677a6a4cabf0ab5bc924a36 100644 (file)
@@ -29,7 +29,6 @@
 #include "rv_ppsmc.h"
 #include "smu10_driver_if.h"
 #include "smu10.h"
-#include "ppatomctrl.h"
 #include "pp_debug.h"
 
 
index 09b844ec3eabae4f09f8c0d10ed84d53fcc75ee2..e2787e14a50086831f619427b070029e31dba0c6 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
@@ -61,9 +62,13 @@ static uint32_t smu8_get_argument(struct pp_hwmgr *hwmgr)
                                        mmSMU_MP1_SRBM2P_ARG_0);
 }
 
-static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg)
+/* Send a message to the SMC, and wait for its response.*/
+static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
+                                           uint16_t msg, uint32_t parameter)
 {
        int result = 0;
+       ktime_t t_start;
+       s64 elapsed_us;
 
        if (hwmgr == NULL || hwmgr->device == NULL)
                return -EINVAL;
@@ -74,28 +79,31 @@ static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg)
                /* Read the last message to SMU, to report actual cause */
                uint32_t val = cgs_read_register(hwmgr->device,
                                                 mmSMU_MP1_SRBM2P_MSG_0);
-               pr_err("smu8_send_msg_to_smc_async (0x%04x) failed\n", msg);
-               pr_err("SMU still servicing msg (0x%04x)\n", val);
+               pr_err("%s(0x%04x) aborted; SMU still servicing msg (0x%04x)\n",
+                       __func__, msg, val);
                return result;
        }
+       t_start = ktime_get();
+
+       cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
 
        cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
        cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
 
-       return 0;
+       result = PHM_WAIT_FIELD_UNEQUAL(hwmgr,
+                                       SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+
+       elapsed_us = ktime_us_delta(ktime_get(), t_start);
+
+       WARN(result, "%s(0x%04x, %#x) timed out after %lld us\n",
+                       __func__, msg, parameter, elapsed_us);
+
+       return result;
 }
 
-/* Send a message to the SMC, and wait for its response.*/
 static int smu8_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
 {
-       int result = 0;
-
-       result = smu8_send_msg_to_smc_async(hwmgr, msg);
-       if (result != 0)
-               return result;
-
-       return PHM_WAIT_FIELD_UNEQUAL(hwmgr,
-                                       SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+       return smu8_send_msg_to_smc_with_parameter(hwmgr, msg, 0);
 }
 
 static int smu8_set_smc_sram_address(struct pp_hwmgr *hwmgr,
@@ -135,17 +143,6 @@ static int smu8_write_smc_sram_dword(struct pp_hwmgr *hwmgr,
        return result;
 }
 
-static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
-                                         uint16_t msg, uint32_t parameter)
-{
-       if (hwmgr == NULL || hwmgr->device == NULL)
-               return -EINVAL;
-
-       cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
-
-       return smu8_send_msg_to_smc(hwmgr, msg);
-}
-
 static int smu8_check_fw_load_finish(struct pp_hwmgr *hwmgr,
                                   uint32_t firmware)
 {
@@ -737,6 +734,10 @@ static int smu8_start_smu(struct pp_hwmgr *hwmgr)
 
        cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index);
        hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA);
+       pr_info("smu version %02d.%02d.%02d\n",
+               ((hwmgr->smu_version >> 16) & 0xFF),
+               ((hwmgr->smu_version >> 8) & 0xFF),
+               (hwmgr->smu_version & 0xFF));
        adev->pm.fw_version = hwmgr->smu_version >> 8;
 
        return smu8_request_smu_load_fw(hwmgr);
index 9f71512b25109d53afeba1b3c3a3429b05d0228d..1e69300f6175666b585741a25fb5937fdd3a9203 100644 (file)
@@ -40,7 +40,6 @@
 
 #include "smu7_hwmgr.h"
 #include "hardwaremanager.h"
-#include "ppatomctrl.h"
 #include "atombios.h"
 #include "pppcielanes.h"
 
index e8fcf3ab1d9a9d297287ea15b80493acbe4e40a4..90ef76b19f8a912cf9db34695c6bfc7db7eac274 100644 (file)
@@ -20,7 +20,6 @@
 struct arcpgu_drm_private {
        void __iomem            *regs;
        struct clk              *clk;
-       struct drm_fbdev_cma    *fbdev;
        struct drm_framebuffer  *fb;
        struct drm_crtc         crtc;
        struct drm_plane        *plane;
@@ -43,8 +42,5 @@ static inline u32 arc_pgu_read(struct arcpgu_drm_private *arcpgu,
 int arc_pgu_setup_crtc(struct drm_device *dev);
 int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np);
 int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np);
-struct drm_fbdev_cma *arcpgu_fbdev_cma_init(struct drm_device *dev,
-       unsigned int preferred_bpp, unsigned int num_crtc,
-       unsigned int max_conn_count);
 
 #endif
index 965cda48dc13ceeca19ff677558c08ef537871dc..62f51f70606d73060ea0d0430e305a0ff6b9860f 100644 (file)
@@ -158,8 +158,6 @@ static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = {
        .mode_valid     = arc_pgu_crtc_mode_valid,
-       .mode_set       = drm_helper_crtc_mode_set,
-       .mode_set_base  = drm_helper_crtc_mode_set_base,
        .mode_set_nofb  = arc_pgu_crtc_mode_set_nofb,
        .atomic_begin   = arc_pgu_crtc_atomic_begin,
        .atomic_enable  = arc_pgu_crtc_atomic_enable,
@@ -186,7 +184,6 @@ static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
 
 static void arc_pgu_plane_destroy(struct drm_plane *plane)
 {
-       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 }
 
index f067de4e1e829f0f0b79f5629f417cad30be9d42..206a76abf77133f0e56ac668041ada8b9ea9859b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include "arcpgu.h"
 #include "arcpgu_regs.h"
 
-static void arcpgu_fb_output_poll_changed(struct drm_device *dev)
-{
-       struct arcpgu_drm_private *arcpgu = dev->dev_private;
-
-       drm_fbdev_cma_hotplug_event(arcpgu->fbdev);
-}
-
 static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = {
        .fb_create  = drm_gem_fb_create,
-       .output_poll_changed = arcpgu_fb_output_poll_changed,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
@@ -51,13 +44,6 @@ static void arcpgu_setup_mode_config(struct drm_device *drm)
 
 DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops);
 
-static void arcpgu_lastclose(struct drm_device *drm)
-{
-       struct arcpgu_drm_private *arcpgu = drm->dev_private;
-
-       drm_fbdev_cma_restore_mode(arcpgu->fbdev);
-}
-
 static int arcpgu_load(struct drm_device *drm)
 {
        struct platform_device *pdev = to_platform_device(drm->dev);
@@ -113,27 +99,14 @@ static int arcpgu_load(struct drm_device *drm)
        drm_mode_config_reset(drm);
        drm_kms_helper_poll_init(drm);
 
-       arcpgu->fbdev = drm_fbdev_cma_init(drm, 16,
-                                          drm->mode_config.num_connector);
-       if (IS_ERR(arcpgu->fbdev)) {
-               ret = PTR_ERR(arcpgu->fbdev);
-               arcpgu->fbdev = NULL;
-               return -ENODEV;
-       }
-
        platform_set_drvdata(pdev, drm);
        return 0;
 }
 
 static int arcpgu_unload(struct drm_device *drm)
 {
-       struct arcpgu_drm_private *arcpgu = drm->dev_private;
-
-       if (arcpgu->fbdev) {
-               drm_fbdev_cma_fini(arcpgu->fbdev);
-               arcpgu->fbdev = NULL;
-       }
        drm_kms_helper_poll_fini(drm);
+       drm_atomic_helper_shutdown(drm);
        drm_mode_config_cleanup(drm);
 
        return 0;
@@ -167,7 +140,6 @@ static int arcpgu_debugfs_init(struct drm_minor *minor)
 static struct drm_driver arcpgu_drm_driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
                           DRIVER_ATOMIC,
-       .lastclose = arcpgu_lastclose,
        .name = "arcpgu",
        .desc = "ARC PGU Controller",
        .date = "20160219",
@@ -210,13 +182,15 @@ static int arcpgu_probe(struct platform_device *pdev)
        if (ret)
                goto err_unload;
 
+       drm_fbdev_generic_setup(drm, 16);
+
        return 0;
 
 err_unload:
        arcpgu_unload(drm);
 
 err_unref:
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return ret;
 }
@@ -227,7 +201,7 @@ static int arcpgu_remove(struct platform_device *pdev)
 
        drm_dev_unregister(drm);
        arcpgu_unload(drm);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return 0;
 }
index 7aad7dd80d8c40313d59e992a7cac12b844c7ff6..b9bed1138fa31b5c50610f1226347592104f821b 100644 (file)
@@ -77,12 +77,18 @@ static const struct malidp_format_id malidp500_de_formats[] = {
        { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
        { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
        { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },      \
-       { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
+       { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
+       { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
 
 static const struct malidp_format_id malidp550_de_formats[] = {
        MALIDP_COMMON_FORMATS,
 };
 
+static const struct malidp_format_id malidp650_de_formats[] = {
+       MALIDP_COMMON_FORMATS,
+       { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
+};
+
 static const struct malidp_layer malidp500_layers[] = {
        /* id, base address, fb pointer address base, stride offset,
         *      yuv2rgb matrix offset, mmu control register offset, rotation_features
@@ -630,6 +636,8 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
        case DRM_FORMAT_BGR565:
        case DRM_FORMAT_UYVY:
        case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_X0L0:
+       case DRM_FORMAT_X0L2:
                bytes_per_col = 32;
                break;
        /* 16 lines at 1.5 bytes per pixel */
@@ -905,8 +913,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
                                            MALIDP550_DC_IRQ_SE,
                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
                        },
-                       .pixel_formats = malidp550_de_formats,
-                       .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
+                       .pixel_formats = malidp650_de_formats,
+                       .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
                        .bus_align_bytes = 16,
                },
                .query_hw = malidp650_query_hw,
index 837a24d566757c91f3f5152bb62a938bc04bd2dd..c9a6d3e0cada6860a8c6aab04398de6e4672aedf 100644 (file)
@@ -398,6 +398,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
        struct drm_framebuffer *fb;
        u16 pixel_alpha = state->pixel_blend_mode;
        int i, ret;
+       unsigned int block_w, block_h;
 
        if (!state->crtc || !state->fb)
                return 0;
@@ -413,13 +414,26 @@ static int malidp_de_plane_check(struct drm_plane *plane,
        ms->n_planes = fb->format->num_planes;
        for (i = 0; i < ms->n_planes; i++) {
                u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);
-               if (fb->pitches[i] & (alignment - 1)) {
+
+               if ((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
+                               & (alignment - 1)) {
                        DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
                                      fb->pitches[i], i);
                        return -EINVAL;
                }
        }
 
+       block_w = drm_format_info_block_width(fb->format, 0);
+       block_h = drm_format_info_block_height(fb->format, 0);
+       if (fb->width % block_w || fb->height % block_h) {
+               DRM_DEBUG_KMS("Buffer width/height needs to be a multiple of tile sizes");
+               return -EINVAL;
+       }
+       if ((state->src_x >> 16) % block_w || (state->src_y >> 16) % block_h) {
+               DRM_DEBUG_KMS("Plane src_x/src_y needs to be a multiple of tile sizes");
+               return -EINVAL;
+       }
+
        if ((state->crtc_w > mp->hwdev->max_line_size) ||
            (state->crtc_h > mp->hwdev->max_line_size) ||
            (state->crtc_w < mp->hwdev->min_line_size) ||
@@ -492,10 +506,18 @@ static void malidp_de_set_plane_pitches(struct malidp_plane *mp,
                num_strides = (mp->hwdev->hw->features &
                               MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
 
-       for (i = 0; i < num_strides; ++i)
-               malidp_hw_write(mp->hwdev, pitches[i],
+       /*
+        * The drm convention for pitch is that it needs to cover width * cpp,
+        * but our hardware wants the pitch/stride to cover all rows included
+        * in a tile.
+        */
+       for (i = 0; i < num_strides; ++i) {
+               unsigned int block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
+
+               malidp_hw_write(mp->hwdev, pitches[i] * block_h,
                                mp->layer->base +
                                mp->layer->stride_offset + i * 4);
+       }
 }
 
 static const s16
index e6c4cd3dc50ec7540d65efd61fea71ddb249ecdd..bfc65040dfcbf702c4420f75105cce38be77254a 100644 (file)
@@ -104,8 +104,6 @@ struct ast_private {
        int fb_mtrr;
 
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
        } ttm;
 
index fe354ebf374d236029a3b671fdafe7d0c3af5aa4..c168d62fe8f9742e280fa287d38fe79a8c98554f 100644 (file)
@@ -36,63 +36,6 @@ ast_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct ast_private, ttm.bdev);
 }
 
-static int
-ast_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void
-ast_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int ast_ttm_global_init(struct ast_private *ast)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       global_ref = &ast->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &ast_ttm_mem_global_init;
-       global_ref->release = &ast_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       ast->ttm.bo_global_ref.mem_glob =
-               ast->ttm.mem_global_ref.object;
-       global_ref = &ast->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&ast->ttm.mem_global_ref);
-               return r;
-       }
-       return 0;
-}
-
-static void
-ast_ttm_global_release(struct ast_private *ast)
-{
-       if (ast->ttm.mem_global_ref.release == NULL)
-               return;
-
-       drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&ast->ttm.mem_global_ref);
-       ast->ttm.mem_global_ref.release = NULL;
-}
-
-
 static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct ast_bo *bo;
@@ -232,12 +175,7 @@ int ast_mm_init(struct ast_private *ast)
        struct drm_device *dev = ast->dev;
        struct ttm_bo_device *bdev = &ast->ttm.bdev;
 
-       ret = ast_ttm_global_init(ast);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&ast->ttm.bdev,
-                                ast->ttm.bo_global_ref.ref.object,
                                 &ast_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET,
@@ -268,8 +206,6 @@ void ast_mm_fini(struct ast_private *ast)
 
        ttm_bo_device_release(&ast->ttm.bdev);
 
-       ast_ttm_global_release(ast);
-
        arch_phys_wc_del(ast->fb_mtrr);
        arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
                                pci_resource_len(dev->pdev, 0));
index 9e34bce089d032a6e63c6f34e22f4dfa776c3efa..96f4082671fe79c156f9909d30b38f0dc5b675ff 100644 (file)
@@ -364,9 +364,7 @@ static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
        .mode_valid = atmel_hlcdc_crtc_mode_valid,
-       .mode_set = drm_helper_crtc_mode_set,
        .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
-       .mode_set_base = drm_helper_crtc_mode_set_base,
        .atomic_check = atmel_hlcdc_crtc_atomic_check,
        .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
        .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
index 843cac222e60d8e801aa1ad5c95db75d848d69ff..034a91112098d87848fd26c26749680d49c50b07 100644 (file)
@@ -556,7 +556,6 @@ error:
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = atmel_hlcdc_fb_create,
-       .output_poll_changed = drm_fb_helper_output_poll_changed,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = atmel_hlcdc_dc_atomic_commit,
 };
@@ -658,8 +657,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
        platform_set_drvdata(pdev, dev);
 
-       drm_fb_cma_fbdev_init(dev, 24, 0);
-
        drm_kms_helper_poll_init(dev);
 
        return 0;
@@ -678,7 +675,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
 {
        struct atmel_hlcdc_dc *dc = dev->dev_private;
 
-       drm_fb_cma_fbdev_fini(dev);
        flush_workqueue(dc->wq);
        drm_kms_helper_poll_fini(dev);
        drm_atomic_helper_shutdown(dev);
@@ -727,7 +723,6 @@ static struct drm_driver atmel_hlcdc_dc_driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
                           DRIVER_MODESET | DRIVER_PRIME |
                           DRIVER_ATOMIC,
-       .lastclose = drm_fb_helper_lastclose,
        .irq_handler = atmel_hlcdc_dc_irq_handler,
        .irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
        .irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
@@ -763,19 +758,21 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
 
        ret = atmel_hlcdc_dc_load(ddev);
        if (ret)
-               goto err_unref;
+               goto err_put;
 
        ret = drm_dev_register(ddev, 0);
        if (ret)
                goto err_unload;
 
+       drm_fbdev_generic_setup(ddev, 24);
+
        return 0;
 
 err_unload:
        atmel_hlcdc_dc_unload(ddev);
 
-err_unref:
-       drm_dev_unref(ddev);
+err_put:
+       drm_dev_put(ddev);
 
        return ret;
 }
@@ -786,7 +783,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
 
        drm_dev_unregister(ddev);
        atmel_hlcdc_dc_unload(ddev);
-       drm_dev_unref(ddev);
+       drm_dev_put(ddev);
 
        return 0;
 }
index e7a69077e45adfa15431fdb8bb89d6d00c420541..fb38c8b857b5a26a7e40d2469d00fe3ce02546ed 100644 (file)
@@ -66,6 +66,7 @@ struct bochs_device {
        u16 yres_virtual;
        u32 stride;
        u32 bpp;
+       struct edid *edid;
 
        /* drm */
        struct drm_device  *dev;
@@ -76,8 +77,6 @@ struct bochs_device {
 
        /* ttm */
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
                bool initialized;
        } ttm;
@@ -126,6 +125,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
                      const struct drm_format_info *format);
 void bochs_hw_setbase(struct bochs_device *bochs,
                      int x, int y, u64 addr);
+int bochs_hw_load_edid(struct bochs_device *bochs);
 
 /* bochs_mm.c */
 int bochs_mm_init(struct bochs_device *bochs);
index cacff73a64abf15fc67790521914b75074df9969..c90a0d492fd5973fe53f0430919e0fa8f2883368 100644 (file)
@@ -69,6 +69,35 @@ static void bochs_hw_set_little_endian(struct bochs_device *bochs)
 #define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b)
 #endif
 
+static int bochs_get_edid_block(void *data, u8 *buf,
+                               unsigned int block, size_t len)
+{
+       struct bochs_device *bochs = data;
+       size_t i, start = block * EDID_LENGTH;
+
+       if (start + len > 0x400 /* vga register offset */)
+               return -1;
+
+       for (i = 0; i < len; i++) {
+               buf[i] = readb(bochs->mmio + start + i);
+       }
+       return 0;
+}
+
+int bochs_hw_load_edid(struct bochs_device *bochs)
+{
+       if (!bochs->mmio)
+               return -1;
+
+       kfree(bochs->edid);
+       bochs->edid = drm_do_get_edid(&bochs->connector,
+                                     bochs_get_edid_block, bochs);
+       if (bochs->edid == NULL)
+               return -1;
+
+       return 0;
+}
+
 int bochs_hw_init(struct drm_device *dev)
 {
        struct bochs_device *bochs = dev->dev_private;
@@ -164,6 +193,7 @@ void bochs_hw_fini(struct drm_device *dev)
        if (bochs->fb_map)
                iounmap(bochs->fb_map);
        pci_release_regions(dev->pdev);
+       kfree(bochs->edid);
 }
 
 void bochs_hw_setmode(struct bochs_device *bochs,
index 9bc5b438aefdb342bde508ece4cf46bde7c97592..f87c284dd93d896c720172e66bb9b8ada9c6e2a8 100644 (file)
@@ -213,10 +213,17 @@ static void bochs_encoder_init(struct drm_device *dev)
 
 static int bochs_connector_get_modes(struct drm_connector *connector)
 {
-       int count;
+       struct bochs_device *bochs =
+               container_of(connector, struct bochs_device, connector);
+       int count = 0;
+
+       if (bochs->edid)
+               count = drm_add_edid_modes(connector, bochs->edid);
 
-       count = drm_add_modes_noedid(connector, 8192, 8192);
-       drm_set_preferred_mode(connector, defx, defy);
+       if (!count) {
+               count = drm_add_modes_noedid(connector, 8192, 8192);
+               drm_set_preferred_mode(connector, defx, defy);
+       }
        return count;
 }
 
@@ -271,6 +278,13 @@ static void bochs_connector_init(struct drm_device *dev)
        drm_connector_helper_add(connector,
                                 &bochs_connector_connector_helper_funcs);
        drm_connector_register(connector);
+
+       bochs_hw_load_edid(bochs);
+       if (bochs->edid) {
+               DRM_INFO("Found EDID data blob.\n");
+               drm_connector_attach_edid_property(connector);
+               drm_connector_update_edid_property(connector, bochs->edid);
+       }
 }
 
 
index a61c1ecb2bdc2f1e801f849c4093c7e2d249a1d3..0980411e41bf0d7d61fa173b4199253795aa2966 100644 (file)
@@ -16,61 +16,6 @@ static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct bochs_device, ttm.bdev);
 }
 
-static int bochs_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void bochs_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int bochs_ttm_global_init(struct bochs_device *bochs)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       global_ref = &bochs->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &bochs_ttm_mem_global_init;
-       global_ref->release = &bochs_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       bochs->ttm.bo_global_ref.mem_glob =
-               bochs->ttm.mem_global_ref.object;
-       global_ref = &bochs->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&bochs->ttm.mem_global_ref);
-               return r;
-       }
-
-       return 0;
-}
-
-static void bochs_ttm_global_release(struct bochs_device *bochs)
-{
-       if (bochs->ttm.mem_global_ref.release == NULL)
-               return;
-
-       drm_global_item_unref(&bochs->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&bochs->ttm.mem_global_ref);
-       bochs->ttm.mem_global_ref.release = NULL;
-}
-
-
 static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct bochs_bo *bo;
@@ -208,12 +153,7 @@ int bochs_mm_init(struct bochs_device *bochs)
        struct ttm_bo_device *bdev = &bochs->ttm.bdev;
        int ret;
 
-       ret = bochs_ttm_global_init(bochs);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&bochs->ttm.bdev,
-                                bochs->ttm.bo_global_ref.ref.object,
                                 &bochs_bo_driver,
                                 bochs->dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET,
@@ -240,7 +180,6 @@ void bochs_mm_fini(struct bochs_device *bochs)
                return;
 
        ttm_bo_device_release(&bochs->ttm.bdev);
-       bochs_ttm_global_release(bochs);
        bochs->ttm.initialized = false;
 }
 
@@ -414,7 +353,7 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
                return ret;
 
        ret = drm_gem_handle_create(file, gobj, &handle);
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        if (ret)
                return ret;
 
@@ -454,6 +393,6 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
        bo = gem_to_bochs_bo(obj);
        *offset = bochs_bo_mmap_offset(bo);
 
-       drm_gem_object_unreference_unlocked(obj);
+       drm_gem_object_put_unlocked(obj);
        return 0;
 }
index 9eeb8ef0b1742227fda0e7386def9ab91d8887b0..2fee47b0d50b3af5bee4c3a4501707c81fe74f89 100644 (file)
@@ -95,6 +95,7 @@ config DRM_SII902X
        depends on OF
        select DRM_KMS_HELPER
        select REGMAP_I2C
+       select I2C_MUX
        ---help---
          Silicon Image sii902x bridge chip driver.
 
index 2f21d3b6850b784d60b0d3ad802517635d4b7d63..753e96129ab7a63355d3d50e322780f563e76684 100644 (file)
@@ -1219,12 +1219,12 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
         * plat_data->attch return, that's why we record the connector
         * point after plat attached.
         */
-        if (dp->plat_data->attach) {
-                ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
-                if (ret) {
-                        DRM_ERROR("Failed at platform attch func\n");
-                        return ret;
-                }
+       if (dp->plat_data->attach) {
+               ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
+               if (ret) {
+                       DRM_ERROR("Failed at platform attach func\n");
+                       return ret;
+               }
        }
 
        if (dp->plat_data->panel) {
index e59a135423336bd187f0038956f06ac4574d94dc..bfa902013aa42e06f3eff686d25ba593cd9b2b89 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2018 Renesas Electronics
+ *
  * Copyright (C) 2016 Atmel
  *                   Bo Shen <voice.shen@atmel.com>
  *
@@ -21,6 +23,7 @@
  */
 
 #include <linux/gpio/consumer.h>
+#include <linux/i2c-mux.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -86,8 +89,49 @@ struct sii902x {
        struct drm_bridge bridge;
        struct drm_connector connector;
        struct gpio_desc *reset_gpio;
+       struct i2c_mux_core *i2cmux;
 };
 
+static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val)
+{
+       union i2c_smbus_data data;
+       int ret;
+
+       ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
+                              I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data);
+
+       if (ret < 0)
+               return ret;
+
+       *val = data.byte;
+       return 0;
+}
+
+static int sii902x_write_unlocked(struct i2c_client *i2c, u8 reg, u8 val)
+{
+       union i2c_smbus_data data;
+
+       data.byte = val;
+
+       return __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
+                               I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA,
+                               &data);
+}
+
+static int sii902x_update_bits_unlocked(struct i2c_client *i2c, u8 reg, u8 mask,
+                                       u8 val)
+{
+       int ret;
+       u8 status;
+
+       ret = sii902x_read_unlocked(i2c, reg, &status);
+       if (ret)
+               return ret;
+       status &= ~mask;
+       status |= val & mask;
+       return sii902x_write_unlocked(i2c, reg, status);
+}
+
 static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge)
 {
        return container_of(bridge, struct sii902x, bridge);
@@ -135,41 +179,11 @@ static const struct drm_connector_funcs sii902x_connector_funcs = {
 static int sii902x_get_modes(struct drm_connector *connector)
 {
        struct sii902x *sii902x = connector_to_sii902x(connector);
-       struct regmap *regmap = sii902x->regmap;
        u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-       struct device *dev = &sii902x->i2c->dev;
-       unsigned long timeout;
-       unsigned int retries;
-       unsigned int status;
        struct edid *edid;
-       int num = 0;
-       int ret;
-
-       ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
-                                SII902X_SYS_CTRL_DDC_BUS_REQ,
-                                SII902X_SYS_CTRL_DDC_BUS_REQ);
-       if (ret)
-               return ret;
-
-       timeout = jiffies +
-                 msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
-       do {
-               ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
-               if (ret)
-                       return ret;
-       } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
-                time_before(jiffies, timeout));
+       int num = 0, ret;
 
-       if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
-               dev_err(dev, "failed to acquire the i2c bus\n");
-               return -ETIMEDOUT;
-       }
-
-       ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status);
-       if (ret)
-               return ret;
-
-       edid = drm_get_edid(connector, sii902x->i2c->adapter);
+       edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]);
        drm_connector_update_edid_property(connector, edid);
        if (edid) {
                num = drm_add_edid_modes(connector, edid);
@@ -181,42 +195,6 @@ static int sii902x_get_modes(struct drm_connector *connector)
        if (ret)
                return ret;
 
-       /*
-        * Sometimes the I2C bus can stall after failure to use the
-        * EDID channel. Retry a few times to see if things clear
-        * up, else continue anyway.
-        */
-       retries = 5;
-       do {
-               ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA,
-                                 &status);
-               retries--;
-       } while (ret && retries);
-       if (ret)
-               dev_err(dev, "failed to read status (%d)\n", ret);
-
-       ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
-                                SII902X_SYS_CTRL_DDC_BUS_REQ |
-                                SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
-       if (ret)
-               return ret;
-
-       timeout = jiffies +
-                 msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
-       do {
-               ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
-               if (ret)
-                       return ret;
-       } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
-                          SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
-                time_before(jiffies, timeout));
-
-       if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
-                     SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
-               dev_err(dev, "failed to release the i2c bus\n");
-               return -ETIMEDOUT;
-       }
-
        return num;
 }
 
@@ -366,6 +344,121 @@ static irqreturn_t sii902x_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/*
+ * The purpose of sii902x_i2c_bypass_select is to enable the pass through
+ * mode of the HDMI transmitter. Do not use regmap from within this function,
+ * only use sii902x_*_unlocked functions to read/modify/write registers.
+ * We are holding the parent adapter lock here, keep this in mind before
+ * adding more i2c transactions.
+ *
+ * Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere
+ * in this driver, we need to make sure that we only touch 0x1A[2:1] from
+ * within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that
+ * we leave the remaining bits as we have found them.
+ */
+static int sii902x_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
+{
+       struct sii902x *sii902x = i2c_mux_priv(mux);
+       struct device *dev = &sii902x->i2c->dev;
+       unsigned long timeout;
+       u8 status;
+       int ret;
+
+       ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                          SII902X_SYS_CTRL_DDC_BUS_REQ,
+                                          SII902X_SYS_CTRL_DDC_BUS_REQ);
+       if (ret)
+               return ret;
+
+       timeout = jiffies +
+                 msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
+       do {
+               ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                           &status);
+               if (ret)
+                       return ret;
+       } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
+                time_before(jiffies, timeout));
+
+       if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
+               dev_err(dev, "Failed to acquire the i2c bus\n");
+               return -ETIMEDOUT;
+       }
+
+       return sii902x_write_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                     status);
+}
+
+/*
+ * The purpose of sii902x_i2c_bypass_deselect is to disable the pass through
+ * mode of the HDMI transmitter. Do not use regmap from within this function,
+ * only use sii902x_*_unlocked functions to read/modify/write registers.
+ * We are holding the parent adapter lock here, keep this in mind before
+ * adding more i2c transactions.
+ *
+ * Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere
+ * in this driver, we need to make sure that we only touch 0x1A[2:1] from
+ * within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that
+ * we leave the remaining bits as we have found them.
+ */
+static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
+{
+       struct sii902x *sii902x = i2c_mux_priv(mux);
+       struct device *dev = &sii902x->i2c->dev;
+       unsigned long timeout;
+       unsigned int retries;
+       u8 status;
+       int ret;
+
+       /*
+        * When the HDMI transmitter is in pass through mode, we need an
+        * (undocumented) additional delay between STOP and START conditions
+        * to guarantee the bus won't get stuck.
+        */
+       udelay(30);
+
+       /*
+        * Sometimes the I2C bus can stall after failure to use the
+        * EDID channel. Retry a few times to see if things clear
+        * up, else continue anyway.
+        */
+       retries = 5;
+       do {
+               ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                           &status);
+               retries--;
+       } while (ret && retries);
+       if (ret) {
+               dev_err(dev, "failed to read status (%d)\n", ret);
+               return ret;
+       }
+
+       ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                          SII902X_SYS_CTRL_DDC_BUS_REQ |
+                                          SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
+       if (ret)
+               return ret;
+
+       timeout = jiffies +
+                 msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
+       do {
+               ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA,
+                                           &status);
+               if (ret)
+                       return ret;
+       } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
+                          SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
+                time_before(jiffies, timeout));
+
+       if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
+                     SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
+               dev_err(dev, "failed to release the i2c bus\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 static int sii902x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -375,6 +468,13 @@ static int sii902x_probe(struct i2c_client *client,
        u8 chipid[4];
        int ret;
 
+       ret = i2c_check_functionality(client->adapter,
+                                     I2C_FUNC_SMBUS_BYTE_DATA);
+       if (!ret) {
+               dev_err(dev, "I2C adapter not suitable\n");
+               return -EIO;
+       }
+
        sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL);
        if (!sii902x)
                return -ENOMEM;
@@ -433,7 +533,15 @@ static int sii902x_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, sii902x);
 
-       return 0;
+       sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev,
+                                       1, 0, I2C_MUX_GATE,
+                                       sii902x_i2c_bypass_select,
+                                       sii902x_i2c_bypass_deselect);
+       if (!sii902x->i2cmux)
+               return -ENOMEM;
+
+       sii902x->i2cmux->priv = sii902x;
+       return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
 }
 
 static int sii902x_remove(struct i2c_client *client)
@@ -441,6 +549,7 @@ static int sii902x_remove(struct i2c_client *client)
 {
        struct sii902x *sii902x = i2c_get_clientdata(client);
 
+       i2c_mux_del_adapters(sii902x->i2cmux);
        drm_bridge_remove(&sii902x->bridge);
 
        return 0;
index 5971976284bf9ddb34434485624d531313791ee3..64c3cf0275182649d9a5572ce6f3d907165f822a 100644 (file)
@@ -1664,6 +1664,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
        case 0x131a:
        case 0x132a:
        case 0x201a:
+       case 0x212a:
                count = 1;
                break;
        default:
@@ -1957,7 +1958,6 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
 
 static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
        .get_modes = dw_hdmi_connector_get_modes,
-       .best_encoder = drm_atomic_helper_best_encoder,
 };
 
 static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
@@ -2205,7 +2205,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
        unsigned int i;
        u8 phy_type;
 
-       phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
+       phy_type = hdmi->plat_data->phy_force_vendor ?
+                               DW_HDMI_PHY_VENDOR_PHY :
+                               hdmi_readb(hdmi, HDMI_CONFIG2_ID);
 
        if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
                /* Vendor PHYs require support from the glue layer. */
index fd7999642cf8a5689124d8c2df1e64448c96744a..2f4b145b73af23d7db14845a111c5fc9d4f27736 100644 (file)
@@ -230,9 +230,20 @@ struct dw_mipi_dsi {
        u32 format;
        unsigned long mode_flags;
 
+       struct dw_mipi_dsi *master; /* dual-dsi master ptr */
+       struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
+
        const struct dw_mipi_dsi_plat_data *plat_data;
 };
 
+/*
+ * Check if either a link to a master or slave is present
+ */
+static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi)
+{
+       return dsi->slave || dsi->master;
+}
+
 /*
  * The controller should generate 2 frames before
  * preparing the peripheral.
@@ -270,6 +281,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
                                   struct mipi_dsi_device *device)
 {
        struct dw_mipi_dsi *dsi = host_to_dsi(host);
+       const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
        struct drm_bridge *bridge;
        struct drm_panel *panel;
        int ret;
@@ -300,6 +312,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 
        drm_bridge_add(&dsi->bridge);
 
+       if (pdata->host_ops && pdata->host_ops->attach) {
+               ret = pdata->host_ops->attach(pdata->priv_data, device);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -307,6 +325,14 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
                                   struct mipi_dsi_device *device)
 {
        struct dw_mipi_dsi *dsi = host_to_dsi(host);
+       const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
+       int ret;
+
+       if (pdata->host_ops && pdata->host_ops->detach) {
+               ret = pdata->host_ops->detach(pdata->priv_data, device);
+               if (ret < 0)
+                       return ret;
+       }
 
        drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
 
@@ -441,10 +467,17 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
        }
 
        dw_mipi_message_config(dsi, msg);
+       if (dsi->slave)
+               dw_mipi_message_config(dsi->slave, msg);
 
        ret = dw_mipi_dsi_write(dsi, &packet);
        if (ret)
                return ret;
+       if (dsi->slave) {
+               ret = dw_mipi_dsi_write(dsi->slave, &packet);
+               if (ret)
+                       return ret;
+       }
 
        if (msg->rx_buf && msg->rx_len) {
                ret = dw_mipi_dsi_read(dsi, msg);
@@ -583,7 +616,11 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
         * DSI_VNPCR.NPSIZE... especially because this driver supports
         * non-burst video modes, see dw_mipi_dsi_video_mode_config()...
         */
-       dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
+
+       dsi_write(dsi, DSI_VID_PKT_SIZE,
+                      dw_mipi_is_dual_mode(dsi) ?
+                               VID_PKT_SIZE(mode->hdisplay / 2) :
+                               VID_PKT_SIZE(mode->hdisplay));
 }
 
 static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -755,24 +792,43 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
         */
        dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
 
+       if (dsi->slave) {
+               dw_mipi_dsi_disable(dsi->slave);
+               clk_disable_unprepare(dsi->slave->pclk);
+               pm_runtime_put(dsi->slave->dev);
+       }
        dw_mipi_dsi_disable(dsi);
+
        clk_disable_unprepare(dsi->pclk);
        pm_runtime_put(dsi->dev);
 }
 
-static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
-                                       struct drm_display_mode *mode,
-                                       struct drm_display_mode *adjusted_mode)
+static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
+{
+       /* this instance is the slave, so add the master's lanes */
+       if (dsi->master)
+               return dsi->master->lanes + dsi->lanes;
+
+       /* this instance is the master, so add the slave's lanes */
+       if (dsi->slave)
+               return dsi->lanes + dsi->slave->lanes;
+
+       /* single-dsi, so no other instance to consider */
+       return dsi->lanes;
+}
+
+static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
+                               struct drm_display_mode *adjusted_mode)
 {
-       struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
        const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
        void *priv_data = dsi->plat_data->priv_data;
        int ret;
+       u32 lanes = dw_mipi_dsi_get_lanes(dsi);
 
        clk_prepare_enable(dsi->pclk);
 
        ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags,
-                                    dsi->lanes, dsi->format, &dsi->lane_mbps);
+                                    lanes, dsi->format, &dsi->lane_mbps);
        if (ret)
                DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
 
@@ -804,12 +860,25 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
        dw_mipi_dsi_set_mode(dsi, 0);
 }
 
+static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
+                                       struct drm_display_mode *mode,
+                                       struct drm_display_mode *adjusted_mode)
+{
+       struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+       dw_mipi_dsi_mode_set(dsi, adjusted_mode);
+       if (dsi->slave)
+               dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
+}
+
 static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
 {
        struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
 
        /* Switch to video mode for panel-bridge enable & panel enable */
        dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
+       if (dsi->slave)
+               dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
 }
 
 static enum drm_mode_status
@@ -941,9 +1010,25 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
 
 static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
 {
+       mipi_dsi_host_unregister(&dsi->dsi_host);
+
        pm_runtime_disable(dsi->dev);
 }
 
+void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave)
+{
+       /* introduce controllers to each other */
+       dsi->slave = slave;
+       dsi->slave->master = dsi;
+
+       /* migrate settings for already attached displays */
+       dsi->slave->lanes = dsi->lanes;
+       dsi->slave->channel = dsi->channel;
+       dsi->slave->format = dsi->format;
+       dsi->slave->mode_flags = dsi->mode_flags;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave);
+
 /*
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
@@ -957,8 +1042,6 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
 
 void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
 {
-       mipi_dsi_host_unregister(&dsi->dsi_host);
-
        __dw_mipi_dsi_remove(dsi);
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
@@ -966,31 +1049,22 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
 /*
  * Bind/unbind API, used from platforms based on the component framework.
  */
-struct dw_mipi_dsi *
-dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-                const struct dw_mipi_dsi_plat_data *plat_data)
+int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
 {
-       struct dw_mipi_dsi *dsi;
        int ret;
 
-       dsi = __dw_mipi_dsi_probe(pdev, plat_data);
-       if (IS_ERR(dsi))
-               return dsi;
-
        ret = drm_bridge_attach(encoder, &dsi->bridge, NULL);
        if (ret) {
-               dw_mipi_dsi_remove(dsi);
                DRM_ERROR("Failed to initialize bridge with drm\n");
-               return ERR_PTR(ret);
+               return ret;
        }
 
-       return dsi;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
 
 void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi)
 {
-       __dw_mipi_dsi_remove(dsi);
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
 
index ee6b98efa9c221015cd7cefb9cd3384dfa9efd16..afd491018bfc55817511ea1d7db9e6fc5f19a99b 100644 (file)
@@ -379,7 +379,7 @@ static void tc358764_detach(struct drm_bridge *bridge)
        drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector);
        drm_panel_detach(ctx->panel);
        ctx->panel = NULL;
-       drm_connector_unreference(&ctx->connector);
+       drm_connector_put(&ctx->connector);
 }
 
 static const struct drm_bridge_funcs tc358764_bridge_funcs = {
index a29f87e98d9d2a224cfb699528e38f4cbdb44c7b..f2b2e0d169fabb73a8c55a6ab459720799a682cf 100644 (file)
@@ -136,8 +136,6 @@ struct cirrus_device {
        int fb_mtrr;
 
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
        } ttm;
        bool mm_inited;
index 68ab1821e15bcc1787a9dd9800963971a4321117..4dd499c7d1ba13fc2cb49e91fc011ece76b07f16 100644 (file)
@@ -169,7 +169,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
        struct drm_mode_fb_cmd2 mode_cmd;
        void *sysram;
        struct drm_gem_object *gobj = NULL;
-       struct cirrus_bo *bo = NULL;
        int size, ret;
 
        mode_cmd.width = sizes->surface_width;
@@ -185,8 +184,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
                return ret;
        }
 
-       bo = gem_to_cirrus_bo(gobj);
-
        sysram = vmalloc(size);
        if (!sysram)
                return -ENOMEM;
index f2195324379039a651b21c2fec0a1209f35800c0..e075810b4bd4063af7334d0543123c28c44198a9 100644 (file)
@@ -36,63 +36,6 @@ cirrus_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct cirrus_device, ttm.bdev);
 }
 
-static int
-cirrus_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void
-cirrus_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int cirrus_ttm_global_init(struct cirrus_device *cirrus)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       global_ref = &cirrus->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &cirrus_ttm_mem_global_init;
-       global_ref->release = &cirrus_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       cirrus->ttm.bo_global_ref.mem_glob =
-               cirrus->ttm.mem_global_ref.object;
-       global_ref = &cirrus->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&cirrus->ttm.mem_global_ref);
-               return r;
-       }
-       return 0;
-}
-
-static void
-cirrus_ttm_global_release(struct cirrus_device *cirrus)
-{
-       if (cirrus->ttm.mem_global_ref.release == NULL)
-               return;
-
-       drm_global_item_unref(&cirrus->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&cirrus->ttm.mem_global_ref);
-       cirrus->ttm.mem_global_ref.release = NULL;
-}
-
-
 static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct cirrus_bo *bo;
@@ -232,12 +175,7 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
        struct drm_device *dev = cirrus->dev;
        struct ttm_bo_device *bdev = &cirrus->ttm.bdev;
 
-       ret = cirrus_ttm_global_init(cirrus);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&cirrus->ttm.bdev,
-                                cirrus->ttm.bo_global_ref.ref.object,
                                 &cirrus_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET,
@@ -273,8 +211,6 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
 
        ttm_bo_device_release(&cirrus->ttm.bdev);
 
-       cirrus_ttm_global_release(cirrus);
-
        arch_phys_wc_del(cirrus->fb_mtrr);
        cirrus->fb_mtrr = 0;
        arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
index 3dbfbddae7e6f2f887b30773e9b06a98774d640c..48ec378fb27ec37804179a306979fb06c7b72bf5 100644 (file)
@@ -315,9 +315,11 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_get_crtc_state);
 
-static int drm_atomic_crtc_check(struct drm_crtc *crtc,
-               struct drm_crtc_state *state)
+static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state,
+                                const struct drm_crtc_state *new_crtc_state)
 {
+       struct drm_crtc *crtc = new_crtc_state->crtc;
+
        /* NOTE: we explicitly don't enforce constraints such as primary
         * layer covering entire screen, since that is something we want
         * to allow (on hw that supports it).  For hw that does not, it
@@ -326,7 +328,7 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
         * TODO: Add generic modeset state checks once we support those.
         */
 
-       if (state->active && !state->enable) {
+       if (new_crtc_state->active && !new_crtc_state->enable) {
                DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n",
                                 crtc->base.id, crtc->name);
                return -EINVAL;
@@ -336,14 +338,14 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
         * as this is a kernel-internal detail that userspace should never
         * be able to trigger. */
        if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
-           WARN_ON(state->enable && !state->mode_blob)) {
+           WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) {
                DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled without mode blob\n",
                                 crtc->base.id, crtc->name);
                return -EINVAL;
        }
 
        if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
-           WARN_ON(!state->enable && state->mode_blob)) {
+           WARN_ON(!new_crtc_state->enable && new_crtc_state->mode_blob)) {
                DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled with mode blob\n",
                                 crtc->base.id, crtc->name);
                return -EINVAL;
@@ -359,7 +361,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
         * and legacy page_flip IOCTL which also reject service on a disabled
         * pipe.
         */
-       if (state->event && !state->active && !crtc->state->active) {
+       if (new_crtc_state->event &&
+           !new_crtc_state->active && !old_crtc_state->active) {
                DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requesting event but off\n",
                                 crtc->base.id, crtc->name);
                return -EINVAL;
@@ -395,6 +398,11 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
 {
        struct drm_crtc_state *crtc_state;
        struct drm_writeback_job *writeback_job = state->writeback_job;
+       const struct drm_display_info *info = &connector->display_info;
+
+       state->max_bpc = info->bpc ? info->bpc : 8;
+       if (connector->max_bpc_property)
+               state->max_bpc = min(state->max_bpc, state->max_requested_bpc);
 
        if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job)
                return 0;
@@ -489,14 +497,13 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_plane_state);
 
 static bool
-plane_switching_crtc(struct drm_atomic_state *state,
-                    struct drm_plane *plane,
-                    struct drm_plane_state *plane_state)
+plane_switching_crtc(const struct drm_plane_state *old_plane_state,
+                    const struct drm_plane_state *new_plane_state)
 {
-       if (!plane->state->crtc || !plane_state->crtc)
+       if (!old_plane_state->crtc || !new_plane_state->crtc)
                return false;
 
-       if (plane->state->crtc == plane_state->crtc)
+       if (old_plane_state->crtc == new_plane_state->crtc)
                return false;
 
        /* This could be refined, but currently there's no helper or driver code
@@ -509,88 +516,117 @@ plane_switching_crtc(struct drm_atomic_state *state,
 
 /**
  * drm_atomic_plane_check - check plane state
- * @plane: plane to check
- * @state: plane state to check
+ * @old_plane_state: old plane state to check
+ * @new_plane_state: new plane state to check
  *
  * Provides core sanity checks for plane state.
  *
  * RETURNS:
  * Zero on success, error code on failure
  */
-static int drm_atomic_plane_check(struct drm_plane *plane,
-               struct drm_plane_state *state)
+static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
+                                 const struct drm_plane_state *new_plane_state)
 {
+       struct drm_plane *plane = new_plane_state->plane;
+       struct drm_crtc *crtc = new_plane_state->crtc;
+       const struct drm_framebuffer *fb = new_plane_state->fb;
        unsigned int fb_width, fb_height;
+       struct drm_mode_rect *clips;
+       uint32_t num_clips;
        int ret;
 
        /* either *both* CRTC and FB must be set, or neither */
-       if (state->crtc && !state->fb) {
+       if (crtc && !fb) {
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] CRTC set but no FB\n",
                                 plane->base.id, plane->name);
                return -EINVAL;
-       } else if (state->fb && !state->crtc) {
+       } else if (fb && !crtc) {
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n",
                                 plane->base.id, plane->name);
                return -EINVAL;
        }
 
        /* if disabled, we don't care about the rest of the state: */
-       if (!state->crtc)
+       if (!crtc)
                return 0;
 
        /* Check whether this plane is usable on this CRTC */
-       if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
+       if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
                DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n",
-                                state->crtc->base.id, state->crtc->name,
+                                crtc->base.id, crtc->name,
                                 plane->base.id, plane->name);
                return -EINVAL;
        }
 
        /* Check whether this plane supports the fb pixel format. */
-       ret = drm_plane_check_pixel_format(plane, state->fb->format->format,
-                                          state->fb->modifier);
+       ret = drm_plane_check_pixel_format(plane, fb->format->format,
+                                          fb->modifier);
        if (ret) {
                struct drm_format_name_buf format_name;
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid pixel format %s, modifier 0x%llx\n",
                                 plane->base.id, plane->name,
-                                drm_get_format_name(state->fb->format->format,
+                                drm_get_format_name(fb->format->format,
                                                     &format_name),
-                                state->fb->modifier);
+                                fb->modifier);
                return ret;
        }
 
        /* Give drivers some help against integer overflows */
-       if (state->crtc_w > INT_MAX ||
-           state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
-           state->crtc_h > INT_MAX ||
-           state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+       if (new_plane_state->crtc_w > INT_MAX ||
+           new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w ||
+           new_plane_state->crtc_h > INT_MAX ||
+           new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) {
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n",
                                 plane->base.id, plane->name,
-                                state->crtc_w, state->crtc_h,
-                                state->crtc_x, state->crtc_y);
+                                new_plane_state->crtc_w, new_plane_state->crtc_h,
+                                new_plane_state->crtc_x, new_plane_state->crtc_y);
                return -ERANGE;
        }
 
-       fb_width = state->fb->width << 16;
-       fb_height = state->fb->height << 16;
+       fb_width = fb->width << 16;
+       fb_height = fb->height << 16;
 
        /* Make sure source coordinates are inside the fb. */
-       if (state->src_w > fb_width ||
-           state->src_x > fb_width - state->src_w ||
-           state->src_h > fb_height ||
-           state->src_y > fb_height - state->src_h) {
+       if (new_plane_state->src_w > fb_width ||
+           new_plane_state->src_x > fb_width - new_plane_state->src_w ||
+           new_plane_state->src_h > fb_height ||
+           new_plane_state->src_y > fb_height - new_plane_state->src_h) {
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid source coordinates "
                                 "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
                                 plane->base.id, plane->name,
-                                state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
-                                state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
-                                state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
-                                state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10,
-                                state->fb->width, state->fb->height);
+                                new_plane_state->src_w >> 16,
+                                ((new_plane_state->src_w & 0xffff) * 15625) >> 10,
+                                new_plane_state->src_h >> 16,
+                                ((new_plane_state->src_h & 0xffff) * 15625) >> 10,
+                                new_plane_state->src_x >> 16,
+                                ((new_plane_state->src_x & 0xffff) * 15625) >> 10,
+                                new_plane_state->src_y >> 16,
+                                ((new_plane_state->src_y & 0xffff) * 15625) >> 10,
+                                fb->width, fb->height);
                return -ENOSPC;
        }
 
-       if (plane_switching_crtc(state->state, plane, state)) {
+       clips = drm_plane_get_damage_clips(new_plane_state);
+       num_clips = drm_plane_get_damage_clips_count(new_plane_state);
+
+       /* Make sure damage clips are valid and inside the fb. */
+       while (num_clips > 0) {
+               if (clips->x1 >= clips->x2 ||
+                   clips->y1 >= clips->y2 ||
+                   clips->x1 < 0 ||
+                   clips->y1 < 0 ||
+                   clips->x2 > fb_width ||
+                   clips->y2 > fb_height) {
+                       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n",
+                                        plane->base.id, plane->name, clips->x1,
+                                        clips->y1, clips->x2, clips->y2);
+                       return -EINVAL;
+               }
+               clips++;
+               num_clips--;
+       }
+
+       if (plane_switching_crtc(old_plane_state, new_plane_state)) {
                DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
                                 plane->base.id, plane->name);
                return -EINVAL;
@@ -927,6 +963,8 @@ int
 drm_atomic_add_affected_planes(struct drm_atomic_state *state,
                               struct drm_crtc *crtc)
 {
+       const struct drm_crtc_state *old_crtc_state =
+               drm_atomic_get_old_crtc_state(state, crtc);
        struct drm_plane *plane;
 
        WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));
@@ -934,7 +972,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
        DRM_DEBUG_ATOMIC("Adding all current planes for [CRTC:%d:%s] to %p\n",
                         crtc->base.id, crtc->name, state);
 
-       drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) {
+       drm_for_each_plane_mask(plane, state->dev, old_crtc_state->plane_mask) {
                struct drm_plane_state *plane_state =
                        drm_atomic_get_plane_state(state, plane);
 
@@ -961,17 +999,19 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct drm_mode_config *config = &dev->mode_config;
        struct drm_plane *plane;
-       struct drm_plane_state *plane_state;
+       struct drm_plane_state *old_plane_state;
+       struct drm_plane_state *new_plane_state;
        struct drm_crtc *crtc;
-       struct drm_crtc_state *crtc_state;
+       struct drm_crtc_state *old_crtc_state;
+       struct drm_crtc_state *new_crtc_state;
        struct drm_connector *conn;
        struct drm_connector_state *conn_state;
        int i, ret = 0;
 
        DRM_DEBUG_ATOMIC("checking %p\n", state);
 
-       for_each_new_plane_in_state(state, plane, plane_state, i) {
-               ret = drm_atomic_plane_check(plane, plane_state);
+       for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+               ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
                if (ret) {
                        DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n",
                                         plane->base.id, plane->name);
@@ -979,8 +1019,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                }
        }
 
-       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
-               ret = drm_atomic_crtc_check(crtc, crtc_state);
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state);
                if (ret) {
                        DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n",
                                         crtc->base.id, crtc->name);
@@ -1008,8 +1048,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
        }
 
        if (!state->allow_modeset) {
-               for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
-                       if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+               for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+                       if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
                                DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n",
                                                 crtc->base.id, crtc->name);
                                return -EINVAL;
index d8b526b7932c3db06e1ff7cad3f2485ddfe52cee..54e2ae614dccb4e94187df67abfebf776962f2a6 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_writeback.h>
+#include <drm/drm_damage_helper.h>
 #include <linux/dma-fence.h>
 
 #include "drm_crtc_helper_internal.h"
@@ -92,6 +93,17 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
        }
 }
 
+/*
+ * For connectors that support multiple encoders, either the
+ * .atomic_best_encoder() or .best_encoder() operation must be implemented.
+ */
+static struct drm_encoder *
+pick_single_encoder_for_connector(struct drm_connector *connector)
+{
+       WARN_ON(connector->encoder_ids[1]);
+       return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
+}
+
 static int handle_conflicting_encoders(struct drm_atomic_state *state,
                                       bool disable_conflicting_encoders)
 {
@@ -119,7 +131,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,
                else if (funcs->best_encoder)
                        new_encoder = funcs->best_encoder(connector);
                else
-                       new_encoder = drm_atomic_helper_best_encoder(connector);
+                       new_encoder = pick_single_encoder_for_connector(connector);
 
                if (new_encoder) {
                        if (encoder_mask & drm_encoder_mask(new_encoder)) {
@@ -336,7 +348,7 @@ update_connector_routing(struct drm_atomic_state *state,
        else if (funcs->best_encoder)
                new_encoder = funcs->best_encoder(connector);
        else
-               new_encoder = drm_atomic_helper_best_encoder(connector);
+               new_encoder = pick_single_encoder_for_connector(connector);
 
        if (!new_encoder) {
                DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -658,6 +670,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                        if (old_connector_state->link_status !=
                            new_connector_state->link_status)
                                new_crtc_state->connectors_changed = true;
+
+                       if (old_connector_state->max_requested_bpc !=
+                           new_connector_state->max_requested_bpc)
+                               new_crtc_state->connectors_changed = true;
                }
 
                if (funcs->atomic_check)
@@ -847,6 +863,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
 
                drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
 
+               drm_atomic_helper_check_plane_damage(state, new_plane_state);
+
                if (!funcs || !funcs->atomic_check)
                        continue;
 
@@ -1445,6 +1463,9 @@ void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
                        DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",
                                  crtc->base.id, crtc->name);
        }
+
+       if (old_state->fake_commit)
+               complete_all(&old_state->fake_commit->flip_done);
 }
 EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
 
@@ -2202,8 +2223,10 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
                spin_unlock(&crtc->commit_lock);
        }
 
-       if (old_state->fake_commit)
+       if (old_state->fake_commit) {
                complete_all(&old_state->fake_commit->cleanup_done);
+               WARN_ON(!try_wait_for_completion(&old_state->fake_commit->hw_done));
+       }
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
 
@@ -3108,26 +3131,103 @@ void drm_atomic_helper_shutdown(struct drm_device *dev)
        struct drm_modeset_acquire_ctx ctx;
        int ret;
 
-       drm_modeset_acquire_init(&ctx, 0);
-       while (1) {
-               ret = drm_modeset_lock_all_ctx(dev, &ctx);
-               if (!ret)
-                       ret = __drm_atomic_helper_disable_all(dev, &ctx, true);
-
-               if (ret != -EDEADLK)
-                       break;
-
-               drm_modeset_backoff(&ctx);
-       }
+       DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
 
+       ret = __drm_atomic_helper_disable_all(dev, &ctx, true);
        if (ret)
                DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret);
 
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
+       DRM_MODESET_LOCK_ALL_END(ctx, ret);
 }
 EXPORT_SYMBOL(drm_atomic_helper_shutdown);
 
+/**
+ * drm_atomic_helper_duplicate_state - duplicate an atomic state object
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Makes a copy of the current atomic state by looping over all objects and
+ * duplicating their respective states. This is used for example by suspend/
+ * resume support code to save the state prior to suspend such that it can
+ * be restored upon resume.
+ *
+ * Note that this treats atomic state as persistent between save and restore.
+ * Drivers must make sure that this is possible and won't result in confusion
+ * or erroneous behaviour.
+ *
+ * Note that if callers haven't already acquired all modeset locks this might
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
+ *
+ * Returns:
+ * A pointer to the copy of the atomic state object on success or an
+ * ERR_PTR()-encoded error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
+ */
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_state(struct drm_device *dev,
+                                 struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_atomic_state *state;
+       struct drm_connector *conn;
+       struct drm_connector_list_iter conn_iter;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+       int err = 0;
+
+       state = drm_atomic_state_alloc(dev);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       state->acquire_ctx = ctx;
+
+       drm_for_each_crtc(crtc, dev) {
+               struct drm_crtc_state *crtc_state;
+
+               crtc_state = drm_atomic_get_crtc_state(state, crtc);
+               if (IS_ERR(crtc_state)) {
+                       err = PTR_ERR(crtc_state);
+                       goto free;
+               }
+       }
+
+       drm_for_each_plane(plane, dev) {
+               struct drm_plane_state *plane_state;
+
+               plane_state = drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state)) {
+                       err = PTR_ERR(plane_state);
+                       goto free;
+               }
+       }
+
+       drm_connector_list_iter_begin(dev, &conn_iter);
+       drm_for_each_connector_iter(conn, &conn_iter) {
+               struct drm_connector_state *conn_state;
+
+               conn_state = drm_atomic_get_connector_state(state, conn);
+               if (IS_ERR(conn_state)) {
+                       err = PTR_ERR(conn_state);
+                       drm_connector_list_iter_end(&conn_iter);
+                       goto free;
+               }
+       }
+       drm_connector_list_iter_end(&conn_iter);
+
+       /* clear the acquire context so that it isn't accidentally reused */
+       state->acquire_ctx = NULL;
+
+free:
+       if (err < 0) {
+               drm_atomic_state_put(state);
+               state = ERR_PTR(err);
+       }
+
+       return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+
 /**
  * drm_atomic_helper_suspend - subsystem-level suspend helper
  * @dev: DRM device
@@ -3159,14 +3259,10 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
        struct drm_atomic_state *state;
        int err;
 
-       drm_modeset_acquire_init(&ctx, 0);
+       /* This can never be returned, but it makes the compiler happy */
+       state = ERR_PTR(-EINVAL);
 
-retry:
-       err = drm_modeset_lock_all_ctx(dev, &ctx);
-       if (err < 0) {
-               state = ERR_PTR(err);
-               goto unlock;
-       }
+       DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
 
        state = drm_atomic_helper_duplicate_state(dev, &ctx);
        if (IS_ERR(state))
@@ -3180,13 +3276,10 @@ retry:
        }
 
 unlock:
-       if (PTR_ERR(state) == -EDEADLK) {
-               drm_modeset_backoff(&ctx);
-               goto retry;
-       }
+       DRM_MODESET_LOCK_ALL_END(ctx, err);
+       if (err)
+               return ERR_PTR(err);
 
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_suspend);
@@ -3209,7 +3302,7 @@ EXPORT_SYMBOL(drm_atomic_helper_suspend);
 int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
                                              struct drm_modeset_acquire_ctx *ctx)
 {
-       int i;
+       int i, ret;
        struct drm_plane *plane;
        struct drm_plane_state *new_plane_state;
        struct drm_connector *connector;
@@ -3228,7 +3321,11 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
        for_each_new_connector_in_state(state, connector, new_conn_state, i)
                state->connectors[i].old_state = connector->state;
 
-       return drm_atomic_commit(state);
+       ret = drm_atomic_commit(state);
+
+       state->acquire_ctx = NULL;
+
+       return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state);
 
@@ -3256,23 +3353,12 @@ int drm_atomic_helper_resume(struct drm_device *dev,
 
        drm_mode_config_reset(dev);
 
-       drm_modeset_acquire_init(&ctx, 0);
-       while (1) {
-               err = drm_modeset_lock_all_ctx(dev, &ctx);
-               if (err)
-                       goto out;
-
-               err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
-out:
-               if (err != -EDEADLK)
-                       break;
+       DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
 
-               drm_modeset_backoff(&ctx);
-       }
+       err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
 
+       DRM_MODESET_LOCK_ALL_END(ctx, err);
        drm_atomic_state_put(state);
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
 
        return err;
 }
@@ -3412,504 +3498,6 @@ fail:
 }
 EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
 
-/**
- * drm_atomic_helper_best_encoder - Helper for
- *     &drm_connector_helper_funcs.best_encoder callback
- * @connector: Connector control structure
- *
- * This is a &drm_connector_helper_funcs.best_encoder callback helper for
- * connectors that support exactly 1 encoder, statically determined at driver
- * init time.
- */
-struct drm_encoder *
-drm_atomic_helper_best_encoder(struct drm_connector *connector)
-{
-       WARN_ON(connector->encoder_ids[1]);
-       return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
-}
-EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
-
-/**
- * DOC: atomic state reset and initialization
- *
- * Both the drm core and the atomic helpers assume that there is always the full
- * and correct atomic software state for all connectors, CRTCs and planes
- * available. Which is a bit a problem on driver load and also after system
- * suspend. One way to solve this is to have a hardware state read-out
- * infrastructure which reconstructs the full software state (e.g. the i915
- * driver).
- *
- * The simpler solution is to just reset the software state to everything off,
- * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
- * the atomic helpers provide default reset implementations for all hooks.
- *
- * On the upside the precise state tracking of atomic simplifies system suspend
- * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
- * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
- * For other drivers the building blocks are split out, see the documentation
- * for these functions.
- */
-
-/**
- * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
- * @crtc: drm CRTC
- *
- * Resets the atomic state for @crtc by freeing the state pointer (which might
- * be NULL, e.g. at driver load time) and allocating a new empty state object.
- */
-void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
-{
-       if (crtc->state)
-               __drm_atomic_helper_crtc_destroy_state(crtc->state);
-
-       kfree(crtc->state);
-       crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
-
-       if (crtc->state)
-               crtc->state->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));
-
-       if (state->mode_blob)
-               drm_property_blob_get(state->mode_blob);
-       if (state->degamma_lut)
-               drm_property_blob_get(state->degamma_lut);
-       if (state->ctm)
-               drm_property_blob_get(state->ctm);
-       if (state->gamma_lut)
-               drm_property_blob_get(state->gamma_lut);
-       state->mode_changed = false;
-       state->active_changed = false;
-       state->planes_changed = false;
-       state->connectors_changed = false;
-       state->color_mgmt_changed = false;
-       state->zpos_changed = false;
-       state->commit = NULL;
-       state->event = NULL;
-       state->pageflip_flags = 0;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
-
-/**
- * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
- * @crtc: drm CRTC
- *
- * Default CRTC state duplicate hook for drivers which don't have their own
- * subclassed CRTC state structure.
- */
-struct drm_crtc_state *
-drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
-{
-       struct drm_crtc_state *state;
-
-       if (WARN_ON(!crtc->state))
-               return 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
- * @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_state *state)
-{
-       if (state->commit) {
-               /*
-                * In the event that a non-blocking commit returns
-                * -ERESTARTSYS before the commit_tail work is queued, we will
-                * have an extra reference to the commit object. Release it, if
-                * the event has not been consumed by the worker.
-                *
-                * state->event may be freed, so we can't directly look at
-                * state->event->base.completion.
-                */
-               if (state->event && state->commit->abort_completion)
-                       drm_crtc_commit_put(state->commit);
-
-               kfree(state->commit->event);
-               state->commit->event = NULL;
-
-               drm_crtc_commit_put(state->commit);
-       }
-
-       drm_property_blob_put(state->mode_blob);
-       drm_property_blob_put(state->degamma_lut);
-       drm_property_blob_put(state->ctm);
-       drm_property_blob_put(state->gamma_lut);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
-
-/**
- * drm_atomic_helper_crtc_destroy_state - default state destroy hook
- * @crtc: drm CRTC
- * @state: CRTC state object to release
- *
- * Default CRTC state destroy hook for drivers which don't have their own
- * subclassed CRTC state structure.
- */
-void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
-                                         struct drm_crtc_state *state)
-{
-       __drm_atomic_helper_crtc_destroy_state(state);
-       kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
-
-/**
- * __drm_atomic_helper_plane_reset - resets planes state to default values
- * @plane: plane object, must not be NULL
- * @state: atomic plane state, must not be NULL
- *
- * Initializes plane state to default. This is useful for drivers that subclass
- * the plane state.
- */
-void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
-                                    struct drm_plane_state *state)
-{
-       state->plane = plane;
-       state->rotation = DRM_MODE_ROTATE_0;
-
-       state->alpha = DRM_BLEND_ALPHA_OPAQUE;
-       state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
-
-       plane->state = state;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
-
-/**
- * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
- * @plane: drm plane
- *
- * Resets the atomic state for @plane by freeing the state pointer (which might
- * be NULL, e.g. at driver load time) and allocating a new empty state object.
- */
-void drm_atomic_helper_plane_reset(struct drm_plane *plane)
-{
-       if (plane->state)
-               __drm_atomic_helper_plane_destroy_state(plane->state);
-
-       kfree(plane->state);
-       plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
-       if (plane->state)
-               __drm_atomic_helper_plane_reset(plane, plane->state);
-}
-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_get(state->fb);
-
-       state->fence = NULL;
-       state->commit = NULL;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
-
-/**
- * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
- * @plane: drm plane
- *
- * Default plane state duplicate hook for drivers which don't have their own
- * subclassed plane state structure.
- */
-struct drm_plane_state *
-drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
-{
-       struct drm_plane_state *state;
-
-       if (WARN_ON(!plane->state))
-               return NULL;
-
-       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
- * @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_state *state)
-{
-       if (state->fb)
-               drm_framebuffer_put(state->fb);
-
-       if (state->fence)
-               dma_fence_put(state->fence);
-
-       if (state->commit)
-               drm_crtc_commit_put(state->commit);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
-
-/**
- * drm_atomic_helper_plane_destroy_state - default state destroy hook
- * @plane: drm plane
- * @state: plane state object to release
- *
- * Default plane state destroy hook for drivers which don't have their own
- * subclassed plane state structure.
- */
-void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
-                                          struct drm_plane_state *state)
-{
-       __drm_atomic_helper_plane_destroy_state(state);
-       kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
-
-/**
- * __drm_atomic_helper_connector_reset - reset state on connector
- * @connector: drm connector
- * @conn_state: connector state to assign
- *
- * Initializes the newly allocated @conn_state and assigns it to
- * the &drm_conector->state pointer of @connector, usually required when
- * initializing the drivers or when called from the &drm_connector_funcs.reset
- * hook.
- *
- * This is useful for drivers that subclass the connector state.
- */
-void
-__drm_atomic_helper_connector_reset(struct drm_connector *connector,
-                                   struct drm_connector_state *conn_state)
-{
-       if (conn_state)
-               conn_state->connector = connector;
-
-       connector->state = conn_state;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
-
-/**
- * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
- * @connector: drm connector
- *
- * Resets the atomic state for @connector by freeing the state pointer (which
- * might be NULL, e.g. at driver load time) and allocating a new empty state
- * object.
- */
-void drm_atomic_helper_connector_reset(struct drm_connector *connector)
-{
-       struct drm_connector_state *conn_state =
-               kzalloc(sizeof(*conn_state), GFP_KERNEL);
-
-       if (connector->state)
-               __drm_atomic_helper_connector_destroy_state(connector->state);
-
-       kfree(connector->state);
-       __drm_atomic_helper_connector_reset(connector, conn_state);
-}
-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));
-       if (state->crtc)
-               drm_connector_get(connector);
-       state->commit = NULL;
-
-       /* Don't copy over a writeback job, they are used only once */
-       state->writeback_job = NULL;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
-
-/**
- * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
- * @connector: drm connector
- *
- * Default connector state duplicate hook for drivers which don't have their own
- * subclassed connector state structure.
- */
-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;
-
-       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_duplicate_state - duplicate an atomic state object
- * @dev: DRM device
- * @ctx: lock acquisition context
- *
- * Makes a copy of the current atomic state by looping over all objects and
- * duplicating their respective states. This is used for example by suspend/
- * resume support code to save the state prior to suspend such that it can
- * be restored upon resume.
- *
- * Note that this treats atomic state as persistent between save and restore.
- * Drivers must make sure that this is possible and won't result in confusion
- * or erroneous behaviour.
- *
- * Note that if callers haven't already acquired all modeset locks this might
- * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
- *
- * Returns:
- * A pointer to the copy of the atomic state object on success or an
- * ERR_PTR()-encoded error code on failure.
- *
- * See also:
- * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
- */
-struct drm_atomic_state *
-drm_atomic_helper_duplicate_state(struct drm_device *dev,
-                                 struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_atomic_state *state;
-       struct drm_connector *conn;
-       struct drm_connector_list_iter conn_iter;
-       struct drm_plane *plane;
-       struct drm_crtc *crtc;
-       int err = 0;
-
-       state = drm_atomic_state_alloc(dev);
-       if (!state)
-               return ERR_PTR(-ENOMEM);
-
-       state->acquire_ctx = ctx;
-
-       drm_for_each_crtc(crtc, dev) {
-               struct drm_crtc_state *crtc_state;
-
-               crtc_state = drm_atomic_get_crtc_state(state, crtc);
-               if (IS_ERR(crtc_state)) {
-                       err = PTR_ERR(crtc_state);
-                       goto free;
-               }
-       }
-
-       drm_for_each_plane(plane, dev) {
-               struct drm_plane_state *plane_state;
-
-               plane_state = drm_atomic_get_plane_state(state, plane);
-               if (IS_ERR(plane_state)) {
-                       err = PTR_ERR(plane_state);
-                       goto free;
-               }
-       }
-
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       drm_for_each_connector_iter(conn, &conn_iter) {
-               struct drm_connector_state *conn_state;
-
-               conn_state = drm_atomic_get_connector_state(state, conn);
-               if (IS_ERR(conn_state)) {
-                       err = PTR_ERR(conn_state);
-                       drm_connector_list_iter_end(&conn_iter);
-                       goto free;
-               }
-       }
-       drm_connector_list_iter_end(&conn_iter);
-
-       /* clear the acquire context so that it isn't accidentally reused */
-       state->acquire_ctx = NULL;
-
-free:
-       if (err < 0) {
-               drm_atomic_state_put(state);
-               state = ERR_PTR(err);
-       }
-
-       return state;
-}
-EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
-
-/**
- * __drm_atomic_helper_connector_destroy_state - release connector state
- * @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_state *state)
-{
-       if (state->crtc)
-               drm_connector_put(state->connector);
-
-       if (state->commit)
-               drm_crtc_commit_put(state->commit);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
-
-/**
- * drm_atomic_helper_connector_destroy_state - default state destroy hook
- * @connector: drm connector
- * @state: connector state object to release
- *
- * Default connector state destroy hook for drivers which don't have their own
- * subclassed connector state structure.
- */
-void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
-                                         struct drm_connector_state *state)
-{
-       __drm_atomic_helper_connector_destroy_state(state);
-       kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
-
 /**
  * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
  * @crtc: CRTC object
@@ -3979,18 +3567,3 @@ fail:
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
-
-/**
- * __drm_atomic_helper_private_duplicate_state - copy atomic private state
- * @obj: CRTC object
- * @state: new private object state
- *
- * Copies atomic state from a private objects's current state and resets inferred values.
- * This is useful for drivers that subclass the private state.
- */
-void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
-                                                    struct drm_private_state *state)
-{
-       memcpy(state, obj->state, sizeof(*state));
-}
-EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
new file mode 100644 (file)
index 0000000..60bd7d7
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * 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:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_device.h>
+
+#include <linux/slab.h>
+#include <linux/dma-fence.h>
+
+/**
+ * DOC: atomic state reset and initialization
+ *
+ * Both the drm core and the atomic helpers assume that there is always the full
+ * and correct atomic software state for all connectors, CRTCs and planes
+ * available. Which is a bit a problem on driver load and also after system
+ * suspend. One way to solve this is to have a hardware state read-out
+ * infrastructure which reconstructs the full software state (e.g. the i915
+ * driver).
+ *
+ * The simpler solution is to just reset the software state to everything off,
+ * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
+ * the atomic helpers provide default reset implementations for all hooks.
+ *
+ * On the upside the precise state tracking of atomic simplifies system suspend
+ * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
+ * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
+ * For other drivers the building blocks are split out, see the documentation
+ * for these functions.
+ */
+
+/**
+ * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
+ * @crtc: drm CRTC
+ *
+ * Resets the atomic state for @crtc by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
+{
+       if (crtc->state)
+               __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+       kfree(crtc->state);
+       crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+
+       if (crtc->state)
+               crtc->state->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));
+
+       if (state->mode_blob)
+               drm_property_blob_get(state->mode_blob);
+       if (state->degamma_lut)
+               drm_property_blob_get(state->degamma_lut);
+       if (state->ctm)
+               drm_property_blob_get(state->ctm);
+       if (state->gamma_lut)
+               drm_property_blob_get(state->gamma_lut);
+       state->mode_changed = false;
+       state->active_changed = false;
+       state->planes_changed = false;
+       state->connectors_changed = false;
+       state->color_mgmt_changed = false;
+       state->zpos_changed = false;
+       state->commit = NULL;
+       state->event = NULL;
+       state->pageflip_flags = 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
+
+/**
+ * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
+ * @crtc: drm CRTC
+ *
+ * Default CRTC state duplicate hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+       struct drm_crtc_state *state;
+
+       if (WARN_ON(!crtc->state))
+               return 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
+ * @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_state *state)
+{
+       if (state->commit) {
+               /*
+                * In the event that a non-blocking commit returns
+                * -ERESTARTSYS before the commit_tail work is queued, we will
+                * have an extra reference to the commit object. Release it, if
+                * the event has not been consumed by the worker.
+                *
+                * state->event may be freed, so we can't directly look at
+                * state->event->base.completion.
+                */
+               if (state->event && state->commit->abort_completion)
+                       drm_crtc_commit_put(state->commit);
+
+               kfree(state->commit->event);
+               state->commit->event = NULL;
+
+               drm_crtc_commit_put(state->commit);
+       }
+
+       drm_property_blob_put(state->mode_blob);
+       drm_property_blob_put(state->degamma_lut);
+       drm_property_blob_put(state->ctm);
+       drm_property_blob_put(state->gamma_lut);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * drm_atomic_helper_crtc_destroy_state - default state destroy hook
+ * @crtc: drm CRTC
+ * @state: CRTC state object to release
+ *
+ * Default CRTC state destroy hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                         struct drm_crtc_state *state)
+{
+       __drm_atomic_helper_crtc_destroy_state(state);
+       kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * __drm_atomic_helper_plane_reset - resets planes state to default values
+ * @plane: plane object, must not be NULL
+ * @state: atomic plane state, must not be NULL
+ *
+ * Initializes plane state to default. This is useful for drivers that subclass
+ * the plane state.
+ */
+void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
+                                    struct drm_plane_state *state)
+{
+       state->plane = plane;
+       state->rotation = DRM_MODE_ROTATE_0;
+
+       state->alpha = DRM_BLEND_ALPHA_OPAQUE;
+       state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
+
+       plane->state = state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
+
+/**
+ * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
+ * @plane: drm plane
+ *
+ * Resets the atomic state for @plane by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_plane_reset(struct drm_plane *plane)
+{
+       if (plane->state)
+               __drm_atomic_helper_plane_destroy_state(plane->state);
+
+       kfree(plane->state);
+       plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+       if (plane->state)
+               __drm_atomic_helper_plane_reset(plane, plane->state);
+}
+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_get(state->fb);
+
+       state->fence = NULL;
+       state->commit = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
+
+/**
+ * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
+ * @plane: drm plane
+ *
+ * Default plane state duplicate hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
+{
+       struct drm_plane_state *state;
+
+       if (WARN_ON(!plane->state))
+               return NULL;
+
+       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
+ * @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_state *state)
+{
+       if (state->fb)
+               drm_framebuffer_put(state->fb);
+
+       if (state->fence)
+               dma_fence_put(state->fence);
+
+       if (state->commit)
+               drm_crtc_commit_put(state->commit);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
+
+/**
+ * drm_atomic_helper_plane_destroy_state - default state destroy hook
+ * @plane: drm plane
+ * @state: plane state object to release
+ *
+ * Default plane state destroy hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                          struct drm_plane_state *state)
+{
+       __drm_atomic_helper_plane_destroy_state(state);
+       kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
+
+/**
+ * __drm_atomic_helper_connector_reset - reset state on connector
+ * @connector: drm connector
+ * @conn_state: connector state to assign
+ *
+ * Initializes the newly allocated @conn_state and assigns it to
+ * the &drm_conector->state pointer of @connector, usually required when
+ * initializing the drivers or when called from the &drm_connector_funcs.reset
+ * hook.
+ *
+ * This is useful for drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_reset(struct drm_connector *connector,
+                                   struct drm_connector_state *conn_state)
+{
+       if (conn_state)
+               conn_state->connector = connector;
+
+       connector->state = conn_state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
+
+/**
+ * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
+ * @connector: drm connector
+ *
+ * Resets the atomic state for @connector by freeing the state pointer (which
+ * might be NULL, e.g. at driver load time) and allocating a new empty state
+ * object.
+ */
+void drm_atomic_helper_connector_reset(struct drm_connector *connector)
+{
+       struct drm_connector_state *conn_state =
+               kzalloc(sizeof(*conn_state), GFP_KERNEL);
+
+       if (connector->state)
+               __drm_atomic_helper_connector_destroy_state(connector->state);
+
+       kfree(connector->state);
+       __drm_atomic_helper_connector_reset(connector, conn_state);
+}
+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));
+       if (state->crtc)
+               drm_connector_get(connector);
+       state->commit = NULL;
+
+       /* Don't copy over a writeback job, they are used only once */
+       state->writeback_job = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
+
+/**
+ * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
+ * @connector: drm connector
+ *
+ * Default connector state duplicate hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+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;
+
+       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
+ * @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_state *state)
+{
+       if (state->crtc)
+               drm_connector_put(state->connector);
+
+       if (state->commit)
+               drm_crtc_commit_put(state->commit);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
+
+/**
+ * drm_atomic_helper_connector_destroy_state - default state destroy hook
+ * @connector: drm connector
+ * @state: connector state object to release
+ *
+ * Default connector state destroy hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                         struct drm_connector_state *state)
+{
+       __drm_atomic_helper_connector_destroy_state(state);
+       kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+
+/**
+ * __drm_atomic_helper_private_duplicate_state - copy atomic private state
+ * @obj: CRTC object
+ * @state: new private object state
+ *
+ * Copies atomic state from a private objects's current state and resets inferred values.
+ * This is useful for drivers that subclass the private state.
+ */
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+                                                    struct drm_private_state *state)
+{
+       memcpy(state, obj->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
index d5b7f315098c23b2ddc0c0ab74e410396e0ad917..c40889888a16bccc0cf44591130fdf3872292ab5 100644 (file)
@@ -433,6 +433,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
                ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
                drm_property_blob_put(mode);
                return ret;
+       } else if (property == config->prop_vrr_enabled) {
+               state->vrr_enabled = val;
        } else if (property == config->degamma_lut_property) {
                ret = drm_atomic_replace_property_blob_from_id(dev,
                                        &state->degamma_lut,
@@ -491,6 +493,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
                *val = state->active;
        else if (property == config->prop_mode_id)
                *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
+       else if (property == config->prop_vrr_enabled)
+               *val = state->vrr_enabled;
        else if (property == config->degamma_lut_property)
                *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
        else if (property == config->ctm_property)
@@ -513,6 +517,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
 {
        struct drm_device *dev = plane->dev;
        struct drm_mode_config *config = &dev->mode_config;
+       bool replaced = false;
+       int ret;
 
        if (property == config->prop_fb_id) {
                struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
@@ -566,6 +572,14 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
                state->color_encoding = val;
        } else if (property == plane->color_range_property) {
                state->color_range = val;
+       } else if (property == config->prop_fb_damage_clips) {
+               ret = drm_atomic_replace_property_blob_from_id(dev,
+                                       &state->fb_damage_clips,
+                                       val,
+                                       -1,
+                                       sizeof(struct drm_rect),
+                                       &replaced);
+               return ret;
        } else if (plane->funcs->atomic_set_property) {
                return plane->funcs->atomic_set_property(plane, state,
                                property, val);
@@ -621,6 +635,9 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
                *val = state->color_encoding;
        } else if (property == plane->color_range_property) {
                *val = state->color_range;
+       } else if (property == config->prop_fb_damage_clips) {
+               *val = (state->fb_damage_clips) ?
+                       state->fb_damage_clips->base.id : 0;
        } else if (plane->funcs->atomic_get_property) {
                return plane->funcs->atomic_get_property(plane, state, property, val);
        } else {
@@ -740,6 +757,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 
                return set_out_fence_for_connector(state->state, connector,
                                                   fence_ptr);
+       } else if (property == connector->max_bpc_property) {
+               state->max_requested_bpc = val;
        } else if (connector->funcs->atomic_set_property) {
                return connector->funcs->atomic_set_property(connector,
                                state, property, val);
@@ -804,6 +823,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
                *val = 0;
        } else if (property == config->writeback_out_fence_ptr_property) {
                *val = 0;
+       } else if (property == connector->max_bpc_property) {
+               *val = state->max_requested_bpc;
        } else if (connector->funcs->atomic_get_property) {
                return connector->funcs->atomic_get_property(connector,
                                state, property, val);
index 7412acaf3cde5051cafb90ccc806a272c5fbc9b1..d7d10cabb9bbfd15540f8fe04edb0bdd9fc6558d 100644 (file)
@@ -36,6 +36,8 @@
 #include <drm/drmP.h>
 #include "drm_legacy.h"
 
+#include <linux/nospec.h>
+
 static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
                                                  struct drm_local_map *map)
 {
@@ -1417,6 +1419,7 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
                                  idx, dma->buf_count - 1);
                        return -EINVAL;
                }
+               idx = array_index_nospec(idx, dma->buf_count);
                buf = dma->buflist[idx];
                if (buf->file_priv != file_priv) {
                        DRM_ERROR("Process %d freeing buffer not owned\n",
index fc03d26fcacc8057034bb22bf6c76b03f5f87b2f..9b2bd28dde0a61b3202adfa726c800231f022cd9 100644 (file)
@@ -81,8 +81,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
 {
        int ret;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
-           !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
+       if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
                return -EOPNOTSUPP;
 
        if (funcs && !try_module_get(funcs->owner))
@@ -229,8 +228,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
 {
        struct drm_device *dev = buffer->client->dev;
 
-       if (buffer->vaddr && dev->driver->gem_prime_vunmap)
-               dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
+       drm_gem_vunmap(buffer->gem, buffer->vaddr);
 
        if (buffer->gem)
                drm_gem_object_put_unlocked(buffer->gem);
@@ -283,9 +281,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
         * fd_install step out of the driver backend hooks, to make that
         * final step optional for internal users.
         */
-       vaddr = dev->driver->gem_prime_vmap(obj);
-       if (!vaddr) {
-               ret = -ENOMEM;
+       vaddr = drm_gem_vmap(obj);
+       if (IS_ERR(vaddr)) {
+               ret = PTR_ERR(vaddr);
                goto err_delete;
        }
 
index 581cc378822309e4220a1f49ba8073240ec8ca1e..07dcf47daafe2befc0be3652fbc0e484a69a549e 100644 (file)
@@ -255,11 +255,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
        if (crtc_lut->gamma_size != crtc->gamma_size)
                return -EINVAL;
 
-       drm_modeset_acquire_init(&ctx, 0);
-retry:
-       ret = drm_modeset_lock_all_ctx(dev, &ctx);
-       if (ret)
-               goto out;
+       DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
 
        size = crtc_lut->gamma_size * (sizeof(uint16_t));
        r_base = crtc->gamma_store;
@@ -284,13 +280,7 @@ retry:
                                     crtc->gamma_size, &ctx);
 
 out:
-       if (ret == -EDEADLK) {
-               drm_modeset_backoff(&ctx);
-               goto retry;
-       }
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-
+       DRM_MODESET_LOCK_ALL_END(ctx, ret);
        return ret;
 
 }
index 4943cef178beb7675ab46a0d3100e33ae836bd0e..da8ae80c27506d279fa7fd2419b34eb72a3b292f 100644 (file)
@@ -260,9 +260,7 @@ int drm_connector_init(struct drm_device *dev,
 
        if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL &&
            connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
-               drm_object_attach_property(&connector->base,
-                                             config->edid_property,
-                                             0);
+               drm_connector_attach_edid_property(connector);
 
        drm_object_attach_property(&connector->base,
                                      config->dpms_property, 0);
@@ -294,6 +292,24 @@ out_put:
 }
 EXPORT_SYMBOL(drm_connector_init);
 
+/**
+ * drm_connector_attach_edid_property - attach edid property.
+ * @connector: the connector
+ *
+ * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a
+ * edid property attached by default.  This function can be used to
+ * explicitly enable the edid property in these cases.
+ */
+void drm_connector_attach_edid_property(struct drm_connector *connector)
+{
+       struct drm_mode_config *config = &connector->dev->mode_config;
+
+       drm_object_attach_property(&connector->base,
+                                  config->edid_property,
+                                  0);
+}
+EXPORT_SYMBOL(drm_connector_attach_edid_property);
+
 /**
  * drm_connector_attach_encoder - attach a connector to an encoder
  * @connector: connector to attach
@@ -916,6 +932,13 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
  *       is no longer protected and userspace should take appropriate action
  *       (whatever that might be).
  *
+ * max bpc:
+ *     This range property is used by userspace to limit the bit depth. When
+ *     used the driver would limit the bpc in accordance with the valid range
+ *     supported by the hardware and sink. Drivers to use the function
+ *     drm_connector_attach_max_bpc_property() to create and attach the
+ *     property to the connector during initialization.
+ *
  * Connectors also have one standardized atomic property:
  *
  * CRTC_ID:
@@ -1255,6 +1278,105 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
+/**
+ * DOC: Variable refresh properties
+ *
+ * Variable refresh rate capable displays can dynamically adjust their
+ * refresh rate by extending the duration of their vertical front porch
+ * until page flip or timeout occurs. This can reduce or remove stuttering
+ * and latency in scenarios where the page flip does not align with the
+ * vblank interval.
+ *
+ * An example scenario would be an application flipping at a constant rate
+ * of 48Hz on a 60Hz display. The page flip will frequently miss the vblank
+ * interval and the same contents will be displayed twice. This can be
+ * observed as stuttering for content with motion.
+ *
+ * If variable refresh rate was active on a display that supported a
+ * variable refresh range from 35Hz to 60Hz no stuttering would be observable
+ * for the example scenario. The minimum supported variable refresh rate of
+ * 35Hz is below the page flip frequency and the vertical front porch can
+ * be extended until the page flip occurs. The vblank interval will be
+ * directly aligned to the page flip rate.
+ *
+ * Not all userspace content is suitable for use with variable refresh rate.
+ * Large and frequent changes in vertical front porch duration may worsen
+ * perceived stuttering for input sensitive applications.
+ *
+ * Panel brightness will also vary with vertical front porch duration. Some
+ * panels may have noticeable differences in brightness between the minimum
+ * vertical front porch duration and the maximum vertical front porch duration.
+ * Large and frequent changes in vertical front porch duration may produce
+ * observable flickering for such panels.
+ *
+ * Userspace control for variable refresh rate is supported via properties
+ * on the &drm_connector and &drm_crtc objects.
+ *
+ * "vrr_capable":
+ *     Optional &drm_connector boolean property that drivers should attach
+ *     with drm_connector_attach_vrr_capable_property() on connectors that
+ *     could support variable refresh rates. Drivers should update the
+ *     property value by calling drm_connector_set_vrr_capable_property().
+ *
+ *     Absence of the property should indicate absence of support.
+ *
+ * "vrr_enabled":
+ *     Default &drm_crtc boolean property that notifies the driver that the
+ *     content on the CRTC is suitable for variable refresh rate presentation.
+ *     The driver will take this property as a hint to enable variable
+ *     refresh rate support if the receiver supports it, ie. if the
+ *     "vrr_capable" property is true on the &drm_connector object. The
+ *     vertical front porch duration will be extended until page-flip or
+ *     timeout when enabled.
+ *
+ *     The minimum vertical front porch duration is defined as the vertical
+ *     front porch duration for the current mode.
+ *
+ *     The maximum vertical front porch duration is greater than or equal to
+ *     the minimum vertical front porch duration. The duration is derived
+ *     from the minimum supported variable refresh rate for the connector.
+ *
+ *     The driver may place further restrictions within these minimum
+ *     and maximum bounds.
+ *
+ *     The semantics for the vertical blank timestamp differ when
+ *     variable refresh rate is active. The vertical blank timestamp
+ *     is defined to be an estimate using the current mode's fixed
+ *     refresh rate timings. The semantics for the page-flip event
+ *     timestamp remain the same.
+ */
+
+/**
+ * drm_connector_attach_vrr_capable_property - creates the
+ * vrr_capable property
+ * @connector: connector to create the vrr_capable property on.
+ *
+ * This is used by atomic drivers to add support for querying
+ * variable refresh rate capability for a connector.
+ *
+ * Returns:
+ * Zero on success, negative errono on failure.
+ */
+int drm_connector_attach_vrr_capable_property(
+       struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_property *prop;
+
+       if (!connector->vrr_capable_property) {
+               prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE,
+                       "vrr_capable");
+               if (!prop)
+                       return -ENOMEM;
+
+               connector->vrr_capable_property = prop;
+               drm_object_attach_property(&connector->base, prop, 0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property);
+
 /**
  * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property
  * @connector: connector to attach scaling mode property on.
@@ -1583,6 +1705,58 @@ void drm_connector_set_link_status_property(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_connector_set_link_status_property);
 
+/**
+ * drm_connector_attach_max_bpc_property - attach "max bpc" property
+ * @connector: connector to attach max bpc property on.
+ * @min: The minimum bit depth supported by the connector.
+ * @max: The maximum bit depth supported by the connector.
+ *
+ * This is used to add support for limiting the bit depth on a connector.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
+                                         int min, int max)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_property *prop;
+
+       prop = connector->max_bpc_property;
+       if (!prop) {
+               prop = drm_property_create_range(dev, 0, "max bpc", min, max);
+               if (!prop)
+                       return -ENOMEM;
+
+               connector->max_bpc_property = prop;
+       }
+
+       drm_object_attach_property(&connector->base, prop, max);
+       connector->state->max_requested_bpc = max;
+       connector->state->max_bpc = max;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
+
+/**
+ * drm_connector_set_vrr_capable_property - sets the variable refresh rate
+ * capable property for a connector
+ * @connector: drm connector
+ * @capable: True if the connector is variable refresh rate capable
+ *
+ * Should be used by atomic drivers to update the indicated support for
+ * variable refresh rate over a connector.
+ */
+void drm_connector_set_vrr_capable_property(
+               struct drm_connector *connector, bool capable)
+{
+       drm_object_property_set_value(&connector->base,
+                                     connector->vrr_capable_property,
+                                     capable);
+}
+EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
+
 /**
  * drm_connector_init_panel_orientation_property -
  *     initialize the connecters panel_orientation property
index 268a182ae18939e4ea16e18d9d12dd29bb153b7b..1593dd6cdfb729c3bdfe19215947314df1f0a74d 100644 (file)
@@ -340,6 +340,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
                drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
                drm_object_attach_property(&crtc->base,
                                           config->prop_out_fence_ptr, 0);
+               drm_object_attach_property(&crtc->base,
+                                          config->prop_vrr_enabled, 0);
        }
 
        return 0;
@@ -570,9 +572,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        struct drm_mode_crtc *crtc_req = data;
        struct drm_crtc *crtc;
        struct drm_plane *plane;
-       struct drm_connector **connector_set, *connector;
-       struct drm_framebuffer *fb;
-       struct drm_display_mode *mode;
+       struct drm_connector **connector_set = NULL, *connector;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_display_mode *mode = NULL;
        struct drm_mode_set set;
        uint32_t __user *set_connectors_ptr;
        struct drm_modeset_acquire_ctx ctx;
@@ -599,15 +601,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        plane = crtc->primary;
 
        mutex_lock(&crtc->dev->mode_config.mutex);
-       drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
-retry:
-       connector_set = NULL;
-       fb = NULL;
-       mode = NULL;
-
-       ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx);
-       if (ret)
-               goto out;
+       DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
+                                  DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
 
        if (crtc_req->mode_valid) {
                /* If we have a mode we need a framebuffer. */
@@ -766,13 +761,13 @@ out:
        }
        kfree(connector_set);
        drm_mode_destroy(dev, mode);
-       if (ret == -EDEADLK) {
-               ret = drm_modeset_backoff(&ctx);
-               if (!ret)
-                       goto retry;
-       }
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
+
+       /* In case we need to retry... */
+       connector_set = NULL;
+       fb = NULL;
+       mode = NULL;
+
+       DRM_MODESET_LOCK_ALL_END(ctx, ret);
        mutex_unlock(&crtc->dev->mode_config.mutex);
 
        return ret;
index ce75e9506e851fbf6fcecf028ca51aa17c5f87c0..a3c81850e755f6b8904b662744002d810f04c289 100644 (file)
@@ -984,118 +984,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
        drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
-
-/**
- * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
- * @crtc: DRM CRTC
- * @mode: DRM display mode which userspace requested
- * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
- * @x: x offset of the CRTC scanout area on the underlying framebuffer
- * @y: y offset of the CRTC scanout area on the underlying framebuffer
- * @old_fb: previous framebuffer
- *
- * This function implements a callback useable as the ->mode_set callback
- * required by the CRTC helpers. Besides the atomic plane helper functions for
- * the primary plane the driver must also provide the ->mode_set_nofb callback
- * to set up the CRTC.
- *
- * This is a transitional helper useful for converting drivers to the atomic
- * interfaces.
- */
-int drm_helper_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)
-{
-       struct drm_crtc_state *crtc_state;
-       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       int ret;
-
-       if (crtc->funcs->atomic_duplicate_state)
-               crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
-       else {
-               if (!crtc->state)
-                       drm_atomic_helper_crtc_reset(crtc);
-
-               crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
-       }
-
-       if (!crtc_state)
-               return -ENOMEM;
-
-       crtc_state->planes_changed = true;
-       crtc_state->mode_changed = true;
-       ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
-       if (ret)
-               goto out;
-       drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
-
-       if (crtc_funcs->atomic_check) {
-               ret = crtc_funcs->atomic_check(crtc, crtc_state);
-               if (ret)
-                       goto out;
-       }
-
-       swap(crtc->state, crtc_state);
-
-       crtc_funcs->mode_set_nofb(crtc);
-
-       ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
-
-out:
-       if (crtc_state) {
-               if (crtc->funcs->atomic_destroy_state)
-                       crtc->funcs->atomic_destroy_state(crtc, crtc_state);
-               else
-                       drm_atomic_helper_crtc_destroy_state(crtc, crtc_state);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(drm_helper_crtc_mode_set);
-
-/**
- * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
- * @crtc: DRM CRTC
- * @x: x offset of the CRTC scanout area on the underlying framebuffer
- * @y: y offset of the CRTC scanout area on the underlying framebuffer
- * @old_fb: previous framebuffer
- *
- * This function implements a callback useable as the ->mode_set_base used
- * required by the CRTC helpers. The driver must provide the atomic plane helper
- * functions for the primary plane.
- *
- * This is a transitional helper useful for converting drivers to the atomic
- * interfaces.
- */
-int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                 struct drm_framebuffer *old_fb)
-{
-       struct drm_plane_state *plane_state;
-       struct drm_plane *plane = crtc->primary;
-
-       if (plane->funcs->atomic_duplicate_state)
-               plane_state = plane->funcs->atomic_duplicate_state(plane);
-       else {
-               if (!plane->state)
-                       drm_atomic_helper_plane_reset(plane);
-
-               plane_state = drm_atomic_helper_plane_duplicate_state(plane);
-       }
-       if (!plane_state)
-               return -ENOMEM;
-       plane_state->plane = plane;
-
-       plane_state->crtc = crtc;
-       drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
-       plane_state->crtc_x = 0;
-       plane_state->crtc_y = 0;
-       plane_state->crtc_h = crtc->mode.vdisplay;
-       plane_state->crtc_w = crtc->mode.hdisplay;
-       plane_state->src_x = x << 16;
-       plane_state->src_y = y << 16;
-       plane_state->src_h = crtc->mode.vdisplay << 16;
-       plane_state->src_w = crtc->mode.hdisplay << 16;
-
-       return drm_plane_helper_commit(plane, plane_state, old_fb);
-}
-EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
new file mode 100644 (file)
index 0000000..d2a1c73
--- /dev/null
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/**************************************************************************
+ *
+ * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Deepak Rawat <drawat@vmware.com>
+ * Rob Clark <robdclark@gmail.com>
+ *
+ **************************************************************************/
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_damage_helper.h>
+
+/**
+ * DOC: overview
+ *
+ * FB_DAMAGE_CLIPS is an optional plane property which provides a means to
+ * specify a list of damage rectangles on a plane in framebuffer coordinates of
+ * the framebuffer attached to the plane. In current context damage is the area
+ * of plane framebuffer that has changed since last plane update (also called
+ * page-flip), irrespective of whether currently attached framebuffer is same as
+ * framebuffer attached during last plane update or not.
+ *
+ * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers
+ * to optimize internally especially for virtual devices where each framebuffer
+ * change needs to be transmitted over network, usb, etc.
+ *
+ * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can
+ * ignore damage clips property and in that case driver will do a full plane
+ * update. In case damage clips are provided then it is guaranteed that the area
+ * inside damage clips will be updated to plane. For efficiency driver can do
+ * full update or can update more than specified in damage clips. Since driver
+ * is free to read more, user-space must always render the entire visible
+ * framebuffer. Otherwise there can be corruptions. Also, if a user-space
+ * provides damage clips which doesn't encompass the actual damage to
+ * framebuffer (since last plane update) can result in incorrect rendering.
+ *
+ * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an
+ * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,
+ * damage clips are not in 16.16 fixed point. Similar to plane src in
+ * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are
+ * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped
+ * damage clips, it is strongly discouraged.
+ *
+ * Drivers that are interested in damage interface for plane should enable
+ * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
+ * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
+ * drm_atomic_helper_damage_iter_next() helper iterator function to get damage
+ * rectangles clipped to &drm_plane_state.src.
+ */
+
+static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
+                                     struct drm_mode_rect *dest,
+                                     uint32_t num_clips, uint32_t src_inc)
+{
+       while (num_clips > 0) {
+               dest->x1 = src->x1;
+               dest->y1 = src->y1;
+               dest->x2 = src->x2;
+               dest->y2 = src->y2;
+               src += src_inc;
+               dest++;
+               num_clips--;
+       }
+}
+
+/**
+ * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.
+ * @plane: Plane on which to enable damage clips property.
+ *
+ * This function lets driver to enable the damage clips property on a plane.
+ */
+void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
+{
+       struct drm_device *dev = plane->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
+                                  0);
+}
+EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
+
+/**
+ * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
+ * @state: The driver state object.
+ * @plane_state: Plane state for which to verify damage.
+ *
+ * This helper function makes sure that damage from plane state is discarded
+ * for full modeset. If there are more reasons a driver would want to do a full
+ * plane update rather than processing individual damage regions, then those
+ * cases should be taken care of here.
+ *
+ * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
+ * full plane update should happen. It also ensure helper iterator will return
+ * &drm_plane_state.src as damage.
+ */
+void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
+                                         struct drm_plane_state *plane_state)
+{
+       struct drm_crtc_state *crtc_state;
+
+       if (plane_state->crtc) {
+               crtc_state = drm_atomic_get_new_crtc_state(state,
+                                                          plane_state->crtc);
+
+               if (WARN_ON(!crtc_state))
+                       return;
+
+               if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+                       drm_property_blob_put(plane_state->fb_damage_clips);
+                       plane_state->fb_damage_clips = NULL;
+               }
+       }
+}
+EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
+
+/**
+ * drm_atomic_helper_dirtyfb - Helper for dirtyfb.
+ * @fb: DRM framebuffer.
+ * @file_priv: Drm file for the ioctl call.
+ * @flags: Dirty fb annotate flags.
+ * @color: Color for annotate fill.
+ * @clips: Dirty region.
+ * @num_clips: Count of clip in clips.
+ *
+ * A helper to implement &drm_framebuffer_funcs.dirty using damage interface
+ * during plane update. If num_clips is 0 then this helper will do a full plane
+ * update. This is the same behaviour expected by DIRTFB IOCTL.
+ *
+ * Note that this helper is blocking implementation. This is what current
+ * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
+ * to rate-limit userspace and make sure its rendering doesn't get ahead of
+ * uploading new data too much.
+ *
+ * Return: Zero on success, negative errno on failure.
+ */
+int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
+                             struct drm_file *file_priv, unsigned int flags,
+                             unsigned int color, struct drm_clip_rect *clips,
+                             unsigned int num_clips)
+{
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_property_blob *damage = NULL;
+       struct drm_mode_rect *rects = NULL;
+       struct drm_atomic_state *state;
+       struct drm_plane *plane;
+       int ret = 0;
+
+       /*
+        * When called from ioctl, we are interruptable, but not when called
+        * internally (ie. defio worker)
+        */
+       drm_modeset_acquire_init(&ctx,
+               file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
+
+       state = drm_atomic_state_alloc(fb->dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       state->acquire_ctx = &ctx;
+
+       if (clips) {
+               uint32_t inc = 1;
+
+               if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
+                       inc = 2;
+                       num_clips /= 2;
+               }
+
+               rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
+               if (!rects) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               convert_clip_rect_to_rect(clips, rects, num_clips, inc);
+               damage = drm_property_create_blob(fb->dev,
+                                                 num_clips * sizeof(*rects),
+                                                 rects);
+               if (IS_ERR(damage)) {
+                       ret = PTR_ERR(damage);
+                       damage = NULL;
+                       goto out;
+               }
+       }
+
+retry:
+       drm_for_each_plane(plane, fb->dev) {
+               struct drm_plane_state *plane_state;
+
+               if (plane->state->fb != fb)
+                       continue;
+
+               plane_state = drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state)) {
+                       ret = PTR_ERR(plane_state);
+                       goto out;
+               }
+
+               drm_property_replace_blob(&plane_state->fb_damage_clips,
+                                         damage);
+       }
+
+       ret = drm_atomic_commit(state);
+
+out:
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               ret = drm_modeset_backoff(&ctx);
+               if (!ret)
+                       goto retry;
+       }
+
+       drm_property_blob_put(damage);
+       kfree(rects);
+       drm_atomic_state_put(state);
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
+       return ret;
+
+}
+EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
+
+/**
+ * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
+ * @iter: The iterator to initialize.
+ * @old_state: Old plane state for validation.
+ * @state: Plane state from which to iterate the damage clips.
+ *
+ * Initialize an iterator, which clips plane damage
+ * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
+ * returns full plane src in case damage is not present because either
+ * user-space didn't sent or driver discarded it (it want to do full plane
+ * update). Currently this iterator returns full plane src in case plane src
+ * changed but that can be changed in future to return damage.
+ *
+ * For the case when plane is not visible or plane update should not happen the
+ * first call to iter_next will return false. Note that this helper use clipped
+ * &drm_plane_state.src, so driver calling this helper should have called
+ * drm_atomic_helper_check_plane_state() earlier.
+ */
+void
+drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
+                                  const struct drm_plane_state *old_state,
+                                  const struct drm_plane_state *state)
+{
+       memset(iter, 0, sizeof(*iter));
+
+       if (!state || !state->crtc || !state->fb || !state->visible)
+               return;
+
+       iter->clips = drm_helper_get_plane_damage_clips(state);
+       iter->num_clips = drm_plane_get_damage_clips_count(state);
+
+       /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
+       iter->plane_src.x1 = state->src.x1 >> 16;
+       iter->plane_src.y1 = state->src.y1 >> 16;
+       iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
+       iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
+
+       if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
+               iter->clips = 0;
+               iter->num_clips = 0;
+               iter->full_update = true;
+       }
+}
+EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
+
+/**
+ * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
+ * @iter: The iterator to advance.
+ * @rect: Return a rectangle in fb coordinate clipped to plane src.
+ *
+ * Since plane src is in 16.16 fixed point and damage clips are whole number,
+ * this iterator round off clips that intersect with plane src. Round down for
+ * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
+ * off for full plane src, in case it's returned as damage. This iterator will
+ * skip damage clips outside of plane src.
+ *
+ * Return: True if the output is valid, false if reached the end.
+ *
+ * If the first call to iterator next returns false then it means no need to
+ * update the plane.
+ */
+bool
+drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
+                                  struct drm_rect *rect)
+{
+       bool ret = false;
+
+       if (iter->full_update) {
+               *rect = iter->plane_src;
+               iter->full_update = false;
+               return true;
+       }
+
+       while (iter->curr_clip < iter->num_clips) {
+               *rect = iter->clips[iter->curr_clip];
+               iter->curr_clip++;
+
+               if (drm_rect_intersect(rect, &iter->plane_src)) {
+                       ret = true;
+                       break;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
index 373bd4c2b698ba1ebcb3b4572cb6c84b3ce448fe..f8468eae05033f7c90242e2203eaacc306fe37ff 100644 (file)
@@ -32,6 +32,8 @@
 #include <drm/drm_debugfs.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_auth.h>
+#include <drm/drm_gem.h>
 #include <drm/drmP.h>
 
 #include "drm_internal.h"
  * Initialization, etc.
  **************************************************/
 
+static int drm_name_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_minor *minor = node->minor;
+       struct drm_device *dev = minor->dev;
+       struct drm_master *master;
+
+       mutex_lock(&dev->master_mutex);
+       master = dev->master;
+       seq_printf(m, "%s", dev->driver->name);
+       if (dev->dev)
+               seq_printf(m, " dev=%s", dev_name(dev->dev));
+       if (master && master->unique)
+               seq_printf(m, " master=%s", master->unique);
+       if (dev->unique)
+               seq_printf(m, " unique=%s", dev->unique);
+       seq_printf(m, "\n");
+       mutex_unlock(&dev->master_mutex);
+
+       return 0;
+}
+
+static int drm_clients_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_file *priv;
+       kuid_t uid;
+
+       seq_printf(m,
+                  "%20s %5s %3s master a %5s %10s\n",
+                  "command",
+                  "pid",
+                  "dev",
+                  "uid",
+                  "magic");
+
+       /* dev->filelist is sorted youngest first, but we want to present
+        * oldest first (i.e. kernel, servers, clients), so walk backwardss.
+        */
+       mutex_lock(&dev->filelist_mutex);
+       list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
+               struct task_struct *task;
+
+               rcu_read_lock(); /* locks pid_task()->comm */
+               task = pid_task(priv->pid, PIDTYPE_PID);
+               uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID;
+               seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
+                          task ? task->comm : "<unknown>",
+                          pid_vnr(priv->pid),
+                          priv->minor->index,
+                          drm_is_current_master(priv) ? 'y' : 'n',
+                          priv->authenticated ? 'y' : 'n',
+                          from_kuid_munged(seq_user_ns(m), uid),
+                          priv->magic);
+               rcu_read_unlock();
+       }
+       mutex_unlock(&dev->filelist_mutex);
+       return 0;
+}
+
+static int drm_gem_one_name_info(int id, void *ptr, void *data)
+{
+       struct drm_gem_object *obj = ptr;
+       struct seq_file *m = data;
+
+       seq_printf(m, "%6d %8zd %7d %8d\n",
+                  obj->name, obj->size,
+                  obj->handle_count,
+                  kref_read(&obj->refcount));
+       return 0;
+}
+
+static int drm_gem_name_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;
+
+       seq_printf(m, "  name     size handles refcount\n");
+
+       mutex_lock(&dev->object_name_lock);
+       idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m);
+       mutex_unlock(&dev->object_name_lock);
+
+       return 0;
+}
+
 static const struct drm_info_list drm_debugfs_list[] = {
        {"name", drm_name_info, 0},
        {"clients", drm_clients_info, 0},
index 8a718f85079a0d55d10e41f3d9e907a090adbbda..b15cee85b702b257f0ebdd19c3d2f6e4995207fc 100644 (file)
@@ -424,8 +424,6 @@ void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name,
        aux->cec.parent = parent;
        INIT_DELAYED_WORK(&aux->cec.unregister_work,
                          drm_dp_cec_unregister_work);
-
-       drm_dp_cec_set_edid(aux, NULL);
 }
 EXPORT_SYMBOL(drm_dp_cec_register_connector);
 
index 37c01b6076ec42abf14a34128eb4409649d399e7..2d6c491a0542ef02655b8bee98a52644000703b3 100644 (file)
@@ -1352,3 +1352,95 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
        return 0;
 }
 EXPORT_SYMBOL(drm_dp_read_desc);
+
+/**
+ * DRM DP Helpers for DSC
+ */
+u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
+                                  bool is_edp)
+{
+       u8 slice_cap1 = dsc_dpcd[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT];
+
+       if (is_edp) {
+               /* For eDP, register DSC_SLICE_CAPABILITIES_1 gives slice count */
+               if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK)
+                       return 4;
+               if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK)
+                       return 2;
+               if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK)
+                       return 1;
+       } else {
+               /* For DP, use values from DSC_SLICE_CAP_1 and DSC_SLICE_CAP2 */
+               u8 slice_cap2 = dsc_dpcd[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT];
+
+               if (slice_cap2 & DP_DSC_24_PER_DP_DSC_SINK)
+                       return 24;
+               if (slice_cap2 & DP_DSC_20_PER_DP_DSC_SINK)
+                       return 20;
+               if (slice_cap2 & DP_DSC_16_PER_DP_DSC_SINK)
+                       return 16;
+               if (slice_cap1 & DP_DSC_12_PER_DP_DSC_SINK)
+                       return 12;
+               if (slice_cap1 & DP_DSC_10_PER_DP_DSC_SINK)
+                       return 10;
+               if (slice_cap1 & DP_DSC_8_PER_DP_DSC_SINK)
+                       return 8;
+               if (slice_cap1 & DP_DSC_6_PER_DP_DSC_SINK)
+                       return 6;
+               if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK)
+                       return 4;
+               if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK)
+                       return 2;
+               if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK)
+                       return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count);
+
+u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
+{
+       u8 line_buf_depth = dsc_dpcd[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT];
+
+       switch (line_buf_depth & DP_DSC_LINE_BUF_BIT_DEPTH_MASK) {
+       case DP_DSC_LINE_BUF_BIT_DEPTH_9:
+               return 9;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_10:
+               return 10;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_11:
+               return 11;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_12:
+               return 12;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_13:
+               return 13;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_14:
+               return 14;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_15:
+               return 15;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_16:
+               return 16;
+       case DP_DSC_LINE_BUF_BIT_DEPTH_8:
+               return 8;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_dp_dsc_sink_line_buf_depth);
+
+int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
+                                        u8 dsc_bpc[3])
+{
+       int num_bpc = 0;
+       u8 color_depth = dsc_dpcd[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT];
+
+       if (color_depth & DP_DSC_12_BPC)
+               dsc_bpc[num_bpc++] = 12;
+       if (color_depth & DP_DSC_10_BPC)
+               dsc_bpc[num_bpc++] = 10;
+       if (color_depth & DP_DSC_8_BPC)
+               dsc_bpc[num_bpc++] = 8;
+
+       return num_bpc;
+}
+EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs);
index 0e0df398222d1e0220b4388d0513bf73f66164ae..5294145569625df3e8d7fc05c5ccc5e405ef62b1 100644 (file)
@@ -2572,9 +2572,16 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
 EXPORT_SYMBOL(drm_dp_mst_get_edid);
 
 /**
- * drm_dp_find_vcpi_slots() - find slots for this PBN value
+ * drm_dp_find_vcpi_slots() - Find VCPI slots for this PBN value
  * @mgr: manager to use
  * @pbn: payload bandwidth to convert into slots.
+ *
+ * Calculate the number of VCPI slots that will be required for the given PBN
+ * value. This function is deprecated, and should not be used in atomic
+ * drivers.
+ *
+ * RETURNS:
+ * The total slots required for this port, or error.
  */
 int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
                           int pbn)
index 36e8e9cbec5270b5c14c9328db279c14e16fe136..12e5e2be7890e39952947f85594675093f4e8eb9 100644 (file)
@@ -476,8 +476,6 @@ static void drm_fs_inode_free(struct inode *inode)
  * The initial ref-count of the object is 1. Use drm_dev_get() and
  * drm_dev_put() to take and drop further ref-counts.
  *
- * Note that for purely virtual devices @parent can be NULL.
- *
  * Drivers that do not want to allocate their own device struct
  * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
  * that do embed &struct drm_device it must be placed first in the overall
@@ -502,6 +500,8 @@ int drm_dev_init(struct drm_device *dev,
                return -ENODEV;
        }
 
+       BUG_ON(!parent);
+
        kref_init(&dev->ref);
        dev->dev = parent;
        dev->driver = driver;
@@ -556,9 +556,7 @@ int drm_dev_init(struct drm_device *dev,
                }
        }
 
-       /* Use the parent device name as DRM device unique identifier, but fall
-        * back to the driver name for virtual devices like vgem. */
-       ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
+       ret = drm_dev_set_unique(dev, dev_name(parent));
        if (ret)
                goto err_setunique;
 
@@ -706,19 +704,6 @@ void drm_dev_put(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_dev_put);
 
-/**
- * drm_dev_unref - Drop reference of a DRM device
- * @dev: device to drop reference of or NULL
- *
- * This is a compatibility alias for drm_dev_put() and should not be used by new
- * code.
- */
-void drm_dev_unref(struct drm_device *dev)
-{
-       drm_dev_put(dev);
-}
-EXPORT_SYMBOL(drm_dev_unref);
-
 static int create_compat_control_link(struct drm_device *dev)
 {
        struct drm_minor *minor;
@@ -975,14 +960,12 @@ static void drm_core_exit(void)
        drm_sysfs_destroy();
        idr_destroy(&drm_minors_idr);
        drm_connector_ida_destroy();
-       drm_global_release();
 }
 
 static int __init drm_core_init(void)
 {
        int ret;
 
-       drm_global_init();
        drm_connector_ida_init();
        idr_init(&drm_minors_idr);
 
diff --git a/drivers/gpu/drm/drm_dsc.c b/drivers/gpu/drm/drm_dsc.c
new file mode 100644 (file)
index 0000000..bc2b23a
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corp
+ *
+ * Author:
+ * Manasi Navare <manasi.d.navare@intel.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/byteorder/generic.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_dsc.h>
+
+/**
+ * DOC: dsc helpers
+ *
+ * These functions contain some common logic and helpers to deal with VESA
+ * Display Stream Compression standard required for DSC on Display Port/eDP or
+ * MIPI display interfaces.
+ */
+
+/**
+ * drm_dsc_dp_pps_header_init() - Initializes the PPS Header
+ * for DisplayPort as per the DP 1.4 spec.
+ * @pps_sdp: Secondary data packet for DSC Picture Parameter Set
+ */
+void drm_dsc_dp_pps_header_init(struct drm_dsc_pps_infoframe *pps_sdp)
+{
+       memset(&pps_sdp->pps_header, 0, sizeof(pps_sdp->pps_header));
+
+       pps_sdp->pps_header.HB1 = DP_SDP_PPS;
+       pps_sdp->pps_header.HB2 = DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1;
+}
+EXPORT_SYMBOL(drm_dsc_dp_pps_header_init);
+
+/**
+ * drm_dsc_pps_infoframe_pack() - Populates the DSC PPS infoframe
+ * using the DSC configuration parameters in the order expected
+ * by the DSC Display Sink device. For the DSC, the sink device
+ * expects the PPS payload in the big endian format for the fields
+ * that span more than 1 byte.
+ *
+ * @pps_sdp:
+ * Secondary data packet for DSC Picture Parameter Set
+ * @dsc_cfg:
+ * DSC Configuration data filled by driver
+ */
+void drm_dsc_pps_infoframe_pack(struct drm_dsc_pps_infoframe *pps_sdp,
+                               const struct drm_dsc_config *dsc_cfg)
+{
+       int i;
+
+       /* Protect against someone accidently changing struct size */
+       BUILD_BUG_ON(sizeof(pps_sdp->pps_payload) !=
+                    DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1);
+
+       memset(&pps_sdp->pps_payload, 0, sizeof(pps_sdp->pps_payload));
+
+       /* PPS 0 */
+       pps_sdp->pps_payload.dsc_version =
+               dsc_cfg->dsc_version_minor |
+               dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT;
+
+       /* PPS 1, 2 is 0 */
+
+       /* PPS 3 */
+       pps_sdp->pps_payload.pps_3 =
+               dsc_cfg->line_buf_depth |
+               dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT;
+
+       /* PPS 4 */
+       pps_sdp->pps_payload.pps_4 =
+               ((dsc_cfg->bits_per_pixel & DSC_PPS_BPP_HIGH_MASK) >>
+                DSC_PPS_MSB_SHIFT) |
+               dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT |
+               dsc_cfg->enable422 << DSC_PPS_SIMPLE422_SHIFT |
+               dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT |
+               dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT;
+
+       /* PPS 5 */
+       pps_sdp->pps_payload.bits_per_pixel_low =
+               (dsc_cfg->bits_per_pixel & DSC_PPS_LSB_MASK);
+
+       /*
+        * The DSC panel expects the PPS packet to have big endian format
+        * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert
+        * to big endian format. If format is little endian, it will swap
+        * bytes to convert to Big endian else keep it unchanged.
+        */
+
+       /* PPS 6, 7 */
+       pps_sdp->pps_payload.pic_height = cpu_to_be16(dsc_cfg->pic_height);
+
+       /* PPS 8, 9 */
+       pps_sdp->pps_payload.pic_width = cpu_to_be16(dsc_cfg->pic_width);
+
+       /* PPS 10, 11 */
+       pps_sdp->pps_payload.slice_height = cpu_to_be16(dsc_cfg->slice_height);
+
+       /* PPS 12, 13 */
+       pps_sdp->pps_payload.slice_width = cpu_to_be16(dsc_cfg->slice_width);
+
+       /* PPS 14, 15 */
+       pps_sdp->pps_payload.chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size);
+
+       /* PPS 16 */
+       pps_sdp->pps_payload.initial_xmit_delay_high =
+               ((dsc_cfg->initial_xmit_delay &
+                 DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >>
+                DSC_PPS_MSB_SHIFT);
+
+       /* PPS 17 */
+       pps_sdp->pps_payload.initial_xmit_delay_low =
+               (dsc_cfg->initial_xmit_delay & DSC_PPS_LSB_MASK);
+
+       /* PPS 18, 19 */
+       pps_sdp->pps_payload.initial_dec_delay =
+               cpu_to_be16(dsc_cfg->initial_dec_delay);
+
+       /* PPS 20 is 0 */
+
+       /* PPS 21 */
+       pps_sdp->pps_payload.initial_scale_value =
+               dsc_cfg->initial_scale_value;
+
+       /* PPS 22, 23 */
+       pps_sdp->pps_payload.scale_increment_interval =
+               cpu_to_be16(dsc_cfg->scale_increment_interval);
+
+       /* PPS 24 */
+       pps_sdp->pps_payload.scale_decrement_interval_high =
+               ((dsc_cfg->scale_decrement_interval &
+                 DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >>
+                DSC_PPS_MSB_SHIFT);
+
+       /* PPS 25 */
+       pps_sdp->pps_payload.scale_decrement_interval_low =
+               (dsc_cfg->scale_decrement_interval & DSC_PPS_LSB_MASK);
+
+       /* PPS 26[7:0], PPS 27[7:5] RESERVED */
+
+       /* PPS 27 */
+       pps_sdp->pps_payload.first_line_bpg_offset =
+               dsc_cfg->first_line_bpg_offset;
+
+       /* PPS 28, 29 */
+       pps_sdp->pps_payload.nfl_bpg_offset =
+               cpu_to_be16(dsc_cfg->nfl_bpg_offset);
+
+       /* PPS 30, 31 */
+       pps_sdp->pps_payload.slice_bpg_offset =
+               cpu_to_be16(dsc_cfg->slice_bpg_offset);
+
+       /* PPS 32, 33 */
+       pps_sdp->pps_payload.initial_offset =
+               cpu_to_be16(dsc_cfg->initial_offset);
+
+       /* PPS 34, 35 */
+       pps_sdp->pps_payload.final_offset = cpu_to_be16(dsc_cfg->final_offset);
+
+       /* PPS 36 */
+       pps_sdp->pps_payload.flatness_min_qp = dsc_cfg->flatness_min_qp;
+
+       /* PPS 37 */
+       pps_sdp->pps_payload.flatness_max_qp = dsc_cfg->flatness_max_qp;
+
+       /* PPS 38, 39 */
+       pps_sdp->pps_payload.rc_model_size =
+               cpu_to_be16(DSC_RC_MODEL_SIZE_CONST);
+
+       /* PPS 40 */
+       pps_sdp->pps_payload.rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST;
+
+       /* PPS 41 */
+       pps_sdp->pps_payload.rc_quant_incr_limit0 =
+               dsc_cfg->rc_quant_incr_limit0;
+
+       /* PPS 42 */
+       pps_sdp->pps_payload.rc_quant_incr_limit1 =
+               dsc_cfg->rc_quant_incr_limit1;
+
+       /* PPS 43 */
+       pps_sdp->pps_payload.rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST |
+               DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT;
+
+       /* PPS 44 - 57 */
+       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
+               pps_sdp->pps_payload.rc_buf_thresh[i] =
+                       dsc_cfg->rc_buf_thresh[i];
+
+       /* PPS 58 - 87 */
+       /*
+        * For DSC sink programming the RC Range parameter fields
+        * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0]
+        */
+       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+               pps_sdp->pps_payload.rc_range_parameters[i] =
+                       ((dsc_cfg->rc_range_params[i].range_min_qp <<
+                         DSC_PPS_RC_RANGE_MINQP_SHIFT) |
+                        (dsc_cfg->rc_range_params[i].range_max_qp <<
+                         DSC_PPS_RC_RANGE_MAXQP_SHIFT) |
+                        (dsc_cfg->rc_range_params[i].range_bpg_offset));
+               pps_sdp->pps_payload.rc_range_parameters[i] =
+                       cpu_to_be16(pps_sdp->pps_payload.rc_range_parameters[i]);
+       }
+
+       /* PPS 88 */
+       pps_sdp->pps_payload.native_422_420 = dsc_cfg->native_422 |
+               dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT;
+
+       /* PPS 89 */
+       pps_sdp->pps_payload.second_line_bpg_offset =
+               dsc_cfg->second_line_bpg_offset;
+
+       /* PPS 90, 91 */
+       pps_sdp->pps_payload.nsl_bpg_offset =
+               cpu_to_be16(dsc_cfg->nsl_bpg_offset);
+
+       /* PPS 92, 93 */
+       pps_sdp->pps_payload.second_line_offset_adj =
+               cpu_to_be16(dsc_cfg->second_line_offset_adj);
+
+       /* PPS 94 - 127 are O */
+}
+EXPORT_SYMBOL(drm_dsc_pps_infoframe_pack);
index fb0dfc62b1b6340521cb5edade5540ee29efc169..5b516615881a0029c54a8fad9db2696f02406b80 100644 (file)
@@ -72,7 +72,9 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
 EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
 
 /**
- * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer
+ * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel
+ * formats where values are grouped in blocks this will get you the beginning of
+ * the block
  * @fb: The framebuffer
  * @state: Which state of drm plane
  * @plane: Which plane
@@ -87,6 +89,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
        struct drm_gem_cma_object *obj;
        dma_addr_t paddr;
        u8 h_div = 1, v_div = 1;
+       u32 block_w = drm_format_info_block_width(fb->format, plane);
+       u32 block_h = drm_format_info_block_height(fb->format, plane);
+       u32 block_size = fb->format->char_per_block[plane];
+       u32 sample_x;
+       u32 sample_y;
+       u32 block_start_y;
+       u32 num_hblocks;
 
        obj = drm_fb_cma_get_gem_obj(fb, plane);
        if (!obj)
@@ -99,8 +108,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
                v_div = fb->format->vsub;
        }
 
-       paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div;
-       paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div;
+       sample_x = (state->src_x >> 16) / h_div;
+       sample_y = (state->src_y >> 16) / v_div;
+       block_start_y = (sample_y / block_h) * block_h;
+       num_hblocks = sample_x / block_w;
+
+       paddr += fb->pitches[plane] * block_start_y;
+       paddr += block_size * num_hblocks;
 
        return paddr;
 }
@@ -124,10 +138,7 @@ int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
 
        /* dev->fb_helper will indirectly point to fbdev_cma after this call */
        fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count);
-       if (IS_ERR(fbdev_cma))
-               return PTR_ERR(fbdev_cma);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(fbdev_cma);
 }
 EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init);
 
@@ -226,21 +237,3 @@ void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
                drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
 }
 EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
-
-/**
- * drm_fbdev_cma_set_suspend_unlocked - wrapper around
- *                                      drm_fb_helper_set_suspend_unlocked
- * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
- * @state: desired state, zero to resume, non-zero to suspend
- *
- * Calls drm_fb_helper_set_suspend, which is a wrapper around
- * fb_set_suspend implemented by fbdev core.
- */
-void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
-                                       bool state)
-{
-       if (fbdev_cma)
-               drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper,
-                                                  state);
-}
-EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);
index 9d64f874f965be1a74970997f3be5ec07df2139c..d3af098b0922320f2c8be1db7d779ae91538618d 100644 (file)
@@ -1635,6 +1635,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
        if (var->pixclock != 0 || in_dbg_master())
                return -EINVAL;
 
+       if ((drm_format_info_block_width(fb->format, 0) > 1) ||
+           (drm_format_info_block_height(fb->format, 0) > 1))
+               return -EINVAL;
+
        /*
         * Changes struct fb_var_screeninfo are currently not pushed back
         * to KMS, hence fail if different settings are requested.
@@ -1952,6 +1956,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 {
        struct drm_framebuffer *fb = fb_helper->fb;
 
+       WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
+               (drm_format_info_block_height(fb->format, 0) > 1));
        info->pseudo_palette = fb_helper->pseudo_palette;
        info->var.xres_virtual = fb->width;
        info->var.yres_virtual = fb->height;
index 8aaa5e86a979ce0985c822201643768200e4a2e3..d90ee03a84c607ed713ab1539e4a9b1b5cf4d936 100644 (file)
@@ -103,8 +103,8 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  *
  * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
- * and depending on the quirk_addfb_prefer_host_byte_order flag it returns
- * little endian byte order or host byte order framebuffer formats.
+ * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
+ * it returns little endian byte order or host byte order framebuffer formats.
  */
 uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
                                     uint32_t bpp, uint32_t depth)
@@ -224,7 +224,20 @@ const struct drm_format_info *__drm_format_info(u32 format)
                { .format = DRM_FORMAT_YVYU,            .depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
                { .format = DRM_FORMAT_UYVY,            .depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
                { .format = DRM_FORMAT_VYUY,            .depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
+               { .format = DRM_FORMAT_XYUV8888,        .depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
                { .format = DRM_FORMAT_AYUV,            .depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
+               { .format = DRM_FORMAT_Y0L0,            .depth = 0,  .num_planes = 1,
+                 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+                 .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
+               { .format = DRM_FORMAT_X0L0,            .depth = 0,  .num_planes = 1,
+                 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+                 .hsub = 2, .vsub = 2, .is_yuv = true },
+               { .format = DRM_FORMAT_Y0L2,            .depth = 0,  .num_planes = 1,
+                 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+                 .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
+               { .format = DRM_FORMAT_X0L2,            .depth = 0,  .num_planes = 1,
+                 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+                 .hsub = 2, .vsub = 2, .is_yuv = true },
        };
 
        unsigned int i;
@@ -400,3 +413,65 @@ int drm_format_plane_height(int height, uint32_t format, int plane)
        return height / info->vsub;
 }
 EXPORT_SYMBOL(drm_format_plane_height);
+
+/**
+ * drm_format_info_block_width - width in pixels of block.
+ * @info: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+unsigned int drm_format_info_block_width(const struct drm_format_info *info,
+                                        int plane)
+{
+       if (!info || plane < 0 || plane >= info->num_planes)
+               return 0;
+
+       if (!info->block_w[plane])
+               return 1;
+       return info->block_w[plane];
+}
+EXPORT_SYMBOL(drm_format_info_block_width);
+
+/**
+ * drm_format_info_block_height - height in pixels of a block
+ * @info: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+unsigned int drm_format_info_block_height(const struct drm_format_info *info,
+                                         int plane)
+{
+       if (!info || plane < 0 || plane >= info->num_planes)
+               return 0;
+
+       if (!info->block_h[plane])
+               return 1;
+       return info->block_h[plane];
+}
+EXPORT_SYMBOL(drm_format_info_block_height);
+
+/**
+ * drm_format_info_min_pitch - computes the minimum required pitch in bytes
+ * @info: pixel format info
+ * @plane: plane index
+ * @buffer_width: buffer width in pixels
+ *
+ * Returns:
+ * The minimum required pitch in bytes for a buffer by taking into consideration
+ * the pixel format information and the buffer width.
+ */
+uint64_t drm_format_info_min_pitch(const struct drm_format_info *info,
+                                  int plane, unsigned int buffer_width)
+{
+       if (!info || plane < 0 || plane >= info->num_planes)
+               return 0;
+
+       return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
+                           drm_format_info_block_width(info, plane) *
+                           drm_format_info_block_height(info, plane));
+}
+EXPORT_SYMBOL(drm_format_info_min_pitch);
index 3bf729d0aae5899e1bca8dbd5783bbc38f899c73..fcaea8f50513d845b8d736d7d3df0092dc33d67b 100644 (file)
@@ -195,20 +195,26 @@ static int framebuffer_check(struct drm_device *dev,
        for (i = 0; i < info->num_planes; i++) {
                unsigned int width = fb_plane_width(r->width, info, i);
                unsigned int height = fb_plane_height(r->height, info, i);
-               unsigned int cpp = info->cpp[i];
+               unsigned int block_size = info->char_per_block[i];
+               u64 min_pitch = drm_format_info_min_pitch(info, i, width);
+
+               if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
+                       DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
+                       return -EINVAL;
+               }
 
                if (!r->handles[i]) {
                        DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
                        return -EINVAL;
                }
 
-               if ((uint64_t) width * cpp > UINT_MAX)
+               if (min_pitch > UINT_MAX)
                        return -ERANGE;
 
                if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
                        return -ERANGE;
 
-               if (r->pitches[i] < width * cpp) {
+               if (block_size && r->pitches[i] < min_pitch) {
                        DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
                        return -EINVAL;
                }
@@ -317,6 +323,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
 
        return fb;
 }
+EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create);
 
 /**
  * drm_mode_addfb2 - add an FB to the graphics configuration
index 512078ebd97b92f143d63f2af16fbe79ea6c7554..8b55ece97967f43d0861d6d5f6dfc043f00b9a39 100644 (file)
@@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
        struct drm_gem_object *obj = ptr;
        struct drm_device *dev = obj->dev;
 
-       if (dev->driver->gem_close_object)
+       if (obj->funcs && obj->funcs->close)
+               obj->funcs->close(obj, file_priv);
+       else if (dev->driver->gem_close_object)
                dev->driver->gem_close_object(obj, file_priv);
 
        if (drm_core_check_feature(dev, DRIVER_PRIME))
@@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
        if (ret)
                goto err_remove;
 
-       if (dev->driver->gem_open_object) {
+       if (obj->funcs && obj->funcs->open) {
+               ret = obj->funcs->open(obj, file_priv);
+               if (ret)
+                       goto err_revoke;
+       } else if (dev->driver->gem_open_object) {
                ret = dev->driver->gem_open_object(obj, file_priv);
                if (ret)
                        goto err_revoke;
@@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
                container_of(kref, struct drm_gem_object, refcount);
        struct drm_device *dev = obj->dev;
 
-       if (dev->driver->gem_free_object_unlocked) {
+       if (obj->funcs) {
+               obj->funcs->free(obj);
+       } else if (dev->driver->gem_free_object_unlocked) {
                dev->driver->gem_free_object_unlocked(obj);
        } else if (dev->driver->gem_free_object) {
                WARN_ON(!mutex_is_locked(&dev->struct_mutex));
@@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
 
        dev = obj->dev;
 
-       if (dev->driver->gem_free_object_unlocked) {
-               kref_put(&obj->refcount, drm_gem_object_free);
-       } else {
+       if (dev->driver->gem_free_object) {
                might_lock(&dev->struct_mutex);
                if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
                                &dev->struct_mutex))
                        mutex_unlock(&dev->struct_mutex);
+       } else {
+               kref_put(&obj->refcount, drm_gem_object_free);
        }
 }
 EXPORT_SYMBOL(drm_gem_object_put_unlocked);
@@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
        if (obj_size < vma->vm_end - vma->vm_start)
                return -EINVAL;
 
-       if (!dev->driver->gem_vm_ops)
+       if (obj->funcs && obj->funcs->vm_ops)
+               vma->vm_ops = obj->funcs->vm_ops;
+       else if (dev->driver->gem_vm_ops)
+               vma->vm_ops = dev->driver->gem_vm_ops;
+       else
                return -EINVAL;
 
        vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
-       vma->vm_ops = dev->driver->gem_vm_ops;
        vma->vm_private_data = obj;
        vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
        vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
@@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
        drm_printf_indent(p, indent, "imported=%s\n",
                          obj->import_attach ? "yes" : "no");
 
-       if (obj->dev->driver->gem_print_info)
+       if (obj->funcs && obj->funcs->print_info)
+               obj->funcs->print_info(p, indent, obj);
+       else if (obj->dev->driver->gem_print_info)
                obj->dev->driver->gem_print_info(p, indent, obj);
 }
+
+/**
+ * drm_gem_pin - Pin backing buffer in memory
+ * @obj: GEM object
+ *
+ * Make sure the backing buffer is pinned in memory.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_pin(struct drm_gem_object *obj)
+{
+       if (obj->funcs && obj->funcs->pin)
+               return obj->funcs->pin(obj);
+       else if (obj->dev->driver->gem_prime_pin)
+               return obj->dev->driver->gem_prime_pin(obj);
+       else
+               return 0;
+}
+EXPORT_SYMBOL(drm_gem_pin);
+
+/**
+ * drm_gem_unpin - Unpin backing buffer from memory
+ * @obj: GEM object
+ *
+ * Relax the requirement that the backing buffer is pinned in memory.
+ */
+void drm_gem_unpin(struct drm_gem_object *obj)
+{
+       if (obj->funcs && obj->funcs->unpin)
+               obj->funcs->unpin(obj);
+       else if (obj->dev->driver->gem_prime_unpin)
+               obj->dev->driver->gem_prime_unpin(obj);
+}
+EXPORT_SYMBOL(drm_gem_unpin);
+
+/**
+ * drm_gem_vmap - Map buffer into kernel virtual address space
+ * @obj: GEM object
+ *
+ * Returns:
+ * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
+ * error code on failure.
+ */
+void *drm_gem_vmap(struct drm_gem_object *obj)
+{
+       void *vaddr;
+
+       if (obj->funcs && obj->funcs->vmap)
+               vaddr = obj->funcs->vmap(obj);
+       else if (obj->dev->driver->gem_prime_vmap)
+               vaddr = obj->dev->driver->gem_prime_vmap(obj);
+       else
+               vaddr = ERR_PTR(-EOPNOTSUPP);
+
+       if (!vaddr)
+               vaddr = ERR_PTR(-ENOMEM);
+
+       return vaddr;
+}
+EXPORT_SYMBOL(drm_gem_vmap);
+
+/**
+ * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
+ * @obj: GEM object
+ * @vaddr: Virtual address (can be NULL)
+ */
+void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       if (!vaddr)
+               return;
+
+       if (obj->funcs && obj->funcs->vunmap)
+               obj->funcs->vunmap(obj, vaddr);
+       else if (obj->dev->driver->gem_prime_vunmap)
+               obj->dev->driver->gem_prime_vunmap(obj, vaddr);
+}
+EXPORT_SYMBOL(drm_gem_vunmap);
index 1d2ced882b6695d6723793e4d0e95577be2f07ec..cc26625b4b33b26f2d04d8884e977d56e5574cb4 100644 (file)
@@ -176,6 +176,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv,
  *
  * This function frees the backing memory of the CMA GEM object, cleans up the
  * GEM object state and frees the memory used to store the object itself.
+ * If the buffer is imported and the virtual address is set, it is released.
  * Drivers using the CMA helpers should set this as their
  * &drm_driver.gem_free_object_unlocked callback.
  */
@@ -189,6 +190,8 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
                dma_free_wc(gem_obj->dev->dev, cma_obj->base.size,
                            cma_obj->vaddr, cma_obj->paddr);
        } else if (gem_obj->import_attach) {
+               if (cma_obj->vaddr)
+                       dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr);
                drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
        }
 
@@ -575,3 +578,86 @@ void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
        /* Nothing to do */
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vunmap);
+
+static const struct drm_gem_object_funcs drm_cma_gem_default_funcs = {
+       .free = drm_gem_cma_free_object,
+       .print_info = drm_gem_cma_print_info,
+       .get_sg_table = drm_gem_cma_prime_get_sg_table,
+       .vmap = drm_gem_cma_prime_vmap,
+       .vm_ops = &drm_gem_cma_vm_ops,
+};
+
+/**
+ * drm_cma_gem_create_object_default_funcs - Create a CMA GEM object with a
+ *                                           default function table
+ * @dev: DRM device
+ * @size: Size of the object to allocate
+ *
+ * This sets the GEM object functions to the default CMA helper functions.
+ * This function can be used as the &drm_driver.gem_create_object callback.
+ *
+ * Returns:
+ * A pointer to a allocated GEM object or an error pointer on failure.
+ */
+struct drm_gem_object *
+drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size)
+{
+       struct drm_gem_cma_object *cma_obj;
+
+       cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
+       if (!cma_obj)
+               return NULL;
+
+       cma_obj->base.funcs = &drm_cma_gem_default_funcs;
+
+       return &cma_obj->base;
+}
+EXPORT_SYMBOL(drm_cma_gem_create_object_default_funcs);
+
+/**
+ * drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's
+ *     scatter/gather table and get the virtual address of the buffer
+ * @dev: DRM device
+ * @attach: DMA-BUF attachment
+ * @sgt: Scatter/gather table of pinned pages
+ *
+ * This function imports a scatter/gather table using
+ * drm_gem_cma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel
+ * virtual address. This ensures that a CMA GEM object always has its virtual
+ * address set. This address is released when the object is freed.
+ *
+ * This function can be used as the &drm_driver.gem_prime_import_sg_table
+ * callback. The DRM_GEM_CMA_VMAP_DRIVER_OPS() macro provides a shortcut to set
+ * the necessary DRM driver operations.
+ *
+ * Returns:
+ * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
+ * error code on failure.
+ */
+struct drm_gem_object *
+drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *dev,
+                                      struct dma_buf_attachment *attach,
+                                      struct sg_table *sgt)
+{
+       struct drm_gem_cma_object *cma_obj;
+       struct drm_gem_object *obj;
+       void *vaddr;
+
+       vaddr = dma_buf_vmap(attach->dmabuf);
+       if (!vaddr) {
+               DRM_ERROR("Failed to vmap PRIME buffer\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
+       if (IS_ERR(obj)) {
+               dma_buf_vunmap(attach->dmabuf, vaddr);
+               return obj;
+       }
+
+       cma_obj = to_drm_gem_cma_obj(obj);
+       cma_obj->vaddr = vaddr;
+
+       return obj;
+}
+EXPORT_SYMBOL(drm_gem_cma_prime_import_sg_table_vmap);
index ded7a379ac3576faf1bba2dcf72fe6fb20b64f41..acb466d25afc28b545240149710d425ba094e9af 100644 (file)
@@ -171,7 +171,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
                }
 
                min_size = (height - 1) * mode_cmd->pitches[i]
-                        + width * info->cpp[i]
+                        + drm_format_info_min_pitch(info, i, width)
                         + mode_cmd->offsets[i];
 
                if (objs[i]->size < min_size) {
diff --git a/drivers/gpu/drm/drm_global.c b/drivers/gpu/drm/drm_global.c
deleted file mode 100644 (file)
index 5799e27..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR MIT
-/**************************************************************************
- *
- * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-/*
- * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
- */
-
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <drm/drm_global.h>
-
-struct drm_global_item {
-       struct mutex mutex;
-       void *object;
-       int refcount;
-};
-
-static struct drm_global_item glob[DRM_GLOBAL_NUM];
-
-void drm_global_init(void)
-{
-       int i;
-
-       for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
-               struct drm_global_item *item = &glob[i];
-               mutex_init(&item->mutex);
-               item->object = NULL;
-               item->refcount = 0;
-       }
-}
-
-void drm_global_release(void)
-{
-       int i;
-       for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
-               struct drm_global_item *item = &glob[i];
-               BUG_ON(item->object != NULL);
-               BUG_ON(item->refcount != 0);
-       }
-}
-
-/**
- * drm_global_item_ref - Initialize and acquire reference to memory
- * object
- * @ref: Object for initialization
- *
- * This initializes a memory object, allocating memory and calling the
- * .init() hook. Further calls will increase the reference count for
- * that item.
- *
- * Returns:
- * Zero on success, non-zero otherwise.
- */
-int drm_global_item_ref(struct drm_global_reference *ref)
-{
-       int ret = 0;
-       struct drm_global_item *item = &glob[ref->global_type];
-
-       mutex_lock(&item->mutex);
-       if (item->refcount == 0) {
-               ref->object = kzalloc(ref->size, GFP_KERNEL);
-               if (unlikely(ref->object == NULL)) {
-                       ret = -ENOMEM;
-                       goto error_unlock;
-               }
-               ret = ref->init(ref);
-               if (unlikely(ret != 0))
-                       goto error_free;
-
-               item->object = ref->object;
-       } else {
-               ref->object = item->object;
-       }
-
-       ++item->refcount;
-       mutex_unlock(&item->mutex);
-       return 0;
-
-error_free:
-       kfree(ref->object);
-       ref->object = NULL;
-error_unlock:
-       mutex_unlock(&item->mutex);
-       return ret;
-}
-EXPORT_SYMBOL(drm_global_item_ref);
-
-/**
- * drm_global_item_unref - Drop reference to memory
- * object
- * @ref: Object being removed
- *
- * Drop a reference to the memory object and eventually call the
- * release() hook.  The allocated object should be dropped in the
- * release() hook or before calling this function
- *
- */
-
-void drm_global_item_unref(struct drm_global_reference *ref)
-{
-       struct drm_global_item *item = &glob[ref->global_type];
-
-       mutex_lock(&item->mutex);
-       BUG_ON(item->refcount == 0);
-       BUG_ON(ref->object != item->object);
-       if (--item->refcount == 0) {
-               ref->release(ref);
-               item->object = NULL;
-       }
-       mutex_unlock(&item->mutex);
-}
-EXPORT_SYMBOL(drm_global_item_unref);
-
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
deleted file mode 100644 (file)
index 6b68e90..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * \file drm_info.c
- * DRM info file implementations
- *
- * \author Ben Gamari <bgamari@gmail.com>
- */
-
-/*
- * Created: Sun Dec 21 13:09:50 2008 by bgamari@gmail.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * Copyright 2008 Ben Gamari <bgamari@gmail.com>
- * 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 (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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <linux/seq_file.h>
-#include <drm/drmP.h>
-#include <drm/drm_gem.h>
-
-#include "drm_internal.h"
-#include "drm_legacy.h"
-
-/**
- * Called when "/proc/dri/.../name" is read.
- *
- * Prints the device name together with the bus id if available.
- */
-int drm_name_info(struct seq_file *m, void *data)
-{
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_minor *minor = node->minor;
-       struct drm_device *dev = minor->dev;
-       struct drm_master *master;
-
-       mutex_lock(&dev->master_mutex);
-       master = dev->master;
-       seq_printf(m, "%s", dev->driver->name);
-       if (dev->dev)
-               seq_printf(m, " dev=%s", dev_name(dev->dev));
-       if (master && master->unique)
-               seq_printf(m, " master=%s", master->unique);
-       if (dev->unique)
-               seq_printf(m, " unique=%s", dev->unique);
-       seq_printf(m, "\n");
-       mutex_unlock(&dev->master_mutex);
-
-       return 0;
-}
-
-/**
- * Called when "/proc/dri/.../clients" is read.
- *
- */
-int drm_clients_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_file *priv;
-       kuid_t uid;
-
-       seq_printf(m,
-                  "%20s %5s %3s master a %5s %10s\n",
-                  "command",
-                  "pid",
-                  "dev",
-                  "uid",
-                  "magic");
-
-       /* dev->filelist is sorted youngest first, but we want to present
-        * oldest first (i.e. kernel, servers, clients), so walk backwardss.
-        */
-       mutex_lock(&dev->filelist_mutex);
-       list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
-               struct task_struct *task;
-
-               rcu_read_lock(); /* locks pid_task()->comm */
-               task = pid_task(priv->pid, PIDTYPE_PID);
-               uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID;
-               seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
-                          task ? task->comm : "<unknown>",
-                          pid_vnr(priv->pid),
-                          priv->minor->index,
-                          drm_is_current_master(priv) ? 'y' : 'n',
-                          priv->authenticated ? 'y' : 'n',
-                          from_kuid_munged(seq_user_ns(m), uid),
-                          priv->magic);
-               rcu_read_unlock();
-       }
-       mutex_unlock(&dev->filelist_mutex);
-       return 0;
-}
-
-static int drm_gem_one_name_info(int id, void *ptr, void *data)
-{
-       struct drm_gem_object *obj = ptr;
-       struct seq_file *m = data;
-
-       seq_printf(m, "%6d %8zd %7d %8d\n",
-                  obj->name, obj->size,
-                  obj->handle_count,
-                  kref_read(&obj->refcount));
-       return 0;
-}
-
-int drm_gem_name_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;
-
-       seq_printf(m, "  name     size handles refcount\n");
-
-       mutex_lock(&dev->object_name_lock);
-       idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m);
-       mutex_unlock(&dev->object_name_lock);
-
-       return 0;
-}
index 51e06defc8d8a0ea7fd2eb770a85dbce94d2b3b7..d9caf205e0b33448f55e3c275f6c864de4881856 100644 (file)
@@ -56,11 +56,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
 struct drm_minor *drm_minor_acquire(unsigned int minor_id);
 void drm_minor_release(struct drm_minor *minor);
 
-/* drm_info.c */
-int drm_name_info(struct seq_file *m, void *data);
-int drm_clients_info(struct seq_file *m, void* data);
-int drm_gem_name_info(struct seq_file *m, void *data);
-
 /* drm_vblank.c */
 void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe);
 void drm_vblank_cleanup(struct drm_device *dev);
index 94bd872d56c48b24512ef660849237781e6316c0..7e6746b2d704c588db58f950461d293d4a1fd018 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/pci.h>
 #include <linux/export.h>
+#include <linux/nospec.h>
 
 /**
  * DOC: getunique and setversion story
@@ -800,13 +801,17 @@ long drm_ioctl(struct file *filp,
 
        if (is_driver_ioctl) {
                /* driver ioctl */
-               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+               unsigned int index = nr - DRM_COMMAND_BASE;
+
+               if (index >= dev->driver->num_ioctls)
                        goto err_i1;
-               ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+               index = array_index_nospec(index, dev->driver->num_ioctls);
+               ioctl = &dev->driver->ioctls[index];
        } else {
                /* core ioctl */
                if (nr >= DRM_CORE_IOCTL_COUNT)
                        goto err_i1;
+               nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
                ioctl = &drm_ioctls[nr];
        }
 
@@ -888,6 +893,7 @@ bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
 
        if (nr >= DRM_CORE_IOCTL_COUNT)
                return false;
+       nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
 
        *flags = drm_ioctls[nr].flags;
        return true;
index c61680ad962d9ef3189b476fbec507eac8a2a459..99cba8ea5d825596d7d86120f2ad6346926c64ba 100644 (file)
@@ -39,7 +39,6 @@ struct drm_master *drm_lease_owner(struct drm_master *master)
                master = master->lessor;
        return master;
 }
-EXPORT_SYMBOL(drm_lease_owner);
 
 /**
  * _drm_find_lessee - find lessee by id (idr_mutex held)
@@ -117,7 +116,6 @@ bool _drm_lease_held(struct drm_file *file_priv, int id)
 
        return _drm_lease_held_master(file_priv->master, id);
 }
-EXPORT_SYMBOL(_drm_lease_held);
 
 /**
  * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
@@ -144,7 +142,6 @@ bool drm_lease_held(struct drm_file *file_priv, int id)
        mutex_unlock(&master->dev->mode_config.idr_mutex);
        return ret;
 }
-EXPORT_SYMBOL(drm_lease_held);
 
 /**
  * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
@@ -184,7 +181,6 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
        mutex_unlock(&master->dev->mode_config.idr_mutex);
        return crtcs_out;
 }
-EXPORT_SYMBOL(drm_lease_filter_crtcs);
 
 /*
  * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
@@ -195,7 +191,7 @@ EXPORT_SYMBOL(drm_lease_filter_crtcs);
  * make sure all of the desired objects can be leased, atomically
  * leasing them to the new drmmaster.
  *
- *     ERR_PTR(-EACCESS)       some other master holds the title to any object
+ *     ERR_PTR(-EACCES       some other master holds the title to any object
  *     ERR_PTR(-ENOENT)        some object is not a valid DRM object for this device
  *     ERR_PTR(-EBUSY)         some other lessee holds title to this object
  *     ERR_PTR(-EEXIST)        same object specified more than once in the provided list
@@ -357,9 +353,9 @@ void drm_lease_revoke(struct drm_master *top)
 }
 
 static int validate_lease(struct drm_device *dev,
-                         struct drm_file *lessor_priv,
                          int object_count,
-                         struct drm_mode_object **objects)
+                         struct drm_mode_object **objects,
+                         bool universal_planes)
 {
        int o;
        int has_crtc = -1;
@@ -376,14 +372,14 @@ static int validate_lease(struct drm_device *dev,
                if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
                        has_connector = o;
 
-               if (lessor_priv->universal_planes) {
+               if (universal_planes) {
                        if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
                                has_plane = o;
                }
        }
        if (has_crtc == -1 || has_connector == -1)
                return -EINVAL;
-       if (lessor_priv->universal_planes && has_plane == -1)
+       if (universal_planes && has_plane == -1)
                return -EINVAL;
        return 0;
 }
@@ -397,6 +393,8 @@ static int fill_object_idr(struct drm_device *dev,
        struct drm_mode_object **objects;
        u32 o;
        int ret;
+       bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
+
        objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
                          GFP_KERNEL);
        if (!objects)
@@ -419,14 +417,17 @@ static int fill_object_idr(struct drm_device *dev,
                }
 
                if (!drm_mode_object_lease_required(objects[o]->type)) {
+                       DRM_DEBUG_KMS("invalid object for lease\n");
                        ret = -EINVAL;
                        goto out_free_objects;
                }
        }
 
-       ret = validate_lease(dev, lessor_priv, object_count, objects);
-       if (ret)
+       ret = validate_lease(dev, object_count, objects, universal_planes);
+       if (ret) {
+               DRM_DEBUG_LEASE("lease validation failed\n");
                goto out_free_objects;
+       }
 
        /* add their IDs to the lease request - taking into account
           universal planes */
@@ -449,7 +450,7 @@ static int fill_object_idr(struct drm_device *dev,
                                        object_id, ret);
                        goto out_free_objects;
                }
-               if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) {
+               if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
                        struct drm_crtc *crtc = obj_to_crtc(obj);
                        ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
                        if (ret < 0) {
@@ -509,15 +510,21 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
                return -EOPNOTSUPP;
 
        /* Do not allow sub-leases */
-       if (lessor->lessor)
+       if (lessor->lessor) {
+               DRM_DEBUG_LEASE("recursive leasing not allowed\n");
                return -EINVAL;
+       }
 
        /* need some objects */
-       if (cl->object_count == 0)
+       if (cl->object_count == 0) {
+               DRM_DEBUG_LEASE("no objects in lease\n");
                return -EINVAL;
+       }
 
-       if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK)))
+       if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
+               DRM_DEBUG_LEASE("invalid flags\n");
                return -EINVAL;
+       }
 
        object_count = cl->object_count;
 
@@ -532,6 +539,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
                              object_count, object_ids);
        kfree(object_ids);
        if (ret) {
+               DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
                idr_destroy(&leases);
                return ret;
        }
index d69e4fc1ee7735ede633c0714d6130c5fc366aac..40c4349cb93935a694be59ef37e321941b845e0f 100644 (file)
@@ -51,7 +51,7 @@
 #endif
 
 static void *agp_remap(unsigned long offset, unsigned long size,
-                      struct drm_device * dev)
+                      struct drm_device *dev)
 {
        unsigned long i, num_pages =
            PAGE_ALIGN(size) / PAGE_SIZE;
@@ -94,26 +94,26 @@ static void *agp_remap(unsigned long offset, unsigned long size,
 }
 
 /** Wrapper around agp_free_memory() */
-void drm_free_agp(struct agp_memory * handle, int pages)
+void drm_free_agp(struct agp_memory *handle, int pages)
 {
        agp_free_memory(handle);
 }
 
 /** Wrapper around agp_bind_memory() */
-int drm_bind_agp(struct agp_memory * handle, unsigned int start)
+int drm_bind_agp(struct agp_memory *handle, unsigned int start)
 {
        return agp_bind_memory(handle, start);
 }
 
 /** Wrapper around agp_unbind_memory() */
-int drm_unbind_agp(struct agp_memory * handle)
+int drm_unbind_agp(struct agp_memory *handle)
 {
        return agp_unbind_memory(handle);
 }
 
 #else /*  CONFIG_AGP  */
 static inline void *agp_remap(unsigned long offset, unsigned long size,
-                             struct drm_device * dev)
+                             struct drm_device *dev)
 {
        return NULL;
 }
index ee80788f2c40deb56045fa363e710450f25ef63d..703bfce975bbc296c9ad470bea2b731e9cb2e385 100644 (file)
@@ -297,6 +297,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
                return -ENOMEM;
        dev->mode_config.prop_crtc_id = prop;
 
+       prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "FB_DAMAGE_CLIPS",
+                                  0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_fb_damage_clips = prop;
+
        prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
                        "ACTIVE");
        if (!prop)
@@ -310,6 +316,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
                return -ENOMEM;
        dev->mode_config.prop_mode_id = prop;
 
+       prop = drm_property_create_bool(dev, 0,
+                       "VRR_ENABLED");
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_vrr_enabled = prop;
+
        prop = drm_property_create(dev,
                        DRM_MODE_PROP_BLOB,
                        "DEGAMMA_LUT", 0);
index be8b754eaf60c93b3a1d86cc2efc0929b9fef16e..cd9bc0ce9be07bfc3169ddf5596184f3991e5bc6 100644 (file)
@@ -38,7 +38,8 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
        int ret;
 
        mutex_lock(&dev->mode_config.idr_mutex);
-       ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
+       ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL,
+                       1, 0, GFP_KERNEL);
        if (ret >= 0) {
                /*
                 * Set up the object linking under the protection of the idr
index 02db9ac82d7a91a9b7de054a71a92e377d27a3d5..24a7504365596c32c60333ad04e25ba1c26306bf 100644 (file)
@@ -716,8 +716,8 @@ int of_get_drm_display_mode(struct device_node *np,
        if (bus_flags)
                drm_bus_flags_from_videomode(&vm, bus_flags);
 
-       pr_debug("%pOF: got %dx%d display mode from %s\n",
-               np, vm.hactive, vm.vactive, np->name);
+       pr_debug("%pOF: got %dx%d display mode\n",
+               np, vm.hactive, vm.vactive);
        drm_mode_debug_printmodeline(dmode);
 
        return 0;
index f1c24ab0ef09f6ca4c45d08c6c4552f11126516b..9150fa385bba7d212dce1b1da55d677d47f1e765 100644 (file)
@@ -146,6 +146,21 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
  * Initialize a CRTC object with a default helper-provided primary plane and no
  * cursor plane.
  *
+ * Note that we make some assumptions about hardware limitations that may not be
+ * true for all hardware:
+ *
+ * 1. Primary plane cannot be repositioned.
+ * 2. Primary plane cannot be scaled.
+ * 3. Primary plane must cover the entire CRTC.
+ * 4. Subpixel positioning is not supported.
+ * 5. The primary plane must always be on if the CRTC is enabled.
+ *
+ * This is purely a backwards compatibility helper for old drivers. Drivers
+ * should instead implement their own primary plane. Atomic drivers must do so.
+ * Drivers with the above hardware restriction can look into using &struct
+ * drm_simple_display_pipe, which encapsulates the above limitations into a nice
+ * interface.
+ *
  * Returns:
  * Zero on success, error code on failure.
  */
index 8a5100685875a38cc0f844c3c57d1273045d585f..51f534db91070772e59265d16b3115a4883f2afe 100644 (file)
  *     drm_modeset_drop_locks(ctx);
  *     drm_modeset_acquire_fini(ctx);
  *
+ * For convenience this control flow is implemented in
+ * DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() for the case
+ * where all modeset locks need to be taken through drm_modeset_lock_all_ctx().
+ *
  * If all that is needed is a single modeset lock, then the &struct
  * drm_modeset_acquire_ctx is not needed and the locking can be simplified
  * by passing a NULL instead of ctx in the drm_modeset_lock() call or
@@ -383,6 +387,8 @@ EXPORT_SYMBOL(drm_modeset_unlock);
  * Locks acquired with this function should be released by calling the
  * drm_modeset_drop_locks() function on @ctx.
  *
+ * See also: DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END()
+ *
  * Returns: 0 on success or a negative error-code on failure.
  */
 int drm_modeset_lock_all_ctx(struct drm_device *dev,
index ee4a5e1221f1fcefeb6e488accdf80d59a10b111..52e445bb1aa581a4f012e03a166bb985a6aaf675 100644 (file)
@@ -59,6 +59,14 @@ static const struct drm_dmi_panel_orientation_data gpd_win = {
        .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data gpd_win2 = {
+       .width = 720,
+       .height = 1280,
+       .bios_dates = (const char * const []){
+               "12/07/2017", "05/24/2018", "06/29/2018", NULL },
+       .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
 static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
        .width = 800,
        .height = 1280,
@@ -106,6 +114,14 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
                },
                .driver_data = (void *)&gpd_win,
+       }, {    /* GPD Win 2 (too generic strings, also match on bios date) */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+                 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
+                 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+               },
+               .driver_data = (void *)&gpd_win2,
        }, {    /* I.T.Works TW891 */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
index 48f615d38931a946914b2a1ac1268acdb3bf95ff..a9d9df6c85ad9e65af837273bd2aeac95ede7c8b 100644 (file)
@@ -61,15 +61,14 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
                return NULL;
 
        dmah->size = size;
-       dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
+       dmah->vaddr = dma_zalloc_coherent(&dev->pdev->dev, size, &dmah->busaddr,
+                                               GFP_KERNEL | __GFP_COMP);
 
        if (dmah->vaddr == NULL) {
                kfree(dmah);
                return NULL;
        }
 
-       memset(dmah->vaddr, 0, size);
-
        /* XXX - Is virt_to_page() legal for consistent mem? */
        /* Reserve */
        for (addr = (unsigned long)dmah->vaddr, sz = size;
index 1fa98bd120030e91b1701fbe52688729ada6b95a..5f650d8fc66b7a9514db4be47b937871f28d900f 100644 (file)
@@ -636,6 +636,29 @@ static int __setplane_check(struct drm_plane *plane,
        return 0;
 }
 
+/**
+ * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
+ * @dev: DRM device
+ * @format: pixel format (DRM_FORMAT_*)
+ * @modifier: data layout modifier
+ *
+ * Returns:
+ * Whether at least one plane supports the specified format and modifier combination.
+ */
+bool drm_any_plane_has_format(struct drm_device *dev,
+                             u32 format, u64 modifier)
+{
+       struct drm_plane *plane;
+
+       drm_for_each_plane(plane, dev) {
+               if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
+                       return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(drm_any_plane_has_format);
+
 /*
  * __setplane_internal - setplane handler for internal callers
  *
@@ -744,11 +767,8 @@ static int setplane_internal(struct drm_plane *plane,
        struct drm_modeset_acquire_ctx ctx;
        int ret;
 
-       drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
-retry:
-       ret = drm_modeset_lock_all_ctx(plane->dev, &ctx);
-       if (ret)
-               goto fail;
+       DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
+                                  DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
 
        if (drm_drv_uses_atomic_modeset(plane->dev))
                ret = __setplane_atomic(plane, crtc, fb,
@@ -759,14 +779,7 @@ retry:
                                          crtc_x, crtc_y, crtc_w, crtc_h,
                                          src_x, src_y, src_w, src_h, &ctx);
 
-fail:
-       if (ret == -EDEADLK) {
-               ret = drm_modeset_backoff(&ctx);
-               if (!ret)
-                       goto retry;
-       }
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
+       DRM_MODESET_LOCK_ALL_END(ctx, ret);
 
        return ret;
 }
index a393756b664e159e7122fb0c9021035cb8e8ecc9..0fff72dcd06de6fd05a2ddc356a96dd8efc00043 100644 (file)
  * primary plane support on top of the normal CRTC configuration interface.
  * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
  * plane together with the CRTC state this does not allow userspace to disable
- * the primary plane itself.  To avoid too much duplicated code use
- * drm_plane_helper_check_update() which can be used to enforce the same
- * restrictions as primary planes had thus. The default primary plane only
- * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
- * framebuffer.
+ * the primary plane itself. The default primary plane only expose XRBG8888 and
+ * ARGB8888 as valid pixel formats for the attached framebuffer.
  *
  * Drivers are highly recommended to implement proper support for primary
  * planes, and newly merged drivers must not rely upon these transitional
@@ -100,43 +97,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
        return count;
 }
 
-/**
- * drm_plane_helper_check_update() - Check plane update for validity
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @src: source coordinates in 16.16 fixed point
- * @dst: integer destination coordinates
- * @rotation: plane rotation
- * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
- * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
- * @can_position: is it legal to position the plane such that it
- *                doesn't cover the entire crtc?  This will generally
- *                only be false for primary planes.
- * @can_update_disabled: can the plane be updated while the crtc
- *                       is disabled?
- * @visible: output parameter indicating whether plane is still visible after
- *           clipping
- *
- * Checks that a desired plane update is valid.  Drivers that provide
- * their own plane handling rather than helper-provided implementations may
- * still wish to call this function to avoid duplication of error checking
- * code.
- *
- * RETURNS:
- * Zero if update appears valid, error code on failure
- */
-int drm_plane_helper_check_update(struct drm_plane *plane,
-                                 struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_rect *src,
-                                 struct drm_rect *dst,
-                                 unsigned int rotation,
-                                 int min_scale,
-                                 int max_scale,
-                                 bool can_position,
-                                 bool can_update_disabled,
-                                 bool *visible)
+static int drm_plane_helper_check_update(struct drm_plane *plane,
+                                        struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
+                                        struct drm_rect *src,
+                                        struct drm_rect *dst,
+                                        unsigned int rotation,
+                                        int min_scale,
+                                        int max_scale,
+                                        bool can_position,
+                                        bool can_update_disabled,
+                                        bool *visible)
 {
        struct drm_plane_state plane_state = {
                .plane = plane,
@@ -173,52 +144,14 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
 
        return 0;
 }
-EXPORT_SYMBOL(drm_plane_helper_check_update);
 
-/**
- * drm_primary_helper_update() - Helper for primary plane update
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @crtc_x: x offset of primary plane on crtc
- * @crtc_y: y offset of primary plane on crtc
- * @crtc_w: width of primary plane rectangle on crtc
- * @crtc_h: height of primary plane rectangle on crtc
- * @src_x: x offset of @fb for panning
- * @src_y: y offset of @fb for panning
- * @src_w: width of source rectangle in @fb
- * @src_h: height of source rectangle in @fb
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane update handler for primary planes.  This is handler
- * is called in response to a userspace SetPlane operation on the plane with a
- * non-NULL framebuffer.  We call the driver's modeset handler to update the
- * framebuffer.
- *
- * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
- * return an error.
- *
- * Note that we make some assumptions about hardware limitations that may not be
- * true for all hardware --
- *
- * 1. Primary plane cannot be repositioned.
- * 2. Primary plane cannot be scaled.
- * 3. Primary plane must cover the entire CRTC.
- * 4. Subpixel positioning is not supported.
- *
- * Drivers for hardware that don't have these restrictions can provide their
- * own implementation rather than using this helper.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
-                             struct drm_framebuffer *fb,
-                             int crtc_x, int crtc_y,
-                             unsigned int crtc_w, unsigned int crtc_h,
-                             uint32_t src_x, uint32_t src_y,
-                             uint32_t src_w, uint32_t src_h,
-                             struct drm_modeset_acquire_ctx *ctx)
+static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+                                    struct drm_framebuffer *fb,
+                                    int crtc_x, int crtc_y,
+                                    unsigned int crtc_w, unsigned int crtc_h,
+                                    uint32_t src_x, uint32_t src_y,
+                                    uint32_t src_w, uint32_t src_h,
+                                    struct drm_modeset_acquire_ctx *ctx)
 {
        struct drm_mode_set set = {
                .crtc = crtc,
@@ -285,35 +218,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
        kfree(connector_list);
        return ret;
 }
-EXPORT_SYMBOL(drm_primary_helper_update);
 
-/**
- * drm_primary_helper_disable() - Helper for primary plane disable
- * @plane: plane to disable
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane disable handler for primary planes.  This is handler
- * is called in response to a userspace SetPlane operation on the plane with a
- * NULL framebuffer parameter.  It unconditionally fails the disable call with
- * -EINVAL the only way to disable the primary plane without driver support is
- * to disable the entire CRTC. Which does not match the plane
- * &drm_plane_funcs.disable_plane hook.
- *
- * Note that some hardware may be able to disable the primary plane without
- * disabling the whole CRTC.  Drivers for such hardware should provide their
- * own disable handler that disables just the primary plane (and they'll likely
- * need to provide their own update handler as well to properly re-enable a
- * disabled primary plane).
- *
- * RETURNS:
- * Unconditionally returns -EINVAL.
- */
-int drm_primary_helper_disable(struct drm_plane *plane,
-                              struct drm_modeset_acquire_ctx *ctx)
+static int drm_primary_helper_disable(struct drm_plane *plane,
+                                     struct drm_modeset_acquire_ctx *ctx)
 {
        return -EINVAL;
 }
-EXPORT_SYMBOL(drm_primary_helper_disable);
 
 /**
  * drm_primary_helper_destroy() - Helper for primary plane destruction
@@ -336,200 +246,3 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
        .destroy = drm_primary_helper_destroy,
 };
 EXPORT_SYMBOL(drm_primary_helper_funcs);
-
-int drm_plane_helper_commit(struct drm_plane *plane,
-                           struct drm_plane_state *plane_state,
-                           struct drm_framebuffer *old_fb)
-{
-       const struct drm_plane_helper_funcs *plane_funcs;
-       struct drm_crtc *crtc[2];
-       const struct drm_crtc_helper_funcs *crtc_funcs[2];
-       int i, ret = 0;
-
-       plane_funcs = plane->helper_private;
-
-       /* Since this is a transitional helper we can't assume that plane->state
-        * is always valid. Hence we need to use plane->crtc instead of
-        * plane->state->crtc as the old crtc. */
-       crtc[0] = plane->crtc;
-       crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
-
-       for (i = 0; i < 2; i++)
-               crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
-
-       if (plane_funcs->atomic_check) {
-               ret = plane_funcs->atomic_check(plane, plane_state);
-               if (ret)
-                       goto out;
-       }
-
-       if (plane_funcs->prepare_fb && plane_state->fb != old_fb) {
-               ret = plane_funcs->prepare_fb(plane,
-                                             plane_state);
-               if (ret)
-                       goto out;
-       }
-
-       /* Point of no return, commit sw state. */
-       swap(plane->state, plane_state);
-
-       for (i = 0; i < 2; i++) {
-               if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
-                       crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
-       }
-
-       /*
-        * Drivers may optionally implement the ->atomic_disable callback, so
-        * special-case that here.
-        */
-       if (drm_atomic_plane_disabling(plane_state, plane->state) &&
-           plane_funcs->atomic_disable)
-               plane_funcs->atomic_disable(plane, plane_state);
-       else
-               plane_funcs->atomic_update(plane, plane_state);
-
-       for (i = 0; i < 2; i++) {
-               if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
-                       crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
-       }
-
-       /*
-        * If we only moved the plane and didn't change fb's, there's no need to
-        * wait for vblank.
-        */
-       if (plane->state->fb == old_fb)
-               goto out;
-
-       for (i = 0; i < 2; i++) {
-               if (!crtc[i])
-                       continue;
-
-               if (crtc[i]->cursor == plane)
-                       continue;
-
-               /* There's no other way to figure out whether the crtc is running. */
-               ret = drm_crtc_vblank_get(crtc[i]);
-               if (ret == 0) {
-                       drm_crtc_wait_one_vblank(crtc[i]);
-                       drm_crtc_vblank_put(crtc[i]);
-               }
-
-               ret = 0;
-       }
-
-       if (plane_funcs->cleanup_fb)
-               plane_funcs->cleanup_fb(plane, plane_state);
-out:
-       if (plane->funcs->atomic_destroy_state)
-               plane->funcs->atomic_destroy_state(plane, plane_state);
-       else
-               drm_atomic_helper_plane_destroy_state(plane, plane_state);
-
-       return ret;
-}
-
-/**
- * drm_plane_helper_update() - Transitional helper for plane update
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @crtc_x: x offset of primary plane on crtc
- * @crtc_y: y offset of primary plane on crtc
- * @crtc_w: width of primary plane rectangle on crtc
- * @crtc_h: height of primary plane rectangle on crtc
- * @src_x: x offset of @fb for panning
- * @src_y: y offset of @fb for panning
- * @src_w: width of source rectangle in @fb
- * @src_h: height of source rectangle in @fb
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane update handler using the atomic plane update
- * functions. It is fully left to the driver to check plane constraints and
- * handle corner-cases like a fully occluded or otherwise invisible plane.
- *
- * This is useful for piecewise transitioning of a driver to the atomic helpers.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
-                           struct drm_framebuffer *fb,
-                           int crtc_x, int crtc_y,
-                           unsigned int crtc_w, unsigned int crtc_h,
-                           uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h,
-                           struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_plane_state *plane_state;
-
-       if (plane->funcs->atomic_duplicate_state)
-               plane_state = plane->funcs->atomic_duplicate_state(plane);
-       else {
-               if (!plane->state)
-                       drm_atomic_helper_plane_reset(plane);
-
-               plane_state = drm_atomic_helper_plane_duplicate_state(plane);
-       }
-       if (!plane_state)
-               return -ENOMEM;
-       plane_state->plane = plane;
-
-       plane_state->crtc = crtc;
-       drm_atomic_set_fb_for_plane(plane_state, fb);
-       plane_state->crtc_x = crtc_x;
-       plane_state->crtc_y = crtc_y;
-       plane_state->crtc_h = crtc_h;
-       plane_state->crtc_w = crtc_w;
-       plane_state->src_x = src_x;
-       plane_state->src_y = src_y;
-       plane_state->src_h = src_h;
-       plane_state->src_w = src_w;
-
-       return drm_plane_helper_commit(plane, plane_state, plane->fb);
-}
-EXPORT_SYMBOL(drm_plane_helper_update);
-
-/**
- * drm_plane_helper_disable() - Transitional helper for plane disable
- * @plane: plane to disable
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane disable handler using the atomic plane update
- * functions. It is fully left to the driver to check plane constraints and
- * handle corner-cases like a fully occluded or otherwise invisible plane.
- *
- * This is useful for piecewise transitioning of a driver to the atomic helpers.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_plane_helper_disable(struct drm_plane *plane,
-                            struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_plane_state *plane_state;
-       struct drm_framebuffer *old_fb;
-
-       /* crtc helpers love to call disable functions for already disabled hw
-        * functions. So cope with that. */
-       if (!plane->crtc)
-               return 0;
-
-       if (plane->funcs->atomic_duplicate_state)
-               plane_state = plane->funcs->atomic_duplicate_state(plane);
-       else {
-               if (!plane->state)
-                       drm_atomic_helper_plane_reset(plane);
-
-               plane_state = drm_atomic_helper_plane_duplicate_state(plane);
-       }
-       if (!plane_state)
-               return -ENOMEM;
-       plane_state->plane = plane;
-
-       plane_state->crtc = NULL;
-       old_fb = plane_state->fb;
-       drm_atomic_set_fb_for_plane(plane_state, NULL);
-
-       return drm_plane_helper_commit(plane, plane_state, old_fb);
-}
-EXPORT_SYMBOL(drm_plane_helper_disable);
index 3f0205fc0a1a0efdfdbf7c637ac5a9b7b0f2227a..231e3f6d5f4162c243c19c04811b71727f7c50cb 100644 (file)
@@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
 {
        struct drm_prime_attachment *prime_attach;
        struct drm_gem_object *obj = dma_buf->priv;
-       struct drm_device *dev = obj->dev;
 
        prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
        if (!prime_attach)
@@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
        prime_attach->dir = DMA_NONE;
        attach->priv = prime_attach;
 
-       if (!dev->driver->gem_prime_pin)
-               return 0;
-
-       return dev->driver->gem_prime_pin(obj);
+       return drm_gem_pin(obj);
 }
 EXPORT_SYMBOL(drm_gem_map_attach);
 
@@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
 {
        struct drm_prime_attachment *prime_attach = attach->priv;
        struct drm_gem_object *obj = dma_buf->priv;
-       struct drm_device *dev = obj->dev;
 
        if (prime_attach) {
                struct sg_table *sgt = prime_attach->sgt;
@@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
                attach->priv = NULL;
        }
 
-       if (dev->driver->gem_prime_unpin)
-               dev->driver->gem_prime_unpin(obj);
+       drm_gem_unpin(obj);
 }
 EXPORT_SYMBOL(drm_gem_map_detach);
 
@@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
        if (WARN_ON(prime_attach->dir != DMA_NONE))
                return ERR_PTR(-EBUSY);
 
-       sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
+       if (obj->funcs)
+               sgt = obj->funcs->get_sg_table(obj);
+       else
+               sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
 
        if (!IS_ERR(sgt)) {
                if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
@@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
 void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
 {
        struct drm_gem_object *obj = dma_buf->priv;
-       struct drm_device *dev = obj->dev;
+       void *vaddr;
 
-       if (dev->driver->gem_prime_vmap)
-               return dev->driver->gem_prime_vmap(obj);
-       else
-               return NULL;
+       vaddr = drm_gem_vmap(obj);
+       if (IS_ERR(vaddr))
+               vaddr = NULL;
+
+       return vaddr;
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 
@@ -426,41 +424,11 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
 {
        struct drm_gem_object *obj = dma_buf->priv;
-       struct drm_device *dev = obj->dev;
 
-       if (dev->driver->gem_prime_vunmap)
-               dev->driver->gem_prime_vunmap(obj, vaddr);
+       drm_gem_vunmap(obj, vaddr);
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
 
-/**
- * drm_gem_dmabuf_kmap - map implementation for GEM
- * @dma_buf: buffer to be mapped
- * @page_num: page number within the buffer
- *
- * Not implemented. This can be used as the &dma_buf_ops.map callback.
- */
-void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
-{
-       return NULL;
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_kmap);
-
-/**
- * drm_gem_dmabuf_kunmap - unmap implementation for GEM
- * @dma_buf: buffer to be unmapped
- * @page_num: page number within the buffer
- * @addr: virtual address of the buffer
- *
- * Not implemented. This can be used as the &dma_buf_ops.unmap callback.
- */
-void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
-                          void *addr)
-{
-
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_kunmap);
-
 /**
  * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
  * @dma_buf: buffer to be mapped
@@ -489,8 +457,6 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
        .map_dma_buf = drm_gem_map_dma_buf,
        .unmap_dma_buf = drm_gem_unmap_dma_buf,
        .release = drm_gem_dmabuf_release,
-       .map = drm_gem_dmabuf_kmap,
-       .unmap = drm_gem_dmabuf_kunmap,
        .mmap = drm_gem_dmabuf_mmap,
        .vmap = drm_gem_dmabuf_vmap,
        .vunmap = drm_gem_dmabuf_vunmap,
@@ -559,7 +525,12 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
                return dmabuf;
        }
 
-       dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
+       if (obj->funcs && obj->funcs->export)
+               dmabuf = obj->funcs->export(obj, flags);
+       else if (dev->driver->gem_prime_export)
+               dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
+       else
+               dmabuf = drm_gem_prime_export(dev, obj, flags);
        if (IS_ERR(dmabuf)) {
                /* normally the created dma-buf takes ownership of the ref,
                 * but if that fails then drop the ref
@@ -678,6 +649,52 @@ out_unlock:
 }
 EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
 
+/**
+ * drm_gem_prime_mmap - PRIME mmap function for GEM drivers
+ * @obj: GEM object
+ * @vma: Virtual address range
+ *
+ * This function sets up a userspace mapping for PRIME exported buffers using
+ * the same codepath that is used for regular GEM buffer mapping on the DRM fd.
+ * The fake GEM offset is added to vma->vm_pgoff and &drm_driver->fops->mmap is
+ * called to set up the mapping.
+ *
+ * Drivers can use this as their &drm_driver.gem_prime_mmap callback.
+ */
+int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+       struct drm_file *priv;
+       struct file *fil;
+       int ret;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       fil = kzalloc(sizeof(*fil), GFP_KERNEL);
+       if (!priv || !fil) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Used by drm_gem_mmap() to lookup the GEM object */
+       priv->minor = obj->dev->primary;
+       fil->private_data = priv;
+
+       ret = drm_vma_node_allow(&obj->vma_node, priv);
+       if (ret)
+               goto out;
+
+       vma->vm_pgoff += drm_vma_node_start(&obj->vma_node);
+
+       ret = obj->dev->driver->fops->mmap(fil, vma);
+
+       drm_vma_node_revoke(&obj->vma_node, priv);
+out:
+       kfree(priv);
+       kfree(fil);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_mmap);
+
 /**
  * drm_gem_prime_import_dev - core implementation of the import callback
  * @dev: drm_device to import into
@@ -792,7 +809,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
 
        /* never seen this one, need to import */
        mutex_lock(&dev->object_name_lock);
-       obj = dev->driver->gem_prime_import(dev, dma_buf);
+       if (dev->driver->gem_prime_import)
+               obj = dev->driver->gem_prime_import(dev, dma_buf);
+       else
+               obj = drm_gem_prime_import(dev, dma_buf);
        if (IS_ERR(obj)) {
                ret = PTR_ERR(obj);
                goto out_unlock;
index 51fa978f0d236821ac020b16144f50e2fbb854bb..917812448d1ba954b7a84ff6a33ba04a988ef2fb 100644 (file)
@@ -190,6 +190,13 @@ static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
        pipe->funcs->cleanup_fb(pipe, state);
 }
 
+static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
+                                               uint32_t format,
+                                               uint64_t modifier)
+{
+       return modifier == DRM_FORMAT_MOD_LINEAR;
+}
+
 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
        .prepare_fb = drm_simple_kms_plane_prepare_fb,
        .cleanup_fb = drm_simple_kms_plane_cleanup_fb,
@@ -204,6 +211,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
        .reset                  = drm_atomic_helper_plane_reset,
        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
        .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
+       .format_mod_supported   = drm_simple_kms_format_mod_supported,
 };
 
 /**
index 5c2091dbd230307bcd8825674b0206f0433ec9d1..db30a0e89db8f30825a8401d91aadc1b78a6c86e 100644 (file)
 #include "drm_internal.h"
 #include <drm/drm_syncobj.h>
 
-struct drm_syncobj_stub_fence {
-       struct dma_fence base;
-       spinlock_t lock;
-};
-
-static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence)
-{
-        return "syncobjstub";
-}
-
-static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
-       .get_driver_name = drm_syncobj_stub_fence_get_name,
-       .get_timeline_name = drm_syncobj_stub_fence_get_name,
-};
-
-
 /**
  * drm_syncobj_find - lookup and reference a sync object.
  * @file_private: drm file private pointer
@@ -113,8 +97,6 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
 {
        int ret;
 
-       WARN_ON(*fence);
-
        *fence = drm_syncobj_fence_get(syncobj);
        if (*fence)
                return 1;
@@ -158,13 +140,11 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
 /**
  * drm_syncobj_replace_fence - replace fence in a sync object.
  * @syncobj: Sync object to replace fence in
- * @point: timeline point
  * @fence: fence to install in sync file.
  *
- * This replaces the fence on a sync object, or a timeline point fence.
+ * This replaces the fence on a sync object.
  */
 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
-                              u64 point,
                               struct dma_fence *fence)
 {
        struct dma_fence *old_fence;
@@ -192,23 +172,18 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 }
 EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
-static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
+/**
+ * drm_syncobj_assign_null_handle - assign a stub fence to the sync object
+ * @syncobj: sync object to assign the fence on
+ *
+ * Assign a already signaled stub fence to the sync object.
+ */
+static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
 {
-       struct drm_syncobj_stub_fence *fence;
-       fence = kzalloc(sizeof(*fence), GFP_KERNEL);
-       if (fence == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&fence->lock);
-       dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops,
-                      &fence->lock, 0, 0);
-       dma_fence_signal(&fence->base);
-
-       drm_syncobj_replace_fence(syncobj, 0, &fence->base);
-
-       dma_fence_put(&fence->base);
+       struct dma_fence *fence = dma_fence_get_stub();
 
-       return 0;
+       drm_syncobj_replace_fence(syncobj, fence);
+       dma_fence_put(fence);
 }
 
 /**
@@ -216,6 +191,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * @file_private: drm file private pointer
  * @handle: sync object handle to lookup.
  * @point: timeline point
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
  * @fence: out parameter for the fence
  *
  * This is just a convenience function that combines drm_syncobj_find() and
@@ -226,7 +202,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * dma_fence_put().
  */
 int drm_syncobj_find_fence(struct drm_file *file_private,
-                          u32 handle, u64 point,
+                          u32 handle, u64 point, u64 flags,
                           struct dma_fence **fence)
 {
        struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
@@ -255,7 +231,7 @@ void drm_syncobj_free(struct kref *kref)
        struct drm_syncobj *syncobj = container_of(kref,
                                                   struct drm_syncobj,
                                                   refcount);
-       drm_syncobj_replace_fence(syncobj, 0, NULL);
+       drm_syncobj_replace_fence(syncobj, NULL);
        kfree(syncobj);
 }
 EXPORT_SYMBOL(drm_syncobj_free);
@@ -275,7 +251,6 @@ EXPORT_SYMBOL(drm_syncobj_free);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
                       struct dma_fence *fence)
 {
-       int ret;
        struct drm_syncobj *syncobj;
 
        syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);
@@ -286,16 +261,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
        INIT_LIST_HEAD(&syncobj->cb_list);
        spin_lock_init(&syncobj->lock);
 
-       if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
-               ret = drm_syncobj_assign_null_handle(syncobj);
-               if (ret < 0) {
-                       drm_syncobj_put(syncobj);
-                       return ret;
-               }
-       }
+       if (flags & DRM_SYNCOBJ_CREATE_SIGNALED)
+               drm_syncobj_assign_null_handle(syncobj);
 
        if (fence)
-               drm_syncobj_replace_fence(syncobj, 0, fence);
+               drm_syncobj_replace_fence(syncobj, fence);
 
        *out_syncobj = syncobj;
        return 0;
@@ -480,7 +450,7 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
                return -ENOENT;
        }
 
-       drm_syncobj_replace_fence(syncobj, 0, fence);
+       drm_syncobj_replace_fence(syncobj, fence);
        dma_fence_put(fence);
        drm_syncobj_put(syncobj);
        return 0;
@@ -497,7 +467,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
        if (fd < 0)
                return fd;
 
-       ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
+       ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
        if (ret)
                goto err_put_fd;
 
@@ -719,9 +689,6 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 
        if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
                for (i = 0; i < count; ++i) {
-                       if (entries[i].fence)
-                               continue;
-
                        drm_syncobj_fence_get_or_add_callback(syncobjs[i],
                                                              &entries[i].fence,
                                                              &entries[i].syncobj_cb,
@@ -954,7 +921,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
                return ret;
 
        for (i = 0; i < args->count_handles; i++)
-               drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
+               drm_syncobj_replace_fence(syncobjs[i], NULL);
 
        drm_syncobj_array_free(syncobjs, args->count_handles);
 
@@ -986,11 +953,8 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
        if (ret < 0)
                return ret;
 
-       for (i = 0; i < args->count_handles; i++) {
-               ret = drm_syncobj_assign_null_handle(syncobjs[i]);
-               if (ret < 0)
-                       break;
-       }
+       for (i = 0; i < args->count_handles; i++)
+               drm_syncobj_assign_null_handle(syncobjs[i]);
 
        drm_syncobj_array_free(syncobjs, args->count_handles);
 
index 83c1f46670bfea9dcbe95e42da598c8665576b03..52802e6049e0adab5045b57cc09bd265708ae34d 100644 (file)
@@ -550,7 +550,7 @@ out_register:
 out_bind:
        kfree(priv);
 out_unref:
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return ret;
 }
@@ -567,7 +567,7 @@ static void etnaviv_unbind(struct device *dev)
        drm->dev_private = NULL;
        kfree(priv);
 
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 }
 
 static const struct component_master_ops etnaviv_master_ops = {
index 9146e30e24a6de20d8bda5f80c7ea7470ddca334..3fbb4855396cc98505eeb2062de6579c01478d57 100644 (file)
@@ -118,6 +118,7 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
        unsigned int n_obj, n_bomap_pages;
        size_t file_size, mmu_size;
        __le64 *bomap, *bomap_start;
+       unsigned long flags;
 
        /* Only catch the first event, or when manually re-armed */
        if (!etnaviv_dump_core)
@@ -134,13 +135,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
                    mmu_size + gpu->buffer.size;
 
        /* Add in the active command buffers */
-       spin_lock(&gpu->sched.job_list_lock);
+       spin_lock_irqsave(&gpu->sched.job_list_lock, flags);
        list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
                submit = to_etnaviv_submit(s_job);
                file_size += submit->cmdbuf.size;
                n_obj++;
        }
-       spin_unlock(&gpu->sched.job_list_lock);
+       spin_unlock_irqrestore(&gpu->sched.job_list_lock, flags);
 
        /* Add in the active buffer objects */
        list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
@@ -182,14 +183,14 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
                              gpu->buffer.size,
                              etnaviv_cmdbuf_get_va(&gpu->buffer));
 
-       spin_lock(&gpu->sched.job_list_lock);
+       spin_lock_irqsave(&gpu->sched.job_list_lock, flags);
        list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
                submit = to_etnaviv_submit(s_job);
                etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD,
                                      submit->cmdbuf.vaddr, submit->cmdbuf.size,
                                      etnaviv_cmdbuf_get_va(&submit->cmdbuf));
        }
-       spin_unlock(&gpu->sched.job_list_lock);
+       spin_unlock_irqrestore(&gpu->sched.job_list_lock, flags);
 
        /* Reserve space for the bomap */
        if (n_bomap_pages) {
index 983e67f19e4508b5023cb5efba221981f4a9b4b0..30875f8f293371ccd240be02b826302a8abeed08 100644 (file)
@@ -179,7 +179,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
                struct reservation_object *robj = bo->obj->resv;
 
                if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) {
-                       ret = reservation_object_reserve_shared(robj);
+                       ret = reservation_object_reserve_shared(robj, 1);
                        if (ret)
                                return ret;
                }
index 9b476368aa313efd7c33945aeadd2b4c481c70d2..49a6763693f1ab372d4eeea89f72cd04bbf63442 100644 (file)
@@ -105,8 +105,6 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
        change = dma_addr - gpu->hangcheck_dma_addr;
        if (change < 0 || change > 16) {
                gpu->hangcheck_dma_addr = dma_addr;
-               schedule_delayed_work(&sched_job->sched->work_tdr,
-                                     sched_job->sched->timeout);
                return;
        }
 
@@ -127,6 +125,8 @@ static void etnaviv_sched_free_job(struct drm_sched_job *sched_job)
 {
        struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
 
+       drm_sched_job_cleanup(sched_job);
+
        etnaviv_submit_put(submit);
 }
 
@@ -159,6 +159,7 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
                                                submit->out_fence, 0,
                                                INT_MAX, GFP_KERNEL);
        if (submit->out_fence_id < 0) {
+               drm_sched_job_cleanup(&submit->sched_job);
                ret = -ENOMEM;
                goto out_unlock;
        }
index 208bc27be3cc47a937625f110883c998be41ac7b..3691a140c9502e995d28454fbd52196ca599a5d7 100644 (file)
@@ -10,11 +10,6 @@ config DRM_EXYNOS
 
 if DRM_EXYNOS
 
-config DRM_EXYNOS_IOMMU
-       bool
-       depends on EXYNOS_IOMMU
-       default y
-
 comment "CRTCs"
 
 config DRM_EXYNOS_FIMD
index 2ad146bbf4f5488e8b6293dabc9238c03753c044..2fd2f3ee4fcf09244fdb399e4b1b684e1308b5a7 100644 (file)
@@ -4,10 +4,9 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
-               exynos_drm_gem.o exynos_drm_plane.o
+               exynos_drm_gem.o exynos_drm_plane.o exynos_drm_dma.o
 
 exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)    += exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON)       += exynos5433_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)  += exynos7_drm_decon.o
index aef487dd873153d77fd602726ab6bd92256ab593..5b4e0e8b23bc4d86fbb13e1120c40ec78f99a029 100644 (file)
@@ -25,7 +25,6 @@
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_plane.h"
-#include "exynos_drm_iommu.h"
 #include "regs-decon5433.h"
 
 #define DSD_CFG_MUX 0x1004
@@ -84,6 +83,14 @@ static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
        [CURSON_WIN] = DRM_PLANE_TYPE_CURSOR,
 };
 
+static const unsigned int capabilities[WINDOWS_NR] = {
+       0,
+       EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
+       EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
+       EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
+       EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
+};
+
 static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
                                  u32 val)
 {
@@ -252,11 +259,76 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
        decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
 }
 
+static void decon_win_set_bldeq(struct decon_context *ctx, unsigned int win,
+                               unsigned int alpha, unsigned int pixel_alpha)
+{
+       u32 mask = BLENDERQ_A_FUNC_F(0xf) | BLENDERQ_B_FUNC_F(0xf);
+       u32 val = 0;
+
+       switch (pixel_alpha) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+       case DRM_MODE_BLEND_COVERAGE:
+               val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA_A);
+               val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
+               break;
+       case DRM_MODE_BLEND_PREMULTI:
+       default:
+               if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
+                       val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA0);
+                       val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
+               } else {
+                       val |= BLENDERQ_A_FUNC_F(BLENDERQ_ONE);
+                       val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
+               }
+               break;
+       }
+       decon_set_bits(ctx, DECON_BLENDERQx(win), mask, val);
+}
+
+static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win,
+                                unsigned int alpha, unsigned int pixel_alpha)
+{
+       u32 win_alpha = alpha >> 8;
+       u32 val = 0;
+
+       switch (pixel_alpha) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+               break;
+       case DRM_MODE_BLEND_COVERAGE:
+       case DRM_MODE_BLEND_PREMULTI:
+       default:
+               val |= WINCONx_ALPHA_SEL_F;
+               val |= WINCONx_BLD_PIX_F;
+               val |= WINCONx_ALPHA_MUL_F;
+               break;
+       }
+       decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_BLEND_MODE_MASK, val);
+
+       if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
+               val = VIDOSD_Wx_ALPHA_R_F(win_alpha) |
+                     VIDOSD_Wx_ALPHA_G_F(win_alpha) |
+                     VIDOSD_Wx_ALPHA_B_F(win_alpha);
+               decon_set_bits(ctx, DECON_VIDOSDxC(win),
+                              VIDOSDxC_ALPHA0_RGB_MASK, val);
+               decon_set_bits(ctx, DECON_BLENDCON, BLEND_NEW, BLEND_NEW);
+       }
+}
+
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
                                 struct drm_framebuffer *fb)
 {
+       struct exynos_drm_plane plane = ctx->planes[win];
+       struct exynos_drm_plane_state *state =
+               to_exynos_plane_state(plane.base.state);
+       unsigned int alpha = state->base.alpha;
+       unsigned int pixel_alpha;
        unsigned long val;
 
+       if (fb->format->has_alpha)
+               pixel_alpha = state->base.pixel_blend_mode;
+       else
+               pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
+
        val = readl(ctx->addr + DECON_WINCONx(win));
        val &= WINCONx_ENWIN_F;
 
@@ -279,7 +351,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
        case DRM_FORMAT_ARGB8888:
        default:
                val |= WINCONx_BPPMODE_32BPP_A8888;
-               val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F;
+               val |= WINCONx_WSWP_F;
                val |= WINCONx_BURSTLEN_16WORD;
                break;
        }
@@ -298,8 +370,12 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_8WORD;
        }
+       decon_set_bits(ctx, DECON_WINCONx(win), ~WINCONx_BLEND_MODE_MASK, val);
 
-       writel(val, ctx->addr + DECON_WINCONx(win));
+       if (win > 0) {
+               decon_win_set_bldmod(ctx, win, alpha, pixel_alpha);
+               decon_win_set_bldeq(ctx, win, alpha, pixel_alpha);
+       }
 }
 
 static void decon_shadow_protect(struct decon_context *ctx, bool protect)
@@ -552,6 +628,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
                ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats);
                ctx->configs[win].zpos = win - ctx->first_win;
                ctx->configs[win].type = decon_win_types[win];
+               ctx->configs[win].capabilities = capabilities[win];
 
                ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
                                        &ctx->configs[win]);
@@ -569,7 +646,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
 
        decon_clear_channels(ctx->crtc);
 
-       return drm_iommu_attach_device(drm_dev, dev);
+       return exynos_drm_register_dma(drm_dev, dev);
 }
 
 static void decon_unbind(struct device *dev, struct device *master, void *data)
@@ -579,7 +656,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
        decon_disable(ctx->crtc);
 
        /* detach this sub driver from iommu mapping if supported. */
-       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
 }
 
 static const struct component_ops decon_component_ops = {
index 88cbd000eb094cb480d85d77a7cf40f664f1bd1f..381aa3d60e37a86d7bc0be1c4a8737ace9098498 100644 (file)
@@ -30,7 +30,6 @@
 #include "exynos_drm_plane.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
-#include "exynos_drm_iommu.h"
 #include "regs-decon7.h"
 
 /*
@@ -133,13 +132,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,
 
        decon_clear_channels(ctx->crtc);
 
-       return drm_iommu_attach_device(drm_dev, ctx->dev);
+       return exynos_drm_register_dma(drm_dev, ctx->dev);
 }
 
 static void decon_ctx_remove(struct decon_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
-       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
 }
 
 static u32 decon_calc_clkdiv(struct decon_context *ctx,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c
new file mode 100644 (file)
index 0000000..3432c5e
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Inki Dae <inki.dae@samsung.com>
+// Author: Andrzej Hajda <a.hajda@samsung.com>
+
+#include <drm/drmP.h>
+#include <drm/exynos_drm.h>
+#include <linux/dma-iommu.h>
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+
+#include "exynos_drm_drv.h"
+
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#else
+#define arm_iommu_create_mapping(...)  ({ NULL; })
+#define arm_iommu_attach_device(...)   ({ -ENODEV; })
+#define arm_iommu_release_mapping(...) ({ })
+#define arm_iommu_detach_device(...)   ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
+#if !defined(CONFIG_IOMMU_DMA)
+#define iommu_dma_init_domain(...) ({ -EINVAL; })
+#endif
+
+#define EXYNOS_DEV_ADDR_START  0x20000000
+#define EXYNOS_DEV_ADDR_SIZE   0x40000000
+
+static inline int configure_dma_max_seg_size(struct device *dev)
+{
+       if (!dev->dma_parms)
+               dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
+       if (!dev->dma_parms)
+               return -ENOMEM;
+
+       dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+       return 0;
+}
+
+static inline void clear_dma_max_seg_size(struct device *dev)
+{
+       kfree(dev->dma_parms);
+       dev->dma_parms = NULL;
+}
+
+/*
+ * drm_iommu_attach_device- attach device to iommu mapping
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be attach
+ *
+ * This function should be called by sub drivers to attach it to iommu
+ * mapping.
+ */
+static int drm_iommu_attach_device(struct drm_device *drm_dev,
+                               struct device *subdrv_dev)
+{
+       struct exynos_drm_private *priv = drm_dev->dev_private;
+       int ret;
+
+       if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
+               DRM_ERROR("Device %s lacks support for IOMMU\n",
+                         dev_name(subdrv_dev));
+               return -EINVAL;
+       }
+
+       ret = configure_dma_max_seg_size(subdrv_dev);
+       if (ret)
+               return ret;
+
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+               if (to_dma_iommu_mapping(subdrv_dev))
+                       arm_iommu_detach_device(subdrv_dev);
+
+               ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
+       } else if (IS_ENABLED(CONFIG_IOMMU_DMA)) {
+               ret = iommu_attach_device(priv->mapping, subdrv_dev);
+       }
+
+       if (ret)
+               clear_dma_max_seg_size(subdrv_dev);
+
+       return 0;
+}
+
+/*
+ * drm_iommu_detach_device -detach device address space mapping from device
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be detached
+ *
+ * This function should be called by sub drivers to detach it from iommu
+ * mapping
+ */
+static void drm_iommu_detach_device(struct drm_device *drm_dev,
+                               struct device *subdrv_dev)
+{
+       struct exynos_drm_private *priv = drm_dev->dev_private;
+
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+               arm_iommu_detach_device(subdrv_dev);
+       else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+               iommu_detach_device(priv->mapping, subdrv_dev);
+
+       clear_dma_max_seg_size(subdrv_dev);
+}
+
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
+{
+       struct exynos_drm_private *priv = drm->dev_private;
+
+       if (!priv->dma_dev) {
+               priv->dma_dev = dev;
+               DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
+                        dev_name(dev));
+       }
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_IOMMU))
+               return 0;
+
+       if (!priv->mapping) {
+               void *mapping;
+
+               if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+                       mapping = arm_iommu_create_mapping(&platform_bus_type,
+                               EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE);
+               else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+                       mapping = iommu_get_domain_for_dev(priv->dma_dev);
+
+               if (IS_ERR(mapping))
+                       return PTR_ERR(mapping);
+               priv->mapping = mapping;
+       }
+
+       return drm_iommu_attach_device(drm, dev);
+}
+
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
+{
+       if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
+               drm_iommu_detach_device(drm, dev);
+}
+
+void exynos_drm_cleanup_dma(struct drm_device *drm)
+{
+       struct exynos_drm_private *priv = drm->dev_private;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_IOMMU))
+               return;
+
+       arm_iommu_release_mapping(priv->mapping);
+       priv->mapping = NULL;
+       priv->dma_dev = NULL;
+}
index 6f76baf4550ada0fc6a75990abde632914f656a3..2c75e789b2a7e9faf80aa9c6eac3ef5b65fa98e6 100644 (file)
@@ -30,7 +30,6 @@
 #include "exynos_drm_ipp.h"
 #include "exynos_drm_vidi.h"
 #include "exynos_drm_g2d.h"
-#include "exynos_drm_iommu.h"
 
 #define DRIVER_NAME    "exynos"
 #define DRIVER_DESC    "Samsung SoC DRM"
@@ -175,8 +174,7 @@ struct exynos_drm_driver_info {
 
 #define DRM_COMPONENT_DRIVER   BIT(0)  /* supports component framework */
 #define DRM_VIRTUAL_DEVICE     BIT(1)  /* create virtual platform device */
-#define DRM_DMA_DEVICE         BIT(2)  /* can be used for dma allocations */
-#define DRM_FIMC_DEVICE                BIT(3)  /* devices shared with V4L2 subsystem */
+#define DRM_FIMC_DEVICE                BIT(2)  /* devices shared with V4L2 subsystem */
 
 #define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL)
 
@@ -187,16 +185,16 @@ struct exynos_drm_driver_info {
 static struct exynos_drm_driver_info exynos_drm_drivers[] = {
        {
                DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD),
-               DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
+               DRM_COMPONENT_DRIVER
        }, {
                DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON),
-               DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
+               DRM_COMPONENT_DRIVER
        }, {
                DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON),
-               DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
+               DRM_COMPONENT_DRIVER
        }, {
                DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER),
-               DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
+               DRM_COMPONENT_DRIVER
        }, {
                DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC),
                DRM_COMPONENT_DRIVER
@@ -267,27 +265,6 @@ static struct component_match *exynos_drm_match_add(struct device *dev)
        return match ?: ERR_PTR(-ENODEV);
 }
 
-static struct device *exynos_drm_get_dma_device(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
-               struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
-               struct device *dev;
-
-               if (!info->driver || !(info->flags & DRM_DMA_DEVICE))
-                       continue;
-
-               while ((dev = bus_find_device(&platform_bus_type, NULL,
-                                           &info->driver->driver,
-                                           (void *)platform_bus_type.match))) {
-                       put_device(dev);
-                       return dev;
-               }
-       }
-       return NULL;
-}
-
 static int exynos_drm_bind(struct device *dev)
 {
        struct exynos_drm_private *private;
@@ -312,23 +289,6 @@ static int exynos_drm_bind(struct device *dev)
        dev_set_drvdata(dev, drm);
        drm->dev_private = (void *)private;
 
-       /* the first real CRTC device is used for all dma mapping operations */
-       private->dma_dev = exynos_drm_get_dma_device();
-       if (!private->dma_dev) {
-               DRM_ERROR("no device found for DMA mapping operations.\n");
-               ret = -ENODEV;
-               goto err_free_private;
-       }
-       DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
-                dev_name(private->dma_dev));
-
-       /* create common IOMMU mapping for all devices attached to Exynos DRM */
-       ret = drm_create_iommu_mapping(drm);
-       if (ret < 0) {
-               DRM_ERROR("failed to create iommu mapping.\n");
-               goto err_free_private;
-       }
-
        drm_mode_config_init(drm);
 
        exynos_drm_mode_config_init(drm);
@@ -385,8 +345,7 @@ err_unbind_all:
        component_unbind_all(drm->dev, drm);
 err_mode_config_cleanup:
        drm_mode_config_cleanup(drm);
-       drm_release_iommu_mapping(drm);
-err_free_private:
+       exynos_drm_cleanup_dma(drm);
        kfree(private);
 err_free_drm:
        drm_dev_put(drm);
@@ -405,7 +364,7 @@ static void exynos_drm_unbind(struct device *dev)
 
        component_unbind_all(drm->dev, drm);
        drm_mode_config_cleanup(drm);
-       drm_release_iommu_mapping(drm);
+       exynos_drm_cleanup_dma(drm);
 
        kfree(drm->dev_private);
        drm->dev_private = NULL;
index 5e61e707f95555da181969aa71254fc71ffa4098..71eb240bc1f4f7d7c7dc1ab342cf03216ef98a44 100644 (file)
@@ -214,6 +214,17 @@ static inline struct device *to_dma_dev(struct drm_device *dev)
        return priv->dma_dev;
 }
 
+static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
+{
+       struct exynos_drm_private *priv = drm_dev->dev_private;
+
+       return priv->mapping ? true : false;
+}
+
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
+void exynos_drm_cleanup_dma(struct drm_device *drm);
+
 #ifdef CONFIG_DRM_EXYNOS_DPI
 struct drm_encoder *exynos_dpi_probe(struct device *dev);
 int exynos_dpi_remove(struct drm_encoder *encoder);
index 9f52382e19ee338e18dbe8212b0d1a69c604d3e9..31eb538a44ae1950c7f94fa9b994abb154b525df 100644 (file)
@@ -24,7 +24,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_fbdev.h"
-#include "exynos_drm_iommu.h"
 #include "exynos_drm_crtc.h"
 
 static int check_fb_gem_memory_type(struct drm_device *drm_dev,
index 01d182289efa38fd75a83cd399b02bbfd1e590c0..ce9604ca8041d7b03a783e1cad743a7480074cc3 100644 (file)
@@ -23,7 +23,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_fbdev.h"
-#include "exynos_drm_iommu.h"
 
 #define MAX_CONNECTOR          4
 #define PREFERRED_BPP          32
index e8d0670bb5f8d280a9e17a1e4270c0464b1e4abc..90dfea0aec4d3cdcf33d6635c843f5dc578812a3 100644 (file)
@@ -25,7 +25,6 @@
 #include <drm/exynos_drm.h>
 #include "regs-fimc.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
 #include "exynos_drm_ipp.h"
 
 /*
@@ -1129,7 +1128,7 @@ static int fimc_bind(struct device *dev, struct device *master, void *data)
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        ctx->drm_dev = drm_dev;
-       drm_iommu_attach_device(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev);
 
        exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1149,7 +1148,7 @@ static void fimc_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        exynos_drm_ipp_unregister(drm_dev, ipp);
-       drm_iommu_detach_device(drm_dev, dev);
+       exynos_drm_unregister_dma(drm_dev, dev);
 }
 
 static const struct component_ops fimc_component_ops = {
index b7f56935a46bc2a33fec03c18854774cb331f70d..e3d6a8584715a7966b2d87bfa546bdddf0f90605 100644 (file)
@@ -32,7 +32,6 @@
 #include "exynos_drm_fb.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_plane.h"
-#include "exynos_drm_iommu.h"
 
 /*
  * FIMD stands for Fully Interactive Mobile Display and
@@ -1011,7 +1010,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
        if (is_drm_iommu_supported(drm_dev))
                fimd_clear_channels(ctx->crtc);
 
-       return drm_iommu_attach_device(drm_dev, dev);
+       return exynos_drm_register_dma(drm_dev, dev);
 }
 
 static void fimd_unbind(struct device *dev, struct device *master,
@@ -1021,7 +1020,7 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_disable(ctx->crtc);
 
-       drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
 
        if (ctx->encoder)
                exynos_dpi_remove(ctx->encoder);
index f2481a2014bb3c91ac1c8d60711a5fea89f43636..24c536d6d9cf866afda4c9839fdbc6e61a5a8854 100644 (file)
@@ -25,7 +25,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_g2d.h"
 #include "exynos_drm_gem.h"
-#include "exynos_drm_iommu.h"
 
 #define G2D_HW_MAJOR_VER               4
 #define G2D_HW_MINOR_VER               1
@@ -1405,7 +1404,7 @@ static int g2d_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       ret = drm_iommu_attach_device(drm_dev, dev);
+       ret = exynos_drm_register_dma(drm_dev, dev);
        if (ret < 0) {
                dev_err(dev, "failed to enable iommu.\n");
                g2d_fini_cmdlist(g2d);
@@ -1430,7 +1429,7 @@ static void g2d_unbind(struct device *dev, struct device *master, void *data)
        priv->g2d_dev = NULL;
 
        cancel_work_sync(&g2d->runqueue_work);
-       drm_iommu_detach_device(g2d->drm_dev, dev);
+       exynos_drm_unregister_dma(g2d->drm_dev, dev);
 }
 
 static const struct component_ops g2d_component_ops = {
index 34ace85feb6883e3dcf9793d5057a5c1de2ebb21..df66c383a877a583be0e457a0f866a8b5f3b819f 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
-#include "exynos_drm_iommu.h"
 
 static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
 {
index ce15d46bfce8a57dc007e0af5317dd9d1f7385a0..f048d97fe9e2e9b522b0366b868e9ca09f156c97 100644 (file)
@@ -24,7 +24,6 @@
 #include <drm/exynos_drm.h>
 #include "regs-gsc.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
 #include "exynos_drm_ipp.h"
 
 /*
@@ -1170,7 +1169,7 @@ static int gsc_bind(struct device *dev, struct device *master, void *data)
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        ctx->drm_dev = drm_dev;
-       drm_iommu_attach_device(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev);
 
        exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1190,7 +1189,7 @@ static void gsc_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        exynos_drm_ipp_unregister(drm_dev, ipp);
-       drm_iommu_detach_device(drm_dev, dev);
+       exynos_drm_unregister_dma(drm_dev, dev);
 }
 
 static const struct component_ops gsc_component_ops = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
deleted file mode 100644 (file)
index 0f37370..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* exynos_drm_iommu.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Author: Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/exynos_drm.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/iommu.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
-
-static inline int configure_dma_max_seg_size(struct device *dev)
-{
-       if (!dev->dma_parms)
-               dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
-       if (!dev->dma_parms)
-               return -ENOMEM;
-
-       dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
-       return 0;
-}
-
-static inline void clear_dma_max_seg_size(struct device *dev)
-{
-       kfree(dev->dma_parms);
-       dev->dma_parms = NULL;
-}
-
-/*
- * drm_create_iommu_mapping - create a mapping structure
- *
- * @drm_dev: DRM device
- */
-int drm_create_iommu_mapping(struct drm_device *drm_dev)
-{
-       struct exynos_drm_private *priv = drm_dev->dev_private;
-
-       return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
-                                            EXYNOS_DEV_ADDR_SIZE);
-}
-
-/*
- * drm_release_iommu_mapping - release iommu mapping structure
- *
- * @drm_dev: DRM device
- */
-void drm_release_iommu_mapping(struct drm_device *drm_dev)
-{
-       struct exynos_drm_private *priv = drm_dev->dev_private;
-
-       __exynos_iommu_release_mapping(priv);
-}
-
-/*
- * drm_iommu_attach_device- attach device to iommu mapping
- *
- * @drm_dev: DRM device
- * @subdrv_dev: device to be attach
- *
- * This function should be called by sub drivers to attach it to iommu
- * mapping.
- */
-int drm_iommu_attach_device(struct drm_device *drm_dev,
-                               struct device *subdrv_dev)
-{
-       struct exynos_drm_private *priv = drm_dev->dev_private;
-       int ret;
-
-       if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
-               DRM_ERROR("Device %s lacks support for IOMMU\n",
-                         dev_name(subdrv_dev));
-               return -EINVAL;
-       }
-
-       ret = configure_dma_max_seg_size(subdrv_dev);
-       if (ret)
-               return ret;
-
-       ret = __exynos_iommu_attach(priv, subdrv_dev);
-       if (ret)
-               clear_dma_max_seg_size(subdrv_dev);
-
-       return 0;
-}
-
-/*
- * drm_iommu_detach_device -detach device address space mapping from device
- *
- * @drm_dev: DRM device
- * @subdrv_dev: device to be detached
- *
- * This function should be called by sub drivers to detach it from iommu
- * mapping
- */
-void drm_iommu_detach_device(struct drm_device *drm_dev,
-                               struct device *subdrv_dev)
-{
-       struct exynos_drm_private *priv = drm_dev->dev_private;
-
-       __exynos_iommu_detach(priv, subdrv_dev);
-       clear_dma_max_seg_size(subdrv_dev);
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
deleted file mode 100644 (file)
index 797d9ee..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* exynos_drm_iommu.h
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Authoer: Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_IOMMU_H_
-#define _EXYNOS_DRM_IOMMU_H_
-
-#define EXYNOS_DEV_ADDR_START  0x20000000
-#define EXYNOS_DEV_ADDR_SIZE   0x40000000
-
-#ifdef CONFIG_DRM_EXYNOS_IOMMU
-
-#if defined(CONFIG_ARM_DMA_USE_IOMMU)
-#include <asm/dma-iommu.h>
-
-static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
-                                       unsigned long start, unsigned long size)
-{
-       priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
-                                                size);
-       return IS_ERR(priv->mapping);
-}
-
-static inline void
-__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
-{
-       arm_iommu_release_mapping(priv->mapping);
-}
-
-static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
-                                       struct device *dev)
-{
-       if (dev->archdata.mapping)
-               arm_iommu_detach_device(dev);
-
-       return arm_iommu_attach_device(dev, priv->mapping);
-}
-
-static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
-                                        struct device *dev)
-{
-       arm_iommu_detach_device(dev);
-}
-
-#elif defined(CONFIG_IOMMU_DMA)
-#include <linux/dma-iommu.h>
-
-static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
-                                       unsigned long start, unsigned long size)
-{
-       priv->mapping = iommu_get_domain_for_dev(priv->dma_dev);
-       return 0;
-}
-
-static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
-{
-       priv->mapping = NULL;
-}
-
-static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
-                                       struct device *dev)
-{
-       struct iommu_domain *domain = priv->mapping;
-
-       if (dev != priv->dma_dev)
-               return iommu_attach_device(domain, dev);
-       return 0;
-}
-
-static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
-                                        struct device *dev)
-{
-       struct iommu_domain *domain = priv->mapping;
-
-       if (dev != priv->dma_dev)
-               iommu_detach_device(domain, dev);
-}
-#else
-#error Unsupported architecture and IOMMU/DMA-mapping glue code
-#endif
-
-int drm_create_iommu_mapping(struct drm_device *drm_dev);
-
-void drm_release_iommu_mapping(struct drm_device *drm_dev);
-
-int drm_iommu_attach_device(struct drm_device *drm_dev,
-                               struct device *subdrv_dev);
-
-void drm_iommu_detach_device(struct drm_device *dev_dev,
-                               struct device *subdrv_dev);
-
-static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
-{
-       struct exynos_drm_private *priv = drm_dev->dev_private;
-
-       return priv->mapping ? true : false;
-}
-
-#else
-
-static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
-{
-       return 0;
-}
-
-static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
-{
-}
-
-static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
-                                               struct device *subdrv_dev)
-{
-       return 0;
-}
-
-static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
-                                               struct device *subdrv_dev)
-{
-}
-
-static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
-{
-       return false;
-}
-
-#endif
-#endif
index a820a68429b9a8f56be132d251b2f4ea81f6c1b4..8d67b2a54be3b66f68e008d07a6203140bf2f7f4 100644 (file)
@@ -23,7 +23,6 @@
 #include <drm/exynos_drm.h>
 #include "regs-rotator.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
 #include "exynos_drm_ipp.h"
 
 /*
@@ -244,7 +243,7 @@ static int rotator_bind(struct device *dev, struct device *master, void *data)
        struct exynos_drm_ipp *ipp = &rot->ipp;
 
        rot->drm_dev = drm_dev;
-       drm_iommu_attach_device(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev);
 
        exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
                           DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
@@ -263,7 +262,7 @@ static void rotator_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &rot->ipp;
 
        exynos_drm_ipp_unregister(drm_dev, ipp);
-       drm_iommu_detach_device(rot->drm_dev, rot->dev);
+       exynos_drm_unregister_dma(rot->drm_dev, rot->dev);
 }
 
 static const struct component_ops rotator_component_ops = {
index cd66774e817d37a9d49aa61c40733192164531e5..71270efa64f3f35e7d983488b13202192936b245 100644 (file)
@@ -23,7 +23,6 @@
 #include "regs-scaler.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_iommu.h"
 #include "exynos_drm_ipp.h"
 
 #define scaler_read(offset)            readl(scaler->regs + (offset))
@@ -452,7 +451,7 @@ static int scaler_bind(struct device *dev, struct device *master, void *data)
        struct exynos_drm_ipp *ipp = &scaler->ipp;
 
        scaler->drm_dev = drm_dev;
-       drm_iommu_attach_device(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev);
 
        exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -473,7 +472,7 @@ static void scaler_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &scaler->ipp;
 
        exynos_drm_ipp_unregister(drm_dev, ipp);
-       drm_iommu_detach_device(scaler->drm_dev, scaler->dev);
+       exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev);
 }
 
 static const struct component_ops scaler_component_ops = {
index e3a4ecbc503b937e4d93a24450e9132024381db1..0573eab0e190f6d76d0e970a9b0b37c67c6dfe3a 100644 (file)
@@ -40,7 +40,6 @@
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_plane.h"
-#include "exynos_drm_iommu.h"
 
 #define MIXER_WIN_NR           3
 #define VP_DEFAULT_WIN         2
@@ -381,19 +380,16 @@ static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
        mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
 }
 
-static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
+static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, struct drm_display_mode *mode)
 {
+       enum hdmi_quantization_range range = drm_default_rgb_quant_range(mode);
        u32 val;
 
-       switch (height) {
-       case 480:
-       case 576:
-               val = MXR_CFG_RGB601_0_255;
-               break;
-       case 720:
-       case 1080:
-       default:
-               val = MXR_CFG_RGB709_16_235;
+       if (mode->vdisplay < 720) {
+               val = MXR_CFG_RGB601;
+       } else {
+               val = MXR_CFG_RGB709;
+
                /* Configure the BT.709 CSC matrix for full range RGB. */
                mixer_reg_write(ctx, MXR_CM_COEFF_Y,
                        MXR_CSC_CT( 0.184,  0.614,  0.063) |
@@ -402,9 +398,13 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
                        MXR_CSC_CT(-0.102, -0.338,  0.440));
                mixer_reg_write(ctx, MXR_CM_COEFF_CR,
                        MXR_CSC_CT( 0.440, -0.399, -0.040));
-               break;
        }
 
+       if (range == HDMI_QUANTIZATION_RANGE_FULL)
+               val |= MXR_CFG_QUANT_RANGE_FULL;
+       else
+               val |= MXR_CFG_QUANT_RANGE_LIMITED;
+
        mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
 }
 
@@ -461,7 +461,7 @@ static void mixer_commit(struct mixer_context *ctx)
        struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
 
        mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
-       mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
+       mixer_cfg_rgb_fmt(ctx, mode);
        mixer_run(ctx);
 }
 
@@ -878,12 +878,12 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
                }
        }
 
-       return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
+       return exynos_drm_register_dma(drm_dev, mixer_ctx->dev);
 }
 
 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
 {
-       drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
+       exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
index 19ad9e47945eb6f3fa3902fb8b80084fdbf7672f..63db6974bf14bc597c8df59f5198904cdf69071f 100644 (file)
 #define WINCONx_BURSTLEN_16WORD                (0x0 << 10)
 #define WINCONx_BURSTLEN_8WORD         (0x1 << 10)
 #define WINCONx_BURSTLEN_4WORD         (0x2 << 10)
+#define WINCONx_ALPHA_MUL_F            (1 << 7)
 #define WINCONx_BLD_PIX_F              (1 << 6)
 #define WINCONx_BPPMODE_MASK           (0xf << 2)
 #define WINCONx_BPPMODE_16BPP_565      (0x5 << 2)
 #define WINCONx_BPPMODE_16BPP_A4444    (0xe << 2)
 #define WINCONx_ALPHA_SEL_F            (1 << 1)
 #define WINCONx_ENWIN_F                        (1 << 0)
+#define WINCONx_BLEND_MODE_MASK                (0xc2)
 
 /* SHADOWCON */
 #define SHADOWCON_PROTECT_MASK         GENMASK(14, 10)
 #define SHADOWCON_Wx_PROTECT(n)                (1 << (10 + (n)))
 
+/* VIDOSDxC */
+#define VIDOSDxC_ALPHA0_RGB_MASK       (0xffffff)
+
 /* VIDOSDxD */
 #define VIDOSD_Wx_ALPHA_R_F(n)         (((n) & 0xff) << 16)
 #define VIDOSD_Wx_ALPHA_G_F(n)         (((n) & 0xff) << 8)
 #define CRCCTRL_CRCEN                  (0x1 << 0)
 #define CRCCTRL_MASK                   (0x7)
 
+/* BLENDCON */
+#define BLEND_NEW                      (1 << 0)
+
+/* BLENDERQx */
+#define BLENDERQ_ZERO                  0x0
+#define BLENDERQ_ONE                   0x1
+#define BLENDERQ_ALPHA_A               0x2
+#define BLENDERQ_ONE_MINUS_ALPHA_A     0x3
+#define BLENDERQ_ALPHA0                        0x6
+#define BLENDERQ_Q_FUNC_F(n)           (n << 18)
+#define BLENDERQ_P_FUNC_F(n)           (n << 12)
+#define BLENDERQ_B_FUNC_F(n)           (n << 6)
+#define BLENDERQ_A_FUNC_F(n)           (n << 0)
+
+/* BLENDCON */
+#define BLEND_NEW                      (1 << 0)
+
 #endif /* EXYNOS_REGS_DECON5433_H */
index d2b8194a07bfb93c71aa21d4df6a154178a1a8bb..5ff095b0c1b371cb6355a6f7ba96a8a30c2e89f8 100644 (file)
 /* bits for MXR_CFG */
 #define MXR_CFG_LAYER_UPDATE           (1 << 31)
 #define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29)
-#define MXR_CFG_RGB601_0_255           (0 << 9)
-#define MXR_CFG_RGB601_16_235          (1 << 9)
-#define MXR_CFG_RGB709_0_255           (2 << 9)
-#define MXR_CFG_RGB709_16_235          (3 << 9)
+#define MXR_CFG_QUANT_RANGE_FULL       (0 << 9)
+#define MXR_CFG_QUANT_RANGE_LIMITED    (1 << 9)
+#define MXR_CFG_RGB601                 (0 << 10)
+#define MXR_CFG_RGB709                 (1 << 10)
+
 #define MXR_CFG_RGB_FMT_MASK           0x600
 #define MXR_CFG_OUT_YUV444             (0 << 8)
 #define MXR_CFG_OUT_RGB888             (1 << 8)
index 0e3752437e44fd822e91949db7c234e9889c30c1..18afc94e4dff89416bcdd16180a573e2f29a1470 100644 (file)
@@ -17,6 +17,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <video/videomode.h>
 
 #include "fsl_dcu_drm_crtc.h"
 #include "fsl_dcu_drm_drv.h"
@@ -85,40 +86,34 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
        struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
        struct drm_connector *con = &fsl_dev->connector.base;
        struct drm_display_mode *mode = &crtc->state->mode;
-       unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0;
+       unsigned int pol = 0;
+       struct videomode vm;
 
-       index = drm_crtc_index(crtc);
        clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000);
 
-       /* Configure timings: */
-       hbp = mode->htotal - mode->hsync_end;
-       hfp = mode->hsync_start - mode->hdisplay;
-       hsw = mode->hsync_end - mode->hsync_start;
-       vbp = mode->vtotal - mode->vsync_end;
-       vfp = mode->vsync_start - mode->vdisplay;
-       vsw = mode->vsync_end - mode->vsync_start;
+       drm_display_mode_to_videomode(mode, &vm);
 
        /* INV_PXCK as default (most display sample data on rising edge) */
        if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE))
                pol |= DCU_SYN_POL_INV_PXCK;
 
-       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+       if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
                pol |= DCU_SYN_POL_INV_HS_LOW;
 
-       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+       if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
                pol |= DCU_SYN_POL_INV_VS_LOW;
 
        regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
-                    DCU_HSYN_PARA_BP(hbp) |
-                    DCU_HSYN_PARA_PW(hsw) |
-                    DCU_HSYN_PARA_FP(hfp));
+                    DCU_HSYN_PARA_BP(vm.hback_porch) |
+                    DCU_HSYN_PARA_PW(vm.hsync_len) |
+                    DCU_HSYN_PARA_FP(vm.hfront_porch));
        regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
-                    DCU_VSYN_PARA_BP(vbp) |
-                    DCU_VSYN_PARA_PW(vsw) |
-                    DCU_VSYN_PARA_FP(vfp));
+                    DCU_VSYN_PARA_BP(vm.vback_porch) |
+                    DCU_VSYN_PARA_PW(vm.vsync_len) |
+                    DCU_VSYN_PARA_FP(vm.vfront_porch));
        regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
-                    DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
-                    DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
+                    DCU_DISP_SIZE_DELTA_Y(vm.vactive) |
+                    DCU_DISP_SIZE_DELTA_X(vm.hactive));
        regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol);
        regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
                     DCU_BGND_G(0) | DCU_BGND_B(0));
index 0496be5212e126fc793aa5f50169fd29f0f6d26f..ceddc3e29258fdd8ed9b5346e94dcafae4b0d280 100644 (file)
@@ -26,6 +26,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_modeset_helper.h>
 
@@ -89,20 +90,11 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
                        "Invalid legacyfb_depth.  Defaulting to 24bpp\n");
                legacyfb_depth = 24;
        }
-       fsl_dev->fbdev = drm_fbdev_cma_init(dev, legacyfb_depth, 1);
-       if (IS_ERR(fsl_dev->fbdev)) {
-               ret = PTR_ERR(fsl_dev->fbdev);
-               fsl_dev->fbdev = NULL;
-               goto done;
-       }
 
        return 0;
 done:
        drm_kms_helper_poll_fini(dev);
 
-       if (fsl_dev->fbdev)
-               drm_fbdev_cma_fini(fsl_dev->fbdev);
-
        drm_mode_config_cleanup(dev);
        drm_irq_uninstall(dev);
        dev->dev_private = NULL;
@@ -112,14 +104,9 @@ done:
 
 static void fsl_dcu_unload(struct drm_device *dev)
 {
-       struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
        drm_atomic_helper_shutdown(dev);
        drm_kms_helper_poll_fini(dev);
 
-       if (fsl_dev->fbdev)
-               drm_fbdev_cma_fini(fsl_dev->fbdev);
-
        drm_mode_config_cleanup(dev);
        drm_irq_uninstall(dev);
 
@@ -147,19 +134,11 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static void fsl_dcu_drm_lastclose(struct drm_device *dev)
-{
-       struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
-       drm_fbdev_cma_restore_mode(fsl_dev->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
 
 static struct drm_driver fsl_dcu_drm_driver = {
        .driver_features        = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
                                | DRIVER_PRIME | DRIVER_ATOMIC,
-       .lastclose              = fsl_dcu_drm_lastclose,
        .load                   = fsl_dcu_load,
        .unload                 = fsl_dcu_unload,
        .irq_handler            = fsl_dcu_drm_irq,
@@ -355,6 +334,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
        if (ret < 0)
                goto put;
 
+       drm_fbdev_generic_setup(drm, legacyfb_depth);
+
        return 0;
 
 put:
index 93bfb98012d461cac745ed4852ff9807784d7efb..cb87bb74cb87a472db1e023730a44e71045fd4ff 100644 (file)
@@ -191,7 +191,6 @@ struct fsl_dcu_drm_device {
        /*protects hardware register*/
        spinlock_t irq_lock;
        struct drm_device *drm;
-       struct drm_fbdev_cma *fbdev;
        struct drm_crtc crtc;
        struct drm_encoder encoder;
        struct fsl_dcu_drm_connector connector;
index 45c25a488f429f58b126de5ce1a5c2ef6c4aa8d5..3c168ae77b0cdf537222ae48c3c383b15533995a 100644 (file)
@@ -49,8 +49,6 @@ struct hibmc_drm_private {
        bool mode_config_initialized;
 
        /* ttm */
-       struct drm_global_reference mem_global_ref;
-       struct ttm_bo_global_ref bo_global_ref;
        struct ttm_bo_device bdev;
        bool initialized;
 
index 2e3e0bdb8932f8a210b698a1adb8d8a089e91e2b..dd383267884cfe46fd00f5149464dc0efbff59c6 100644 (file)
@@ -29,55 +29,6 @@ hibmc_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct hibmc_drm_private, bdev);
 }
 
-static int
-hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void
-hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
-{
-       int ret;
-
-       hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
-       hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
-       hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
-       hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
-       ret = drm_global_item_ref(&hibmc->mem_global_ref);
-       if (ret) {
-               DRM_ERROR("could not get ref on ttm global: %d\n", ret);
-               return ret;
-       }
-
-       hibmc->bo_global_ref.mem_glob =
-               hibmc->mem_global_ref.object;
-       hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
-       hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
-       hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
-       hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
-       ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
-       if (ret) {
-               DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
-               drm_global_item_unref(&hibmc->mem_global_ref);
-               return ret;
-       }
-       return 0;
-}
-
-static void
-hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
-{
-       drm_global_item_unref(&hibmc->bo_global_ref.ref);
-       drm_global_item_unref(&hibmc->mem_global_ref);
-       hibmc->mem_global_ref.release = NULL;
-}
-
 static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
@@ -237,18 +188,12 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc)
        struct drm_device *dev = hibmc->dev;
        struct ttm_bo_device *bdev = &hibmc->bdev;
 
-       ret = hibmc_ttm_global_init(hibmc);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&hibmc->bdev,
-                                hibmc->bo_global_ref.ref.object,
                                 &hibmc_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET,
                                 true);
        if (ret) {
-               hibmc_ttm_global_release(hibmc);
                DRM_ERROR("error initializing bo driver: %d\n", ret);
                return ret;
        }
@@ -256,7 +201,6 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc)
        ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
                             hibmc->fb_size >> PAGE_SHIFT);
        if (ret) {
-               hibmc_ttm_global_release(hibmc);
                DRM_ERROR("failed ttm VRAM init: %d\n", ret);
                return ret;
        }
@@ -271,7 +215,6 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
                return;
 
        ttm_bo_device_release(&hibmc->bdev);
-       hibmc_ttm_global_release(hibmc);
        hibmc->mm_inited = false;
 }
 
index 1c2857f13ad438f2433ae0a90a41227bd4e8f683..19b5fe5016bf6617394da4d0e795d62e8d49a857 100644 (file)
@@ -75,6 +75,7 @@ i915-y += i915_cmd_parser.o \
          i915_gemfs.o \
          i915_query.o \
          i915_request.o \
+         i915_scheduler.o \
          i915_timeline.o \
          i915_trace_points.o \
          i915_vma.o \
@@ -112,6 +113,8 @@ i915-y += intel_audio.o \
          intel_bios.o \
          intel_cdclk.o \
          intel_color.o \
+         intel_combo_phy.o \
+         intel_connector.o \
          intel_display.o \
          intel_dpio_phy.o \
          intel_dpll_mgr.o \
@@ -120,9 +123,9 @@ i915-y += intel_audio.o \
          intel_frontbuffer.o \
          intel_hdcp.o \
          intel_hotplug.o \
-         intel_modes.o \
          intel_overlay.o \
          intel_psr.o \
+         intel_quirks.o \
          intel_sideband.o \
          intel_sprite.o
 i915-$(CONFIG_ACPI)            += intel_acpi.o intel_opregion.o
@@ -142,6 +145,7 @@ i915-y += dvo_ch7017.o \
          intel_dp_link_training.o \
          intel_dp_mst.o \
          intel_dp.o \
+         intel_dsi.o \
          intel_dsi_dcs_backlight.o \
          intel_dsi_vbt.o \
          intel_dvo.o \
@@ -153,14 +157,17 @@ i915-y += dvo_ch7017.o \
          intel_sdvo.o \
          intel_tv.o \
          vlv_dsi.o \
-         vlv_dsi_pll.o
+         vlv_dsi_pll.o \
+         intel_vdsc.o
 
 # Post-mortem debug and GPU hang state capture
 i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
 i915-$(CONFIG_DRM_I915_SELFTEST) += \
        selftests/i915_random.o \
        selftests/i915_selftest.o \
-       selftests/igt_flush_test.o
+       selftests/igt_flush_test.o \
+       selftests/igt_reset.o \
+       selftests/igt_spinner.o
 
 # virtual gpu code
 i915-y += i915_vgpu.o
index ea34003d6dd251e26ac8fad62607d043374e9b71..b8fbe3fabea3062203ad64d5ff33fd4ceebf0da2 100644 (file)
@@ -334,6 +334,28 @@ static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
        i915_gem_object_put(wa_ctx->indirect_ctx.obj);
 }
 
+static int set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload,
+                                        struct i915_gem_context *ctx)
+{
+       struct intel_vgpu_mm *mm = workload->shadow_mm;
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+       int i = 0;
+
+       if (mm->type != INTEL_GVT_MM_PPGTT || !mm->ppgtt_mm.shadowed)
+               return -1;
+
+       if (mm->ppgtt_mm.root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
+               px_dma(&ppgtt->pml4) = mm->ppgtt_mm.shadow_pdps[0];
+       } else {
+               for (i = 0; i < GVT_RING_CTX_NR_PDPS; i++) {
+                       px_dma(ppgtt->pdp.page_directory[i]) =
+                               mm->ppgtt_mm.shadow_pdps[i];
+               }
+       }
+
+       return 0;
+}
+
 /**
  * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and
  * shadow it as well, include ringbuffer,wa_ctx and ctx.
@@ -358,6 +380,12 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
        if (workload->req)
                return 0;
 
+       ret = set_context_ppgtt_from_shadow(workload, shadow_ctx);
+       if (ret < 0) {
+               gvt_vgpu_err("workload shadow ppgtt isn't ready\n");
+               return ret;
+       }
+
        /* pin shadow context by gvt even the shadow context will be pinned
         * when i915 alloc request. That is because gvt will update the guest
         * context from shadow context when workload is completed, and at that
index 4f3ac0a128893405c61e7ea4769215ce9d2cdc4e..38dcee1ca062483272948bce3a7d9af2b4c83a7d 100644 (file)
@@ -943,30 +943,30 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
 static ssize_t gpu_state_read(struct file *file, char __user *ubuf,
                              size_t count, loff_t *pos)
 {
-       struct i915_gpu_state *error = file->private_data;
-       struct drm_i915_error_state_buf str;
+       struct i915_gpu_state *error;
        ssize_t ret;
-       loff_t tmp;
+       void *buf;
 
+       error = file->private_data;
        if (!error)
                return 0;
 
-       ret = i915_error_state_buf_init(&str, error->i915, count, *pos);
-       if (ret)
-               return ret;
+       /* Bounce buffer required because of kernfs __user API convenience. */
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       ret = i915_error_state_to_str(&str, error);
-       if (ret)
+       ret = i915_gpu_state_copy_to_buffer(error, buf, *pos, count);
+       if (ret <= 0)
                goto out;
 
-       tmp = 0;
-       ret = simple_read_from_buffer(ubuf, count, &tmp, str.buf, str.bytes);
-       if (ret < 0)
-               goto out;
+       if (!copy_to_user(ubuf, buf, ret))
+               *pos += ret;
+       else
+               ret = -EFAULT;
 
-       *pos = str.start + ret;
 out:
-       i915_error_state_buf_release(&str);
+       kfree(buf);
        return ret;
 }
 
@@ -1788,6 +1788,8 @@ static int i915_emon_status(struct seq_file *m, void *unused)
        if (!IS_GEN5(dev_priv))
                return -ENODEV;
 
+       intel_runtime_pm_get(dev_priv);
+
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
@@ -1802,6 +1804,8 @@ static int i915_emon_status(struct seq_file *m, void *unused)
        seq_printf(m, "GFX power: %ld\n", gfx);
        seq_printf(m, "Total power: %ld\n", chipset + gfx);
 
+       intel_runtime_pm_put(dev_priv);
+
        return 0;
 }
 
@@ -2215,8 +2219,23 @@ static int i915_rps_boost_info(struct seq_file *m, void *data)
        struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct drm_device *dev = &dev_priv->drm;
        struct intel_rps *rps = &dev_priv->gt_pm.rps;
+       u32 act_freq = rps->cur_freq;
        struct drm_file *file;
 
+       if (intel_runtime_pm_get_if_in_use(dev_priv)) {
+               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+                       mutex_lock(&dev_priv->pcu_lock);
+                       act_freq = vlv_punit_read(dev_priv,
+                                                 PUNIT_REG_GPU_FREQ_STS);
+                       act_freq = (act_freq >> 8) & 0xff;
+                       mutex_unlock(&dev_priv->pcu_lock);
+               } else {
+                       act_freq = intel_get_cagf(dev_priv,
+                                                 I915_READ(GEN6_RPSTAT1));
+               }
+               intel_runtime_pm_put(dev_priv);
+       }
+
        seq_printf(m, "RPS enabled? %d\n", rps->enabled);
        seq_printf(m, "GPU busy? %s [%d requests]\n",
                   yesno(dev_priv->gt.awake), dev_priv->gt.active_requests);
@@ -2224,8 +2243,9 @@ static int i915_rps_boost_info(struct seq_file *m, void *data)
        seq_printf(m, "Boosts outstanding? %d\n",
                   atomic_read(&rps->num_waiters));
        seq_printf(m, "Interactive? %d\n", READ_ONCE(rps->power.interactive));
-       seq_printf(m, "Frequency requested %d\n",
-                  intel_gpu_freq(dev_priv, rps->cur_freq));
+       seq_printf(m, "Frequency requested %d, actual %d\n",
+                  intel_gpu_freq(dev_priv, rps->cur_freq),
+                  intel_gpu_freq(dev_priv, act_freq));
        seq_printf(m, "  min hard:%d, soft:%d; max soft:%d, hard:%d\n",
                   intel_gpu_freq(dev_priv, rps->min_freq),
                   intel_gpu_freq(dev_priv, rps->min_freq_softlimit),
@@ -2900,16 +2920,15 @@ static int i915_dmc_info(struct seq_file *m, void *unused)
        seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version),
                   CSR_VERSION_MINOR(csr->version));
 
-       if (IS_KABYLAKE(dev_priv) ||
-           (IS_SKYLAKE(dev_priv) && csr->version >= CSR_VERSION(1, 6))) {
-               seq_printf(m, "DC3 -> DC5 count: %d\n",
-                          I915_READ(SKL_CSR_DC3_DC5_COUNT));
+       if (WARN_ON(INTEL_GEN(dev_priv) > 11))
+               goto out;
+
+       seq_printf(m, "DC3 -> DC5 count: %d\n",
+                  I915_READ(IS_BROXTON(dev_priv) ? BXT_CSR_DC3_DC5_COUNT :
+                                                   SKL_CSR_DC3_DC5_COUNT));
+       if (!IS_GEN9_LP(dev_priv))
                seq_printf(m, "DC5 -> DC6 count: %d\n",
                           I915_READ(SKL_CSR_DC5_DC6_COUNT));
-       } else if (IS_BROXTON(dev_priv) && csr->version >= CSR_VERSION(1, 4)) {
-               seq_printf(m, "DC3 -> DC5 count: %d\n",
-                          I915_READ(BXT_CSR_DC3_DC5_COUNT));
-       }
 
 out:
        seq_printf(m, "program base: 0x%08x\n", I915_READ(CSR_PROGRAM(0)));
@@ -3049,16 +3068,17 @@ static void intel_connector_info(struct seq_file *m,
        seq_printf(m, "connector %d: type %s, status: %s\n",
                   connector->base.id, connector->name,
                   drm_get_connector_status_name(connector->status));
-       if (connector->status == connector_status_connected) {
-               seq_printf(m, "\tname: %s\n", connector->display_info.name);
-               seq_printf(m, "\tphysical dimensions: %dx%dmm\n",
-                          connector->display_info.width_mm,
-                          connector->display_info.height_mm);
-               seq_printf(m, "\tsubpixel order: %s\n",
-                          drm_get_subpixel_order_name(connector->display_info.subpixel_order));
-               seq_printf(m, "\tCEA rev: %d\n",
-                          connector->display_info.cea_rev);
-       }
+
+       if (connector->status == connector_status_disconnected)
+               return;
+
+       seq_printf(m, "\tname: %s\n", connector->display_info.name);
+       seq_printf(m, "\tphysical dimensions: %dx%dmm\n",
+                  connector->display_info.width_mm,
+                  connector->display_info.height_mm);
+       seq_printf(m, "\tsubpixel order: %s\n",
+                  drm_get_subpixel_order_name(connector->display_info.subpixel_order));
+       seq_printf(m, "\tCEA rev: %d\n", connector->display_info.cea_rev);
 
        if (!intel_encoder)
                return;
@@ -3355,13 +3375,15 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
 
 static int i915_wa_registers(struct seq_file *m, void *unused)
 {
-       struct i915_workarounds *wa = &node_to_i915(m->private)->workarounds;
-       int i;
+       struct drm_i915_private *i915 = node_to_i915(m->private);
+       const struct i915_wa_list *wal = &i915->engine[RCS]->ctx_wa_list;
+       struct i915_wa *wa;
+       unsigned int i;
 
-       seq_printf(m, "Workarounds applied: %d\n", wa->count);
-       for (i = 0; i < wa->count; ++i)
+       seq_printf(m, "Workarounds applied: %u\n", wal->count);
+       for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
                seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X\n",
-                          wa->reg[i].addr, wa->reg[i].value, wa->reg[i].mask);
+                          i915_mmio_reg_offset(wa->reg), wa->val, wa->mask);
 
        return 0;
 }
@@ -3421,31 +3443,32 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
 {
        struct drm_i915_private *dev_priv = node_to_i915(m->private);
        struct drm_device *dev = &dev_priv->drm;
-       struct skl_ddb_allocation *ddb;
        struct skl_ddb_entry *entry;
-       enum pipe pipe;
-       int plane;
+       struct intel_crtc *crtc;
 
        if (INTEL_GEN(dev_priv) < 9)
                return -ENODEV;
 
        drm_modeset_lock_all(dev);
 
-       ddb = &dev_priv->wm.skl_hw.ddb;
-
        seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
 
-       for_each_pipe(dev_priv, pipe) {
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+               enum pipe pipe = crtc->pipe;
+               enum plane_id plane_id;
+
                seq_printf(m, "Pipe %c\n", pipe_name(pipe));
 
-               for_each_universal_plane(dev_priv, pipe, plane) {
-                       entry = &ddb->plane[pipe][plane];
-                       seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane + 1,
+               for_each_plane_id_on_crtc(crtc, plane_id) {
+                       entry = &crtc_state->wm.skl.plane_ddb_y[plane_id];
+                       seq_printf(m, "  Plane%-8d%8u%8u%8u\n", plane_id + 1,
                                   entry->start, entry->end,
                                   skl_ddb_entry_size(entry));
                }
 
-               entry = &ddb->plane[pipe][PLANE_CURSOR];
+               entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR];
                seq_printf(m, "  %-13s%8u%8u%8u\n", "Cursor", entry->start,
                           entry->end, skl_ddb_entry_size(entry));
        }
@@ -4172,6 +4195,7 @@ i915_drop_caches_set(void *data, u64 val)
 
        DRM_DEBUG("Dropping caches: 0x%08llx [0x%08llx]\n",
                  val, val & DROP_ALL);
+       intel_runtime_pm_get(i915);
 
        if (val & DROP_RESET_ACTIVE && !intel_engines_are_idle(i915))
                i915_gem_set_wedged(i915);
@@ -4181,7 +4205,7 @@ i915_drop_caches_set(void *data, u64 val)
        if (val & (DROP_ACTIVE | DROP_RETIRE | DROP_RESET_SEQNO)) {
                ret = mutex_lock_interruptible(&i915->drm.struct_mutex);
                if (ret)
-                       return ret;
+                       goto out;
 
                if (val & DROP_ACTIVE)
                        ret = i915_gem_wait_for_idle(i915,
@@ -4189,11 +4213,8 @@ i915_drop_caches_set(void *data, u64 val)
                                                     I915_WAIT_LOCKED,
                                                     MAX_SCHEDULE_TIMEOUT);
 
-               if (ret == 0 && val & DROP_RESET_SEQNO) {
-                       intel_runtime_pm_get(i915);
+               if (ret == 0 && val & DROP_RESET_SEQNO)
                        ret = i915_gem_set_global_seqno(&i915->drm, 1);
-                       intel_runtime_pm_put(i915);
-               }
 
                if (val & DROP_RETIRE)
                        i915_retire_requests(i915);
@@ -4231,6 +4252,9 @@ i915_drop_caches_set(void *data, u64 val)
        if (val & DROP_FREED)
                i915_gem_drain_freed_objects(i915);
 
+out:
+       intel_runtime_pm_put(i915);
+
        return ret;
 }
 
@@ -4331,7 +4355,7 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv,
        for (s = 0; s < info->sseu.max_slices; s++) {
                /*
                 * FIXME: Valid SS Mask respects the spec and read
-                * only valid bits for those registers, excluding reserverd
+                * only valid bits for those registers, excluding reserved
                 * although this seems wrong because it would leave many
                 * subslices without ACK.
                 */
@@ -4571,6 +4595,13 @@ static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data)
        struct drm_i915_private *dev_priv = m->private;
        struct i915_hotplug *hotplug = &dev_priv->hotplug;
 
+       /* Synchronize with everything first in case there's been an HPD
+        * storm, but we haven't finished handling it in the kernel yet
+        */
+       synchronize_irq(dev_priv->drm.irq);
+       flush_work(&dev_priv->hotplug.dig_port_work);
+       flush_work(&dev_priv->hotplug.hotplug_work);
+
        seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold);
        seq_printf(m, "Detected: %s\n",
                   yesno(delayed_work_pending(&hotplug->reenable_work)));
@@ -4641,24 +4672,122 @@ static const struct file_operations i915_hpd_storm_ctl_fops = {
        .write = i915_hpd_storm_ctl_write
 };
 
+static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data)
+{
+       struct drm_i915_private *dev_priv = m->private;
+
+       seq_printf(m, "Enabled: %s\n",
+                  yesno(dev_priv->hotplug.hpd_short_storm_enabled));
+
+       return 0;
+}
+
+static int
+i915_hpd_short_storm_ctl_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, i915_hpd_short_storm_ctl_show,
+                          inode->i_private);
+}
+
+static ssize_t i915_hpd_short_storm_ctl_write(struct file *file,
+                                             const char __user *ubuf,
+                                             size_t len, loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       struct drm_i915_private *dev_priv = m->private;
+       struct i915_hotplug *hotplug = &dev_priv->hotplug;
+       char *newline;
+       char tmp[16];
+       int i;
+       bool new_state;
+
+       if (len >= sizeof(tmp))
+               return -EINVAL;
+
+       if (copy_from_user(tmp, ubuf, len))
+               return -EFAULT;
+
+       tmp[len] = '\0';
+
+       /* Strip newline, if any */
+       newline = strchr(tmp, '\n');
+       if (newline)
+               *newline = '\0';
+
+       /* Reset to the "default" state for this system */
+       if (strcmp(tmp, "reset") == 0)
+               new_state = !HAS_DP_MST(dev_priv);
+       else if (kstrtobool(tmp, &new_state) != 0)
+               return -EINVAL;
+
+       DRM_DEBUG_KMS("%sabling HPD short storm detection\n",
+                     new_state ? "En" : "Dis");
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       hotplug->hpd_short_storm_enabled = new_state;
+       /* Reset the HPD storm stats so we don't accidentally trigger a storm */
+       for_each_hpd_pin(i)
+               hotplug->stats[i].count = 0;
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       /* Re-enable hpd immediately if we were in an irq storm */
+       flush_delayed_work(&dev_priv->hotplug.reenable_work);
+
+       return len;
+}
+
+static const struct file_operations i915_hpd_short_storm_ctl_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_hpd_short_storm_ctl_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = i915_hpd_short_storm_ctl_write,
+};
+
 static int i915_drrs_ctl_set(void *data, u64 val)
 {
        struct drm_i915_private *dev_priv = data;
        struct drm_device *dev = &dev_priv->drm;
-       struct intel_crtc *intel_crtc;
-       struct intel_encoder *encoder;
-       struct intel_dp *intel_dp;
+       struct intel_crtc *crtc;
 
        if (INTEL_GEN(dev_priv) < 7)
                return -ENODEV;
 
-       drm_modeset_lock_all(dev);
-       for_each_intel_crtc(dev, intel_crtc) {
-               if (!intel_crtc->base.state->active ||
-                                       !intel_crtc->config->has_drrs)
-                       continue;
+       for_each_intel_crtc(dev, crtc) {
+               struct drm_connector_list_iter conn_iter;
+               struct intel_crtc_state *crtc_state;
+               struct drm_connector *connector;
+               struct drm_crtc_commit *commit;
+               int ret;
+
+               ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex);
+               if (ret)
+                       return ret;
+
+               crtc_state = to_intel_crtc_state(crtc->base.state);
+
+               if (!crtc_state->base.active ||
+                   !crtc_state->has_drrs)
+                       goto out;
 
-               for_each_encoder_on_crtc(dev, &intel_crtc->base, encoder) {
+               commit = crtc_state->base.commit;
+               if (commit) {
+                       ret = wait_for_completion_interruptible(&commit->hw_done);
+                       if (ret)
+                               goto out;
+               }
+
+               drm_connector_list_iter_begin(dev, &conn_iter);
+               drm_for_each_connector_iter(connector, &conn_iter) {
+                       struct intel_encoder *encoder;
+                       struct intel_dp *intel_dp;
+
+                       if (!(crtc_state->base.connector_mask &
+                             drm_connector_mask(connector)))
+                               continue;
+
+                       encoder = intel_attached_encoder(connector);
                        if (encoder->type != INTEL_OUTPUT_EDP)
                                continue;
 
@@ -4668,13 +4797,18 @@ static int i915_drrs_ctl_set(void *data, u64 val)
                        intel_dp = enc_to_intel_dp(&encoder->base);
                        if (val)
                                intel_edp_drrs_enable(intel_dp,
-                                                       intel_crtc->config);
+                                                     crtc_state);
                        else
                                intel_edp_drrs_disable(intel_dp,
-                                                       intel_crtc->config);
+                                                      crtc_state);
                }
+               drm_connector_list_iter_end(&conn_iter);
+
+out:
+               drm_modeset_unlock(&crtc->base.mutex);
+               if (ret)
+                       return ret;
        }
-       drm_modeset_unlock_all(dev);
 
        return 0;
 }
@@ -4818,6 +4952,7 @@ static const struct i915_debugfs_files {
        {"i915_guc_log_level", &i915_guc_log_level_fops},
        {"i915_guc_log_relay", &i915_guc_log_relay_fops},
        {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
+       {"i915_hpd_short_storm_ctl", &i915_hpd_short_storm_ctl_fops},
        {"i915_ipc_status", &i915_ipc_status_fops},
        {"i915_drrs_ctl", &i915_drrs_ctl_fops},
        {"i915_edp_psr_debug", &i915_edp_psr_debug_fops}
@@ -4899,13 +5034,10 @@ static int i915_dpcd_show(struct seq_file *m, void *data)
                        continue;
 
                err = drm_dp_dpcd_read(&intel_dp->aux, b->offset, buf, size);
-               if (err <= 0) {
-                       DRM_ERROR("dpcd read (%zu bytes at %u) failed (%zd)\n",
-                                 size, b->offset, err);
-                       continue;
-               }
-
-               seq_printf(m, "%04x: %*ph\n", b->offset, (int) size, buf);
+               if (err < 0)
+                       seq_printf(m, "%04x: ERROR %d\n", b->offset, (int)err);
+               else
+                       seq_printf(m, "%04x: %*ph\n", b->offset, (int)err, buf);
        }
 
        return 0;
@@ -4934,6 +5066,28 @@ static int i915_panel_show(struct seq_file *m, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(i915_panel);
 
+static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data)
+{
+       struct drm_connector *connector = m->private;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+
+       if (connector->status != connector_status_connected)
+               return -ENODEV;
+
+       /* HDCP is supported by connector */
+       if (!intel_connector->hdcp.shim)
+               return -EINVAL;
+
+       seq_printf(m, "%s:%d HDCP version: ", connector->name,
+                  connector->base.id);
+       seq_printf(m, "%s ", !intel_hdcp_capable(intel_connector) ?
+                  "None" : "HDCP1.4");
+       seq_puts(m, "\n");
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability);
+
 /**
  * i915_debugfs_connector_add - add i915 specific connector debugfs files
  * @connector: pointer to a registered drm_connector
@@ -4963,5 +5117,12 @@ int i915_debugfs_connector_add(struct drm_connector *connector)
                                    connector, &i915_psr_sink_status_fops);
        }
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+           connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+           connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
+               debugfs_create_file("i915_hdcp_sink_capability", S_IRUGO, root,
+                                   connector, &i915_hdcp_sink_capability_fops);
+       }
+
        return 0;
 }
index 47062ee979cfb2d38b6078455562c64ef530ec8a..b310a897a4adab444349252503fba2e92134814f 100644 (file)
@@ -53,6 +53,7 @@
 #include "i915_vgpu.h"
 #include "intel_drv.h"
 #include "intel_uc.h"
+#include "intel_workarounds.h"
 
 static struct drm_driver driver;
 
@@ -287,7 +288,7 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv)
         * Use PCH_NOP (PCH but no South Display) for PCH platforms without
         * display.
         */
-       if (pch && INTEL_INFO(dev_priv)->num_pipes == 0) {
+       if (pch && !HAS_DISPLAY(dev_priv)) {
                DRM_DEBUG_KMS("Display disabled, reverting to NOP PCH\n");
                dev_priv->pch_type = PCH_NOP;
                dev_priv->pch_id = 0;
@@ -345,7 +346,7 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data,
                value = HAS_WT(dev_priv);
                break;
        case I915_PARAM_HAS_ALIASING_PPGTT:
-               value = USES_PPGTT(dev_priv);
+               value = min_t(int, INTEL_PPGTT(dev_priv), I915_GEM_PPGTT_FULL);
                break;
        case I915_PARAM_HAS_SEMAPHORES:
                value = HAS_LEGACY_SEMAPHORES(dev_priv);
@@ -645,6 +646,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (i915_inject_load_failure())
                return -ENODEV;
 
+       if (HAS_DISPLAY(dev_priv)) {
+               ret = drm_vblank_init(&dev_priv->drm,
+                                     INTEL_INFO(dev_priv)->num_pipes);
+               if (ret)
+                       goto out;
+       }
+
        intel_bios_init(dev_priv);
 
        /* If we have > 1 VGA cards, then we need to arbitrate access
@@ -687,9 +695,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_modeset;
 
-       intel_setup_overlay(dev_priv);
+       intel_overlay_setup(dev_priv);
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0)
+       if (!HAS_DISPLAY(dev_priv))
                return 0;
 
        ret = intel_fbdev_init(dev);
@@ -699,6 +707,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
        /* Only enable hotplug handling once the fbdev is fully set up. */
        intel_hpd_init(dev_priv);
 
+       intel_init_ipc(dev_priv);
+
        return 0;
 
 cleanup_gem:
@@ -859,6 +869,7 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv)
        pre |= IS_HSW_EARLY_SDV(dev_priv);
        pre |= IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0);
        pre |= IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST);
+       pre |= IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0);
 
        if (pre) {
                DRM_ERROR("This is a pre-production stepping. "
@@ -1030,6 +1041,7 @@ static int i915_driver_init_mmio(struct drm_i915_private *dev_priv)
 
 err_uncore:
        intel_uncore_fini(dev_priv);
+       i915_mmio_cleanup(dev_priv);
 err_bridge:
        pci_dev_put(dev_priv->bridge_dev);
 
@@ -1049,17 +1061,6 @@ static void i915_driver_cleanup_mmio(struct drm_i915_private *dev_priv)
 
 static void intel_sanitize_options(struct drm_i915_private *dev_priv)
 {
-       /*
-        * i915.enable_ppgtt is read-only, so do an early pass to validate the
-        * user's requested state against the hardware/driver capabilities.  We
-        * do this now so that we can print out any log messages once rather
-        * than every time we check intel_enable_ppgtt().
-        */
-       i915_modparams.enable_ppgtt =
-               intel_sanitize_enable_ppgtt(dev_priv,
-                                           i915_modparams.enable_ppgtt);
-       DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915_modparams.enable_ppgtt);
-
        intel_gvt_sanitize_options(dev_priv);
 }
 
@@ -1340,7 +1341,7 @@ intel_get_dram_info(struct drm_i915_private *dev_priv)
        /* Need to calculate bandwidth only for Gen9 */
        if (IS_BROXTON(dev_priv))
                ret = bxt_get_dram_info(dev_priv);
-       else if (INTEL_GEN(dev_priv) == 9)
+       else if (IS_GEN9(dev_priv))
                ret = skl_get_dram_info(dev_priv);
        else
                ret = skl_dram_get_channels_info(dev_priv);
@@ -1375,6 +1376,29 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 
        intel_device_info_runtime_init(mkwrite_device_info(dev_priv));
 
+       if (HAS_PPGTT(dev_priv)) {
+               if (intel_vgpu_active(dev_priv) &&
+                   !intel_vgpu_has_full_48bit_ppgtt(dev_priv)) {
+                       i915_report_error(dev_priv,
+                                         "incompatible vGPU found, support for isolated ppGTT required\n");
+                       return -ENXIO;
+               }
+       }
+
+       if (HAS_EXECLISTS(dev_priv)) {
+               /*
+                * Older GVT emulation depends upon intercepting CSB mmio,
+                * which we no longer use, preferring to use the HWSP cache
+                * instead.
+                */
+               if (intel_vgpu_active(dev_priv) &&
+                   !intel_vgpu_has_hwsp_emulation(dev_priv)) {
+                       i915_report_error(dev_priv,
+                                         "old vGPU host found, support for HWSP emulation required\n");
+                       return -ENXIO;
+               }
+       }
+
        intel_sanitize_options(dev_priv);
 
        i915_perf_init(dev_priv);
@@ -1544,7 +1568,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
        } else
                DRM_ERROR("Failed to register driver for userspace access!\n");
 
-       if (INTEL_INFO(dev_priv)->num_pipes) {
+       if (HAS_DISPLAY(dev_priv)) {
                /* Must be done after probing outputs */
                intel_opregion_register(dev_priv);
                acpi_video_register();
@@ -1568,7 +1592,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
         * We need to coordinate the hotplugs with the asynchronous fbdev
         * configuration, for which we use the fbdev->async_cookie.
         */
-       if (INTEL_INFO(dev_priv)->num_pipes)
+       if (HAS_DISPLAY(dev_priv))
                drm_kms_helper_poll_init(dev);
 
        intel_power_domains_enable(dev_priv);
@@ -1631,14 +1655,16 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent)
                (struct intel_device_info *)ent->driver_data;
        struct intel_device_info *device_info;
        struct drm_i915_private *i915;
+       int err;
 
        i915 = kzalloc(sizeof(*i915), GFP_KERNEL);
        if (!i915)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
-       if (drm_dev_init(&i915->drm, &driver, &pdev->dev)) {
+       err = drm_dev_init(&i915->drm, &driver, &pdev->dev);
+       if (err) {
                kfree(i915);
-               return NULL;
+               return ERR_PTR(err);
        }
 
        i915->drm.pdev = pdev;
@@ -1651,8 +1677,8 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent)
        device_info->device_id = pdev->device;
 
        BUILD_BUG_ON(INTEL_MAX_PLATFORMS >
-                    sizeof(device_info->platform_mask) * BITS_PER_BYTE);
-       BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE);
+                    BITS_PER_TYPE(device_info->platform_mask));
+       BUG_ON(device_info->gen > BITS_PER_TYPE(device_info->gen_mask));
 
        return i915;
 }
@@ -1687,8 +1713,8 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        dev_priv = i915_driver_create(pdev, ent);
-       if (!dev_priv)
-               return -ENOMEM;
+       if (IS_ERR(dev_priv))
+               return PTR_ERR(dev_priv);
 
        /* Disable nuclear pageflip by default on pre-ILK */
        if (!i915_modparams.nuclear_pageflip && match_info->gen < 5)
@@ -1712,26 +1738,12 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret < 0)
                goto out_cleanup_mmio;
 
-       /*
-        * TODO: move the vblank init and parts of modeset init steps into one
-        * of the i915_driver_init_/i915_driver_register functions according
-        * to the role/effect of the given init step.
-        */
-       if (INTEL_INFO(dev_priv)->num_pipes) {
-               ret = drm_vblank_init(&dev_priv->drm,
-                                     INTEL_INFO(dev_priv)->num_pipes);
-               if (ret)
-                       goto out_cleanup_hw;
-       }
-
        ret = i915_load_modeset_init(&dev_priv->drm);
        if (ret < 0)
                goto out_cleanup_hw;
 
        i915_driver_register(dev_priv);
 
-       intel_init_ipc(dev_priv);
-
        enable_rpm_wakeref_asserts(dev_priv);
 
        i915_welcome_messages(dev_priv);
@@ -1783,7 +1795,6 @@ void i915_driver_unload(struct drm_device *dev)
        i915_reset_error_state(dev_priv);
 
        i915_gem_fini(dev_priv);
-       intel_fbc_cleanup_cfb(dev_priv);
 
        intel_power_domains_fini_hw(dev_priv);
 
@@ -1921,9 +1932,7 @@ static int i915_drm_suspend(struct drm_device *dev)
        i915_save_state(dev_priv);
 
        opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
-       intel_opregion_notify_adapter(dev_priv, opregion_target_state);
-
-       intel_opregion_unregister(dev_priv);
+       intel_opregion_suspend(dev_priv, opregion_target_state);
 
        intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
 
@@ -1964,7 +1973,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
                                    get_suspend_mode(dev_priv, hibernation));
 
        ret = 0;
-       if (IS_GEN9_LP(dev_priv))
+       if (INTEL_GEN(dev_priv) >= 11 || IS_GEN9_LP(dev_priv))
                bxt_enable_dc9(dev_priv);
        else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                hsw_enable_pc8(dev_priv);
@@ -2042,7 +2051,6 @@ static int i915_drm_resume(struct drm_device *dev)
 
        i915_restore_state(dev_priv);
        intel_pps_unlock_regs_wa(dev_priv);
-       intel_opregion_setup(dev_priv);
 
        intel_init_pch_refclk(dev_priv);
 
@@ -2084,12 +2092,10 @@ static int i915_drm_resume(struct drm_device *dev)
         * */
        intel_hpd_init(dev_priv);
 
-       intel_opregion_register(dev_priv);
+       intel_opregion_resume(dev_priv);
 
        intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false);
 
-       intel_opregion_notify_adapter(dev_priv, PCI_D0);
-
        intel_power_domains_enable(dev_priv);
 
        enable_rpm_wakeref_asserts(dev_priv);
@@ -2157,7 +2163,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
 
        intel_uncore_resume_early(dev_priv);
 
-       if (IS_GEN9_LP(dev_priv)) {
+       if (INTEL_GEN(dev_priv) >= 11 || IS_GEN9_LP(dev_priv)) {
                gen9_sanitize_dc_state(dev_priv);
                bxt_disable_dc9(dev_priv);
        } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
@@ -2924,7 +2930,10 @@ static int intel_runtime_suspend(struct device *kdev)
        intel_uncore_suspend(dev_priv);
 
        ret = 0;
-       if (IS_GEN9_LP(dev_priv)) {
+       if (INTEL_GEN(dev_priv) >= 11) {
+               icl_display_core_uninit(dev_priv);
+               bxt_enable_dc9(dev_priv);
+       } else if (IS_GEN9_LP(dev_priv)) {
                bxt_display_core_uninit(dev_priv);
                bxt_enable_dc9(dev_priv);
        } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
@@ -3009,7 +3018,18 @@ static int intel_runtime_resume(struct device *kdev)
        if (intel_uncore_unclaimed_mmio(dev_priv))
                DRM_DEBUG_DRIVER("Unclaimed access during suspend, bios?\n");
 
-       if (IS_GEN9_LP(dev_priv)) {
+       if (INTEL_GEN(dev_priv) >= 11) {
+               bxt_disable_dc9(dev_priv);
+               icl_display_core_init(dev_priv, true);
+               if (dev_priv->csr.dmc_payload) {
+                       if (dev_priv->csr.allowed_dc_mask &
+                           DC_STATE_EN_UPTO_DC6)
+                               skl_enable_dc6(dev_priv);
+                       else if (dev_priv->csr.allowed_dc_mask &
+                                DC_STATE_EN_UPTO_DC5)
+                               gen9_enable_dc5(dev_priv);
+               }
+       } else if (IS_GEN9_LP(dev_priv)) {
                bxt_disable_dc9(dev_priv);
                bxt_display_core_init(dev_priv, true);
                if (dev_priv->csr.dmc_payload &&
index 872a2e159a5f903fc6a9d84d6392cc04a44e6d87..b1c31967194b92cc47b8a3cedafea021d82fd073 100644 (file)
@@ -53,7 +53,9 @@
 #include <drm/drm_auth.h>
 #include <drm/drm_cache.h>
 #include <drm/drm_util.h>
+#include <drm/drm_dsc.h>
 
+#include "i915_fixed.h"
 #include "i915_params.h"
 #include "i915_reg.h"
 #include "i915_utils.h"
@@ -88,8 +90,8 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20180921"
-#define DRIVER_TIMESTAMP       1537521997
+#define DRIVER_DATE            "20181204"
+#define DRIVER_TIMESTAMP       1543944377
 
 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
  * WARN_ON()) for hw state sanity checks to check for unexpected conditions
@@ -128,144 +130,6 @@ bool i915_error_injected(void);
        __i915_printk(i915, i915_error_injected() ? KERN_DEBUG : KERN_ERR, \
                      fmt, ##__VA_ARGS__)
 
-typedef struct {
-       uint32_t val;
-} uint_fixed_16_16_t;
-
-#define FP_16_16_MAX ({ \
-       uint_fixed_16_16_t fp; \
-       fp.val = UINT_MAX; \
-       fp; \
-})
-
-static inline bool is_fixed16_zero(uint_fixed_16_16_t val)
-{
-       if (val.val == 0)
-               return true;
-       return false;
-}
-
-static inline uint_fixed_16_16_t u32_to_fixed16(uint32_t val)
-{
-       uint_fixed_16_16_t fp;
-
-       WARN_ON(val > U16_MAX);
-
-       fp.val = val << 16;
-       return fp;
-}
-
-static inline uint32_t fixed16_to_u32_round_up(uint_fixed_16_16_t fp)
-{
-       return DIV_ROUND_UP(fp.val, 1 << 16);
-}
-
-static inline uint32_t fixed16_to_u32(uint_fixed_16_16_t fp)
-{
-       return fp.val >> 16;
-}
-
-static inline uint_fixed_16_16_t min_fixed16(uint_fixed_16_16_t min1,
-                                                uint_fixed_16_16_t min2)
-{
-       uint_fixed_16_16_t min;
-
-       min.val = min(min1.val, min2.val);
-       return min;
-}
-
-static inline uint_fixed_16_16_t max_fixed16(uint_fixed_16_16_t max1,
-                                                uint_fixed_16_16_t max2)
-{
-       uint_fixed_16_16_t max;
-
-       max.val = max(max1.val, max2.val);
-       return max;
-}
-
-static inline uint_fixed_16_16_t clamp_u64_to_fixed16(uint64_t val)
-{
-       uint_fixed_16_16_t fp;
-       WARN_ON(val > U32_MAX);
-       fp.val = (uint32_t) val;
-       return fp;
-}
-
-static inline uint32_t div_round_up_fixed16(uint_fixed_16_16_t val,
-                                           uint_fixed_16_16_t d)
-{
-       return DIV_ROUND_UP(val.val, d.val);
-}
-
-static inline uint32_t mul_round_up_u32_fixed16(uint32_t val,
-                                               uint_fixed_16_16_t mul)
-{
-       uint64_t intermediate_val;
-
-       intermediate_val = (uint64_t) val * mul.val;
-       intermediate_val = DIV_ROUND_UP_ULL(intermediate_val, 1 << 16);
-       WARN_ON(intermediate_val > U32_MAX);
-       return (uint32_t) intermediate_val;
-}
-
-static inline uint_fixed_16_16_t mul_fixed16(uint_fixed_16_16_t val,
-                                            uint_fixed_16_16_t mul)
-{
-       uint64_t intermediate_val;
-
-       intermediate_val = (uint64_t) val.val * mul.val;
-       intermediate_val = intermediate_val >> 16;
-       return clamp_u64_to_fixed16(intermediate_val);
-}
-
-static inline uint_fixed_16_16_t div_fixed16(uint32_t val, uint32_t d)
-{
-       uint64_t interm_val;
-
-       interm_val = (uint64_t)val << 16;
-       interm_val = DIV_ROUND_UP_ULL(interm_val, d);
-       return clamp_u64_to_fixed16(interm_val);
-}
-
-static inline uint32_t div_round_up_u32_fixed16(uint32_t val,
-                                               uint_fixed_16_16_t d)
-{
-       uint64_t interm_val;
-
-       interm_val = (uint64_t)val << 16;
-       interm_val = DIV_ROUND_UP_ULL(interm_val, d.val);
-       WARN_ON(interm_val > U32_MAX);
-       return (uint32_t) interm_val;
-}
-
-static inline uint_fixed_16_16_t mul_u32_fixed16(uint32_t val,
-                                                    uint_fixed_16_16_t mul)
-{
-       uint64_t intermediate_val;
-
-       intermediate_val = (uint64_t) val * mul.val;
-       return clamp_u64_to_fixed16(intermediate_val);
-}
-
-static inline uint_fixed_16_16_t add_fixed16(uint_fixed_16_16_t add1,
-                                            uint_fixed_16_16_t add2)
-{
-       uint64_t interm_sum;
-
-       interm_sum = (uint64_t) add1.val + add2.val;
-       return clamp_u64_to_fixed16(interm_sum);
-}
-
-static inline uint_fixed_16_16_t add_fixed16_u32(uint_fixed_16_16_t add1,
-                                                uint32_t add2)
-{
-       uint64_t interm_sum;
-       uint_fixed_16_16_t interm_add2 = u32_to_fixed16(add2);
-
-       interm_sum = (uint64_t) add1.val + interm_add2.val;
-       return clamp_u64_to_fixed16(interm_sum);
-}
-
 enum hpd_pin {
        HPD_NONE = 0,
        HPD_TV = HPD_NONE,     /* TV is known to be unreliable */
@@ -284,7 +148,8 @@ enum hpd_pin {
 #define for_each_hpd_pin(__pin) \
        for ((__pin) = (HPD_NONE + 1); (__pin) < HPD_NUM_PINS; (__pin)++)
 
-#define HPD_STORM_DEFAULT_THRESHOLD 5
+/* Threshold == 5 for long IRQs, 50 for short */
+#define HPD_STORM_DEFAULT_THRESHOLD 50
 
 struct i915_hotplug {
        struct work_struct hotplug_work;
@@ -309,6 +174,8 @@ struct i915_hotplug {
        bool poll_enabled;
 
        unsigned int hpd_storm_threshold;
+       /* Whether or not to count short HPD IRQs in HPD storms */
+       u8 hpd_short_storm_enabled;
 
        /*
         * if we get a HPD irq from DP and a HPD irq from non-DP
@@ -466,8 +333,10 @@ struct drm_i915_display_funcs {
 struct intel_csr {
        struct work_struct work;
        const char *fw_path;
+       uint32_t required_version;
+       uint32_t max_fw_size; /* bytes */
        uint32_t *dmc_payload;
-       uint32_t dmc_fw_size;
+       uint32_t dmc_fw_size; /* dwords */
        uint32_t version;
        uint32_t mmio_count;
        i915_reg_t mmioaddr[8];
@@ -547,6 +416,8 @@ struct intel_fbc {
                        int adjusted_y;
 
                        int y;
+
+                       uint16_t pixel_blend_mode;
                } plane;
 
                struct {
@@ -625,17 +496,19 @@ struct i915_psr {
        bool sink_support;
        bool prepared, enabled;
        struct intel_dp *dp;
+       enum pipe pipe;
        bool active;
        struct work_struct work;
        unsigned busy_frontbuffer_bits;
        bool sink_psr2_support;
        bool link_standby;
        bool colorimetry_support;
-       bool alpm;
        bool psr2_enabled;
        u8 sink_sync_latency;
        ktime_t last_entry_attempt;
        ktime_t last_exit;
+       bool sink_not_reliable;
+       bool irq_aux_error;
 };
 
 enum intel_pch {
@@ -919,6 +792,11 @@ struct i915_power_well_desc {
                        /* The pw is backing the VGA functionality */
                        bool has_vga:1;
                        bool has_fuses:1;
+                       /*
+                        * The pw is for an ICL+ TypeC PHY port in
+                        * Thunderbolt mode.
+                        */
+                       bool is_tc_tbt:1;
                } hsw;
        };
        const struct i915_power_well_ops *ops;
@@ -1043,17 +921,6 @@ struct i915_gem_mm {
 
 #define I915_ENGINE_WEDGED_TIMEOUT  (60 * HZ)  /* Reset but no recovery? */
 
-#define DP_AUX_A 0x40
-#define DP_AUX_B 0x10
-#define DP_AUX_C 0x20
-#define DP_AUX_D 0x30
-#define DP_AUX_E 0x50
-#define DP_AUX_F 0x60
-
-#define DDC_PIN_B  0x05
-#define DDC_PIN_C  0x04
-#define DDC_PIN_D  0x06
-
 struct ddi_vbt_port_info {
        int max_tmds_clock;
 
@@ -1100,6 +967,7 @@ struct intel_vbt_data {
        unsigned int panel_type:4;
        int lvds_ssc_freq;
        unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
+       enum drm_panel_orientation orientation;
 
        enum drrs_support_type drrs_type;
 
@@ -1145,6 +1013,7 @@ struct intel_vbt_data {
                u8 *data;
                const u8 *sequence[MIPI_SEQ_MAX];
                u8 *deassert_seq; /* Used by fixup_mipi_sequences() */
+               enum drm_panel_orientation orientation;
        } dsi;
 
        int crt_ddc_pin;
@@ -1229,9 +1098,6 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
 }
 
 struct skl_ddb_allocation {
-       /* packed/y */
-       struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
-       struct skl_ddb_entry uv_plane[I915_MAX_PIPES][I915_MAX_PLANES];
        u8 enabled_slices; /* GEN11 has configurable 2 slices */
 };
 
@@ -1241,9 +1107,9 @@ struct skl_ddb_values {
 };
 
 struct skl_wm_level {
-       bool plane_en;
        uint16_t plane_res_b;
        uint8_t plane_res_l;
+       bool plane_en;
 };
 
 /* Stores plane specific WM parameters */
@@ -1324,20 +1190,6 @@ struct i915_frontbuffer_tracking {
        unsigned flip_bits;
 };
 
-struct i915_wa_reg {
-       u32 addr;
-       u32 value;
-       /* bitmask representing WA bits */
-       u32 mask;
-};
-
-#define I915_MAX_WA_REGS 16
-
-struct i915_workarounds {
-       struct i915_wa_reg reg[I915_MAX_WA_REGS];
-       u32 count;
-};
-
 struct i915_virtual_gpu {
        bool active;
        u32 caps;
@@ -1520,31 +1372,13 @@ struct i915_oa_ops {
         */
        bool (*is_valid_flex_reg)(struct drm_i915_private *dev_priv, u32 addr);
 
-       /**
-        * @init_oa_buffer: Resets the head and tail pointers of the
-        * circular buffer for periodic OA reports.
-        *
-        * Called when first opening a stream for OA metrics, but also may be
-        * called in response to an OA buffer overflow or other error
-        * condition.
-        *
-        * Note it may be necessary to clear the full OA buffer here as part of
-        * maintaining the invariable that new reports must be written to
-        * zeroed memory for us to be able to reliable detect if an expected
-        * report has not yet landed in memory.  (At least on Haswell the OA
-        * buffer tail pointer is not synchronized with reports being visible
-        * to the CPU)
-        */
-       void (*init_oa_buffer)(struct drm_i915_private *dev_priv);
-
        /**
         * @enable_metric_set: Selects and applies any MUX configuration to set
         * up the Boolean and Custom (B/C) counters that are part of the
         * counter reports being sampled. May apply system constraints such as
         * disabling EU clock gating as required.
         */
-       int (*enable_metric_set)(struct drm_i915_private *dev_priv,
-                                const struct i915_oa_config *oa_config);
+       int (*enable_metric_set)(struct i915_perf_stream *stream);
 
        /**
         * @disable_metric_set: Remove system constraints associated with using
@@ -1555,12 +1389,12 @@ struct i915_oa_ops {
        /**
         * @oa_enable: Enable periodic sampling
         */
-       void (*oa_enable)(struct drm_i915_private *dev_priv);
+       void (*oa_enable)(struct i915_perf_stream *stream);
 
        /**
         * @oa_disable: Disable periodic sampling
         */
-       void (*oa_disable)(struct drm_i915_private *dev_priv);
+       void (*oa_disable)(struct i915_perf_stream *stream);
 
        /**
         * @read: Copy data from the circular OA buffer into a given userspace
@@ -1805,7 +1639,6 @@ struct drm_i915_private {
 
        int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
 
-       struct i915_workarounds workarounds;
        struct i915_wa_list gt_wa_list;
 
        struct i915_frontbuffer_tracking fb_tracking;
@@ -2326,6 +2159,8 @@ static inline struct scatterlist *__sg_next(struct scatterlist *sg)
             (((__iter).curr += PAGE_SIZE) >= (__iter).max) ?           \
             (__iter) = __sgt_iter(__sg_next((__iter).sgp), false), 0 : 0)
 
+bool i915_sg_trim(struct sg_table *orig_st);
+
 static inline unsigned int i915_sg_page_sizes(struct scatterlist *sg)
 {
        unsigned int page_sizes;
@@ -2371,20 +2206,12 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define REVID_FOREVER          0xff
 #define INTEL_REVID(dev_priv)  ((dev_priv)->drm.pdev->revision)
 
-#define GEN_FOREVER (0)
-
 #define INTEL_GEN_MASK(s, e) ( \
        BUILD_BUG_ON_ZERO(!__builtin_constant_p(s)) + \
        BUILD_BUG_ON_ZERO(!__builtin_constant_p(e)) + \
-       GENMASK((e) != GEN_FOREVER ? (e) - 1 : BITS_PER_LONG - 1, \
-               (s) != GEN_FOREVER ? (s) - 1 : 0) \
-)
+       GENMASK((e) - 1, (s) - 1))
 
-/*
- * Returns true if Gen is in inclusive range [Start, End].
- *
- * Use GEN_FOREVER for unbound start and or end.
- */
+/* Returns true if Gen is in inclusive range [Start, End] */
 #define IS_GEN(dev_priv, s, e) \
        (!!((dev_priv)->info.gen_mask & INTEL_GEN_MASK((s), (e))))
 
@@ -2465,6 +2292,8 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define IS_KBL_ULX(dev_priv)   (INTEL_DEVID(dev_priv) == 0x590E || \
                                 INTEL_DEVID(dev_priv) == 0x5915 || \
                                 INTEL_DEVID(dev_priv) == 0x591E)
+#define IS_AML_ULX(dev_priv)   (INTEL_DEVID(dev_priv) == 0x591C || \
+                                INTEL_DEVID(dev_priv) == 0x87C0)
 #define IS_SKL_GT2(dev_priv)   (IS_SKYLAKE(dev_priv) && \
                                 (dev_priv)->info.gt == 2)
 #define IS_SKL_GT3(dev_priv)   (IS_SKYLAKE(dev_priv) && \
@@ -2596,17 +2425,22 @@ intel_info(const struct drm_i915_private *dev_priv)
 
 #define HAS_EXECLISTS(dev_priv) HAS_LOGICAL_RING_CONTEXTS(dev_priv)
 
-#define USES_PPGTT(dev_priv)           (i915_modparams.enable_ppgtt)
-#define USES_FULL_PPGTT(dev_priv)      (i915_modparams.enable_ppgtt >= 2)
-#define USES_FULL_48BIT_PPGTT(dev_priv)        (i915_modparams.enable_ppgtt == 3)
+#define INTEL_PPGTT(dev_priv) (INTEL_INFO(dev_priv)->ppgtt)
+#define HAS_PPGTT(dev_priv) \
+       (INTEL_PPGTT(dev_priv) != INTEL_PPGTT_NONE)
+#define HAS_FULL_PPGTT(dev_priv) \
+       (INTEL_PPGTT(dev_priv) >= INTEL_PPGTT_FULL)
+#define HAS_FULL_48BIT_PPGTT(dev_priv) \
+       (INTEL_PPGTT(dev_priv) >= INTEL_PPGTT_FULL_4LVL)
+
 #define HAS_PAGE_SIZES(dev_priv, sizes) ({ \
        GEM_BUG_ON((sizes) == 0); \
        ((sizes) & ~(dev_priv)->info.page_sizes) == 0; \
 })
 
-#define HAS_OVERLAY(dev_priv)           ((dev_priv)->info.has_overlay)
+#define HAS_OVERLAY(dev_priv)           ((dev_priv)->info.display.has_overlay)
 #define OVERLAY_NEEDS_PHYSICAL(dev_priv) \
-               ((dev_priv)->info.overlay_needs_physical)
+               ((dev_priv)->info.display.overlay_needs_physical)
 
 /* Early gen2 have a totally busted CS tlb and require pinned batches. */
 #define HAS_BROKEN_CS_TLB(dev_priv)    (IS_I830(dev_priv) || IS_I845G(dev_priv))
@@ -2627,31 +2461,31 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define HAS_128_BYTE_Y_TILING(dev_priv) (!IS_GEN2(dev_priv) && \
                                         !(IS_I915G(dev_priv) || \
                                         IS_I915GM(dev_priv)))
-#define SUPPORTS_TV(dev_priv)          ((dev_priv)->info.supports_tv)
-#define I915_HAS_HOTPLUG(dev_priv)     ((dev_priv)->info.has_hotplug)
+#define SUPPORTS_TV(dev_priv)          ((dev_priv)->info.display.supports_tv)
+#define I915_HAS_HOTPLUG(dev_priv)     ((dev_priv)->info.display.has_hotplug)
 
 #define HAS_FW_BLC(dev_priv)   (INTEL_GEN(dev_priv) > 2)
-#define HAS_FBC(dev_priv)      ((dev_priv)->info.has_fbc)
+#define HAS_FBC(dev_priv)      ((dev_priv)->info.display.has_fbc)
 #define HAS_CUR_FBC(dev_priv)  (!HAS_GMCH_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 7)
 
 #define HAS_IPS(dev_priv)      (IS_HSW_ULT(dev_priv) || IS_BROADWELL(dev_priv))
 
-#define HAS_DP_MST(dev_priv)   ((dev_priv)->info.has_dp_mst)
+#define HAS_DP_MST(dev_priv)   ((dev_priv)->info.display.has_dp_mst)
 
-#define HAS_DDI(dev_priv)               ((dev_priv)->info.has_ddi)
+#define HAS_DDI(dev_priv)               ((dev_priv)->info.display.has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev_priv) ((dev_priv)->info.has_fpga_dbg)
-#define HAS_PSR(dev_priv)               ((dev_priv)->info.has_psr)
+#define HAS_PSR(dev_priv)               ((dev_priv)->info.display.has_psr)
 
 #define HAS_RC6(dev_priv)               ((dev_priv)->info.has_rc6)
 #define HAS_RC6p(dev_priv)              ((dev_priv)->info.has_rc6p)
 #define HAS_RC6pp(dev_priv)             (false) /* HW was never validated */
 
-#define HAS_CSR(dev_priv)      ((dev_priv)->info.has_csr)
+#define HAS_CSR(dev_priv)      ((dev_priv)->info.display.has_csr)
 
 #define HAS_RUNTIME_PM(dev_priv) ((dev_priv)->info.has_runtime_pm)
 #define HAS_64BIT_RELOC(dev_priv) ((dev_priv)->info.has_64bit_reloc)
 
-#define HAS_IPC(dev_priv)               ((dev_priv)->info.has_ipc)
+#define HAS_IPC(dev_priv)               ((dev_priv)->info.display.has_ipc)
 
 /*
  * For now, anything with a GuC requires uCode loading, and then supports
@@ -2712,7 +2546,7 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define HAS_PCH_NOP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_NOP)
 #define HAS_PCH_SPLIT(dev_priv) (INTEL_PCH_TYPE(dev_priv) != PCH_NONE)
 
-#define HAS_GMCH_DISPLAY(dev_priv) ((dev_priv)->info.has_gmch_display)
+#define HAS_GMCH_DISPLAY(dev_priv) ((dev_priv)->info.display.has_gmch_display)
 
 #define HAS_LSPCON(dev_priv) (INTEL_GEN(dev_priv) >= 9)
 
@@ -2724,6 +2558,8 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define GT_FREQUENCY_MULTIPLIER 50
 #define GEN9_FREQ_SCALER 3
 
+#define HAS_DISPLAY(dev_priv) (INTEL_INFO(dev_priv)->num_pipes > 0)
+
 #include "i915_trace.h"
 
 static inline bool intel_vtd_active(void)
@@ -2746,9 +2582,6 @@ intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *dev_priv)
        return IS_BROXTON(dev_priv) && intel_vtd_active();
 }
 
-int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
-                               int enable_ppgtt);
-
 /* i915_drv.c */
 void __printf(3, 4)
 __i915_printk(struct drm_i915_private *dev_priv, const char *level,
@@ -3233,7 +3066,7 @@ int i915_gem_object_wait(struct drm_i915_gem_object *obj,
 int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
                                  unsigned int flags,
                                  const struct i915_sched_attr *attr);
-#define I915_PRIORITY_DISPLAY I915_PRIORITY_MAX
+#define I915_PRIORITY_DISPLAY I915_USER_PRIORITY(I915_PRIORITY_MAX)
 
 int __must_check
 i915_gem_object_set_to_wc_domain(struct drm_i915_gem_object *obj, bool write);
@@ -3465,6 +3298,7 @@ bool intel_bios_is_port_hpd_inverted(struct drm_i915_private *dev_priv,
                                     enum port port);
 bool intel_bios_is_lspcon_present(struct drm_i915_private *dev_priv,
                                enum port port);
+enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv, enum port port);
 
 /* intel_acpi.c */
 #ifdef CONFIG_ACPI
@@ -3486,8 +3320,6 @@ mkwrite_device_info(struct drm_i915_private *dev_priv)
 extern void intel_modeset_init_hw(struct drm_device *dev);
 extern int intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
-extern int intel_connector_register(struct drm_connector *);
-extern void intel_connector_unregister(struct drm_connector *);
 extern int intel_modeset_vga_set_state(struct drm_i915_private *dev_priv,
                                       bool state);
 extern void intel_display_resume(struct drm_device *dev);
@@ -3500,6 +3332,9 @@ extern void intel_rps_mark_interactive(struct drm_i915_private *i915,
                                       bool interactive);
 extern bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
                                  bool enable);
+void intel_dsc_enable(struct intel_encoder *encoder,
+                     const struct intel_crtc_state *crtc_state);
+void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
 
 int i915_reg_read_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file);
@@ -3587,6 +3422,12 @@ void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder,
 void vlv_phy_reset_lanes(struct intel_encoder *encoder,
                         const struct intel_crtc_state *old_crtc_state);
 
+/* intel_combo_phy.c */
+void icl_combo_phys_init(struct drm_i915_private *dev_priv);
+void icl_combo_phys_uninit(struct drm_i915_private *dev_priv);
+void cnl_combo_phys_init(struct drm_i915_private *dev_priv);
+void cnl_combo_phys_uninit(struct drm_i915_private *dev_priv);
+
 int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
 int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
 u64 intel_rc6_residency_ns(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/i915_fixed.h b/drivers/gpu/drm/i915/i915_fixed.h
new file mode 100644 (file)
index 0000000..591dd89
--- /dev/null
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2018 Intel Corporation
+ */
+
+#ifndef _I915_FIXED_H_
+#define _I915_FIXED_H_
+
+typedef struct {
+       u32 val;
+} uint_fixed_16_16_t;
+
+#define FP_16_16_MAX ((uint_fixed_16_16_t){ .val = UINT_MAX })
+
+static inline bool is_fixed16_zero(uint_fixed_16_16_t val)
+{
+       return val.val == 0;
+}
+
+static inline uint_fixed_16_16_t u32_to_fixed16(u32 val)
+{
+       uint_fixed_16_16_t fp = { .val = val << 16 };
+
+       WARN_ON(val > U16_MAX);
+
+       return fp;
+}
+
+static inline u32 fixed16_to_u32_round_up(uint_fixed_16_16_t fp)
+{
+       return DIV_ROUND_UP(fp.val, 1 << 16);
+}
+
+static inline u32 fixed16_to_u32(uint_fixed_16_16_t fp)
+{
+       return fp.val >> 16;
+}
+
+static inline uint_fixed_16_16_t min_fixed16(uint_fixed_16_16_t min1,
+                                            uint_fixed_16_16_t min2)
+{
+       uint_fixed_16_16_t min = { .val = min(min1.val, min2.val) };
+
+       return min;
+}
+
+static inline uint_fixed_16_16_t max_fixed16(uint_fixed_16_16_t max1,
+                                            uint_fixed_16_16_t max2)
+{
+       uint_fixed_16_16_t max = { .val = max(max1.val, max2.val) };
+
+       return max;
+}
+
+static inline uint_fixed_16_16_t clamp_u64_to_fixed16(u64 val)
+{
+       uint_fixed_16_16_t fp = { .val = (u32)val };
+
+       WARN_ON(val > U32_MAX);
+
+       return fp;
+}
+
+static inline u32 div_round_up_fixed16(uint_fixed_16_16_t val,
+                                      uint_fixed_16_16_t d)
+{
+       return DIV_ROUND_UP(val.val, d.val);
+}
+
+static inline u32 mul_round_up_u32_fixed16(u32 val, uint_fixed_16_16_t mul)
+{
+       u64 tmp;
+
+       tmp = (u64)val * mul.val;
+       tmp = DIV_ROUND_UP_ULL(tmp, 1 << 16);
+       WARN_ON(tmp > U32_MAX);
+
+       return (u32)tmp;
+}
+
+static inline uint_fixed_16_16_t mul_fixed16(uint_fixed_16_16_t val,
+                                            uint_fixed_16_16_t mul)
+{
+       u64 tmp;
+
+       tmp = (u64)val.val * mul.val;
+       tmp = tmp >> 16;
+
+       return clamp_u64_to_fixed16(tmp);
+}
+
+static inline uint_fixed_16_16_t div_fixed16(u32 val, u32 d)
+{
+       u64 tmp;
+
+       tmp = (u64)val << 16;
+       tmp = DIV_ROUND_UP_ULL(tmp, d);
+
+       return clamp_u64_to_fixed16(tmp);
+}
+
+static inline u32 div_round_up_u32_fixed16(u32 val, uint_fixed_16_16_t d)
+{
+       u64 tmp;
+
+       tmp = (u64)val << 16;
+       tmp = DIV_ROUND_UP_ULL(tmp, d.val);
+       WARN_ON(tmp > U32_MAX);
+
+       return (u32)tmp;
+}
+
+static inline uint_fixed_16_16_t mul_u32_fixed16(u32 val, uint_fixed_16_16_t mul)
+{
+       u64 tmp;
+
+       tmp = (u64)val * mul.val;
+
+       return clamp_u64_to_fixed16(tmp);
+}
+
+static inline uint_fixed_16_16_t add_fixed16(uint_fixed_16_16_t add1,
+                                            uint_fixed_16_16_t add2)
+{
+       u64 tmp;
+
+       tmp = (u64)add1.val + add2.val;
+
+       return clamp_u64_to_fixed16(tmp);
+}
+
+static inline uint_fixed_16_16_t add_fixed16_u32(uint_fixed_16_16_t add1,
+                                                u32 add2)
+{
+       uint_fixed_16_16_t tmp_add2 = u32_to_fixed16(add2);
+       u64 tmp;
+
+       tmp = (u64)add1.val + tmp_add2.val;
+
+       return clamp_u64_to_fixed16(tmp);
+}
+
+#endif /* _I915_FIXED_H_ */
index 6ae9a6080cc8838b45dc11fb6de28f63fbe09b04..d36a9755ad910f29870e252bb7d6a18a800101d3 100644 (file)
@@ -1740,6 +1740,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
         */
        err = i915_gem_object_wait(obj,
                                   I915_WAIT_INTERRUPTIBLE |
+                                  I915_WAIT_PRIORITY |
                                   (write_domain ? I915_WAIT_ALL : 0),
                                   MAX_SCHEDULE_TIMEOUT,
                                   to_rps_client(file));
@@ -2381,11 +2382,23 @@ void __i915_gem_object_invalidate(struct drm_i915_gem_object *obj)
        invalidate_mapping_pages(mapping, 0, (loff_t)-1);
 }
 
+/*
+ * Move pages to appropriate lru and release the pagevec, decrementing the
+ * ref count of those pages.
+ */
+static void check_release_pagevec(struct pagevec *pvec)
+{
+       check_move_unevictable_pages(pvec);
+       __pagevec_release(pvec);
+       cond_resched();
+}
+
 static void
 i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj,
                              struct sg_table *pages)
 {
        struct sgt_iter sgt_iter;
+       struct pagevec pvec;
        struct page *page;
 
        __i915_gem_object_release_shmem(obj, pages, true);
@@ -2395,6 +2408,9 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj,
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_save_bit_17_swizzle(obj, pages);
 
+       mapping_clear_unevictable(file_inode(obj->base.filp)->i_mapping);
+
+       pagevec_init(&pvec);
        for_each_sgt_page(page, sgt_iter, pages) {
                if (obj->mm.dirty)
                        set_page_dirty(page);
@@ -2402,8 +2418,11 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj,
                if (obj->mm.madv == I915_MADV_WILLNEED)
                        mark_page_accessed(page);
 
-               put_page(page);
+               if (!pagevec_add(&pvec, page))
+                       check_release_pagevec(&pvec);
        }
+       if (pagevec_count(&pvec))
+               check_release_pagevec(&pvec);
        obj->mm.dirty = false;
 
        sg_free_table(pages);
@@ -2483,7 +2502,7 @@ unlock:
        mutex_unlock(&obj->mm.lock);
 }
 
-static bool i915_sg_trim(struct sg_table *orig_st)
+bool i915_sg_trim(struct sg_table *orig_st)
 {
        struct sg_table new_st;
        struct scatterlist *sg, *new_sg;
@@ -2524,6 +2543,7 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        unsigned long last_pfn = 0;     /* suppress gcc warning */
        unsigned int max_segment = i915_sg_segment_size();
        unsigned int sg_page_sizes;
+       struct pagevec pvec;
        gfp_t noreclaim;
        int ret;
 
@@ -2559,6 +2579,7 @@ rebuild_st:
         * Fail silently without starting the shrinker
         */
        mapping = obj->base.filp->f_mapping;
+       mapping_set_unevictable(mapping);
        noreclaim = mapping_gfp_constraint(mapping, ~__GFP_RECLAIM);
        noreclaim |= __GFP_NORETRY | __GFP_NOWARN;
 
@@ -2573,6 +2594,7 @@ rebuild_st:
                gfp_t gfp = noreclaim;
 
                do {
+                       cond_resched();
                        page = shmem_read_mapping_page_gfp(mapping, i, gfp);
                        if (likely(!IS_ERR(page)))
                                break;
@@ -2583,7 +2605,6 @@ rebuild_st:
                        }
 
                        i915_gem_shrink(dev_priv, 2 * page_count, NULL, *s++);
-                       cond_resched();
 
                        /*
                         * We've tried hard to allocate the memory by reaping
@@ -2673,8 +2694,14 @@ rebuild_st:
 err_sg:
        sg_mark_end(sg);
 err_pages:
-       for_each_sgt_page(page, sgt_iter, st)
-               put_page(page);
+       mapping_clear_unevictable(mapping);
+       pagevec_init(&pvec);
+       for_each_sgt_page(page, sgt_iter, st) {
+               if (!pagevec_add(&pvec, page))
+                       check_release_pagevec(&pvec);
+       }
+       if (pagevec_count(&pvec))
+               check_release_pagevec(&pvec);
        sg_free_table(st);
        kfree(st);
 
@@ -3281,16 +3308,6 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
 }
 
 static void nop_submit_request(struct i915_request *request)
-{
-       GEM_TRACE("%s fence %llx:%d -> -EIO\n",
-                 request->engine->name,
-                 request->fence.context, request->fence.seqno);
-       dma_fence_set_error(&request->fence, -EIO);
-
-       i915_request_submit(request);
-}
-
-static void nop_complete_submit_request(struct i915_request *request)
 {
        unsigned long flags;
 
@@ -3327,57 +3344,33 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
         * rolling the global seqno forward (since this would complete requests
         * for which we haven't set the fence error to EIO yet).
         */
-       for_each_engine(engine, i915, id) {
+       for_each_engine(engine, i915, id)
                i915_gem_reset_prepare_engine(engine);
 
-               engine->submit_request = nop_submit_request;
-               engine->schedule = NULL;
-       }
-       i915->caps.scheduler = 0;
-
        /* Even if the GPU reset fails, it should still stop the engines */
        if (INTEL_GEN(i915) >= 5)
                intel_gpu_reset(i915, ALL_ENGINES);
 
-       /*
-        * Make sure no one is running the old callback before we proceed with
-        * cancelling requests and resetting the completion tracking. Otherwise
-        * we might submit a request to the hardware which never completes.
-        */
-       synchronize_rcu();
-
        for_each_engine(engine, i915, id) {
-               /* Mark all executing requests as skipped */
-               engine->cancel_requests(engine);
-
-               /*
-                * Only once we've force-cancelled all in-flight requests can we
-                * start to complete all requests.
-                */
-               engine->submit_request = nop_complete_submit_request;
+               engine->submit_request = nop_submit_request;
+               engine->schedule = NULL;
        }
+       i915->caps.scheduler = 0;
 
        /*
         * Make sure no request can slip through without getting completed by
         * either this call here to intel_engine_init_global_seqno, or the one
-        * in nop_complete_submit_request.
+        * in nop_submit_request.
         */
        synchronize_rcu();
 
-       for_each_engine(engine, i915, id) {
-               unsigned long flags;
-
-               /*
-                * Mark all pending requests as complete so that any concurrent
-                * (lockless) lookup doesn't try and wait upon the request as we
-                * reset it.
-                */
-               spin_lock_irqsave(&engine->timeline.lock, flags);
-               intel_engine_init_global_seqno(engine,
-                                              intel_engine_last_submit(engine));
-               spin_unlock_irqrestore(&engine->timeline.lock, flags);
+       /* Mark all executing requests as skipped */
+       for_each_engine(engine, i915, id)
+               engine->cancel_requests(engine);
 
+       for_each_engine(engine, i915, id) {
                i915_gem_reset_finish_engine(engine);
+               intel_engine_wakeup(engine);
        }
 
 out:
@@ -3530,6 +3523,8 @@ static void __sleep_rcu(struct rcu_head *rcu)
        struct sleep_rcu_work *s = container_of(rcu, typeof(*s), rcu);
        struct drm_i915_private *i915 = s->i915;
 
+       destroy_rcu_head(&s->rcu);
+
        if (same_epoch(i915, s->epoch)) {
                INIT_WORK(&s->work, __sleep_work);
                queue_work(i915->wq, &s->work);
@@ -3646,6 +3641,7 @@ out_rearm:
        if (same_epoch(dev_priv, epoch)) {
                struct sleep_rcu_work *s = kmalloc(sizeof(*s), GFP_KERNEL);
                if (s) {
+                       init_rcu_head(&s->rcu);
                        s->i915 = dev_priv;
                        s->epoch = epoch;
                        call_rcu(&s->rcu, __sleep_rcu);
@@ -3743,7 +3739,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        start = ktime_get();
 
        ret = i915_gem_object_wait(obj,
-                                  I915_WAIT_INTERRUPTIBLE | I915_WAIT_ALL,
+                                  I915_WAIT_INTERRUPTIBLE |
+                                  I915_WAIT_PRIORITY |
+                                  I915_WAIT_ALL,
                                   to_wait_timeout(args->timeout_ns),
                                   to_rps_client(file));
 
@@ -4710,6 +4708,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
        INIT_LIST_HEAD(&obj->lut_list);
        INIT_LIST_HEAD(&obj->batch_pool_link);
 
+       init_rcu_head(&obj->rcu);
+
        obj->ops = ops;
 
        reservation_object_init(&obj->__builtin_resv);
@@ -4976,6 +4976,13 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head)
                container_of(head, typeof(*obj), rcu);
        struct drm_i915_private *i915 = to_i915(obj->base.dev);
 
+       /*
+        * We reuse obj->rcu for the freed list, so we had better not treat
+        * it like a rcu_head from this point forwards. And we expect all
+        * objects to be freed via this path.
+        */
+       destroy_rcu_head(&obj->rcu);
+
        /*
         * Since we require blocking on struct_mutex to unbind the freed
         * object from the GPU before releasing resources back to the
@@ -5293,19 +5300,10 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv)
                I915_WRITE(MI_PREDICATE_RESULT_2, IS_HSW_GT3(dev_priv) ?
                           LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED);
 
-       if (HAS_PCH_NOP(dev_priv)) {
-               if (IS_IVYBRIDGE(dev_priv)) {
-                       u32 temp = I915_READ(GEN7_MSG_CTL);
-                       temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
-                       I915_WRITE(GEN7_MSG_CTL, temp);
-               } else if (INTEL_GEN(dev_priv) >= 7) {
-                       u32 temp = I915_READ(HSW_NDE_RSTWRN_OPT);
-                       temp &= ~RESET_PCH_HANDSHAKE_ENABLE;
-                       I915_WRITE(HSW_NDE_RSTWRN_OPT, temp);
-               }
-       }
-
+       /* Apply the GT workarounds... */
        intel_gt_apply_workarounds(dev_priv);
+       /* ...and determine whether they are sticking. */
+       intel_gt_verify_workarounds(dev_priv, "init");
 
        i915_gem_init_swizzling(dev_priv);
 
@@ -6001,7 +5999,7 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
         * the bits.
         */
        BUILD_BUG_ON(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES >
-                    sizeof(atomic_t) * BITS_PER_BYTE);
+                    BITS_PER_TYPE(atomic_t));
 
        if (old) {
                WARN_ON(!(atomic_read(&old->frontbuffer_bits) & frontbuffer_bits));
index 599c4f6eb1eab017f20ef7e06c4ce43aa817c42f..b0e4b976880c0bf6699197f4f0215e15289c23f4 100644 (file)
@@ -47,17 +47,19 @@ struct drm_i915_private;
 #define GEM_DEBUG_DECL(var) var
 #define GEM_DEBUG_EXEC(expr) expr
 #define GEM_DEBUG_BUG_ON(expr) GEM_BUG_ON(expr)
+#define GEM_DEBUG_WARN_ON(expr) GEM_WARN_ON(expr)
 
 #else
 
 #define GEM_SHOW_DEBUG() (0)
 
 #define GEM_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
-#define GEM_WARN_ON(expr) (BUILD_BUG_ON_INVALID(expr), 0)
+#define GEM_WARN_ON(expr) ({ unlikely(!!(expr)); })
 
 #define GEM_DEBUG_DECL(var)
 #define GEM_DEBUG_EXEC(expr) do { } while (0)
 #define GEM_DEBUG_BUG_ON(expr)
+#define GEM_DEBUG_WARN_ON(expr) ({ BUILD_BUG_ON_INVALID(expr); 0; })
 #endif
 
 #if IS_ENABLED(CONFIG_DRM_I915_TRACE_GEM)
index f772593b99ab484563de0e1cad543e95254e0553..371c070870951d6d1523d828ebfc9874a56e1977 100644 (file)
@@ -337,7 +337,7 @@ __create_hw_context(struct drm_i915_private *dev_priv,
        kref_init(&ctx->ref);
        list_add_tail(&ctx->link, &dev_priv->contexts.list);
        ctx->i915 = dev_priv;
-       ctx->sched.priority = I915_PRIORITY_NORMAL;
+       ctx->sched.priority = I915_USER_PRIORITY(I915_PRIORITY_NORMAL);
 
        for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
                struct intel_context *ce = &ctx->__engine[n];
@@ -414,7 +414,7 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
        if (IS_ERR(ctx))
                return ctx;
 
-       if (USES_FULL_PPGTT(dev_priv)) {
+       if (HAS_FULL_PPGTT(dev_priv)) {
                struct i915_hw_ppgtt *ppgtt;
 
                ppgtt = i915_ppgtt_create(dev_priv, file_priv);
@@ -457,7 +457,7 @@ i915_gem_context_create_gvt(struct drm_device *dev)
        if (ret)
                return ERR_PTR(ret);
 
-       ctx = __create_hw_context(to_i915(dev), NULL);
+       ctx = i915_gem_create_context(to_i915(dev), NULL);
        if (IS_ERR(ctx))
                goto out;
 
@@ -504,7 +504,7 @@ i915_gem_context_create_kernel(struct drm_i915_private *i915, int prio)
        }
 
        i915_gem_context_clear_bannable(ctx);
-       ctx->sched.priority = prio;
+       ctx->sched.priority = I915_USER_PRIORITY(prio);
        ctx->ring_size = PAGE_SIZE;
 
        GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
@@ -535,16 +535,12 @@ static bool needs_preempt_context(struct drm_i915_private *i915)
 int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
 {
        struct i915_gem_context *ctx;
-       int ret;
 
        /* Reassure ourselves we are only called once */
        GEM_BUG_ON(dev_priv->kernel_context);
        GEM_BUG_ON(dev_priv->preempt_context);
 
-       ret = intel_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
-
+       intel_engine_init_ctx_wa(dev_priv->engine[RCS]);
        init_contexts(dev_priv);
 
        /* lowest priority; idle task */
@@ -879,7 +875,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
                args->value = i915_gem_context_is_bannable(ctx);
                break;
        case I915_CONTEXT_PARAM_PRIORITY:
-               args->value = ctx->sched.priority;
+               args->value = ctx->sched.priority >> I915_USER_PRIORITY_SHIFT;
                break;
        default:
                ret = -EINVAL;
@@ -948,7 +944,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
                                 !capable(CAP_SYS_NICE))
                                ret = -EPERM;
                        else
-                               ctx->sched.priority = priority;
+                               ctx->sched.priority =
+                                       I915_USER_PRIORITY(priority);
                }
                break;
 
index 08165f6a0a842482cd1eec32f5bd131e39e44500..f6d870b1f73e397971e4f55714d8524f68220395 100644 (file)
@@ -163,6 +163,7 @@ struct i915_gem_context {
        /** engine: per-engine logical HW state */
        struct intel_context {
                struct i915_gem_context *gem_context;
+               struct intel_engine_cs *active;
                struct i915_vma *state;
                struct intel_ring *ring;
                u32 *lrc_reg_state;
index 1aaccbe7e1debd0c11440ac9acae9c15b07880d5..786d719e652de95e82e540847b03698b0e2907b9 100644 (file)
@@ -2186,7 +2186,7 @@ signal_fence_array(struct i915_execbuffer *eb,
                if (!(flags & I915_EXEC_FENCE_SIGNAL))
                        continue;
 
-               drm_syncobj_replace_fence(syncobj, 0, fence);
+               drm_syncobj_replace_fence(syncobj, fence);
        }
 }
 
index 07999fe09ad231a037bc73379b5fc27aaf484b94..add1fe7aeb930f2e21e73d12dbf96f095decc5be 100644 (file)
@@ -133,55 +133,6 @@ static inline void i915_ggtt_invalidate(struct drm_i915_private *i915)
        i915->ggtt.invalidate(i915);
 }
 
-int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
-                               int enable_ppgtt)
-{
-       bool has_full_ppgtt;
-       bool has_full_48bit_ppgtt;
-
-       if (!dev_priv->info.has_aliasing_ppgtt)
-               return 0;
-
-       has_full_ppgtt = dev_priv->info.has_full_ppgtt;
-       has_full_48bit_ppgtt = dev_priv->info.has_full_48bit_ppgtt;
-
-       if (intel_vgpu_active(dev_priv)) {
-               /* GVT-g has no support for 32bit ppgtt */
-               has_full_ppgtt = false;
-               has_full_48bit_ppgtt = intel_vgpu_has_full_48bit_ppgtt(dev_priv);
-       }
-
-       /*
-        * We don't allow disabling PPGTT for gen9+ as it's a requirement for
-        * execlists, the sole mechanism available to submit work.
-        */
-       if (enable_ppgtt == 0 && INTEL_GEN(dev_priv) < 9)
-               return 0;
-
-       if (enable_ppgtt == 1)
-               return 1;
-
-       if (enable_ppgtt == 2 && has_full_ppgtt)
-               return 2;
-
-       if (enable_ppgtt == 3 && has_full_48bit_ppgtt)
-               return 3;
-
-       /* Disable ppgtt on SNB if VT-d is on. */
-       if (IS_GEN6(dev_priv) && intel_vtd_active()) {
-               DRM_INFO("Disabling PPGTT because VT-d is on\n");
-               return 0;
-       }
-
-       if (has_full_48bit_ppgtt)
-               return 3;
-
-       if (has_full_ppgtt)
-               return 2;
-
-       return 1;
-}
-
 static int ppgtt_bind_vma(struct i915_vma *vma,
                          enum i915_cache_level cache_level,
                          u32 unused)
@@ -235,9 +186,9 @@ static void clear_pages(struct i915_vma *vma)
        memset(&vma->page_sizes, 0, sizeof(vma->page_sizes));
 }
 
-static gen8_pte_t gen8_pte_encode(dma_addr_t addr,
-                                 enum i915_cache_level level,
-                                 u32 flags)
+static u64 gen8_pte_encode(dma_addr_t addr,
+                          enum i915_cache_level level,
+                          u32 flags)
 {
        gen8_pte_t pte = addr | _PAGE_PRESENT | _PAGE_RW;
 
@@ -274,9 +225,9 @@ static gen8_pde_t gen8_pde_encode(const dma_addr_t addr,
 #define gen8_pdpe_encode gen8_pde_encode
 #define gen8_pml4e_encode gen8_pde_encode
 
-static gen6_pte_t snb_pte_encode(dma_addr_t addr,
-                                enum i915_cache_level level,
-                                u32 unused)
+static u64 snb_pte_encode(dma_addr_t addr,
+                         enum i915_cache_level level,
+                         u32 flags)
 {
        gen6_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -296,9 +247,9 @@ static gen6_pte_t snb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_pte_t ivb_pte_encode(dma_addr_t addr,
-                                enum i915_cache_level level,
-                                u32 unused)
+static u64 ivb_pte_encode(dma_addr_t addr,
+                         enum i915_cache_level level,
+                         u32 flags)
 {
        gen6_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -320,9 +271,9 @@ static gen6_pte_t ivb_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_pte_t byt_pte_encode(dma_addr_t addr,
-                                enum i915_cache_level level,
-                                u32 flags)
+static u64 byt_pte_encode(dma_addr_t addr,
+                         enum i915_cache_level level,
+                         u32 flags)
 {
        gen6_pte_t pte = GEN6_PTE_VALID;
        pte |= GEN6_PTE_ADDR_ENCODE(addr);
@@ -336,9 +287,9 @@ static gen6_pte_t byt_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_pte_t hsw_pte_encode(dma_addr_t addr,
-                                enum i915_cache_level level,
-                                u32 unused)
+static u64 hsw_pte_encode(dma_addr_t addr,
+                         enum i915_cache_level level,
+                         u32 flags)
 {
        gen6_pte_t pte = GEN6_PTE_VALID;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
@@ -349,9 +300,9 @@ static gen6_pte_t hsw_pte_encode(dma_addr_t addr,
        return pte;
 }
 
-static gen6_pte_t iris_pte_encode(dma_addr_t addr,
-                                 enum i915_cache_level level,
-                                 u32 unused)
+static u64 iris_pte_encode(dma_addr_t addr,
+                          enum i915_cache_level level,
+                          u32 flags)
 {
        gen6_pte_t pte = GEN6_PTE_VALID;
        pte |= HSW_PTE_ADDR_ENCODE(addr);
@@ -629,10 +580,9 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp)
         * region, including any PTEs which happen to point to scratch.
         *
         * This is only relevant for the 48b PPGTT where we support
-        * huge-gtt-pages, see also i915_vma_insert().
-        *
-        * TODO: we should really consider write-protecting the scratch-page and
-        * sharing between ppgtt
+        * huge-gtt-pages, see also i915_vma_insert(). However, as we share the
+        * scratch (read-only) between all vm, we create one 64k scratch page
+        * for all.
         */
        size = I915_GTT_PAGE_SIZE_4K;
        if (i915_vm_is_48bit(vm) &&
@@ -715,14 +665,13 @@ static void free_pt(struct i915_address_space *vm, struct i915_page_table *pt)
 static void gen8_initialize_pt(struct i915_address_space *vm,
                               struct i915_page_table *pt)
 {
-       fill_px(vm, pt,
-               gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0));
+       fill_px(vm, pt, vm->scratch_pte);
 }
 
-static void gen6_initialize_pt(struct gen6_hw_ppgtt *ppgtt,
+static void gen6_initialize_pt(struct i915_address_space *vm,
                               struct i915_page_table *pt)
 {
-       fill32_px(&ppgtt->base.vm, pt, ppgtt->scratch_pte);
+       fill32_px(vm, pt, vm->scratch_pte);
 }
 
 static struct i915_page_directory *alloc_pd(struct i915_address_space *vm)
@@ -856,15 +805,13 @@ static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt)
 /* Removes entries from a single page table, releasing it if it's empty.
  * Caller can use the return value to update higher-level entries.
  */
-static bool gen8_ppgtt_clear_pt(struct i915_address_space *vm,
+static bool gen8_ppgtt_clear_pt(const struct i915_address_space *vm,
                                struct i915_page_table *pt,
                                u64 start, u64 length)
 {
        unsigned int num_entries = gen8_pte_count(start, length);
        unsigned int pte = gen8_pte_index(start);
        unsigned int pte_end = pte + num_entries;
-       const gen8_pte_t scratch_pte =
-               gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0);
        gen8_pte_t *vaddr;
 
        GEM_BUG_ON(num_entries > pt->used_ptes);
@@ -875,7 +822,7 @@ static bool gen8_ppgtt_clear_pt(struct i915_address_space *vm,
 
        vaddr = kmap_atomic_px(pt);
        while (pte < pte_end)
-               vaddr[pte++] = scratch_pte;
+               vaddr[pte++] = vm->scratch_pte;
        kunmap_atomic(vaddr);
 
        return false;
@@ -1208,7 +1155,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma,
                        if (I915_SELFTEST_ONLY(vma->vm->scrub_64K)) {
                                u16 i;
 
-                               encode = pte_encode | vma->vm->scratch_page.daddr;
+                               encode = vma->vm->scratch_pte;
                                vaddr = kmap_atomic_px(pd->page_table[idx.pde]);
 
                                for (i = 1; i < index; i += 16)
@@ -1261,10 +1208,35 @@ static int gen8_init_scratch(struct i915_address_space *vm)
 {
        int ret;
 
+       /*
+        * If everybody agrees to not to write into the scratch page,
+        * we can reuse it for all vm, keeping contexts and processes separate.
+        */
+       if (vm->has_read_only &&
+           vm->i915->kernel_context &&
+           vm->i915->kernel_context->ppgtt) {
+               struct i915_address_space *clone =
+                       &vm->i915->kernel_context->ppgtt->vm;
+
+               GEM_BUG_ON(!clone->has_read_only);
+
+               vm->scratch_page.order = clone->scratch_page.order;
+               vm->scratch_pte = clone->scratch_pte;
+               vm->scratch_pt  = clone->scratch_pt;
+               vm->scratch_pd  = clone->scratch_pd;
+               vm->scratch_pdp = clone->scratch_pdp;
+               return 0;
+       }
+
        ret = setup_scratch_page(vm, __GFP_HIGHMEM);
        if (ret)
                return ret;
 
+       vm->scratch_pte =
+               gen8_pte_encode(vm->scratch_page.daddr,
+                               I915_CACHE_LLC,
+                               PTE_READ_ONLY);
+
        vm->scratch_pt = alloc_pt(vm);
        if (IS_ERR(vm->scratch_pt)) {
                ret = PTR_ERR(vm->scratch_pt);
@@ -1336,6 +1308,9 @@ static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create)
 
 static void gen8_free_scratch(struct i915_address_space *vm)
 {
+       if (!vm->scratch_page.daddr)
+               return;
+
        if (use_4lvl(vm))
                free_pdp(vm, vm->scratch_pdp);
        free_pd(vm, vm->scratch_pd);
@@ -1573,8 +1548,7 @@ static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt,
 static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
 {
        struct i915_address_space *vm = &ppgtt->vm;
-       const gen8_pte_t scratch_pte =
-               gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0);
+       const gen8_pte_t scratch_pte = vm->scratch_pte;
        u64 start = 0, length = ppgtt->vm.total;
 
        if (use_4lvl(vm)) {
@@ -1647,16 +1621,12 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915)
        ppgtt->vm.i915 = i915;
        ppgtt->vm.dma = &i915->drm.pdev->dev;
 
-       ppgtt->vm.total = USES_FULL_48BIT_PPGTT(i915) ?
+       ppgtt->vm.total = HAS_FULL_48BIT_PPGTT(i915) ?
                1ULL << 48 :
                1ULL << 32;
 
-       /*
-        * From bdw, there is support for read-only pages in the PPGTT.
-        *
-        * XXX GVT is not honouring the lack of RW in the PTE bits.
-        */
-       ppgtt->vm.has_read_only = !intel_vgpu_active(i915);
+       /* From bdw, there is support for read-only pages in the PPGTT. */
+       ppgtt->vm.has_read_only = true;
 
        i915_address_space_init(&ppgtt->vm, i915);
 
@@ -1721,7 +1691,7 @@ err_free:
 static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m)
 {
        struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base);
-       const gen6_pte_t scratch_pte = ppgtt->scratch_pte;
+       const gen6_pte_t scratch_pte = base->vm.scratch_pte;
        struct i915_page_table *pt;
        u32 pte, pde;
 
@@ -1782,19 +1752,6 @@ static inline void gen6_write_pde(const struct gen6_hw_ppgtt *ppgtt,
                  ppgtt->pd_addr + pde);
 }
 
-static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv)
-{
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-
-       for_each_engine(engine, dev_priv, id) {
-               u32 four_level = USES_FULL_48BIT_PPGTT(dev_priv) ?
-                                GEN8_GFX_PPGTT_48B : 0;
-               I915_WRITE(RING_MODE_GEN7(engine),
-                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE | four_level));
-       }
-}
-
 static void gen7_ppgtt_enable(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
@@ -1834,7 +1791,8 @@ static void gen6_ppgtt_enable(struct drm_i915_private *dev_priv)
        ecochk = I915_READ(GAM_ECOCHK);
        I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
 
-       I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+       if (HAS_PPGTT(dev_priv)) /* may be disabled for VT-d */
+               I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
@@ -1846,7 +1804,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
        unsigned int pde = first_entry / GEN6_PTES;
        unsigned int pte = first_entry % GEN6_PTES;
        unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
-       const gen6_pte_t scratch_pte = ppgtt->scratch_pte;
+       const gen6_pte_t scratch_pte = vm->scratch_pte;
 
        while (num_entries) {
                struct i915_page_table *pt = ppgtt->base.pd.page_table[pde++];
@@ -1937,7 +1895,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm,
                        if (IS_ERR(pt))
                                goto unwind_out;
 
-                       gen6_initialize_pt(ppgtt, pt);
+                       gen6_initialize_pt(vm, pt);
                        ppgtt->base.pd.page_table[pde] = pt;
 
                        if (i915_vma_is_bound(ppgtt->vma,
@@ -1975,9 +1933,9 @@ static int gen6_ppgtt_init_scratch(struct gen6_hw_ppgtt *ppgtt)
        if (ret)
                return ret;
 
-       ppgtt->scratch_pte =
-               vm->pte_encode(vm->scratch_page.daddr,
-                              I915_CACHE_NONE, PTE_READ_ONLY);
+       vm->scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
+                                        I915_CACHE_NONE,
+                                        PTE_READ_ONLY);
 
        vm->scratch_pt = alloc_pt(vm);
        if (IS_ERR(vm->scratch_pt)) {
@@ -1985,7 +1943,7 @@ static int gen6_ppgtt_init_scratch(struct gen6_hw_ppgtt *ppgtt)
                return PTR_ERR(vm->scratch_pt);
        }
 
-       gen6_initialize_pt(ppgtt, vm->scratch_pt);
+       gen6_initialize_pt(vm, vm->scratch_pt);
        gen6_for_all_pdes(unused, &ppgtt->base.pd, pde)
                ppgtt->base.pd.page_table[pde] = vm->scratch_pt;
 
@@ -2237,23 +2195,10 @@ int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv)
 {
        gtt_write_workarounds(dev_priv);
 
-       /* In the case of execlists, PPGTT is enabled by the context descriptor
-        * and the PDPs are contained within the context itself.  We don't
-        * need to do anything here. */
-       if (HAS_LOGICAL_RING_CONTEXTS(dev_priv))
-               return 0;
-
-       if (!USES_PPGTT(dev_priv))
-               return 0;
-
        if (IS_GEN6(dev_priv))
                gen6_ppgtt_enable(dev_priv);
        else if (IS_GEN7(dev_priv))
                gen7_ppgtt_enable(dev_priv);
-       else if (INTEL_GEN(dev_priv) >= 8)
-               gen8_ppgtt_enable(dev_priv);
-       else
-               MISSING_CASE(INTEL_GEN(dev_priv));
 
        return 0;
 }
@@ -2543,8 +2488,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
        unsigned first_entry = start / I915_GTT_PAGE_SIZE;
        unsigned num_entries = length / I915_GTT_PAGE_SIZE;
-       const gen8_pte_t scratch_pte =
-               gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0);
+       const gen8_pte_t scratch_pte = vm->scratch_pte;
        gen8_pte_t __iomem *gtt_base =
                (gen8_pte_t __iomem *)ggtt->gsm + first_entry;
        const int max_entries = ggtt_total_entries(ggtt) - first_entry;
@@ -2669,8 +2613,7 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
-                                    I915_CACHE_LLC, 0);
+       scratch_pte = vm->scratch_pte;
 
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
@@ -2952,7 +2895,7 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
        /* And finally clear the reserved guard page */
        ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE);
 
-       if (USES_PPGTT(dev_priv) && !USES_FULL_PPGTT(dev_priv)) {
+       if (INTEL_PPGTT(dev_priv) == INTEL_PPGTT_ALIASING) {
                ret = i915_gem_init_aliasing_ppgtt(dev_priv);
                if (ret)
                        goto err;
@@ -3076,6 +3019,10 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
                return ret;
        }
 
+       ggtt->vm.scratch_pte =
+               ggtt->vm.pte_encode(ggtt->vm.scratch_page.daddr,
+                                   I915_CACHE_NONE, 0);
+
        return 0;
 }
 
@@ -3275,7 +3222,7 @@ static void bdw_setup_private_ppat(struct intel_ppat *ppat)
        ppat->match = bdw_private_pat_match;
        ppat->clear_value = GEN8_PPAT_WB | GEN8_PPAT_LLCELLC | GEN8_PPAT_AGE(3);
 
-       if (!USES_PPGTT(ppat->i915)) {
+       if (!HAS_PPGTT(ppat->i915)) {
                /* Spec: "For GGTT, there is NO pat_sel[2:0] from the entry,
                 * so RTL will always use the value corresponding to
                 * pat_sel = 000".
@@ -3402,7 +3349,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
        ggtt->vm.cleanup = gen6_gmch_remove;
        ggtt->vm.insert_page = gen8_ggtt_insert_page;
        ggtt->vm.clear_range = nop_clear_range;
-       if (!USES_FULL_PPGTT(dev_priv) || intel_scanout_needs_vtd_wa(dev_priv))
+       if (intel_scanout_needs_vtd_wa(dev_priv))
                ggtt->vm.clear_range = gen8_ggtt_clear_range;
 
        ggtt->vm.insert_entries = gen8_ggtt_insert_entries;
@@ -3427,6 +3374,8 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
        ggtt->vm.vma_ops.set_pages   = ggtt_set_pages;
        ggtt->vm.vma_ops.clear_pages = clear_pages;
 
+       ggtt->vm.pte_encode = gen8_pte_encode;
+
        setup_private_pat(dev_priv);
 
        return ggtt_probe_common(ggtt, size);
@@ -3614,7 +3563,7 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv)
        /* Only VLV supports read-only GGTT mappings */
        ggtt->vm.has_read_only = IS_VALLEYVIEW(dev_priv);
 
-       if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv))
+       if (!HAS_LLC(dev_priv) && !HAS_PPGTT(dev_priv))
                ggtt->vm.mm.color_adjust = i915_gtt_color_adjust;
        mutex_unlock(&dev_priv->drm.struct_mutex);
 
@@ -3716,7 +3665,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
 }
 
 static struct scatterlist *
-rotate_pages(const dma_addr_t *in, unsigned int offset,
+rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset,
             unsigned int width, unsigned int height,
             unsigned int stride,
             struct sg_table *st, struct scatterlist *sg)
@@ -3725,7 +3674,7 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
        unsigned int src_idx;
 
        for (column = 0; column < width; column++) {
-               src_idx = stride * (height - 1) + column;
+               src_idx = stride * (height - 1) + column + offset;
                for (row = 0; row < height; row++) {
                        st->nents++;
                        /* We don't need the pages, but need to initialize
@@ -3733,7 +3682,8 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
                         * The only thing we need are DMA addresses.
                         */
                        sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0);
-                       sg_dma_address(sg) = in[offset + src_idx];
+                       sg_dma_address(sg) =
+                               i915_gem_object_get_dma_address(obj, src_idx);
                        sg_dma_len(sg) = I915_GTT_PAGE_SIZE;
                        sg = sg_next(sg);
                        src_idx -= stride;
@@ -3747,22 +3697,11 @@ static noinline struct sg_table *
 intel_rotate_pages(struct intel_rotation_info *rot_info,
                   struct drm_i915_gem_object *obj)
 {
-       const unsigned long n_pages = obj->base.size / I915_GTT_PAGE_SIZE;
        unsigned int size = intel_rotation_info_size(rot_info);
-       struct sgt_iter sgt_iter;
-       dma_addr_t dma_addr;
-       unsigned long i;
-       dma_addr_t *page_addr_list;
        struct sg_table *st;
        struct scatterlist *sg;
        int ret = -ENOMEM;
-
-       /* Allocate a temporary list of source pages for random access. */
-       page_addr_list = kvmalloc_array(n_pages,
-                                       sizeof(dma_addr_t),
-                                       GFP_KERNEL);
-       if (!page_addr_list)
-               return ERR_PTR(ret);
+       int i;
 
        /* Allocate target SG list. */
        st = kmalloc(sizeof(*st), GFP_KERNEL);
@@ -3773,29 +3712,20 @@ intel_rotate_pages(struct intel_rotation_info *rot_info,
        if (ret)
                goto err_sg_alloc;
 
-       /* Populate source page list from the object. */
-       i = 0;
-       for_each_sgt_dma(dma_addr, sgt_iter, obj->mm.pages)
-               page_addr_list[i++] = dma_addr;
-
-       GEM_BUG_ON(i != n_pages);
        st->nents = 0;
        sg = st->sgl;
 
        for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) {
-               sg = rotate_pages(page_addr_list, rot_info->plane[i].offset,
+               sg = rotate_pages(obj, rot_info->plane[i].offset,
                                  rot_info->plane[i].width, rot_info->plane[i].height,
                                  rot_info->plane[i].stride, st, sg);
        }
 
-       kvfree(page_addr_list);
-
        return st;
 
 err_sg_alloc:
        kfree(st);
 err_st_alloc:
-       kvfree(page_addr_list);
 
        DRM_DEBUG_DRIVER("Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n",
                         obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
@@ -3840,6 +3770,8 @@ intel_partial_pages(const struct i915_ggtt_view *view,
                count -= len >> PAGE_SHIFT;
                if (count == 0) {
                        sg_mark_end(sg);
+                       i915_sg_trim(st); /* Drop any unused tail entries. */
+
                        return st;
                }
 
index 28039290655cb7d5cf11f2c94260ba88c669e169..4874da09a3c471d24697b55b4ab7687d2d76afbf 100644 (file)
@@ -289,6 +289,7 @@ struct i915_address_space {
 
        struct mutex mutex; /* protects vma and our lists */
 
+       u64 scratch_pte;
        struct i915_page_dma scratch_page;
        struct i915_page_table *scratch_pt;
        struct i915_page_directory *scratch_pd;
@@ -335,12 +336,11 @@ struct i915_address_space {
        /* Some systems support read-only mappings for GGTT and/or PPGTT */
        bool has_read_only:1;
 
-       /* FIXME: Need a more generic return type */
-       gen6_pte_t (*pte_encode)(dma_addr_t addr,
-                                enum i915_cache_level level,
-                                u32 flags); /* Create a valid PTE */
-       /* flags for pte_encode */
+       u64 (*pte_encode)(dma_addr_t addr,
+                         enum i915_cache_level level,
+                         u32 flags); /* Create a valid PTE */
 #define PTE_READ_ONLY  (1<<0)
+
        int (*allocate_va_range)(struct i915_address_space *vm,
                                 u64 start, u64 length);
        void (*clear_range)(struct i915_address_space *vm,
@@ -422,7 +422,6 @@ struct gen6_hw_ppgtt {
 
        struct i915_vma *vma;
        gen6_pte_t __iomem *pd_addr;
-       gen6_pte_t scratch_pte;
 
        unsigned int pin_count;
        bool scan_for_unused_pt;
index db4128d6c09b6735a02efb76ea7cf756459eaa51..07465123c1663c61818fc1b63c1c04cab782ba06 100644 (file)
  *
  */
 
-#include <generated/utsrelease.h>
+#include <linux/ascii85.h>
+#include <linux/nmi.h>
+#include <linux/scatterlist.h>
 #include <linux/stop_machine.h>
+#include <linux/utsname.h>
 #include <linux/zlib.h>
+
 #include <drm/drm_print.h>
-#include <linux/ascii85.h>
 
 #include "i915_gpu_error.h"
 #include "i915_drv.h"
@@ -77,112 +80,110 @@ static const char *purgeable_flag(int purgeable)
        return purgeable ? " purgeable" : "";
 }
 
-static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
+static void __sg_set_buf(struct scatterlist *sg,
+                        void *addr, unsigned int len, loff_t it)
 {
-
-       if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
-               e->err = -ENOSPC;
-               return false;
-       }
-
-       if (e->bytes == e->size - 1 || e->err)
-               return false;
-
-       return true;
+       sg->page_link = (unsigned long)virt_to_page(addr);
+       sg->offset = offset_in_page(addr);
+       sg->length = len;
+       sg->dma_address = it;
 }
 
-static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
-                             unsigned len)
+static bool __i915_error_grow(struct drm_i915_error_state_buf *e, size_t len)
 {
-       if (e->pos + len <= e->start) {
-               e->pos += len;
+       if (!len)
                return false;
-       }
 
-       /* First vsnprintf needs to fit in its entirety for memmove */
-       if (len >= e->size) {
-               e->err = -EIO;
-               return false;
-       }
+       if (e->bytes + len + 1 <= e->size)
+               return true;
 
-       return true;
-}
+       if (e->bytes) {
+               __sg_set_buf(e->cur++, e->buf, e->bytes, e->iter);
+               e->iter += e->bytes;
+               e->buf = NULL;
+               e->bytes = 0;
+       }
 
-static void __i915_error_advance(struct drm_i915_error_state_buf *e,
-                                unsigned len)
-{
-       /* If this is first printf in this window, adjust it so that
-        * start position matches start of the buffer
-        */
+       if (e->cur == e->end) {
+               struct scatterlist *sgl;
 
-       if (e->pos < e->start) {
-               const size_t off = e->start - e->pos;
+               sgl = (typeof(sgl))__get_free_page(GFP_KERNEL);
+               if (!sgl) {
+                       e->err = -ENOMEM;
+                       return false;
+               }
 
-               /* Should not happen but be paranoid */
-               if (off > len || e->bytes) {
-                       e->err = -EIO;
-                       return;
+               if (e->cur) {
+                       e->cur->offset = 0;
+                       e->cur->length = 0;
+                       e->cur->page_link =
+                               (unsigned long)sgl | SG_CHAIN;
+               } else {
+                       e->sgl = sgl;
                }
 
-               memmove(e->buf, e->buf + off, len - off);
-               e->bytes = len - off;
-               e->pos = e->start;
-               return;
+               e->cur = sgl;
+               e->end = sgl + SG_MAX_SINGLE_ALLOC - 1;
        }
 
-       e->bytes += len;
-       e->pos += len;
+       e->size = ALIGN(len + 1, SZ_64K);
+       e->buf = kmalloc(e->size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
+       if (!e->buf) {
+               e->size = PAGE_ALIGN(len + 1);
+               e->buf = kmalloc(e->size, GFP_KERNEL);
+       }
+       if (!e->buf) {
+               e->err = -ENOMEM;
+               return false;
+       }
+
+       return true;
 }
 
 __printf(2, 0)
 static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
-                              const char *f, va_list args)
+                              const char *fmt, va_list args)
 {
-       unsigned len;
+       va_list ap;
+       int len;
 
-       if (!__i915_error_ok(e))
+       if (e->err)
                return;
 
-       /* Seek the first printf which is hits start position */
-       if (e->pos < e->start) {
-               va_list tmp;
-
-               va_copy(tmp, args);
-               len = vsnprintf(NULL, 0, f, tmp);
-               va_end(tmp);
-
-               if (!__i915_error_seek(e, len))
-                       return;
+       va_copy(ap, args);
+       len = vsnprintf(NULL, 0, fmt, ap);
+       va_end(ap);
+       if (len <= 0) {
+               e->err = len;
+               return;
        }
 
-       len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
-       if (len >= e->size - e->bytes)
-               len = e->size - e->bytes - 1;
+       if (!__i915_error_grow(e, len))
+               return;
 
-       __i915_error_advance(e, len);
+       GEM_BUG_ON(e->bytes >= e->size);
+       len = vscnprintf(e->buf + e->bytes, e->size - e->bytes, fmt, args);
+       if (len < 0) {
+               e->err = len;
+               return;
+       }
+       e->bytes += len;
 }
 
-static void i915_error_puts(struct drm_i915_error_state_buf *e,
-                           const char *str)
+static void i915_error_puts(struct drm_i915_error_state_buf *e, const char *str)
 {
        unsigned len;
 
-       if (!__i915_error_ok(e))
+       if (e->err || !str)
                return;
 
        len = strlen(str);
+       if (!__i915_error_grow(e, len))
+               return;
 
-       /* Seek the first printf which is hits start position */
-       if (e->pos < e->start) {
-               if (!__i915_error_seek(e, len))
-                       return;
-       }
-
-       if (len >= e->size - e->bytes)
-               len = e->size - e->bytes - 1;
+       GEM_BUG_ON(e->bytes + len > e->size);
        memcpy(e->buf + e->bytes, str, len);
-
-       __i915_error_advance(e, len);
+       e->bytes += len;
 }
 
 #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
@@ -268,6 +269,8 @@ static int compress_page(struct compress *c,
 
                if (zlib_deflate(zstream, Z_NO_FLUSH) != Z_OK)
                        return -EIO;
+
+               touch_nmi_watchdog();
        } while (zstream->avail_in);
 
        /* Fallback to uncompressed if we increase size? */
@@ -512,7 +515,7 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
                        err_printf(m, "  SYNC_2: 0x%08x\n",
                                   ee->semaphore_mboxes[2]);
        }
-       if (USES_PPGTT(m->i915)) {
+       if (HAS_PPGTT(m->i915)) {
                err_printf(m, "  GFX_MODE: 0x%08x\n", ee->vm_info.gfx_mode);
 
                if (INTEL_GEN(m->i915) >= 8) {
@@ -635,25 +638,33 @@ static void err_print_uc(struct drm_i915_error_state_buf *m,
        print_error_obj(m, NULL, "GuC log buffer", error_uc->guc_log);
 }
 
-int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
-                           const struct i915_gpu_state *error)
+static void err_free_sgl(struct scatterlist *sgl)
 {
-       struct drm_i915_private *dev_priv = m->i915;
-       struct drm_i915_error_object *obj;
-       struct timespec64 ts;
-       int i, j;
+       while (sgl) {
+               struct scatterlist *sg;
 
-       if (!error) {
-               err_printf(m, "No error state collected\n");
-               return 0;
+               for (sg = sgl; !sg_is_chain(sg); sg++) {
+                       kfree(sg_virt(sg));
+                       if (sg_is_last(sg))
+                               break;
+               }
+
+               sg = sg_is_last(sg) ? NULL : sg_chain_ptr(sg);
+               free_page((unsigned long)sgl);
+               sgl = sg;
        }
+}
 
-       if (IS_ERR(error))
-               return PTR_ERR(error);
+static void __err_print_to_sgl(struct drm_i915_error_state_buf *m,
+                              struct i915_gpu_state *error)
+{
+       struct drm_i915_error_object *obj;
+       struct timespec64 ts;
+       int i, j;
 
        if (*error->error_msg)
                err_printf(m, "%s\n", error->error_msg);
-       err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       err_printf(m, "Kernel: %s\n", init_utsname()->release);
        ts = ktime_to_timespec64(error->time);
        err_printf(m, "Time: %lld s %ld us\n",
                   (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC);
@@ -683,12 +694,12 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        err_printf(m, "Reset count: %u\n", error->reset_count);
        err_printf(m, "Suspend count: %u\n", error->suspend_count);
        err_printf(m, "Platform: %s\n", intel_platform_name(error->device_info.platform));
-       err_print_pciid(m, error->i915);
+       err_print_pciid(m, m->i915);
 
        err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
 
-       if (HAS_CSR(dev_priv)) {
-               struct intel_csr *csr = &dev_priv->csr;
+       if (HAS_CSR(m->i915)) {
+               struct intel_csr *csr = &m->i915->csr;
 
                err_printf(m, "DMC loaded: %s\n",
                           yesno(csr->dmc_payload != NULL));
@@ -708,22 +719,23 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
        err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
        err_printf(m, "CCID: 0x%08x\n", error->ccid);
-       err_printf(m, "Missed interrupts: 0x%08lx\n", dev_priv->gpu_error.missed_irq_rings);
+       err_printf(m, "Missed interrupts: 0x%08lx\n",
+                  m->i915->gpu_error.missed_irq_rings);
 
        for (i = 0; i < error->nfence; i++)
                err_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
 
-       if (INTEL_GEN(dev_priv) >= 6) {
+       if (INTEL_GEN(m->i915) >= 6) {
                err_printf(m, "ERROR: 0x%08x\n", error->error);
 
-               if (INTEL_GEN(dev_priv) >= 8)
+               if (INTEL_GEN(m->i915) >= 8)
                        err_printf(m, "FAULT_TLB_DATA: 0x%08x 0x%08x\n",
                                   error->fault_data1, error->fault_data0);
 
                err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
        }
 
-       if (IS_GEN7(dev_priv))
+       if (IS_GEN7(m->i915))
                err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
        for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
@@ -745,7 +757,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
                        len += scnprintf(buf + len, sizeof(buf), "%s%s",
                                         first ? "" : ", ",
-                                        dev_priv->engine[j]->name);
+                                        m->i915->engine[j]->name);
                        first = 0;
                }
                scnprintf(buf + len, sizeof(buf), ")");
@@ -763,7 +775,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
                obj = ee->batchbuffer;
                if (obj) {
-                       err_puts(m, dev_priv->engine[i]->name);
+                       err_puts(m, m->i915->engine[i]->name);
                        if (ee->context.pid)
                                err_printf(m, " (submitted by %s [%d], ctx %d [%d], score %d%s)",
                                           ee->context.comm,
@@ -775,16 +787,16 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        err_printf(m, " --- gtt_offset = 0x%08x %08x\n",
                                   upper_32_bits(obj->gtt_offset),
                                   lower_32_bits(obj->gtt_offset));
-                       print_error_obj(m, dev_priv->engine[i], NULL, obj);
+                       print_error_obj(m, m->i915->engine[i], NULL, obj);
                }
 
                for (j = 0; j < ee->user_bo_count; j++)
-                       print_error_obj(m, dev_priv->engine[i],
+                       print_error_obj(m, m->i915->engine[i],
                                        "user", ee->user_bo[j]);
 
                if (ee->num_requests) {
                        err_printf(m, "%s --- %d requests\n",
-                                  dev_priv->engine[i]->name,
+                                  m->i915->engine[i]->name,
                                   ee->num_requests);
                        for (j = 0; j < ee->num_requests; j++)
                                error_print_request(m, " ",
@@ -794,10 +806,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 
                if (IS_ERR(ee->waiters)) {
                        err_printf(m, "%s --- ? waiters [unable to acquire spinlock]\n",
-                                  dev_priv->engine[i]->name);
+                                  m->i915->engine[i]->name);
                } else if (ee->num_waiters) {
                        err_printf(m, "%s --- %d waiters\n",
-                                  dev_priv->engine[i]->name,
+                                  m->i915->engine[i]->name,
                                   ee->num_waiters);
                        for (j = 0; j < ee->num_waiters; j++) {
                                err_printf(m, " seqno 0x%08x for %s [%d]\n",
@@ -807,22 +819,22 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        }
                }
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "ringbuffer", ee->ringbuffer);
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "HW Status", ee->hws_page);
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "HW context", ee->ctx);
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "WA context", ee->wa_ctx);
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "WA batchbuffer", ee->wa_batchbuffer);
 
-               print_error_obj(m, dev_priv->engine[i],
+               print_error_obj(m, m->i915->engine[i],
                                "NULL context", ee->default_state);
        }
 
@@ -835,43 +847,107 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        err_print_capabilities(m, &error->device_info, &error->driver_caps);
        err_print_params(m, &error->params);
        err_print_uc(m, &error->uc);
+}
+
+static int err_print_to_sgl(struct i915_gpu_state *error)
+{
+       struct drm_i915_error_state_buf m;
+
+       if (IS_ERR(error))
+               return PTR_ERR(error);
+
+       if (READ_ONCE(error->sgl))
+               return 0;
+
+       memset(&m, 0, sizeof(m));
+       m.i915 = error->i915;
 
-       if (m->bytes == 0 && m->err)
-               return m->err;
+       __err_print_to_sgl(&m, error);
+
+       if (m.buf) {
+               __sg_set_buf(m.cur++, m.buf, m.bytes, m.iter);
+               m.bytes = 0;
+               m.buf = NULL;
+       }
+       if (m.cur) {
+               GEM_BUG_ON(m.end < m.cur);
+               sg_mark_end(m.cur - 1);
+       }
+       GEM_BUG_ON(m.sgl && !m.cur);
+
+       if (m.err) {
+               err_free_sgl(m.sgl);
+               return m.err;
+       }
+
+       if (cmpxchg(&error->sgl, NULL, m.sgl))
+               err_free_sgl(m.sgl);
 
        return 0;
 }
 
-int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf,
-                             struct drm_i915_private *i915,
-                             size_t count, loff_t pos)
+ssize_t i915_gpu_state_copy_to_buffer(struct i915_gpu_state *error,
+                                     char *buf, loff_t off, size_t rem)
 {
-       memset(ebuf, 0, sizeof(*ebuf));
-       ebuf->i915 = i915;
+       struct scatterlist *sg;
+       size_t count;
+       loff_t pos;
+       int err;
 
-       /* We need to have enough room to store any i915_error_state printf
-        * so that we can move it to start position.
-        */
-       ebuf->size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
-       ebuf->buf = kmalloc(ebuf->size,
-                               GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
+       if (!error || !rem)
+               return 0;
 
-       if (ebuf->buf == NULL) {
-               ebuf->size = PAGE_SIZE;
-               ebuf->buf = kmalloc(ebuf->size, GFP_KERNEL);
-       }
+       err = err_print_to_sgl(error);
+       if (err)
+               return err;
 
-       if (ebuf->buf == NULL) {
-               ebuf->size = 128;
-               ebuf->buf = kmalloc(ebuf->size, GFP_KERNEL);
-       }
+       sg = READ_ONCE(error->fit);
+       if (!sg || off < sg->dma_address)
+               sg = error->sgl;
+       if (!sg)
+               return 0;
 
-       if (ebuf->buf == NULL)
-               return -ENOMEM;
+       pos = sg->dma_address;
+       count = 0;
+       do {
+               size_t len, start;
 
-       ebuf->start = pos;
+               if (sg_is_chain(sg)) {
+                       sg = sg_chain_ptr(sg);
+                       GEM_BUG_ON(sg_is_chain(sg));
+               }
 
-       return 0;
+               len = sg->length;
+               if (pos + len <= off) {
+                       pos += len;
+                       continue;
+               }
+
+               start = sg->offset;
+               if (pos < off) {
+                       GEM_BUG_ON(off - pos > len);
+                       len -= off - pos;
+                       start += off - pos;
+                       pos = off;
+               }
+
+               len = min(len, rem);
+               GEM_BUG_ON(!len || len > sg->length);
+
+               memcpy(buf, page_address(sg_page(sg)) + start, len);
+
+               count += len;
+               pos += len;
+
+               buf += len;
+               rem -= len;
+               if (!rem) {
+                       WRITE_ONCE(error->fit, sg);
+                       break;
+               }
+       } while (!sg_is_last(sg++));
+
+       return count;
 }
 
 static void i915_error_object_free(struct drm_i915_error_object *obj)
@@ -944,6 +1020,7 @@ void __i915_gpu_state_free(struct kref *error_ref)
        cleanup_params(error);
        cleanup_uc_state(error);
 
+       err_free_sgl(error->sgl);
        kfree(error);
 }
 
@@ -1002,7 +1079,6 @@ i915_error_object_create(struct drm_i915_private *i915,
        }
 
        compress_fini(&compress, dst);
-       ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE);
        return dst;
 }
 
@@ -1271,7 +1347,7 @@ static void error_record_engine_registers(struct i915_gpu_state *error,
        ee->reset_count = i915_reset_engine_count(&dev_priv->gpu_error,
                                                  engine);
 
-       if (USES_PPGTT(dev_priv)) {
+       if (HAS_PPGTT(dev_priv)) {
                int i;
 
                ee->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(engine));
@@ -1788,6 +1864,14 @@ static unsigned long capture_find_epoch(const struct i915_gpu_state *error)
        return epoch;
 }
 
+static void capture_finish(struct i915_gpu_state *error)
+{
+       struct i915_ggtt *ggtt = &error->i915->ggtt;
+       const u64 slot = ggtt->error_capture.start;
+
+       ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE);
+}
+
 static int capture(void *data)
 {
        struct i915_gpu_state *error = data;
@@ -1812,6 +1896,7 @@ static int capture(void *data)
 
        error->epoch = capture_find_epoch(error);
 
+       capture_finish(error);
        return 0;
 }
 
index 3ec89a504de52331ade6a9452a844527d84ec515..ff2652bbb0b08bb22cab8d32f338c1bdf8643e81 100644 (file)
@@ -192,6 +192,8 @@ struct i915_gpu_state {
        } *active_bo[I915_NUM_ENGINES], *pinned_bo;
        u32 active_bo_count[I915_NUM_ENGINES], pinned_bo_count;
        struct i915_address_space *active_vm[I915_NUM_ENGINES];
+
+       struct scatterlist *sgl, *fit;
 };
 
 struct i915_gpu_error {
@@ -298,29 +300,20 @@ struct i915_gpu_error {
 
 struct drm_i915_error_state_buf {
        struct drm_i915_private *i915;
-       unsigned int bytes;
-       unsigned int size;
+       struct scatterlist *sgl, *cur, *end;
+
+       char *buf;
+       size_t bytes;
+       size_t size;
+       loff_t iter;
+
        int err;
-       u8 *buf;
-       loff_t start;
-       loff_t pos;
 };
 
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
 
 __printf(2, 3)
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
-int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
-                           const struct i915_gpu_state *gpu);
-int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
-                             struct drm_i915_private *i915,
-                             size_t count, loff_t pos);
-
-static inline void
-i915_error_state_buf_release(struct drm_i915_error_state_buf *eb)
-{
-       kfree(eb->buf);
-}
 
 struct i915_gpu_state *i915_capture_gpu_state(struct drm_i915_private *i915);
 void i915_capture_error_state(struct drm_i915_private *dev_priv,
@@ -334,6 +327,9 @@ i915_gpu_state_get(struct i915_gpu_state *gpu)
        return gpu;
 }
 
+ssize_t i915_gpu_state_copy_to_buffer(struct i915_gpu_state *error,
+                                     char *buf, loff_t offset, size_t count);
+
 void __i915_gpu_state_free(struct kref *kref);
 static inline void i915_gpu_state_put(struct i915_gpu_state *gpu)
 {
index 2e242270e270865ca2f1cc0db2ebbf03dac11185..d447d7d508f483c62baecad23035a60702fd6a3c 100644 (file)
@@ -2887,21 +2887,39 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
        return ret;
 }
 
+static inline u32 gen8_master_intr_disable(void __iomem * const regs)
+{
+       raw_reg_write(regs, GEN8_MASTER_IRQ, 0);
+
+       /*
+        * Now with master disabled, get a sample of level indications
+        * for this interrupt. Indications will be cleared on related acks.
+        * New indications can and will light up during processing,
+        * and will generate new interrupt after enabling master.
+        */
+       return raw_reg_read(regs, GEN8_MASTER_IRQ);
+}
+
+static inline void gen8_master_intr_enable(void __iomem * const regs)
+{
+       raw_reg_write(regs, GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
+}
+
 static irqreturn_t gen8_irq_handler(int irq, void *arg)
 {
        struct drm_i915_private *dev_priv = to_i915(arg);
+       void __iomem * const regs = dev_priv->regs;
        u32 master_ctl;
        u32 gt_iir[4];
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
 
-       master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
-       master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
-       if (!master_ctl)
+       master_ctl = gen8_master_intr_disable(regs);
+       if (!master_ctl) {
+               gen8_master_intr_enable(regs);
                return IRQ_NONE;
-
-       I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
+       }
 
        /* Find, clear, then process each source of interrupt */
        gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
@@ -2913,7 +2931,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                enable_rpm_wakeref_asserts(dev_priv);
        }
 
-       I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
+       gen8_master_intr_enable(regs);
 
        gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
 
@@ -3111,6 +3129,24 @@ gen11_gu_misc_irq_handler(struct drm_i915_private *dev_priv, const u32 iir)
                intel_opregion_asle_intr(dev_priv);
 }
 
+static inline u32 gen11_master_intr_disable(void __iomem * const regs)
+{
+       raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
+
+       /*
+        * Now with master disabled, get a sample of level indications
+        * for this interrupt. Indications will be cleared on related acks.
+        * New indications can and will light up during processing,
+        * and will generate new interrupt after enabling master.
+        */
+       return raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
+}
+
+static inline void gen11_master_intr_enable(void __iomem * const regs)
+{
+       raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ);
+}
+
 static irqreturn_t gen11_irq_handler(int irq, void *arg)
 {
        struct drm_i915_private * const i915 = to_i915(arg);
@@ -3121,13 +3157,11 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg)
        if (!intel_irqs_enabled(i915))
                return IRQ_NONE;
 
-       master_ctl = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
-       master_ctl &= ~GEN11_MASTER_IRQ;
-       if (!master_ctl)
+       master_ctl = gen11_master_intr_disable(regs);
+       if (!master_ctl) {
+               gen11_master_intr_enable(regs);
                return IRQ_NONE;
-
-       /* Disable interrupts. */
-       raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
+       }
 
        /* Find, clear, then process each source of interrupt. */
        gen11_gt_irq_handler(i915, master_ctl);
@@ -3147,8 +3181,7 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg)
 
        gu_misc_iir = gen11_gu_misc_irq_ack(i915, master_ctl);
 
-       /* Acknowledge and enable interrupts. */
-       raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ | master_ctl);
+       gen11_master_intr_enable(regs);
 
        gen11_gu_misc_irq_handler(i915, gu_misc_iir);
 
@@ -3598,8 +3631,7 @@ static void gen8_irq_reset(struct drm_device *dev)
        struct drm_i915_private *dev_priv = to_i915(dev);
        int pipe;
 
-       I915_WRITE(GEN8_MASTER_IRQ, 0);
-       POSTING_READ(GEN8_MASTER_IRQ);
+       gen8_master_intr_disable(dev_priv->regs);
 
        gen8_gt_irq_reset(dev_priv);
 
@@ -3641,13 +3673,15 @@ static void gen11_irq_reset(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       I915_WRITE(GEN11_GFX_MSTR_IRQ, 0);
-       POSTING_READ(GEN11_GFX_MSTR_IRQ);
+       gen11_master_intr_disable(dev_priv->regs);
 
        gen11_gt_irq_reset(dev_priv);
 
        I915_WRITE(GEN11_DISPLAY_INT_CTL, 0);
 
+       I915_WRITE(EDP_PSR_IMR, 0xffffffff);
+       I915_WRITE(EDP_PSR_IIR, 0xffffffff);
+
        for_each_pipe(dev_priv, pipe)
                if (intel_display_power_is_enabled(dev_priv,
                                                   POWER_DOMAIN_PIPE(pipe)))
@@ -4244,8 +4278,7 @@ static int gen8_irq_postinstall(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev_priv))
                ibx_irq_postinstall(dev);
 
-       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
-       POSTING_READ(GEN8_MASTER_IRQ);
+       gen8_master_intr_enable(dev_priv->regs);
 
        return 0;
 }
@@ -4307,8 +4340,7 @@ static int gen11_irq_postinstall(struct drm_device *dev)
 
        I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE);
 
-       I915_WRITE(GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ);
-       POSTING_READ(GEN11_GFX_MSTR_IRQ);
+       gen11_master_intr_enable(dev_priv->regs);
 
        return 0;
 }
@@ -4834,6 +4866,13 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
                dev_priv->display_irqs_enabled = false;
 
        dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
+       /* If we have MST support, we want to avoid doing short HPD IRQ storm
+        * detection, as short HPD storms will occur as a natural part of
+        * sideband messaging with MST.
+        * On older platforms however, IRQ storms can occur with both long and
+        * short pulses, as seen on some G4x systems.
+        */
+       dev_priv->hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv);
 
        dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
        dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
index 4abd2e8b50839ee217fb6945461c13b5073cf212..4acdb94555b727d3a90072cc4ff80ee148410b29 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index b812d16162ac7816d50aeb69d2b8bf86639ebe5e..0e667f1a8aa19ea1b02d8847016871a9c5faa8b1 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_BDW_H__
index cb6f304ec16a3e5eaccdda5941979745f80b9873..a44195c399230f6ef39b0466ca1efbab7c783de6 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 690b963a23833550a1ed7f897d6c9c99eb26fd2f..679e92cf4f1dfde80cf002b77cf1402747df8ab3 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_BXT_H__
index 8641ae30e343a8a423d35a87e964c6f2894bcf00..7f60d51b87611e686dc22ea6c994992be96921d2 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 1f3268ef2ea2b142653c2943fa430d0a37d7a9d3..4d6025559bbe72596afc244f7e26fa443af59832 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_CFLGT2_H__
index 792facdb6702bffdcb808f8bc748518c8299ac8e..a92c38e3a0ce96e42f96c361941a1b424616140c 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index c13b5aac01b9b6b6475d3efde6835a1ac7de5952..0697f407740296e91b02177a4cebd581835a5102 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_CFLGT3_H__
index 556febb2c3c870142aa24d6f29fe15e126224209..71ec889a01145f998f1856bc3eb540442663094d 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index b9622496979ed88155dd9192a37c58f552b4aeb1..0986eae3135f87dd76e2a5306b563d687b837824 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_CHV_H__
index ba9140c87cc0ba7de03f0c36ef91ebcaf372b4c8..5c23d883d6c941247f7783498e1005951feef58f 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index fb918b1311058935c77fd97b79dc5e30439cfd5c..e830a406aff216157cdf7f6352728126fcad5456 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_CNL_H__
index 971db587957c6c306710983f33e17f7908bf6167..4bdda66df7d22bbb6cf2ec2a963b533a61dc0c08 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 63bd113f4bc9deb7e4a9a9bf1f6c9e4a035c293b..06dedf991edb3234746d88cb5f3e93b4753141c3 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_GLK_H__
index 434a9b96d7abdc44f4ecc02116e40536082b4f8c..cc6526fdd2bdc7e7b764285313b9cc13001224f3 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 74d03439c157ebc9c169b649f031564edecad847..3d0c870cd0bdbd5e832800c077c80c7a77da5c25 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_HSW_H__
index a5667926e3de88e1e7d431086628fbb399027c22..baa51427a543facad55c23105436e0512c26a4f0 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index ae1c24aafe4fccd720681695f0ed357fb8bdd046..24eaa97d61ba7629101d96f7090449d91602a3bc 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_ICL_H__
index 2fa98a40bbc84195daaa0f40c7ad47be0dd199f0..168e49ab0d4d7d6e9c5965caa21b356dc9bc0df5 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 25b803546dc1bcd5557f23ea134252172ee02ff3..a55398a904de4b272fe60faf505b949231eafb56 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_KBLGT2_H__
index f3cb6679a1bcfdb62f7d6e3a2742c57d1bb1a4da..6ffa553c388ed70ad1199772569587a445954da5 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index d5b5b5c1923ee1a6ed2faf8dc880b6f8c2cf37fd..3ddd3483b7ccc791abc7be3cb4a87d75c7103c9a 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_KBLGT3_H__
index bf8b8cd8a50d6696b6be196666666b320b26b39c..7ce6ee851d4315774ea7380dbab1d19a2df2f7af 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index fe1aa2c0395840ad8f9755022b29d60eaeac9254..be6256037239919ba2995c450a584c806c0c11d8 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_SKLGT2_H__
index ae534c7c8135e133448d5b3e1cdb8ce0ab6ff309..086ca2631e1cfd87d730f694289d813c4cea11dd 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 06746b2616c81db701b2856c46ac20eb21c36bfd..650beb068e566e4ce885da6d0c590044bafd8ee8 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_SKLGT3_H__
index 817fba2d82df36fc19a0b52ea06800adf6d87194..b291a6eb8a87b983b648bac0e135a34675bad36d 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #include <linux/sysfs.h>
index 944fd525c8b15768ea00fb170d015119c88fae0c..8dcf849d131e0f33af7bfc7ebd37298f1cd529c8 100644 (file)
@@ -1,29 +1,10 @@
 /*
- * Autogenerated file by GPU Top : https://github.com/rib/gputop
- * DO NOT EDIT manually!
- *
- *
- * Copyright (c) 2015 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * 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.
+ * Copyright © 2018 Intel Corporation
  *
+ * Autogenerated file by GPU Top : https://github.com/rib/gputop
+ * DO NOT EDIT manually!
  */
 
 #ifndef __I915_OA_SKLGT4_H__
index 295e981e4a398c242d10bd6ed446aeb0bfecdc70..2e0356561839d15016d72394d7960388545fb223 100644 (file)
@@ -82,10 +82,6 @@ i915_param_named_unsafe(enable_hangcheck, bool, 0644,
        "WARNING: Disabling this can cause system wide hangs. "
        "(default: true)");
 
-i915_param_named_unsafe(enable_ppgtt, int, 0400,
-       "Override PPGTT usage. "
-       "(-1=auto [default], 0=disabled, 1=aliasing, 2=full, 3=full with extended address space)");
-
 i915_param_named_unsafe(enable_psr, int, 0600,
        "Enable PSR "
        "(0=disabled, 1=enabled) "
@@ -171,8 +167,10 @@ i915_param_named_unsafe(inject_load_failure, uint, 0400,
 i915_param_named(enable_dpcd_backlight, bool, 0600,
        "Enable support for DPCD backlight control (default:false)");
 
+#if IS_ENABLED(CONFIG_DRM_I915_GVT)
 i915_param_named(enable_gvt, bool, 0400,
        "Enable support for Intel GVT-g graphics virtualization host support(default:false)");
+#endif
 
 static __always_inline void _print_param(struct drm_printer *p,
                                         const char *name,
@@ -188,7 +186,8 @@ static __always_inline void _print_param(struct drm_printer *p,
        else if (!__builtin_strcmp(type, "char *"))
                drm_printf(p, "i915.%s=%s\n", name, *(const char **)x);
        else
-               BUILD_BUG();
+               WARN_ONCE(1, "no printer defined for param type %s (i915.%s)\n",
+                         type, name);
 }
 
 /**
index 6c4d4a21474b5ffaa9954a145068b1d3effce694..7e56c516c815c269230c697da6166a7fae455fd8 100644 (file)
@@ -41,7 +41,6 @@ struct drm_printer;
        param(int, vbt_sdvo_panel_type, -1) \
        param(int, enable_dc, -1) \
        param(int, enable_fbc, -1) \
-       param(int, enable_ppgtt, -1) \
        param(int, enable_psr, -1) \
        param(int, disable_power_well, -1) \
        param(int, enable_ips, 1) \
index d6f7b9fe1d261fcaa4630f88659427deca873bf8..6350db5503cda372cedcda638680dfcec9725a7e 100644 (file)
 #define GEN(x) .gen = (x), .gen_mask = BIT((x) - 1)
 
 #define GEN_DEFAULT_PIPEOFFSETS \
-       .pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
-                         PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \
-       .trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \
-                          TRANSCODER_C_OFFSET, TRANSCODER_EDP_OFFSET }, \
-       .palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET }
+       .pipe_offsets = { \
+               [TRANSCODER_A] = PIPE_A_OFFSET, \
+               [TRANSCODER_B] = PIPE_B_OFFSET, \
+               [TRANSCODER_C] = PIPE_C_OFFSET, \
+               [TRANSCODER_EDP] = PIPE_EDP_OFFSET, \
+       }, \
+       .trans_offsets = { \
+               [TRANSCODER_A] = TRANSCODER_A_OFFSET, \
+               [TRANSCODER_B] = TRANSCODER_B_OFFSET, \
+               [TRANSCODER_C] = TRANSCODER_C_OFFSET, \
+               [TRANSCODER_EDP] = TRANSCODER_EDP_OFFSET, \
+       }
 
 #define GEN_CHV_PIPEOFFSETS \
-       .pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
-                         CHV_PIPE_C_OFFSET }, \
-       .trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \
-                          CHV_TRANSCODER_C_OFFSET, }, \
-       .palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET, \
-                            CHV_PALETTE_C_OFFSET }
+       .pipe_offsets = { \
+               [TRANSCODER_A] = PIPE_A_OFFSET, \
+               [TRANSCODER_B] = PIPE_B_OFFSET, \
+               [TRANSCODER_C] = CHV_PIPE_C_OFFSET, \
+       }, \
+       .trans_offsets = { \
+               [TRANSCODER_A] = TRANSCODER_A_OFFSET, \
+               [TRANSCODER_B] = TRANSCODER_B_OFFSET, \
+               [TRANSCODER_C] = CHV_TRANSCODER_C_OFFSET, \
+       }
 
 #define CURSOR_OFFSETS \
        .cursor_offsets = { CURSOR_A_OFFSET, CURSOR_B_OFFSET, CHV_CURSOR_C_OFFSET }
@@ -68,8 +79,9 @@
 #define GEN2_FEATURES \
        GEN(2), \
        .num_pipes = 1, \
-       .has_overlay = 1, .overlay_needs_physical = 1, \
-       .has_gmch_display = 1, \
+       .display.has_overlay = 1, \
+       .display.overlay_needs_physical = 1, \
+       .display.has_gmch_display = 1, \
        .hws_needs_physical = 1, \
        .unfenced_needs_alignment = 1, \
        .ring_mask = RENDER_RING, \
@@ -82,7 +94,8 @@
 static const struct intel_device_info intel_i830_info = {
        GEN2_FEATURES,
        PLATFORM(INTEL_I830),
-       .is_mobile = 1, .cursor_needs_physical = 1,
+       .is_mobile = 1,
+       .display.cursor_needs_physical = 1,
        .num_pipes = 2, /* legal, last one wins */
 };
 
@@ -96,8 +109,8 @@ static const struct intel_device_info intel_i85x_info = {
        PLATFORM(INTEL_I85X),
        .is_mobile = 1,
        .num_pipes = 2, /* legal, last one wins */
-       .cursor_needs_physical = 1,
-       .has_fbc = 1,
+       .display.cursor_needs_physical = 1,
+       .display.has_fbc = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
@@ -108,7 +121,7 @@ static const struct intel_device_info intel_i865g_info = {
 #define GEN3_FEATURES \
        GEN(3), \
        .num_pipes = 2, \
-       .has_gmch_display = 1, \
+       .display.has_gmch_display = 1, \
        .ring_mask = RENDER_RING, \
        .has_snoop = true, \
        .has_coherent_ggtt = true, \
@@ -120,8 +133,9 @@ static const struct intel_device_info intel_i915g_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_I915G),
        .has_coherent_ggtt = false,
-       .cursor_needs_physical = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
+       .display.cursor_needs_physical = 1,
+       .display.has_overlay = 1,
+       .display.overlay_needs_physical = 1,
        .hws_needs_physical = 1,
        .unfenced_needs_alignment = 1,
 };
@@ -130,10 +144,11 @@ static const struct intel_device_info intel_i915gm_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_I915GM),
        .is_mobile = 1,
-       .cursor_needs_physical = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
-       .supports_tv = 1,
-       .has_fbc = 1,
+       .display.cursor_needs_physical = 1,
+       .display.has_overlay = 1,
+       .display.overlay_needs_physical = 1,
+       .display.supports_tv = 1,
+       .display.has_fbc = 1,
        .hws_needs_physical = 1,
        .unfenced_needs_alignment = 1,
 };
@@ -141,8 +156,10 @@ static const struct intel_device_info intel_i915gm_info = {
 static const struct intel_device_info intel_i945g_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_I945G),
-       .has_hotplug = 1, .cursor_needs_physical = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
+       .display.has_hotplug = 1,
+       .display.cursor_needs_physical = 1,
+       .display.has_overlay = 1,
+       .display.overlay_needs_physical = 1,
        .hws_needs_physical = 1,
        .unfenced_needs_alignment = 1,
 };
@@ -151,10 +168,12 @@ static const struct intel_device_info intel_i945gm_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_I945GM),
        .is_mobile = 1,
-       .has_hotplug = 1, .cursor_needs_physical = 1,
-       .has_overlay = 1, .overlay_needs_physical = 1,
-       .supports_tv = 1,
-       .has_fbc = 1,
+       .display.has_hotplug = 1,
+       .display.cursor_needs_physical = 1,
+       .display.has_overlay = 1,
+       .display.overlay_needs_physical = 1,
+       .display.supports_tv = 1,
+       .display.has_fbc = 1,
        .hws_needs_physical = 1,
        .unfenced_needs_alignment = 1,
 };
@@ -162,23 +181,23 @@ static const struct intel_device_info intel_i945gm_info = {
 static const struct intel_device_info intel_g33_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_G33),
-       .has_hotplug = 1,
-       .has_overlay = 1,
+       .display.has_hotplug = 1,
+       .display.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
        GEN3_FEATURES,
        PLATFORM(INTEL_PINEVIEW),
        .is_mobile = 1,
-       .has_hotplug = 1,
-       .has_overlay = 1,
+       .display.has_hotplug = 1,
+       .display.has_overlay = 1,
 };
 
 #define GEN4_FEATURES \
        GEN(4), \
        .num_pipes = 2, \
-       .has_hotplug = 1, \
-       .has_gmch_display = 1, \
+       .display.has_hotplug = 1, \
+       .display.has_gmch_display = 1, \
        .ring_mask = RENDER_RING, \
        .has_snoop = true, \
        .has_coherent_ggtt = true, \
@@ -189,7 +208,7 @@ static const struct intel_device_info intel_pineview_info = {
 static const struct intel_device_info intel_i965g_info = {
        GEN4_FEATURES,
        PLATFORM(INTEL_I965G),
-       .has_overlay = 1,
+       .display.has_overlay = 1,
        .hws_needs_physical = 1,
        .has_snoop = false,
 };
@@ -197,9 +216,10 @@ static const struct intel_device_info intel_i965g_info = {
 static const struct intel_device_info intel_i965gm_info = {
        GEN4_FEATURES,
        PLATFORM(INTEL_I965GM),
-       .is_mobile = 1, .has_fbc = 1,
-       .has_overlay = 1,
-       .supports_tv = 1,
+       .is_mobile = 1,
+       .display.has_fbc = 1,
+       .display.has_overlay = 1,
+       .display.supports_tv = 1,
        .hws_needs_physical = 1,
        .has_snoop = false,
 };
@@ -213,15 +233,16 @@ static const struct intel_device_info intel_g45_info = {
 static const struct intel_device_info intel_gm45_info = {
        GEN4_FEATURES,
        PLATFORM(INTEL_GM45),
-       .is_mobile = 1, .has_fbc = 1,
-       .supports_tv = 1,
+       .is_mobile = 1,
+       .display.has_fbc = 1,
+       .display.supports_tv = 1,
        .ring_mask = RENDER_RING | BSD_RING,
 };
 
 #define GEN5_FEATURES \
        GEN(5), \
        .num_pipes = 2, \
-       .has_hotplug = 1, \
+       .display.has_hotplug = 1, \
        .ring_mask = RENDER_RING | BSD_RING, \
        .has_snoop = true, \
        .has_coherent_ggtt = true, \
@@ -239,20 +260,21 @@ static const struct intel_device_info intel_ironlake_d_info = {
 static const struct intel_device_info intel_ironlake_m_info = {
        GEN5_FEATURES,
        PLATFORM(INTEL_IRONLAKE),
-       .is_mobile = 1, .has_fbc = 1,
+       .is_mobile = 1,
+       .display.has_fbc = 1,
 };
 
 #define GEN6_FEATURES \
        GEN(6), \
        .num_pipes = 2, \
-       .has_hotplug = 1, \
-       .has_fbc = 1, \
+       .display.has_hotplug = 1, \
+       .display.has_fbc = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
        .has_coherent_ggtt = true, \
        .has_llc = 1, \
        .has_rc6 = 1, \
        .has_rc6p = 1, \
-       .has_aliasing_ppgtt = 1, \
+       .ppgtt = INTEL_PPGTT_ALIASING, \
        GEN_DEFAULT_PIPEOFFSETS, \
        GEN_DEFAULT_PAGE_SIZES, \
        CURSOR_OFFSETS
@@ -290,15 +312,14 @@ static const struct intel_device_info intel_sandybridge_m_gt2_info = {
 #define GEN7_FEATURES  \
        GEN(7), \
        .num_pipes = 3, \
-       .has_hotplug = 1, \
-       .has_fbc = 1, \
+       .display.has_hotplug = 1, \
+       .display.has_fbc = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
        .has_coherent_ggtt = true, \
        .has_llc = 1, \
        .has_rc6 = 1, \
        .has_rc6p = 1, \
-       .has_aliasing_ppgtt = 1, \
-       .has_full_ppgtt = 1, \
+       .ppgtt = INTEL_PPGTT_FULL, \
        GEN_DEFAULT_PIPEOFFSETS, \
        GEN_DEFAULT_PAGE_SIZES, \
        IVB_CURSOR_OFFSETS
@@ -349,10 +370,9 @@ static const struct intel_device_info intel_valleyview_info = {
        .num_pipes = 2,
        .has_runtime_pm = 1,
        .has_rc6 = 1,
-       .has_gmch_display = 1,
-       .has_hotplug = 1,
-       .has_aliasing_ppgtt = 1,
-       .has_full_ppgtt = 1,
+       .display.has_gmch_display = 1,
+       .display.has_hotplug = 1,
+       .ppgtt = INTEL_PPGTT_FULL,
        .has_snoop = true,
        .has_coherent_ggtt = false,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
@@ -365,10 +385,10 @@ static const struct intel_device_info intel_valleyview_info = {
 #define G75_FEATURES  \
        GEN7_FEATURES, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
-       .has_ddi = 1, \
+       .display.has_ddi = 1, \
        .has_fpga_dbg = 1, \
-       .has_psr = 1, \
-       .has_dp_mst = 1, \
+       .display.has_psr = 1, \
+       .display.has_dp_mst = 1, \
        .has_rc6p = 0 /* RC6p removed-by HSW */, \
        .has_runtime_pm = 1
 
@@ -399,7 +419,7 @@ static const struct intel_device_info intel_haswell_gt3_info = {
        .page_sizes = I915_GTT_PAGE_SIZE_4K | \
                      I915_GTT_PAGE_SIZE_2M, \
        .has_logical_ring_contexts = 1, \
-       .has_full_48bit_ppgtt = 1, \
+       .ppgtt = INTEL_PPGTT_FULL_4LVL, \
        .has_64bit_reloc = 1, \
        .has_reset_engine = 1
 
@@ -435,16 +455,15 @@ static const struct intel_device_info intel_cherryview_info = {
        PLATFORM(INTEL_CHERRYVIEW),
        GEN(8),
        .num_pipes = 3,
-       .has_hotplug = 1,
+       .display.has_hotplug = 1,
        .is_lp = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
        .has_64bit_reloc = 1,
        .has_runtime_pm = 1,
        .has_rc6 = 1,
        .has_logical_ring_contexts = 1,
-       .has_gmch_display = 1,
-       .has_aliasing_ppgtt = 1,
-       .has_full_ppgtt = 1,
+       .display.has_gmch_display = 1,
+       .ppgtt = INTEL_PPGTT_FULL,
        .has_reset_engine = 1,
        .has_snoop = true,
        .has_coherent_ggtt = false,
@@ -465,13 +484,15 @@ static const struct intel_device_info intel_cherryview_info = {
        GEN(9), \
        GEN9_DEFAULT_PAGE_SIZES, \
        .has_logical_ring_preemption = 1, \
-       .has_csr = 1, \
+       .display.has_csr = 1, \
        .has_guc = 1, \
-       .has_ipc = 1, \
+       .display.has_ipc = 1, \
        .ddb_size = 896
 
 #define SKL_PLATFORM \
        GEN9_FEATURES, \
+       /* Display WA #0477 WaDisableIPC: skl */ \
+       .display.has_ipc = 0, \
        PLATFORM(INTEL_SKYLAKE)
 
 static const struct intel_device_info intel_skylake_gt1_info = {
@@ -502,29 +523,27 @@ static const struct intel_device_info intel_skylake_gt4_info = {
 #define GEN9_LP_FEATURES \
        GEN(9), \
        .is_lp = 1, \
-       .has_hotplug = 1, \
+       .display.has_hotplug = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
        .num_pipes = 3, \
        .has_64bit_reloc = 1, \
-       .has_ddi = 1, \
+       .display.has_ddi = 1, \
        .has_fpga_dbg = 1, \
-       .has_fbc = 1, \
-       .has_psr = 1, \
+       .display.has_fbc = 1, \
+       .display.has_psr = 1, \
        .has_runtime_pm = 1, \
        .has_pooled_eu = 0, \
-       .has_csr = 1, \
+       .display.has_csr = 1, \
        .has_rc6 = 1, \
-       .has_dp_mst = 1, \
+       .display.has_dp_mst = 1, \
        .has_logical_ring_contexts = 1, \
        .has_logical_ring_preemption = 1, \
        .has_guc = 1, \
-       .has_aliasing_ppgtt = 1, \
-       .has_full_ppgtt = 1, \
-       .has_full_48bit_ppgtt = 1, \
+       .ppgtt = INTEL_PPGTT_FULL_4LVL, \
        .has_reset_engine = 1, \
        .has_snoop = true, \
        .has_coherent_ggtt = false, \
-       .has_ipc = 1, \
+       .display.has_ipc = 1, \
        GEN9_DEFAULT_PAGE_SIZES, \
        GEN_DEFAULT_PIPEOFFSETS, \
        IVB_CURSOR_OFFSETS, \
@@ -598,6 +617,22 @@ static const struct intel_device_info intel_cannonlake_info = {
 
 #define GEN11_FEATURES \
        GEN10_FEATURES, \
+       .pipe_offsets = { \
+               [TRANSCODER_A] = PIPE_A_OFFSET, \
+               [TRANSCODER_B] = PIPE_B_OFFSET, \
+               [TRANSCODER_C] = PIPE_C_OFFSET, \
+               [TRANSCODER_EDP] = PIPE_EDP_OFFSET, \
+               [TRANSCODER_DSI_0] = PIPE_DSI0_OFFSET, \
+               [TRANSCODER_DSI_1] = PIPE_DSI1_OFFSET, \
+       }, \
+       .trans_offsets = { \
+               [TRANSCODER_A] = TRANSCODER_A_OFFSET, \
+               [TRANSCODER_B] = TRANSCODER_B_OFFSET, \
+               [TRANSCODER_C] = TRANSCODER_C_OFFSET, \
+               [TRANSCODER_EDP] = TRANSCODER_EDP_OFFSET, \
+               [TRANSCODER_DSI_0] = TRANSCODER_DSI0_OFFSET, \
+               [TRANSCODER_DSI_1] = TRANSCODER_DSI1_OFFSET, \
+       }, \
        GEN(11), \
        .ddb_size = 2048, \
        .has_logical_ring_elsq = 1
@@ -663,7 +698,7 @@ static const struct pci_device_id pciidlist[] = {
        INTEL_KBL_GT2_IDS(&intel_kabylake_gt2_info),
        INTEL_KBL_GT3_IDS(&intel_kabylake_gt3_info),
        INTEL_KBL_GT4_IDS(&intel_kabylake_gt3_info),
-       INTEL_AML_GT2_IDS(&intel_kabylake_gt2_info),
+       INTEL_AML_KBL_GT2_IDS(&intel_kabylake_gt2_info),
        INTEL_CFL_S_GT1_IDS(&intel_coffeelake_gt1_info),
        INTEL_CFL_S_GT2_IDS(&intel_coffeelake_gt2_info),
        INTEL_CFL_H_GT2_IDS(&intel_coffeelake_gt2_info),
@@ -671,6 +706,7 @@ static const struct pci_device_id pciidlist[] = {
        INTEL_CFL_U_GT3_IDS(&intel_coffeelake_gt3_info),
        INTEL_WHL_U_GT1_IDS(&intel_coffeelake_gt1_info),
        INTEL_WHL_U_GT2_IDS(&intel_coffeelake_gt2_info),
+       INTEL_AML_CFL_GT2_IDS(&intel_coffeelake_gt2_info),
        INTEL_WHL_U_GT3_IDS(&intel_coffeelake_gt3_info),
        INTEL_CNL_IDS(&intel_cannonlake_info),
        INTEL_ICL_11_IDS(&intel_icelake_11_info),
index 664b96bb65a38d08ac99b2e16dc350c1f511fd47..4529edfdcfc80580ea66b306713a42250e1f2626 100644 (file)
@@ -890,8 +890,8 @@ static int gen8_oa_read(struct i915_perf_stream *stream,
                DRM_DEBUG("OA buffer overflow (exponent = %d): force restart\n",
                          dev_priv->perf.oa.period_exponent);
 
-               dev_priv->perf.oa.ops.oa_disable(dev_priv);
-               dev_priv->perf.oa.ops.oa_enable(dev_priv);
+               dev_priv->perf.oa.ops.oa_disable(stream);
+               dev_priv->perf.oa.ops.oa_enable(stream);
 
                /*
                 * Note: .oa_enable() is expected to re-init the oabuffer and
@@ -1114,8 +1114,8 @@ static int gen7_oa_read(struct i915_perf_stream *stream,
                DRM_DEBUG("OA buffer overflow (exponent = %d): force restart\n",
                          dev_priv->perf.oa.period_exponent);
 
-               dev_priv->perf.oa.ops.oa_disable(dev_priv);
-               dev_priv->perf.oa.ops.oa_enable(dev_priv);
+               dev_priv->perf.oa.ops.oa_disable(stream);
+               dev_priv->perf.oa.ops.oa_enable(stream);
 
                oastatus1 = I915_READ(GEN7_OASTATUS1);
        }
@@ -1528,8 +1528,6 @@ static int alloc_oa_buffer(struct drm_i915_private *dev_priv)
                goto err_unpin;
        }
 
-       dev_priv->perf.oa.ops.init_oa_buffer(dev_priv);
-
        DRM_DEBUG_DRIVER("OA Buffer initialized, gtt offset = 0x%x, vaddr = %p\n",
                         i915_ggtt_offset(dev_priv->perf.oa.oa_buffer.vma),
                         dev_priv->perf.oa.oa_buffer.vaddr);
@@ -1563,9 +1561,11 @@ static void config_oa_regs(struct drm_i915_private *dev_priv,
        }
 }
 
-static int hsw_enable_metric_set(struct drm_i915_private *dev_priv,
-                                const struct i915_oa_config *oa_config)
+static int hsw_enable_metric_set(struct i915_perf_stream *stream)
 {
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       const struct i915_oa_config *oa_config = stream->oa_config;
+
        /* PRM:
         *
         * OA unit is using “crclk” for its functionality. When trunk
@@ -1767,9 +1767,10 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
        return 0;
 }
 
-static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
-                                 const struct i915_oa_config *oa_config)
+static int gen8_enable_metric_set(struct i915_perf_stream *stream)
 {
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       const struct i915_oa_config *oa_config = stream->oa_config;
        int ret;
 
        /*
@@ -1837,10 +1838,10 @@ static void gen10_disable_metric_set(struct drm_i915_private *dev_priv)
                   I915_READ(RPM_CONFIG1) & ~GEN10_GT_NOA_ENABLE);
 }
 
-static void gen7_oa_enable(struct drm_i915_private *dev_priv)
+static void gen7_oa_enable(struct i915_perf_stream *stream)
 {
-       struct i915_gem_context *ctx =
-                       dev_priv->perf.oa.exclusive_stream->ctx;
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       struct i915_gem_context *ctx = stream->ctx;
        u32 ctx_id = dev_priv->perf.oa.specific_ctx_id;
        bool periodic = dev_priv->perf.oa.periodic;
        u32 period_exponent = dev_priv->perf.oa.period_exponent;
@@ -1867,8 +1868,9 @@ static void gen7_oa_enable(struct drm_i915_private *dev_priv)
                   GEN7_OACONTROL_ENABLE);
 }
 
-static void gen8_oa_enable(struct drm_i915_private *dev_priv)
+static void gen8_oa_enable(struct i915_perf_stream *stream)
 {
+       struct drm_i915_private *dev_priv = stream->dev_priv;
        u32 report_format = dev_priv->perf.oa.oa_buffer.format;
 
        /*
@@ -1905,7 +1907,7 @@ static void i915_oa_stream_enable(struct i915_perf_stream *stream)
 {
        struct drm_i915_private *dev_priv = stream->dev_priv;
 
-       dev_priv->perf.oa.ops.oa_enable(dev_priv);
+       dev_priv->perf.oa.ops.oa_enable(stream);
 
        if (dev_priv->perf.oa.periodic)
                hrtimer_start(&dev_priv->perf.oa.poll_check_timer,
@@ -1913,8 +1915,10 @@ static void i915_oa_stream_enable(struct i915_perf_stream *stream)
                              HRTIMER_MODE_REL_PINNED);
 }
 
-static void gen7_oa_disable(struct drm_i915_private *dev_priv)
+static void gen7_oa_disable(struct i915_perf_stream *stream)
 {
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+
        I915_WRITE(GEN7_OACONTROL, 0);
        if (intel_wait_for_register(dev_priv,
                                    GEN7_OACONTROL, GEN7_OACONTROL_ENABLE, 0,
@@ -1922,8 +1926,10 @@ static void gen7_oa_disable(struct drm_i915_private *dev_priv)
                DRM_ERROR("wait for OA to be disabled timed out\n");
 }
 
-static void gen8_oa_disable(struct drm_i915_private *dev_priv)
+static void gen8_oa_disable(struct i915_perf_stream *stream)
 {
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+
        I915_WRITE(GEN8_OACONTROL, 0);
        if (intel_wait_for_register(dev_priv,
                                    GEN8_OACONTROL, GEN8_OA_COUNTER_ENABLE, 0,
@@ -1943,7 +1949,7 @@ static void i915_oa_stream_disable(struct i915_perf_stream *stream)
 {
        struct drm_i915_private *dev_priv = stream->dev_priv;
 
-       dev_priv->perf.oa.ops.oa_disable(dev_priv);
+       dev_priv->perf.oa.ops.oa_disable(stream);
 
        if (dev_priv->perf.oa.periodic)
                hrtimer_cancel(&dev_priv->perf.oa.poll_check_timer);
@@ -1998,7 +2004,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
                return -EINVAL;
        }
 
-       if (!dev_priv->perf.oa.ops.init_oa_buffer) {
+       if (!dev_priv->perf.oa.ops.enable_metric_set) {
                DRM_DEBUG("OA unit not supported\n");
                return -ENODEV;
        }
@@ -2092,8 +2098,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        if (ret)
                goto err_lock;
 
-       ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv,
-                                                     stream->oa_config);
+       ret = dev_priv->perf.oa.ops.enable_metric_set(stream);
        if (ret) {
                DRM_DEBUG("Unable to enable metric set\n");
                goto err_enable;
@@ -3387,7 +3392,6 @@ void i915_perf_init(struct drm_i915_private *dev_priv)
                dev_priv->perf.oa.ops.is_valid_mux_reg =
                        hsw_is_valid_mux_addr;
                dev_priv->perf.oa.ops.is_valid_flex_reg = NULL;
-               dev_priv->perf.oa.ops.init_oa_buffer = gen7_init_oa_buffer;
                dev_priv->perf.oa.ops.enable_metric_set = hsw_enable_metric_set;
                dev_priv->perf.oa.ops.disable_metric_set = hsw_disable_metric_set;
                dev_priv->perf.oa.ops.oa_enable = gen7_oa_enable;
@@ -3406,7 +3410,6 @@ void i915_perf_init(struct drm_i915_private *dev_priv)
                 */
                dev_priv->perf.oa.oa_formats = gen8_plus_oa_formats;
 
-               dev_priv->perf.oa.ops.init_oa_buffer = gen8_init_oa_buffer;
                dev_priv->perf.oa.ops.oa_enable = gen8_oa_enable;
                dev_priv->perf.oa.ops.oa_disable = gen8_oa_disable;
                dev_priv->perf.oa.ops.read = gen8_oa_read;
index 3f502eef243166612321dd7cc219374f1daae43b..6fc4b8eeab428f7b10bf56ba5c07eba5789b59a7 100644 (file)
@@ -27,8 +27,7 @@ static int query_topology_info(struct drm_i915_private *dev_priv,
 
        slice_length = sizeof(sseu->slice_mask);
        subslice_length = sseu->max_slices *
-               DIV_ROUND_UP(sseu->max_subslices,
-                            sizeof(sseu->subslice_mask[0]) * BITS_PER_BYTE);
+               DIV_ROUND_UP(sseu->max_subslices, BITS_PER_BYTE);
        eu_length = sseu->max_slices * sseu->max_subslices *
                DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE);
 
index e31c27e45734ef19ae3764b5894da3320f4b2991..0a7d60509ca7527f018a12208316bff91c7c6be8 100644 (file)
@@ -157,20 +157,37 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 /*
  * Named helper wrappers around _PICK_EVEN() and _PICK().
  */
-#define _PIPE(pipe, a, b) _PICK_EVEN(pipe, a, b)
-#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
-#define _PLANE(plane, a, b) _PICK_EVEN(plane, a, b)
-#define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b)
-#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b)
-#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
-#define _PORT(port, a, b) _PICK_EVEN(port, a, b)
-#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
-#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
-#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
-#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b)
-#define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b))
-#define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__)
-#define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
+#define _PIPE(pipe, a, b)              _PICK_EVEN(pipe, a, b)
+#define _PLANE(plane, a, b)            _PICK_EVEN(plane, a, b)
+#define _TRANS(tran, a, b)             _PICK_EVEN(tran, a, b)
+#define _PORT(port, a, b)              _PICK_EVEN(port, a, b)
+#define _PLL(pll, a, b)                        _PICK_EVEN(pll, a, b)
+
+#define _MMIO_PIPE(pipe, a, b)         _MMIO(_PIPE(pipe, a, b))
+#define _MMIO_PLANE(plane, a, b)       _MMIO(_PLANE(plane, a, b))
+#define _MMIO_TRANS(tran, a, b)                _MMIO(_TRANS(tran, a, b))
+#define _MMIO_PORT(port, a, b)         _MMIO(_PORT(port, a, b))
+#define _MMIO_PLL(pll, a, b)           _MMIO(_PLL(pll, a, b))
+
+#define _PHY3(phy, ...)                        _PICK(phy, __VA_ARGS__)
+
+#define _MMIO_PIPE3(pipe, a, b, c)     _MMIO(_PICK(pipe, a, b, c))
+#define _MMIO_PORT3(pipe, a, b, c)     _MMIO(_PICK(pipe, a, b, c))
+#define _MMIO_PHY3(phy, a, b, c)       _MMIO(_PHY3(phy, a, b, c))
+
+/*
+ * Device info offset array based helpers for groups of registers with unevenly
+ * spaced base offsets.
+ */
+#define _MMIO_PIPE2(pipe, reg)         _MMIO(dev_priv->info.pipe_offsets[pipe] - \
+                                             dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \
+                                             dev_priv->info.display_mmio_offset)
+#define _MMIO_TRANS2(pipe, reg)                _MMIO(dev_priv->info.trans_offsets[(pipe)] - \
+                                             dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \
+                                             dev_priv->info.display_mmio_offset)
+#define _CURSOR2(pipe, reg)            _MMIO(dev_priv->info.cursor_offsets[(pipe)] - \
+                                             dev_priv->info.cursor_offsets[PIPE_A] + (reg) + \
+                                             dev_priv->info.display_mmio_offset)
 
 #define __MASKED_FIELD(mask, value) ((mask) << 16 | (value))
 #define _MASKED_FIELD(mask, value) ({                                     \
@@ -1631,35 +1648,6 @@ enum i915_power_well_id {
 #define   PHY_RESERVED                 (1 << 7)
 #define BXT_PORT_CL1CM_DW0(phy)                _BXT_PHY((phy), _PORT_CL1CM_DW0_BC)
 
-#define CNL_PORT_CL1CM_DW5             _MMIO(0x162014)
-#define   CL_POWER_DOWN_ENABLE         (1 << 4)
-#define   SUS_CLOCK_CONFIG             (3 << 0)
-
-#define _ICL_PORT_CL_DW5_A     0x162014
-#define _ICL_PORT_CL_DW5_B     0x6C014
-#define ICL_PORT_CL_DW5(port)  _MMIO_PORT(port, _ICL_PORT_CL_DW5_A, \
-                                                _ICL_PORT_CL_DW5_B)
-
-#define _CNL_PORT_CL_DW10_A            0x162028
-#define _ICL_PORT_CL_DW10_B            0x6c028
-#define ICL_PORT_CL_DW10(port)         _MMIO_PORT(port,        \
-                                                  _CNL_PORT_CL_DW10_A, \
-                                                  _ICL_PORT_CL_DW10_B)
-#define  PG_SEQ_DELAY_OVERRIDE_MASK    (3 << 25)
-#define  PG_SEQ_DELAY_OVERRIDE_SHIFT   25
-#define  PG_SEQ_DELAY_OVERRIDE_ENABLE  (1 << 24)
-#define  PWR_UP_ALL_LANES              (0x0 << 4)
-#define  PWR_DOWN_LN_3_2_1             (0xe << 4)
-#define  PWR_DOWN_LN_3_2               (0xc << 4)
-#define  PWR_DOWN_LN_3                 (0x8 << 4)
-#define  PWR_DOWN_LN_2_1_0             (0x7 << 4)
-#define  PWR_DOWN_LN_1_0               (0x3 << 4)
-#define  PWR_DOWN_LN_1                 (0x2 << 4)
-#define  PWR_DOWN_LN_3_1               (0xa << 4)
-#define  PWR_DOWN_LN_3_1_0             (0xb << 4)
-#define  PWR_DOWN_LN_MASK              (0xf << 4)
-#define  PWR_DOWN_LN_SHIFT             4
-
 #define _PORT_CL1CM_DW9_A              0x162024
 #define _PORT_CL1CM_DW9_BC             0x6C024
 #define   IREF0RC_OFFSET_SHIFT         8
@@ -1672,13 +1660,6 @@ enum i915_power_well_id {
 #define   IREF1RC_OFFSET_MASK          (0xFF << IREF1RC_OFFSET_SHIFT)
 #define BXT_PORT_CL1CM_DW10(phy)       _BXT_PHY((phy), _PORT_CL1CM_DW10_BC)
 
-#define _ICL_PORT_CL_DW12_A            0x162030
-#define _ICL_PORT_CL_DW12_B            0x6C030
-#define   ICL_LANE_ENABLE_AUX          (1 << 0)
-#define ICL_PORT_CL_DW12(port)         _MMIO_PORT((port),              \
-                                                  _ICL_PORT_CL_DW12_A, \
-                                                  _ICL_PORT_CL_DW12_B)
-
 #define _PORT_CL1CM_DW28_A             0x162070
 #define _PORT_CL1CM_DW28_BC            0x6C070
 #define   OCL1_POWER_DOWN_EN           (1 << 23)
@@ -1691,6 +1672,74 @@ enum i915_power_well_id {
 #define   OCL2_LDOFUSE_PWR_DIS         (1 << 6)
 #define BXT_PORT_CL1CM_DW30(phy)       _BXT_PHY((phy), _PORT_CL1CM_DW30_BC)
 
+/*
+ * CNL/ICL Port/COMBO-PHY Registers
+ */
+#define _ICL_COMBOPHY_A                        0x162000
+#define _ICL_COMBOPHY_B                        0x6C000
+#define _ICL_COMBOPHY(port)            _PICK(port, _ICL_COMBOPHY_A, \
+                                             _ICL_COMBOPHY_B)
+
+/* CNL/ICL Port CL_DW registers */
+#define _ICL_PORT_CL_DW(dw, port)      (_ICL_COMBOPHY(port) + \
+                                        4 * (dw))
+
+#define CNL_PORT_CL1CM_DW5             _MMIO(0x162014)
+#define ICL_PORT_CL_DW5(port)          _MMIO(_ICL_PORT_CL_DW(5, port))
+#define   CL_POWER_DOWN_ENABLE         (1 << 4)
+#define   SUS_CLOCK_CONFIG             (3 << 0)
+
+#define ICL_PORT_CL_DW10(port)         _MMIO(_ICL_PORT_CL_DW(10, port))
+#define  PG_SEQ_DELAY_OVERRIDE_MASK    (3 << 25)
+#define  PG_SEQ_DELAY_OVERRIDE_SHIFT   25
+#define  PG_SEQ_DELAY_OVERRIDE_ENABLE  (1 << 24)
+#define  PWR_UP_ALL_LANES              (0x0 << 4)
+#define  PWR_DOWN_LN_3_2_1             (0xe << 4)
+#define  PWR_DOWN_LN_3_2               (0xc << 4)
+#define  PWR_DOWN_LN_3                 (0x8 << 4)
+#define  PWR_DOWN_LN_2_1_0             (0x7 << 4)
+#define  PWR_DOWN_LN_1_0               (0x3 << 4)
+#define  PWR_DOWN_LN_1                 (0x2 << 4)
+#define  PWR_DOWN_LN_3_1               (0xa << 4)
+#define  PWR_DOWN_LN_3_1_0             (0xb << 4)
+#define  PWR_DOWN_LN_MASK              (0xf << 4)
+#define  PWR_DOWN_LN_SHIFT             4
+
+#define ICL_PORT_CL_DW12(port)         _MMIO(_ICL_PORT_CL_DW(12, port))
+#define   ICL_LANE_ENABLE_AUX          (1 << 0)
+
+/* CNL/ICL Port COMP_DW registers */
+#define _ICL_PORT_COMP                 0x100
+#define _ICL_PORT_COMP_DW(dw, port)    (_ICL_COMBOPHY(port) + \
+                                        _ICL_PORT_COMP + 4 * (dw))
+
+#define CNL_PORT_COMP_DW0              _MMIO(0x162100)
+#define ICL_PORT_COMP_DW0(port)                _MMIO(_ICL_PORT_COMP_DW(0, port))
+#define   COMP_INIT                    (1 << 31)
+
+#define CNL_PORT_COMP_DW1              _MMIO(0x162104)
+#define ICL_PORT_COMP_DW1(port)                _MMIO(_ICL_PORT_COMP_DW(1, port))
+
+#define CNL_PORT_COMP_DW3              _MMIO(0x16210c)
+#define ICL_PORT_COMP_DW3(port)                _MMIO(_ICL_PORT_COMP_DW(3, port))
+#define   PROCESS_INFO_DOT_0           (0 << 26)
+#define   PROCESS_INFO_DOT_1           (1 << 26)
+#define   PROCESS_INFO_DOT_4           (2 << 26)
+#define   PROCESS_INFO_MASK            (7 << 26)
+#define   PROCESS_INFO_SHIFT           26
+#define   VOLTAGE_INFO_0_85V           (0 << 24)
+#define   VOLTAGE_INFO_0_95V           (1 << 24)
+#define   VOLTAGE_INFO_1_05V           (2 << 24)
+#define   VOLTAGE_INFO_MASK            (3 << 24)
+#define   VOLTAGE_INFO_SHIFT           24
+
+#define CNL_PORT_COMP_DW9              _MMIO(0x162124)
+#define ICL_PORT_COMP_DW9(port)                _MMIO(_ICL_PORT_COMP_DW(9, port))
+
+#define CNL_PORT_COMP_DW10             _MMIO(0x162128)
+#define ICL_PORT_COMP_DW10(port)       _MMIO(_ICL_PORT_COMP_DW(10, port))
+
+/* CNL/ICL Port PCS registers */
 #define _CNL_PORT_PCS_DW1_GRP_AE       0x162304
 #define _CNL_PORT_PCS_DW1_GRP_B                0x162384
 #define _CNL_PORT_PCS_DW1_GRP_C                0x162B04
@@ -1708,7 +1757,6 @@ enum i915_power_well_id {
                                                    _CNL_PORT_PCS_DW1_GRP_D, \
                                                    _CNL_PORT_PCS_DW1_GRP_AE, \
                                                    _CNL_PORT_PCS_DW1_GRP_F))
-
 #define CNL_PORT_PCS_DW1_LN0(port)     _MMIO(_PICK(port, \
                                                    _CNL_PORT_PCS_DW1_LN0_AE, \
                                                    _CNL_PORT_PCS_DW1_LN0_B, \
@@ -1717,24 +1765,21 @@ enum i915_power_well_id {
                                                    _CNL_PORT_PCS_DW1_LN0_AE, \
                                                    _CNL_PORT_PCS_DW1_LN0_F))
 
-#define _ICL_PORT_PCS_DW1_GRP_A                0x162604
-#define _ICL_PORT_PCS_DW1_GRP_B                0x6C604
-#define _ICL_PORT_PCS_DW1_LN0_A                0x162804
-#define _ICL_PORT_PCS_DW1_LN0_B                0x6C804
-#define _ICL_PORT_PCS_DW1_AUX_A                0x162304
-#define _ICL_PORT_PCS_DW1_AUX_B                0x6c304
-#define ICL_PORT_PCS_DW1_GRP(port)     _MMIO_PORT(port,\
-                                                  _ICL_PORT_PCS_DW1_GRP_A, \
-                                                  _ICL_PORT_PCS_DW1_GRP_B)
-#define ICL_PORT_PCS_DW1_LN0(port)     _MMIO_PORT(port, \
-                                                  _ICL_PORT_PCS_DW1_LN0_A, \
-                                                  _ICL_PORT_PCS_DW1_LN0_B)
-#define ICL_PORT_PCS_DW1_AUX(port)     _MMIO_PORT(port, \
-                                                  _ICL_PORT_PCS_DW1_AUX_A, \
-                                                  _ICL_PORT_PCS_DW1_AUX_B)
+#define _ICL_PORT_PCS_AUX              0x300
+#define _ICL_PORT_PCS_GRP              0x600
+#define _ICL_PORT_PCS_LN(ln)           (0x800 + (ln) * 0x100)
+#define _ICL_PORT_PCS_DW_AUX(dw, port) (_ICL_COMBOPHY(port) + \
+                                        _ICL_PORT_PCS_AUX + 4 * (dw))
+#define _ICL_PORT_PCS_DW_GRP(dw, port) (_ICL_COMBOPHY(port) + \
+                                        _ICL_PORT_PCS_GRP + 4 * (dw))
+#define _ICL_PORT_PCS_DW_LN(dw, ln, port) (_ICL_COMBOPHY(port) + \
+                                         _ICL_PORT_PCS_LN(ln) + 4 * (dw))
+#define ICL_PORT_PCS_DW1_AUX(port)     _MMIO(_ICL_PORT_PCS_DW_AUX(1, port))
+#define ICL_PORT_PCS_DW1_GRP(port)     _MMIO(_ICL_PORT_PCS_DW_GRP(1, port))
+#define ICL_PORT_PCS_DW1_LN0(port)     _MMIO(_ICL_PORT_PCS_DW_LN(1, 0, port))
 #define   COMMON_KEEPER_EN             (1 << 26)
 
-/* CNL Port TX registers */
+/* CNL/ICL Port TX registers */
 #define _CNL_PORT_TX_AE_GRP_OFFSET             0x162340
 #define _CNL_PORT_TX_B_GRP_OFFSET              0x1623C0
 #define _CNL_PORT_TX_C_GRP_OFFSET              0x162B40
@@ -1762,23 +1807,22 @@ enum i915_power_well_id {
                                               _CNL_PORT_TX_F_LN0_OFFSET) + \
                                               4 * (dw))
 
-#define CNL_PORT_TX_DW2_GRP(port)      _MMIO(_CNL_PORT_TX_DW_GRP((port), 2))
-#define CNL_PORT_TX_DW2_LN0(port)      _MMIO(_CNL_PORT_TX_DW_LN0((port), 2))
-#define _ICL_PORT_TX_DW2_GRP_A         0x162688
-#define _ICL_PORT_TX_DW2_GRP_B         0x6C688
-#define _ICL_PORT_TX_DW2_LN0_A         0x162888
-#define _ICL_PORT_TX_DW2_LN0_B         0x6C888
-#define _ICL_PORT_TX_DW2_AUX_A         0x162388
-#define _ICL_PORT_TX_DW2_AUX_B         0x6c388
-#define ICL_PORT_TX_DW2_GRP(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW2_GRP_A, \
-                                                  _ICL_PORT_TX_DW2_GRP_B)
-#define ICL_PORT_TX_DW2_LN0(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW2_LN0_A, \
-                                                  _ICL_PORT_TX_DW2_LN0_B)
-#define ICL_PORT_TX_DW2_AUX(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW2_AUX_A, \
-                                                  _ICL_PORT_TX_DW2_AUX_B)
+#define _ICL_PORT_TX_AUX               0x380
+#define _ICL_PORT_TX_GRP               0x680
+#define _ICL_PORT_TX_LN(ln)            (0x880 + (ln) * 0x100)
+
+#define _ICL_PORT_TX_DW_AUX(dw, port)  (_ICL_COMBOPHY(port) + \
+                                        _ICL_PORT_TX_AUX + 4 * (dw))
+#define _ICL_PORT_TX_DW_GRP(dw, port)  (_ICL_COMBOPHY(port) + \
+                                        _ICL_PORT_TX_GRP + 4 * (dw))
+#define _ICL_PORT_TX_DW_LN(dw, ln, port) (_ICL_COMBOPHY(port) + \
+                                         _ICL_PORT_TX_LN(ln) + 4 * (dw))
+
+#define CNL_PORT_TX_DW2_GRP(port)      _MMIO(_CNL_PORT_TX_DW_GRP(2, port))
+#define CNL_PORT_TX_DW2_LN0(port)      _MMIO(_CNL_PORT_TX_DW_LN0(2, port))
+#define ICL_PORT_TX_DW2_AUX(port)      _MMIO(_ICL_PORT_TX_DW_AUX(2, port))
+#define ICL_PORT_TX_DW2_GRP(port)      _MMIO(_ICL_PORT_TX_DW_GRP(2, port))
+#define ICL_PORT_TX_DW2_LN0(port)      _MMIO(_ICL_PORT_TX_DW_LN(2, 0, port))
 #define   SWING_SEL_UPPER(x)           (((x) >> 3) << 15)
 #define   SWING_SEL_UPPER_MASK         (1 << 15)
 #define   SWING_SEL_LOWER(x)           (((x) & 0x7) << 11)
@@ -1795,24 +1839,10 @@ enum i915_power_well_id {
 #define CNL_PORT_TX_DW4_LN(port, ln)   _MMIO(_CNL_PORT_TX_DW_LN0((port), 4) + \
                                           ((ln) * (_CNL_PORT_TX_DW4_LN1_AE - \
                                                    _CNL_PORT_TX_DW4_LN0_AE)))
-#define _ICL_PORT_TX_DW4_GRP_A         0x162690
-#define _ICL_PORT_TX_DW4_GRP_B         0x6C690
-#define _ICL_PORT_TX_DW4_LN0_A         0x162890
-#define _ICL_PORT_TX_DW4_LN1_A         0x162990
-#define _ICL_PORT_TX_DW4_LN0_B         0x6C890
-#define _ICL_PORT_TX_DW4_AUX_A         0x162390
-#define _ICL_PORT_TX_DW4_AUX_B         0x6c390
-#define ICL_PORT_TX_DW4_GRP(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW4_GRP_A, \
-                                                  _ICL_PORT_TX_DW4_GRP_B)
-#define ICL_PORT_TX_DW4_LN(port, ln)   _MMIO(_PORT(port, \
-                                                  _ICL_PORT_TX_DW4_LN0_A, \
-                                                  _ICL_PORT_TX_DW4_LN0_B) + \
-                                            ((ln) * (_ICL_PORT_TX_DW4_LN1_A - \
-                                                     _ICL_PORT_TX_DW4_LN0_A)))
-#define ICL_PORT_TX_DW4_AUX(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW4_AUX_A, \
-                                                  _ICL_PORT_TX_DW4_AUX_B)
+#define ICL_PORT_TX_DW4_AUX(port)      _MMIO(_ICL_PORT_TX_DW_AUX(4, port))
+#define ICL_PORT_TX_DW4_GRP(port)      _MMIO(_ICL_PORT_TX_DW_GRP(4, port))
+#define ICL_PORT_TX_DW4_LN0(port)      _MMIO(_ICL_PORT_TX_DW_LN(4, 0, port))
+#define ICL_PORT_TX_DW4_LN(port, ln)   _MMIO(_ICL_PORT_TX_DW_LN(4, ln, port))
 #define   LOADGEN_SELECT               (1 << 31)
 #define   POST_CURSOR_1(x)             ((x) << 12)
 #define   POST_CURSOR_1_MASK           (0x3F << 12)
@@ -1821,23 +1851,11 @@ enum i915_power_well_id {
 #define   CURSOR_COEFF(x)              ((x) << 0)
 #define   CURSOR_COEFF_MASK            (0x3F << 0)
 
-#define CNL_PORT_TX_DW5_GRP(port)      _MMIO(_CNL_PORT_TX_DW_GRP((port), 5))
-#define CNL_PORT_TX_DW5_LN0(port)      _MMIO(_CNL_PORT_TX_DW_LN0((port), 5))
-#define _ICL_PORT_TX_DW5_GRP_A         0x162694
-#define _ICL_PORT_TX_DW5_GRP_B         0x6C694
-#define _ICL_PORT_TX_DW5_LN0_A         0x162894
-#define _ICL_PORT_TX_DW5_LN0_B         0x6C894
-#define _ICL_PORT_TX_DW5_AUX_A         0x162394
-#define _ICL_PORT_TX_DW5_AUX_B         0x6c394
-#define ICL_PORT_TX_DW5_GRP(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW5_GRP_A, \
-                                                  _ICL_PORT_TX_DW5_GRP_B)
-#define ICL_PORT_TX_DW5_LN0(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW5_LN0_A, \
-                                                  _ICL_PORT_TX_DW5_LN0_B)
-#define ICL_PORT_TX_DW5_AUX(port)      _MMIO_PORT(port, \
-                                                  _ICL_PORT_TX_DW5_AUX_A, \
-                                                  _ICL_PORT_TX_DW5_AUX_B)
+#define CNL_PORT_TX_DW5_GRP(port)      _MMIO(_CNL_PORT_TX_DW_GRP(5, port))
+#define CNL_PORT_TX_DW5_LN0(port)      _MMIO(_CNL_PORT_TX_DW_LN0(5, port))
+#define ICL_PORT_TX_DW5_AUX(port)      _MMIO(_ICL_PORT_TX_DW_AUX(5, port))
+#define ICL_PORT_TX_DW5_GRP(port)      _MMIO(_ICL_PORT_TX_DW_GRP(5, port))
+#define ICL_PORT_TX_DW5_LN0(port)      _MMIO(_ICL_PORT_TX_DW_LN(5, 0, port))
 #define   TX_TRAINING_EN               (1 << 31)
 #define   TAP2_DISABLE                 (1 << 30)
 #define   TAP3_DISABLE                 (1 << 29)
@@ -2054,47 +2072,10 @@ enum i915_power_well_id {
 #define BXT_PORT_CL2CM_DW6(phy)                _BXT_PHY((phy), _PORT_CL2CM_DW6_BC)
 #define   DW6_OLDO_DYN_PWR_DOWN_EN     (1 << 28)
 
-#define CNL_PORT_COMP_DW0              _MMIO(0x162100)
-#define   COMP_INIT                    (1 << 31)
-#define CNL_PORT_COMP_DW1              _MMIO(0x162104)
-#define CNL_PORT_COMP_DW3              _MMIO(0x16210c)
-#define   PROCESS_INFO_DOT_0           (0 << 26)
-#define   PROCESS_INFO_DOT_1           (1 << 26)
-#define   PROCESS_INFO_DOT_4           (2 << 26)
-#define   PROCESS_INFO_MASK            (7 << 26)
-#define   PROCESS_INFO_SHIFT           26
-#define   VOLTAGE_INFO_0_85V           (0 << 24)
-#define   VOLTAGE_INFO_0_95V           (1 << 24)
-#define   VOLTAGE_INFO_1_05V           (2 << 24)
-#define   VOLTAGE_INFO_MASK            (3 << 24)
-#define   VOLTAGE_INFO_SHIFT           24
-#define CNL_PORT_COMP_DW9              _MMIO(0x162124)
-#define CNL_PORT_COMP_DW10             _MMIO(0x162128)
-
-#define _ICL_PORT_COMP_DW0_A           0x162100
-#define _ICL_PORT_COMP_DW0_B           0x6C100
-#define ICL_PORT_COMP_DW0(port)                _MMIO_PORT(port, _ICL_PORT_COMP_DW0_A, \
-                                                        _ICL_PORT_COMP_DW0_B)
-#define _ICL_PORT_COMP_DW1_A           0x162104
-#define _ICL_PORT_COMP_DW1_B           0x6C104
-#define ICL_PORT_COMP_DW1(port)                _MMIO_PORT(port, _ICL_PORT_COMP_DW1_A, \
-                                                        _ICL_PORT_COMP_DW1_B)
-#define _ICL_PORT_COMP_DW3_A           0x16210C
-#define _ICL_PORT_COMP_DW3_B           0x6C10C
-#define ICL_PORT_COMP_DW3(port)                _MMIO_PORT(port, _ICL_PORT_COMP_DW3_A, \
-                                                        _ICL_PORT_COMP_DW3_B)
-#define _ICL_PORT_COMP_DW9_A           0x162124
-#define _ICL_PORT_COMP_DW9_B           0x6C124
-#define ICL_PORT_COMP_DW9(port)                _MMIO_PORT(port, _ICL_PORT_COMP_DW9_A, \
-                                                        _ICL_PORT_COMP_DW9_B)
-#define _ICL_PORT_COMP_DW10_A          0x162128
-#define _ICL_PORT_COMP_DW10_B          0x6C128
-#define ICL_PORT_COMP_DW10(port)       _MMIO_PORT(port, \
-                                                  _ICL_PORT_COMP_DW10_A, \
-                                                  _ICL_PORT_COMP_DW10_B)
+#define FIA1_BASE                      0x163000
 
 /* ICL PHY DFLEX registers */
-#define PORT_TX_DFLEXDPMLE1            _MMIO(0x1638C0)
+#define PORT_TX_DFLEXDPMLE1            _MMIO(FIA1_BASE + 0x008C0)
 #define   DFLEXDPMLE1_DPMLETC_MASK(tc_port)    (0xf << (4 * (tc_port)))
 #define   DFLEXDPMLE1_DPMLETC_ML0(tc_port)     (1 << (4 * (tc_port)))
 #define   DFLEXDPMLE1_DPMLETC_ML1_0(tc_port)   (3 << (4 * (tc_port)))
@@ -2417,6 +2398,7 @@ enum i915_power_well_id {
 
 #define GEN8_GAMW_ECO_DEV_RW_IA _MMIO(0x4080)
 #define   GAMW_ECO_ENABLE_64K_IPS_FIELD 0xF
+#define   GAMW_ECO_DEV_CTX_RELOAD_DISABLE      (1 << 7)
 
 #define GAMT_CHKN_BIT_REG      _MMIO(0x4ab8)
 #define   GAMT_CHKN_DISABLE_L3_COH_PIPE                        (1 << 31)
@@ -2577,6 +2559,7 @@ enum i915_power_well_id {
 /* chicken reg for WaConextSwitchWithConcurrentTLBInvalidate */
 #define GEN9_CSFE_CHICKEN1_RCS _MMIO(0x20D4)
 #define   GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE (1 << 2)
+#define   GEN11_ENABLE_32_PLANE_MODE (1 << 7)
 
 /* WaClearTdlStateAckDirtyBits */
 #define GEN8_STATE_ACK         _MMIO(0x20F0)
@@ -3479,11 +3462,13 @@ enum i915_power_well_id {
 /*
  * Palette regs
  */
-#define PALETTE_A_OFFSET 0xa000
-#define PALETTE_B_OFFSET 0xa800
-#define CHV_PALETTE_C_OFFSET 0xc000
-#define PALETTE(pipe, i) _MMIO(dev_priv->info.palette_offsets[pipe] +  \
-                             dev_priv->info.display_mmio_offset + (i) * 4)
+#define _PALETTE_A             0xa000
+#define _PALETTE_B             0xa800
+#define _CHV_PALETTE_C         0xc000
+#define PALETTE(pipe, i)       _MMIO(dev_priv->info.display_mmio_offset + \
+                                     _PICK((pipe), _PALETTE_A,         \
+                                           _PALETTE_B, _CHV_PALETTE_C) + \
+                                     (i) * 4)
 
 /* MCH MMIO space */
 
@@ -4065,15 +4050,27 @@ enum {
 #define _VSYNCSHIFT_B  0x61028
 #define _PIPE_MULT_B   0x6102c
 
+/* DSI 0 timing regs */
+#define _HTOTAL_DSI0           0x6b000
+#define _HSYNC_DSI0            0x6b008
+#define _VTOTAL_DSI0           0x6b00c
+#define _VSYNC_DSI0            0x6b014
+#define _VSYNCSHIFT_DSI0       0x6b028
+
+/* DSI 1 timing regs */
+#define _HTOTAL_DSI1           0x6b800
+#define _HSYNC_DSI1            0x6b808
+#define _VTOTAL_DSI1           0x6b80c
+#define _VSYNC_DSI1            0x6b814
+#define _VSYNCSHIFT_DSI1       0x6b828
+
 #define TRANSCODER_A_OFFSET 0x60000
 #define TRANSCODER_B_OFFSET 0x61000
 #define TRANSCODER_C_OFFSET 0x62000
 #define CHV_TRANSCODER_C_OFFSET 0x63000
 #define TRANSCODER_EDP_OFFSET 0x6f000
-
-#define _MMIO_TRANS2(pipe, reg) _MMIO(dev_priv->info.trans_offsets[(pipe)] - \
-       dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \
-       dev_priv->info.display_mmio_offset)
+#define TRANSCODER_DSI0_OFFSET 0x6b000
+#define TRANSCODER_DSI1_OFFSET 0x6b800
 
 #define HTOTAL(trans)          _MMIO_TRANS2(trans, _HTOTAL_A)
 #define HBLANK(trans)          _MMIO_TRANS2(trans, _HBLANK_A)
@@ -4153,9 +4150,13 @@ enum {
 /* Bspec claims those aren't shifted but stay at 0x64800 */
 #define EDP_PSR_IMR                            _MMIO(0x64834)
 #define EDP_PSR_IIR                            _MMIO(0x64838)
-#define   EDP_PSR_ERROR(trans)                 (1 << (((trans) * 8 + 10) & 31))
-#define   EDP_PSR_POST_EXIT(trans)             (1 << (((trans) * 8 + 9) & 31))
-#define   EDP_PSR_PRE_ENTRY(trans)             (1 << (((trans) * 8 + 8) & 31))
+#define   EDP_PSR_ERROR(shift)                 (1 << ((shift) + 2))
+#define   EDP_PSR_POST_EXIT(shift)             (1 << ((shift) + 1))
+#define   EDP_PSR_PRE_ENTRY(shift)             (1 << (shift))
+#define   EDP_PSR_TRANSCODER_C_SHIFT           24
+#define   EDP_PSR_TRANSCODER_B_SHIFT           16
+#define   EDP_PSR_TRANSCODER_A_SHIFT           8
+#define   EDP_PSR_TRANSCODER_EDP_SHIFT         0
 
 #define EDP_PSR_AUX_CTL                                _MMIO(dev_priv->psr_mmio_base + 0x10)
 #define   EDP_PSR_AUX_CTL_TIME_OUT_MASK                (3 << 26)
@@ -4199,7 +4200,7 @@ enum {
 #define   EDP_PSR_DEBUG_MASK_LPSP              (1 << 27)
 #define   EDP_PSR_DEBUG_MASK_MEMUP             (1 << 26)
 #define   EDP_PSR_DEBUG_MASK_HPD               (1 << 25)
-#define   EDP_PSR_DEBUG_MASK_DISP_REG_WRITE    (1 << 16)
+#define   EDP_PSR_DEBUG_MASK_DISP_REG_WRITE    (1 << 16) /* Reserved in ICL+ */
 #define   EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1 << 15) /* SKL+ */
 
 #define EDP_PSR2_CTL                   _MMIO(0x6f900)
@@ -4236,7 +4237,7 @@ enum {
 #define  PSR_EVENT_FRONT_BUFFER_MODIFY         (1 << 9)
 #define  PSR_EVENT_WD_TIMER_EXPIRE             (1 << 8)
 #define  PSR_EVENT_PIPE_REGISTERS_UPDATE       (1 << 6)
-#define  PSR_EVENT_REGISTER_UPDATE             (1 << 5)
+#define  PSR_EVENT_REGISTER_UPDATE             (1 << 5) /* Reserved in ICL+ */
 #define  PSR_EVENT_HDCP_ENABLE                 (1 << 4)
 #define  PSR_EVENT_KVMR_SESSION_ENABLE         (1 << 3)
 #define  PSR_EVENT_VBI_ENABLE                  (1 << 2)
@@ -4569,6 +4570,7 @@ enum {
  * of the infoframe structure specified by CEA-861. */
 #define   VIDEO_DIP_DATA_SIZE  32
 #define   VIDEO_DIP_VSC_DATA_SIZE      36
+#define   VIDEO_DIP_PPS_DATA_SIZE      132
 #define VIDEO_DIP_CTL          _MMIO(0x61170)
 /* Pre HSW: */
 #define   VIDEO_DIP_ENABLE             (1 << 31)
@@ -4588,6 +4590,15 @@ enum {
 #define   VIDEO_DIP_FREQ_2VSYNC                (2 << 16)
 #define   VIDEO_DIP_FREQ_MASK          (3 << 16)
 /* HSW and later: */
+#define   DRM_DIP_ENABLE               (1 << 28)
+#define   PSR_VSC_BIT_7_SET            (1 << 27)
+#define   VSC_SELECT_MASK              (0x3 << 25)
+#define   VSC_SELECT_SHIFT             25
+#define   VSC_DIP_HW_HEA_DATA          (0 << 25)
+#define   VSC_DIP_HW_HEA_SW_DATA       (1 << 25)
+#define   VSC_DIP_HW_DATA_SW_HEA       (2 << 25)
+#define   VSC_DIP_SW_HEA_DATA          (3 << 25)
+#define   VDIP_ENABLE_PPS              (1 << 24)
 #define   VIDEO_DIP_ENABLE_VSC_HSW     (1 << 20)
 #define   VIDEO_DIP_ENABLE_GCP_HSW     (1 << 16)
 #define   VIDEO_DIP_ENABLE_AVI_HSW     (1 << 12)
@@ -4595,16 +4606,6 @@ enum {
 #define   VIDEO_DIP_ENABLE_GMP_HSW     (1 << 4)
 #define   VIDEO_DIP_ENABLE_SPD_HSW     (1 << 0)
 
-#define  DRM_DIP_ENABLE                        (1 << 28)
-#define  PSR_VSC_BIT_7_SET             (1 << 27)
-#define  VSC_SELECT_MASK               (0x3 << 25)
-#define  VSC_SELECT_SHIFT              25
-#define  VSC_DIP_HW_HEA_DATA           (0 << 25)
-#define  VSC_DIP_HW_HEA_SW_DATA                (1 << 25)
-#define  VSC_DIP_HW_DATA_SW_HEA                (2 << 25)
-#define  VSC_DIP_SW_HEA_DATA           (3 << 25)
-#define  VDIP_ENABLE_PPS               (1 << 24)
-
 /* Panel power sequencing */
 #define PPS_BASE                       0x61200
 #define VLV_PPS_BASE                   (VLV_DISPLAY_BASE + PPS_BASE)
@@ -4617,6 +4618,17 @@ enum {
 #define _PP_STATUS                     0x61200
 #define PP_STATUS(pps_idx)             _MMIO_PPS(pps_idx, _PP_STATUS)
 #define   PP_ON                                (1 << 31)
+
+#define _PP_CONTROL_1                  0xc7204
+#define _PP_CONTROL_2                  0xc7304
+#define ICP_PP_CONTROL(x)              _MMIO(((x) == 1) ? _PP_CONTROL_1 : \
+                                             _PP_CONTROL_2)
+#define  POWER_CYCLE_DELAY_MASK        (0x1f << 4)
+#define  POWER_CYCLE_DELAY_SHIFT       4
+#define  VDD_OVERRIDE_FORCE            (1 << 3)
+#define  BACKLIGHT_ENABLE              (1 << 2)
+#define  PWR_DOWN_ON_RESET             (1 << 1)
+#define  PWR_STATE_TARGET              (1 << 0)
 /*
  * Indicates that all dependencies of the panel are on:
  *
@@ -5640,9 +5652,9 @@ enum {
  */
 #define PIPE_EDP_OFFSET        0x7f000
 
-#define _MMIO_PIPE2(pipe, reg) _MMIO(dev_priv->info.pipe_offsets[pipe] - \
-       dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \
-       dev_priv->info.display_mmio_offset)
+/* ICL DSI 0 and 1 */
+#define PIPE_DSI0_OFFSET       0x7b000
+#define PIPE_DSI1_OFFSET       0x7b800
 
 #define PIPECONF(pipe)         _MMIO_PIPE2(pipe, _PIPEACONF)
 #define PIPEDSL(pipe)          _MMIO_PIPE2(pipe, _PIPEADSL)
@@ -6091,10 +6103,6 @@ enum {
 #define _CURBBASE_IVB          0x71084
 #define _CURBPOS_IVB           0x71088
 
-#define _CURSOR2(pipe, reg) _MMIO(dev_priv->info.cursor_offsets[(pipe)] - \
-       dev_priv->info.cursor_offsets[PIPE_A] + (reg) + \
-       dev_priv->info.display_mmio_offset)
-
 #define CURCNTR(pipe) _CURSOR2(pipe, _CURACNTR)
 #define CURBASE(pipe) _CURSOR2(pipe, _CURABASE)
 #define CURPOS(pipe) _CURSOR2(pipe, _CURAPOS)
@@ -6228,6 +6236,10 @@ enum {
 #define _DSPBOFFSET            (dev_priv->info.display_mmio_offset + 0x711A4)
 #define _DSPBSURFLIVE          (dev_priv->info.display_mmio_offset + 0x711AC)
 
+/* ICL DSI 0 and 1 */
+#define _PIPEDSI0CONF          0x7b008
+#define _PIPEDSI1CONF          0x7b808
+
 /* Sprite A control */
 #define _DVSACNTR              0x72180
 #define   DVS_ENABLE           (1 << 31)
@@ -6515,6 +6527,7 @@ enum {
 #define   PLANE_CTL_KEY_ENABLE_DESTINATION     (2 << 21)
 #define   PLANE_CTL_ORDER_BGRX                 (0 << 20)
 #define   PLANE_CTL_ORDER_RGBX                 (1 << 20)
+#define   PLANE_CTL_YUV420_Y_PLANE             (1 << 19)
 #define   PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709        (1 << 18)
 #define   PLANE_CTL_YUV422_ORDER_MASK          (0x3 << 16)
 #define   PLANE_CTL_YUV422_YUYV                        (0 << 16)
@@ -6558,17 +6571,33 @@ enum {
 #define _PLANE_KEYVAL_2_A                      0x70294
 #define _PLANE_KEYMSK_1_A                      0x70198
 #define _PLANE_KEYMSK_2_A                      0x70298
+#define  PLANE_KEYMSK_ALPHA_ENABLE             (1 << 31)
 #define _PLANE_KEYMAX_1_A                      0x701a0
 #define _PLANE_KEYMAX_2_A                      0x702a0
+#define  PLANE_KEYMAX_ALPHA(a)                 ((a) << 24)
 #define _PLANE_AUX_DIST_1_A                    0x701c0
 #define _PLANE_AUX_DIST_2_A                    0x702c0
 #define _PLANE_AUX_OFFSET_1_A                  0x701c4
 #define _PLANE_AUX_OFFSET_2_A                  0x702c4
+#define _PLANE_CUS_CTL_1_A                     0x701c8
+#define _PLANE_CUS_CTL_2_A                     0x702c8
+#define  PLANE_CUS_ENABLE                      (1 << 31)
+#define  PLANE_CUS_PLANE_6                     (0 << 30)
+#define  PLANE_CUS_PLANE_7                     (1 << 30)
+#define  PLANE_CUS_HPHASE_SIGN_NEGATIVE                (1 << 19)
+#define  PLANE_CUS_HPHASE_0                    (0 << 16)
+#define  PLANE_CUS_HPHASE_0_25                 (1 << 16)
+#define  PLANE_CUS_HPHASE_0_5                  (2 << 16)
+#define  PLANE_CUS_VPHASE_SIGN_NEGATIVE                (1 << 15)
+#define  PLANE_CUS_VPHASE_0                    (0 << 12)
+#define  PLANE_CUS_VPHASE_0_25                 (1 << 12)
+#define  PLANE_CUS_VPHASE_0_5                  (2 << 12)
 #define _PLANE_COLOR_CTL_1_A                   0x701CC /* GLK+ */
 #define _PLANE_COLOR_CTL_2_A                   0x702CC /* GLK+ */
 #define _PLANE_COLOR_CTL_3_A                   0x703CC /* GLK+ */
 #define   PLANE_COLOR_PIPE_GAMMA_ENABLE                (1 << 30) /* Pre-ICL */
 #define   PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE     (1 << 28)
+#define   PLANE_COLOR_INPUT_CSC_ENABLE         (1 << 20) /* ICL+ */
 #define   PLANE_COLOR_PIPE_CSC_ENABLE          (1 << 23) /* Pre-ICL */
 #define   PLANE_COLOR_CSC_MODE_BYPASS                  (0 << 17)
 #define   PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709                (1 << 17)
@@ -6585,6 +6614,55 @@ enum {
 #define _PLANE_NV12_BUF_CFG_1_A                0x70278
 #define _PLANE_NV12_BUF_CFG_2_A                0x70378
 
+/* Input CSC Register Definitions */
+#define _PLANE_INPUT_CSC_RY_GY_1_A     0x701E0
+#define _PLANE_INPUT_CSC_RY_GY_2_A     0x702E0
+
+#define _PLANE_INPUT_CSC_RY_GY_1_B     0x711E0
+#define _PLANE_INPUT_CSC_RY_GY_2_B     0x712E0
+
+#define _PLANE_INPUT_CSC_RY_GY_1(pipe) \
+       _PIPE(pipe, _PLANE_INPUT_CSC_RY_GY_1_A, \
+            _PLANE_INPUT_CSC_RY_GY_1_B)
+#define _PLANE_INPUT_CSC_RY_GY_2(pipe) \
+       _PIPE(pipe, _PLANE_INPUT_CSC_RY_GY_2_A, \
+            _PLANE_INPUT_CSC_RY_GY_2_B)
+
+#define PLANE_INPUT_CSC_COEFF(pipe, plane, index)      \
+       _MMIO_PLANE(plane, _PLANE_INPUT_CSC_RY_GY_1(pipe) +  (index) * 4, \
+                   _PLANE_INPUT_CSC_RY_GY_2(pipe) + (index) * 4)
+
+#define _PLANE_INPUT_CSC_PREOFF_HI_1_A         0x701F8
+#define _PLANE_INPUT_CSC_PREOFF_HI_2_A         0x702F8
+
+#define _PLANE_INPUT_CSC_PREOFF_HI_1_B         0x711F8
+#define _PLANE_INPUT_CSC_PREOFF_HI_2_B         0x712F8
+
+#define _PLANE_INPUT_CSC_PREOFF_HI_1(pipe)     \
+       _PIPE(pipe, _PLANE_INPUT_CSC_PREOFF_HI_1_A, \
+            _PLANE_INPUT_CSC_PREOFF_HI_1_B)
+#define _PLANE_INPUT_CSC_PREOFF_HI_2(pipe)     \
+       _PIPE(pipe, _PLANE_INPUT_CSC_PREOFF_HI_2_A, \
+            _PLANE_INPUT_CSC_PREOFF_HI_2_B)
+#define PLANE_INPUT_CSC_PREOFF(pipe, plane, index)     \
+       _MMIO_PLANE(plane, _PLANE_INPUT_CSC_PREOFF_HI_1(pipe) + (index) * 4, \
+                   _PLANE_INPUT_CSC_PREOFF_HI_2(pipe) + (index) * 4)
+
+#define _PLANE_INPUT_CSC_POSTOFF_HI_1_A                0x70204
+#define _PLANE_INPUT_CSC_POSTOFF_HI_2_A                0x70304
+
+#define _PLANE_INPUT_CSC_POSTOFF_HI_1_B                0x71204
+#define _PLANE_INPUT_CSC_POSTOFF_HI_2_B                0x71304
+
+#define _PLANE_INPUT_CSC_POSTOFF_HI_1(pipe)    \
+       _PIPE(pipe, _PLANE_INPUT_CSC_POSTOFF_HI_1_A, \
+            _PLANE_INPUT_CSC_POSTOFF_HI_1_B)
+#define _PLANE_INPUT_CSC_POSTOFF_HI_2(pipe)    \
+       _PIPE(pipe, _PLANE_INPUT_CSC_POSTOFF_HI_2_A, \
+            _PLANE_INPUT_CSC_POSTOFF_HI_2_B)
+#define PLANE_INPUT_CSC_POSTOFF(pipe, plane, index)    \
+       _MMIO_PLANE(plane, _PLANE_INPUT_CSC_POSTOFF_HI_1(pipe) + (index) * 4, \
+                   _PLANE_INPUT_CSC_POSTOFF_HI_2(pipe) + (index) * 4)
 
 #define _PLANE_CTL_1_B                         0x71180
 #define _PLANE_CTL_2_B                         0x71280
@@ -6701,6 +6779,15 @@ enum {
 #define PLANE_AUX_OFFSET(pipe, plane)   \
        _MMIO_PLANE(plane, _PLANE_AUX_OFFSET_1(pipe), _PLANE_AUX_OFFSET_2(pipe))
 
+#define _PLANE_CUS_CTL_1_B             0x711c8
+#define _PLANE_CUS_CTL_2_B             0x712c8
+#define _PLANE_CUS_CTL_1(pipe)       \
+               _PIPE(pipe, _PLANE_CUS_CTL_1_A, _PLANE_CUS_CTL_1_B)
+#define _PLANE_CUS_CTL_2(pipe)       \
+               _PIPE(pipe, _PLANE_CUS_CTL_2_A, _PLANE_CUS_CTL_2_B)
+#define PLANE_CUS_CTL(pipe, plane)   \
+       _MMIO_PLANE(plane, _PLANE_CUS_CTL_1(pipe), _PLANE_CUS_CTL_2(pipe))
+
 #define _PLANE_COLOR_CTL_1_B                   0x711CC
 #define _PLANE_COLOR_CTL_2_B                   0x712CC
 #define _PLANE_COLOR_CTL_3_B                   0x713CC
@@ -6854,11 +6941,12 @@ enum {
 #define _PS_2B_CTRL      0x68A80
 #define _PS_1C_CTRL      0x69180
 #define PS_SCALER_EN        (1 << 31)
-#define PS_SCALER_MODE_MASK (3 << 28)
-#define PS_SCALER_MODE_DYN  (0 << 28)
-#define PS_SCALER_MODE_HQ  (1 << 28)
+#define SKL_PS_SCALER_MODE_MASK (3 << 28)
+#define SKL_PS_SCALER_MODE_DYN  (0 << 28)
+#define SKL_PS_SCALER_MODE_HQ  (1 << 28)
 #define SKL_PS_SCALER_MODE_NV12 (2 << 28)
 #define PS_SCALER_MODE_PLANAR (1 << 29)
+#define PS_SCALER_MODE_NORMAL (0 << 29)
 #define PS_PLANE_SEL_MASK  (7 << 25)
 #define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
 #define PS_FILTER_MASK         (3 << 23)
@@ -6875,6 +6963,8 @@ enum {
 #define PS_VADAPT_MODE_LEAST_ADAPT (0 << 5)
 #define PS_VADAPT_MODE_MOD_ADAPT   (1 << 5)
 #define PS_VADAPT_MODE_MOST_ADAPT  (3 << 5)
+#define PS_PLANE_Y_SEL_MASK  (7 << 5)
+#define PS_PLANE_Y_SEL(plane) (((plane) + 1) << 5)
 
 #define _PS_PWR_GATE_1A     0x68160
 #define _PS_PWR_GATE_2A     0x68260
@@ -7321,9 +7411,10 @@ enum {
 #define  BDW_DPRS_MASK_VBLANK_SRD      (1 << 0)
 #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
 
-#define CHICKEN_TRANS_A         0x420c0
-#define CHICKEN_TRANS_B         0x420c4
-#define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B)
+#define CHICKEN_TRANS_A                _MMIO(0x420c0)
+#define CHICKEN_TRANS_B                _MMIO(0x420c4)
+#define CHICKEN_TRANS_C                _MMIO(0x420c8)
+#define CHICKEN_TRANS_EDP      _MMIO(0x420cc)
 #define  VSC_DATA_SEL_SOFTWARE_CONTROL (1 << 25) /* GLK and CNL+ */
 #define  DDI_TRAINING_OVERRIDE_ENABLE  (1 << 19)
 #define  DDI_TRAINING_OVERRIDE_VALUE   (1 << 18)
@@ -7413,6 +7504,10 @@ enum {
 #define GEN9_SLICE_COMMON_ECO_CHICKEN1         _MMIO(0x731c)
 #define   GEN11_STATE_CACHE_REDIRECT_TO_CS     (1 << 11)
 
+#define GEN7_SARCHKMD                          _MMIO(0xB000)
+#define GEN7_DISABLE_DEMAND_PREFETCH           (1 << 31)
+#define GEN7_DISABLE_SAMPLER_PREFETCH           (1 << 30)
+
 #define GEN7_L3SQCREG1                         _MMIO(0xB010)
 #define  VLV_B0_WA_L3SQCREG1_VALUE             0x00D30000
 
@@ -7667,6 +7762,7 @@ enum {
 #define   ICP_DDIB_HPD_LONG_DETECT             (2 << 4)
 #define   ICP_DDIB_HPD_SHORT_LONG_DETECT       (3 << 4)
 #define   ICP_DDIA_HPD_ENABLE                  (1 << 3)
+#define   ICP_DDIA_HPD_OP_DRIVE_1              (1 << 2)
 #define   ICP_DDIA_HPD_STATUS_MASK             (3 << 0)
 #define   ICP_DDIA_HPD_NO_DETECT               (0 << 0)
 #define   ICP_DDIA_HPD_SHORT_DETECT            (1 << 0)
@@ -7828,8 +7924,7 @@ enum {
 #define  CNP_RAWCLK_DIV_MASK   (0x3ff << 16)
 #define  CNP_RAWCLK_DIV(div)   ((div) << 16)
 #define  CNP_RAWCLK_FRAC_MASK  (0xf << 26)
-#define  CNP_RAWCLK_FRAC(frac) ((frac) << 26)
-#define  ICP_RAWCLK_DEN(den)   ((den) << 26)
+#define  CNP_RAWCLK_DEN(den)   ((den) << 26)
 #define  ICP_RAWCLK_NUM(num)   ((num) << 11)
 
 #define PCH_DPLL_TMR_CFG        _MMIO(0xc6208)
@@ -8629,8 +8724,7 @@ enum {
 #define   GEN11_LSN_UNSLCVC_GAFS_HALF_CL2_MAXALLOC     (1 << 9)
 #define   GEN11_LSN_UNSLCVC_GAFS_HALF_SF_MAXALLOC      (1 << 7)
 
-#define GAMW_ECO_DEV_RW_IA_REG                 _MMIO(0x4080)
-#define   GAMW_ECO_DEV_CTX_RELOAD_DISABLE      (1 << 7)
+#define GEN10_SAMPLER_MODE             _MMIO(0xE18C)
 
 /* IVYBRIDGE DPF */
 #define GEN7_L3CDERRST1(slice)         _MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */
@@ -8931,6 +9025,15 @@ enum skl_power_gate {
 #define   CNL_AUX_ANAOVRD1_ENABLE      (1 << 16)
 #define   CNL_AUX_ANAOVRD1_LDO_BYPASS  (1 << 23)
 
+#define _ICL_AUX_REG_IDX(pw_idx)       ((pw_idx) - ICL_PW_CTL_IDX_AUX_A)
+#define _ICL_AUX_ANAOVRD1_A            0x162398
+#define _ICL_AUX_ANAOVRD1_B            0x6C398
+#define ICL_AUX_ANAOVRD1(pw_idx)       _MMIO(_PICK(_ICL_AUX_REG_IDX(pw_idx), \
+                                                   _ICL_AUX_ANAOVRD1_A, \
+                                                   _ICL_AUX_ANAOVRD1_B))
+#define   ICL_AUX_ANAOVRD1_LDO_BYPASS  (1 << 7)
+#define   ICL_AUX_ANAOVRD1_ENABLE      (1 << 0)
+
 /* HDCP Key Registers */
 #define HDCP_KEY_CONF                  _MMIO(0x66c00)
 #define  HDCP_AKSV_SEND_TRIGGER                BIT(31)
@@ -9013,11 +9116,45 @@ enum skl_power_gate {
 #define  HDCP_STATUS_CIPHER            BIT(16)
 #define  HDCP_STATUS_FRAME_CNT(x)      (((x) >> 8) & 0xff)
 
+/* HDCP2.2 Registers */
+#define _PORTA_HDCP2_BASE              0x66800
+#define _PORTB_HDCP2_BASE              0x66500
+#define _PORTC_HDCP2_BASE              0x66600
+#define _PORTD_HDCP2_BASE              0x66700
+#define _PORTE_HDCP2_BASE              0x66A00
+#define _PORTF_HDCP2_BASE              0x66900
+#define _PORT_HDCP2_BASE(port, x)      _MMIO(_PICK((port), \
+                                         _PORTA_HDCP2_BASE, \
+                                         _PORTB_HDCP2_BASE, \
+                                         _PORTC_HDCP2_BASE, \
+                                         _PORTD_HDCP2_BASE, \
+                                         _PORTE_HDCP2_BASE, \
+                                         _PORTF_HDCP2_BASE) + (x))
+
+#define HDCP2_AUTH_DDI(port)           _PORT_HDCP2_BASE(port, 0x98)
+#define   AUTH_LINK_AUTHENTICATED      BIT(31)
+#define   AUTH_LINK_TYPE               BIT(30)
+#define   AUTH_FORCE_CLR_INPUTCTR      BIT(19)
+#define   AUTH_CLR_KEYS                        BIT(18)
+
+#define HDCP2_CTL_DDI(port)            _PORT_HDCP2_BASE(port, 0xB0)
+#define   CTL_LINK_ENCRYPTION_REQ      BIT(31)
+
+#define HDCP2_STATUS_DDI(port)         _PORT_HDCP2_BASE(port, 0xB4)
+#define   STREAM_ENCRYPTION_STATUS_A   BIT(31)
+#define   STREAM_ENCRYPTION_STATUS_B   BIT(30)
+#define   STREAM_ENCRYPTION_STATUS_C   BIT(29)
+#define   LINK_TYPE_STATUS             BIT(22)
+#define   LINK_AUTH_STATUS             BIT(21)
+#define   LINK_ENCRYPTION_STATUS       BIT(20)
+
 /* Per-pipe DDI Function Control */
 #define _TRANS_DDI_FUNC_CTL_A          0x60400
 #define _TRANS_DDI_FUNC_CTL_B          0x61400
 #define _TRANS_DDI_FUNC_CTL_C          0x62400
 #define _TRANS_DDI_FUNC_CTL_EDP                0x6F400
+#define _TRANS_DDI_FUNC_CTL_DSI0       0x6b400
+#define _TRANS_DDI_FUNC_CTL_DSI1       0x6bc00
 #define TRANS_DDI_FUNC_CTL(tran) _MMIO_TRANS2(tran, _TRANS_DDI_FUNC_CTL_A)
 
 #define  TRANS_DDI_FUNC_ENABLE         (1 << 31)
@@ -9055,11 +9192,25 @@ enum skl_power_gate {
                                        | TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ \
                                        | TRANS_DDI_HDMI_SCRAMBLING)
 
+#define _TRANS_DDI_FUNC_CTL2_A         0x60404
+#define _TRANS_DDI_FUNC_CTL2_B         0x61404
+#define _TRANS_DDI_FUNC_CTL2_C         0x62404
+#define _TRANS_DDI_FUNC_CTL2_EDP       0x6f404
+#define _TRANS_DDI_FUNC_CTL2_DSI0      0x6b404
+#define _TRANS_DDI_FUNC_CTL2_DSI1      0x6bc04
+#define TRANS_DDI_FUNC_CTL2(tran)      _MMIO_TRANS2(tran, \
+                                                    _TRANS_DDI_FUNC_CTL2_A)
+#define  PORT_SYNC_MODE_ENABLE                 (1 << 4)
+#define  PORT_SYNC_MODE_MASTER_SELECT(x)       ((x) < 0)
+#define  PORT_SYNC_MODE_MASTER_SELECT_MASK     (0x7 << 0)
+#define  PORT_SYNC_MODE_MASTER_SELECT_SHIFT    0
+
 /* DisplayPort Transport Control */
 #define _DP_TP_CTL_A                   0x64040
 #define _DP_TP_CTL_B                   0x64140
 #define DP_TP_CTL(port) _MMIO_PORT(port, _DP_TP_CTL_A, _DP_TP_CTL_B)
 #define  DP_TP_CTL_ENABLE                      (1 << 31)
+#define  DP_TP_CTL_FEC_ENABLE                  (1 << 30)
 #define  DP_TP_CTL_MODE_SST                    (0 << 27)
 #define  DP_TP_CTL_MODE_MST                    (1 << 27)
 #define  DP_TP_CTL_FORCE_ACT                   (1 << 25)
@@ -9078,6 +9229,7 @@ enum skl_power_gate {
 #define _DP_TP_STATUS_A                        0x64044
 #define _DP_TP_STATUS_B                        0x64144
 #define DP_TP_STATUS(port) _MMIO_PORT(port, _DP_TP_STATUS_A, _DP_TP_STATUS_B)
+#define  DP_TP_STATUS_FEC_ENABLE_LIVE          (1 << 28)
 #define  DP_TP_STATUS_IDLE_DONE                        (1 << 25)
 #define  DP_TP_STATUS_ACT_SENT                 (1 << 24)
 #define  DP_TP_STATUS_MODE_STATUS_MST          (1 << 23)
@@ -9226,6 +9378,8 @@ enum skl_power_gate {
 #define TRANS_MSA_MISC(tran) _MMIO_TRANS2(tran, _TRANSA_MSA_MISC)
 
 #define  TRANS_MSA_SYNC_CLK            (1 << 0)
+#define  TRANS_MSA_SAMPLING_444                (2 << 1)
+#define  TRANS_MSA_CLRSP_YCBCR         (2 << 3)
 #define  TRANS_MSA_6_BPC               (0 << 5)
 #define  TRANS_MSA_8_BPC               (1 << 5)
 #define  TRANS_MSA_10_BPC              (2 << 5)
@@ -9793,6 +9947,10 @@ enum skl_power_gate {
 #define _MIPI_PORT(port, a, c) (((port) == PORT_A) ? a : c)    /* ports A and C only */
 #define _MMIO_MIPI(port, a, c) _MMIO(_MIPI_PORT(port, a, c))
 
+/* Gen11 DSI */
+#define _MMIO_DSI(tc, dsi0, dsi1)      _MMIO_TRANS((tc) - TRANSCODER_DSI_0, \
+                                                   dsi0, dsi1)
+
 #define MIPIO_TXESC_CLK_DIV1                   _MMIO(0x160004)
 #define  GLK_TX_ESC_CLK_DIV1_MASK                      0x3FF
 #define MIPIO_TXESC_CLK_DIV2                   _MMIO(0x160008)
@@ -9956,6 +10114,39 @@ enum skl_power_gate {
                                                    _ICL_DSI_IO_MODECTL_1)
 #define  COMBO_PHY_MODE_DSI                            (1 << 0)
 
+/* Display Stream Splitter Control */
+#define DSS_CTL1                               _MMIO(0x67400)
+#define  SPLITTER_ENABLE                       (1 << 31)
+#define  JOINER_ENABLE                         (1 << 30)
+#define  DUAL_LINK_MODE_INTERLEAVE             (1 << 24)
+#define  DUAL_LINK_MODE_FRONTBACK              (0 << 24)
+#define  OVERLAP_PIXELS_MASK                   (0xf << 16)
+#define  OVERLAP_PIXELS(pixels)                        ((pixels) << 16)
+#define  LEFT_DL_BUF_TARGET_DEPTH_MASK         (0xfff << 0)
+#define  LEFT_DL_BUF_TARGET_DEPTH(pixels)      ((pixels) << 0)
+#define  MAX_DL_BUFFER_TARGET_DEPTH            0x5a0
+
+#define DSS_CTL2                               _MMIO(0x67404)
+#define  LEFT_BRANCH_VDSC_ENABLE               (1 << 31)
+#define  RIGHT_BRANCH_VDSC_ENABLE              (1 << 15)
+#define  RIGHT_DL_BUF_TARGET_DEPTH_MASK                (0xfff << 0)
+#define  RIGHT_DL_BUF_TARGET_DEPTH(pixels)     ((pixels) << 0)
+
+#define _ICL_PIPE_DSS_CTL1_PB                  0x78200
+#define _ICL_PIPE_DSS_CTL1_PC                  0x78400
+#define ICL_PIPE_DSS_CTL1(pipe)                        _MMIO_PIPE((pipe) - PIPE_B, \
+                                                          _ICL_PIPE_DSS_CTL1_PB, \
+                                                          _ICL_PIPE_DSS_CTL1_PC)
+#define  BIG_JOINER_ENABLE                     (1 << 29)
+#define  MASTER_BIG_JOINER_ENABLE              (1 << 28)
+#define  VGA_CENTERING_ENABLE                  (1 << 27)
+
+#define _ICL_PIPE_DSS_CTL2_PB                  0x78204
+#define _ICL_PIPE_DSS_CTL2_PC                  0x78404
+#define ICL_PIPE_DSS_CTL2(pipe)                        _MMIO_PIPE((pipe) - PIPE_B, \
+                                                          _ICL_PIPE_DSS_CTL2_PB, \
+                                                          _ICL_PIPE_DSS_CTL2_PC)
+
 #define BXT_P_DSI_REGULATOR_CFG                        _MMIO(0x160020)
 #define  STAP_SELECT                                   (1 << 0)
 
@@ -10292,6 +10483,235 @@ enum skl_power_gate {
                                                   _ICL_DSI_T_INIT_MASTER_0,\
                                                   _ICL_DSI_T_INIT_MASTER_1)
 
+#define _DPHY_CLK_TIMING_PARAM_0       0x162180
+#define _DPHY_CLK_TIMING_PARAM_1       0x6c180
+#define DPHY_CLK_TIMING_PARAM(port)    _MMIO_PORT(port,        \
+                                                  _DPHY_CLK_TIMING_PARAM_0,\
+                                                  _DPHY_CLK_TIMING_PARAM_1)
+#define _DSI_CLK_TIMING_PARAM_0                0x6b080
+#define _DSI_CLK_TIMING_PARAM_1                0x6b880
+#define DSI_CLK_TIMING_PARAM(port)     _MMIO_PORT(port,        \
+                                                  _DSI_CLK_TIMING_PARAM_0,\
+                                                  _DSI_CLK_TIMING_PARAM_1)
+#define  CLK_PREPARE_OVERRIDE          (1 << 31)
+#define  CLK_PREPARE(x)                ((x) << 28)
+#define  CLK_PREPARE_MASK              (0x7 << 28)
+#define  CLK_PREPARE_SHIFT             28
+#define  CLK_ZERO_OVERRIDE             (1 << 27)
+#define  CLK_ZERO(x)                   ((x) << 20)
+#define  CLK_ZERO_MASK                 (0xf << 20)
+#define  CLK_ZERO_SHIFT                20
+#define  CLK_PRE_OVERRIDE              (1 << 19)
+#define  CLK_PRE(x)                    ((x) << 16)
+#define  CLK_PRE_MASK                  (0x3 << 16)
+#define  CLK_PRE_SHIFT                 16
+#define  CLK_POST_OVERRIDE             (1 << 15)
+#define  CLK_POST(x)                   ((x) << 8)
+#define  CLK_POST_MASK                 (0x7 << 8)
+#define  CLK_POST_SHIFT                8
+#define  CLK_TRAIL_OVERRIDE            (1 << 7)
+#define  CLK_TRAIL(x)                  ((x) << 0)
+#define  CLK_TRAIL_MASK                (0xf << 0)
+#define  CLK_TRAIL_SHIFT               0
+
+#define _DPHY_DATA_TIMING_PARAM_0      0x162184
+#define _DPHY_DATA_TIMING_PARAM_1      0x6c184
+#define DPHY_DATA_TIMING_PARAM(port)   _MMIO_PORT(port,        \
+                                                  _DPHY_DATA_TIMING_PARAM_0,\
+                                                  _DPHY_DATA_TIMING_PARAM_1)
+#define _DSI_DATA_TIMING_PARAM_0       0x6B084
+#define _DSI_DATA_TIMING_PARAM_1       0x6B884
+#define DSI_DATA_TIMING_PARAM(port)    _MMIO_PORT(port,        \
+                                                  _DSI_DATA_TIMING_PARAM_0,\
+                                                  _DSI_DATA_TIMING_PARAM_1)
+#define  HS_PREPARE_OVERRIDE           (1 << 31)
+#define  HS_PREPARE(x)                 ((x) << 24)
+#define  HS_PREPARE_MASK               (0x7 << 24)
+#define  HS_PREPARE_SHIFT              24
+#define  HS_ZERO_OVERRIDE              (1 << 23)
+#define  HS_ZERO(x)                    ((x) << 16)
+#define  HS_ZERO_MASK                  (0xf << 16)
+#define  HS_ZERO_SHIFT                 16
+#define  HS_TRAIL_OVERRIDE             (1 << 15)
+#define  HS_TRAIL(x)                   ((x) << 8)
+#define  HS_TRAIL_MASK                 (0x7 << 8)
+#define  HS_TRAIL_SHIFT                8
+#define  HS_EXIT_OVERRIDE              (1 << 7)
+#define  HS_EXIT(x)                    ((x) << 0)
+#define  HS_EXIT_MASK                  (0x7 << 0)
+#define  HS_EXIT_SHIFT                 0
+
+#define _DPHY_TA_TIMING_PARAM_0                0x162188
+#define _DPHY_TA_TIMING_PARAM_1                0x6c188
+#define DPHY_TA_TIMING_PARAM(port)     _MMIO_PORT(port,        \
+                                                  _DPHY_TA_TIMING_PARAM_0,\
+                                                  _DPHY_TA_TIMING_PARAM_1)
+#define _DSI_TA_TIMING_PARAM_0         0x6b098
+#define _DSI_TA_TIMING_PARAM_1         0x6b898
+#define DSI_TA_TIMING_PARAM(port)      _MMIO_PORT(port,        \
+                                                  _DSI_TA_TIMING_PARAM_0,\
+                                                  _DSI_TA_TIMING_PARAM_1)
+#define  TA_SURE_OVERRIDE              (1 << 31)
+#define  TA_SURE(x)                    ((x) << 16)
+#define  TA_SURE_MASK                  (0x1f << 16)
+#define  TA_SURE_SHIFT                 16
+#define  TA_GO_OVERRIDE                (1 << 15)
+#define  TA_GO(x)                      ((x) << 8)
+#define  TA_GO_MASK                    (0xf << 8)
+#define  TA_GO_SHIFT                   8
+#define  TA_GET_OVERRIDE               (1 << 7)
+#define  TA_GET(x)                     ((x) << 0)
+#define  TA_GET_MASK                   (0xf << 0)
+#define  TA_GET_SHIFT                  0
+
+/* DSI transcoder configuration */
+#define _DSI_TRANS_FUNC_CONF_0         0x6b030
+#define _DSI_TRANS_FUNC_CONF_1         0x6b830
+#define DSI_TRANS_FUNC_CONF(tc)                _MMIO_DSI(tc,   \
+                                                 _DSI_TRANS_FUNC_CONF_0,\
+                                                 _DSI_TRANS_FUNC_CONF_1)
+#define  OP_MODE_MASK                  (0x3 << 28)
+#define  OP_MODE_SHIFT                 28
+#define  CMD_MODE_NO_GATE              (0x0 << 28)
+#define  CMD_MODE_TE_GATE              (0x1 << 28)
+#define  VIDEO_MODE_SYNC_EVENT         (0x2 << 28)
+#define  VIDEO_MODE_SYNC_PULSE         (0x3 << 28)
+#define  LINK_READY                    (1 << 20)
+#define  PIX_FMT_MASK                  (0x3 << 16)
+#define  PIX_FMT_SHIFT                 16
+#define  PIX_FMT_RGB565                        (0x0 << 16)
+#define  PIX_FMT_RGB666_PACKED         (0x1 << 16)
+#define  PIX_FMT_RGB666_LOOSE          (0x2 << 16)
+#define  PIX_FMT_RGB888                        (0x3 << 16)
+#define  PIX_FMT_RGB101010             (0x4 << 16)
+#define  PIX_FMT_RGB121212             (0x5 << 16)
+#define  PIX_FMT_COMPRESSED            (0x6 << 16)
+#define  BGR_TRANSMISSION              (1 << 15)
+#define  PIX_VIRT_CHAN(x)              ((x) << 12)
+#define  PIX_VIRT_CHAN_MASK            (0x3 << 12)
+#define  PIX_VIRT_CHAN_SHIFT           12
+#define  PIX_BUF_THRESHOLD_MASK                (0x3 << 10)
+#define  PIX_BUF_THRESHOLD_SHIFT       10
+#define  PIX_BUF_THRESHOLD_1_4         (0x0 << 10)
+#define  PIX_BUF_THRESHOLD_1_2         (0x1 << 10)
+#define  PIX_BUF_THRESHOLD_3_4         (0x2 << 10)
+#define  PIX_BUF_THRESHOLD_FULL                (0x3 << 10)
+#define  CONTINUOUS_CLK_MASK           (0x3 << 8)
+#define  CONTINUOUS_CLK_SHIFT          8
+#define  CLK_ENTER_LP_AFTER_DATA       (0x0 << 8)
+#define  CLK_HS_OR_LP                  (0x2 << 8)
+#define  CLK_HS_CONTINUOUS             (0x3 << 8)
+#define  LINK_CALIBRATION_MASK         (0x3 << 4)
+#define  LINK_CALIBRATION_SHIFT                4
+#define  CALIBRATION_DISABLED          (0x0 << 4)
+#define  CALIBRATION_ENABLED_INITIAL_ONLY      (0x2 << 4)
+#define  CALIBRATION_ENABLED_INITIAL_PERIODIC  (0x3 << 4)
+#define  S3D_ORIENTATION_LANDSCAPE     (1 << 1)
+#define  EOTP_DISABLED                 (1 << 0)
+
+#define _DSI_CMD_RXCTL_0               0x6b0d4
+#define _DSI_CMD_RXCTL_1               0x6b8d4
+#define DSI_CMD_RXCTL(tc)              _MMIO_DSI(tc,   \
+                                                 _DSI_CMD_RXCTL_0,\
+                                                 _DSI_CMD_RXCTL_1)
+#define  READ_UNLOADS_DW               (1 << 16)
+#define  RECEIVED_UNASSIGNED_TRIGGER   (1 << 15)
+#define  RECEIVED_ACKNOWLEDGE_TRIGGER  (1 << 14)
+#define  RECEIVED_TEAR_EFFECT_TRIGGER  (1 << 13)
+#define  RECEIVED_RESET_TRIGGER                (1 << 12)
+#define  RECEIVED_PAYLOAD_WAS_LOST     (1 << 11)
+#define  RECEIVED_CRC_WAS_LOST         (1 << 10)
+#define  NUMBER_RX_PLOAD_DW_MASK       (0xff << 0)
+#define  NUMBER_RX_PLOAD_DW_SHIFT      0
+
+#define _DSI_CMD_TXCTL_0               0x6b0d0
+#define _DSI_CMD_TXCTL_1               0x6b8d0
+#define DSI_CMD_TXCTL(tc)              _MMIO_DSI(tc,   \
+                                                 _DSI_CMD_TXCTL_0,\
+                                                 _DSI_CMD_TXCTL_1)
+#define  KEEP_LINK_IN_HS               (1 << 24)
+#define  FREE_HEADER_CREDIT_MASK       (0x1f << 8)
+#define  FREE_HEADER_CREDIT_SHIFT      0x8
+#define  FREE_PLOAD_CREDIT_MASK                (0xff << 0)
+#define  FREE_PLOAD_CREDIT_SHIFT       0
+#define  MAX_HEADER_CREDIT             0x10
+#define  MAX_PLOAD_CREDIT              0x40
+
+#define _DSI_CMD_TXHDR_0               0x6b100
+#define _DSI_CMD_TXHDR_1               0x6b900
+#define DSI_CMD_TXHDR(tc)              _MMIO_DSI(tc,   \
+                                                 _DSI_CMD_TXHDR_0,\
+                                                 _DSI_CMD_TXHDR_1)
+#define  PAYLOAD_PRESENT               (1 << 31)
+#define  LP_DATA_TRANSFER              (1 << 30)
+#define  VBLANK_FENCE                  (1 << 29)
+#define  PARAM_WC_MASK                 (0xffff << 8)
+#define  PARAM_WC_LOWER_SHIFT          8
+#define  PARAM_WC_UPPER_SHIFT          16
+#define  VC_MASK                       (0x3 << 6)
+#define  VC_SHIFT                      6
+#define  DT_MASK                       (0x3f << 0)
+#define  DT_SHIFT                      0
+
+#define _DSI_CMD_TXPYLD_0              0x6b104
+#define _DSI_CMD_TXPYLD_1              0x6b904
+#define DSI_CMD_TXPYLD(tc)             _MMIO_DSI(tc,   \
+                                                 _DSI_CMD_TXPYLD_0,\
+                                                 _DSI_CMD_TXPYLD_1)
+
+#define _DSI_LP_MSG_0                  0x6b0d8
+#define _DSI_LP_MSG_1                  0x6b8d8
+#define DSI_LP_MSG(tc)                 _MMIO_DSI(tc,   \
+                                                 _DSI_LP_MSG_0,\
+                                                 _DSI_LP_MSG_1)
+#define  LPTX_IN_PROGRESS              (1 << 17)
+#define  LINK_IN_ULPS                  (1 << 16)
+#define  LINK_ULPS_TYPE_LP11           (1 << 8)
+#define  LINK_ENTER_ULPS               (1 << 0)
+
+/* DSI timeout registers */
+#define _DSI_HSTX_TO_0                 0x6b044
+#define _DSI_HSTX_TO_1                 0x6b844
+#define DSI_HSTX_TO(tc)                        _MMIO_DSI(tc,   \
+                                                 _DSI_HSTX_TO_0,\
+                                                 _DSI_HSTX_TO_1)
+#define  HSTX_TIMEOUT_VALUE_MASK       (0xffff << 16)
+#define  HSTX_TIMEOUT_VALUE_SHIFT      16
+#define  HSTX_TIMEOUT_VALUE(x)         ((x) << 16)
+#define  HSTX_TIMED_OUT                        (1 << 0)
+
+#define _DSI_LPRX_HOST_TO_0            0x6b048
+#define _DSI_LPRX_HOST_TO_1            0x6b848
+#define DSI_LPRX_HOST_TO(tc)           _MMIO_DSI(tc,   \
+                                                 _DSI_LPRX_HOST_TO_0,\
+                                                 _DSI_LPRX_HOST_TO_1)
+#define  LPRX_TIMED_OUT                        (1 << 16)
+#define  LPRX_TIMEOUT_VALUE_MASK       (0xffff << 0)
+#define  LPRX_TIMEOUT_VALUE_SHIFT      0
+#define  LPRX_TIMEOUT_VALUE(x)         ((x) << 0)
+
+#define _DSI_PWAIT_TO_0                        0x6b040
+#define _DSI_PWAIT_TO_1                        0x6b840
+#define DSI_PWAIT_TO(tc)               _MMIO_DSI(tc,   \
+                                                 _DSI_PWAIT_TO_0,\
+                                                 _DSI_PWAIT_TO_1)
+#define  PRESET_TIMEOUT_VALUE_MASK     (0xffff << 16)
+#define  PRESET_TIMEOUT_VALUE_SHIFT    16
+#define  PRESET_TIMEOUT_VALUE(x)       ((x) << 16)
+#define  PRESPONSE_TIMEOUT_VALUE_MASK  (0xffff << 0)
+#define  PRESPONSE_TIMEOUT_VALUE_SHIFT 0
+#define  PRESPONSE_TIMEOUT_VALUE(x)    ((x) << 0)
+
+#define _DSI_TA_TO_0                   0x6b04c
+#define _DSI_TA_TO_1                   0x6b84c
+#define DSI_TA_TO(tc)                  _MMIO_DSI(tc,   \
+                                                 _DSI_TA_TO_0,\
+                                                 _DSI_TA_TO_1)
+#define  TA_TIMED_OUT                  (1 << 16)
+#define  TA_TIMEOUT_VALUE_MASK         (0xffff << 0)
+#define  TA_TIMEOUT_VALUE_SHIFT                0
+#define  TA_TIMEOUT_VALUE(x)           ((x) << 0)
+
 /* bits 31:0 */
 #define _MIPIA_DBI_BW_CTRL             (dev_priv->mipi_mmio_base + 0xb084)
 #define _MIPIC_DBI_BW_CTRL             (dev_priv->mipi_mmio_base + 0xb884)
@@ -10404,10 +10824,6 @@ enum skl_power_gate {
 #define MIPI_READ_DATA_VALID(port)     _MMIO_MIPI(port, _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
 #define  READ_DATA_VALID(n)                            (1 << (n))
 
-/* For UMS only (deprecated): */
-#define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
-#define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
-
 /* MOCS (Memory Object Control State) registers */
 #define GEN9_LNCFCMOCS(i)      _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */
 
@@ -10693,6 +11109,7 @@ enum skl_power_gate {
 #define ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe)        _MMIO_PIPE((pipe) - PIPE_B, \
                                                           _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB, \
                                                           _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC)
+#define  DSC_SLICE_ROW_PER_FRAME(slice_row_per_frame)  ((slice_row_per_frame) << 20)
 #define  DSC_SLICE_PER_LINE(slice_per_line)            ((slice_per_line) << 16)
 #define  DSC_SLICE_CHUNK_SIZE(slice_chunk_size)                ((slice_chunk_size) << 0)
 
@@ -10747,17 +11164,17 @@ enum skl_power_gate {
                                                _ICL_DSC1_RC_BUF_THRESH_1_UDW_PB, \
                                                _ICL_DSC1_RC_BUF_THRESH_1_UDW_PC)
 
-#define PORT_TX_DFLEXDPSP                      _MMIO(0x1638A0)
+#define PORT_TX_DFLEXDPSP                      _MMIO(FIA1_BASE + 0x008A0)
 #define   TC_LIVE_STATE_TBT(tc_port)           (1 << ((tc_port) * 8 + 6))
 #define   TC_LIVE_STATE_TC(tc_port)            (1 << ((tc_port) * 8 + 5))
 #define   DP_LANE_ASSIGNMENT_SHIFT(tc_port)    ((tc_port) * 8)
 #define   DP_LANE_ASSIGNMENT_MASK(tc_port)     (0xf << ((tc_port) * 8))
 #define   DP_LANE_ASSIGNMENT(tc_port, x)       ((x) << ((tc_port) * 8))
 
-#define PORT_TX_DFLEXDPPMS                             _MMIO(0x163890)
+#define PORT_TX_DFLEXDPPMS                             _MMIO(FIA1_BASE + 0x00890)
 #define   DP_PHY_MODE_STATUS_COMPLETED(tc_port)                (1 << (tc_port))
 
-#define PORT_TX_DFLEXDPCSSS                            _MMIO(0x163894)
+#define PORT_TX_DFLEXDPCSSS                    _MMIO(FIA1_BASE + 0x00894)
 #define   DP_PHY_MODE_STATUS_NOT_SAFE(tc_port)         (1 << (tc_port))
 
 #endif /* _I915_REG_H_ */
index a492385b2089252d1a1b18daf5af68a9587b5760..ca95ab2f4cfa3bf2c4fed83a7dd67b5f6d1b34f5 100644 (file)
@@ -111,91 +111,6 @@ i915_request_remove_from_client(struct i915_request *request)
        spin_unlock(&file_priv->mm.lock);
 }
 
-static struct i915_dependency *
-i915_dependency_alloc(struct drm_i915_private *i915)
-{
-       return kmem_cache_alloc(i915->dependencies, GFP_KERNEL);
-}
-
-static void
-i915_dependency_free(struct drm_i915_private *i915,
-                    struct i915_dependency *dep)
-{
-       kmem_cache_free(i915->dependencies, dep);
-}
-
-static void
-__i915_sched_node_add_dependency(struct i915_sched_node *node,
-                                struct i915_sched_node *signal,
-                                struct i915_dependency *dep,
-                                unsigned long flags)
-{
-       INIT_LIST_HEAD(&dep->dfs_link);
-       list_add(&dep->wait_link, &signal->waiters_list);
-       list_add(&dep->signal_link, &node->signalers_list);
-       dep->signaler = signal;
-       dep->flags = flags;
-}
-
-static int
-i915_sched_node_add_dependency(struct drm_i915_private *i915,
-                              struct i915_sched_node *node,
-                              struct i915_sched_node *signal)
-{
-       struct i915_dependency *dep;
-
-       dep = i915_dependency_alloc(i915);
-       if (!dep)
-               return -ENOMEM;
-
-       __i915_sched_node_add_dependency(node, signal, dep,
-                                        I915_DEPENDENCY_ALLOC);
-       return 0;
-}
-
-static void
-i915_sched_node_fini(struct drm_i915_private *i915,
-                    struct i915_sched_node *node)
-{
-       struct i915_dependency *dep, *tmp;
-
-       GEM_BUG_ON(!list_empty(&node->link));
-
-       /*
-        * Everyone we depended upon (the fences we wait to be signaled)
-        * should retire before us and remove themselves from our list.
-        * However, retirement is run independently on each timeline and
-        * so we may be called out-of-order.
-        */
-       list_for_each_entry_safe(dep, tmp, &node->signalers_list, signal_link) {
-               GEM_BUG_ON(!i915_sched_node_signaled(dep->signaler));
-               GEM_BUG_ON(!list_empty(&dep->dfs_link));
-
-               list_del(&dep->wait_link);
-               if (dep->flags & I915_DEPENDENCY_ALLOC)
-                       i915_dependency_free(i915, dep);
-       }
-
-       /* Remove ourselves from everyone who depends upon us */
-       list_for_each_entry_safe(dep, tmp, &node->waiters_list, wait_link) {
-               GEM_BUG_ON(dep->signaler != node);
-               GEM_BUG_ON(!list_empty(&dep->dfs_link));
-
-               list_del(&dep->signal_link);
-               if (dep->flags & I915_DEPENDENCY_ALLOC)
-                       i915_dependency_free(i915, dep);
-       }
-}
-
-static void
-i915_sched_node_init(struct i915_sched_node *node)
-{
-       INIT_LIST_HEAD(&node->signalers_list);
-       INIT_LIST_HEAD(&node->waiters_list);
-       INIT_LIST_HEAD(&node->link);
-       node->attr.priority = I915_PRIORITY_INVALID;
-}
-
 static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
 {
        struct intel_engine_cs *engine;
@@ -221,6 +136,11 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
                          intel_engine_get_seqno(engine),
                          seqno);
 
+               if (seqno == engine->timeline.seqno)
+                       continue;
+
+               kthread_park(engine->breadcrumbs.signaler);
+
                if (!i915_seqno_passed(seqno, engine->timeline.seqno)) {
                        /* Flush any waiters before we reuse the seqno */
                        intel_engine_disarm_breadcrumbs(engine);
@@ -235,6 +155,8 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
                /* Finally reset hw state */
                intel_engine_init_global_seqno(engine, seqno);
                engine->timeline.seqno = seqno;
+
+               kthread_unpark(engine->breadcrumbs.signaler);
        }
 
        list_for_each_entry(timeline, &i915->gt.timelines, link)
@@ -740,17 +662,6 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
                if (rq)
                        cond_synchronize_rcu(rq->rcustate);
 
-               /*
-                * We've forced the client to stall and catch up with whatever
-                * backlog there might have been. As we are assuming that we
-                * caused the mempressure, now is an opportune time to
-                * recover as much memory from the request pool as is possible.
-                * Having already penalized the client to stall, we spend
-                * a little extra time to re-optimise page allocation.
-                */
-               kmem_cache_shrink(i915->requests);
-               rcu_barrier(); /* Recover the TYPESAFE_BY_RCU pages */
-
                rq = kmem_cache_alloc(i915->requests, GFP_KERNEL);
                if (!rq) {
                        ret = -ENOMEM;
@@ -1127,8 +1038,20 @@ void i915_request_add(struct i915_request *request)
         */
        local_bh_disable();
        rcu_read_lock(); /* RCU serialisation for set-wedged protection */
-       if (engine->schedule)
-               engine->schedule(request, &request->gem_context->sched);
+       if (engine->schedule) {
+               struct i915_sched_attr attr = request->gem_context->sched;
+
+               /*
+                * Boost priorities to new clients (new request flows).
+                *
+                * Allow interactive/synchronous clients to jump ahead of
+                * the bulk clients. (FQ_CODEL)
+                */
+               if (!prev || i915_request_completed(prev))
+                       attr.priority |= I915_PRIORITY_NEWCLIENT;
+
+               engine->schedule(request, &attr);
+       }
        rcu_read_unlock();
        i915_sw_fence_commit(&request->submit);
        local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
@@ -1310,6 +1233,8 @@ long i915_request_wait(struct i915_request *rq,
                add_wait_queue(errq, &reset);
 
        intel_wait_init(&wait);
+       if (flags & I915_WAIT_PRIORITY)
+               i915_schedule_bump_priority(rq, I915_PRIORITY_WAIT);
 
 restart:
        do {
index 7fa94b0249683b476142fc1213f86e0d6abac013..90e9d170a0cd5e00645842e3955df058e4a8b338 100644 (file)
@@ -277,8 +277,9 @@ long i915_request_wait(struct i915_request *rq,
        __attribute__((nonnull(1)));
 #define I915_WAIT_INTERRUPTIBLE        BIT(0)
 #define I915_WAIT_LOCKED       BIT(1) /* struct_mutex held, handle GPU reset */
-#define I915_WAIT_ALL          BIT(2) /* used by i915_gem_object_wait() */
-#define I915_WAIT_FOR_IDLE_BOOST BIT(3)
+#define I915_WAIT_PRIORITY     BIT(2) /* small priority bump for the request */
+#define I915_WAIT_ALL          BIT(3) /* used by i915_gem_object_wait() */
+#define I915_WAIT_FOR_IDLE_BOOST BIT(4)
 
 static inline bool intel_engine_has_started(struct intel_engine_cs *engine,
                                            u32 seqno);
@@ -332,14 +333,6 @@ static inline bool i915_request_completed(const struct i915_request *rq)
        return __i915_request_completed(rq, seqno);
 }
 
-static inline bool i915_sched_node_signaled(const struct i915_sched_node *node)
-{
-       const struct i915_request *rq =
-               container_of(node, const struct i915_request, sched);
-
-       return i915_request_completed(rq);
-}
-
 void i915_retire_requests(struct drm_i915_private *i915);
 
 /*
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
new file mode 100644 (file)
index 0000000..340faea
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include <linux/mutex.h>
+
+#include "i915_drv.h"
+#include "i915_request.h"
+#include "i915_scheduler.h"
+
+static DEFINE_SPINLOCK(schedule_lock);
+
+static const struct i915_request *
+node_to_request(const struct i915_sched_node *node)
+{
+       return container_of(node, const struct i915_request, sched);
+}
+
+static inline bool node_signaled(const struct i915_sched_node *node)
+{
+       return i915_request_completed(node_to_request(node));
+}
+
+void i915_sched_node_init(struct i915_sched_node *node)
+{
+       INIT_LIST_HEAD(&node->signalers_list);
+       INIT_LIST_HEAD(&node->waiters_list);
+       INIT_LIST_HEAD(&node->link);
+       node->attr.priority = I915_PRIORITY_INVALID;
+}
+
+static struct i915_dependency *
+i915_dependency_alloc(struct drm_i915_private *i915)
+{
+       return kmem_cache_alloc(i915->dependencies, GFP_KERNEL);
+}
+
+static void
+i915_dependency_free(struct drm_i915_private *i915,
+                    struct i915_dependency *dep)
+{
+       kmem_cache_free(i915->dependencies, dep);
+}
+
+bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
+                                     struct i915_sched_node *signal,
+                                     struct i915_dependency *dep,
+                                     unsigned long flags)
+{
+       bool ret = false;
+
+       spin_lock(&schedule_lock);
+
+       if (!node_signaled(signal)) {
+               INIT_LIST_HEAD(&dep->dfs_link);
+               list_add(&dep->wait_link, &signal->waiters_list);
+               list_add(&dep->signal_link, &node->signalers_list);
+               dep->signaler = signal;
+               dep->flags = flags;
+
+               ret = true;
+       }
+
+       spin_unlock(&schedule_lock);
+
+       return ret;
+}
+
+int i915_sched_node_add_dependency(struct drm_i915_private *i915,
+                                  struct i915_sched_node *node,
+                                  struct i915_sched_node *signal)
+{
+       struct i915_dependency *dep;
+
+       dep = i915_dependency_alloc(i915);
+       if (!dep)
+               return -ENOMEM;
+
+       if (!__i915_sched_node_add_dependency(node, signal, dep,
+                                             I915_DEPENDENCY_ALLOC))
+               i915_dependency_free(i915, dep);
+
+       return 0;
+}
+
+void i915_sched_node_fini(struct drm_i915_private *i915,
+                         struct i915_sched_node *node)
+{
+       struct i915_dependency *dep, *tmp;
+
+       GEM_BUG_ON(!list_empty(&node->link));
+
+       spin_lock(&schedule_lock);
+
+       /*
+        * Everyone we depended upon (the fences we wait to be signaled)
+        * should retire before us and remove themselves from our list.
+        * However, retirement is run independently on each timeline and
+        * so we may be called out-of-order.
+        */
+       list_for_each_entry_safe(dep, tmp, &node->signalers_list, signal_link) {
+               GEM_BUG_ON(!node_signaled(dep->signaler));
+               GEM_BUG_ON(!list_empty(&dep->dfs_link));
+
+               list_del(&dep->wait_link);
+               if (dep->flags & I915_DEPENDENCY_ALLOC)
+                       i915_dependency_free(i915, dep);
+       }
+
+       /* Remove ourselves from everyone who depends upon us */
+       list_for_each_entry_safe(dep, tmp, &node->waiters_list, wait_link) {
+               GEM_BUG_ON(dep->signaler != node);
+               GEM_BUG_ON(!list_empty(&dep->dfs_link));
+
+               list_del(&dep->signal_link);
+               if (dep->flags & I915_DEPENDENCY_ALLOC)
+                       i915_dependency_free(i915, dep);
+       }
+
+       spin_unlock(&schedule_lock);
+}
+
+static inline struct i915_priolist *to_priolist(struct rb_node *rb)
+{
+       return rb_entry(rb, struct i915_priolist, node);
+}
+
+static void assert_priolists(struct intel_engine_execlists * const execlists,
+                            long queue_priority)
+{
+       struct rb_node *rb;
+       long last_prio, i;
+
+       if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
+               return;
+
+       GEM_BUG_ON(rb_first_cached(&execlists->queue) !=
+                  rb_first(&execlists->queue.rb_root));
+
+       last_prio = (queue_priority >> I915_USER_PRIORITY_SHIFT) + 1;
+       for (rb = rb_first_cached(&execlists->queue); rb; rb = rb_next(rb)) {
+               const struct i915_priolist *p = to_priolist(rb);
+
+               GEM_BUG_ON(p->priority >= last_prio);
+               last_prio = p->priority;
+
+               GEM_BUG_ON(!p->used);
+               for (i = 0; i < ARRAY_SIZE(p->requests); i++) {
+                       if (list_empty(&p->requests[i]))
+                               continue;
+
+                       GEM_BUG_ON(!(p->used & BIT(i)));
+               }
+       }
+}
+
+struct list_head *
+i915_sched_lookup_priolist(struct intel_engine_cs *engine, int prio)
+{
+       struct intel_engine_execlists * const execlists = &engine->execlists;
+       struct i915_priolist *p;
+       struct rb_node **parent, *rb;
+       bool first = true;
+       int idx, i;
+
+       lockdep_assert_held(&engine->timeline.lock);
+       assert_priolists(execlists, INT_MAX);
+
+       /* buckets sorted from highest [in slot 0] to lowest priority */
+       idx = I915_PRIORITY_COUNT - (prio & I915_PRIORITY_MASK) - 1;
+       prio >>= I915_USER_PRIORITY_SHIFT;
+       if (unlikely(execlists->no_priolist))
+               prio = I915_PRIORITY_NORMAL;
+
+find_priolist:
+       /* most positive priority is scheduled first, equal priorities fifo */
+       rb = NULL;
+       parent = &execlists->queue.rb_root.rb_node;
+       while (*parent) {
+               rb = *parent;
+               p = to_priolist(rb);
+               if (prio > p->priority) {
+                       parent = &rb->rb_left;
+               } else if (prio < p->priority) {
+                       parent = &rb->rb_right;
+                       first = false;
+               } else {
+                       goto out;
+               }
+       }
+
+       if (prio == I915_PRIORITY_NORMAL) {
+               p = &execlists->default_priolist;
+       } else {
+               p = kmem_cache_alloc(engine->i915->priorities, GFP_ATOMIC);
+               /* Convert an allocation failure to a priority bump */
+               if (unlikely(!p)) {
+                       prio = I915_PRIORITY_NORMAL; /* recurses just once */
+
+                       /* To maintain ordering with all rendering, after an
+                        * allocation failure we have to disable all scheduling.
+                        * Requests will then be executed in fifo, and schedule
+                        * will ensure that dependencies are emitted in fifo.
+                        * There will be still some reordering with existing
+                        * requests, so if userspace lied about their
+                        * dependencies that reordering may be visible.
+                        */
+                       execlists->no_priolist = true;
+                       goto find_priolist;
+               }
+       }
+
+       p->priority = prio;
+       for (i = 0; i < ARRAY_SIZE(p->requests); i++)
+               INIT_LIST_HEAD(&p->requests[i]);
+       rb_link_node(&p->node, rb, parent);
+       rb_insert_color_cached(&p->node, &execlists->queue, first);
+       p->used = 0;
+
+out:
+       p->used |= BIT(idx);
+       return &p->requests[idx];
+}
+
+static struct intel_engine_cs *
+sched_lock_engine(struct i915_sched_node *node, struct intel_engine_cs *locked)
+{
+       struct intel_engine_cs *engine = node_to_request(node)->engine;
+
+       GEM_BUG_ON(!locked);
+
+       if (engine != locked) {
+               spin_unlock(&locked->timeline.lock);
+               spin_lock(&engine->timeline.lock);
+       }
+
+       return engine;
+}
+
+static void __i915_schedule(struct i915_request *rq,
+                           const struct i915_sched_attr *attr)
+{
+       struct list_head *uninitialized_var(pl);
+       struct intel_engine_cs *engine, *last;
+       struct i915_dependency *dep, *p;
+       struct i915_dependency stack;
+       const int prio = attr->priority;
+       LIST_HEAD(dfs);
+
+       /* Needed in order to use the temporary link inside i915_dependency */
+       lockdep_assert_held(&schedule_lock);
+       GEM_BUG_ON(prio == I915_PRIORITY_INVALID);
+
+       if (i915_request_completed(rq))
+               return;
+
+       if (prio <= READ_ONCE(rq->sched.attr.priority))
+               return;
+
+       stack.signaler = &rq->sched;
+       list_add(&stack.dfs_link, &dfs);
+
+       /*
+        * Recursively bump all dependent priorities to match the new request.
+        *
+        * A naive approach would be to use recursion:
+        * static void update_priorities(struct i915_sched_node *node, prio) {
+        *      list_for_each_entry(dep, &node->signalers_list, signal_link)
+        *              update_priorities(dep->signal, prio)
+        *      queue_request(node);
+        * }
+        * but that may have unlimited recursion depth and so runs a very
+        * real risk of overunning the kernel stack. Instead, we build
+        * a flat list of all dependencies starting with the current request.
+        * As we walk the list of dependencies, we add all of its dependencies
+        * to the end of the list (this may include an already visited
+        * request) and continue to walk onwards onto the new dependencies. The
+        * end result is a topological list of requests in reverse order, the
+        * last element in the list is the request we must execute first.
+        */
+       list_for_each_entry(dep, &dfs, dfs_link) {
+               struct i915_sched_node *node = dep->signaler;
+
+               /*
+                * Within an engine, there can be no cycle, but we may
+                * refer to the same dependency chain multiple times
+                * (redundant dependencies are not eliminated) and across
+                * engines.
+                */
+               list_for_each_entry(p, &node->signalers_list, signal_link) {
+                       GEM_BUG_ON(p == dep); /* no cycles! */
+
+                       if (node_signaled(p->signaler))
+                               continue;
+
+                       GEM_BUG_ON(p->signaler->attr.priority < node->attr.priority);
+                       if (prio > READ_ONCE(p->signaler->attr.priority))
+                               list_move_tail(&p->dfs_link, &dfs);
+               }
+       }
+
+       /*
+        * If we didn't need to bump any existing priorities, and we haven't
+        * yet submitted this request (i.e. there is no potential race with
+        * execlists_submit_request()), we can set our own priority and skip
+        * acquiring the engine locks.
+        */
+       if (rq->sched.attr.priority == I915_PRIORITY_INVALID) {
+               GEM_BUG_ON(!list_empty(&rq->sched.link));
+               rq->sched.attr = *attr;
+
+               if (stack.dfs_link.next == stack.dfs_link.prev)
+                       return;
+
+               __list_del_entry(&stack.dfs_link);
+       }
+
+       last = NULL;
+       engine = rq->engine;
+       spin_lock_irq(&engine->timeline.lock);
+
+       /* Fifo and depth-first replacement ensure our deps execute before us */
+       list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
+               struct i915_sched_node *node = dep->signaler;
+
+               INIT_LIST_HEAD(&dep->dfs_link);
+
+               engine = sched_lock_engine(node, engine);
+
+               /* Recheck after acquiring the engine->timeline.lock */
+               if (prio <= node->attr.priority || node_signaled(node))
+                       continue;
+
+               node->attr.priority = prio;
+               if (!list_empty(&node->link)) {
+                       if (last != engine) {
+                               pl = i915_sched_lookup_priolist(engine, prio);
+                               last = engine;
+                       }
+                       list_move_tail(&node->link, pl);
+               } else {
+                       /*
+                        * If the request is not in the priolist queue because
+                        * it is not yet runnable, then it doesn't contribute
+                        * to our preemption decisions. On the other hand,
+                        * if the request is on the HW, it too is not in the
+                        * queue; but in that case we may still need to reorder
+                        * the inflight requests.
+                        */
+                       if (!i915_sw_fence_done(&node_to_request(node)->submit))
+                               continue;
+               }
+
+               if (prio <= engine->execlists.queue_priority)
+                       continue;
+
+               /*
+                * If we are already the currently executing context, don't
+                * bother evaluating if we should preempt ourselves.
+                */
+               if (node_to_request(node)->global_seqno &&
+                   i915_seqno_passed(port_request(engine->execlists.port)->global_seqno,
+                                     node_to_request(node)->global_seqno))
+                       continue;
+
+               /* Defer (tasklet) submission until after all of our updates. */
+               engine->execlists.queue_priority = prio;
+               tasklet_hi_schedule(&engine->execlists.tasklet);
+       }
+
+       spin_unlock_irq(&engine->timeline.lock);
+}
+
+void i915_schedule(struct i915_request *rq, const struct i915_sched_attr *attr)
+{
+       spin_lock(&schedule_lock);
+       __i915_schedule(rq, attr);
+       spin_unlock(&schedule_lock);
+}
+
+void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump)
+{
+       struct i915_sched_attr attr;
+
+       GEM_BUG_ON(bump & ~I915_PRIORITY_MASK);
+
+       if (READ_ONCE(rq->sched.attr.priority) == I915_PRIORITY_INVALID)
+               return;
+
+       spin_lock_bh(&schedule_lock);
+
+       attr = rq->sched.attr;
+       attr.priority |= bump;
+       __i915_schedule(rq, &attr);
+
+       spin_unlock_bh(&schedule_lock);
+}
index 70a42220358d894170e63aa64724f142942ef940..dbe9cb7ecd82928bc83be7b042994a1566724d82 100644 (file)
@@ -8,9 +8,14 @@
 #define _I915_SCHEDULER_H_
 
 #include <linux/bitops.h>
+#include <linux/kernel.h>
 
 #include <uapi/drm/i915_drm.h>
 
+struct drm_i915_private;
+struct i915_request;
+struct intel_engine_cs;
+
 enum {
        I915_PRIORITY_MIN = I915_CONTEXT_MIN_USER_PRIORITY - 1,
        I915_PRIORITY_NORMAL = I915_CONTEXT_DEFAULT_PRIORITY,
@@ -19,6 +24,15 @@ enum {
        I915_PRIORITY_INVALID = INT_MIN
 };
 
+#define I915_USER_PRIORITY_SHIFT 2
+#define I915_USER_PRIORITY(x) ((x) << I915_USER_PRIORITY_SHIFT)
+
+#define I915_PRIORITY_COUNT BIT(I915_USER_PRIORITY_SHIFT)
+#define I915_PRIORITY_MASK (I915_PRIORITY_COUNT - 1)
+
+#define I915_PRIORITY_WAIT     ((u8)BIT(0))
+#define I915_PRIORITY_NEWCLIENT        ((u8)BIT(1))
+
 struct i915_sched_attr {
        /**
         * @priority: execution and service priority
@@ -69,4 +83,26 @@ struct i915_dependency {
 #define I915_DEPENDENCY_ALLOC BIT(0)
 };
 
+void i915_sched_node_init(struct i915_sched_node *node);
+
+bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
+                                     struct i915_sched_node *signal,
+                                     struct i915_dependency *dep,
+                                     unsigned long flags);
+
+int i915_sched_node_add_dependency(struct drm_i915_private *i915,
+                                  struct i915_sched_node *node,
+                                  struct i915_sched_node *signal);
+
+void i915_sched_node_fini(struct drm_i915_private *i915,
+                         struct i915_sched_node *node);
+
+void i915_schedule(struct i915_request *request,
+                  const struct i915_sched_attr *attr);
+
+void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump);
+
+struct list_head *
+i915_sched_lookup_priolist(struct intel_engine_cs *engine, int prio);
+
 #endif /* _I915_SCHEDULER_H_ */
index 6dbeed079ae53fc35d7cb692879421adfce04bfc..fc2eeab823b70e505beed80a77b6e08f56bc2810 100644 (file)
@@ -1,10 +1,7 @@
 /*
- * (C) Copyright 2016 Intel Corporation
+ * SPDX-License-Identifier: MIT
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
+ * (C) Copyright 2016 Intel Corporation
  */
 
 #include <linux/slab.h>
index fe2ef4dadfc635c28ba3e47382f85feeb9c6a094..0e055ea0179f321a4aafc8b95a667f8bbc8543f6 100644 (file)
@@ -1,10 +1,9 @@
 /*
+ * SPDX-License-Identifier: MIT
+ *
  * i915_sw_fence.h - library routines for N:M synchronisation points
  *
  * Copyright (C) 2016 Intel Corporation
- *
- * This file is released under the GPLv2.
- *
  */
 
 #ifndef _I915_SW_FENCE_H_
index 58f8d0cc125c0e6e58a30973d8443037208f4bb4..60404dbb2e9fa9f3484989cdfe34bacd202d0ca9 100644 (file)
@@ -92,7 +92,7 @@ void i915_syncmap_init(struct i915_syncmap **root)
 {
        BUILD_BUG_ON_NOT_POWER_OF_2(KSYNCMAP);
        BUILD_BUG_ON_NOT_POWER_OF_2(SHIFT);
-       BUILD_BUG_ON(KSYNCMAP > BITS_PER_BYTE * sizeof((*root)->bitmap));
+       BUILD_BUG_ON(KSYNCMAP > BITS_PER_TYPE((*root)->bitmap));
        *root = NULL;
 }
 
index e5e6f6bb2b05a62039652c260a2accd51e2b2c95..535caebd9813af5d82701b1d7e47b987563cd608 100644 (file)
@@ -483,7 +483,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
-static const struct attribute *gen6_attrs[] = {
+static const struct attribute * const gen6_attrs[] = {
        &dev_attr_gt_act_freq_mhz.attr,
        &dev_attr_gt_cur_freq_mhz.attr,
        &dev_attr_gt_boost_freq_mhz.attr,
@@ -495,7 +495,7 @@ static const struct attribute *gen6_attrs[] = {
        NULL,
 };
 
-static const struct attribute *vlv_attrs[] = {
+static const struct attribute * const vlv_attrs[] = {
        &dev_attr_gt_act_freq_mhz.attr,
        &dev_attr_gt_cur_freq_mhz.attr,
        &dev_attr_gt_boost_freq_mhz.attr,
@@ -516,26 +516,21 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
 {
 
        struct device *kdev = kobj_to_dev(kobj);
-       struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
-       struct drm_i915_error_state_buf error_str;
+       struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
        struct i915_gpu_state *gpu;
        ssize_t ret;
 
-       ret = i915_error_state_buf_init(&error_str, dev_priv, count, off);
-       if (ret)
-               return ret;
-
-       gpu = i915_first_error_state(dev_priv);
-       ret = i915_error_state_to_str(&error_str, gpu);
-       if (ret)
-               goto out;
-
-       ret = count < error_str.bytes ? count : error_str.bytes;
-       memcpy(buf, error_str.buf, ret);
+       gpu = i915_first_error_state(i915);
+       if (gpu) {
+               ret = i915_gpu_state_copy_to_buffer(gpu, buf, off, count);
+               i915_gpu_state_put(gpu);
+       } else {
+               const char *str = "No error state collected\n";
+               size_t len = strlen(str);
 
-out:
-       i915_gpu_state_put(gpu);
-       i915_error_state_buf_release(&error_str);
+               ret = min_t(size_t, count, len - off);
+               memcpy(buf, str + off, ret);
+       }
 
        return ret;
 }
index a2c2c3ab5fb0ceea22c2c1426b1c307b5d1aa460..ebd71b487220aec95a2bfdeb1c924f0836ae64c1 100644 (file)
@@ -83,6 +83,25 @@ void i915_timeline_init(struct drm_i915_private *i915,
                        const char *name);
 void i915_timeline_fini(struct i915_timeline *tl);
 
+static inline void
+i915_timeline_set_subclass(struct i915_timeline *timeline,
+                          unsigned int subclass)
+{
+       lockdep_set_subclass(&timeline->lock, subclass);
+
+       /*
+        * Due to an interesting quirk in lockdep's internal debug tracking,
+        * after setting a subclass we must ensure the lock is used. Otherwise,
+        * nr_unused_locks is incremented once too often.
+        */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       local_irq_disable();
+       lock_map_acquire(&timeline->lock.dep_map);
+       lock_map_release(&timeline->lock.dep_map);
+       local_irq_enable();
+#endif
+}
+
 struct i915_timeline *
 i915_timeline_create(struct drm_i915_private *i915, const char *name);
 
index 395dd251156833d46a48de3e49163c22a6627bc8..9726df37c4c41b2ce2316a2fd6438363275e654c 100644 (file)
                             __stringify(x), (long)(x))
 
 #if defined(GCC_VERSION) && GCC_VERSION >= 70000
-#define add_overflows(A, B) \
-       __builtin_add_overflow_p((A), (B), (typeof((A) + (B)))0)
+#define add_overflows_t(T, A, B) \
+       __builtin_add_overflow_p((A), (B), (T)0)
 #else
-#define add_overflows(A, B) ({ \
+#define add_overflows_t(T, A, B) ({ \
        typeof(A) a = (A); \
        typeof(B) b = (B); \
-       a + b < a; \
+       (T)(a + b) < a; \
 })
 #endif
 
+#define add_overflows(A, B) \
+       add_overflows_t(typeof((A) + (B)), (A), (B))
+
 #define range_overflows(start, size, max) ({ \
        typeof(start) start__ = (start); \
        typeof(size) size__ = (size); \
@@ -68,7 +71,7 @@
 
 /* Note we don't consider signbits :| */
 #define overflows_type(x, T) \
-       (sizeof(x) > sizeof(T) && (x) >> (sizeof(T) * BITS_PER_BYTE))
+       (sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T))
 
 #define ptr_mask_bits(ptr, n) ({                                       \
        unsigned long __v = (unsigned long)(ptr);                       \
index 31efc971a3a83897b545c49142fc0e1366641521..5b4d78cdb4ca32c4162322b4750e2dec80fe99d1 100644 (file)
@@ -305,12 +305,12 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
        GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
        GEM_BUG_ON(vma->size > vma->node.size);
 
-       if (GEM_WARN_ON(range_overflows(vma->node.start,
-                                       vma->node.size,
-                                       vma->vm->total)))
+       if (GEM_DEBUG_WARN_ON(range_overflows(vma->node.start,
+                                             vma->node.size,
+                                             vma->vm->total)))
                return -ENODEV;
 
-       if (GEM_WARN_ON(!flags))
+       if (GEM_DEBUG_WARN_ON(!flags))
                return -EINVAL;
 
        bind_flags = 0;
@@ -892,7 +892,7 @@ static void export_fence(struct i915_vma *vma,
        reservation_object_lock(resv, NULL);
        if (flags & EXEC_OBJECT_WRITE)
                reservation_object_add_excl_fence(resv, &rq->fence);
-       else if (reservation_object_reserve_shared(resv) == 0)
+       else if (reservation_object_reserve_shared(resv, 1) == 0)
                reservation_object_add_shared_fence(resv, &rq->fence);
        reservation_object_unlock(resv);
 }
index 13830e43a4d12a8fa59ff4c131aa3cddeff8fe10..4dd793b789962873a3523222336ba7a5d99a0677 100644 (file)
  *   Jani Nikula <jani.nikula@intel.com>
  */
 
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_atomic_helper.h>
 #include "intel_dsi.h"
 
+static inline int header_credits_available(struct drm_i915_private *dev_priv,
+                                          enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK)
+               >> FREE_HEADER_CREDIT_SHIFT;
+}
+
+static inline int payload_credits_available(struct drm_i915_private *dev_priv,
+                                           enum transcoder dsi_trans)
+{
+       return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK)
+               >> FREE_PLOAD_CREDIT_SHIFT;
+}
+
+static void wait_for_header_credits(struct drm_i915_private *dev_priv,
+                                   enum transcoder dsi_trans)
+{
+       if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >=
+                       MAX_HEADER_CREDIT, 100))
+               DRM_ERROR("DSI header credits not released\n");
+}
+
+static void wait_for_payload_credits(struct drm_i915_private *dev_priv,
+                                    enum transcoder dsi_trans)
+{
+       if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >=
+                       MAX_PLOAD_CREDIT, 100))
+               DRM_ERROR("DSI payload credits not released\n");
+}
+
+static enum transcoder dsi_port_to_transcoder(enum port port)
+{
+       if (port == PORT_A)
+               return TRANSCODER_DSI_0;
+       else
+               return TRANSCODER_DSI_1;
+}
+
+static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi;
+       enum port port;
+       enum transcoder dsi_trans;
+       int ret;
+
+       /* wait for header/payload credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+               wait_for_payload_credits(dev_priv, dsi_trans);
+       }
+
+       /* send nop DCS command */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi = intel_dsi->dsi_hosts[port]->device;
+               dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+               dsi->channel = 0;
+               ret = mipi_dsi_dcs_nop(dsi);
+               if (ret < 0)
+                       DRM_ERROR("error sending DCS NOP command\n");
+       }
+
+       /* wait for header credits to be released */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               wait_for_header_credits(dev_priv, dsi_trans);
+       }
+
+       /* wait for LP TX in progress bit to be cleared */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) &
+                                 LPTX_IN_PROGRESS), 20))
+                       DRM_ERROR("LPTX bit not cleared\n");
+       }
+}
+
+static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data,
+                              u32 len)
+{
+       struct intel_dsi *intel_dsi = host->intel_dsi;
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
+       int free_credits;
+       int i, j;
+
+       for (i = 0; i < len; i += 4) {
+               u32 tmp = 0;
+
+               free_credits = payload_credits_available(dev_priv, dsi_trans);
+               if (free_credits < 1) {
+                       DRM_ERROR("Payload credit not available\n");
+                       return false;
+               }
+
+               for (j = 0; j < min_t(u32, len - i, 4); j++)
+                       tmp |= *data++ << 8 * j;
+
+               I915_WRITE(DSI_CMD_TXPYLD(dsi_trans), tmp);
+       }
+
+       return true;
+}
+
+static int dsi_send_pkt_hdr(struct intel_dsi_host *host,
+                           struct mipi_dsi_packet pkt, bool enable_lpdt)
+{
+       struct intel_dsi *intel_dsi = host->intel_dsi;
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       enum transcoder dsi_trans = dsi_port_to_transcoder(host->port);
+       u32 tmp;
+       int free_credits;
+
+       /* check if header credit available */
+       free_credits = header_credits_available(dev_priv, dsi_trans);
+       if (free_credits < 1) {
+               DRM_ERROR("send pkt header failed, not enough hdr credits\n");
+               return -1;
+       }
+
+       tmp = I915_READ(DSI_CMD_TXHDR(dsi_trans));
+
+       if (pkt.payload)
+               tmp |= PAYLOAD_PRESENT;
+       else
+               tmp &= ~PAYLOAD_PRESENT;
+
+       tmp &= ~VBLANK_FENCE;
+
+       if (enable_lpdt)
+               tmp |= LP_DATA_TRANSFER;
+
+       tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK);
+       tmp |= ((pkt.header[0] & VC_MASK) << VC_SHIFT);
+       tmp |= ((pkt.header[0] & DT_MASK) << DT_SHIFT);
+       tmp |= (pkt.header[1] << PARAM_WC_LOWER_SHIFT);
+       tmp |= (pkt.header[2] << PARAM_WC_UPPER_SHIFT);
+       I915_WRITE(DSI_CMD_TXHDR(dsi_trans), tmp);
+
+       return 0;
+}
+
+static int dsi_send_pkt_payld(struct intel_dsi_host *host,
+                             struct mipi_dsi_packet pkt)
+{
+       /* payload queue can accept *256 bytes*, check limit */
+       if (pkt.payload_length > MAX_PLOAD_CREDIT * 4) {
+               DRM_ERROR("payload size exceeds max queue limit\n");
+               return -1;
+       }
+
+       /* load data into command payload queue */
+       if (!add_payld_to_queue(host, pkt.payload,
+                               pkt.payload_length)) {
+               DRM_ERROR("adding payload to queue failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+
+               /*
+                * Program voltage swing and pre-emphasis level values as per
+                * table in BSPEC under DDI buffer programing
+                */
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK);
+               tmp |= SCALING_MODE_SEL(0x2);
+               tmp |= TAP2_DISABLE | TAP3_DISABLE;
+               tmp |= RTERM_SELECT(0x6);
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK |
+                        RCOMP_SCALAR_MASK);
+               tmp |= SWING_SEL_UPPER(0x2);
+               tmp |= SWING_SEL_LOWER(0x2);
+               tmp |= RCOMP_SCALAR(0x98);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                        CURSOR_COEFF_MASK);
+               tmp |= POST_CURSOR_1(0x0);
+               tmp |= POST_CURSOR_2(0x0);
+               tmp |= CURSOR_COEFF(0x3f);
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+
+               for (lane = 0; lane <= 3; lane++) {
+                       /* Bspec: must not use GRP register for write */
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
+                       tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK |
+                                CURSOR_COEFF_MASK);
+                       tmp |= POST_CURSOR_1(0x0);
+                       tmp |= POST_CURSOR_2(0x0);
+                       tmp |= CURSOR_COEFF(0x3f);
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
+               }
+       }
+}
+
+static void configure_dual_link_mode(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 dss_ctl1;
+
+       dss_ctl1 = I915_READ(DSS_CTL1);
+       dss_ctl1 |= SPLITTER_ENABLE;
+       dss_ctl1 &= ~OVERLAP_PIXELS_MASK;
+       dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap);
+
+       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+               const struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+               u32 dss_ctl2;
+               u16 hactive = adjusted_mode->crtc_hdisplay;
+               u16 dl_buffer_depth;
+
+               dss_ctl1 &= ~DUAL_LINK_MODE_INTERLEAVE;
+               dl_buffer_depth = hactive / 2 + intel_dsi->pixel_overlap;
+
+               if (dl_buffer_depth > MAX_DL_BUFFER_TARGET_DEPTH)
+                       DRM_ERROR("DL buffer depth exceed max value\n");
+
+               dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK;
+               dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
+               dss_ctl2 = I915_READ(DSS_CTL2);
+               dss_ctl2 &= ~RIGHT_DL_BUF_TARGET_DEPTH_MASK;
+               dss_ctl2 |= RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth);
+               I915_WRITE(DSS_CTL2, dss_ctl2);
+       } else {
+               /* Interleave */
+               dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE;
+       }
+
+       I915_WRITE(DSS_CTL1, dss_ctl1);
+}
+
 static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -105,23 +374,1079 @@ static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
        }
 }
 
-static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder)
+static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       int lane;
+
+       /* Step 4b(i) set loadgen select for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port));
+               tmp &= ~LOADGEN_SELECT;
+               I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp);
+               for (lane = 0; lane <= 3; lane++) {
+                       tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane));
+                       tmp &= ~LOADGEN_SELECT;
+                       if (lane != 2)
+                               tmp |= LOADGEN_SELECT;
+                       I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp);
+               }
+       }
+
+       /* Step 4b(ii) set latency optimization for transmit and aux lanes */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port));
+               tmp &= ~FRC_LATENCY_OPTIM_MASK;
+               tmp |= FRC_LATENCY_OPTIM_VAL(0x5);
+               I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp);
+       }
+
+}
+
+static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* clear common keeper enable bit */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port));
+               tmp &= ~COMMON_KEEPER_EN;
+               I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp);
+       }
+
+       /*
+        * Set SUS Clock Config bitfield to 11b
+        * Note: loadgen select program is done
+        * as part of lane phy sequence configuration
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_CL_DW5(port));
+               tmp |= SUS_CLOCK_CONFIG;
+               I915_WRITE(ICL_PORT_CL_DW5(port), tmp);
+       }
+
+       /* Clear training enable to change swing values */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp &= ~TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+
+       /* Program swing and de-emphasis */
+       dsi_program_swing_and_deemphasis(encoder);
+
+       /* Set training enable to trigger update */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp);
+               tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port));
+               tmp |= TX_TRAINING_EN;
+               I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp);
+       }
+}
+
+static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(DDI_BUF_CTL(port));
+               tmp |= DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), tmp);
+
+               if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) &
+                                 DDI_BUF_IS_IDLE),
+                                 500))
+                       DRM_ERROR("DDI port:%c buffer idle\n", port_name(port));
+       }
+}
+
+static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       /* Program T-INIT master registers */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port));
+               tmp &= ~MASTER_INIT_TIMER_MASK;
+               tmp |= intel_dsi->init_count;
+               I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp);
+       }
+
+       /* Program DPHY clock lanes timings */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
+
+               /* shadow register inside display core */
+               I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg);
+       }
+
+       /* Program DPHY data lanes timings */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(DPHY_DATA_TIMING_PARAM(port),
+                          intel_dsi->dphy_data_lane_reg);
+
+               /* shadow register inside display core */
+               I915_WRITE(DSI_DATA_TIMING_PARAM(port),
+                          intel_dsi->dphy_data_lane_reg);
+       }
+
+       /*
+        * If DSI link operating at or below an 800 MHz,
+        * TA_SURE should be override and programmed to
+        * a value '0' inside TA_PARAM_REGISTERS otherwise
+        * leave all fields at HW default values.
+        */
+       if (intel_dsi_bitrate(intel_dsi) <= 800000) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       tmp = I915_READ(DPHY_TA_TIMING_PARAM(port));
+                       tmp &= ~TA_SURE_MASK;
+                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
+                       I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp);
+
+                       /* shadow register inside display core */
+                       tmp = I915_READ(DSI_TA_TIMING_PARAM(port));
+                       tmp &= ~TA_SURE_MASK;
+                       tmp |= TA_SURE_OVERRIDE | TA_SURE(0);
+                       I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp);
+               }
+       }
+}
+
+static void gen11_dsi_gate_clocks(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       mutex_lock(&dev_priv->dpll_lock);
+       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp |= DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       }
+
+       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       mutex_lock(&dev_priv->dpll_lock);
+       tmp = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
+       }
+
+       I915_WRITE(DPCLKA_CFGCR0_ICL, tmp);
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void gen11_dsi_map_pll(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+       enum port port;
+       u32 val;
+
+       mutex_lock(&dev_priv->dpll_lock);
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
+       }
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+       POSTING_READ(DPCLKA_CFGCR0_ICL);
+
+       mutex_unlock(&dev_priv->dpll_lock);
+}
+
+static void
+gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
+                              const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       u32 tmp;
+       enum port port;
+       enum transcoder dsi_trans;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans));
+
+               if (intel_dsi->eotp_pkt)
+                       tmp &= ~EOTP_DISABLED;
+               else
+                       tmp |= EOTP_DISABLED;
+
+               /* enable link calibration if freq > 1.5Gbps */
+               if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) {
+                       tmp &= ~LINK_CALIBRATION_MASK;
+                       tmp |= CALIBRATION_ENABLED_INITIAL_ONLY;
+               }
+
+               /* configure continuous clock */
+               tmp &= ~CONTINUOUS_CLK_MASK;
+               if (intel_dsi->clock_stop)
+                       tmp |= CLK_ENTER_LP_AFTER_DATA;
+               else
+                       tmp |= CLK_HS_CONTINUOUS;
+
+               /* configure buffer threshold limit to minimum */
+               tmp &= ~PIX_BUF_THRESHOLD_MASK;
+               tmp |= PIX_BUF_THRESHOLD_1_4;
+
+               /* set virtual channel to '0' */
+               tmp &= ~PIX_VIRT_CHAN_MASK;
+               tmp |= PIX_VIRT_CHAN(0);
+
+               /* program BGR transmission */
+               if (intel_dsi->bgr_enabled)
+                       tmp |= BGR_TRANSMISSION;
+
+               /* select pixel format */
+               tmp &= ~PIX_FMT_MASK;
+               switch (intel_dsi->pixel_format) {
+               default:
+                       MISSING_CASE(intel_dsi->pixel_format);
+                       /* fallthrough */
+               case MIPI_DSI_FMT_RGB565:
+                       tmp |= PIX_FMT_RGB565;
+                       break;
+               case MIPI_DSI_FMT_RGB666_PACKED:
+                       tmp |= PIX_FMT_RGB666_PACKED;
+                       break;
+               case MIPI_DSI_FMT_RGB666:
+                       tmp |= PIX_FMT_RGB666_LOOSE;
+                       break;
+               case MIPI_DSI_FMT_RGB888:
+                       tmp |= PIX_FMT_RGB888;
+                       break;
+               }
+
+               /* program DSI operation mode */
+               if (is_vid_mode(intel_dsi)) {
+                       tmp &= ~OP_MODE_MASK;
+                       switch (intel_dsi->video_mode_format) {
+                       default:
+                               MISSING_CASE(intel_dsi->video_mode_format);
+                               /* fallthrough */
+                       case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS:
+                               tmp |= VIDEO_MODE_SYNC_EVENT;
+                               break;
+                       case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE:
+                               tmp |= VIDEO_MODE_SYNC_PULSE;
+                               break;
+                       }
+               }
+
+               I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp);
+       }
+
+       /* enable port sync mode if dual link */
+       if (intel_dsi->dual_link) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
+                       tmp |= PORT_SYNC_MODE_ENABLE;
+                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
+               }
+
+               /* configure stream splitting */
+               configure_dual_link_mode(encoder, pipe_config);
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* select data lane width */
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               tmp &= ~DDI_PORT_WIDTH_MASK;
+               tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count);
+
+               /* select input pipe */
+               tmp &= ~TRANS_DDI_EDP_INPUT_MASK;
+               switch (pipe) {
+               default:
+                       MISSING_CASE(pipe);
+                       /* fallthrough */
+               case PIPE_A:
+                       tmp |= TRANS_DDI_EDP_INPUT_A_ON;
+                       break;
+               case PIPE_B:
+                       tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
+                       break;
+               case PIPE_C:
+                       tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF;
+                       break;
+               }
+
+               /* enable DDI buffer */
+               tmp |= TRANS_DDI_FUNC_ENABLE;
+               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
+       }
+
+       /* wait for link ready */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) &
+                               LINK_READY), 2500))
+                       DRM_ERROR("DSI link not ready\n");
+       }
+}
+
+static void
+gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       const struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+       enum port port;
+       enum transcoder dsi_trans;
+       /* horizontal timings */
+       u16 htotal, hactive, hsync_start, hsync_end, hsync_size;
+       u16 hfront_porch, hback_porch;
+       /* vertical timings */
+       u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift;
+
+       hactive = adjusted_mode->crtc_hdisplay;
+       htotal = adjusted_mode->crtc_htotal;
+       hsync_start = adjusted_mode->crtc_hsync_start;
+       hsync_end = adjusted_mode->crtc_hsync_end;
+       hsync_size  = hsync_end - hsync_start;
+       hfront_porch = (adjusted_mode->crtc_hsync_start -
+                       adjusted_mode->crtc_hdisplay);
+       hback_porch = (adjusted_mode->crtc_htotal -
+                      adjusted_mode->crtc_hsync_end);
+       vactive = adjusted_mode->crtc_vdisplay;
+       vtotal = adjusted_mode->crtc_vtotal;
+       vsync_start = adjusted_mode->crtc_vsync_start;
+       vsync_end = adjusted_mode->crtc_vsync_end;
+       vsync_shift = hsync_start - htotal / 2;
+
+       if (intel_dsi->dual_link) {
+               hactive /= 2;
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+                       hactive += intel_dsi->pixel_overlap;
+               htotal /= 2;
+       }
+
+       /* minimum hactive as per bspec: 256 pixels */
+       if (adjusted_mode->crtc_hdisplay < 256)
+               DRM_ERROR("hactive is less then 256 pixels\n");
+
+       /* if RGB666 format, then hactive must be multiple of 4 pixels */
+       if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0)
+               DRM_ERROR("hactive pixels are not multiple of 4\n");
+
+       /* program TRANS_HTOTAL register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(HTOTAL(dsi_trans),
+                          (hactive - 1) | ((htotal - 1) << 16));
+       }
+
+       /* TRANS_HSYNC register to be programmed only for video mode */
+       if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) {
+               if (intel_dsi->video_mode_format ==
+                   VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE) {
+                       /* BSPEC: hsync size should be atleast 16 pixels */
+                       if (hsync_size < 16)
+                               DRM_ERROR("hsync size < 16 pixels\n");
+               }
+
+               if (hback_porch < 16)
+                       DRM_ERROR("hback porch < 16 pixels\n");
+
+               if (intel_dsi->dual_link) {
+                       hsync_start /= 2;
+                       hsync_end /= 2;
+               }
+
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       I915_WRITE(HSYNC(dsi_trans),
+                                  (hsync_start - 1) | ((hsync_end - 1) << 16));
+               }
+       }
+
+       /* program TRANS_VTOTAL register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               /*
+                * FIXME: Programing this by assuming progressive mode, since
+                * non-interlaced info from VBT is not saved inside
+                * struct drm_display_mode.
+                * For interlace mode: program required pixel minus 2
+                */
+               I915_WRITE(VTOTAL(dsi_trans),
+                          (vactive - 1) | ((vtotal - 1) << 16));
+       }
+
+       if (vsync_end < vsync_start || vsync_end > vtotal)
+               DRM_ERROR("Invalid vsync_end value\n");
+
+       if (vsync_start < vactive)
+               DRM_ERROR("vsync_start less than vactive\n");
+
+       /* program TRANS_VSYNC register */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(VSYNC(dsi_trans),
+                          (vsync_start - 1) | ((vsync_end - 1) << 16));
+       }
+
+       /*
+        * FIXME: It has to be programmed only for interlaced
+        * modes. Put the check condition here once interlaced
+        * info available as described above.
+        * program TRANS_VSYNCSHIFT register
+        */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               I915_WRITE(VSYNCSHIFT(dsi_trans), vsync_shift);
+       }
+}
+
+static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               tmp |= PIPECONF_ENABLE;
+               I915_WRITE(PIPECONF(dsi_trans), tmp);
+
+               /* wait for transcoder to be enabled */
+               if (intel_wait_for_register(dev_priv, PIPECONF(dsi_trans),
+                                           I965_PIPECONF_ACTIVE,
+                                           I965_PIPECONF_ACTIVE, 10))
+                       DRM_ERROR("DSI transcoder not enabled\n");
+       }
+}
+
+static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp, hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul;
+
+       /*
+        * escape clock count calculation:
+        * BYTE_CLK_COUNT = TIME_NS/(8 * UI)
+        * UI (nsec) = (10^6)/Bitrate
+        * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate
+        * ESCAPE_CLK_COUNT  = TIME_NS/ESC_CLK_NS
+        */
+       divisor = intel_dsi_tlpx_ns(intel_dsi) * intel_dsi_bitrate(intel_dsi) * 1000;
+       mul = 8 * 1000000;
+       hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul,
+                                    divisor);
+       lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor);
+       ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* program hst_tx_timeout */
+               tmp = I915_READ(DSI_HSTX_TO(dsi_trans));
+               tmp &= ~HSTX_TIMEOUT_VALUE_MASK;
+               tmp |= HSTX_TIMEOUT_VALUE(hs_tx_timeout);
+               I915_WRITE(DSI_HSTX_TO(dsi_trans), tmp);
+
+               /* FIXME: DSI_CALIB_TO */
+
+               /* program lp_rx_host timeout */
+               tmp = I915_READ(DSI_LPRX_HOST_TO(dsi_trans));
+               tmp &= ~LPRX_TIMEOUT_VALUE_MASK;
+               tmp |= LPRX_TIMEOUT_VALUE(lp_rx_timeout);
+               I915_WRITE(DSI_LPRX_HOST_TO(dsi_trans), tmp);
+
+               /* FIXME: DSI_PWAIT_TO */
+
+               /* program turn around timeout */
+               tmp = I915_READ(DSI_TA_TO(dsi_trans));
+               tmp &= ~TA_TIMEOUT_VALUE_MASK;
+               tmp |= TA_TIMEOUT_VALUE(ta_timeout);
+               I915_WRITE(DSI_TA_TO(dsi_trans), tmp);
+       }
+}
+
+static void
+gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config)
 {
        /* step 4a: power up all lanes of the DDI used by DSI */
        gen11_dsi_power_up_lanes(encoder);
+
+       /* step 4b: configure lane sequencing of the Combo-PHY transmitters */
+       gen11_dsi_config_phy_lanes_sequence(encoder);
+
+       /* step 4c: configure voltage swing and skew */
+       gen11_dsi_voltage_swing_program_seq(encoder);
+
+       /* enable DDI buffer */
+       gen11_dsi_enable_ddi_buffer(encoder);
+
+       /* setup D-PHY timings */
+       gen11_dsi_setup_dphy_timings(encoder);
+
+       /* step 4h: setup DSI protocol timeouts */
+       gen11_dsi_setup_timeouts(encoder);
+
+       /* Step (4h, 4i, 4j, 4k): Configure transcoder */
+       gen11_dsi_configure_transcoder(encoder, pipe_config);
+
+       /* Step 4l: Gate DDI clocks */
+       gen11_dsi_gate_clocks(encoder);
 }
 
-static void __attribute__((unused))
-gen11_dsi_pre_enable(struct intel_encoder *encoder,
-                    const struct intel_crtc_state *pipe_config,
-                    const struct drm_connector_state *conn_state)
+static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       struct mipi_dsi_device *dsi;
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+       int ret;
+
+       /* set maximum return packet size */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /*
+                * FIXME: This uses the number of DW's currently in the payload
+                * receive queue. This is probably not what we want here.
+                */
+               tmp = I915_READ(DSI_CMD_RXCTL(dsi_trans));
+               tmp &= NUMBER_RX_PLOAD_DW_MASK;
+               /* multiply "Number Rx Payload DW" by 4 to get max value */
+               tmp = tmp * 4;
+               dsi = intel_dsi->dsi_hosts[port]->device;
+               ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp);
+               if (ret < 0)
+                       DRM_ERROR("error setting max return pkt size%d\n", tmp);
+       }
+
+       /* panel power on related mipi dsi vbt sequences */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
+       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
+
+       /* ensure all panel commands dispatched before enabling transcoder */
+       wait_for_cmds_dispatched_to_panel(encoder);
+}
+
+static void gen11_dsi_pre_pll_enable(struct intel_encoder *encoder,
+                                    const struct intel_crtc_state *pipe_config,
+                                    const struct drm_connector_state *conn_state)
 {
        /* step2: enable IO power */
        gen11_dsi_enable_io_power(encoder);
 
        /* step3: enable DSI PLL */
        gen11_dsi_program_esc_clk_div(encoder);
+}
+
+static void gen11_dsi_pre_enable(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *pipe_config,
+                                const struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       /* step3b */
+       gen11_dsi_map_pll(encoder, pipe_config);
 
        /* step4: enable DSI port and DPHY */
-       gen11_dsi_enable_port_and_phy(encoder);
+       gen11_dsi_enable_port_and_phy(encoder, pipe_config);
+
+       /* step5: program and powerup panel */
+       gen11_dsi_powerup_panel(encoder);
+
+       /* step6c: configure transcoder timings */
+       gen11_dsi_set_transcoder_timings(encoder, pipe_config);
+
+       /* step6d: enable dsi transcoder */
+       gen11_dsi_enable_transcoder(encoder);
+
+       /* step7: enable backlight */
+       intel_panel_enable_backlight(pipe_config, conn_state);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
+}
+
+static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+
+               /* disable transcoder */
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               tmp &= ~PIPECONF_ENABLE;
+               I915_WRITE(PIPECONF(dsi_trans), tmp);
+
+               /* wait for transcoder to be disabled */
+               if (intel_wait_for_register(dev_priv, PIPECONF(dsi_trans),
+                                           I965_PIPECONF_ACTIVE, 0, 50))
+                       DRM_ERROR("DSI trancoder not disabled\n");
+       }
+}
+
+static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
+
+       /* ensure cmds dispatched to panel */
+       wait_for_cmds_dispatched_to_panel(encoder);
+}
+
+static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       enum transcoder dsi_trans;
+       u32 tmp;
+
+       /* put dsi link in ULPS */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(DSI_LP_MSG(dsi_trans));
+               tmp |= LINK_ENTER_ULPS;
+               tmp &= ~LINK_ULPS_TYPE_LP11;
+               I915_WRITE(DSI_LP_MSG(dsi_trans), tmp);
+
+               if (wait_for_us((I915_READ(DSI_LP_MSG(dsi_trans)) &
+                               LINK_IN_ULPS),
+                               10))
+                       DRM_ERROR("DSI link not in ULPS\n");
+       }
+
+       /* disable ddi function */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               tmp &= ~TRANS_DDI_FUNC_ENABLE;
+               I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp);
+       }
+
+       /* disable port sync mode if dual link */
+       if (intel_dsi->dual_link) {
+               for_each_dsi_port(port, intel_dsi->ports) {
+                       dsi_trans = dsi_port_to_transcoder(port);
+                       tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans));
+                       tmp &= ~PORT_SYNC_MODE_ENABLE;
+                       I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp);
+               }
+       }
+}
+
+static void gen11_dsi_disable_port(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+
+       gen11_dsi_ungate_clocks(encoder);
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(DDI_BUF_CTL(port));
+               tmp &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(port), tmp);
+
+               if (wait_for_us((I915_READ(DDI_BUF_CTL(port)) &
+                                DDI_BUF_IS_IDLE),
+                                8))
+                       DRM_ERROR("DDI port:%c buffer not idle\n",
+                                 port_name(port));
+       }
+       gen11_dsi_ungate_clocks(encoder);
+}
+
+static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO);
+
+       if (intel_dsi->dual_link)
+               intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO);
+
+       /* set mode to DDI */
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
+               tmp &= ~COMBO_PHY_MODE_DSI;
+               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
+       }
+}
+
+static void gen11_dsi_disable(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *old_crtc_state,
+                             const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       /* step1: turn off backlight */
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
+       intel_panel_disable_backlight(old_conn_state);
+
+       /* step2d,e: disable transcoder and wait */
+       gen11_dsi_disable_transcoder(encoder);
+
+       /* step2f,g: powerdown panel */
+       gen11_dsi_powerdown_panel(encoder);
+
+       /* step2h,i,j: deconfig trancoder */
+       gen11_dsi_deconfigure_trancoder(encoder);
+
+       /* step3: disable port */
+       gen11_dsi_disable_port(encoder);
+
+       /* step4: disable IO power */
+       gen11_dsi_disable_io_power(encoder);
+}
+
+static void gen11_dsi_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 pll_id;
+
+       /* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
+       pll_id = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll);
+       pipe_config->port_clock = cnl_calc_wrpll_link(dev_priv, pll_id);
+       pipe_config->base.adjusted_mode.crtc_clock = intel_dsi->pclk;
+       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
+}
+
+static bool gen11_dsi_compute_config(struct intel_encoder *encoder,
+                                    struct intel_crtc_state *pipe_config,
+                                    struct drm_connector_state *conn_state)
+{
+       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
+                                                  base);
+       struct intel_connector *intel_connector = intel_dsi->attached_connector;
+       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
+       const struct drm_display_mode *fixed_mode =
+                                       intel_connector->panel.fixed_mode;
+       struct drm_display_mode *adjusted_mode =
+                                       &pipe_config->base.adjusted_mode;
+
+       intel_fixed_panel_mode(fixed_mode, adjusted_mode);
+       intel_pch_panel_fitting(crtc, pipe_config, conn_state->scaling_mode);
+
+       adjusted_mode->flags = 0;
+
+       /* Dual link goes to trancoder DSI'0' */
+       if (intel_dsi->ports == BIT(PORT_B))
+               pipe_config->cpu_transcoder = TRANSCODER_DSI_1;
+       else
+               pipe_config->cpu_transcoder = TRANSCODER_DSI_0;
+
+       pipe_config->clock_set = true;
+       pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5;
+
+       return true;
+}
+
+static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder,
+                                      struct intel_crtc_state *crtc_state)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u64 domains = 0;
+       enum port port;
+
+       for_each_dsi_port(port, intel_dsi->ports)
+               if (port == PORT_A)
+                       domains |= BIT_ULL(POWER_DOMAIN_PORT_DDI_A_IO);
+               else
+                       domains |= BIT_ULL(POWER_DOMAIN_PORT_DDI_B_IO);
+
+       return domains;
+}
+
+static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
+                                  enum pipe *pipe)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       u32 tmp;
+       enum port port;
+       enum transcoder dsi_trans;
+       bool ret = false;
+
+       if (!intel_display_power_get_if_enabled(dev_priv,
+                                               encoder->power_domain))
+               return false;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               dsi_trans = dsi_port_to_transcoder(port);
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+               switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               case TRANS_DDI_EDP_INPUT_A_ON:
+                       *pipe = PIPE_A;
+                       break;
+               case TRANS_DDI_EDP_INPUT_B_ONOFF:
+                       *pipe = PIPE_B;
+                       break;
+               case TRANS_DDI_EDP_INPUT_C_ONOFF:
+                       *pipe = PIPE_C;
+                       break;
+               default:
+                       DRM_ERROR("Invalid PIPE input\n");
+                       goto out;
+               }
+
+               tmp = I915_READ(PIPECONF(dsi_trans));
+               ret = tmp & PIPECONF_ENABLE;
+       }
+out:
+       intel_display_power_put(dev_priv, encoder->power_domain);
+       return ret;
+}
+
+static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+       intel_encoder_destroy(encoder);
+}
+
+static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
+       .destroy = gen11_dsi_encoder_destroy,
+};
+
+static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
+       .late_register = intel_connector_register,
+       .early_unregister = intel_connector_unregister,
+       .destroy = intel_connector_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .atomic_get_property = intel_digital_connector_atomic_get_property,
+       .atomic_set_property = intel_digital_connector_atomic_set_property,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs gen11_dsi_connector_helper_funcs = {
+       .get_modes = intel_dsi_get_modes,
+       .mode_valid = intel_dsi_mode_valid,
+       .atomic_check = intel_digital_connector_atomic_check,
+};
+
+static int gen11_dsi_host_attach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static int gen11_dsi_host_detach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *dsi)
+{
+       return 0;
+}
+
+static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host,
+                                      const struct mipi_dsi_msg *msg)
+{
+       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
+       struct mipi_dsi_packet dsi_pkt;
+       ssize_t ret;
+       bool enable_lpdt = false;
+
+       ret = mipi_dsi_create_packet(&dsi_pkt, msg);
+       if (ret < 0)
+               return ret;
+
+       if (msg->flags & MIPI_DSI_MSG_USE_LPM)
+               enable_lpdt = true;
+
+       /* send packet header */
+       ret  = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt);
+       if (ret < 0)
+               return ret;
+
+       /* only long packet contains payload */
+       if (mipi_dsi_packet_format_is_long(msg->type)) {
+               ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt);
+               if (ret < 0)
+                       return ret;
+       }
+
+       //TODO: add payload receive code if needed
+
+       ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length;
+
+       return ret;
+}
+
+static const struct mipi_dsi_host_ops gen11_dsi_host_ops = {
+       .attach = gen11_dsi_host_attach,
+       .detach = gen11_dsi_host_detach,
+       .transfer = gen11_dsi_host_transfer,
+};
+
+void icl_dsi_init(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = &dev_priv->drm;
+       struct intel_dsi *intel_dsi;
+       struct intel_encoder *encoder;
+       struct intel_connector *intel_connector;
+       struct drm_connector *connector;
+       struct drm_display_mode *scan, *fixed_mode = NULL;
+       enum port port;
+
+       if (!intel_bios_is_dsi_present(dev_priv, &port))
+               return;
+
+       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
+       if (!intel_dsi)
+               return;
+
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
+               kfree(intel_dsi);
+               return;
+       }
+
+       encoder = &intel_dsi->base;
+       intel_dsi->attached_connector = intel_connector;
+       connector = &intel_connector->base;
+
+       /* register DSI encoder with DRM subsystem */
+       drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs,
+                        DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
+
+       encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
+       encoder->pre_enable = gen11_dsi_pre_enable;
+       encoder->disable = gen11_dsi_disable;
+       encoder->port = port;
+       encoder->get_config = gen11_dsi_get_config;
+       encoder->compute_config = gen11_dsi_compute_config;
+       encoder->get_hw_state = gen11_dsi_get_hw_state;
+       encoder->type = INTEL_OUTPUT_DSI;
+       encoder->cloneable = 0;
+       encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
+       encoder->power_domain = POWER_DOMAIN_PORT_DSI;
+       encoder->get_power_domains = gen11_dsi_get_power_domains;
+
+       /* register DSI connector with DRM subsystem */
+       drm_connector_init(dev, connector, &gen11_dsi_connector_funcs,
+                          DRM_MODE_CONNECTOR_DSI);
+       drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
+       /* attach connector to encoder */
+       intel_connector_attach_encoder(intel_connector, encoder);
+
+       /* fill mode info from VBT */
+       mutex_lock(&dev->mode_config.mutex);
+       intel_dsi_vbt_get_modes(intel_dsi);
+       list_for_each_entry(scan, &connector->probed_modes, head) {
+               if (scan->type & DRM_MODE_TYPE_PREFERRED) {
+                       fixed_mode = drm_mode_duplicate(dev, scan);
+                       break;
+               }
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+
+       if (!fixed_mode) {
+               DRM_ERROR("DSI fixed mode info missing\n");
+               goto err;
+       }
+
+       connector->display_info.width_mm = fixed_mode->width_mm;
+       connector->display_info.height_mm = fixed_mode->height_mm;
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
+       intel_panel_setup_backlight(connector, INVALID_PIPE);
+
+
+       if (dev_priv->vbt.dsi.config->dual_link)
+               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B);
+       else
+               intel_dsi->ports = BIT(port);
+
+       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
+       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               struct intel_dsi_host *host;
+
+               host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
+               if (!host)
+                       goto err;
+
+               intel_dsi->dsi_hosts[port] = host;
+       }
+
+       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
+               DRM_DEBUG_KMS("no device found\n");
+               goto err;
+       }
+
+       return;
+
+err:
+       drm_encoder_cleanup(&encoder->base);
+       kfree(intel_dsi);
+       kfree(intel_connector);
 }
index b04952bacf77c01896ffdd910eed3d692e538d10..8cb02f28d30cf6b12fe002c13c8bd9d17f9fa6f2 100644 (file)
@@ -184,6 +184,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
        crtc_state->fifo_changed = false;
        crtc_state->wm.need_postvbl_update = false;
        crtc_state->fb_bits = 0;
+       crtc_state->update_planes = 0;
 
        return &crtc_state->base;
 }
@@ -203,6 +204,72 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
        drm_atomic_helper_crtc_destroy_state(crtc, state);
 }
 
+static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
+                                     int num_scalers_need, struct intel_crtc *intel_crtc,
+                                     const char *name, int idx,
+                                     struct intel_plane_state *plane_state,
+                                     int *scaler_id)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       int j;
+       u32 mode;
+
+       if (*scaler_id < 0) {
+               /* find a free scaler */
+               for (j = 0; j < intel_crtc->num_scalers; j++) {
+                       if (scaler_state->scalers[j].in_use)
+                               continue;
+
+                       *scaler_id = j;
+                       scaler_state->scalers[*scaler_id].in_use = 1;
+                       break;
+               }
+       }
+
+       if (WARN(*scaler_id < 0, "Cannot find scaler for %s:%d\n", name, idx))
+               return;
+
+       /* set scaler mode */
+       if (plane_state && plane_state->base.fb &&
+           plane_state->base.fb->format->is_yuv &&
+           plane_state->base.fb->format->num_planes > 1) {
+               if (IS_GEN9(dev_priv) &&
+                   !IS_GEMINILAKE(dev_priv)) {
+                       mode = SKL_PS_SCALER_MODE_NV12;
+               } else if (icl_is_hdr_plane(to_intel_plane(plane_state->base.plane))) {
+                       /*
+                        * On gen11+'s HDR planes we only use the scaler for
+                        * scaling. They have a dedicated chroma upsampler, so
+                        * we don't need the scaler to upsample the UV plane.
+                        */
+                       mode = PS_SCALER_MODE_NORMAL;
+               } else {
+                       mode = PS_SCALER_MODE_PLANAR;
+
+                       if (plane_state->linked_plane)
+                               mode |= PS_PLANE_Y_SEL(plane_state->linked_plane->id);
+               }
+       } else if (INTEL_GEN(dev_priv) > 9 || IS_GEMINILAKE(dev_priv)) {
+               mode = PS_SCALER_MODE_NORMAL;
+       } else if (num_scalers_need == 1 && intel_crtc->num_scalers > 1) {
+               /*
+                * when only 1 scaler is in use on a pipe with 2 scalers
+                * scaler 0 operates in high quality (HQ) mode.
+                * In this case use scaler 0 to take advantage of HQ mode
+                */
+               scaler_state->scalers[*scaler_id].in_use = 0;
+               *scaler_id = 0;
+               scaler_state->scalers[0].in_use = 1;
+               mode = SKL_PS_SCALER_MODE_HQ;
+       } else {
+               mode = SKL_PS_SCALER_MODE_DYN;
+       }
+
+       DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
+                     intel_crtc->pipe, *scaler_id, name, idx);
+       scaler_state->scalers[*scaler_id].mode = mode;
+}
+
 /**
  * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
  * @dev_priv: i915 device
@@ -232,7 +299,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
        struct drm_atomic_state *drm_state = crtc_state->base.state;
        struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state);
        int num_scalers_need;
-       int i, j;
+       int i;
 
        num_scalers_need = hweight32(scaler_state->scaler_users);
 
@@ -304,59 +371,17 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
                        idx = plane->base.id;
 
                        /* plane on different crtc cannot be a scaler user of this crtc */
-                       if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) {
+                       if (WARN_ON(intel_plane->pipe != intel_crtc->pipe))
                                continue;
-                       }
 
                        plane_state = intel_atomic_get_new_plane_state(intel_state,
                                                                       intel_plane);
                        scaler_id = &plane_state->scaler_id;
                }
 
-               if (*scaler_id < 0) {
-                       /* find a free scaler */
-                       for (j = 0; j < intel_crtc->num_scalers; j++) {
-                               if (!scaler_state->scalers[j].in_use) {
-                                       scaler_state->scalers[j].in_use = 1;
-                                       *scaler_id = j;
-                                       DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
-                                               intel_crtc->pipe, *scaler_id, name, idx);
-                                       break;
-                               }
-                       }
-               }
-
-               if (WARN_ON(*scaler_id < 0)) {
-                       DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", name, idx);
-                       continue;
-               }
-
-               /* set scaler mode */
-               if ((INTEL_GEN(dev_priv) >= 9) &&
-                   plane_state && plane_state->base.fb &&
-                   plane_state->base.fb->format->format ==
-                   DRM_FORMAT_NV12) {
-                       if (INTEL_GEN(dev_priv) == 9 &&
-                           !IS_GEMINILAKE(dev_priv) &&
-                           !IS_SKYLAKE(dev_priv))
-                               scaler_state->scalers[*scaler_id].mode =
-                                       SKL_PS_SCALER_MODE_NV12;
-                       else
-                               scaler_state->scalers[*scaler_id].mode =
-                                       PS_SCALER_MODE_PLANAR;
-               } else if (num_scalers_need == 1 && intel_crtc->pipe != PIPE_C) {
-                       /*
-                        * when only 1 scaler is in use on either pipe A or B,
-                        * scaler 0 operates in high quality (HQ) mode.
-                        * In this case use scaler 0 to take advantage of HQ mode
-                        */
-                       *scaler_id = 0;
-                       scaler_state->scalers[0].in_use = 1;
-                       scaler_state->scalers[0].mode = PS_SCALER_MODE_HQ;
-                       scaler_state->scalers[1].in_use = 0;
-               } else {
-                       scaler_state->scalers[*scaler_id].mode = PS_SCALER_MODE_DYN;
-               }
+               intel_atomic_setup_scaler(scaler_state, num_scalers_need,
+                                         intel_crtc, name, idx,
+                                         plane_state, scaler_id);
        }
 
        return 0;
index aabebe0d2e9b48ab0e23586eca62dadee7f93a35..0a73e6e65c2030b2f094c5a89f8248cb807a8020 100644 (file)
 #include <drm/drm_plane_helper.h>
 #include "intel_drv.h"
 
-/**
- * intel_create_plane_state - create plane state object
- * @plane: drm plane
- *
- * Allocates a fresh plane state for the given plane and sets some of
- * the state values to sensible initial values.
- *
- * Returns: A newly allocated plane state, or NULL on failure
- */
-struct intel_plane_state *
-intel_create_plane_state(struct drm_plane *plane)
+struct intel_plane *intel_plane_alloc(void)
 {
-       struct intel_plane_state *state;
+       struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state)
-               return NULL;
+       plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+       if (!plane)
+               return ERR_PTR(-ENOMEM);
 
-       state->base.plane = plane;
-       state->base.rotation = DRM_MODE_ROTATE_0;
+       plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+       if (!plane_state) {
+               kfree(plane);
+               return ERR_PTR(-ENOMEM);
+       }
 
-       return state;
+       __drm_atomic_helper_plane_reset(&plane->base, &plane_state->base);
+       plane_state->scaler_id = -1;
+
+       return plane;
+}
+
+void intel_plane_free(struct intel_plane *plane)
+{
+       intel_plane_destroy_state(&plane->base, plane->base.state);
+       kfree(plane);
 }
 
 /**
@@ -117,10 +120,14 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int ret;
 
+       crtc_state->active_planes &= ~BIT(intel_plane->id);
+       crtc_state->nv12_planes &= ~BIT(intel_plane->id);
+       intel_state->base.visible = false;
+
+       /* If this is a cursor plane, no further checks are needed. */
        if (!intel_state->base.crtc && !old_plane_state->base.crtc)
                return 0;
 
-       intel_state->base.visible = false;
        ret = intel_plane->check_plane(crtc_state, intel_state);
        if (ret)
                return ret;
@@ -128,13 +135,12 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
        /* FIXME pre-g4x don't work like this */
        if (state->visible)
                crtc_state->active_planes |= BIT(intel_plane->id);
-       else
-               crtc_state->active_planes &= ~BIT(intel_plane->id);
 
        if (state->visible && state->fb->format->format == DRM_FORMAT_NV12)
                crtc_state->nv12_planes |= BIT(intel_plane->id);
-       else
-               crtc_state->nv12_planes &= ~BIT(intel_plane->id);
+
+       if (state->visible || old_plane_state->base.visible)
+               crtc_state->update_planes |= BIT(intel_plane->id);
 
        return intel_plane_atomic_calc_changes(old_crtc_state,
                                               &crtc_state->base,
@@ -152,6 +158,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
        const struct drm_crtc_state *old_crtc_state;
        struct drm_crtc_state *new_crtc_state;
 
+       new_plane_state->visible = false;
        if (!crtc)
                return 0;
 
@@ -164,29 +171,123 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
                                                   to_intel_plane_state(new_plane_state));
 }
 
-static void intel_plane_atomic_update(struct drm_plane *plane,
-                                     struct drm_plane_state *old_state)
+static struct intel_plane *
+skl_next_plane_to_commit(struct intel_atomic_state *state,
+                        struct intel_crtc *crtc,
+                        struct skl_ddb_entry entries_y[I915_MAX_PLANES],
+                        struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
+                        unsigned int *update_mask)
 {
-       struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-       const struct intel_plane_state *new_plane_state =
-               intel_atomic_get_new_plane_state(state, intel_plane);
-       struct drm_crtc *crtc = new_plane_state->base.crtc ?: old_state->crtc;
+       struct intel_crtc_state *crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
+       int i;
+
+       if (*update_mask == 0)
+               return NULL;
 
-       if (new_plane_state->base.visible) {
-               const struct intel_crtc_state *new_crtc_state =
-                       intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               enum plane_id plane_id = plane->id;
 
-               trace_intel_update_plane(plane,
-                                        to_intel_crtc(crtc));
+               if (crtc->pipe != plane->pipe ||
+                   !(*update_mask & BIT(plane_id)))
+                       continue;
+
+               if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
+                                               entries_y,
+                                               I915_MAX_PLANES, plane_id) ||
+                   skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
+                                               entries_uv,
+                                               I915_MAX_PLANES, plane_id))
+                       continue;
+
+               *update_mask &= ~BIT(plane_id);
+               entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
+               entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
+
+               return plane;
+       }
 
-               intel_plane->update_plane(intel_plane,
-                                         new_crtc_state, new_plane_state);
-       } else {
-               trace_intel_disable_plane(plane,
-                                         to_intel_crtc(crtc));
+       /* should never happen */
+       WARN_ON(1);
 
-               intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
+       return NULL;
+}
+
+void skl_update_planes_on_crtc(struct intel_atomic_state *state,
+                              struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
+       struct intel_crtc_state *new_crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct skl_ddb_entry entries_y[I915_MAX_PLANES];
+       struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
+       u32 update_mask = new_crtc_state->update_planes;
+       struct intel_plane *plane;
+
+       memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
+              sizeof(old_crtc_state->wm.skl.plane_ddb_y));
+       memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
+              sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
+
+       while ((plane = skl_next_plane_to_commit(state, crtc,
+                                                entries_y, entries_uv,
+                                                &update_mask))) {
+               struct intel_plane_state *new_plane_state =
+                       intel_atomic_get_new_plane_state(state, plane);
+
+               if (new_plane_state->base.visible) {
+                       trace_intel_update_plane(&plane->base, crtc);
+                       plane->update_plane(plane, new_crtc_state, new_plane_state);
+               } else if (new_plane_state->slave) {
+                       struct intel_plane *master =
+                               new_plane_state->linked_plane;
+
+                       /*
+                        * We update the slave plane from this function because
+                        * programming it from the master plane's update_plane
+                        * callback runs into issues when the Y plane is
+                        * reassigned, disabled or used by a different plane.
+                        *
+                        * The slave plane is updated with the master plane's
+                        * plane_state.
+                        */
+                       new_plane_state =
+                               intel_atomic_get_new_plane_state(state, master);
+
+                       trace_intel_update_plane(&plane->base, crtc);
+                       plane->update_slave(plane, new_crtc_state, new_plane_state);
+               } else {
+                       trace_intel_disable_plane(&plane->base, crtc);
+                       plane->disable_plane(plane, new_crtc_state);
+               }
+       }
+}
+
+void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *new_crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       u32 update_mask = new_crtc_state->update_planes;
+       struct intel_plane_state *new_plane_state;
+       struct intel_plane *plane;
+       int i;
+
+       for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
+               if (crtc->pipe != plane->pipe ||
+                   !(update_mask & BIT(plane->id)))
+                       continue;
+
+               if (new_plane_state->base.visible) {
+                       trace_intel_update_plane(&plane->base, crtc);
+                       plane->update_plane(plane, new_crtc_state, new_plane_state);
+               } else {
+                       trace_intel_disable_plane(&plane->base, crtc);
+                       plane->disable_plane(plane, new_crtc_state);
+               }
        }
 }
 
@@ -194,7 +295,6 @@ const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
        .prepare_fb = intel_prepare_plane_fb,
        .cleanup_fb = intel_cleanup_plane_fb,
        .atomic_check = intel_plane_atomic_check,
-       .atomic_update = intel_plane_atomic_update,
 };
 
 /**
index ee3ca2de983b96ea52ffda2c794963f2b23d705d..ae55a6865d5cca98f8738cbf8db4cffe5039bfa2 100644 (file)
@@ -153,32 +153,32 @@ static const struct {
        int n;
        int cts;
 } hdmi_aud_ncts[] = {
-       { 44100, TMDS_296M, 4459, 234375 },
-       { 44100, TMDS_297M, 4704, 247500 },
-       { 48000, TMDS_296M, 5824, 281250 },
-       { 48000, TMDS_297M, 5120, 247500 },
        { 32000, TMDS_296M, 5824, 421875 },
        { 32000, TMDS_297M, 3072, 222750 },
+       { 32000, TMDS_593M, 5824, 843750 },
+       { 32000, TMDS_594M, 3072, 445500 },
+       { 44100, TMDS_296M, 4459, 234375 },
+       { 44100, TMDS_297M, 4704, 247500 },
+       { 44100, TMDS_593M, 8918, 937500 },
+       { 44100, TMDS_594M, 9408, 990000 },
        { 88200, TMDS_296M, 8918, 234375 },
        { 88200, TMDS_297M, 9408, 247500 },
-       { 96000, TMDS_296M, 11648, 281250 },
-       { 96000, TMDS_297M, 10240, 247500 },
+       { 88200, TMDS_593M, 17836, 937500 },
+       { 88200, TMDS_594M, 18816, 990000 },
        { 176400, TMDS_296M, 17836, 234375 },
        { 176400, TMDS_297M, 18816, 247500 },
-       { 192000, TMDS_296M, 23296, 281250 },
-       { 192000, TMDS_297M, 20480, 247500 },
-       { 44100, TMDS_593M, 8918, 937500 },
-       { 44100, TMDS_594M, 9408, 990000 },
+       { 176400, TMDS_593M, 35672, 937500 },
+       { 176400, TMDS_594M, 37632, 990000 },
+       { 48000, TMDS_296M, 5824, 281250 },
+       { 48000, TMDS_297M, 5120, 247500 },
        { 48000, TMDS_593M, 5824, 562500 },
        { 48000, TMDS_594M, 6144, 594000 },
-       { 32000, TMDS_593M, 5824, 843750 },
-       { 32000, TMDS_594M, 3072, 445500 },
-       { 88200, TMDS_593M, 17836, 937500 },
-       { 88200, TMDS_594M, 18816, 990000 },
+       { 96000, TMDS_296M, 11648, 281250 },
+       { 96000, TMDS_297M, 10240, 247500 },
        { 96000, TMDS_593M, 11648, 562500 },
        { 96000, TMDS_594M, 12288, 594000 },
-       { 176400, TMDS_593M, 35672, 937500 },
-       { 176400, TMDS_594M, 37632, 990000 },
+       { 192000, TMDS_296M, 23296, 281250 },
+       { 192000, TMDS_297M, 20480, 247500 },
        { 192000, TMDS_593M, 23296, 562500 },
        { 192000, TMDS_594M, 24576, 594000 },
 };
@@ -929,6 +929,9 @@ static int i915_audio_component_bind(struct device *i915_kdev,
        if (WARN_ON(acomp->base.ops || acomp->base.dev))
                return -EEXIST;
 
+       if (WARN_ON(!device_link_add(hda_kdev, i915_kdev, DL_FLAG_STATELESS)))
+               return -ENOMEM;
+
        drm_modeset_lock_all(&dev_priv->drm);
        acomp->base.ops = &i915_audio_component_ops;
        acomp->base.dev = i915_kdev;
@@ -952,6 +955,8 @@ static void i915_audio_component_unbind(struct device *i915_kdev,
        acomp->base.dev = NULL;
        dev_priv->audio_component = NULL;
        drm_modeset_unlock_all(&dev_priv->drm);
+
+       device_link_remove(hda_kdev, i915_kdev);
 }
 
 static const struct component_ops i915_audio_component_bind_ops = {
index 1faa494e2bc91a245861135ab5de015a7a6810ff..6d3e0260d49cda5b2d5ffa36152ef6eb544cc14e 100644 (file)
@@ -420,6 +420,13 @@ parse_general_features(struct drm_i915_private *dev_priv,
                intel_bios_ssc_frequency(dev_priv, general->ssc_freq);
        dev_priv->vbt.display_clock_mode = general->display_clock_mode;
        dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
+       if (bdb->version >= 181) {
+               dev_priv->vbt.orientation = general->rotate_180 ?
+                       DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP :
+                       DRM_MODE_PANEL_ORIENTATION_NORMAL;
+       } else {
+               dev_priv->vbt.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+       }
        DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n",
                      dev_priv->vbt.int_tv_support,
                      dev_priv->vbt.int_crt_support,
@@ -852,6 +859,30 @@ parse_mipi_config(struct drm_i915_private *dev_priv,
 
        parse_dsi_backlight_ports(dev_priv, bdb->version, port);
 
+       /* FIXME is the 90 vs. 270 correct? */
+       switch (config->rotation) {
+       case ENABLE_ROTATION_0:
+               /*
+                * Most (all?) VBTs claim 0 degrees despite having
+                * an upside down panel, thus we do not trust this.
+                */
+               dev_priv->vbt.dsi.orientation =
+                       DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+               break;
+       case ENABLE_ROTATION_90:
+               dev_priv->vbt.dsi.orientation =
+                       DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
+               break;
+       case ENABLE_ROTATION_180:
+               dev_priv->vbt.dsi.orientation =
+                       DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+               break;
+       case ENABLE_ROTATION_270:
+               dev_priv->vbt.dsi.orientation =
+                       DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
+               break;
+       }
+
        /* We have mandatory mipi config blocks. Initialize as generic panel */
        dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
 }
@@ -1721,7 +1752,7 @@ void intel_bios_init(struct drm_i915_private *dev_priv)
        const struct bdb_header *bdb;
        u8 __iomem *bios = NULL;
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0) {
+       if (!HAS_DISPLAY(dev_priv)) {
                DRM_DEBUG_KMS("Skipping VBT init due to disabled display.\n");
                return;
        }
@@ -2039,17 +2070,17 @@ bool intel_bios_is_dsi_present(struct drm_i915_private *dev_priv,
 
                dvo_port = child->dvo_port;
 
-               switch (dvo_port) {
-               case DVO_PORT_MIPIA:
-               case DVO_PORT_MIPIC:
+               if (dvo_port == DVO_PORT_MIPIA ||
+                   (dvo_port == DVO_PORT_MIPIB && IS_ICELAKE(dev_priv)) ||
+                   (dvo_port == DVO_PORT_MIPIC && !IS_ICELAKE(dev_priv))) {
                        if (port)
                                *port = dvo_port - DVO_PORT_MIPIA;
                        return true;
-               case DVO_PORT_MIPIB:
-               case DVO_PORT_MIPID:
+               } else if (dvo_port == DVO_PORT_MIPIB ||
+                          dvo_port == DVO_PORT_MIPIC ||
+                          dvo_port == DVO_PORT_MIPID) {
                        DRM_DEBUG_KMS("VBT has unsupported DSI port %c\n",
                                      port_name(dvo_port - DVO_PORT_MIPIA));
-                       break;
                }
        }
 
@@ -2159,3 +2190,49 @@ intel_bios_is_lspcon_present(struct drm_i915_private *dev_priv,
 
        return false;
 }
+
+enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
+                                  enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       enum aux_ch aux_ch;
+
+       if (!info->alternate_aux_channel) {
+               aux_ch = (enum aux_ch)port;
+
+               DRM_DEBUG_KMS("using AUX %c for port %c (platform default)\n",
+                             aux_ch_name(aux_ch), port_name(port));
+               return aux_ch;
+       }
+
+       switch (info->alternate_aux_channel) {
+       case DP_AUX_A:
+               aux_ch = AUX_CH_A;
+               break;
+       case DP_AUX_B:
+               aux_ch = AUX_CH_B;
+               break;
+       case DP_AUX_C:
+               aux_ch = AUX_CH_C;
+               break;
+       case DP_AUX_D:
+               aux_ch = AUX_CH_D;
+               break;
+       case DP_AUX_E:
+               aux_ch = AUX_CH_E;
+               break;
+       case DP_AUX_F:
+               aux_ch = AUX_CH_F;
+               break;
+       default:
+               MISSING_CASE(info->alternate_aux_channel);
+               aux_ch = AUX_CH_A;
+               break;
+       }
+
+       DRM_DEBUG_KMS("using AUX %c for port %c (VBT)\n",
+                     aux_ch_name(aux_ch), port_name(port));
+
+       return aux_ch;
+}
index 84bf8d827136dc28515216df4bec41528024d9e5..447c5256f63a9399f39f2439a558e3b88e4205ae 100644 (file)
 
 #include "i915_drv.h"
 
-#ifdef CONFIG_SMP
-#define task_asleep(tsk) ((tsk)->state & TASK_NORMAL && !(tsk)->on_cpu)
-#else
-#define task_asleep(tsk) ((tsk)->state & TASK_NORMAL)
-#endif
+#define task_asleep(tsk) ((tsk)->state & TASK_NORMAL && !(tsk)->on_rq)
 
 static unsigned int __intel_breadcrumbs_wakeup(struct intel_breadcrumbs *b)
 {
index 8d74276029e621f9ae7e6db54c815be5d2d0c9d1..25e3aba9cded6e45f3751039a3f7bb20845dd7b8 100644 (file)
@@ -2660,37 +2660,18 @@ static int cnp_rawclk(struct drm_i915_private *dev_priv)
                fraction = 200;
        }
 
-       rawclk = CNP_RAWCLK_DIV((divider / 1000) - 1);
-       if (fraction)
-               rawclk |= CNP_RAWCLK_FRAC(DIV_ROUND_CLOSEST(1000,
-                                                           fraction) - 1);
+       rawclk = CNP_RAWCLK_DIV(divider / 1000);
+       if (fraction) {
+               int numerator = 1;
 
-       I915_WRITE(PCH_RAWCLK_FREQ, rawclk);
-       return divider + fraction;
-}
-
-static int icp_rawclk(struct drm_i915_private *dev_priv)
-{
-       u32 rawclk;
-       int divider, numerator, denominator, frequency;
-
-       if (I915_READ(SFUSE_STRAP) & SFUSE_STRAP_RAW_FREQUENCY) {
-               frequency = 24000;
-               divider = 23;
-               numerator = 0;
-               denominator = 0;
-       } else {
-               frequency = 19200;
-               divider = 18;
-               numerator = 1;
-               denominator = 4;
+               rawclk |= CNP_RAWCLK_DEN(DIV_ROUND_CLOSEST(numerator * 1000,
+                                                          fraction) - 1);
+               if (HAS_PCH_ICP(dev_priv))
+                       rawclk |= ICP_RAWCLK_NUM(numerator);
        }
 
-       rawclk = CNP_RAWCLK_DIV(divider) | ICP_RAWCLK_NUM(numerator) |
-                ICP_RAWCLK_DEN(denominator);
-
        I915_WRITE(PCH_RAWCLK_FREQ, rawclk);
-       return frequency;
+       return divider + fraction;
 }
 
 static int pch_rawclk(struct drm_i915_private *dev_priv)
@@ -2740,9 +2721,7 @@ static int g4x_hrawclk(struct drm_i915_private *dev_priv)
  */
 void intel_update_rawclk(struct drm_i915_private *dev_priv)
 {
-       if (HAS_PCH_ICP(dev_priv))
-               dev_priv->rawclk_freq = icp_rawclk(dev_priv);
-       else if (HAS_PCH_CNP(dev_priv))
+       if (HAS_PCH_CNP(dev_priv) || HAS_PCH_ICP(dev_priv))
                dev_priv->rawclk_freq = cnp_rawclk(dev_priv);
        else if (HAS_PCH_SPLIT(dev_priv))
                dev_priv->rawclk_freq = pch_rawclk(dev_priv);
index c6a7beabd58d1f636af7f3fb53a16214b4a7e6a1..5127da286a2b4f61ca5a32ce00220e01a9397f93 100644 (file)
@@ -149,7 +149,8 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state)
        if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv))
                limited_color_range = intel_crtc_state->limited_color_range;
 
-       if (intel_crtc_state->ycbcr420) {
+       if (intel_crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+           intel_crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
                ilk_load_ycbcr_conversion_matrix(intel_crtc);
                return;
        } else if (crtc_state->ctm) {
diff --git a/drivers/gpu/drm/i915/intel_combo_phy.c b/drivers/gpu/drm/i915/intel_combo_phy.c
new file mode 100644 (file)
index 0000000..3d0271c
--- /dev/null
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include "intel_drv.h"
+
+#define for_each_combo_port(__dev_priv, __port) \
+       for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++)  \
+               for_each_if(intel_port_is_combophy(__dev_priv, __port))
+
+#define for_each_combo_port_reverse(__dev_priv, __port) \
+       for ((__port) = I915_MAX_PORTS; (__port)-- > PORT_A;) \
+               for_each_if(intel_port_is_combophy(__dev_priv, __port))
+
+enum {
+       PROCMON_0_85V_DOT_0,
+       PROCMON_0_95V_DOT_0,
+       PROCMON_0_95V_DOT_1,
+       PROCMON_1_05V_DOT_0,
+       PROCMON_1_05V_DOT_1,
+};
+
+static const struct cnl_procmon {
+       u32 dw1, dw9, dw10;
+} cnl_procmon_values[] = {
+       [PROCMON_0_85V_DOT_0] =
+               { .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, },
+       [PROCMON_0_95V_DOT_0] =
+               { .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, },
+       [PROCMON_0_95V_DOT_1] =
+               { .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, },
+       [PROCMON_1_05V_DOT_0] =
+               { .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, },
+       [PROCMON_1_05V_DOT_1] =
+               { .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, },
+};
+
+/*
+ * CNL has just one set of registers, while ICL has two sets: one for port A and
+ * the other for port B. The CNL registers are equivalent to the ICL port A
+ * registers, that's why we call the ICL macros even though the function has CNL
+ * on its name.
+ */
+static const struct cnl_procmon *
+cnl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum port port)
+{
+       const struct cnl_procmon *procmon;
+       u32 val;
+
+       val = I915_READ(ICL_PORT_COMP_DW3(port));
+       switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
+       default:
+               MISSING_CASE(val);
+               /* fall through */
+       case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0:
+               procmon = &cnl_procmon_values[PROCMON_0_85V_DOT_0];
+               break;
+       case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_0:
+               procmon = &cnl_procmon_values[PROCMON_0_95V_DOT_0];
+               break;
+       case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_1:
+               procmon = &cnl_procmon_values[PROCMON_0_95V_DOT_1];
+               break;
+       case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_0:
+               procmon = &cnl_procmon_values[PROCMON_1_05V_DOT_0];
+               break;
+       case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_1:
+               procmon = &cnl_procmon_values[PROCMON_1_05V_DOT_1];
+               break;
+       }
+
+       return procmon;
+}
+
+static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
+                                      enum port port)
+{
+       const struct cnl_procmon *procmon;
+       u32 val;
+
+       procmon = cnl_get_procmon_ref_values(dev_priv, port);
+
+       val = I915_READ(ICL_PORT_COMP_DW1(port));
+       val &= ~((0xff << 16) | 0xff);
+       val |= procmon->dw1;
+       I915_WRITE(ICL_PORT_COMP_DW1(port), val);
+
+       I915_WRITE(ICL_PORT_COMP_DW9(port), procmon->dw9);
+       I915_WRITE(ICL_PORT_COMP_DW10(port), procmon->dw10);
+}
+
+static bool check_phy_reg(struct drm_i915_private *dev_priv,
+                         enum port port, i915_reg_t reg, u32 mask,
+                         u32 expected_val)
+{
+       u32 val = I915_READ(reg);
+
+       if ((val & mask) != expected_val) {
+               DRM_DEBUG_DRIVER("Port %c combo PHY reg %08x state mismatch: "
+                                "current %08x mask %08x expected %08x\n",
+                                port_name(port),
+                                reg.reg, val, mask, expected_val);
+               return false;
+       }
+
+       return true;
+}
+
+static bool cnl_verify_procmon_ref_values(struct drm_i915_private *dev_priv,
+                                         enum port port)
+{
+       const struct cnl_procmon *procmon;
+       bool ret;
+
+       procmon = cnl_get_procmon_ref_values(dev_priv, port);
+
+       ret = check_phy_reg(dev_priv, port, ICL_PORT_COMP_DW1(port),
+                           (0xff << 16) | 0xff, procmon->dw1);
+       ret &= check_phy_reg(dev_priv, port, ICL_PORT_COMP_DW9(port),
+                            -1U, procmon->dw9);
+       ret &= check_phy_reg(dev_priv, port, ICL_PORT_COMP_DW10(port),
+                            -1U, procmon->dw10);
+
+       return ret;
+}
+
+static bool cnl_combo_phy_enabled(struct drm_i915_private *dev_priv)
+{
+       return !(I915_READ(CHICKEN_MISC_2) & CNL_COMP_PWR_DOWN) &&
+               (I915_READ(CNL_PORT_COMP_DW0) & COMP_INIT);
+}
+
+static bool cnl_combo_phy_verify_state(struct drm_i915_private *dev_priv)
+{
+       enum port port = PORT_A;
+       bool ret;
+
+       if (!cnl_combo_phy_enabled(dev_priv))
+               return false;
+
+       ret = cnl_verify_procmon_ref_values(dev_priv, port);
+
+       ret &= check_phy_reg(dev_priv, port, CNL_PORT_CL1CM_DW5,
+                            CL_POWER_DOWN_ENABLE, CL_POWER_DOWN_ENABLE);
+
+       return ret;
+}
+
+void cnl_combo_phys_init(struct drm_i915_private *dev_priv)
+{
+       u32 val;
+
+       val = I915_READ(CHICKEN_MISC_2);
+       val &= ~CNL_COMP_PWR_DOWN;
+       I915_WRITE(CHICKEN_MISC_2, val);
+
+       /* Dummy PORT_A to get the correct CNL register from the ICL macro */
+       cnl_set_procmon_ref_values(dev_priv, PORT_A);
+
+       val = I915_READ(CNL_PORT_COMP_DW0);
+       val |= COMP_INIT;
+       I915_WRITE(CNL_PORT_COMP_DW0, val);
+
+       val = I915_READ(CNL_PORT_CL1CM_DW5);
+       val |= CL_POWER_DOWN_ENABLE;
+       I915_WRITE(CNL_PORT_CL1CM_DW5, val);
+}
+
+void cnl_combo_phys_uninit(struct drm_i915_private *dev_priv)
+{
+       u32 val;
+
+       if (!cnl_combo_phy_verify_state(dev_priv))
+               DRM_WARN("Combo PHY HW state changed unexpectedly.\n");
+
+       val = I915_READ(CHICKEN_MISC_2);
+       val |= CNL_COMP_PWR_DOWN;
+       I915_WRITE(CHICKEN_MISC_2, val);
+}
+
+static bool icl_combo_phy_enabled(struct drm_i915_private *dev_priv,
+                                 enum port port)
+{
+       return !(I915_READ(ICL_PHY_MISC(port)) &
+                ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN) &&
+               (I915_READ(ICL_PORT_COMP_DW0(port)) & COMP_INIT);
+}
+
+static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
+                                      enum port port)
+{
+       bool ret;
+
+       if (!icl_combo_phy_enabled(dev_priv, port))
+               return false;
+
+       ret = cnl_verify_procmon_ref_values(dev_priv, port);
+
+       ret &= check_phy_reg(dev_priv, port, ICL_PORT_CL_DW5(port),
+                            CL_POWER_DOWN_ENABLE, CL_POWER_DOWN_ENABLE);
+
+       return ret;
+}
+
+void icl_combo_phys_init(struct drm_i915_private *dev_priv)
+{
+       enum port port;
+
+       for_each_combo_port(dev_priv, port) {
+               u32 val;
+
+               if (icl_combo_phy_verify_state(dev_priv, port)) {
+                       DRM_DEBUG_DRIVER("Port %c combo PHY already enabled, won't reprogram it.\n",
+                                        port_name(port));
+                       continue;
+               }
+
+               val = I915_READ(ICL_PHY_MISC(port));
+               val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+               I915_WRITE(ICL_PHY_MISC(port), val);
+
+               cnl_set_procmon_ref_values(dev_priv, port);
+
+               val = I915_READ(ICL_PORT_COMP_DW0(port));
+               val |= COMP_INIT;
+               I915_WRITE(ICL_PORT_COMP_DW0(port), val);
+
+               val = I915_READ(ICL_PORT_CL_DW5(port));
+               val |= CL_POWER_DOWN_ENABLE;
+               I915_WRITE(ICL_PORT_CL_DW5(port), val);
+       }
+}
+
+void icl_combo_phys_uninit(struct drm_i915_private *dev_priv)
+{
+       enum port port;
+
+       for_each_combo_port_reverse(dev_priv, port) {
+               u32 val;
+
+               if (!icl_combo_phy_verify_state(dev_priv, port))
+                       DRM_WARN("Port %c combo PHY HW state changed unexpectedly\n",
+                                port_name(port));
+
+               val = I915_READ(ICL_PHY_MISC(port));
+               val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+               I915_WRITE(ICL_PHY_MISC(port), val);
+
+               val = I915_READ(ICL_PORT_COMP_DW0(port));
+               val &= ~COMP_INIT;
+               I915_WRITE(ICL_PORT_COMP_DW0(port), val);
+       }
+}
diff --git a/drivers/gpu/drm/i915/intel_connector.c b/drivers/gpu/drm/i915/intel_connector.c
new file mode 100644 (file)
index 0000000..18e370f
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007, 2010 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (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.
+ */
+
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drmP.h>
+#include "intel_drv.h"
+#include "i915_drv.h"
+
+int intel_connector_init(struct intel_connector *connector)
+{
+       struct intel_digital_connector_state *conn_state;
+
+       /*
+        * Allocate enough memory to hold intel_digital_connector_state,
+        * This might be a few bytes too many, but for connectors that don't
+        * need it we'll free the state and allocate a smaller one on the first
+        * successful commit anyway.
+        */
+       conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
+       if (!conn_state)
+               return -ENOMEM;
+
+       __drm_atomic_helper_connector_reset(&connector->base,
+                                           &conn_state->base);
+
+       return 0;
+}
+
+struct intel_connector *intel_connector_alloc(void)
+{
+       struct intel_connector *connector;
+
+       connector = kzalloc(sizeof(*connector), GFP_KERNEL);
+       if (!connector)
+               return NULL;
+
+       if (intel_connector_init(connector) < 0) {
+               kfree(connector);
+               return NULL;
+       }
+
+       return connector;
+}
+
+/*
+ * Free the bits allocated by intel_connector_alloc.
+ * This should only be used after intel_connector_alloc has returned
+ * successfully, and before drm_connector_init returns successfully.
+ * Otherwise the destroy callbacks for the connector and the state should
+ * take care of proper cleanup/free (see intel_connector_destroy).
+ */
+void intel_connector_free(struct intel_connector *connector)
+{
+       kfree(to_intel_digital_connector_state(connector->base.state));
+       kfree(connector);
+}
+
+/*
+ * Connector type independent destroy hook for drm_connector_funcs.
+ */
+void intel_connector_destroy(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+
+       kfree(intel_connector->detect_edid);
+
+       if (!IS_ERR_OR_NULL(intel_connector->edid))
+               kfree(intel_connector->edid);
+
+       intel_panel_fini(&intel_connector->panel);
+
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+int intel_connector_register(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       int ret;
+
+       ret = intel_backlight_device_register(intel_connector);
+       if (ret)
+               goto err;
+
+       if (i915_inject_load_failure()) {
+               ret = -EFAULT;
+               goto err_backlight;
+       }
+
+       return 0;
+
+err_backlight:
+       intel_backlight_device_unregister(intel_connector);
+err:
+       return ret;
+}
+
+void intel_connector_unregister(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+
+       intel_backlight_device_unregister(intel_connector);
+}
+
+void intel_connector_attach_encoder(struct intel_connector *connector,
+                                   struct intel_encoder *encoder)
+{
+       connector->encoder = encoder;
+       drm_connector_attach_encoder(&connector->base, &encoder->base);
+}
+
+/*
+ * Simple connector->get_hw_state implementation for encoders that support only
+ * one connector and no cloning and hence the encoder state determines the state
+ * of the connector.
+ */
+bool intel_connector_get_hw_state(struct intel_connector *connector)
+{
+       enum pipe pipe = 0;
+       struct intel_encoder *encoder = connector->encoder;
+
+       return encoder->get_hw_state(encoder, &pipe);
+}
+
+enum pipe intel_connector_get_pipe(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+
+       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+
+       if (!connector->base.state->crtc)
+               return INVALID_PIPE;
+
+       return to_intel_crtc(connector->base.state->crtc)->pipe;
+}
+
+/**
+ * intel_connector_update_modes - update connector from edid
+ * @connector: DRM connector device to use
+ * @edid: previously read EDID information
+ */
+int intel_connector_update_modes(struct drm_connector *connector,
+                               struct edid *edid)
+{
+       int ret;
+
+       drm_connector_update_edid_property(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+
+       return ret;
+}
+
+/**
+ * intel_ddc_get_modes - get modelist from monitor
+ * @connector: DRM connector device to use
+ * @adapter: i2c adapter
+ *
+ * Fetch the EDID information from @connector using the DDC bus.
+ */
+int intel_ddc_get_modes(struct drm_connector *connector,
+                       struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+       int ret;
+
+       edid = drm_get_edid(connector, adapter);
+       if (!edid)
+               return 0;
+
+       ret = intel_connector_update_modes(connector, edid);
+       kfree(edid);
+
+       return ret;
+}
+
+static const struct drm_prop_enum_list force_audio_names[] = {
+       { HDMI_AUDIO_OFF_DVI, "force-dvi" },
+       { HDMI_AUDIO_OFF, "off" },
+       { HDMI_AUDIO_AUTO, "auto" },
+       { HDMI_AUDIO_ON, "on" },
+};
+
+void
+intel_attach_force_audio_property(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_property *prop;
+
+       prop = dev_priv->force_audio_property;
+       if (prop == NULL) {
+               prop = drm_property_create_enum(dev, 0,
+                                          "audio",
+                                          force_audio_names,
+                                          ARRAY_SIZE(force_audio_names));
+               if (prop == NULL)
+                       return;
+
+               dev_priv->force_audio_property = prop;
+       }
+       drm_object_attach_property(&connector->base, prop, 0);
+}
+
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+       { INTEL_BROADCAST_RGB_AUTO, "Automatic" },
+       { INTEL_BROADCAST_RGB_FULL, "Full" },
+       { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" },
+};
+
+void
+intel_attach_broadcast_rgb_property(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_property *prop;
+
+       prop = dev_priv->broadcast_rgb_property;
+       if (prop == NULL) {
+               prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
+                                          "Broadcast RGB",
+                                          broadcast_rgb_names,
+                                          ARRAY_SIZE(broadcast_rgb_names));
+               if (prop == NULL)
+                       return;
+
+               dev_priv->broadcast_rgb_property = prop;
+       }
+
+       drm_object_attach_property(&connector->base, prop, 0);
+}
+
+void
+intel_attach_aspect_ratio_property(struct drm_connector *connector)
+{
+       if (!drm_mode_create_aspect_ratio_property(connector->dev))
+               drm_object_attach_property(&connector->base,
+                       connector->dev->mode_config.aspect_ratio_property,
+                       DRM_MODE_PICTURE_ASPECT_NONE);
+}
index 0c6bf82bb059a87e1b6ce96e1412bb0aa60f92f3..68f2fb89ece3fa259bfb2da593a7a66c68c81021 100644 (file)
@@ -354,6 +354,7 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        return true;
 }
 
@@ -368,6 +369,7 @@ static bool pch_crt_compute_config(struct intel_encoder *encoder,
                return false;
 
        pipe_config->has_pch_encoder = true;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
        return true;
 }
@@ -389,6 +391,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder,
                return false;
 
        pipe_config->has_pch_encoder = true;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
        /* LPT FDI RX only supports 8bpc. */
        if (HAS_PCH_LPT(dev_priv)) {
@@ -849,12 +852,6 @@ out:
        return status;
 }
 
-static void intel_crt_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
@@ -909,7 +906,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_crt_destroy,
+       .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
index d48186e9ddadf8027b78e6d87ec025b5ec3df027..a516697bf57dfc8d63434b95d3f15aaaff748c21 100644 (file)
  * low-power state and comes back to normal.
  */
 
-#define I915_CSR_ICL "i915/icl_dmc_ver1_07.bin"
-MODULE_FIRMWARE(I915_CSR_ICL);
-#define ICL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 7)
+#define GEN12_CSR_MAX_FW_SIZE          ICL_CSR_MAX_FW_SIZE
 
-#define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin"
-MODULE_FIRMWARE(I915_CSR_GLK);
-#define GLK_CSR_VERSION_REQUIRED       CSR_VERSION(1, 4)
+#define ICL_CSR_PATH                   "i915/icl_dmc_ver1_07.bin"
+#define ICL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 7)
+#define ICL_CSR_MAX_FW_SIZE            0x6000
+MODULE_FIRMWARE(ICL_CSR_PATH);
 
-#define I915_CSR_CNL "i915/cnl_dmc_ver1_07.bin"
-MODULE_FIRMWARE(I915_CSR_CNL);
+#define CNL_CSR_PATH                   "i915/cnl_dmc_ver1_07.bin"
 #define CNL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 7)
+#define CNL_CSR_MAX_FW_SIZE            GLK_CSR_MAX_FW_SIZE
+MODULE_FIRMWARE(CNL_CSR_PATH);
+
+#define GLK_CSR_PATH                   "i915/glk_dmc_ver1_04.bin"
+#define GLK_CSR_VERSION_REQUIRED       CSR_VERSION(1, 4)
+#define GLK_CSR_MAX_FW_SIZE            0x4000
+MODULE_FIRMWARE(GLK_CSR_PATH);
 
-#define I915_CSR_KBL "i915/kbl_dmc_ver1_04.bin"
-MODULE_FIRMWARE(I915_CSR_KBL);
+#define KBL_CSR_PATH                   "i915/kbl_dmc_ver1_04.bin"
 #define KBL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 4)
+#define KBL_CSR_MAX_FW_SIZE            BXT_CSR_MAX_FW_SIZE
+MODULE_FIRMWARE(KBL_CSR_PATH);
 
-#define I915_CSR_SKL "i915/skl_dmc_ver1_27.bin"
-MODULE_FIRMWARE(I915_CSR_SKL);
+#define SKL_CSR_PATH                   "i915/skl_dmc_ver1_27.bin"
 #define SKL_CSR_VERSION_REQUIRED       CSR_VERSION(1, 27)
+#define SKL_CSR_MAX_FW_SIZE            BXT_CSR_MAX_FW_SIZE
+MODULE_FIRMWARE(SKL_CSR_PATH);
 
-#define I915_CSR_BXT "i915/bxt_dmc_ver1_07.bin"
-MODULE_FIRMWARE(I915_CSR_BXT);
+#define BXT_CSR_PATH                   "i915/bxt_dmc_ver1_07.bin"
 #define BXT_CSR_VERSION_REQUIRED       CSR_VERSION(1, 7)
-
-
 #define BXT_CSR_MAX_FW_SIZE            0x3000
-#define GLK_CSR_MAX_FW_SIZE            0x4000
-#define ICL_CSR_MAX_FW_SIZE            0x6000
+MODULE_FIRMWARE(BXT_CSR_PATH);
+
 #define CSR_DEFAULT_FW_OFFSET          0xFFFFFFFF
 
 struct intel_css_header {
@@ -190,6 +194,12 @@ static const struct stepping_info bxt_stepping_info[] = {
        {'B', '0'}, {'B', '1'}, {'B', '2'}
 };
 
+static const struct stepping_info icl_stepping_info[] = {
+       {'A', '0'}, {'A', '1'}, {'A', '2'},
+       {'B', '0'}, {'B', '2'},
+       {'C', '0'}
+};
+
 static const struct stepping_info no_stepping_info = { '*', '*' };
 
 static const struct stepping_info *
@@ -198,7 +208,10 @@ intel_get_stepping_info(struct drm_i915_private *dev_priv)
        const struct stepping_info *si;
        unsigned int size;
 
-       if (IS_SKYLAKE(dev_priv)) {
+       if (IS_ICELAKE(dev_priv)) {
+               size = ARRAY_SIZE(icl_stepping_info);
+               si = icl_stepping_info;
+       } else if (IS_SKYLAKE(dev_priv)) {
                size = ARRAY_SIZE(skl_stepping_info);
                si = skl_stepping_info;
        } else if (IS_BROXTON(dev_priv)) {
@@ -285,10 +298,8 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
        struct intel_csr *csr = &dev_priv->csr;
        const struct stepping_info *si = intel_get_stepping_info(dev_priv);
        uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
-       uint32_t max_fw_size = 0;
        uint32_t i;
        uint32_t *dmc_payload;
-       uint32_t required_version;
 
        if (!fw)
                return NULL;
@@ -303,38 +314,19 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
                return NULL;
        }
 
-       csr->version = css_header->version;
-
-       if (csr->fw_path == i915_modparams.dmc_firmware_path) {
-               /* Bypass version check for firmware override. */
-               required_version = csr->version;
-       } else if (IS_ICELAKE(dev_priv)) {
-               required_version = ICL_CSR_VERSION_REQUIRED;
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               required_version = CNL_CSR_VERSION_REQUIRED;
-       } else if (IS_GEMINILAKE(dev_priv)) {
-               required_version = GLK_CSR_VERSION_REQUIRED;
-       } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
-               required_version = KBL_CSR_VERSION_REQUIRED;
-       } else if (IS_SKYLAKE(dev_priv)) {
-               required_version = SKL_CSR_VERSION_REQUIRED;
-       } else if (IS_BROXTON(dev_priv)) {
-               required_version = BXT_CSR_VERSION_REQUIRED;
-       } else {
-               MISSING_CASE(INTEL_REVID(dev_priv));
-               required_version = 0;
-       }
-
-       if (csr->version != required_version) {
+       if (csr->required_version &&
+           css_header->version != csr->required_version) {
                DRM_INFO("Refusing to load DMC firmware v%u.%u,"
                         " please use v%u.%u\n",
-                        CSR_VERSION_MAJOR(csr->version),
-                        CSR_VERSION_MINOR(csr->version),
-                        CSR_VERSION_MAJOR(required_version),
-                        CSR_VERSION_MINOR(required_version));
+                        CSR_VERSION_MAJOR(css_header->version),
+                        CSR_VERSION_MINOR(css_header->version),
+                        CSR_VERSION_MAJOR(csr->required_version),
+                        CSR_VERSION_MINOR(csr->required_version));
                return NULL;
        }
 
+       csr->version = css_header->version;
+
        readcount += sizeof(struct intel_css_header);
 
        /* Extract Package Header information*/
@@ -402,15 +394,7 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
 
        /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */
        nbytes = dmc_header->fw_size * 4;
-       if (INTEL_GEN(dev_priv) >= 11)
-               max_fw_size = ICL_CSR_MAX_FW_SIZE;
-       else if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
-               max_fw_size = GLK_CSR_MAX_FW_SIZE;
-       else if (IS_GEN9(dev_priv))
-               max_fw_size = BXT_CSR_MAX_FW_SIZE;
-       else
-               MISSING_CASE(INTEL_REVID(dev_priv));
-       if (nbytes > max_fw_size) {
+       if (nbytes > csr->max_fw_size) {
                DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes);
                return NULL;
        }
@@ -475,27 +459,57 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
        if (!HAS_CSR(dev_priv))
                return;
 
-       if (i915_modparams.dmc_firmware_path)
-               csr->fw_path = i915_modparams.dmc_firmware_path;
-       else if (IS_ICELAKE(dev_priv))
-               csr->fw_path = I915_CSR_ICL;
-       else if (IS_CANNONLAKE(dev_priv))
-               csr->fw_path = I915_CSR_CNL;
-       else if (IS_GEMINILAKE(dev_priv))
-               csr->fw_path = I915_CSR_GLK;
-       else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
-               csr->fw_path = I915_CSR_KBL;
-       else if (IS_SKYLAKE(dev_priv))
-               csr->fw_path = I915_CSR_SKL;
-       else if (IS_BROXTON(dev_priv))
-               csr->fw_path = I915_CSR_BXT;
-
        /*
-        * Obtain a runtime pm reference, until CSR is loaded,
-        * to avoid entering runtime-suspend.
+        * Obtain a runtime pm reference, until CSR is loaded, to avoid entering
+        * runtime-suspend.
+        *
+        * On error, we return with the rpm wakeref held to prevent runtime
+        * suspend as runtime suspend *requires* a working CSR for whatever
+        * reason.
         */
        intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 
+       if (INTEL_GEN(dev_priv) >= 12) {
+               /* Allow to load fw via parameter using the last known size */
+               csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE;
+       } else if (IS_ICELAKE(dev_priv)) {
+               csr->fw_path = ICL_CSR_PATH;
+               csr->required_version = ICL_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = ICL_CSR_MAX_FW_SIZE;
+       } else if (IS_CANNONLAKE(dev_priv)) {
+               csr->fw_path = CNL_CSR_PATH;
+               csr->required_version = CNL_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = CNL_CSR_MAX_FW_SIZE;
+       } else if (IS_GEMINILAKE(dev_priv)) {
+               csr->fw_path = GLK_CSR_PATH;
+               csr->required_version = GLK_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = GLK_CSR_MAX_FW_SIZE;
+       } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
+               csr->fw_path = KBL_CSR_PATH;
+               csr->required_version = KBL_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = KBL_CSR_MAX_FW_SIZE;
+       } else if (IS_SKYLAKE(dev_priv)) {
+               csr->fw_path = SKL_CSR_PATH;
+               csr->required_version = SKL_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = SKL_CSR_MAX_FW_SIZE;
+       } else if (IS_BROXTON(dev_priv)) {
+               csr->fw_path = BXT_CSR_PATH;
+               csr->required_version = BXT_CSR_VERSION_REQUIRED;
+               csr->max_fw_size = BXT_CSR_MAX_FW_SIZE;
+       }
+
+       if (i915_modparams.dmc_firmware_path) {
+               if (strlen(i915_modparams.dmc_firmware_path) == 0) {
+                       csr->fw_path = NULL;
+                       DRM_INFO("Disabling CSR firmware and runtime PM\n");
+                       return;
+               }
+
+               csr->fw_path = i915_modparams.dmc_firmware_path;
+               /* Bypass version check for firmware override. */
+               csr->required_version = 0;
+       }
+
        if (csr->fw_path == NULL) {
                DRM_DEBUG_KMS("No known CSR firmware for platform, disabling runtime PM\n");
                WARN_ON(!IS_ALPHA_SUPPORT(INTEL_INFO(dev_priv)));
index 5186cd7075f919b047fb78701cb29a99b9bb8795..f3e1d6a0b7dda7cabb0cc882e40aecbd83a1501c 100644 (file)
@@ -28,6 +28,7 @@
 #include <drm/drm_scdc_helper.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
+#include "intel_dsi.h"
 
 struct ddi_buf_trans {
        u32 trans1;     /* balance leg enable, de-emph level */
@@ -642,7 +643,7 @@ skl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
 static const struct ddi_buf_trans *
 kbl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
 {
-       if (IS_KBL_ULX(dev_priv)) {
+       if (IS_KBL_ULX(dev_priv) || IS_AML_ULX(dev_priv)) {
                *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp);
                return kbl_y_ddi_translations_dp;
        } else if (IS_KBL_ULT(dev_priv) || IS_CFL_ULT(dev_priv)) {
@@ -658,7 +659,7 @@ static const struct ddi_buf_trans *
 skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 {
        if (dev_priv->vbt.edp.low_vswing) {
-               if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv)) {
+               if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) || IS_AML_ULX(dev_priv)) {
                        *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp);
                        return skl_y_ddi_translations_edp;
                } else if (IS_SKL_ULT(dev_priv) || IS_KBL_ULT(dev_priv) ||
@@ -680,7 +681,7 @@ skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 static const struct ddi_buf_trans *
 skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
 {
-       if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv)) {
+       if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv) || IS_AML_ULX(dev_priv)) {
                *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi);
                return skl_y_ddi_translations_hdmi;
        } else {
@@ -1060,10 +1061,10 @@ static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll)
 }
 
 static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder,
-                                      const struct intel_shared_dpll *pll)
+                                      const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       int clock = crtc->config->port_clock;
+       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
+       int clock = crtc_state->port_clock;
        const enum intel_dpll_id id = pll->info->id;
 
        switch (id) {
@@ -1363,8 +1364,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
        return dco_freq / (p0 * p1 * p2 * 5);
 }
 
-static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
-                              enum intel_dpll_id pll_id)
+int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                       enum intel_dpll_id pll_id)
 {
        uint32_t cfgcr0, cfgcr1;
        uint32_t p0, p1, p2, dco_freq, ref_clock;
@@ -1517,7 +1518,7 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
        else
                dotclock = pipe_config->port_clock;
 
-       if (pipe_config->ycbcr420)
+       if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
                dotclock *= 2;
 
        if (pipe_config->pixel_multiplier)
@@ -1737,16 +1738,16 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder,
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 
-       if (INTEL_GEN(dev_priv) <= 8)
-               hsw_ddi_clock_get(encoder, pipe_config);
-       else if (IS_GEN9_BC(dev_priv))
-               skl_ddi_clock_get(encoder, pipe_config);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_ddi_clock_get(encoder, pipe_config);
+       if (IS_ICELAKE(dev_priv))
+               icl_ddi_clock_get(encoder, pipe_config);
        else if (IS_CANNONLAKE(dev_priv))
                cnl_ddi_clock_get(encoder, pipe_config);
-       else if (IS_ICELAKE(dev_priv))
-               icl_ddi_clock_get(encoder, pipe_config);
+       else if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_clock_get(encoder, pipe_config);
+       else if (IS_GEN9_BC(dev_priv))
+               skl_ddi_clock_get(encoder, pipe_config);
+       else if (INTEL_GEN(dev_priv) <= 8)
+               hsw_ddi_clock_get(encoder, pipe_config);
 }
 
 void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
@@ -1784,6 +1785,13 @@ void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
                break;
        }
 
+       /*
+        * As per DP 1.2 spec section 2.3.4.3 while sending
+        * YCBCR 444 signals we should program MSA MISC1/0 fields with
+        * colorspace information. The output colorspace encoding is BT601.
+        */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+               temp |= TRANS_MSA_SAMPLING_444 | TRANS_MSA_CLRSP_YCBCR;
        I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
 }
 
@@ -1998,24 +2006,24 @@ out:
        return ret;
 }
 
-bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
-                           enum pipe *pipe)
+static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
+                                       u8 *pipe_mask, bool *is_dp_mst)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum port port = encoder->port;
        enum pipe p;
        u32 tmp;
-       bool ret;
+       u8 mst_pipe_mask;
+
+       *pipe_mask = 0;
+       *is_dp_mst = false;
 
        if (!intel_display_power_get_if_enabled(dev_priv,
                                                encoder->power_domain))
-               return false;
-
-       ret = false;
+               return;
 
        tmp = I915_READ(DDI_BUF_CTL(port));
-
        if (!(tmp & DDI_BUF_CTL_ENABLE))
                goto out;
 
@@ -2023,44 +2031,58 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
 
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+               default:
+                       MISSING_CASE(tmp & TRANS_DDI_EDP_INPUT_MASK);
+                       /* fallthrough */
                case TRANS_DDI_EDP_INPUT_A_ON:
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
-                       *pipe = PIPE_A;
+                       *pipe_mask = BIT(PIPE_A);
                        break;
                case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                       *pipe = PIPE_B;
+                       *pipe_mask = BIT(PIPE_B);
                        break;
                case TRANS_DDI_EDP_INPUT_C_ONOFF:
-                       *pipe = PIPE_C;
+                       *pipe_mask = BIT(PIPE_C);
                        break;
                }
 
-               ret = true;
-
                goto out;
        }
 
+       mst_pipe_mask = 0;
        for_each_pipe(dev_priv, p) {
-               enum transcoder cpu_transcoder = (enum transcoder) p;
+               enum transcoder cpu_transcoder = (enum transcoder)p;
 
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
 
-               if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
-                       if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
-                           TRANS_DDI_MODE_SELECT_DP_MST)
-                               goto out;
+               if ((tmp & TRANS_DDI_PORT_MASK) != TRANS_DDI_SELECT_PORT(port))
+                       continue;
 
-                       *pipe = p;
-                       ret = true;
+               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
+                   TRANS_DDI_MODE_SELECT_DP_MST)
+                       mst_pipe_mask |= BIT(p);
 
-                       goto out;
-               }
+               *pipe_mask |= BIT(p);
+       }
+
+       if (!*pipe_mask)
+               DRM_DEBUG_KMS("No pipe for ddi port %c found\n",
+                             port_name(port));
+
+       if (!mst_pipe_mask && hweight8(*pipe_mask) > 1) {
+               DRM_DEBUG_KMS("Multiple pipes for non DP-MST port %c (pipe_mask %02x)\n",
+                             port_name(port), *pipe_mask);
+               *pipe_mask = BIT(ffs(*pipe_mask) - 1);
        }
 
-       DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
+       if (mst_pipe_mask && mst_pipe_mask != *pipe_mask)
+               DRM_DEBUG_KMS("Conflicting MST and non-MST encoders for port %c (pipe_mask %02x mst_pipe_mask %02x)\n",
+                             port_name(port), *pipe_mask, mst_pipe_mask);
+       else
+               *is_dp_mst = mst_pipe_mask;
 
 out:
-       if (ret && IS_GEN9_LP(dev_priv)) {
+       if (*pipe_mask && IS_GEN9_LP(dev_priv)) {
                tmp = I915_READ(BXT_PHY_CTL(port));
                if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK |
                            BXT_PHY_LANE_POWERDOWN_ACK |
@@ -2070,12 +2092,26 @@ out:
        }
 
        intel_display_power_put(dev_priv, encoder->power_domain);
+}
 
-       return ret;
+bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
+                           enum pipe *pipe)
+{
+       u8 pipe_mask;
+       bool is_mst;
+
+       intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
+
+       if (is_mst || !pipe_mask)
+               return false;
+
+       *pipe = ffs(pipe_mask) - 1;
+
+       return true;
 }
 
 static inline enum intel_display_power_domain
-intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp)
+intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port)
 {
        /* CNL+ HW requires corresponding AUX IOs to be powered up for PSR with
         * DC states enabled at the same time, while for driver initiated AUX
@@ -2089,13 +2125,14 @@ intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp)
         * Note that PSR is enabled only on Port A even though this function
         * returns the correct domain for other ports too.
         */
-       return intel_dp->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
-                                             intel_dp->aux_power_domain;
+       return dig_port->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
+                                             intel_aux_power_domain(dig_port);
 }
 
 static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder,
                                       struct intel_crtc_state *crtc_state)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_digital_port *dig_port;
        u64 domains;
 
@@ -2110,12 +2147,19 @@ static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder,
        dig_port = enc_to_dig_port(&encoder->base);
        domains = BIT_ULL(dig_port->ddi_io_power_domain);
 
-       /* AUX power is only needed for (e)DP mode, not for HDMI. */
-       if (intel_crtc_has_dp_encoder(crtc_state)) {
-               struct intel_dp *intel_dp = &dig_port->dp;
+       /*
+        * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
+        * ports.
+        */
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               domains |= BIT_ULL(intel_ddi_main_link_aux_domain(dig_port));
 
-               domains |= BIT_ULL(intel_ddi_main_link_aux_domain(intel_dp));
-       }
+       /*
+        * VDSC power is needed when DSC is enabled
+        */
+       if (crtc_state->dsc_params.compression_enable)
+               domains |= BIT_ULL(intel_dsc_power_domain(crtc_state));
 
        return domains;
 }
@@ -2748,77 +2792,130 @@ uint32_t icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
        return 0;
 }
 
-void icl_map_plls_to_ports(struct drm_crtc *crtc,
-                          struct intel_crtc_state *crtc_state,
-                          struct drm_atomic_state *old_state)
+static void icl_map_plls_to_ports(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_shared_dpll *pll = crtc_state->shared_dpll;
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct drm_connector_state *conn_state;
-       struct drm_connector *conn;
-       int i;
+       enum port port = encoder->port;
+       u32 val;
 
-       for_each_new_connector_in_state(old_state, conn, conn_state, i) {
-               struct intel_encoder *encoder =
-                       to_intel_encoder(conn_state->best_encoder);
-               enum port port;
-               uint32_t val;
+       mutex_lock(&dev_priv->dpll_lock);
 
-               if (conn_state->crtc != crtc)
-                       continue;
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0);
 
-               port = encoder->port;
-               mutex_lock(&dev_priv->dpll_lock);
+       if (intel_port_is_combophy(dev_priv, port)) {
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
+               val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
+               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+               POSTING_READ(DPCLKA_CFGCR0_ICL);
+       }
 
-               val = I915_READ(DPCLKA_CFGCR0_ICL);
-               WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0);
+       val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
 
-               if (intel_port_is_combophy(dev_priv, port)) {
-                       val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
-                       val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port);
-                       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
-                       POSTING_READ(DPCLKA_CFGCR0_ICL);
-               }
+       mutex_unlock(&dev_priv->dpll_lock);
+}
 
-               val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port);
-               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+static void icl_unmap_plls_to_ports(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
 
-               mutex_unlock(&dev_priv->dpll_lock);
-       }
+       mutex_lock(&dev_priv->dpll_lock);
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+       I915_WRITE(DPCLKA_CFGCR0_ICL, val);
+
+       mutex_unlock(&dev_priv->dpll_lock);
 }
 
-void icl_unmap_plls_to_ports(struct drm_crtc *crtc,
-                            struct intel_crtc_state *crtc_state,
-                            struct drm_atomic_state *old_state)
+void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct drm_connector_state *old_conn_state;
-       struct drm_connector *conn;
-       int i;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       u32 val;
+       enum port port;
+       u32 port_mask;
+       bool ddi_clk_needed;
+
+       /*
+        * In case of DP MST, we sanitize the primary encoder only, not the
+        * virtual ones.
+        */
+       if (encoder->type == INTEL_OUTPUT_DP_MST)
+               return;
 
-       for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
-               struct intel_encoder *encoder =
-                       to_intel_encoder(old_conn_state->best_encoder);
-               enum port port;
+       if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) {
+               u8 pipe_mask;
+               bool is_mst;
 
-               if (old_conn_state->crtc != crtc)
+               intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);
+               /*
+                * In the unlikely case that BIOS enables DP in MST mode, just
+                * warn since our MST HW readout is incomplete.
+                */
+               if (WARN_ON(is_mst))
+                       return;
+       }
+
+       port_mask = BIT(encoder->port);
+       ddi_clk_needed = encoder->base.crtc;
+
+       if (encoder->type == INTEL_OUTPUT_DSI) {
+               struct intel_encoder *other_encoder;
+
+               port_mask = intel_dsi_encoder_ports(encoder);
+               /*
+                * Sanity check that we haven't incorrectly registered another
+                * encoder using any of the ports of this DSI encoder.
+                */
+               for_each_intel_encoder(&dev_priv->drm, other_encoder) {
+                       if (other_encoder == encoder)
+                               continue;
+
+                       if (WARN_ON(port_mask & BIT(other_encoder->port)))
+                               return;
+               }
+               /*
+                * DSI ports should have their DDI clock ungated when disabled
+                * and gated when enabled.
+                */
+               ddi_clk_needed = !encoder->base.crtc;
+       }
+
+       val = I915_READ(DPCLKA_CFGCR0_ICL);
+       for_each_port_masked(port, port_mask) {
+               bool ddi_clk_ungated = !(val &
+                                        icl_dpclka_cfgcr0_clk_off(dev_priv,
+                                                                  port));
+
+               if (ddi_clk_needed == ddi_clk_ungated)
                        continue;
 
-               port = encoder->port;
-               mutex_lock(&dev_priv->dpll_lock);
-               I915_WRITE(DPCLKA_CFGCR0_ICL,
-                          I915_READ(DPCLKA_CFGCR0_ICL) |
-                          icl_dpclka_cfgcr0_clk_off(dev_priv, port));
-               mutex_unlock(&dev_priv->dpll_lock);
+               /*
+                * Punt on the case now where clock is gated, but it would
+                * be needed by the port. Something else is really broken then.
+                */
+               if (WARN_ON(ddi_clk_needed))
+                       continue;
+
+               DRM_NOTE("Port %c is disabled/in DSI mode with an ungated DDI clock, gate it\n",
+                        port_name(port));
+               val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port);
+               I915_WRITE(DPCLKA_CFGCR0_ICL, val);
        }
 }
 
 static void intel_ddi_clk_select(struct intel_encoder *encoder,
-                                const struct intel_shared_dpll *pll)
+                                const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = encoder->port;
        uint32_t val;
+       const struct intel_shared_dpll *pll = crtc_state->shared_dpll;
 
        if (WARN_ON(!pll))
                return;
@@ -2828,7 +2925,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
        if (IS_ICELAKE(dev_priv)) {
                if (!intel_port_is_combophy(dev_priv, port))
                        I915_WRITE(DDI_CLK_SEL(port),
-                                  icl_pll_to_ddi_pll_sel(encoder, pll));
+                                  icl_pll_to_ddi_pll_sel(encoder, crtc_state));
        } else if (IS_CANNONLAKE(dev_priv)) {
                /* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */
                val = I915_READ(DPCLKA_CFGCR0);
@@ -2881,6 +2978,184 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder)
        }
 }
 
+static void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
+       u32 val;
+       int i;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
+               val = I915_READ(mg_regs[i]);
+               val |= MG_DP_MODE_CFG_TR2PWR_GATING |
+                      MG_DP_MODE_CFG_TRPWR_GATING |
+                      MG_DP_MODE_CFG_CLNPWR_GATING |
+                      MG_DP_MODE_CFG_DIGPWR_GATING |
+                      MG_DP_MODE_CFG_GAONPWR_GATING;
+               I915_WRITE(mg_regs[i], val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) |
+              MG_MISC_SUS0_CFG_TR2PWR_GATING |
+              MG_MISC_SUS0_CFG_CL2PWR_GATING |
+              MG_MISC_SUS0_CFG_GAONPWR_GATING |
+              MG_MISC_SUS0_CFG_TRPWR_GATING |
+              MG_MISC_SUS0_CFG_CL1PWR_GATING |
+              MG_MISC_SUS0_CFG_DGPWR_GATING;
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
+static void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
+       u32 val;
+       int i;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
+               val = I915_READ(mg_regs[i]);
+               val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING |
+                        MG_DP_MODE_CFG_TRPWR_GATING |
+                        MG_DP_MODE_CFG_CLNPWR_GATING |
+                        MG_DP_MODE_CFG_DIGPWR_GATING |
+                        MG_DP_MODE_CFG_GAONPWR_GATING);
+               I915_WRITE(mg_regs[i], val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK |
+                MG_MISC_SUS0_CFG_TR2PWR_GATING |
+                MG_MISC_SUS0_CFG_CL2PWR_GATING |
+                MG_MISC_SUS0_CFG_GAONPWR_GATING |
+                MG_MISC_SUS0_CFG_TRPWR_GATING |
+                MG_MISC_SUS0_CFG_CL1PWR_GATING |
+                MG_MISC_SUS0_CFG_DGPWR_GATING);
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
+static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
+       enum port port = intel_dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       u32 ln0, ln1, lane_info;
+
+       if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT)
+               return;
+
+       ln0 = I915_READ(MG_DP_MODE(port, 0));
+       ln1 = I915_READ(MG_DP_MODE(port, 1));
+
+       switch (intel_dig_port->tc_type) {
+       case TC_PORT_TYPEC:
+               ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
+               ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
+
+               lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
+                            DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
+                           DP_LANE_ASSIGNMENT_SHIFT(tc_port);
+
+               switch (lane_info) {
+               case 0x1:
+               case 0x4:
+                       break;
+               case 0x2:
+                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE;
+                       break;
+               case 0x3:
+                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       break;
+               case 0x8:
+                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE;
+                       break;
+               case 0xC:
+                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       break;
+               case 0xF:
+                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
+                              MG_DP_MODE_CFG_DP_X2_MODE;
+                       break;
+               default:
+                       MISSING_CASE(lane_info);
+               }
+               break;
+
+       case TC_PORT_LEGACY:
+               ln0 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE;
+               ln1 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE;
+               break;
+
+       default:
+               MISSING_CASE(intel_dig_port->tc_type);
+               return;
+       }
+
+       I915_WRITE(MG_DP_MODE(port, 0), ln0);
+       I915_WRITE(MG_DP_MODE(port, 1), ln1);
+}
+
+static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
+                                       const struct intel_crtc_state *crtc_state)
+{
+       if (!crtc_state->fec_enable)
+               return;
+
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0)
+               DRM_DEBUG_KMS("Failed to set FEC_READY in the sink\n");
+}
+
+static void intel_ddi_enable_fec(struct intel_encoder *encoder,
+                                const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+
+       if (!crtc_state->fec_enable)
+               return;
+
+       val = I915_READ(DP_TP_CTL(port));
+       val |= DP_TP_CTL_FEC_ENABLE;
+       I915_WRITE(DP_TP_CTL(port), val);
+
+       if (intel_wait_for_register(dev_priv, DP_TP_STATUS(port),
+                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
+                                   DP_TP_STATUS_FEC_ENABLE_LIVE,
+                                   1))
+               DRM_ERROR("Timed out waiting for FEC Enable Status\n");
+}
+
+static void intel_ddi_disable_fec_state(struct intel_encoder *encoder,
+                                       const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum port port = encoder->port;
+       u32 val;
+
+       if (!crtc_state->fec_enable)
+               return;
+
+       val = I915_READ(DP_TP_CTL(port));
+       val &= ~DP_TP_CTL_FEC_ENABLE;
+       I915_WRITE(DP_TP_CTL(port), val);
+       POSTING_READ(DP_TP_CTL(port));
+}
+
 static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
                                    const struct intel_crtc_state *crtc_state,
                                    const struct drm_connector_state *conn_state)
@@ -2894,19 +3169,16 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 
        WARN_ON(is_mst && (port == PORT_A || port == PORT_E));
 
-       intel_display_power_get(dev_priv,
-                               intel_ddi_main_link_aux_domain(intel_dp));
-
        intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
                                 crtc_state->lane_count, is_mst);
 
        intel_edp_panel_on(intel_dp);
 
-       intel_ddi_clk_select(encoder, crtc_state->shared_dpll);
+       intel_ddi_clk_select(encoder, crtc_state);
 
        intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
 
-       icl_program_mg_dp_mode(intel_dp);
+       icl_program_mg_dp_mode(dig_port);
        icl_disable_phy_clock_gating(dig_port);
 
        if (IS_ICELAKE(dev_priv))
@@ -2922,14 +3194,21 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
        intel_ddi_init_dp_buf_reg(encoder);
        if (!is_mst)
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
+                                             true);
+       intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
        intel_dp_start_link_train(intel_dp);
        if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
                intel_dp_stop_link_train(intel_dp);
 
+       intel_ddi_enable_fec(encoder, crtc_state);
+
        icl_enable_phy_clock_gating(dig_port);
 
        if (!is_mst)
                intel_ddi_enable_pipe_clock(crtc_state);
+
+       intel_dsc_enable(encoder, crtc_state);
 }
 
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
@@ -2944,10 +3223,13 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
 
        intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
-       intel_ddi_clk_select(encoder, crtc_state->shared_dpll);
+       intel_ddi_clk_select(encoder, crtc_state);
 
        intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
 
+       icl_program_mg_dp_mode(dig_port);
+       icl_disable_phy_clock_gating(dig_port);
+
        if (IS_ICELAKE(dev_priv))
                icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
                                        level, INTEL_OUTPUT_HDMI);
@@ -2958,12 +3240,14 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
        else
                intel_prepare_hdmi_ddi_buffers(encoder, level);
 
+       icl_enable_phy_clock_gating(dig_port);
+
        if (IS_GEN9_BC(dev_priv))
                skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
 
        intel_ddi_enable_pipe_clock(crtc_state);
 
-       intel_dig_port->set_infoframes(&encoder->base,
+       intel_dig_port->set_infoframes(encoder,
                                       crtc_state->has_infoframe,
                                       crtc_state, conn_state);
 }
@@ -2991,15 +3275,31 @@ static void intel_ddi_pre_enable(struct intel_encoder *encoder,
 
        WARN_ON(crtc_state->has_pch_encoder);
 
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_map_plls_to_ports(encoder, crtc_state);
+
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
                intel_ddi_pre_enable_hdmi(encoder, crtc_state, conn_state);
-       else
+       } else {
+               struct intel_lspcon *lspcon =
+                               enc_to_intel_lspcon(&encoder->base);
+
                intel_ddi_pre_enable_dp(encoder, crtc_state, conn_state);
+               if (lspcon->active) {
+                       struct intel_digital_port *dig_port =
+                                       enc_to_dig_port(&encoder->base);
+
+                       dig_port->set_infoframes(encoder,
+                                                crtc_state->has_infoframe,
+                                                crtc_state, conn_state);
+               }
+       }
 }
 
-static void intel_disable_ddi_buf(struct intel_encoder *encoder)
+static void intel_disable_ddi_buf(struct intel_encoder *encoder,
+                                 const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = encoder->port;
@@ -3018,6 +3318,9 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder)
        val |= DP_TP_CTL_LINK_TRAIN_PAT1;
        I915_WRITE(DP_TP_CTL(port), val);
 
+       /* Disable FEC in DP Sink */
+       intel_ddi_disable_fec_state(encoder, crtc_state);
+
        if (wait)
                intel_wait_ddi_buf_idle(dev_priv, port);
 }
@@ -3041,7 +3344,7 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        }
 
-       intel_disable_ddi_buf(encoder);
+       intel_disable_ddi_buf(encoder, old_crtc_state);
 
        intel_edp_panel_vdd_on(intel_dp);
        intel_edp_panel_off(intel_dp);
@@ -3049,9 +3352,6 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
        intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
 
        intel_ddi_clk_disable(encoder);
-
-       intel_display_power_put(dev_priv,
-                               intel_ddi_main_link_aux_domain(intel_dp));
 }
 
 static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
@@ -3062,12 +3362,12 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
 
-       dig_port->set_infoframes(&encoder->base, false,
+       dig_port->set_infoframes(encoder, false,
                                 old_crtc_state, old_conn_state);
 
        intel_ddi_disable_pipe_clock(old_crtc_state);
 
-       intel_disable_ddi_buf(encoder);
+       intel_disable_ddi_buf(encoder, old_crtc_state);
 
        intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
 
@@ -3080,6 +3380,8 @@ static void intel_ddi_post_disable(struct intel_encoder *encoder,
                                   const struct intel_crtc_state *old_crtc_state,
                                   const struct drm_connector_state *old_conn_state)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
        /*
         * When called from DP MST code:
         * - old_conn_state will be NULL
@@ -3099,6 +3401,9 @@ static void intel_ddi_post_disable(struct intel_encoder *encoder,
        else
                intel_ddi_post_disable_dp(encoder,
                                          old_crtc_state, old_conn_state);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_unmap_plls_to_ports(encoder);
 }
 
 void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
@@ -3118,7 +3423,7 @@ void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
        val &= ~FDI_RX_ENABLE;
        I915_WRITE(FDI_RX_CTL(PIPE_A), val);
 
-       intel_disable_ddi_buf(encoder);
+       intel_disable_ddi_buf(encoder, old_crtc_state);
        intel_ddi_clk_disable(encoder);
 
        val = I915_READ(FDI_RX_MISC(PIPE_A));
@@ -3154,6 +3459,26 @@ static void intel_enable_ddi_dp(struct intel_encoder *encoder,
                intel_audio_codec_enable(encoder, crtc_state, conn_state);
 }
 
+static i915_reg_t
+gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv,
+                              enum port port)
+{
+       static const i915_reg_t regs[] = {
+               [PORT_A] = CHICKEN_TRANS_EDP,
+               [PORT_B] = CHICKEN_TRANS_A,
+               [PORT_C] = CHICKEN_TRANS_B,
+               [PORT_D] = CHICKEN_TRANS_C,
+               [PORT_E] = CHICKEN_TRANS_A,
+       };
+
+       WARN_ON(INTEL_GEN(dev_priv) < 9);
+
+       if (WARN_ON(port < PORT_A || port > PORT_E))
+               port = PORT_A;
+
+       return regs[port];
+}
+
 static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *crtc_state,
                                  const struct drm_connector_state *conn_state)
@@ -3177,17 +3502,10 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
                 * the bits affect a specific DDI port rather than
                 * a specific transcoder.
                 */
-               static const enum transcoder port_to_transcoder[] = {
-                       [PORT_A] = TRANSCODER_EDP,
-                       [PORT_B] = TRANSCODER_A,
-                       [PORT_C] = TRANSCODER_B,
-                       [PORT_D] = TRANSCODER_C,
-                       [PORT_E] = TRANSCODER_A,
-               };
-               enum transcoder transcoder = port_to_transcoder[port];
+               i915_reg_t reg = gen9_chicken_trans_reg_by_port(dev_priv, port);
                u32 val;
 
-               val = I915_READ(CHICKEN_TRANS(transcoder));
+               val = I915_READ(reg);
 
                if (port == PORT_E)
                        val |= DDIE_TRAINING_OVERRIDE_ENABLE |
@@ -3196,8 +3514,8 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
                        val |= DDI_TRAINING_OVERRIDE_ENABLE |
                                DDI_TRAINING_OVERRIDE_VALUE;
 
-               I915_WRITE(CHICKEN_TRANS(transcoder), val);
-               POSTING_READ(CHICKEN_TRANS(transcoder));
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
 
                udelay(1);
 
@@ -3208,7 +3526,7 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
                        val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
                                 DDI_TRAINING_OVERRIDE_VALUE);
 
-               I915_WRITE(CHICKEN_TRANS(transcoder), val);
+               I915_WRITE(reg, val);
        }
 
        /* In HDMI/DVI mode, the port width, and swing/emphasis values
@@ -3252,6 +3570,9 @@ static void intel_disable_ddi_dp(struct intel_encoder *encoder,
        intel_edp_drrs_disable(intel_dp, old_crtc_state);
        intel_psr_disable(intel_dp, old_crtc_state);
        intel_edp_backlight_off(old_conn_state);
+       /* Disable the decompression in DP Sink */
+       intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
+                                             false);
 }
 
 static void intel_disable_ddi_hdmi(struct intel_encoder *encoder,
@@ -3282,13 +3603,76 @@ static void intel_disable_ddi(struct intel_encoder *encoder,
                intel_disable_ddi_dp(encoder, old_crtc_state, old_conn_state);
 }
 
-static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *pipe_config,
-                                  const struct drm_connector_state *conn_state)
+static void intel_ddi_set_fia_lane_count(struct intel_encoder *encoder,
+                                        const struct intel_crtc_state *pipe_config,
+                                        enum port port)
 {
-       uint8_t mask = pipe_config->lane_lat_optim_mask;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       u32 val = I915_READ(PORT_TX_DFLEXDPMLE1);
+       bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
+
+       val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc_port);
+       switch (pipe_config->lane_count) {
+       case 1:
+               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3(tc_port) :
+               DFLEXDPMLE1_DPMLETC_ML0(tc_port);
+               break;
+       case 2:
+               val |= (lane_reversal) ? DFLEXDPMLE1_DPMLETC_ML3_2(tc_port) :
+               DFLEXDPMLE1_DPMLETC_ML1_0(tc_port);
+               break;
+       case 4:
+               val |= DFLEXDPMLE1_DPMLETC_ML3_0(tc_port);
+               break;
+       default:
+               MISSING_CASE(pipe_config->lane_count);
+       }
+       I915_WRITE(PORT_TX_DFLEXDPMLE1, val);
+}
 
-       bxt_ddi_phy_set_lane_optim_mask(encoder, mask);
+static void
+intel_ddi_pre_pll_enable(struct intel_encoder *encoder,
+                        const struct intel_crtc_state *crtc_state,
+                        const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       enum port port = encoder->port;
+
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               intel_display_power_get(dev_priv,
+                                       intel_ddi_main_link_aux_domain(dig_port));
+
+       if (IS_GEN9_LP(dev_priv))
+               bxt_ddi_phy_set_lane_optim_mask(encoder,
+                                               crtc_state->lane_lat_optim_mask);
+
+       /*
+        * Program the lane count for static/dynamic connections on Type-C ports.
+        * Skip this step for TBT.
+        */
+       if (dig_port->tc_type == TC_PORT_UNKNOWN ||
+           dig_port->tc_type == TC_PORT_TBT)
+               return;
+
+       intel_ddi_set_fia_lane_count(encoder, crtc_state, port);
+}
+
+static void
+intel_ddi_post_pll_disable(struct intel_encoder *encoder,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+
+       if (intel_crtc_has_dp_encoder(crtc_state) ||
+           intel_port_is_tc(dev_priv, encoder->port))
+               intel_display_power_put(dev_priv,
+                                       intel_ddi_main_link_aux_domain(dig_port));
 }
 
 void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
@@ -3353,10 +3737,10 @@ static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
 void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
                                         struct intel_crtc_state *crtc_state)
 {
-       if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000)
-               crtc_state->min_voltage_level = 2;
-       else if (IS_ICELAKE(dev_priv) && crtc_state->port_clock > 594000)
+       if (IS_ICELAKE(dev_priv) && crtc_state->port_clock > 594000)
                crtc_state->min_voltage_level = 1;
+       else if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000)
+               crtc_state->min_voltage_level = 2;
 }
 
 void intel_ddi_get_config(struct intel_encoder *encoder,
@@ -3406,7 +3790,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
                pipe_config->has_hdmi_sink = true;
                intel_dig_port = enc_to_dig_port(&encoder->base);
 
-               if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
+               if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
                        pipe_config->has_infoframe = true;
 
                if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
@@ -3767,6 +4151,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        struct intel_encoder *intel_encoder;
        struct drm_encoder *encoder;
        bool init_hdmi, init_dp, init_lspcon = false;
+       enum pipe pipe;
 
 
        init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
@@ -3805,8 +4190,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        intel_encoder->compute_output_type = intel_ddi_compute_output_type;
        intel_encoder->compute_config = intel_ddi_compute_config;
        intel_encoder->enable = intel_enable_ddi;
-       if (IS_GEN9_LP(dev_priv))
-               intel_encoder->pre_pll_enable = bxt_ddi_pre_pll_enable;
+       intel_encoder->pre_pll_enable = intel_ddi_pre_pll_enable;
+       intel_encoder->post_pll_disable = intel_ddi_post_pll_disable;
        intel_encoder->pre_enable = intel_ddi_pre_enable;
        intel_encoder->disable = intel_disable_ddi;
        intel_encoder->post_disable = intel_ddi_post_disable;
@@ -3817,8 +4202,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
        intel_encoder->type = INTEL_OUTPUT_DDI;
        intel_encoder->power_domain = intel_port_to_power_domain(port);
        intel_encoder->port = port;
-       intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
+       for_each_pipe(dev_priv, pipe)
+               intel_encoder->crtc_mask |= BIT(pipe);
 
        if (INTEL_GEN(dev_priv) >= 11)
                intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
@@ -3828,6 +4214,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                        (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES);
        intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
        intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port);
+       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
 
        switch (port) {
        case PORT_A:
@@ -3858,8 +4245,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                MISSING_CASE(port);
        }
 
-       intel_infoframe_init(intel_dig_port);
-
        if (init_dp) {
                if (!intel_ddi_init_dp_connector(intel_dig_port))
                        goto err;
@@ -3888,6 +4273,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
                                port_name(port));
        }
 
+       intel_infoframe_init(intel_dig_port);
        return;
 
 err:
index 01fa98299bae65a125862e57c307cdbce07c3d32..1e56319334f38ed248a2d12d93ddc3b97937d6c8 100644 (file)
@@ -77,6 +77,10 @@ void intel_device_info_dump_flags(const struct intel_device_info *info,
 #define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->name));
        DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG);
 #undef PRINT_FLAG
+
+#define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->display.name));
+       DEV_INFO_DISPLAY_FOR_EACH_FLAG(PRINT_FLAG);
+#undef PRINT_FLAG
 }
 
 static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
@@ -744,27 +748,30 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
        if (INTEL_GEN(dev_priv) >= 10) {
                for_each_pipe(dev_priv, pipe)
                        info->num_scalers[pipe] = 2;
-       } else if (INTEL_GEN(dev_priv) == 9) {
+       } else if (IS_GEN9(dev_priv)) {
                info->num_scalers[PIPE_A] = 2;
                info->num_scalers[PIPE_B] = 2;
                info->num_scalers[PIPE_C] = 1;
        }
 
-       BUILD_BUG_ON(I915_NUM_ENGINES >
-                    sizeof(intel_ring_mask_t) * BITS_PER_BYTE);
+       BUILD_BUG_ON(I915_NUM_ENGINES > BITS_PER_TYPE(intel_ring_mask_t));
 
-       /*
-        * Skylake and Broxton currently don't expose the topmost plane as its
-        * use is exclusive with the legacy cursor and we only want to expose
-        * one of those, not both. Until we can safely expose the topmost plane
-        * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported,
-        * we don't expose the topmost plane at all to prevent ABI breakage
-        * down the line.
-        */
-       if (IS_GEN10(dev_priv) || IS_GEMINILAKE(dev_priv))
+       if (IS_GEN11(dev_priv))
+               for_each_pipe(dev_priv, pipe)
+                       info->num_sprites[pipe] = 6;
+       else if (IS_GEN10(dev_priv) || IS_GEMINILAKE(dev_priv))
                for_each_pipe(dev_priv, pipe)
                        info->num_sprites[pipe] = 3;
        else if (IS_BROXTON(dev_priv)) {
+               /*
+                * Skylake and Broxton currently don't expose the topmost plane as its
+                * use is exclusive with the legacy cursor and we only want to expose
+                * one of those, not both. Until we can safely expose the topmost plane
+                * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported,
+                * we don't expose the topmost plane at all to prevent ABI breakage
+                * down the line.
+                */
+
                info->num_sprites[PIPE_A] = 2;
                info->num_sprites[PIPE_B] = 2;
                info->num_sprites[PIPE_C] = 1;
@@ -779,7 +786,7 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
        if (i915_modparams.disable_display) {
                DRM_INFO("Display disabled (module parameter)\n");
                info->num_pipes = 0;
-       } else if (info->num_pipes > 0 &&
+       } else if (HAS_DISPLAY(dev_priv) &&
                   (IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) &&
                   HAS_PCH_SPLIT(dev_priv)) {
                u32 fuse_strap = I915_READ(FUSE_STRAP);
@@ -804,7 +811,7 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
                        DRM_INFO("PipeC fused off\n");
                        info->num_pipes -= 1;
                }
-       } else if (info->num_pipes > 0 && IS_GEN9(dev_priv)) {
+       } else if (HAS_DISPLAY(dev_priv) && IS_GEN9(dev_priv)) {
                u32 dfsm = I915_READ(SKL_DFSM);
                u8 disabled_mask = 0;
                bool invalid;
@@ -844,13 +851,18 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
                cherryview_sseu_info_init(dev_priv);
        else if (IS_BROADWELL(dev_priv))
                broadwell_sseu_info_init(dev_priv);
-       else if (INTEL_GEN(dev_priv) == 9)
+       else if (IS_GEN9(dev_priv))
                gen9_sseu_info_init(dev_priv);
-       else if (INTEL_GEN(dev_priv) == 10)
+       else if (IS_GEN10(dev_priv))
                gen10_sseu_info_init(dev_priv);
        else if (INTEL_GEN(dev_priv) >= 11)
                gen11_sseu_info_init(dev_priv);
 
+       if (IS_GEN6(dev_priv) && intel_vtd_active()) {
+               DRM_INFO("Disabling ppGTT for VT-d support\n");
+               info->ppgtt = INTEL_PPGTT_NONE;
+       }
+
        /* Initialize command stream timestamp frequency */
        info->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv);
 }
@@ -872,40 +884,37 @@ void intel_driver_caps_print(const struct intel_driver_caps *caps,
 void intel_device_info_init_mmio(struct drm_i915_private *dev_priv)
 {
        struct intel_device_info *info = mkwrite_device_info(dev_priv);
-       u8 vdbox_disable, vebox_disable;
        u32 media_fuse;
-       int i;
+       unsigned int i;
 
        if (INTEL_GEN(dev_priv) < 11)
                return;
 
-       media_fuse = I915_READ(GEN11_GT_VEBOX_VDBOX_DISABLE);
+       media_fuse = ~I915_READ(GEN11_GT_VEBOX_VDBOX_DISABLE);
 
-       vdbox_disable = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK;
-       vebox_disable = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >>
-                       GEN11_GT_VEBOX_DISABLE_SHIFT;
+       info->vdbox_enable = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK;
+       info->vebox_enable = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >>
+                            GEN11_GT_VEBOX_DISABLE_SHIFT;
 
-       DRM_DEBUG_DRIVER("vdbox disable: %04x\n", vdbox_disable);
+       DRM_DEBUG_DRIVER("vdbox enable: %04x\n", info->vdbox_enable);
        for (i = 0; i < I915_MAX_VCS; i++) {
                if (!HAS_ENGINE(dev_priv, _VCS(i)))
                        continue;
 
-               if (!(BIT(i) & vdbox_disable))
-                       continue;
-
-               info->ring_mask &= ~ENGINE_MASK(_VCS(i));
-               DRM_DEBUG_DRIVER("vcs%u fused off\n", i);
+               if (!(BIT(i) & info->vdbox_enable)) {
+                       info->ring_mask &= ~ENGINE_MASK(_VCS(i));
+                       DRM_DEBUG_DRIVER("vcs%u fused off\n", i);
+               }
        }
 
-       DRM_DEBUG_DRIVER("vebox disable: %04x\n", vebox_disable);
+       DRM_DEBUG_DRIVER("vebox enable: %04x\n", info->vebox_enable);
        for (i = 0; i < I915_MAX_VECS; i++) {
                if (!HAS_ENGINE(dev_priv, _VECS(i)))
                        continue;
 
-               if (!(BIT(i) & vebox_disable))
-                       continue;
-
-               info->ring_mask &= ~ENGINE_MASK(_VECS(i));
-               DRM_DEBUG_DRIVER("vecs%u fused off\n", i);
+               if (!(BIT(i) & info->vebox_enable)) {
+                       info->ring_mask &= ~ENGINE_MASK(_VECS(i));
+                       DRM_DEBUG_DRIVER("vecs%u fused off\n", i);
+               }
        }
 }
index 6eecd64734d51808af700da8f7a41fa399fc0df8..1caf24e2cf0ba5a7d332ef4add45c085f332128c 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef _INTEL_DEVICE_INFO_H_
 #define _INTEL_DEVICE_INFO_H_
 
+#include <uapi/drm/i915_drm.h>
+
 #include "intel_display.h"
 
 struct drm_printer;
@@ -74,51 +76,58 @@ enum intel_platform {
        INTEL_MAX_PLATFORMS
 };
 
+enum intel_ppgtt {
+       INTEL_PPGTT_NONE = I915_GEM_PPGTT_NONE,
+       INTEL_PPGTT_ALIASING = I915_GEM_PPGTT_ALIASING,
+       INTEL_PPGTT_FULL = I915_GEM_PPGTT_FULL,
+       INTEL_PPGTT_FULL_4LVL,
+};
+
 #define DEV_INFO_FOR_EACH_FLAG(func) \
        func(is_mobile); \
        func(is_lp); \
        func(is_alpha_support); \
        /* Keep has_* in alphabetical order */ \
        func(has_64bit_reloc); \
-       func(has_aliasing_ppgtt); \
-       func(has_csr); \
-       func(has_ddi); \
-       func(has_dp_mst); \
        func(has_reset_engine); \
-       func(has_fbc); \
        func(has_fpga_dbg); \
-       func(has_full_ppgtt); \
-       func(has_full_48bit_ppgtt); \
-       func(has_gmch_display); \
        func(has_guc); \
        func(has_guc_ct); \
-       func(has_hotplug); \
        func(has_l3_dpf); \
        func(has_llc); \
        func(has_logical_ring_contexts); \
        func(has_logical_ring_elsq); \
        func(has_logical_ring_preemption); \
-       func(has_overlay); \
        func(has_pooled_eu); \
-       func(has_psr); \
        func(has_rc6); \
        func(has_rc6p); \
        func(has_runtime_pm); \
        func(has_snoop); \
        func(has_coherent_ggtt); \
        func(unfenced_needs_alignment); \
+       func(hws_needs_physical);
+
+#define DEV_INFO_DISPLAY_FOR_EACH_FLAG(func) \
+       /* Keep in alphabetical order */ \
        func(cursor_needs_physical); \
-       func(hws_needs_physical); \
+       func(has_csr); \
+       func(has_ddi); \
+       func(has_dp_mst); \
+       func(has_fbc); \
+       func(has_gmch_display); \
+       func(has_hotplug); \
+       func(has_ipc); \
+       func(has_overlay); \
+       func(has_psr); \
        func(overlay_needs_physical); \
-       func(supports_tv); \
-       func(has_ipc);
+       func(supports_tv);
 
 #define GEN_MAX_SLICES         (6) /* CNL upper bound */
 #define GEN_MAX_SUBSLICES      (8) /* ICL upper bound */
 
 struct sseu_dev_info {
        u8 slice_mask;
-       u8 subslice_mask[GEN_MAX_SUBSLICES];
+       u8 subslice_mask[GEN_MAX_SLICES];
        u16 eu_total;
        u8 eu_per_subslice;
        u8 min_eu_in_pool;
@@ -154,6 +163,7 @@ struct intel_device_info {
        enum intel_platform platform;
        u32 platform_mask;
 
+       enum intel_ppgtt ppgtt;
        unsigned int page_sizes; /* page sizes supported by the HW */
 
        u32 display_mmio_offset;
@@ -165,12 +175,18 @@ struct intel_device_info {
 #define DEFINE_FLAG(name) u8 name:1
        DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG);
 #undef DEFINE_FLAG
+
+       struct {
+#define DEFINE_FLAG(name) u8 name:1
+               DEV_INFO_DISPLAY_FOR_EACH_FLAG(DEFINE_FLAG);
+#undef DEFINE_FLAG
+       } display;
+
        u16 ddb_size; /* in blocks */
 
        /* Register offsets for the various display pipes and transcoders */
        int pipe_offsets[I915_MAX_TRANSCODERS];
        int trans_offsets[I915_MAX_TRANSCODERS];
-       int palette_offsets[I915_MAX_PIPES];
        int cursor_offsets[I915_MAX_PIPES];
 
        /* Slice/subslice/EU info */
@@ -178,6 +194,10 @@ struct intel_device_info {
 
        u32 cs_timestamp_frequency_khz;
 
+       /* Enabled (not fused off) media engine bitmasks. */
+       u8 vdbox_enable;
+       u8 vebox_enable;
+
        struct color_luts {
                u16 degamma_lut_size;
                u16 gamma_lut_size;
index c9878dd1f7cd04dd3a6a7b8877d8f5d95eafc620..07c861884c7068124f3c7835a9f46ff23f0da10f 100644 (file)
@@ -24,7 +24,6 @@
  *     Eric Anholt <eric@anholt.net>
  */
 
-#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
@@ -74,55 +73,6 @@ static const uint64_t i9xx_format_modifiers[] = {
        DRM_FORMAT_MOD_INVALID
 };
 
-static const uint32_t skl_primary_formats[] = {
-       DRM_FORMAT_C8,
-       DRM_FORMAT_RGB565,
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_XBGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_XRGB2101010,
-       DRM_FORMAT_XBGR2101010,
-       DRM_FORMAT_YUYV,
-       DRM_FORMAT_YVYU,
-       DRM_FORMAT_UYVY,
-       DRM_FORMAT_VYUY,
-};
-
-static const uint32_t skl_pri_planar_formats[] = {
-       DRM_FORMAT_C8,
-       DRM_FORMAT_RGB565,
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_XBGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_XRGB2101010,
-       DRM_FORMAT_XBGR2101010,
-       DRM_FORMAT_YUYV,
-       DRM_FORMAT_YVYU,
-       DRM_FORMAT_UYVY,
-       DRM_FORMAT_VYUY,
-       DRM_FORMAT_NV12,
-};
-
-static const uint64_t skl_format_modifiers_noccs[] = {
-       I915_FORMAT_MOD_Yf_TILED,
-       I915_FORMAT_MOD_Y_TILED,
-       I915_FORMAT_MOD_X_TILED,
-       DRM_FORMAT_MOD_LINEAR,
-       DRM_FORMAT_MOD_INVALID
-};
-
-static const uint64_t skl_format_modifiers_ccs[] = {
-       I915_FORMAT_MOD_Yf_TILED_CCS,
-       I915_FORMAT_MOD_Y_TILED_CCS,
-       I915_FORMAT_MOD_Yf_TILED,
-       I915_FORMAT_MOD_Y_TILED,
-       I915_FORMAT_MOD_X_TILED,
-       DRM_FORMAT_MOD_LINEAR,
-       DRM_FORMAT_MOD_INVALID
-};
-
 /* Cursor formats */
 static const uint32_t intel_cursor_formats[] = {
        DRM_FORMAT_ARGB8888,
@@ -141,15 +91,15 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 static int intel_framebuffer_init(struct intel_framebuffer *ifb,
                                  struct drm_i915_gem_object *obj,
                                  struct drm_mode_fb_cmd2 *mode_cmd);
-static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc);
-static void intel_set_pipe_timings(struct intel_crtc *intel_crtc);
-static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc);
-static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n,
-                                        struct intel_link_m_n *m2_n2);
-static void ironlake_set_pipeconf(struct drm_crtc *crtc);
-static void haswell_set_pipeconf(struct drm_crtc *crtc);
-static void haswell_set_pipemisc(struct drm_crtc *crtc);
+static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state);
+static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state);
+static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n,
+                                        const struct intel_link_m_n *m2_n2);
+static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void ironlake_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void haswell_set_pipeconf(const struct intel_crtc_state *crtc_state);
+static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state);
 static void vlv_prepare_pll(struct intel_crtc *crtc,
                            const struct intel_crtc_state *pipe_config);
 static void chv_prepare_pll(struct intel_crtc *crtc,
@@ -158,9 +108,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void intel_crtc_init_scalers(struct intel_crtc *crtc,
                                    struct intel_crtc_state *crtc_state);
-static void skylake_pfit_enable(struct intel_crtc *crtc);
-static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
-static void ironlake_pfit_enable(struct intel_crtc *crtc);
+static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state);
+static void ironlake_pfit_disable(const struct intel_crtc_state *old_crtc_state);
+static void ironlake_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
                                         struct drm_modeset_acquire_ctx *ctx);
 static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
@@ -505,24 +455,9 @@ static const struct intel_limit intel_limits_bxt = {
        .p2 = { .p2_slow = 1, .p2_fast = 20 },
 };
 
-static void
-skl_wa_528(struct drm_i915_private *dev_priv, int pipe, bool enable)
-{
-       if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-               return;
-
-       if (enable)
-               I915_WRITE(CHICKEN_PIPESL_1(pipe), HSW_FBCQ_DIS);
-       else
-               I915_WRITE(CHICKEN_PIPESL_1(pipe), 0);
-}
-
 static void
 skl_wa_clkgate(struct drm_i915_private *dev_priv, int pipe, bool enable)
 {
-       if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-               return;
-
        if (enable)
                I915_WRITE(CLKGATE_DIS_PSL(pipe),
                           DUPS1_GATING_DIS | DUPS2_GATING_DIS);
@@ -1381,6 +1316,7 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
                        "PCH LVDS enabled on transcoder %c, should be disabled\n",
                        pipe_name(pipe));
 
+       /* PCH SDVOB multiplex with HDMIB */
        assert_pch_hdmi_disabled(dev_priv, pipe, PORT_B, PCH_HDMIB);
        assert_pch_hdmi_disabled(dev_priv, pipe, PORT_C, PCH_HDMIC);
        assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID);
@@ -1565,14 +1501,15 @@ static void i9xx_enable_pll(struct intel_crtc *crtc,
        }
 }
 
-static void i9xx_disable_pll(struct intel_crtc *crtc)
+static void i9xx_disable_pll(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
 
        /* Disable DVO 2x clock on both PLLs if necessary */
        if (IS_I830(dev_priv) &&
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DVO) &&
+           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO) &&
            !intel_num_dvo_pipes(dev_priv)) {
                I915_WRITE(DPLL(PIPE_B),
                           I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE);
@@ -1666,16 +1603,16 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
                     I915_READ(dpll_reg) & port_mask, expected_mask);
 }
 
-static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
-                                          enum pipe pipe)
+static void ironlake_enable_pch_transcoder(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
-                                                               pipe);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
        i915_reg_t reg;
        uint32_t val, pipeconf_val;
 
        /* Make sure PCH DPLL is enabled */
-       assert_shared_dpll_enabled(dev_priv, intel_crtc->config->shared_dpll);
+       assert_shared_dpll_enabled(dev_priv, crtc_state->shared_dpll);
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, pipe);
@@ -1701,7 +1638,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
                 * here for both 8bpc and 12bpc.
                 */
                val &= ~PIPECONF_BPC_MASK;
-               if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_HDMI))
+               if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
                        val |= PIPECONF_8BPC;
                else
                        val |= pipeconf_val & PIPECONF_BPC_MASK;
@@ -1710,7 +1647,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        val &= ~TRANS_INTERLACE_MASK;
        if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
                if (HAS_PCH_IBX(dev_priv) &&
-                   intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+                   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        val |= TRANS_LEGACY_INTERLACED_ILK;
                else
                        val |= TRANS_INTERLACED;
@@ -2254,6 +2191,11 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
        return new_offset;
 }
 
+static bool is_surface_linear(u64 modifier, int color_plane)
+{
+       return modifier == DRM_FORMAT_MOD_LINEAR;
+}
+
 static u32 intel_adjust_aligned_offset(int *x, int *y,
                                       const struct drm_framebuffer *fb,
                                       int color_plane,
@@ -2266,7 +2208,7 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
 
        WARN_ON(new_offset > old_offset);
 
-       if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+       if (!is_surface_linear(fb->modifier, color_plane)) {
                unsigned int tile_size, tile_width, tile_height;
                unsigned int pitch_tiles;
 
@@ -2330,14 +2272,13 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
                                        unsigned int rotation,
                                        u32 alignment)
 {
-       uint64_t fb_modifier = fb->modifier;
        unsigned int cpp = fb->format->cpp[color_plane];
        u32 offset, offset_aligned;
 
        if (alignment)
                alignment--;
 
-       if (fb_modifier != DRM_FORMAT_MOD_LINEAR) {
+       if (!is_surface_linear(fb->modifier, color_plane)) {
                unsigned int tile_size, tile_width, tile_height;
                unsigned int tile_rows, tiles, pitch_tiles;
 
@@ -2400,10 +2341,26 @@ static int intel_fb_offset_to_xy(int *x, int *y,
                                 int color_plane)
 {
        struct drm_i915_private *dev_priv = to_i915(fb->dev);
+       unsigned int height;
 
        if (fb->modifier != DRM_FORMAT_MOD_LINEAR &&
-           fb->offsets[color_plane] % intel_tile_size(dev_priv))
+           fb->offsets[color_plane] % intel_tile_size(dev_priv)) {
+               DRM_DEBUG_KMS("Misaligned offset 0x%08x for color plane %d\n",
+                             fb->offsets[color_plane], color_plane);
                return -EINVAL;
+       }
+
+       height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
+       height = ALIGN(height, intel_tile_height(fb, color_plane));
+
+       /* Catch potential overflows early */
+       if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]),
+                           fb->offsets[color_plane])) {
+               DRM_DEBUG_KMS("Bad offset 0x%08x or pitch %d for color plane %d\n",
+                             fb->offsets[color_plane], fb->pitches[color_plane],
+                             color_plane);
+               return -ERANGE;
+       }
 
        *x = 0;
        *y = 0;
@@ -2574,7 +2531,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
                                                      tile_size);
                offset /= tile_size;
 
-               if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+               if (!is_surface_linear(fb->modifier, i)) {
                        unsigned int tile_width, tile_height;
                        unsigned int pitch_tiles;
                        struct drm_rect r;
@@ -2788,10 +2745,6 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state,
                crtc_state->base.plane_mask |= drm_plane_mask(&plane->base);
        else
                crtc_state->base.plane_mask &= ~drm_plane_mask(&plane->base);
-
-       DRM_DEBUG_KMS("%s active planes 0x%x\n",
-                     crtc_state->base.crtc->name,
-                     crtc_state->active_planes);
 }
 
 static void fixup_active_planes(struct intel_crtc_state *crtc_state)
@@ -2819,6 +2772,10 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
        struct intel_plane_state *plane_state =
                to_intel_plane_state(plane->base.state);
 
+       DRM_DEBUG_KMS("Disabling [PLANE:%d:%s] on [CRTC:%d:%s]\n",
+                     plane->base.base.id, plane->base.name,
+                     crtc->base.base.id, crtc->base.name);
+
        intel_set_plane_visible(crtc_state, plane_state, false);
        fixup_active_planes(crtc_state);
 
@@ -2826,7 +2783,7 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
                intel_pre_disable_primary_noatomic(&crtc->base);
 
        trace_intel_disable_plane(&plane->base, crtc);
-       plane->disable_plane(plane, crtc);
+       plane->disable_plane(plane, crtc_state);
 }
 
 static void
@@ -3099,28 +3056,6 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
        return 0;
 }
 
-static int
-skl_check_nv12_surface(struct intel_plane_state *plane_state)
-{
-       /* Display WA #1106 */
-       if (plane_state->base.rotation !=
-           (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90) &&
-           plane_state->base.rotation != DRM_MODE_ROTATE_270)
-               return 0;
-
-       /*
-        * src coordinates are rotated here.
-        * We check height but report it as width
-        */
-       if (((drm_rect_height(&plane_state->base.src) >> 16) % 4) != 0) {
-               DRM_DEBUG_KMS("src width must be multiple "
-                             "of 4 for rotated NV12\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
@@ -3199,9 +3134,6 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
         * the main surface setup depends on it.
         */
        if (fb->format->format == DRM_FORMAT_NV12) {
-               ret = skl_check_nv12_surface(plane_state);
-               if (ret)
-                       return ret;
                ret = skl_check_nv12_aux_surface(plane_state);
                if (ret)
                        return ret;
@@ -3399,7 +3331,6 @@ static void i9xx_update_plane(struct intel_plane *plane,
        enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
        u32 linear_offset;
        u32 dspcntr = plane_state->ctl;
-       i915_reg_t reg = DSPCNTR(i9xx_plane);
        int x = plane_state->color_plane[0].x;
        int y = plane_state->color_plane[0].y;
        unsigned long irqflags;
@@ -3414,48 +3345,51 @@ static void i9xx_update_plane(struct intel_plane *plane,
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
+       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride);
+
        if (INTEL_GEN(dev_priv) < 4) {
                /* pipesrc and dspsize control the size that is scaled from,
                 * which should always be the user's requested size.
                 */
+               I915_WRITE_FW(DSPPOS(i9xx_plane), 0);
                I915_WRITE_FW(DSPSIZE(i9xx_plane),
                              ((crtc_state->pipe_src_h - 1) << 16) |
                              (crtc_state->pipe_src_w - 1));
-               I915_WRITE_FW(DSPPOS(i9xx_plane), 0);
        } else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
+               I915_WRITE_FW(PRIMPOS(i9xx_plane), 0);
                I915_WRITE_FW(PRIMSIZE(i9xx_plane),
                              ((crtc_state->pipe_src_h - 1) << 16) |
                              (crtc_state->pipe_src_w - 1));
-               I915_WRITE_FW(PRIMPOS(i9xx_plane), 0);
                I915_WRITE_FW(PRIMCNSTALPHA(i9xx_plane), 0);
        }
 
-       I915_WRITE_FW(reg, dspcntr);
-
-       I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride);
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
-               I915_WRITE_FW(DSPSURF(i9xx_plane),
-                             intel_plane_ggtt_offset(plane_state) +
-                             dspaddr_offset);
                I915_WRITE_FW(DSPOFFSET(i9xx_plane), (y << 16) | x);
        } else if (INTEL_GEN(dev_priv) >= 4) {
+               I915_WRITE_FW(DSPLINOFF(i9xx_plane), linear_offset);
+               I915_WRITE_FW(DSPTILEOFF(i9xx_plane), (y << 16) | x);
+       }
+
+       /*
+        * The control register self-arms if the plane was previously
+        * disabled. Try to make the plane enable atomic by writing
+        * the control register just before the surface register.
+        */
+       I915_WRITE_FW(DSPCNTR(i9xx_plane), dspcntr);
+       if (INTEL_GEN(dev_priv) >= 4)
                I915_WRITE_FW(DSPSURF(i9xx_plane),
                              intel_plane_ggtt_offset(plane_state) +
                              dspaddr_offset);
-               I915_WRITE_FW(DSPTILEOFF(i9xx_plane), (y << 16) | x);
-               I915_WRITE_FW(DSPLINOFF(i9xx_plane), linear_offset);
-       } else {
+       else
                I915_WRITE_FW(DSPADDR(i9xx_plane),
                              intel_plane_ggtt_offset(plane_state) +
                              dspaddr_offset);
-       }
-       POSTING_READ_FW(reg);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void i9xx_disable_plane(struct intel_plane *plane,
-                              struct intel_crtc *crtc)
+                              const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
@@ -3468,7 +3402,6 @@ static void i9xx_disable_plane(struct intel_plane *plane,
                I915_WRITE_FW(DSPSURF(i9xx_plane), 0);
        else
                I915_WRITE_FW(DSPADDR(i9xx_plane), 0);
-       POSTING_READ_FW(DSPCNTR(i9xx_plane));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -3528,13 +3461,13 @@ static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
 /*
  * This function detaches (aka. unbinds) unused scalers in hardware
  */
-static void skl_detach_scalers(struct intel_crtc *intel_crtc)
+static void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc_scaler_state *scaler_state;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       const struct intel_crtc_scaler_state *scaler_state =
+               &crtc_state->scaler_state;
        int i;
 
-       scaler_state = &intel_crtc->config->scaler_state;
-
        /* loop through and disable scalers that aren't in use */
        for (i = 0; i < intel_crtc->num_scalers; i++) {
                if (!scaler_state->scalers[i].in_use)
@@ -3542,6 +3475,21 @@ static void skl_detach_scalers(struct intel_crtc *intel_crtc)
        }
 }
 
+static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
+                                         int color_plane, unsigned int rotation)
+{
+       /*
+        * The stride is either expressed as a multiple of 64 bytes chunks for
+        * linear buffers or in number of tiles for tiled buffers.
+        */
+       if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
+               return 64;
+       else if (drm_rotation_90_or_270(rotation))
+               return intel_tile_height(fb, color_plane);
+       else
+               return intel_tile_width_bytes(fb, color_plane);
+}
+
 u32 skl_plane_stride(const struct intel_plane_state *plane_state,
                     int color_plane)
 {
@@ -3552,16 +3500,7 @@ u32 skl_plane_stride(const struct intel_plane_state *plane_state,
        if (color_plane >= fb->format->num_planes)
                return 0;
 
-       /*
-        * The stride is either expressed as a multiple of 64 bytes chunks for
-        * linear buffers or in number of tiles for tiled buffers.
-        */
-       if (drm_rotation_90_or_270(rotation))
-               stride /= intel_tile_height(fb, color_plane);
-       else
-               stride /= intel_fb_stride_alignment(fb, color_plane);
-
-       return stride;
+       return stride / skl_plane_stride_mult(fb, color_plane, rotation);
 }
 
 static u32 skl_plane_ctl_format(uint32_t pixel_format)
@@ -3598,29 +3537,38 @@ static u32 skl_plane_ctl_format(uint32_t pixel_format)
        return 0;
 }
 
-/*
- * XXX: For ARBG/ABGR formats we default to expecting scanout buffers
- * to be already pre-multiplied. We need to add a knob (or a different
- * DRM_FORMAT) for user-space to configure that.
- */
-static u32 skl_plane_ctl_alpha(uint32_t pixel_format)
+static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
 {
-       switch (pixel_format) {
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_ARGB8888:
+       if (!plane_state->base.fb->format->has_alpha)
+               return PLANE_CTL_ALPHA_DISABLE;
+
+       switch (plane_state->base.pixel_blend_mode) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+               return PLANE_CTL_ALPHA_DISABLE;
+       case DRM_MODE_BLEND_PREMULTI:
                return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+       case DRM_MODE_BLEND_COVERAGE:
+               return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
        default:
+               MISSING_CASE(plane_state->base.pixel_blend_mode);
                return PLANE_CTL_ALPHA_DISABLE;
        }
 }
 
-static u32 glk_plane_color_ctl_alpha(uint32_t pixel_format)
+static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
 {
-       switch (pixel_format) {
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_ARGB8888:
+       if (!plane_state->base.fb->format->has_alpha)
+               return PLANE_COLOR_ALPHA_DISABLE;
+
+       switch (plane_state->base.pixel_blend_mode) {
+       case DRM_MODE_BLEND_PIXEL_NONE:
+               return PLANE_COLOR_ALPHA_DISABLE;
+       case DRM_MODE_BLEND_PREMULTI:
                return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
+       case DRM_MODE_BLEND_COVERAGE:
+               return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
        default:
+               MISSING_CASE(plane_state->base.pixel_blend_mode);
                return PLANE_COLOR_ALPHA_DISABLE;
        }
 }
@@ -3697,7 +3645,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
        plane_ctl = PLANE_CTL_ENABLE;
 
        if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
-               plane_ctl |= skl_plane_ctl_alpha(fb->format->format);
+               plane_ctl |= skl_plane_ctl_alpha(plane_state);
                plane_ctl |=
                        PLANE_CTL_PIPE_GAMMA_ENABLE |
                        PLANE_CTL_PIPE_CSC_ENABLE |
@@ -3732,6 +3680,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
        struct drm_i915_private *dev_priv =
                to_i915(plane_state->base.plane->dev);
        const struct drm_framebuffer *fb = plane_state->base.fb;
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        u32 plane_color_ctl = 0;
 
        if (INTEL_GEN(dev_priv) < 11) {
@@ -3739,9 +3688,9 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
                plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
        }
        plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
-       plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format);
+       plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
 
-       if (fb->format->is_yuv) {
+       if (fb->format->is_yuv && !icl_is_hdr_plane(plane)) {
                if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
                        plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
                else
@@ -3749,6 +3698,8 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
 
                if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
                        plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
+       } else if (fb->format->is_yuv) {
+               plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
        }
 
        return plane_color_ctl;
@@ -3933,15 +3884,15 @@ static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_sta
 
        /* on skylake this is done by detaching scalers */
        if (INTEL_GEN(dev_priv) >= 9) {
-               skl_detach_scalers(crtc);
+               skl_detach_scalers(new_crtc_state);
 
                if (new_crtc_state->pch_pfit.enabled)
-                       skylake_pfit_enable(crtc);
+                       skylake_pfit_enable(new_crtc_state);
        } else if (HAS_PCH_SPLIT(dev_priv)) {
                if (new_crtc_state->pch_pfit.enabled)
-                       ironlake_pfit_enable(crtc);
+                       ironlake_pfit_enable(new_crtc_state);
                else if (old_crtc_state->pch_pfit.enabled)
-                       ironlake_pfit_disable(crtc, true);
+                       ironlake_pfit_disable(old_crtc_state);
        }
 }
 
@@ -4340,10 +4291,10 @@ train_done:
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
+static void ironlake_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = intel_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
        int pipe = intel_crtc->pipe;
        i915_reg_t reg;
        u32 temp;
@@ -4352,7 +4303,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
        reg = FDI_RX_CTL(pipe);
        temp = I915_READ(reg);
        temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
-       temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
+       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
        temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
        I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
@@ -4501,10 +4452,11 @@ void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
 }
 
 /* Program iCLKIP clock to the desired frequency */
-static void lpt_program_iclkip(struct intel_crtc *crtc)
+static void lpt_program_iclkip(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       int clock = crtc->config->base.adjusted_mode.crtc_clock;
+       int clock = crtc_state->base.adjusted_mode.crtc_clock;
        u32 divsel, phaseinc, auxdiv, phasedir = 0;
        u32 temp;
 
@@ -4615,12 +4567,12 @@ int lpt_get_iclkip(struct drm_i915_private *dev_priv)
                                 desired_divisor << auxdiv);
 }
 
-static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
+static void ironlake_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_state,
                                                enum pipe pch_transcoder)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 
        I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
                   I915_READ(HTOTAL(cpu_transcoder)));
@@ -4639,9 +4591,8 @@ static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
                   I915_READ(VSYNCSHIFT(cpu_transcoder)));
 }
 
-static void cpt_set_fdi_bc_bifurcation(struct drm_device *dev, bool enable)
+static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t temp;
 
        temp = I915_READ(SOUTH_CHICKEN1);
@@ -4660,22 +4611,23 @@ static void cpt_set_fdi_bc_bifurcation(struct drm_device *dev, bool enable)
        POSTING_READ(SOUTH_CHICKEN1);
 }
 
-static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
+static void ivybridge_update_fdi_bc_bifurcation(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = intel_crtc->base.dev;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       switch (intel_crtc->pipe) {
+       switch (crtc->pipe) {
        case PIPE_A:
                break;
        case PIPE_B:
-               if (intel_crtc->config->fdi_lanes > 2)
-                       cpt_set_fdi_bc_bifurcation(dev, false);
+               if (crtc_state->fdi_lanes > 2)
+                       cpt_set_fdi_bc_bifurcation(dev_priv, false);
                else
-                       cpt_set_fdi_bc_bifurcation(dev, true);
+                       cpt_set_fdi_bc_bifurcation(dev_priv, true);
 
                break;
        case PIPE_C:
-               cpt_set_fdi_bc_bifurcation(dev, true);
+               cpt_set_fdi_bc_bifurcation(dev_priv, true);
 
                break;
        default:
@@ -4732,7 +4684,7 @@ static void ironlake_pch_enable(const struct intel_atomic_state *state,
        assert_pch_transcoder_disabled(dev_priv, pipe);
 
        if (IS_IVYBRIDGE(dev_priv))
-               ivybridge_update_fdi_bc_bifurcation(crtc);
+               ivybridge_update_fdi_bc_bifurcation(crtc_state);
 
        /* Write the TU size bits before fdi link training, so that error
         * detection works. */
@@ -4765,11 +4717,11 @@ static void ironlake_pch_enable(const struct intel_atomic_state *state,
         * Note that enable_shared_dpll tries to do the right thing, but
         * get_shared_dpll unconditionally resets the pll - we need that to have
         * the right LVDS enable sequence. */
-       intel_enable_shared_dpll(crtc);
+       intel_enable_shared_dpll(crtc_state);
 
        /* set transcoder timing, panel must allow it */
        assert_panel_unlocked(dev_priv, pipe);
-       ironlake_pch_transcoder_set_timings(crtc, pipe);
+       ironlake_pch_transcoder_set_timings(crtc_state, pipe);
 
        intel_fdi_normal_train(crtc);
 
@@ -4801,7 +4753,7 @@ static void ironlake_pch_enable(const struct intel_atomic_state *state,
                I915_WRITE(reg, temp);
        }
 
-       ironlake_enable_pch_transcoder(dev_priv, pipe);
+       ironlake_enable_pch_transcoder(crtc_state);
 }
 
 static void lpt_pch_enable(const struct intel_atomic_state *state,
@@ -4813,10 +4765,10 @@ static void lpt_pch_enable(const struct intel_atomic_state *state,
 
        assert_pch_transcoder_disabled(dev_priv, PIPE_A);
 
-       lpt_program_iclkip(crtc);
+       lpt_program_iclkip(crtc_state);
 
        /* Set transcoder timing. */
-       ironlake_pch_transcoder_set_timings(crtc, PIPE_A);
+       ironlake_pch_transcoder_set_timings(crtc_state, PIPE_A);
 
        lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
@@ -4904,8 +4856,7 @@ static int
 skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
                  unsigned int scaler_user, int *scaler_id,
                  int src_w, int src_h, int dst_w, int dst_h,
-                 bool plane_scaler_check,
-                 uint32_t pixel_format)
+                 const struct drm_format_info *format, bool need_scaler)
 {
        struct intel_crtc_scaler_state *scaler_state =
                &crtc_state->scaler_state;
@@ -4914,21 +4865,14 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
        struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
        const struct drm_display_mode *adjusted_mode =
                &crtc_state->base.adjusted_mode;
-       int need_scaling;
 
        /*
         * Src coordinates are already rotated by 270 degrees for
         * the 90/270 degree plane rotation cases (to match the
         * GTT mapping), hence no need to account for rotation here.
         */
-       need_scaling = src_w != dst_w || src_h != dst_h;
-
-       if (plane_scaler_check)
-               if (pixel_format == DRM_FORMAT_NV12)
-                       need_scaling = true;
-
-       if (crtc_state->ycbcr420 && scaler_user == SKL_CRTC_INDEX)
-               need_scaling = true;
+       if (src_w != dst_w || src_h != dst_h)
+               need_scaler = true;
 
        /*
         * Scaling/fitting not supported in IF-ID mode in GEN9+
@@ -4937,7 +4881,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
         * for NV12.
         */
        if (INTEL_GEN(dev_priv) >= 9 && crtc_state->base.enable &&
-           need_scaling && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+           need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
                DRM_DEBUG_KMS("Pipe/Plane scaling not supported with IF-ID mode\n");
                return -EINVAL;
        }
@@ -4952,7 +4896,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
         * update to free the scaler is done in plane/panel-fit programming.
         * For this purpose crtc/plane_state->scaler_id isn't reset here.
         */
-       if (force_detach || !need_scaling) {
+       if (force_detach || !need_scaler) {
                if (*scaler_id >= 0) {
                        scaler_state->scaler_users &= ~(1 << scaler_user);
                        scaler_state->scalers[*scaler_id].in_use = 0;
@@ -4966,7 +4910,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
                return 0;
        }
 
-       if (plane_scaler_check && pixel_format == DRM_FORMAT_NV12 &&
+       if (format && format->format == DRM_FORMAT_NV12 &&
            (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) {
                DRM_DEBUG_KMS("NV12: src dimensions not met\n");
                return -EINVAL;
@@ -5009,12 +4953,16 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
 int skl_update_scaler_crtc(struct intel_crtc_state *state)
 {
        const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode;
+       bool need_scaler = false;
+
+       if (state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               need_scaler = true;
 
        return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
                                 &state->scaler_state.scaler_id,
                                 state->pipe_src_w, state->pipe_src_h,
                                 adjusted_mode->crtc_hdisplay,
-                                adjusted_mode->crtc_vdisplay, false, 0);
+                                adjusted_mode->crtc_vdisplay, NULL, need_scaler);
 }
 
 /**
@@ -5029,13 +4977,17 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
 static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
                                   struct intel_plane_state *plane_state)
 {
-
        struct intel_plane *intel_plane =
                to_intel_plane(plane_state->base.plane);
        struct drm_framebuffer *fb = plane_state->base.fb;
        int ret;
-
        bool force_detach = !fb || !plane_state->base.visible;
+       bool need_scaler = false;
+
+       /* Pre-gen11 and SDR planes always need a scaler for planar formats. */
+       if (!icl_is_hdr_plane(intel_plane) &&
+           fb && fb->format->format == DRM_FORMAT_NV12)
+               need_scaler = true;
 
        ret = skl_update_scaler(crtc_state, force_detach,
                                drm_plane_index(&intel_plane->base),
@@ -5044,7 +4996,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
                                drm_rect_height(&plane_state->base.src) >> 16,
                                drm_rect_width(&plane_state->base.dst),
                                drm_rect_height(&plane_state->base.dst),
-                               fb ? true : false, fb ? fb->format->format : 0);
+                               fb ? fb->format : NULL, need_scaler);
 
        if (ret || plane_state->scaler_id < 0)
                return ret;
@@ -5090,27 +5042,27 @@ static void skylake_scaler_disable(struct intel_crtc *crtc)
                skl_detach_scaler(crtc, i);
 }
 
-static void skylake_pfit_enable(struct intel_crtc *crtc)
+static void skylake_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
-       struct intel_crtc_scaler_state *scaler_state =
-               &crtc->config->scaler_state;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       const struct intel_crtc_scaler_state *scaler_state =
+               &crtc_state->scaler_state;
 
-       if (crtc->config->pch_pfit.enabled) {
+       if (crtc_state->pch_pfit.enabled) {
                u16 uv_rgb_hphase, uv_rgb_vphase;
                int pfit_w, pfit_h, hscale, vscale;
                int id;
 
-               if (WARN_ON(crtc->config->scaler_state.scaler_id < 0))
+               if (WARN_ON(crtc_state->scaler_state.scaler_id < 0))
                        return;
 
-               pfit_w = (crtc->config->pch_pfit.size >> 16) & 0xFFFF;
-               pfit_h = crtc->config->pch_pfit.size & 0xFFFF;
+               pfit_w = (crtc_state->pch_pfit.size >> 16) & 0xFFFF;
+               pfit_h = crtc_state->pch_pfit.size & 0xFFFF;
 
-               hscale = (crtc->config->pipe_src_w << 16) / pfit_w;
-               vscale = (crtc->config->pipe_src_h << 16) / pfit_h;
+               hscale = (crtc_state->pipe_src_w << 16) / pfit_w;
+               vscale = (crtc_state->pipe_src_h << 16) / pfit_h;
 
                uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
                uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
@@ -5122,18 +5074,18 @@ static void skylake_pfit_enable(struct intel_crtc *crtc)
                              PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
                I915_WRITE_FW(SKL_PS_HPHASE(pipe, id),
                              PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
-               I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc->config->pch_pfit.pos);
-               I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc->config->pch_pfit.size);
+               I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc_state->pch_pfit.pos);
+               I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc_state->pch_pfit.size);
        }
 }
 
-static void ironlake_pfit_enable(struct intel_crtc *crtc)
+static void ironlake_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        int pipe = crtc->pipe;
 
-       if (crtc->config->pch_pfit.enabled) {
+       if (crtc_state->pch_pfit.enabled) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
@@ -5143,8 +5095,8 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
                                                 PF_PIPE_SEL_IVB(pipe));
                else
                        I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
-               I915_WRITE(PF_WIN_POS(pipe), crtc->config->pch_pfit.pos);
-               I915_WRITE(PF_WIN_SZ(pipe), crtc->config->pch_pfit.size);
+               I915_WRITE(PF_WIN_POS(pipe), crtc_state->pch_pfit.pos);
+               I915_WRITE(PF_WIN_SZ(pipe), crtc_state->pch_pfit.size);
        }
 }
 
@@ -5339,11 +5291,8 @@ static bool needs_nv12_wa(struct drm_i915_private *dev_priv,
        if (!crtc_state->nv12_planes)
                return false;
 
-       if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-               return false;
-
-       if ((INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) ||
-           IS_CANNONLAKE(dev_priv))
+       /* WA Display #0827: Gen9:all */
+       if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv))
                return true;
 
        return false;
@@ -5386,7 +5335,6 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
        if (needs_nv12_wa(dev_priv, old_crtc_state) &&
            !needs_nv12_wa(dev_priv, pipe_config)) {
                skl_wa_clkgate(dev_priv, crtc->pipe, false);
-               skl_wa_528(dev_priv, crtc->pipe, false);
        }
 }
 
@@ -5426,7 +5374,6 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
        if (!needs_nv12_wa(dev_priv, old_crtc_state) &&
            needs_nv12_wa(dev_priv, pipe_config)) {
                skl_wa_clkgate(dev_priv, crtc->pipe, true);
-               skl_wa_528(dev_priv, crtc->pipe, true);
        }
 
        /*
@@ -5449,7 +5396,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
         *
         * WaCxSRDisabledForSpriteScaling:ivb
         */
-       if (pipe_config->disable_lp_wm && ilk_disable_lp_wm(dev))
+       if (pipe_config->disable_lp_wm && ilk_disable_lp_wm(dev) &&
+           old_crtc_state->base.active)
                intel_wait_for_vblank(dev_priv, crtc->pipe);
 
        /*
@@ -5480,24 +5428,32 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
                intel_update_watermarks(crtc);
 }
 
-static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
+static void intel_crtc_disable_planes(struct intel_atomic_state *state,
+                                     struct intel_crtc *crtc)
 {
-       struct drm_device *dev = crtc->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_plane *p;
-       int pipe = intel_crtc->pipe;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       const struct intel_crtc_state *new_crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       unsigned int update_mask = new_crtc_state->update_planes;
+       const struct intel_plane_state *old_plane_state;
+       struct intel_plane *plane;
+       unsigned fb_bits = 0;
+       int i;
 
-       intel_crtc_dpms_overlay_disable(intel_crtc);
+       intel_crtc_dpms_overlay_disable(crtc);
 
-       drm_for_each_plane_mask(p, dev, plane_mask)
-               to_intel_plane(p)->disable_plane(to_intel_plane(p), intel_crtc);
+       for_each_old_intel_plane_in_state(state, plane, old_plane_state, i) {
+               if (crtc->pipe != plane->pipe ||
+                   !(update_mask & BIT(plane->id)))
+                       continue;
 
-       /*
-        * FIXME: Once we grow proper nuclear flip support out of this we need
-        * to compute the mask of flip planes precisely. For the time being
-        * consider this a flip to a NULL plane.
-        */
-       intel_frontbuffer_flip(to_i915(dev), INTEL_FRONTBUFFER_ALL_MASK(pipe));
+               plane->disable_plane(plane, new_crtc_state);
+
+               if (old_plane_state->base.visible)
+                       fb_bits |= plane->frontbuffer_bit;
+       }
+
+       intel_frontbuffer_flip(dev_priv, fb_bits);
 }
 
 static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
@@ -5555,7 +5511,8 @@ static void intel_encoders_enable(struct drm_crtc *crtc,
                if (conn_state->crtc != crtc)
                        continue;
 
-               encoder->enable(encoder, crtc_state, conn_state);
+               if (encoder->enable)
+                       encoder->enable(encoder, crtc_state, conn_state);
                intel_opregion_notify_encoder(encoder, true);
        }
 }
@@ -5576,7 +5533,8 @@ static void intel_encoders_disable(struct drm_crtc *crtc,
                        continue;
 
                intel_opregion_notify_encoder(encoder, false);
-               encoder->disable(encoder, old_crtc_state, old_conn_state);
+               if (encoder->disable)
+                       encoder->disable(encoder, old_crtc_state, old_conn_state);
        }
 }
 
@@ -5647,37 +5605,37 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
        intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
-       if (intel_crtc->config->has_pch_encoder)
-               intel_prepare_shared_dpll(intel_crtc);
+       if (pipe_config->has_pch_encoder)
+               intel_prepare_shared_dpll(pipe_config);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder) {
-               intel_cpu_transcoder_set_m_n(intel_crtc,
-                                    &intel_crtc->config->fdi_m_n, NULL);
+       if (pipe_config->has_pch_encoder) {
+               intel_cpu_transcoder_set_m_n(pipe_config,
+                                            &pipe_config->fdi_m_n, NULL);
        }
 
-       ironlake_set_pipeconf(crtc);
+       ironlake_set_pipeconf(pipe_config);
 
        intel_crtc->active = true;
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc->config->has_pch_encoder) {
+       if (pipe_config->has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
                 * cpu pipes, hence this is separate from all the other fdi/pch
                 * enabling. */
-               ironlake_fdi_pll_enable(intel_crtc);
+               ironlake_fdi_pll_enable(pipe_config);
        } else {
                assert_fdi_tx_disabled(dev_priv, pipe);
                assert_fdi_rx_disabled(dev_priv, pipe);
        }
 
-       ironlake_pfit_enable(intel_crtc);
+       ironlake_pfit_enable(pipe_config);
 
        /*
         * On ILK+ LUT must be loaded before the pipe is running but with
@@ -5686,10 +5644,10 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_color_load_luts(&pipe_config->base);
 
        if (dev_priv->display.initial_watermarks != NULL)
-               dev_priv->display.initial_watermarks(old_intel_state, intel_crtc->config);
+               dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
        intel_enable_pipe(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (pipe_config->has_pch_encoder)
                ironlake_pch_enable(old_intel_state, pipe_config);
 
        assert_vblank_disabled(crtc);
@@ -5706,7 +5664,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
         * some interlaced HDMI modes. Let's do the double wait always
         * in case there are more corner cases we don't know about.
         */
-       if (intel_crtc->config->has_pch_encoder) {
+       if (pipe_config->has_pch_encoder) {
                intel_wait_for_vblank(dev_priv, pipe);
                intel_wait_for_vblank(dev_priv, pipe);
        }
@@ -5740,10 +5698,9 @@ static void icl_pipe_mbus_enable(struct intel_crtc *crtc)
        enum pipe pipe = crtc->pipe;
        uint32_t val;
 
-       val = MBUS_DBOX_BW_CREDIT(1) | MBUS_DBOX_A_CREDIT(2);
-
-       /* Program B credit equally to all pipes */
-       val |= MBUS_DBOX_B_CREDIT(24 / INTEL_INFO(dev_priv)->num_pipes);
+       val = MBUS_DBOX_A_CREDIT(2);
+       val |= MBUS_DBOX_BW_CREDIT(1);
+       val |= MBUS_DBOX_B_CREDIT(8);
 
        I915_WRITE(PIPE_MBUS_DBOX_CTL(pipe), val);
 }
@@ -5755,7 +5712,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe, hsw_workaround_pipe;
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
        struct intel_atomic_state *old_intel_state =
                to_intel_atomic_state(old_state);
        bool psl_clkgate_wa;
@@ -5766,37 +5723,34 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 
        intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc->config->shared_dpll)
-               intel_enable_shared_dpll(intel_crtc);
-
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_map_plls_to_ports(crtc, pipe_config, old_state);
+       if (pipe_config->shared_dpll)
+               intel_enable_shared_dpll(pipe_config);
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
        if (!transcoder_is_dsi(cpu_transcoder))
-               intel_set_pipe_timings(intel_crtc);
+               intel_set_pipe_timings(pipe_config);
 
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_src_size(pipe_config);
 
        if (cpu_transcoder != TRANSCODER_EDP &&
            !transcoder_is_dsi(cpu_transcoder)) {
                I915_WRITE(PIPE_MULT(cpu_transcoder),
-                          intel_crtc->config->pixel_multiplier - 1);
+                          pipe_config->pixel_multiplier - 1);
        }
 
-       if (intel_crtc->config->has_pch_encoder) {
-               intel_cpu_transcoder_set_m_n(intel_crtc,
-                                    &intel_crtc->config->fdi_m_n, NULL);
+       if (pipe_config->has_pch_encoder) {
+               intel_cpu_transcoder_set_m_n(pipe_config,
+                                            &pipe_config->fdi_m_n, NULL);
        }
 
        if (!transcoder_is_dsi(cpu_transcoder))
-               haswell_set_pipeconf(crtc);
+               haswell_set_pipeconf(pipe_config);
 
-       haswell_set_pipemisc(crtc);
+       haswell_set_pipemisc(pipe_config);
 
        intel_color_set_csc(&pipe_config->base);
 
@@ -5804,14 +5758,14 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 
        /* Display WA #1180: WaDisableScalarClockGating: glk, cnl */
        psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
-                        intel_crtc->config->pch_pfit.enabled;
+                        pipe_config->pch_pfit.enabled;
        if (psl_clkgate_wa)
                glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
 
        if (INTEL_GEN(dev_priv) >= 9)
-               skylake_pfit_enable(intel_crtc);
+               skylake_pfit_enable(pipe_config);
        else
-               ironlake_pfit_enable(intel_crtc);
+               ironlake_pfit_enable(pipe_config);
 
        /*
         * On ILK+ LUT must be loaded before the pipe is running but with
@@ -5844,10 +5798,10 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        if (!transcoder_is_dsi(cpu_transcoder))
                intel_enable_pipe(pipe_config);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (pipe_config->has_pch_encoder)
                lpt_pch_enable(old_intel_state, pipe_config);
 
-       if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST))
+       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST))
                intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
        assert_vblank_disabled(crtc);
@@ -5869,15 +5823,15 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        }
 }
 
-static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
+static void ironlake_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        /* To avoid upsetting the power well on haswell only disable the pfit if
         * it's in use. The hw state code will make sure we get this right. */
-       if (force || crtc->config->pch_pfit.enabled) {
+       if (old_crtc_state->pch_pfit.enabled) {
                I915_WRITE(PF_CTL(pipe), 0);
                I915_WRITE(PF_WIN_POS(pipe), 0);
                I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -5908,14 +5862,14 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
 
        intel_disable_pipe(old_crtc_state);
 
-       ironlake_pfit_disable(intel_crtc, false);
+       ironlake_pfit_disable(old_crtc_state);
 
-       if (intel_crtc->config->has_pch_encoder)
+       if (old_crtc_state->has_pch_encoder)
                ironlake_fdi_disable(crtc);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
-       if (intel_crtc->config->has_pch_encoder) {
+       if (old_crtc_state->has_pch_encoder) {
                ironlake_disable_pch_transcoder(dev_priv, pipe);
 
                if (HAS_PCH_CPT(dev_priv)) {
@@ -5966,24 +5920,24 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
        if (!transcoder_is_dsi(cpu_transcoder))
                intel_ddi_disable_transcoder_func(old_crtc_state);
 
+       intel_dsc_disable(old_crtc_state);
+
        if (INTEL_GEN(dev_priv) >= 9)
                skylake_scaler_disable(intel_crtc);
        else
-               ironlake_pfit_disable(intel_crtc, false);
+               ironlake_pfit_disable(old_crtc_state);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
-       if (INTEL_GEN(dev_priv) >= 11)
-               icl_unmap_plls_to_ports(crtc, old_crtc_state, old_state);
+       intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
 }
 
-static void i9xx_pfit_enable(struct intel_crtc *crtc)
+static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc_state *pipe_config = crtc->config;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       if (!pipe_config->gmch_pfit.control)
+       if (!crtc_state->gmch_pfit.control)
                return;
 
        /*
@@ -5993,8 +5947,8 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
        WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
        assert_pipe_disabled(dev_priv, crtc->pipe);
 
-       I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
-       I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
+       I915_WRITE(PFIT_PGM_RATIOS, crtc_state->gmch_pfit.pgm_ratios);
+       I915_WRITE(PFIT_CONTROL, crtc_state->gmch_pfit.control);
 
        /* Border color in case we don't scale up to the full screen. Black by
         * default, change to something else for debugging. */
@@ -6049,6 +6003,28 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port)
        }
 }
 
+enum intel_display_power_domain
+intel_aux_power_domain(struct intel_digital_port *dig_port)
+{
+       switch (dig_port->aux_ch) {
+       case AUX_CH_A:
+               return POWER_DOMAIN_AUX_A;
+       case AUX_CH_B:
+               return POWER_DOMAIN_AUX_B;
+       case AUX_CH_C:
+               return POWER_DOMAIN_AUX_C;
+       case AUX_CH_D:
+               return POWER_DOMAIN_AUX_D;
+       case AUX_CH_E:
+               return POWER_DOMAIN_AUX_E;
+       case AUX_CH_F:
+               return POWER_DOMAIN_AUX_F;
+       default:
+               MISSING_CASE(dig_port->aux_ch);
+               return POWER_DOMAIN_AUX_A;
+       }
+}
+
 static u64 get_crtc_power_domains(struct drm_crtc *crtc,
                                  struct intel_crtc_state *crtc_state)
 {
@@ -6128,20 +6104,18 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        if (WARN_ON(intel_crtc->active))
                return;
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
        if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
-               struct drm_i915_private *dev_priv = to_i915(dev);
-
                I915_WRITE(CHV_BLEND(pipe), CHV_BLEND_LEGACY);
                I915_WRITE(CHV_CANVAS(pipe), 0);
        }
 
-       i9xx_set_pipeconf(intel_crtc);
+       i9xx_set_pipeconf(pipe_config);
 
        intel_color_set_csc(&pipe_config->base);
 
@@ -6152,16 +6126,16 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
 
        if (IS_CHERRYVIEW(dev_priv)) {
-               chv_prepare_pll(intel_crtc, intel_crtc->config);
-               chv_enable_pll(intel_crtc, intel_crtc->config);
+               chv_prepare_pll(intel_crtc, pipe_config);
+               chv_enable_pll(intel_crtc, pipe_config);
        } else {
-               vlv_prepare_pll(intel_crtc, intel_crtc->config);
-               vlv_enable_pll(intel_crtc, intel_crtc->config);
+               vlv_prepare_pll(intel_crtc, pipe_config);
+               vlv_enable_pll(intel_crtc, pipe_config);
        }
 
        intel_encoders_pre_enable(crtc, pipe_config, old_state);
 
-       i9xx_pfit_enable(intel_crtc);
+       i9xx_pfit_enable(pipe_config);
 
        intel_color_load_luts(&pipe_config->base);
 
@@ -6175,13 +6149,13 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
-static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
+static void i9xx_set_pll_dividers(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       I915_WRITE(FP0(crtc->pipe), crtc->config->dpll_hw_state.fp0);
-       I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
+       I915_WRITE(FP0(crtc->pipe), crtc_state->dpll_hw_state.fp0);
+       I915_WRITE(FP1(crtc->pipe), crtc_state->dpll_hw_state.fp1);
 }
 
 static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
@@ -6198,15 +6172,15 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        if (WARN_ON(intel_crtc->active))
                return;
 
-       i9xx_set_pll_dividers(intel_crtc);
+       i9xx_set_pll_dividers(pipe_config);
 
-       if (intel_crtc_has_dp_encoder(intel_crtc->config))
-               intel_dp_set_m_n(intel_crtc, M1_N1);
+       if (intel_crtc_has_dp_encoder(pipe_config))
+               intel_dp_set_m_n(pipe_config, M1_N1);
 
-       intel_set_pipe_timings(intel_crtc);
-       intel_set_pipe_src_size(intel_crtc);
+       intel_set_pipe_timings(pipe_config);
+       intel_set_pipe_src_size(pipe_config);
 
-       i9xx_set_pipeconf(intel_crtc);
+       i9xx_set_pipeconf(pipe_config);
 
        intel_crtc->active = true;
 
@@ -6217,13 +6191,13 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 
        i9xx_enable_pll(intel_crtc, pipe_config);
 
-       i9xx_pfit_enable(intel_crtc);
+       i9xx_pfit_enable(pipe_config);
 
        intel_color_load_luts(&pipe_config->base);
 
        if (dev_priv->display.initial_watermarks != NULL)
                dev_priv->display.initial_watermarks(old_intel_state,
-                                                    intel_crtc->config);
+                                                    pipe_config);
        else
                intel_update_watermarks(intel_crtc);
        intel_enable_pipe(pipe_config);
@@ -6234,12 +6208,12 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
        intel_encoders_enable(crtc, pipe_config, old_state);
 }
 
-static void i9xx_pfit_disable(struct intel_crtc *crtc)
+static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       if (!crtc->config->gmch_pfit.control)
+       if (!old_crtc_state->gmch_pfit.control)
                return;
 
        assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -6272,17 +6246,17 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
 
        intel_disable_pipe(old_crtc_state);
 
-       i9xx_pfit_disable(intel_crtc);
+       i9xx_pfit_disable(old_crtc_state);
 
        intel_encoders_post_disable(crtc, old_crtc_state, old_state);
 
-       if (!intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI)) {
+       if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DSI)) {
                if (IS_CHERRYVIEW(dev_priv))
                        chv_disable_pll(dev_priv, pipe);
                else if (IS_VALLEYVIEW(dev_priv))
                        vlv_disable_pll(dev_priv, pipe);
                else
-                       i9xx_disable_pll(intel_crtc);
+                       i9xx_disable_pll(old_crtc_state);
        }
 
        intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
@@ -6356,7 +6330,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
 
        intel_fbc_disable(intel_crtc);
        intel_update_watermarks(intel_crtc);
-       intel_disable_shared_dpll(intel_crtc);
+       intel_disable_shared_dpll(to_intel_crtc_state(crtc->state));
 
        domains = intel_crtc->enabled_power_domains;
        for_each_power_domain(domain, domains)
@@ -6434,66 +6408,6 @@ static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
        }
 }
 
-int intel_connector_init(struct intel_connector *connector)
-{
-       struct intel_digital_connector_state *conn_state;
-
-       /*
-        * Allocate enough memory to hold intel_digital_connector_state,
-        * This might be a few bytes too many, but for connectors that don't
-        * need it we'll free the state and allocate a smaller one on the first
-        * succesful commit anyway.
-        */
-       conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
-       if (!conn_state)
-               return -ENOMEM;
-
-       __drm_atomic_helper_connector_reset(&connector->base,
-                                           &conn_state->base);
-
-       return 0;
-}
-
-struct intel_connector *intel_connector_alloc(void)
-{
-       struct intel_connector *connector;
-
-       connector = kzalloc(sizeof *connector, GFP_KERNEL);
-       if (!connector)
-               return NULL;
-
-       if (intel_connector_init(connector) < 0) {
-               kfree(connector);
-               return NULL;
-       }
-
-       return connector;
-}
-
-/*
- * Free the bits allocated by intel_connector_alloc.
- * This should only be used after intel_connector_alloc has returned
- * successfully, and before drm_connector_init returns successfully.
- * Otherwise the destroy callbacks for the connector and the state should
- * take care of proper cleanup/free
- */
-void intel_connector_free(struct intel_connector *connector)
-{
-       kfree(to_intel_digital_connector_state(connector->base.state));
-       kfree(connector);
-}
-
-/* Simple connector->get_hw_state implementation for encoders that support only
- * one connector and no cloning and hence the encoder state determines the state
- * of the connector. */
-bool intel_connector_get_hw_state(struct intel_connector *connector)
-{
-       enum pipe pipe = 0;
-       struct intel_encoder *encoder = connector->encoder;
-
-       return encoder->get_hw_state(encoder, &pipe);
-}
-
 static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
 {
        if (crtc_state->base.enable && crtc_state->has_pch_encoder)
@@ -6604,6 +6518,9 @@ retry:
                               link_bw, &pipe_config->fdi_m_n, false);
 
        ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
+       if (ret == -EDEADLK)
+               return ret;
+
        if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
                pipe_config->pipe_bpp -= 2*3;
                DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
@@ -6760,7 +6677,9 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
                return -EINVAL;
        }
 
-       if (pipe_config->ycbcr420 && pipe_config->base.ctm) {
+       if ((pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+            pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) &&
+            pipe_config->base.ctm) {
                /*
                 * There is only one pipe CSC unit per pipe, and we need that
                 * for output conversion from RGB->YCBCR. So if CTM is already
@@ -6835,7 +6754,7 @@ static void compute_m_n(unsigned int m, unsigned int n,
 }
 
 void
-intel_link_compute_m_n(int bits_per_pixel, int nlanes,
+intel_link_compute_m_n(u16 bits_per_pixel, int nlanes,
                       int pixel_clock, int link_clock,
                       struct intel_link_m_n *m_n,
                       bool constant_n)
@@ -6926,12 +6845,12 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
        vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 }
 
-static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n)
+static void intel_pch_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int pipe = crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
        I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n);
@@ -6939,25 +6858,39 @@ static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
        I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n);
 }
 
-static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n,
-                                        struct intel_link_m_n *m2_n2)
+static bool transcoder_has_m2_n2(struct drm_i915_private *dev_priv,
+                                enum transcoder transcoder)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       int pipe = crtc->pipe;
-       enum transcoder transcoder = crtc->config->cpu_transcoder;
+       if (IS_HASWELL(dev_priv))
+               return transcoder == TRANSCODER_EDP;
 
-       if (INTEL_GEN(dev_priv) >= 5) {
-               I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
+       /*
+        * Strictly speaking some registers are available before
+        * gen7, but we only support DRRS on gen7+
+        */
+       return IS_GEN7(dev_priv) || IS_CHERRYVIEW(dev_priv);
+}
+
+static void intel_cpu_transcoder_set_m_n(const struct intel_crtc_state *crtc_state,
+                                        const struct intel_link_m_n *m_n,
+                                        const struct intel_link_m_n *m2_n2)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum transcoder transcoder = crtc_state->cpu_transcoder;
+
+       if (INTEL_GEN(dev_priv) >= 5) {
+               I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
                I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
                I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
                I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
-               /* M2_N2 registers to be set only for gen < 8 (M2_N2 available
-                * for gen < 8) and if DRRS is supported (to make sure the
-                * registers are not unnecessarily accessed).
+               /*
+                *  M2_N2 registers are set only if DRRS is supported
+                * (to make sure the registers are not unnecessarily accessed).
                 */
-               if (m2_n2 && (IS_CHERRYVIEW(dev_priv) ||
-                   INTEL_GEN(dev_priv) < 8) && crtc->config->has_drrs) {
+               if (m2_n2 && crtc_state->has_drrs &&
+                   transcoder_has_m2_n2(dev_priv, transcoder)) {
                        I915_WRITE(PIPE_DATA_M2(transcoder),
                                        TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
                        I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
@@ -6972,29 +6905,29 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
        }
 }
 
-void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n)
+void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_set m_n)
 {
-       struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
+       const struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
 
        if (m_n == M1_N1) {
-               dp_m_n = &crtc->config->dp_m_n;
-               dp_m2_n2 = &crtc->config->dp_m2_n2;
+               dp_m_n = &crtc_state->dp_m_n;
+               dp_m2_n2 = &crtc_state->dp_m2_n2;
        } else if (m_n == M2_N2) {
 
                /*
                 * M2_N2 registers are not supported. Hence m2_n2 divider value
                 * needs to be programmed into M1_N1.
                 */
-               dp_m_n = &crtc->config->dp_m2_n2;
+               dp_m_n = &crtc_state->dp_m2_n2;
        } else {
                DRM_ERROR("Unsupported divider value\n");
                return;
        }
 
-       if (crtc->config->has_pch_encoder)
-               intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
+       if (crtc_state->has_pch_encoder)
+               intel_pch_transcoder_set_m_n(crtc_state, &crtc_state->dp_m_n);
        else
-               intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2);
+               intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2);
 }
 
 static void vlv_compute_dpll(struct intel_crtc *crtc,
@@ -7093,8 +7026,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
 
        /* Set HBR and RBR LPF coefficients */
        if (pipe_config->port_clock == 162000 ||
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_ANALOG) ||
-           intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
+           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) ||
+           intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
                vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x009f0003);
        else
@@ -7121,7 +7054,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
 
        coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
-       if (intel_crtc_has_dp_encoder(crtc->config))
+       if (intel_crtc_has_dp_encoder(pipe_config))
                coreclk |= 0x01000000;
        vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
 
@@ -7400,12 +7333,13 @@ static void i8xx_compute_dpll(struct intel_crtc *crtc,
        crtc_state->dpll_hw_state.dpll = dpll;
 }
 
-static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
+static void intel_set_pipe_timings(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-       enum pipe pipe = intel_crtc->pipe;
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-       const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
        uint32_t crtc_vtotal, crtc_vblank_end;
        int vsyncshift = 0;
 
@@ -7419,7 +7353,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
                crtc_vtotal -= 1;
                crtc_vblank_end -= 1;
 
-               if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+               if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        vsyncshift = (adjusted_mode->crtc_htotal - 1) / 2;
                else
                        vsyncshift = adjusted_mode->crtc_hsync_start -
@@ -7461,18 +7395,18 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
 
 }
 
-static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc)
+static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = intel_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum pipe pipe = intel_crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
 
        /* pipesrc controls the size that is scaled from, which should
         * always be the user's requested size.
         */
        I915_WRITE(PIPESRC(pipe),
-                  ((intel_crtc->config->pipe_src_w - 1) << 16) |
-                  (intel_crtc->config->pipe_src_h - 1));
+                  ((crtc_state->pipe_src_w - 1) << 16) |
+                  (crtc_state->pipe_src_h - 1));
 }
 
 static void intel_get_pipe_timings(struct intel_crtc *crtc,
@@ -7548,29 +7482,30 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
        drm_mode_set_name(mode);
 }
 
-static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
+static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        uint32_t pipeconf;
 
        pipeconf = 0;
 
        /* we keep both pipes enabled on 830 */
        if (IS_I830(dev_priv))
-               pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
+               pipeconf |= I915_READ(PIPECONF(crtc->pipe)) & PIPECONF_ENABLE;
 
-       if (intel_crtc->config->double_wide)
+       if (crtc_state->double_wide)
                pipeconf |= PIPECONF_DOUBLE_WIDE;
 
        /* only g4x and later have fancy bpc/dither controls */
        if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
            IS_CHERRYVIEW(dev_priv)) {
                /* Bspec claims that we can't use dithering for 30bpp pipes. */
-               if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
+               if (crtc_state->dither && crtc_state->pipe_bpp != 30)
                        pipeconf |= PIPECONF_DITHER_EN |
                                    PIPECONF_DITHER_TYPE_SP;
 
-               switch (intel_crtc->config->pipe_bpp) {
+               switch (crtc_state->pipe_bpp) {
                case 18:
                        pipeconf |= PIPECONF_6BPC;
                        break;
@@ -7586,9 +7521,9 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
                }
        }
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
                if (INTEL_GEN(dev_priv) < 4 ||
-                   intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
+                   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
                        pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
                else
                        pipeconf |= PIPECONF_INTERLACE_W_SYNC_SHIFT;
@@ -7596,11 +7531,11 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
                pipeconf |= PIPECONF_PROGRESSIVE;
 
        if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-            intel_crtc->config->limited_color_range)
+            crtc_state->limited_color_range)
                pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
 
-       I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
-       POSTING_READ(PIPECONF(intel_crtc->pipe));
+       I915_WRITE(PIPECONF(crtc->pipe), pipeconf);
+       POSTING_READ(PIPECONF(crtc->pipe));
 }
 
 static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
@@ -7963,6 +7898,49 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock);
 }
 
+static void intel_get_crtc_ycbcr_config(struct intel_crtc *crtc,
+                                       struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum intel_output_format output = INTEL_OUTPUT_FORMAT_RGB;
+
+       pipe_config->lspcon_downsampling = false;
+
+       if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
+               u32 tmp = I915_READ(PIPEMISC(crtc->pipe));
+
+               if (tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV) {
+                       bool ycbcr420_enabled = tmp & PIPEMISC_YUV420_ENABLE;
+                       bool blend = tmp & PIPEMISC_YUV420_MODE_FULL_BLEND;
+
+                       if (ycbcr420_enabled) {
+                               /* We support 4:2:0 in full blend mode only */
+                               if (!blend)
+                                       output = INTEL_OUTPUT_FORMAT_INVALID;
+                               else if (!(IS_GEMINILAKE(dev_priv) ||
+                                          INTEL_GEN(dev_priv) >= 10))
+                                       output = INTEL_OUTPUT_FORMAT_INVALID;
+                               else
+                                       output = INTEL_OUTPUT_FORMAT_YCBCR420;
+                       } else {
+                               /*
+                                * Currently there is no interface defined to
+                                * check user preference between RGB/YCBCR444
+                                * or YCBCR420. So the only possible case for
+                                * YCBCR444 usage is driving YCBCR420 output
+                                * with LSPCON, when pipe is configured for
+                                * YCBCR444 output and LSPCON takes care of
+                                * downsampling it.
+                                */
+                               pipe_config->lspcon_downsampling = true;
+                               output = INTEL_OUTPUT_FORMAT_YCBCR444;
+                       }
+               }
+       }
+
+       pipe_config->output_format = output;
+}
+
 static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                                 struct intel_crtc_state *pipe_config)
 {
@@ -7975,6 +7953,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = NULL;
 
@@ -8506,16 +8485,16 @@ void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
                lpt_init_pch_refclk(dev_priv);
 }
 
-static void ironlake_set_pipeconf(struct drm_crtc *crtc)
+static void ironlake_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
        uint32_t val;
 
        val = 0;
 
-       switch (intel_crtc->config->pipe_bpp) {
+       switch (crtc_state->pipe_bpp) {
        case 18:
                val |= PIPECONF_6BPC;
                break;
@@ -8533,32 +8512,32 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
                BUG();
        }
 
-       if (intel_crtc->config->dither)
+       if (crtc_state->dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
                val |= PIPECONF_INTERLACED_ILK;
        else
                val |= PIPECONF_PROGRESSIVE;
 
-       if (intel_crtc->config->limited_color_range)
+       if (crtc_state->limited_color_range)
                val |= PIPECONF_COLOR_RANGE_SELECT;
 
        I915_WRITE(PIPECONF(pipe), val);
        POSTING_READ(PIPECONF(pipe));
 }
 
-static void haswell_set_pipeconf(struct drm_crtc *crtc)
+static void haswell_set_pipeconf(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
        u32 val = 0;
 
-       if (IS_HASWELL(dev_priv) && intel_crtc->config->dither)
+       if (IS_HASWELL(dev_priv) && crtc_state->dither)
                val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-       if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+       if (crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
                val |= PIPECONF_INTERLACED_ILK;
        else
                val |= PIPECONF_PROGRESSIVE;
@@ -8567,16 +8546,15 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
        POSTING_READ(PIPECONF(cpu_transcoder));
 }
 
-static void haswell_set_pipemisc(struct drm_crtc *crtc)
+static void haswell_set_pipemisc(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *config = intel_crtc->config;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
 
        if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
                u32 val = 0;
 
-               switch (intel_crtc->config->pipe_bpp) {
+               switch (crtc_state->pipe_bpp) {
                case 18:
                        val |= PIPEMISC_DITHER_6_BPC;
                        break;
@@ -8594,14 +8572,16 @@ static void haswell_set_pipemisc(struct drm_crtc *crtc)
                        BUG();
                }
 
-               if (intel_crtc->config->dither)
+               if (crtc_state->dither)
                        val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
 
-               if (config->ycbcr420) {
-                       val |= PIPEMISC_OUTPUT_COLORSPACE_YUV |
-                               PIPEMISC_YUV420_ENABLE |
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
+                   crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+                       val |= PIPEMISC_OUTPUT_COLORSPACE_YUV;
+
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+                       val |= PIPEMISC_YUV420_ENABLE |
                                PIPEMISC_YUV420_MODE_FULL_BLEND;
-               }
 
                I915_WRITE(PIPEMISC(intel_crtc->pipe), val);
        }
@@ -8812,12 +8792,8 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
                m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
                m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder))
                            & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
-               /* Read M2_N2 registers only for gen < 8 (M2_N2 available for
-                * gen < 8) and if DRRS is supported (to make sure the
-                * registers are not unnecessarily read).
-                */
-               if (m2_n2 && INTEL_GEN(dev_priv) < 8 &&
-                       crtc->config->has_drrs) {
+
+               if (m2_n2 && transcoder_has_m2_n2(dev_priv, transcoder)) {
                        m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
                        m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder));
                        m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder))
@@ -8993,7 +8969,7 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb->width = ((val >> 0) & 0x1fff) + 1;
 
        val = I915_READ(PLANE_STRIDE(pipe, plane_id));
-       stride_mult = intel_fb_stride_alignment(fb, 0);
+       stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0);
        fb->pitches[0] = (val & 0x3ff) * stride_mult;
 
        aligned_height = intel_fb_align_height(fb, 0, fb->height);
@@ -9049,6 +9025,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = NULL;
 
@@ -9356,10 +9333,12 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
 static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
                                      struct intel_crtc_state *crtc_state)
 {
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_atomic_state *state =
                to_intel_atomic_state(crtc_state->base.state);
 
-       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) {
+       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
+           IS_ICELAKE(dev_priv)) {
                struct intel_encoder *encoder =
                        intel_get_crtc_new_encoder(state, crtc_state);
 
@@ -9397,30 +9376,17 @@ static void icelake_get_ddi_pll(struct drm_i915_private *dev_priv,
        u32 temp;
 
        /* TODO: TBT pll not implemented. */
-       switch (port) {
-       case PORT_A:
-       case PORT_B:
+       if (intel_port_is_combophy(dev_priv, port)) {
                temp = I915_READ(DPCLKA_CFGCR0_ICL) &
                       DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
                id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
 
-               if (WARN_ON(id != DPLL_ID_ICL_DPLL0 && id != DPLL_ID_ICL_DPLL1))
+               if (WARN_ON(!intel_dpll_is_combophy(id)))
                        return;
-               break;
-       case PORT_C:
-               id = DPLL_ID_ICL_MGPLL1;
-               break;
-       case PORT_D:
-               id = DPLL_ID_ICL_MGPLL2;
-               break;
-       case PORT_E:
-               id = DPLL_ID_ICL_MGPLL3;
-               break;
-       case PORT_F:
-               id = DPLL_ID_ICL_MGPLL4;
-               break;
-       default:
-               MISSING_CASE(port);
+       } else if (intel_port_is_tc(dev_priv, port)) {
+               id = icl_port_to_mg_pll_id(port);
+       } else {
+               WARN(1, "Invalid port %x\n", port);
                return;
        }
 
@@ -9510,11 +9476,18 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum intel_display_power_domain power_domain;
+       unsigned long panel_transcoder_mask = BIT(TRANSCODER_EDP);
+       unsigned long enabled_panel_transcoders = 0;
+       enum transcoder panel_transcoder;
        u32 tmp;
 
+       if (IS_ICELAKE(dev_priv))
+               panel_transcoder_mask |=
+                       BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1);
+
        /*
         * The pipe->transcoder mapping is fixed with the exception of the eDP
-        * transcoder handled below.
+        * and DSI transcoders handled below.
         */
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
 
@@ -9522,29 +9495,49 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
         * XXX: Do intel_display_power_get_if_enabled before reading this (for
         * consistency and less surprising code; it's in always on power).
         */
-       tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-       if (tmp & TRANS_DDI_FUNC_ENABLE) {
-               enum pipe trans_edp_pipe;
+       for_each_set_bit(panel_transcoder, &panel_transcoder_mask, 32) {
+               enum pipe trans_pipe;
+
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(panel_transcoder));
+               if (!(tmp & TRANS_DDI_FUNC_ENABLE))
+                       continue;
+
+               /*
+                * Log all enabled ones, only use the first one.
+                *
+                * FIXME: This won't work for two separate DSI displays.
+                */
+               enabled_panel_transcoders |= BIT(panel_transcoder);
+               if (enabled_panel_transcoders != BIT(panel_transcoder))
+                       continue;
+
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
                default:
-                       WARN(1, "unknown pipe linked to edp transcoder\n");
+                       WARN(1, "unknown pipe linked to transcoder %s\n",
+                            transcoder_name(panel_transcoder));
                        /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
                case TRANS_DDI_EDP_INPUT_A_ON:
-                       trans_edp_pipe = PIPE_A;
+                       trans_pipe = PIPE_A;
                        break;
                case TRANS_DDI_EDP_INPUT_B_ONOFF:
-                       trans_edp_pipe = PIPE_B;
+                       trans_pipe = PIPE_B;
                        break;
                case TRANS_DDI_EDP_INPUT_C_ONOFF:
-                       trans_edp_pipe = PIPE_C;
+                       trans_pipe = PIPE_C;
                        break;
                }
 
-               if (trans_edp_pipe == crtc->pipe)
-                       pipe_config->cpu_transcoder = TRANSCODER_EDP;
+               if (trans_pipe == crtc->pipe)
+                       pipe_config->cpu_transcoder = panel_transcoder;
        }
 
+       /*
+        * Valid combos: none, eDP, DSI0, DSI1, DSI0+DSI1
+        */
+       WARN_ON((enabled_panel_transcoders & BIT(TRANSCODER_EDP)) &&
+               enabled_panel_transcoders != BIT(TRANSCODER_EDP));
+
        power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
@@ -9677,33 +9670,18 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        if (!active)
                goto out;
 
-       if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
+       if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
+           IS_ICELAKE(dev_priv)) {
                haswell_get_ddi_port_state(crtc, pipe_config);
                intel_get_pipe_timings(crtc, pipe_config);
        }
 
        intel_get_pipe_src_size(crtc, pipe_config);
+       intel_get_crtc_ycbcr_config(crtc, pipe_config);
 
        pipe_config->gamma_mode =
                I915_READ(GAMMA_MODE(crtc->pipe)) & GAMMA_MODE_MODE_MASK;
 
-       if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
-               u32 tmp = I915_READ(PIPEMISC(crtc->pipe));
-               bool clrspace_yuv = tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV;
-
-               if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) >= 10) {
-                       bool blend_mode_420 = tmp &
-                                             PIPEMISC_YUV420_MODE_FULL_BLEND;
-
-                       pipe_config->ycbcr420 = tmp & PIPEMISC_YUV420_ENABLE;
-                       if (pipe_config->ycbcr420 != clrspace_yuv ||
-                           pipe_config->ycbcr420 != blend_mode_420)
-                               DRM_DEBUG_KMS("Bad 4:2:0 mode (%08x)\n", tmp);
-               } else if (clrspace_yuv) {
-                       DRM_DEBUG_KMS("YCbCr 4:2:0 Unsupported\n");
-               }
-       }
-
        power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
        if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
                power_domain_mask |= BIT_ULL(power_domain);
@@ -9749,7 +9727,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
        const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        u32 base;
 
-       if (INTEL_INFO(dev_priv)->cursor_needs_physical)
+       if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
                base = obj->phys_handle->busaddr;
        else
                base = intel_plane_ggtt_offset(plane_state);
@@ -9972,15 +9950,13 @@ static void i845_update_cursor(struct intel_plane *plane,
                I915_WRITE_FW(CURPOS(PIPE_A), pos);
        }
 
-       POSTING_READ_FW(CURCNTR(PIPE_A));
-
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void i845_disable_cursor(struct intel_plane *plane,
-                               struct intel_crtc *crtc)
+                               const struct intel_crtc_state *crtc_state)
 {
-       i845_update_cursor(plane, NULL, NULL);
+       i845_update_cursor(plane, crtc_state, NULL);
 }
 
 static bool i845_cursor_get_hw_state(struct intel_plane *plane,
@@ -10171,8 +10147,8 @@ static void i9xx_update_cursor(struct intel_plane *plane,
         * On some platforms writing CURCNTR first will also
         * cause CURPOS to be armed by the CURBASE write.
         * Without the CURCNTR write the CURPOS write would
-        * arm itself. Thus we always start the full update
-        * with a CURCNTR write.
+        * arm itself. Thus we always update CURCNTR before
+        * CURPOS.
         *
         * On other platforms CURPOS always requires the
         * CURBASE write to arm the update. Additonally
@@ -10182,15 +10158,20 @@ static void i9xx_update_cursor(struct intel_plane *plane,
         * cursor that doesn't appear to move, or even change
         * shape. Thus we always write CURBASE.
         *
-        * CURCNTR and CUR_FBC_CTL are always
-        * armed by the CURBASE write only.
+        * The other registers are armed by by the CURBASE write
+        * except when the plane is getting enabled at which time
+        * the CURCNTR write arms the update.
         */
+
+       if (INTEL_GEN(dev_priv) >= 9)
+               skl_write_cursor_wm(plane, crtc_state);
+
        if (plane->cursor.base != base ||
            plane->cursor.size != fbc_ctl ||
            plane->cursor.cntl != cntl) {
-               I915_WRITE_FW(CURCNTR(pipe), cntl);
                if (HAS_CUR_FBC(dev_priv))
                        I915_WRITE_FW(CUR_FBC_CTL(pipe), fbc_ctl);
+               I915_WRITE_FW(CURCNTR(pipe), cntl);
                I915_WRITE_FW(CURPOS(pipe), pos);
                I915_WRITE_FW(CURBASE(pipe), base);
 
@@ -10202,15 +10183,13 @@ static void i9xx_update_cursor(struct intel_plane *plane,
                I915_WRITE_FW(CURBASE(pipe), base);
        }
 
-       POSTING_READ_FW(CURBASE(pipe));
-
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void i9xx_disable_cursor(struct intel_plane *plane,
-                               struct intel_crtc *crtc)
+                               const struct intel_crtc_state *crtc_state)
 {
-       i9xx_update_cursor(plane, NULL, NULL);
+       i9xx_update_cursor(plane, crtc_state, NULL);
 }
 
 static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
@@ -10808,14 +10787,40 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
                pipe_config->fb_bits |= plane->frontbuffer_bit;
 
        /*
+        * ILK/SNB DVSACNTR/Sprite Enable
+        * IVB SPR_CTL/Sprite Enable
+        * "When in Self Refresh Big FIFO mode, a write to enable the
+        *  plane will be internally buffered and delayed while Big FIFO
+        *  mode is exiting."
+        *
+        * Which means that enabling the sprite can take an extra frame
+        * when we start in big FIFO mode (LP1+). Thus we need to drop
+        * down to LP0 and wait for vblank in order to make sure the
+        * sprite gets enabled on the next vblank after the register write.
+        * Doing otherwise would risk enabling the sprite one frame after
+        * we've already signalled flip completion. We can resume LP1+
+        * once the sprite has been enabled.
+        *
+        *
         * WaCxSRDisabledForSpriteScaling:ivb
+        * IVB SPR_SCALE/Scaling Enable
+        * "Low Power watermarks must be disabled for at least one
+        *  frame before enabling sprite scaling, and kept disabled
+        *  until sprite scaling is disabled."
         *
-        * cstate->update_wm was already set above, so this flag will
-        * take effect when we commit and program watermarks.
+        * ILK/SNB DVSASCALE/Scaling Enable
+        * "When in Self Refresh Big FIFO mode, scaling enable will be
+        *  masked off while Big FIFO mode is exiting."
+        *
+        * Despite the w/a only being listed for IVB we assume that
+        * the ILK/SNB note has similar ramifications, hence we apply
+        * the w/a on all three platforms.
         */
-       if (plane->id == PLANE_SPRITE0 && IS_IVYBRIDGE(dev_priv) &&
-           needs_scaling(to_intel_plane_state(plane_state)) &&
-           !needs_scaling(old_plane_state))
+       if (plane->id == PLANE_SPRITE0 &&
+           (IS_GEN5(dev_priv) || IS_GEN6(dev_priv) ||
+            IS_IVYBRIDGE(dev_priv)) &&
+           (turn_on || (!needs_scaling(old_plane_state) &&
+                        needs_scaling(to_intel_plane_state(plane_state)))))
                pipe_config->disable_lp_wm = true;
 
        return 0;
@@ -10851,6 +10856,101 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
        return true;
 }
 
+static int icl_add_linked_planes(struct intel_atomic_state *state)
+{
+       struct intel_plane *plane, *linked;
+       struct intel_plane_state *plane_state, *linked_plane_state;
+       int i;
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               linked = plane_state->linked_plane;
+
+               if (!linked)
+                       continue;
+
+               linked_plane_state = intel_atomic_get_plane_state(state, linked);
+               if (IS_ERR(linked_plane_state))
+                       return PTR_ERR(linked_plane_state);
+
+               WARN_ON(linked_plane_state->linked_plane != plane);
+               WARN_ON(linked_plane_state->slave == plane_state->slave);
+       }
+
+       return 0;
+}
+
+static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->base.state);
+       struct intel_plane *plane, *linked;
+       struct intel_plane_state *plane_state;
+       int i;
+
+       if (INTEL_GEN(dev_priv) < 11)
+               return 0;
+
+       /*
+        * Destroy all old plane links and make the slave plane invisible
+        * in the crtc_state->active_planes mask.
+        */
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               if (plane->pipe != crtc->pipe || !plane_state->linked_plane)
+                       continue;
+
+               plane_state->linked_plane = NULL;
+               if (plane_state->slave && !plane_state->base.visible) {
+                       crtc_state->active_planes &= ~BIT(plane->id);
+                       crtc_state->update_planes |= BIT(plane->id);
+               }
+
+               plane_state->slave = false;
+       }
+
+       if (!crtc_state->nv12_planes)
+               return 0;
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               struct intel_plane_state *linked_state = NULL;
+
+               if (plane->pipe != crtc->pipe ||
+                   !(crtc_state->nv12_planes & BIT(plane->id)))
+                       continue;
+
+               for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, linked) {
+                       if (!icl_is_nv12_y_plane(linked->id))
+                               continue;
+
+                       if (crtc_state->active_planes & BIT(linked->id))
+                               continue;
+
+                       linked_state = intel_atomic_get_plane_state(state, linked);
+                       if (IS_ERR(linked_state))
+                               return PTR_ERR(linked_state);
+
+                       break;
+               }
+
+               if (!linked_state) {
+                       DRM_DEBUG_KMS("Need %d free Y planes for NV12\n",
+                                     hweight8(crtc_state->nv12_planes));
+
+                       return -EINVAL;
+               }
+
+               plane_state->linked_plane = linked;
+
+               linked_state->slave = true;
+               linked_state->linked_plane = plane;
+               crtc_state->active_planes |= BIT(linked->id);
+               crtc_state->update_planes |= BIT(linked->id);
+               DRM_DEBUG_KMS("Using %s as Y plane for %s\n", linked->base.name, plane->base.name);
+       }
+
+       return 0;
+}
+
 static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                                   struct drm_crtc_state *crtc_state)
 {
@@ -10859,7 +10959,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc_state);
-       struct drm_atomic_state *state = crtc_state->state;
        int ret;
        bool mode_changed = needs_modeset(crtc_state);
 
@@ -10896,8 +10995,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                }
        }
 
-       if (dev_priv->display.compute_intermediate_wm &&
-           !to_intel_atomic_state(state)->skip_intermediate_wm) {
+       if (dev_priv->display.compute_intermediate_wm) {
                if (WARN_ON(!dev_priv->display.compute_pipe_wm))
                        return 0;
 
@@ -10913,15 +11011,14 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                        DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n");
                        return ret;
                }
-       } else if (dev_priv->display.compute_intermediate_wm) {
-               if (HAS_PCH_SPLIT(dev_priv) && INTEL_GEN(dev_priv) < 9)
-                       pipe_config->wm.ilk.intermediate = pipe_config->wm.ilk.optimal;
        }
 
        if (INTEL_GEN(dev_priv) >= 9) {
                if (mode_changed)
                        ret = skl_update_scaler_crtc(pipe_config);
 
+               if (!ret)
+                       ret = icl_check_nv12_planes(pipe_config);
                if (!ret)
                        ret = skl_check_pipe_max_pixel_rate(intel_crtc,
                                                            pipe_config);
@@ -10937,8 +11034,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
-       .atomic_begin = intel_begin_crtc_commit,
-       .atomic_flush = intel_finish_crtc_commit,
        .atomic_check = intel_crtc_atomic_check,
 };
 
@@ -10967,30 +11062,42 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
        drm_connector_list_iter_end(&conn_iter);
 }
 
-static void
-connected_sink_compute_bpp(struct intel_connector *connector,
-                          struct intel_crtc_state *pipe_config)
+static int
+compute_sink_pipe_bpp(const struct drm_connector_state *conn_state,
+                     struct intel_crtc_state *pipe_config)
 {
-       const struct drm_display_info *info = &connector->base.display_info;
-       int bpp = pipe_config->pipe_bpp;
+       struct drm_connector *connector = conn_state->connector;
+       const struct drm_display_info *info = &connector->display_info;
+       int bpp;
 
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
-                     connector->base.base.id,
-                     connector->base.name);
-
-       /* Don't use an invalid EDID bpc value */
-       if (info->bpc != 0 && info->bpc * 3 < bpp) {
-               DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
-                             bpp, info->bpc * 3);
-               pipe_config->pipe_bpp = info->bpc * 3;
+       switch (conn_state->max_bpc) {
+       case 6 ... 7:
+               bpp = 6 * 3;
+               break;
+       case 8 ... 9:
+               bpp = 8 * 3;
+               break;
+       case 10 ... 11:
+               bpp = 10 * 3;
+               break;
+       case 12:
+               bpp = 12 * 3;
+               break;
+       default:
+               return -EINVAL;
        }
 
-       /* Clamp bpp to 8 on screens without EDID 1.4 */
-       if (info->bpc == 0 && bpp > 24) {
-               DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
-                             bpp);
-               pipe_config->pipe_bpp = 24;
+       if (bpp < pipe_config->pipe_bpp) {
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Limiting display bpp to %d instead of "
+                             "EDID bpp %d, requested bpp %d, max platform bpp %d\n",
+                             connector->base.id, connector->name,
+                             bpp, 3 * info->bpc, 3 * conn_state->max_requested_bpc,
+                             pipe_config->pipe_bpp);
+
+               pipe_config->pipe_bpp = bpp;
        }
+
+       return 0;
 }
 
 static int
@@ -10998,7 +11105,7 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
                          struct intel_crtc_state *pipe_config)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct drm_atomic_state *state;
+       struct drm_atomic_state *state = pipe_config->base.state;
        struct drm_connector *connector;
        struct drm_connector_state *connector_state;
        int bpp, i;
@@ -11011,21 +11118,21 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
        else
                bpp = 8*3;
 
-
        pipe_config->pipe_bpp = bpp;
 
-       state = pipe_config->base.state;
-
-       /* Clamp display bpp to EDID value */
+       /* Clamp display bpp to connector max bpp */
        for_each_new_connector_in_state(state, connector, connector_state, i) {
+               int ret;
+
                if (connector_state->crtc != &crtc->base)
                        continue;
 
-               connected_sink_compute_bpp(to_intel_connector(connector),
-                                          pipe_config);
+               ret = compute_sink_pipe_bpp(connector_state, pipe_config);
+               if (ret)
+                       return ret;
        }
 
-       return bpp;
+       return 0;
 }
 
 static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
@@ -11095,6 +11202,20 @@ static void snprintf_output_types(char *buf, size_t len,
        WARN_ON_ONCE(output_types != 0);
 }
 
+static const char * const output_format_str[] = {
+       [INTEL_OUTPUT_FORMAT_INVALID] = "Invalid",
+       [INTEL_OUTPUT_FORMAT_RGB] = "RGB",
+       [INTEL_OUTPUT_FORMAT_YCBCR420] = "YCBCR4:2:0",
+       [INTEL_OUTPUT_FORMAT_YCBCR444] = "YCBCR4:4:4",
+};
+
+static const char *output_formats(enum intel_output_format format)
+{
+       if (format >= ARRAY_SIZE(output_format_str))
+               format = INTEL_OUTPUT_FORMAT_INVALID;
+       return output_format_str[format];
+}
+
 static void intel_dump_pipe_config(struct intel_crtc *crtc,
                                   struct intel_crtc_state *pipe_config,
                                   const char *context)
@@ -11114,6 +11235,9 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("output_types: %s (0x%x)\n",
                      buf, pipe_config->output_types);
 
+       DRM_DEBUG_KMS("output format: %s\n",
+                     output_formats(pipe_config->output_format));
+
        DRM_DEBUG_KMS("cpu_transcoder: %s, pipe bpp: %i, dithering: %i\n",
                      transcoder_name(pipe_config->cpu_transcoder),
                      pipe_config->pipe_bpp, pipe_config->dither);
@@ -11123,9 +11247,6 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                                      pipe_config->fdi_lanes,
                                      &pipe_config->fdi_m_n);
 
-       if (pipe_config->ycbcr420)
-               DRM_DEBUG_KMS("YCbCr 4:2:0 output enabled\n");
-
        if (intel_crtc_has_dp_encoder(pipe_config)) {
                intel_dump_m_n_config(pipe_config, "dp m_n",
                                pipe_config->lane_count, &pipe_config->dp_m_n);
@@ -11314,7 +11435,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
        struct intel_encoder *encoder;
        struct drm_connector *connector;
        struct drm_connector_state *connector_state;
-       int base_bpp, ret = -EINVAL;
+       int base_bpp, ret;
        int i;
        bool retry = true;
 
@@ -11336,10 +11457,12 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
              (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
                pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
 
-       base_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
-                                            pipe_config);
-       if (base_bpp < 0)
-               goto fail;
+       ret = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
+                                       pipe_config);
+       if (ret)
+               return ret;
+
+       base_bpp = pipe_config->pipe_bpp;
 
        /*
         * Determine the real pipe dimensions. Note that stereo modes can
@@ -11361,7 +11484,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
 
                if (!check_single_encoder_cloning(state, to_intel_crtc(crtc), encoder)) {
                        DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
-                       goto fail;
+                       return -EINVAL;
                }
 
                /*
@@ -11397,7 +11520,7 @@ encoder_retry:
 
                if (!(encoder->compute_config(encoder, pipe_config, connector_state))) {
                        DRM_DEBUG_KMS("Encoder config failure\n");
-                       goto fail;
+                       return -EINVAL;
                }
        }
 
@@ -11408,16 +11531,16 @@ encoder_retry:
                        * pipe_config->pixel_multiplier;
 
        ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
+       if (ret == -EDEADLK)
+               return ret;
        if (ret < 0) {
                DRM_DEBUG_KMS("CRTC fixup failed\n");
-               goto fail;
+               return ret;
        }
 
        if (ret == RETRY) {
-               if (WARN(!retry, "loop in pipe configuration computation\n")) {
-                       ret = -EINVAL;
-                       goto fail;
-               }
+               if (WARN(!retry, "loop in pipe configuration computation\n"))
+                       return -EINVAL;
 
                DRM_DEBUG_KMS("CRTC bw constrained, retrying\n");
                retry = false;
@@ -11433,8 +11556,7 @@ encoder_retry:
        DRM_DEBUG_KMS("hw max bpp: %i, pipe bpp: %i, dithering: %i\n",
                      base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
 
-fail:
-       return ret;
+       return 0;
 }
 
 static bool intel_fuzzy_clock_check(int clock1, int clock2)
@@ -11703,6 +11825,7 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
        PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end);
 
        PIPE_CONF_CHECK_I(pixel_multiplier);
+       PIPE_CONF_CHECK_I(output_format);
        PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
        if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
            IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@ -11711,7 +11834,6 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
        PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
        PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
        PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_infoframe);
-       PIPE_CONF_CHECK_BOOL(ycbcr420);
 
        PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
 
@@ -11833,6 +11955,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
        struct skl_pipe_wm hw_wm, *sw_wm;
        struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
        struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
+       struct skl_ddb_entry hw_ddb_y[I915_MAX_PLANES];
+       struct skl_ddb_entry hw_ddb_uv[I915_MAX_PLANES];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        const enum pipe pipe = intel_crtc->pipe;
        int plane, level, max_level = ilk_wm_max_level(dev_priv);
@@ -11843,6 +11967,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
        skl_pipe_wm_get_hw_state(crtc, &hw_wm);
        sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
 
+       skl_pipe_ddb_get_hw_state(intel_crtc, hw_ddb_y, hw_ddb_uv);
+
        skl_ddb_get_hw_state(dev_priv, &hw_ddb);
        sw_ddb = &dev_priv->wm.skl_hw.ddb;
 
@@ -11885,8 +12011,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
                }
 
                /* DDB */
-               hw_ddb_entry = &hw_ddb.plane[pipe][plane];
-               sw_ddb_entry = &sw_ddb->plane[pipe][plane];
+               hw_ddb_entry = &hw_ddb_y[plane];
+               sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[plane];
 
                if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
                        DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
@@ -11935,8 +12061,8 @@ static void verify_wm_state(struct drm_crtc *crtc,
                }
 
                /* DDB */
-               hw_ddb_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
-               sw_ddb_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
+               hw_ddb_entry = &hw_ddb_y[PLANE_CURSOR];
+               sw_ddb_entry = &to_intel_crtc_state(new_state)->wm.skl.plane_ddb_y[PLANE_CURSOR];
 
                if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
                        DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
@@ -12220,8 +12346,9 @@ intel_modeset_verify_disabled(struct drm_device *dev,
        verify_disabled_dpll_state(dev);
 }
 
-static void update_scanline_offset(struct intel_crtc *crtc)
+static void update_scanline_offset(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
        /*
@@ -12252,7 +12379,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
         * answer that's slightly in the future.
         */
        if (IS_GEN2(dev_priv)) {
-               const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+               const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
                int vtotal;
 
                vtotal = adjusted_mode->crtc_vtotal;
@@ -12261,7 +12388,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
 
                crtc->scanline_offset = vtotal - 1;
        } else if (HAS_DDI(dev_priv) &&
-                  intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
+                  intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
                crtc->scanline_offset = 2;
        } else
                crtc->scanline_offset = 1;
@@ -12544,6 +12671,8 @@ static int intel_atomic_check(struct drm_device *dev,
                }
 
                ret = intel_modeset_pipe_config(crtc, pipe_config);
+               if (ret == -EDEADLK)
+                       return ret;
                if (ret) {
                        intel_dump_pipe_config(to_intel_crtc(crtc),
                                               pipe_config, "[failed]");
@@ -12575,6 +12704,10 @@ static int intel_atomic_check(struct drm_device *dev,
                intel_state->cdclk.logical = dev_priv->cdclk.logical;
        }
 
+       ret = icl_add_linked_planes(intel_state);
+       if (ret)
+               return ret;
+
        ret = drm_atomic_helper_check_planes(dev, state);
        if (ret)
                return ret;
@@ -12614,7 +12747,7 @@ static void intel_update_crtc(struct drm_crtc *crtc,
                                                 to_intel_plane(crtc->primary));
 
        if (modeset) {
-               update_scanline_offset(intel_crtc);
+               update_scanline_offset(pipe_config);
                dev_priv->display.crtc_enable(pipe_config, state);
 
                /* vblanks work again, re-enable pipe CRC. */
@@ -12627,7 +12760,14 @@ static void intel_update_crtc(struct drm_crtc *crtc,
        if (new_plane_state)
                intel_fbc_enable(intel_crtc, pipe_config, new_plane_state);
 
-       drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+       intel_begin_crtc_commit(crtc, old_crtc_state);
+
+       if (INTEL_GEN(dev_priv) >= 9)
+               skl_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc);
+       else
+               i9xx_update_planes_on_crtc(to_intel_atomic_state(state), intel_crtc);
+
+       intel_finish_crtc_commit(crtc, old_crtc_state);
 }
 
 static void intel_update_crtcs(struct drm_atomic_state *state)
@@ -12659,13 +12799,12 @@ static void skl_update_crtcs(struct drm_atomic_state *state)
        int i;
        u8 hw_enabled_slices = dev_priv->wm.skl_hw.ddb.enabled_slices;
        u8 required_slices = intel_state->wm_results.ddb.enabled_slices;
-
-       const struct skl_ddb_entry *entries[I915_MAX_PIPES] = {};
+       struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i)
                /* ignore allocations for crtc's that have been turned off. */
                if (new_crtc_state->active)
-                       entries[i] = &to_intel_crtc_state(old_crtc_state)->wm.skl.ddb;
+                       entries[i] = to_intel_crtc_state(old_crtc_state)->wm.skl.ddb;
 
        /* If 2nd DBuf slice required, enable it here */
        if (INTEL_GEN(dev_priv) >= 11 && required_slices > hw_enabled_slices)
@@ -12691,14 +12830,13 @@ static void skl_update_crtcs(struct drm_atomic_state *state)
                        if (updated & cmask || !cstate->base.active)
                                continue;
 
-                       if (skl_ddb_allocation_overlaps(dev_priv,
+                       if (skl_ddb_allocation_overlaps(&cstate->wm.skl.ddb,
                                                        entries,
-                                                       &cstate->wm.skl.ddb,
-                                                       i))
+                                                       INTEL_INFO(dev_priv)->num_pipes, i))
                                continue;
 
                        updated |= cmask;
-                       entries[i] = &cstate->wm.skl.ddb;
+                       entries[i] = cstate->wm.skl.ddb;
 
                        /*
                         * If this is an already active pipe, it's DDB changed,
@@ -12788,8 +12926,9 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct intel_crtc_state *new_intel_crtc_state, *old_intel_crtc_state;
        struct drm_crtc *crtc;
-       struct intel_crtc_state *intel_cstate;
+       struct intel_crtc *intel_crtc;
        u64 put_domains[I915_MAX_PIPES] = {};
        int i;
 
@@ -12801,24 +12940,25 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
+               intel_crtc = to_intel_crtc(crtc);
 
                if (needs_modeset(new_crtc_state) ||
                    to_intel_crtc_state(new_crtc_state)->update_pipe) {
 
-                       put_domains[to_intel_crtc(crtc)->pipe] =
+                       put_domains[intel_crtc->pipe] =
                                modeset_get_crtc_power_domains(crtc,
-                                       to_intel_crtc_state(new_crtc_state));
+                                       new_intel_crtc_state);
                }
 
                if (!needs_modeset(new_crtc_state))
                        continue;
 
-               intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
-                                      to_intel_crtc_state(new_crtc_state));
+               intel_pre_plane_update(old_intel_crtc_state, new_intel_crtc_state);
 
                if (old_crtc_state->active) {
-                       intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
+                       intel_crtc_disable_planes(intel_state, intel_crtc);
 
                        /*
                         * We need to disable pipe CRC before disabling the pipe,
@@ -12826,10 +12966,10 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                         */
                        intel_crtc_disable_pipe_crc(intel_crtc);
 
-                       dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
+                       dev_priv->display.crtc_disable(old_intel_crtc_state, state);
                        intel_crtc->active = false;
                        intel_fbc_disable(intel_crtc);
-                       intel_disable_shared_dpll(intel_crtc);
+                       intel_disable_shared_dpll(old_intel_crtc_state);
 
                        /*
                         * Underruns don't always raise
@@ -12843,7 +12983,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                            !HAS_GMCH_DISPLAY(dev_priv) &&
                            dev_priv->display.initial_watermarks)
                                dev_priv->display.initial_watermarks(intel_state,
-                                                                    to_intel_crtc_state(new_crtc_state));
+                                                                    new_intel_crtc_state);
                }
        }
 
@@ -12902,11 +13042,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
         * TODO: Move this (and other cleanup) to an async worker eventually.
         */
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-               intel_cstate = to_intel_crtc_state(new_crtc_state);
+               new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
 
                if (dev_priv->display.optimize_watermarks)
                        dev_priv->display.optimize_watermarks(intel_state,
-                                                             intel_cstate);
+                                                             new_intel_crtc_state);
        }
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -13173,7 +13313,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
        struct i915_vma *vma;
 
        if (plane->id == PLANE_CURSOR &&
-           INTEL_INFO(dev_priv)->cursor_needs_physical) {
+           INTEL_INFO(dev_priv)->display.cursor_needs_physical) {
                struct drm_i915_gem_object *obj = intel_fb_obj(fb);
                const int align = intel_cursor_alignment(dev_priv);
                int err;
@@ -13289,13 +13429,12 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 
        ret = intel_plane_pin_fb(to_intel_plane_state(new_state));
 
-       fb_obj_bump_render_priority(obj);
-
        mutex_unlock(&dev_priv->drm.struct_mutex);
        i915_gem_object_unpin_pages(obj);
        if (ret)
                return ret;
 
+       fb_obj_bump_render_priority(obj);
        intel_fb_obj_flush(obj, ORIGIN_DIRTYFB);
 
        if (!new_state->fence) { /* implicit fencing */
@@ -13426,7 +13565,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
        if (intel_cstate->update_pipe)
                intel_update_pipe_config(old_intel_cstate, intel_cstate);
        else if (INTEL_GEN(dev_priv) >= 9)
-               skl_detach_scalers(intel_crtc);
+               skl_detach_scalers(intel_cstate);
 
 out:
        if (dev_priv->display.atomic_update_watermarks)
@@ -13528,75 +13667,14 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
        }
 }
 
-static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
-                                          u32 format, u64 modifier)
+static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
+                                             u32 format, u64 modifier)
 {
-       struct intel_plane *plane = to_intel_plane(_plane);
-
-       switch (modifier) {
-       case DRM_FORMAT_MOD_LINEAR:
-       case I915_FORMAT_MOD_X_TILED:
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Yf_TILED:
-               break;
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-       case I915_FORMAT_MOD_Yf_TILED_CCS:
-               if (!plane->has_ccs)
-                       return false;
-               break;
-       default:
-               return false;
-       }
+       return modifier == DRM_FORMAT_MOD_LINEAR &&
+               format == DRM_FORMAT_ARGB8888;
+}
 
-       switch (format) {
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_ARGB8888:
-       case DRM_FORMAT_ABGR8888:
-               if (is_ccs_modifier(modifier))
-                       return true;
-               /* fall through */
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_XBGR2101010:
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-       case DRM_FORMAT_NV12:
-               if (modifier == I915_FORMAT_MOD_Yf_TILED)
-                       return true;
-               /* fall through */
-       case DRM_FORMAT_C8:
-               if (modifier == DRM_FORMAT_MOD_LINEAR ||
-                   modifier == I915_FORMAT_MOD_X_TILED ||
-                   modifier == I915_FORMAT_MOD_Y_TILED)
-                       return true;
-               /* fall through */
-       default:
-               return false;
-       }
-}
-
-static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
-                                             u32 format, u64 modifier)
-{
-       return modifier == DRM_FORMAT_MOD_LINEAR &&
-               format == DRM_FORMAT_ARGB8888;
-}
-
-static struct drm_plane_funcs skl_plane_funcs = {
-       .update_plane = drm_atomic_helper_update_plane,
-       .disable_plane = drm_atomic_helper_disable_plane,
-       .destroy = intel_plane_destroy,
-       .atomic_get_property = intel_plane_atomic_get_property,
-       .atomic_set_property = intel_plane_atomic_set_property,
-       .atomic_duplicate_state = intel_plane_duplicate_state,
-       .atomic_destroy_state = intel_plane_destroy_state,
-       .format_mod_supported = skl_plane_format_mod_supported,
-};
-
-static struct drm_plane_funcs i965_plane_funcs = {
+static const struct drm_plane_funcs i965_plane_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = intel_plane_destroy,
@@ -13607,7 +13685,7 @@ static struct drm_plane_funcs i965_plane_funcs = {
        .format_mod_supported = i965_plane_format_mod_supported,
 };
 
-static struct drm_plane_funcs i8xx_plane_funcs = {
+static const struct drm_plane_funcs i8xx_plane_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = intel_plane_destroy,
@@ -13633,14 +13711,16 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_framebuffer *old_fb;
-       struct drm_crtc_state *crtc_state = crtc->state;
+       struct intel_crtc_state *crtc_state =
+               to_intel_crtc_state(crtc->state);
+       struct intel_crtc_state *new_crtc_state;
 
        /*
         * When crtc is inactive or there is a modeset pending,
         * wait for it to complete in the slowpath
         */
-       if (!crtc_state->active || needs_modeset(crtc_state) ||
-           to_intel_crtc_state(crtc_state)->update_pipe)
+       if (!crtc_state->base.active || needs_modeset(&crtc_state->base) ||
+           crtc_state->update_pipe)
                goto slow;
 
        old_plane_state = plane->state;
@@ -13670,6 +13750,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        if (!new_plane_state)
                return -ENOMEM;
 
+       new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(crtc));
+       if (!new_crtc_state) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
        drm_atomic_set_fb_for_plane(new_plane_state, fb);
 
        new_plane_state->src_x = src_x;
@@ -13681,9 +13767,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        new_plane_state->crtc_w = crtc_w;
        new_plane_state->crtc_h = crtc_h;
 
-       ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
-                                                 to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
-                                                 to_intel_plane_state(plane->state),
+       ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
+                                                 to_intel_plane_state(old_plane_state),
                                                  to_intel_plane_state(new_plane_state));
        if (ret)
                goto out_free;
@@ -13705,14 +13790,25 @@ intel_legacy_cursor_update(struct drm_plane *plane,
        /* Swap plane state */
        plane->state = new_plane_state;
 
+       /*
+        * We cannot swap crtc_state as it may be in use by an atomic commit or
+        * page flip that's running simultaneously. If we swap crtc_state and
+        * destroy the old state, we will cause a use-after-free there.
+        *
+        * Only update active_planes, which is needed for our internal
+        * bookkeeping. Either value will do the right thing when updating
+        * planes atomically. If the cursor was part of the atomic update then
+        * we would have taken the slowpath.
+        */
+       crtc_state->active_planes = new_crtc_state->active_planes;
+
        if (plane->state->visible) {
                trace_intel_update_plane(plane, to_intel_crtc(crtc));
-               intel_plane->update_plane(intel_plane,
-                                         to_intel_crtc_state(crtc->state),
+               intel_plane->update_plane(intel_plane, crtc_state,
                                          to_intel_plane_state(plane->state));
        } else {
                trace_intel_disable_plane(plane, to_intel_crtc(crtc));
-               intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
+               intel_plane->disable_plane(intel_plane, crtc_state);
        }
 
        intel_plane_unpin_fb(to_intel_plane_state(old_plane_state));
@@ -13720,6 +13816,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 out_unlock:
        mutex_unlock(&dev_priv->drm.struct_mutex);
 out_free:
+       if (new_crtc_state)
+               intel_crtc_destroy_state(crtc, &new_crtc_state->base);
        if (ret)
                intel_plane_destroy_state(plane, new_plane_state);
        else
@@ -13760,176 +13858,90 @@ static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
                return i9xx_plane == PLANE_A;
 }
 
-static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
-                             enum pipe pipe, enum plane_id plane_id)
-{
-       if (!HAS_FBC(dev_priv))
-               return false;
-
-       return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
-}
-
-bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
-                         enum pipe pipe, enum plane_id plane_id)
-{
-       /*
-        * FIXME: ICL requires two hardware planes for scanning out NV12
-        * framebuffers. Do not advertize support until this is implemented.
-        */
-       if (INTEL_GEN(dev_priv) >= 11)
-               return false;
-
-       if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
-               return false;
-
-       if (INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C)
-               return false;
-
-       if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0)
-               return false;
-
-       return true;
-}
-
 static struct intel_plane *
 intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
-       struct intel_plane *primary = NULL;
-       struct intel_plane_state *state = NULL;
+       struct intel_plane *plane;
        const struct drm_plane_funcs *plane_funcs;
-       const uint32_t *intel_primary_formats;
        unsigned int supported_rotations;
-       unsigned int num_formats;
-       const uint64_t *modifiers;
+       unsigned int possible_crtcs;
+       const u64 *modifiers;
+       const u32 *formats;
+       int num_formats;
        int ret;
 
-       primary = kzalloc(sizeof(*primary), GFP_KERNEL);
-       if (!primary) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       state = intel_create_plane_state(&primary->base);
-       if (!state) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (INTEL_GEN(dev_priv) >= 9)
+               return skl_universal_plane_create(dev_priv, pipe,
+                                                 PLANE_PRIMARY);
 
-       primary->base.state = &state->base;
+       plane = intel_plane_alloc();
+       if (IS_ERR(plane))
+               return plane;
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               state->scaler_id = -1;
-       primary->pipe = pipe;
+       plane->pipe = pipe;
        /*
         * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
         * port is hooked to pipe B. Hence we want plane A feeding pipe B.
         */
        if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4)
-               primary->i9xx_plane = (enum i9xx_plane_id) !pipe;
+               plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
        else
-               primary->i9xx_plane = (enum i9xx_plane_id) pipe;
-       primary->id = PLANE_PRIMARY;
-       primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id);
+               plane->i9xx_plane = (enum i9xx_plane_id) pipe;
+       plane->id = PLANE_PRIMARY;
+       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               primary->has_fbc = skl_plane_has_fbc(dev_priv,
-                                                    primary->pipe,
-                                                    primary->id);
-       else
-               primary->has_fbc = i9xx_plane_has_fbc(dev_priv,
-                                                     primary->i9xx_plane);
-
-       if (primary->has_fbc) {
+       plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
+       if (plane->has_fbc) {
                struct intel_fbc *fbc = &dev_priv->fbc;
 
-               fbc->possible_framebuffer_bits |= primary->frontbuffer_bit;
+               fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
        }
 
-       if (INTEL_GEN(dev_priv) >= 9) {
-               primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
-                                                    PLANE_PRIMARY);
-
-               if (skl_plane_has_planar(dev_priv, pipe, PLANE_PRIMARY)) {
-                       intel_primary_formats = skl_pri_planar_formats;
-                       num_formats = ARRAY_SIZE(skl_pri_planar_formats);
-               } else {
-                       intel_primary_formats = skl_primary_formats;
-                       num_formats = ARRAY_SIZE(skl_primary_formats);
-               }
-
-               if (primary->has_ccs)
-                       modifiers = skl_format_modifiers_ccs;
-               else
-                       modifiers = skl_format_modifiers_noccs;
-
-               primary->max_stride = skl_plane_max_stride;
-               primary->update_plane = skl_update_plane;
-               primary->disable_plane = skl_disable_plane;
-               primary->get_hw_state = skl_plane_get_hw_state;
-               primary->check_plane = skl_plane_check;
-
-               plane_funcs = &skl_plane_funcs;
-       } else if (INTEL_GEN(dev_priv) >= 4) {
-               intel_primary_formats = i965_primary_formats;
+       if (INTEL_GEN(dev_priv) >= 4) {
+               formats = i965_primary_formats;
                num_formats = ARRAY_SIZE(i965_primary_formats);
                modifiers = i9xx_format_modifiers;
 
-               primary->max_stride = i9xx_plane_max_stride;
-               primary->update_plane = i9xx_update_plane;
-               primary->disable_plane = i9xx_disable_plane;
-               primary->get_hw_state = i9xx_plane_get_hw_state;
-               primary->check_plane = i9xx_plane_check;
+               plane->max_stride = i9xx_plane_max_stride;
+               plane->update_plane = i9xx_update_plane;
+               plane->disable_plane = i9xx_disable_plane;
+               plane->get_hw_state = i9xx_plane_get_hw_state;
+               plane->check_plane = i9xx_plane_check;
 
                plane_funcs = &i965_plane_funcs;
        } else {
-               intel_primary_formats = i8xx_primary_formats;
+               formats = i8xx_primary_formats;
                num_formats = ARRAY_SIZE(i8xx_primary_formats);
                modifiers = i9xx_format_modifiers;
 
-               primary->max_stride = i9xx_plane_max_stride;
-               primary->update_plane = i9xx_update_plane;
-               primary->disable_plane = i9xx_disable_plane;
-               primary->get_hw_state = i9xx_plane_get_hw_state;
-               primary->check_plane = i9xx_plane_check;
+               plane->max_stride = i9xx_plane_max_stride;
+               plane->update_plane = i9xx_update_plane;
+               plane->disable_plane = i9xx_disable_plane;
+               plane->get_hw_state = i9xx_plane_get_hw_state;
+               plane->check_plane = i9xx_plane_check;
 
                plane_funcs = &i8xx_plane_funcs;
        }
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
-                                              DRM_PLANE_TYPE_PRIMARY,
-                                              "plane 1%c", pipe_name(pipe));
-       else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
+       possible_crtcs = BIT(pipe);
+
+       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                              possible_crtcs, plane_funcs,
+                                              formats, num_formats, modifiers,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "primary %c", pipe_name(pipe));
        else
-               ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
-                                              0, plane_funcs,
-                                              intel_primary_formats, num_formats,
-                                              modifiers,
+               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                              possible_crtcs, plane_funcs,
+                                              formats, num_formats, modifiers,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "plane %c",
-                                              plane_name(primary->i9xx_plane));
+                                              plane_name(plane->i9xx_plane));
        if (ret)
                goto fail;
 
-       if (INTEL_GEN(dev_priv) >= 10) {
-               supported_rotations =
-                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-                       DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
-                       DRM_MODE_REFLECT_X;
-       } else if (INTEL_GEN(dev_priv) >= 9) {
-               supported_rotations =
-                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-                       DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
-       } else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
+       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
                supported_rotations =
                        DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
                        DRM_MODE_REFLECT_X;
@@ -13941,26 +13953,16 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
        }
 
        if (INTEL_GEN(dev_priv) >= 4)
-               drm_plane_create_rotation_property(&primary->base,
+               drm_plane_create_rotation_property(&plane->base,
                                                   DRM_MODE_ROTATE_0,
                                                   supported_rotations);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               drm_plane_create_color_properties(&primary->base,
-                                                 BIT(DRM_COLOR_YCBCR_BT601) |
-                                                 BIT(DRM_COLOR_YCBCR_BT709),
-                                                 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-                                                 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-                                                 DRM_COLOR_YCBCR_BT709,
-                                                 DRM_COLOR_YCBCR_LIMITED_RANGE);
+       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
 
-       drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
-
-       return primary;
+       return plane;
 
 fail:
-       kfree(state);
-       kfree(primary);
+       intel_plane_free(plane);
 
        return ERR_PTR(ret);
 }
@@ -13969,23 +13971,13 @@ static struct intel_plane *
 intel_cursor_plane_create(struct drm_i915_private *dev_priv,
                          enum pipe pipe)
 {
-       struct intel_plane *cursor = NULL;
-       struct intel_plane_state *state = NULL;
+       unsigned int possible_crtcs;
+       struct intel_plane *cursor;
        int ret;
 
-       cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
-       if (!cursor) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       state = intel_create_plane_state(&cursor->base);
-       if (!state) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       cursor->base.state = &state->base;
+       cursor = intel_plane_alloc();
+       if (IS_ERR(cursor))
+               return cursor;
 
        cursor->pipe = pipe;
        cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
@@ -14012,8 +14004,10 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
        if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
                cursor->cursor.size = ~0;
 
+       possible_crtcs = BIT(pipe);
+
        ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
-                                      0, &intel_cursor_plane_funcs,
+                                      possible_crtcs, &intel_cursor_plane_funcs,
                                       intel_cursor_formats,
                                       ARRAY_SIZE(intel_cursor_formats),
                                       cursor_format_modifiers,
@@ -14028,16 +14022,12 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
                                                   DRM_MODE_ROTATE_0 |
                                                   DRM_MODE_ROTATE_180);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               state->scaler_id = -1;
-
        drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
 
        return cursor;
 
 fail:
-       kfree(state);
-       kfree(cursor);
+       intel_plane_free(cursor);
 
        return ERR_PTR(ret);
 }
@@ -14058,7 +14048,7 @@ static void intel_crtc_init_scalers(struct intel_crtc *crtc,
                struct intel_scaler *scaler = &scaler_state->scalers[i];
 
                scaler->in_use = 0;
-               scaler->mode = PS_SCALER_MODE_DYN;
+               scaler->mode = 0;
        }
 
        scaler_state->scaler_id = -1;
@@ -14153,18 +14143,6 @@ fail:
        return ret;
 }
 
-enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
-{
-       struct drm_device *dev = connector->base.dev;
-
-       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
-
-       if (!connector->base.state->crtc)
-               return INVALID_PIPE;
-
-       return to_intel_crtc(connector->base.state->crtc)->pipe;
-}
-
 int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file)
 {
@@ -14281,7 +14259,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
 
        intel_pps_init(dev_priv);
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0)
+       if (!HAS_DISPLAY(dev_priv))
                return;
 
        /*
@@ -14301,6 +14279,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
                intel_ddi_init(dev_priv, PORT_D);
                intel_ddi_init(dev_priv, PORT_E);
                intel_ddi_init(dev_priv, PORT_F);
+               icl_dsi_init(dev_priv);
        } else if (IS_GEN9_LP(dev_priv)) {
                /*
                 * FIXME: Broxton doesn't support port detection via the
@@ -14523,7 +14502,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
 
 static
 u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
-                        uint64_t fb_modifier, uint32_t pixel_format)
+                        u32 pixel_format, u64 fb_modifier)
 {
        struct intel_crtc *crtc;
        struct intel_plane *plane;
@@ -14545,7 +14524,6 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
 {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
        struct drm_framebuffer *fb = &intel_fb->base;
-       struct drm_format_name_buf format_name;
        u32 pitch_limit;
        unsigned int tiling, stride;
        int ret = -EINVAL;
@@ -14576,33 +14554,14 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                }
        }
 
-       /* Passed in modifier sanity checking. */
-       switch (mode_cmd->modifier[0]) {
-       case I915_FORMAT_MOD_Y_TILED_CCS:
-       case I915_FORMAT_MOD_Yf_TILED_CCS:
-               switch (mode_cmd->pixel_format) {
-               case DRM_FORMAT_XBGR8888:
-               case DRM_FORMAT_ABGR8888:
-               case DRM_FORMAT_XRGB8888:
-               case DRM_FORMAT_ARGB8888:
-                       break;
-               default:
-                       DRM_DEBUG_KMS("RC supported only with RGB8888 formats\n");
-                       goto err;
-               }
-               /* fall through */
-       case I915_FORMAT_MOD_Y_TILED:
-       case I915_FORMAT_MOD_Yf_TILED:
-               if (INTEL_GEN(dev_priv) < 9) {
-                       DRM_DEBUG_KMS("Unsupported tiling 0x%llx!\n",
-                                     mode_cmd->modifier[0]);
-                       goto err;
-               }
-       case DRM_FORMAT_MOD_LINEAR:
-       case I915_FORMAT_MOD_X_TILED:
-               break;
-       default:
-               DRM_DEBUG_KMS("Unsupported fb modifier 0x%llx!\n",
+       if (!drm_any_plane_has_format(&dev_priv->drm,
+                                     mode_cmd->pixel_format,
+                                     mode_cmd->modifier[0])) {
+               struct drm_format_name_buf format_name;
+
+               DRM_DEBUG_KMS("unsupported pixel format %s / modifier 0x%llx\n",
+                             drm_get_format_name(mode_cmd->pixel_format,
+                                                 &format_name),
                              mode_cmd->modifier[0]);
                goto err;
        }
@@ -14617,8 +14576,8 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                goto err;
        }
 
-       pitch_limit = intel_fb_pitch_limit(dev_priv, mode_cmd->modifier[0],
-                                          mode_cmd->pixel_format);
+       pitch_limit = intel_fb_pitch_limit(dev_priv, mode_cmd->pixel_format,
+                                          mode_cmd->modifier[0]);
        if (mode_cmd->pitches[0] > pitch_limit) {
                DRM_DEBUG_KMS("%s pitch (%u) must be at most %d\n",
                              mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
@@ -14637,69 +14596,6 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                goto err;
        }
 
-       /* Reject formats not supported by any plane early. */
-       switch (mode_cmd->pixel_format) {
-       case DRM_FORMAT_C8:
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_ARGB8888:
-               break;
-       case DRM_FORMAT_XRGB1555:
-               if (INTEL_GEN(dev_priv) > 3) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format, &format_name));
-                       goto err;
-               }
-               break;
-       case DRM_FORMAT_ABGR8888:
-               if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
-                   INTEL_GEN(dev_priv) < 9) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format, &format_name));
-                       goto err;
-               }
-               break;
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_XBGR2101010:
-               if (INTEL_GEN(dev_priv) < 4) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format, &format_name));
-                       goto err;
-               }
-               break;
-       case DRM_FORMAT_ABGR2101010:
-               if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format, &format_name));
-                       goto err;
-               }
-               break;
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_VYUY:
-               if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format, &format_name));
-                       goto err;
-               }
-               break;
-       case DRM_FORMAT_NV12:
-               if (INTEL_GEN(dev_priv) < 9 || IS_SKYLAKE(dev_priv) ||
-                   IS_BROXTON(dev_priv) || INTEL_GEN(dev_priv) >= 11) {
-                       DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                                     drm_get_format_name(mode_cmd->pixel_format,
-                                                         &format_name));
-                       goto err;
-               }
-               break;
-       default:
-               DRM_DEBUG_KMS("unsupported pixel format: %s\n",
-                             drm_get_format_name(mode_cmd->pixel_format, &format_name));
-               goto err;
-       }
-
        /* FIXME need to adjust LINOFF/TILEOFF accordingly. */
        if (mode_cmd->offsets[0] != 0)
                goto err;
@@ -14971,174 +14867,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
                dev_priv->display.update_crtcs = intel_update_crtcs;
 }
 
-/*
- * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
- */
-static void quirk_ssc_force_disable(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
-       DRM_INFO("applying lvds SSC disable quirk\n");
-}
-
-/*
- * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
- * brightness value
- */
-static void quirk_invert_brightness(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
-       DRM_INFO("applying inverted panel brightness quirk\n");
-}
-
-/* Some VBT's incorrectly indicate no backlight is present */
-static void quirk_backlight_present(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       dev_priv->quirks |= QUIRK_BACKLIGHT_PRESENT;
-       DRM_INFO("applying backlight present quirk\n");
-}
-
-/* Toshiba Satellite P50-C-18C requires T12 delay to be min 800ms
- * which is 300 ms greater than eDP spec T12 min.
- */
-static void quirk_increase_t12_delay(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       dev_priv->quirks |= QUIRK_INCREASE_T12_DELAY;
-       DRM_INFO("Applying T12 delay quirk\n");
-}
-
-/*
- * GeminiLake NUC HDMI outputs require additional off time
- * this allows the onboard retimer to correctly sync to signal
- */
-static void quirk_increase_ddi_disabled_time(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       dev_priv->quirks |= QUIRK_INCREASE_DDI_DISABLED_TIME;
-       DRM_INFO("Applying Increase DDI Disabled quirk\n");
-}
-
-struct intel_quirk {
-       int device;
-       int subsystem_vendor;
-       int subsystem_device;
-       void (*hook)(struct drm_device *dev);
-};
-
-/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
-struct intel_dmi_quirk {
-       void (*hook)(struct drm_device *dev);
-       const struct dmi_system_id (*dmi_id_list)[];
-};
-
-static int intel_dmi_reverse_brightness(const struct dmi_system_id *id)
-{
-       DRM_INFO("Backlight polarity reversed on %s\n", id->ident);
-       return 1;
-}
-
-static const struct intel_dmi_quirk intel_dmi_quirks[] = {
-       {
-               .dmi_id_list = &(const struct dmi_system_id[]) {
-                       {
-                               .callback = intel_dmi_reverse_brightness,
-                               .ident = "NCR Corporation",
-                               .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"),
-                                           DMI_MATCH(DMI_PRODUCT_NAME, ""),
-                               },
-                       },
-                       { }  /* terminating entry */
-               },
-               .hook = quirk_invert_brightness,
-       },
-};
-
-static struct intel_quirk intel_quirks[] = {
-       /* Lenovo U160 cannot use SSC on LVDS */
-       { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
-
-       /* Sony Vaio Y cannot use SSC on LVDS */
-       { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
-
-       /* Acer Aspire 5734Z must invert backlight brightness */
-       { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
-
-       /* Acer/eMachines G725 */
-       { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
-
-       /* Acer/eMachines e725 */
-       { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
-
-       /* Acer/Packard Bell NCL20 */
-       { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
-
-       /* Acer Aspire 4736Z */
-       { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
-
-       /* Acer Aspire 5336 */
-       { 0x2a42, 0x1025, 0x048a, quirk_invert_brightness },
-
-       /* Acer C720 and C720P Chromebooks (Celeron 2955U) have backlights */
-       { 0x0a06, 0x1025, 0x0a11, quirk_backlight_present },
-
-       /* Acer C720 Chromebook (Core i3 4005U) */
-       { 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
-
-       /* Apple Macbook 2,1 (Core 2 T7400) */
-       { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
-
-       /* Apple Macbook 4,1 */
-       { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
-
-       /* Toshiba CB35 Chromebook (Celeron 2955U) */
-       { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
-
-       /* HP Chromebook 14 (Celeron 2955U) */
-       { 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
-
-       /* Dell Chromebook 11 */
-       { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
-
-       /* Dell Chromebook 11 (2015 version) */
-       { 0x0a16, 0x1028, 0x0a35, quirk_backlight_present },
-
-       /* Toshiba Satellite P50-C-18C */
-       { 0x191B, 0x1179, 0xF840, quirk_increase_t12_delay },
-
-       /* GeminiLake NUC */
-       { 0x3185, 0x8086, 0x2072, quirk_increase_ddi_disabled_time },
-       { 0x3184, 0x8086, 0x2072, quirk_increase_ddi_disabled_time },
-       /* ASRock ITX*/
-       { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
-       { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
-};
-
-static void intel_init_quirks(struct drm_device *dev)
-{
-       struct pci_dev *d = dev->pdev;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) {
-               struct intel_quirk *q = &intel_quirks[i];
-
-               if (d->device == q->device &&
-                   (d->subsystem_vendor == q->subsystem_vendor ||
-                    q->subsystem_vendor == PCI_ANY_ID) &&
-                   (d->subsystem_device == q->subsystem_device ||
-                    q->subsystem_device == PCI_ANY_ID))
-                       q->hook(dev);
-       }
-       for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) {
-               if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0)
-                       intel_dmi_quirks[i].hook(dev);
-       }
-}
-
 /* Disable the VGA plane that we never use */
 static void i915_disable_vga(struct drm_i915_private *dev_priv)
 {
@@ -15352,7 +15080,9 @@ int intel_modeset_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->atomic_helper.free_work,
                  intel_atomic_helper_free_state_worker);
 
-       intel_init_quirks(dev);
+       intel_init_quirks(dev_priv);
+
+       intel_fbc_init(dev_priv);
 
        intel_init_pm(dev_priv);
 
@@ -15584,8 +15314,8 @@ intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
                if (pipe == crtc->pipe)
                        continue;
 
-               DRM_DEBUG_KMS("%s attached to the wrong pipe, disabling plane\n",
-                             plane->base.name);
+               DRM_DEBUG_KMS("[PLANE:%d:%s] attached to the wrong pipe, disabling plane\n",
+                             plane->base.base.id, plane->base.name);
 
                plane_crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
                intel_plane_disable_noatomic(plane_crtc, plane);
@@ -15626,7 +15356,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+       struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 
        /* Clear any frame start delays used for debugging left by the BIOS */
        if (crtc->active && !transcoder_is_dsi(cpu_transcoder)) {
@@ -15636,7 +15367,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
                           I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
        }
 
-       if (crtc->active) {
+       if (crtc_state->base.active) {
                struct intel_plane *plane;
 
                /* Disable everything but the primary plane */
@@ -15652,10 +15383,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
 
        /* Adjust the state of the output pipe according to whether we
         * have active connectors/encoders. */
-       if (crtc->active && !intel_crtc_has_encoders(crtc))
+       if (crtc_state->base.active && !intel_crtc_has_encoders(crtc))
                intel_crtc_disable_noatomic(&crtc->base, ctx);
 
-       if (crtc->active || HAS_GMCH_DISPLAY(dev_priv)) {
+       if (crtc_state->base.active || HAS_GMCH_DISPLAY(dev_priv)) {
                /*
                 * We start out with underrun reporting disabled to avoid races.
                 * For correct bookkeeping mark this on active crtcs.
@@ -15686,6 +15417,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
 
 static void intel_sanitize_encoder(struct intel_encoder *encoder)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_connector *connector;
 
        /* We need to check both for a crtc link (meaning that the
@@ -15709,7 +15441,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                        DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
                                      encoder->base.base.id,
                                      encoder->base.name);
-                       encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
+                       if (encoder->disable)
+                               encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                        if (encoder->post_disable)
                                encoder->post_disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                }
@@ -15726,6 +15459,9 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
 
        /* notify opregion of the sanitized encoder state */
        intel_opregion_notify_encoder(encoder, connector && has_active_crtc);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               icl_sanitize_encoder_pll_mapping(encoder);
 }
 
 void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv)
@@ -15774,6 +15510,10 @@ static void readout_plane_state(struct drm_i915_private *dev_priv)
                crtc_state = to_intel_crtc_state(crtc->base.state);
 
                intel_set_plane_visible(crtc_state, plane_state, visible);
+
+               DRM_DEBUG_KMS("[PLANE:%d:%s] hw state readout: %s, pipe %c\n",
+                             plane->base.base.id, plane->base.name,
+                             enableddisabled(visible), pipe_name(pipe));
        }
 
        for_each_intel_crtc(&dev_priv->drm, crtc) {
@@ -15926,7 +15666,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
 
                        drm_calc_timestamping_constants(&crtc->base,
                                                        &crtc_state->base.adjusted_mode);
-                       update_scanline_offset(crtc);
+                       update_scanline_offset(crtc_state);
                }
 
                dev_priv->min_cdclk[crtc->pipe] = min_cdclk;
@@ -15981,6 +15721,65 @@ static void intel_early_display_was(struct drm_i915_private *dev_priv)
        }
 }
 
+static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv,
+                                      enum port port, i915_reg_t hdmi_reg)
+{
+       u32 val = I915_READ(hdmi_reg);
+
+       if (val & SDVO_ENABLE ||
+           (val & SDVO_PIPE_SEL_MASK) == SDVO_PIPE_SEL(PIPE_A))
+               return;
+
+       DRM_DEBUG_KMS("Sanitizing transcoder select for HDMI %c\n",
+                     port_name(port));
+
+       val &= ~SDVO_PIPE_SEL_MASK;
+       val |= SDVO_PIPE_SEL(PIPE_A);
+
+       I915_WRITE(hdmi_reg, val);
+}
+
+static void ibx_sanitize_pch_dp_port(struct drm_i915_private *dev_priv,
+                                    enum port port, i915_reg_t dp_reg)
+{
+       u32 val = I915_READ(dp_reg);
+
+       if (val & DP_PORT_EN ||
+           (val & DP_PIPE_SEL_MASK) == DP_PIPE_SEL(PIPE_A))
+               return;
+
+       DRM_DEBUG_KMS("Sanitizing transcoder select for DP %c\n",
+                     port_name(port));
+
+       val &= ~DP_PIPE_SEL_MASK;
+       val |= DP_PIPE_SEL(PIPE_A);
+
+       I915_WRITE(dp_reg, val);
+}
+
+static void ibx_sanitize_pch_ports(struct drm_i915_private *dev_priv)
+{
+       /*
+        * The BIOS may select transcoder B on some of the PCH
+        * ports even it doesn't enable the port. This would trip
+        * assert_pch_dp_disabled() and assert_pch_hdmi_disabled().
+        * Sanitize the transcoder select bits to prevent that. We
+        * assume that the BIOS never actually enabled the port,
+        * because if it did we'd actually have to toggle the port
+        * on and back off to make the transcoder A select stick
+        * (see. intel_dp_link_down(), intel_disable_hdmi(),
+        * intel_disable_sdvo()).
+        */
+       ibx_sanitize_pch_dp_port(dev_priv, PORT_B, PCH_DP_B);
+       ibx_sanitize_pch_dp_port(dev_priv, PORT_C, PCH_DP_C);
+       ibx_sanitize_pch_dp_port(dev_priv, PORT_D, PCH_DP_D);
+
+       /* PCH SDVOB multiplex with HDMIB */
+       ibx_sanitize_pch_hdmi_port(dev_priv, PORT_B, PCH_HDMIB);
+       ibx_sanitize_pch_hdmi_port(dev_priv, PORT_C, PCH_HDMIC);
+       ibx_sanitize_pch_hdmi_port(dev_priv, PORT_D, PCH_HDMID);
+}
+
 /* Scan out the current hw modeset state,
  * and sanitizes it to the current state
  */
@@ -15990,6 +15789,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *crtc;
+       struct intel_crtc_state *crtc_state;
        struct intel_encoder *encoder;
        int i;
 
@@ -16001,6 +15801,9 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        /* HW state is read out, now we need to sanitize this mess. */
        get_encoder_power_domains(dev_priv);
 
+       if (HAS_PCH_IBX(dev_priv))
+               ibx_sanitize_pch_ports(dev_priv);
+
        /*
         * intel_sanitize_plane_mapping() may need to do vblank
         * waits, so we need vblank interrupts restored beforehand.
@@ -16008,7 +15811,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                drm_crtc_vblank_reset(&crtc->base);
 
-               if (crtc->active)
+               if (crtc->base.state->active)
                        drm_crtc_vblank_on(&crtc->base);
        }
 
@@ -16018,8 +15821,9 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                intel_sanitize_encoder(encoder);
 
        for_each_intel_crtc(&dev_priv->drm, crtc) {
+               crtc_state = to_intel_crtc_state(crtc->base.state);
                intel_sanitize_crtc(crtc, ctx);
-               intel_dump_pipe_config(crtc, crtc->config,
+               intel_dump_pipe_config(crtc, crtc_state,
                                       "[setup_hw_state]");
        }
 
@@ -16053,7 +15857,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        for_each_intel_crtc(dev, crtc) {
                u64 put_domains;
 
-               put_domains = modeset_get_crtc_power_domains(&crtc->base, crtc->config);
+               crtc_state = to_intel_crtc_state(crtc->base.state);
+               put_domains = modeset_get_crtc_power_domains(&crtc->base, crtc_state);
                if (WARN_ON(put_domains))
                        modeset_put_power_domains(dev_priv, put_domains);
        }
@@ -16097,29 +15902,6 @@ void intel_display_resume(struct drm_device *dev)
                drm_atomic_state_put(state);
 }
 
-int intel_connector_register(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       int ret;
-
-       ret = intel_backlight_device_register(intel_connector);
-       if (ret)
-               goto err;
-
-       return 0;
-
-err:
-       return ret;
-}
-
-void intel_connector_unregister(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       intel_backlight_device_unregister(intel_connector);
-       intel_panel_destroy_backlight(connector);
-}
-
 static void intel_hpd_poll_fini(struct drm_device *dev)
 {
        struct intel_connector *connector;
@@ -16130,9 +15912,9 @@ static void intel_hpd_poll_fini(struct drm_device *dev)
        for_each_intel_connector_iter(connector, &conn_iter) {
                if (connector->modeset_retry_work.func)
                        cancel_work_sync(&connector->modeset_retry_work);
-               if (connector->hdcp_shim) {
-                       cancel_delayed_work_sync(&connector->hdcp_check_work);
-                       cancel_work_sync(&connector->hdcp_prop_work);
+               if (connector->hdcp.shim) {
+                       cancel_delayed_work_sync(&connector->hdcp.check_work);
+                       cancel_work_sync(&connector->hdcp.prop_work);
                }
        }
        drm_connector_list_iter_end(&conn_iter);
@@ -16172,18 +15954,13 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        drm_mode_config_cleanup(dev);
 
-       intel_cleanup_overlay(dev_priv);
+       intel_overlay_cleanup(dev_priv);
 
        intel_teardown_gmbus(dev_priv);
 
        destroy_workqueue(dev_priv->modeset_wq);
-}
 
-void intel_connector_attach_encoder(struct intel_connector *connector,
-                                   struct intel_encoder *encoder)
-{
-       connector->encoder = encoder;
-       drm_connector_attach_encoder(&connector->base, &encoder->base);
+       intel_fbc_cleanup_cfb(dev_priv);
 }
 
 /*
@@ -16273,7 +16050,7 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv)
        };
        int i;
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0)
+       if (!HAS_DISPLAY(dev_priv))
                return NULL;
 
        error = kzalloc(sizeof(*error), GFP_ATOMIC);
index 9fac67e31205ff19ae9398b23bfd07a1191ac541..4262452963b31442363fe13ccf812c645a831fb7 100644 (file)
@@ -43,6 +43,11 @@ enum i915_gpio {
        GPIOM,
 };
 
+/*
+ * Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
+ * rest have consecutive values and match the enum values of transcoders
+ * with a 1:1 transcoder -> pipe mapping.
+ */
 enum pipe {
        INVALID_PIPE = -1,
 
@@ -57,12 +62,25 @@ enum pipe {
 #define pipe_name(p) ((p) + 'A')
 
 enum transcoder {
-       TRANSCODER_A = 0,
-       TRANSCODER_B,
-       TRANSCODER_C,
+       /*
+        * The following transcoders have a 1:1 transcoder -> pipe mapping,
+        * keep their values fixed: the code assumes that TRANSCODER_A=0, the
+        * rest have consecutive values and match the enum values of the pipes
+        * they map to.
+        */
+       TRANSCODER_A = PIPE_A,
+       TRANSCODER_B = PIPE_B,
+       TRANSCODER_C = PIPE_C,
+
+       /*
+        * The following transcoders can map to any pipe, their enum value
+        * doesn't need to stay fixed.
+        */
        TRANSCODER_EDP,
-       TRANSCODER_DSI_A,
-       TRANSCODER_DSI_C,
+       TRANSCODER_DSI_0,
+       TRANSCODER_DSI_1,
+       TRANSCODER_DSI_A = TRANSCODER_DSI_0,    /* legacy DSI */
+       TRANSCODER_DSI_C = TRANSCODER_DSI_1,    /* legacy DSI */
 
        I915_MAX_TRANSCODERS
 };
@@ -120,6 +138,9 @@ enum plane_id {
        PLANE_SPRITE0,
        PLANE_SPRITE1,
        PLANE_SPRITE2,
+       PLANE_SPRITE3,
+       PLANE_SPRITE4,
+       PLANE_SPRITE5,
        PLANE_CURSOR,
 
        I915_MAX_PLANES,
@@ -221,6 +242,7 @@ enum intel_display_power_domain {
        POWER_DOMAIN_TRANSCODER_B,
        POWER_DOMAIN_TRANSCODER_C,
        POWER_DOMAIN_TRANSCODER_EDP,
+       POWER_DOMAIN_TRANSCODER_EDP_VDSC,
        POWER_DOMAIN_TRANSCODER_DSI_A,
        POWER_DOMAIN_TRANSCODER_DSI_C,
        POWER_DOMAIN_PORT_DDI_A_LANES,
@@ -363,7 +385,7 @@ struct intel_link_m_n {
                (__dev_priv)->power_domains.power_well_count;           \
             (__power_well)++)
 
-#define for_each_power_well_rev(__dev_priv, __power_well)                      \
+#define for_each_power_well_reverse(__dev_priv, __power_well)                  \
        for ((__power_well) = (__dev_priv)->power_domains.power_wells +         \
                              (__dev_priv)->power_domains.power_well_count - 1; \
             (__power_well) - (__dev_priv)->power_domains.power_wells >= 0;     \
@@ -373,10 +395,18 @@ struct intel_link_m_n {
        for_each_power_well(__dev_priv, __power_well)                           \
                for_each_if((__power_well)->desc->domains & (__domain_mask))
 
-#define for_each_power_domain_well_rev(__dev_priv, __power_well, __domain_mask) \
-       for_each_power_well_rev(__dev_priv, __power_well)                       \
+#define for_each_power_domain_well_reverse(__dev_priv, __power_well, __domain_mask) \
+       for_each_power_well_reverse(__dev_priv, __power_well)                   \
                for_each_if((__power_well)->desc->domains & (__domain_mask))
 
+#define for_each_old_intel_plane_in_state(__state, plane, old_plane_state, __i) \
+       for ((__i) = 0; \
+            (__i) < (__state)->base.dev->mode_config.num_total_plane && \
+                    ((plane) = to_intel_plane((__state)->base.planes[__i].ptr), \
+                     (old_plane_state) = to_intel_plane_state((__state)->base.planes[__i].old_state), 1); \
+            (__i)++) \
+               for_each_if(plane)
+
 #define for_each_new_intel_plane_in_state(__state, plane, new_plane_state, __i) \
        for ((__i) = 0; \
             (__i) < (__state)->base.dev->mode_config.num_total_plane && \
@@ -402,10 +432,18 @@ struct intel_link_m_n {
             (__i)++) \
                for_each_if(plane)
 
-void intel_link_compute_m_n(int bpp, int nlanes,
+#define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \
+       for ((__i) = 0; \
+            (__i) < (__state)->base.dev->mode_config.num_crtc && \
+                    ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \
+                     (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \
+                     (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \
+            (__i)++) \
+               for_each_if(crtc)
+
+void intel_link_compute_m_n(u16 bpp, int nlanes,
                            int pixel_clock, int link_clock,
                            struct intel_link_m_n *m_n,
                            bool constant_n);
-
 bool is_ccs_modifier(u64 modifier);
 #endif
index 13f9b56a9ce7ca711467fc9309b720f8d9565661..fdd2cbc56fa335b6bf084c00451eca8a0ef957e3 100644 (file)
 
 #define DP_DPRX_ESI_LEN 14
 
+/* DP DSC small joiner has 2 FIFOs each of 640 x 6 bytes */
+#define DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER     61440
+#define DP_DSC_MIN_SUPPORTED_BPC               8
+#define DP_DSC_MAX_SUPPORTED_BPC               10
+
+/* DP DSC throughput values used for slice count calculations KPixels/s */
+#define DP_DSC_PEAK_PIXEL_RATE                 2720000
+#define DP_DSC_MAX_ENC_THROUGHPUT_0            340000
+#define DP_DSC_MAX_ENC_THROUGHPUT_1            400000
+
+/* DP DSC FEC Overhead factor = (100 - 2.4)/100 */
+#define DP_DSC_FEC_OVERHEAD_FACTOR             976
+
 /* Compliance test status bits  */
 #define INTEL_DP_RESOLUTION_SHIFT_MASK 0
 #define INTEL_DP_RESOLUTION_PREFERRED  (1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
@@ -93,6 +106,14 @@ static const struct dp_link_dpll chv_dpll[] = {
                { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } },
 };
 
+/* Constants for DP DSC configurations */
+static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15};
+
+/* With Single pipe configuration, HW is capable of supporting maximum
+ * of 4 slices per line.
+ */
+static const u8 valid_dsc_slicecount[] = {1, 2, 4};
+
 /**
  * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or PCH)
  * @intel_dp: DP struct
@@ -222,138 +243,6 @@ intel_dp_link_required(int pixel_clock, int bpp)
        return DIV_ROUND_UP(pixel_clock * bpp, 8);
 }
 
-void icl_program_mg_dp_mode(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum port port = intel_dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       u32 ln0, ln1, lane_info;
-
-       if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT)
-               return;
-
-       ln0 = I915_READ(MG_DP_MODE(port, 0));
-       ln1 = I915_READ(MG_DP_MODE(port, 1));
-
-       switch (intel_dig_port->tc_type) {
-       case TC_PORT_TYPEC:
-               ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
-               ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE);
-
-               lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
-                            DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
-                           DP_LANE_ASSIGNMENT_SHIFT(tc_port);
-
-               switch (lane_info) {
-               case 0x1:
-               case 0x4:
-                       break;
-               case 0x2:
-                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE;
-                       break;
-               case 0x3:
-                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       break;
-               case 0x8:
-                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE;
-                       break;
-               case 0xC:
-                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       break;
-               case 0xF:
-                       ln0 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       ln1 |= MG_DP_MODE_CFG_DP_X1_MODE |
-                              MG_DP_MODE_CFG_DP_X2_MODE;
-                       break;
-               default:
-                       MISSING_CASE(lane_info);
-               }
-               break;
-
-       case TC_PORT_LEGACY:
-               ln0 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE;
-               ln1 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE;
-               break;
-
-       default:
-               MISSING_CASE(intel_dig_port->tc_type);
-               return;
-       }
-
-       I915_WRITE(MG_DP_MODE(port, 0), ln0);
-       I915_WRITE(MG_DP_MODE(port, 1), ln1);
-}
-
-void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port)
-{
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       enum port port = dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
-       u32 val;
-       int i;
-
-       if (tc_port == PORT_TC_NONE)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
-               val = I915_READ(mg_regs[i]);
-               val |= MG_DP_MODE_CFG_TR2PWR_GATING |
-                      MG_DP_MODE_CFG_TRPWR_GATING |
-                      MG_DP_MODE_CFG_CLNPWR_GATING |
-                      MG_DP_MODE_CFG_DIGPWR_GATING |
-                      MG_DP_MODE_CFG_GAONPWR_GATING;
-               I915_WRITE(mg_regs[i], val);
-       }
-
-       val = I915_READ(MG_MISC_SUS0(tc_port));
-       val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) |
-              MG_MISC_SUS0_CFG_TR2PWR_GATING |
-              MG_MISC_SUS0_CFG_CL2PWR_GATING |
-              MG_MISC_SUS0_CFG_GAONPWR_GATING |
-              MG_MISC_SUS0_CFG_TRPWR_GATING |
-              MG_MISC_SUS0_CFG_CL1PWR_GATING |
-              MG_MISC_SUS0_CFG_DGPWR_GATING;
-       I915_WRITE(MG_MISC_SUS0(tc_port), val);
-}
-
-void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port)
-{
-       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-       enum port port = dig_port->base.port;
-       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
-       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
-       u32 val;
-       int i;
-
-       if (tc_port == PORT_TC_NONE)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
-               val = I915_READ(mg_regs[i]);
-               val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING |
-                        MG_DP_MODE_CFG_TRPWR_GATING |
-                        MG_DP_MODE_CFG_CLNPWR_GATING |
-                        MG_DP_MODE_CFG_DIGPWR_GATING |
-                        MG_DP_MODE_CFG_GAONPWR_GATING);
-               I915_WRITE(mg_regs[i], val);
-       }
-
-       val = I915_READ(MG_MISC_SUS0(tc_port));
-       val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK |
-                MG_MISC_SUS0_CFG_TR2PWR_GATING |
-                MG_MISC_SUS0_CFG_CL2PWR_GATING |
-                MG_MISC_SUS0_CFG_GAONPWR_GATING |
-                MG_MISC_SUS0_CFG_TRPWR_GATING |
-                MG_MISC_SUS0_CFG_CL1PWR_GATING |
-                MG_MISC_SUS0_CFG_DGPWR_GATING);
-       I915_WRITE(MG_MISC_SUS0(tc_port), val);
-}
-
 int
 intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 {
@@ -455,7 +344,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
        if (INTEL_GEN(dev_priv) >= 10) {
                source_rates = cnl_rates;
                size = ARRAY_SIZE(cnl_rates);
-               if (INTEL_GEN(dev_priv) == 10)
+               if (IS_GEN10(dev_priv))
                        max_rate = cnl_max_source_rate(intel_dp);
                else
                        max_rate = icl_max_source_rate(intel_dp);
@@ -616,9 +505,12 @@ intel_dp_mode_valid(struct drm_connector *connector,
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
        int target_clock = mode->clock;
        int max_rate, mode_rate, max_lanes, max_link_clock;
        int max_dotclk;
+       u16 dsc_max_output_bpp = 0;
+       u8 dsc_slice_count = 0;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -641,7 +533,33 @@ intel_dp_mode_valid(struct drm_connector *connector,
        max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
        mode_rate = intel_dp_link_required(target_clock, 18);
 
-       if (mode_rate > max_rate || target_clock > max_dotclk)
+       /*
+        * Output bpp is stored in 6.4 format so right shift by 4 to get the
+        * integer value since we support only integer values of bpp.
+        */
+       if ((INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) &&
+           drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) {
+               if (intel_dp_is_edp(intel_dp)) {
+                       dsc_max_output_bpp =
+                               drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4;
+                       dsc_slice_count =
+                               drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                               true);
+               } else if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) {
+                       dsc_max_output_bpp =
+                               intel_dp_dsc_get_output_bpp(max_link_clock,
+                                                           max_lanes,
+                                                           target_clock,
+                                                           mode->hdisplay) >> 4;
+                       dsc_slice_count =
+                               intel_dp_dsc_get_slice_count(intel_dp,
+                                                            target_clock,
+                                                            mode->hdisplay);
+               }
+       }
+
+       if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) ||
+           target_clock > max_dotclk)
                return MODE_CLOCK_HIGH;
 
        if (mode->clock < 10000)
@@ -690,7 +608,8 @@ static void pps_lock(struct intel_dp *intel_dp)
         * See intel_power_sequencer_reset() why we need
         * a power domain reference here.
         */
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv,
+                               intel_aux_power_domain(dp_to_dig_port(intel_dp)));
 
        mutex_lock(&dev_priv->pps_mutex);
 }
@@ -701,7 +620,8 @@ static void pps_unlock(struct intel_dp *intel_dp)
 
        mutex_unlock(&dev_priv->pps_mutex);
 
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_put(dev_priv,
+                               intel_aux_power_domain(dp_to_dig_port(intel_dp)));
 }
 
 static void
@@ -1156,6 +1076,7 @@ static uint32_t g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 
        if (index)
                return 0;
@@ -1165,7 +1086,7 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
         * like to run at 2MHz.  So, take the cdclk or PCH rawclk value and
         * divide by 2000 and use that
         */
-       if (intel_dp->aux_ch == AUX_CH_A)
+       if (dig_port->aux_ch == AUX_CH_A)
                return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
        else
                return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
@@ -1174,8 +1095,9 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 
-       if (intel_dp->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
+       if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
                /* Workaround for non-ULT HSW */
                switch (index) {
                case 0: return 63;
@@ -1503,80 +1425,12 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return ret;
 }
 
-static enum aux_ch intel_aux_ch(struct intel_dp *intel_dp)
-{
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       enum port port = encoder->port;
-       const struct ddi_vbt_port_info *info =
-               &dev_priv->vbt.ddi_port_info[port];
-       enum aux_ch aux_ch;
-
-       if (!info->alternate_aux_channel) {
-               aux_ch = (enum aux_ch) port;
-
-               DRM_DEBUG_KMS("using AUX %c for port %c (platform default)\n",
-                             aux_ch_name(aux_ch), port_name(port));
-               return aux_ch;
-       }
-
-       switch (info->alternate_aux_channel) {
-       case DP_AUX_A:
-               aux_ch = AUX_CH_A;
-               break;
-       case DP_AUX_B:
-               aux_ch = AUX_CH_B;
-               break;
-       case DP_AUX_C:
-               aux_ch = AUX_CH_C;
-               break;
-       case DP_AUX_D:
-               aux_ch = AUX_CH_D;
-               break;
-       case DP_AUX_E:
-               aux_ch = AUX_CH_E;
-               break;
-       case DP_AUX_F:
-               aux_ch = AUX_CH_F;
-               break;
-       default:
-               MISSING_CASE(info->alternate_aux_channel);
-               aux_ch = AUX_CH_A;
-               break;
-       }
-
-       DRM_DEBUG_KMS("using AUX %c for port %c (VBT)\n",
-                     aux_ch_name(aux_ch), port_name(port));
-
-       return aux_ch;
-}
-
-static enum intel_display_power_domain
-intel_aux_power_domain(struct intel_dp *intel_dp)
-{
-       switch (intel_dp->aux_ch) {
-       case AUX_CH_A:
-               return POWER_DOMAIN_AUX_A;
-       case AUX_CH_B:
-               return POWER_DOMAIN_AUX_B;
-       case AUX_CH_C:
-               return POWER_DOMAIN_AUX_C;
-       case AUX_CH_D:
-               return POWER_DOMAIN_AUX_D;
-       case AUX_CH_E:
-               return POWER_DOMAIN_AUX_E;
-       case AUX_CH_F:
-               return POWER_DOMAIN_AUX_F;
-       default:
-               MISSING_CASE(intel_dp->aux_ch);
-               return POWER_DOMAIN_AUX_A;
-       }
-}
 
 static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_B:
@@ -1592,7 +1446,8 @@ static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
 static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_B:
@@ -1608,7 +1463,8 @@ static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
 static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_A:
@@ -1626,7 +1482,8 @@ static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
 static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_A:
@@ -1644,7 +1501,8 @@ static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
 static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_A:
@@ -1663,7 +1521,8 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
 static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum aux_ch aux_ch = intel_dp->aux_ch;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       enum aux_ch aux_ch = dig_port->aux_ch;
 
        switch (aux_ch) {
        case AUX_CH_A:
@@ -1689,10 +1548,8 @@ static void
 intel_dp_aux_init(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-
-       intel_dp->aux_ch = intel_aux_ch(intel_dp);
-       intel_dp->aux_power_domain = intel_aux_power_domain(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &dig_port->base;
 
        if (INTEL_GEN(dev_priv) >= 9) {
                intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
@@ -1853,6 +1710,41 @@ struct link_config_limits {
        int min_bpp, max_bpp;
 };
 
+static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       return INTEL_GEN(dev_priv) >= 11 &&
+               pipe_config->cpu_transcoder != TRANSCODER_A;
+}
+
+static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       return intel_dp_source_supports_fec(intel_dp, pipe_config) &&
+               drm_dp_sink_supports_fec(intel_dp->fec_capable);
+}
+
+static bool intel_dp_source_supports_dsc(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+       return INTEL_GEN(dev_priv) >= 10 &&
+               pipe_config->cpu_transcoder != TRANSCODER_A;
+}
+
+static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
+                                 const struct intel_crtc_state *pipe_config)
+{
+       if (!intel_dp_is_edp(intel_dp) && !pipe_config->fec_enable)
+               return false;
+
+       return intel_dp_source_supports_dsc(intel_dp, pipe_config) &&
+               drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
+}
+
 static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
                                struct intel_crtc_state *pipe_config)
 {
@@ -1951,14 +1843,158 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
        return false;
 }
 
+/* Optimize link config in order: max bpp, min lanes, min clock */
+static bool
+intel_dp_compute_link_config_fast(struct intel_dp *intel_dp,
+                                 struct intel_crtc_state *pipe_config,
+                                 const struct link_config_limits *limits)
+{
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       int bpp, clock, lane_count;
+       int mode_rate, link_clock, link_avail;
+
+       for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
+               mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                  bpp);
+
+               for (lane_count = limits->min_lane_count;
+                    lane_count <= limits->max_lane_count;
+                    lane_count <<= 1) {
+                       for (clock = limits->min_clock; clock <= limits->max_clock; clock++) {
+                               link_clock = intel_dp->common_rates[clock];
+                               link_avail = intel_dp_max_data_rate(link_clock,
+                                                                   lane_count);
+
+                               if (mode_rate <= link_avail) {
+                                       pipe_config->lane_count = lane_count;
+                                       pipe_config->pipe_bpp = bpp;
+                                       pipe_config->port_clock = link_clock;
+
+                                       return true;
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
+static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
+{
+       int i, num_bpc;
+       u8 dsc_bpc[3] = {0};
+
+       num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd,
+                                                      dsc_bpc);
+       for (i = 0; i < num_bpc; i++) {
+               if (dsc_max_bpc >= dsc_bpc[i])
+                       return dsc_bpc[i] * 3;
+       }
+
+       return 0;
+}
+
+static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
+                                       struct intel_crtc_state *pipe_config,
+                                       struct drm_connector_state *conn_state,
+                                       struct link_config_limits *limits)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+       u8 dsc_max_bpc;
+       int pipe_bpp;
+
+       if (!intel_dp_supports_dsc(intel_dp, pipe_config))
+               return false;
+
+       dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC,
+                           conn_state->max_requested_bpc);
+
+       pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc);
+       if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) {
+               DRM_DEBUG_KMS("No DSC support for less than 8bpc\n");
+               return false;
+       }
+
+       /*
+        * For now enable DSC for max bpp, max link rate, max lane count.
+        * Optimize this later for the minimum possible link rate/lane count
+        * with DSC enabled for the requested mode.
+        */
+       pipe_config->pipe_bpp = pipe_bpp;
+       pipe_config->port_clock = intel_dp->common_rates[limits->max_clock];
+       pipe_config->lane_count = limits->max_lane_count;
+
+       if (intel_dp_is_edp(intel_dp)) {
+               pipe_config->dsc_params.compressed_bpp =
+                       min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4,
+                             pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count =
+                       drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                       true);
+       } else {
+               u16 dsc_max_output_bpp;
+               u8 dsc_dp_slice_count;
+
+               dsc_max_output_bpp =
+                       intel_dp_dsc_get_output_bpp(pipe_config->port_clock,
+                                                   pipe_config->lane_count,
+                                                   adjusted_mode->crtc_clock,
+                                                   adjusted_mode->crtc_hdisplay);
+               dsc_dp_slice_count =
+                       intel_dp_dsc_get_slice_count(intel_dp,
+                                                    adjusted_mode->crtc_clock,
+                                                    adjusted_mode->crtc_hdisplay);
+               if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
+                       DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
+                       return false;
+               }
+               pipe_config->dsc_params.compressed_bpp = min_t(u16,
+                                                              dsc_max_output_bpp >> 4,
+                                                              pipe_config->pipe_bpp);
+               pipe_config->dsc_params.slice_count = dsc_dp_slice_count;
+       }
+       /*
+        * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate
+        * is greater than the maximum Cdclock and if slice count is even
+        * then we need to use 2 VDSC instances.
+        */
+       if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) {
+               if (pipe_config->dsc_params.slice_count > 1) {
+                       pipe_config->dsc_params.dsc_split = true;
+               } else {
+                       DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
+                       return false;
+               }
+       }
+       if (intel_dp_compute_dsc_params(intel_dp, pipe_config) < 0) {
+               DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d "
+                             "Compressed BPP = %d\n",
+                             pipe_config->pipe_bpp,
+                             pipe_config->dsc_params.compressed_bpp);
+               return false;
+       }
+       pipe_config->dsc_params.compression_enable = true;
+       DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d "
+                     "Compressed Bpp = %d Slice Count = %d\n",
+                     pipe_config->pipe_bpp,
+                     pipe_config->dsc_params.compressed_bpp,
+                     pipe_config->dsc_params.slice_count);
+
+       return true;
+}
+
 static bool
 intel_dp_compute_link_config(struct intel_encoder *encoder,
-                            struct intel_crtc_state *pipe_config)
+                            struct intel_crtc_state *pipe_config,
+                            struct drm_connector_state *conn_state)
 {
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        struct link_config_limits limits;
        int common_len;
+       bool ret;
 
        common_len = intel_dp_common_len_rate_limit(intel_dp,
                                                    intel_dp->max_link_rate);
@@ -1975,13 +2011,15 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
        limits.min_bpp = 6 * 3;
        limits.max_bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
 
-       if (intel_dp_is_edp(intel_dp)) {
+       if (intel_dp_is_edp(intel_dp) && intel_dp->edp_dpcd[0] < DP_EDP_14) {
                /*
                 * Use the maximum clock and number of lanes the eDP panel
-                * advertizes being capable of. The panels are generally
-                * designed to support only a single clock and lane
-                * configuration, and typically these values correspond to the
-                * native resolution of the panel.
+                * advertizes being capable of. The eDP 1.3 and earlier panels
+                * are generally designed to support only a single clock and
+                * lane configuration, and typically these values correspond to
+                * the native resolution of the panel. With eDP 1.4 rate select
+                * and DSC, this is decreasingly the case, and we need to be
+                * able to select less than maximum link config.
                 */
                limits.min_lane_count = limits.max_lane_count;
                limits.min_clock = limits.max_clock;
@@ -1995,23 +2033,52 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
                      intel_dp->common_rates[limits.max_clock],
                      limits.max_bpp, adjusted_mode->crtc_clock);
 
-       /*
-        * Optimize for slow and wide. This is the place to add alternative
-        * optimization policy.
-        */
-       if (!intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits))
-               return false;
-
-       DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
-                     pipe_config->lane_count, pipe_config->port_clock,
-                     pipe_config->pipe_bpp);
-
-       DRM_DEBUG_KMS("DP link rate required %i available %i\n",
-                     intel_dp_link_required(adjusted_mode->crtc_clock,
-                                            pipe_config->pipe_bpp),
-                     intel_dp_max_data_rate(pipe_config->port_clock,
-                                            pipe_config->lane_count));
+       if (intel_dp_is_edp(intel_dp))
+               /*
+                * Optimize for fast and narrow. eDP 1.3 section 3.3 and eDP 1.4
+                * section A.1: "It is recommended that the minimum number of
+                * lanes be used, using the minimum link rate allowed for that
+                * lane configuration."
+                *
+                * Note that we use the max clock and lane count for eDP 1.3 and
+                * earlier, and fast vs. wide is irrelevant.
+                */
+               ret = intel_dp_compute_link_config_fast(intel_dp, pipe_config,
+                                                       &limits);
+       else
+               /* Optimize for slow and wide. */
+               ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config,
+                                                       &limits);
+
+       /* enable compression if the mode doesn't fit available BW */
+       if (!ret) {
+               if (!intel_dp_dsc_compute_config(intel_dp, pipe_config,
+                                                conn_state, &limits))
+                       return false;
+       }
+
+       if (pipe_config->dsc_params.compression_enable) {
+               DRM_DEBUG_KMS("DP lane count %d clock %d Input bpp %d Compressed bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp,
+                             pipe_config->dsc_params.compressed_bpp);
+
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->dsc_params.compressed_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       } else {
+               DRM_DEBUG_KMS("DP lane count %d clock %d bpp %d\n",
+                             pipe_config->lane_count, pipe_config->port_clock,
+                             pipe_config->pipe_bpp);
 
+               DRM_DEBUG_KMS("DP link rate required %i available %i\n",
+                             intel_dp_link_required(adjusted_mode->crtc_clock,
+                                                    pipe_config->pipe_bpp),
+                             intel_dp_max_data_rate(pipe_config->port_clock,
+                                                    pipe_config->lane_count));
+       }
        return true;
 }
 
@@ -2023,6 +2090,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
        enum port port = encoder->port;
        struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        struct intel_connector *intel_connector = intel_dp->attached_connector;
@@ -2034,6 +2102,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
                pipe_config->has_pch_encoder = true;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+       if (lspcon->active)
+               lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
+
        pipe_config->has_drrs = false;
        if (IS_G4X(dev_priv) || port == PORT_A)
                pipe_config->has_audio = false;
@@ -2072,7 +2144,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
                return false;
 
-       if (!intel_dp_compute_link_config(encoder, pipe_config))
+       pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) &&
+                                 intel_dp_supports_fec(intel_dp, pipe_config);
+
+       if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state))
                return false;
 
        if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
@@ -2090,11 +2165,20 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                        intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
        }
 
-       intel_link_compute_m_n(pipe_config->pipe_bpp, pipe_config->lane_count,
-                              adjusted_mode->crtc_clock,
-                              pipe_config->port_clock,
-                              &pipe_config->dp_m_n,
-                              constant_n);
+       if (!pipe_config->dsc_params.compression_enable)
+               intel_link_compute_m_n(pipe_config->pipe_bpp,
+                                      pipe_config->lane_count,
+                                      adjusted_mode->crtc_clock,
+                                      pipe_config->port_clock,
+                                      &pipe_config->dp_m_n,
+                                      constant_n);
+       else
+               intel_link_compute_m_n(pipe_config->dsc_params.compressed_bpp,
+                                      pipe_config->lane_count,
+                                      adjusted_mode->crtc_clock,
+                                      pipe_config->port_clock,
+                                      &pipe_config->dp_m_n,
+                                      constant_n);
 
        if (intel_connector->panel.downclock_mode != NULL &&
                dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
@@ -2338,7 +2422,8 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
        if (edp_have_panel_vdd(intel_dp))
                return need_to_disable;
 
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv,
+                               intel_aux_power_domain(intel_dig_port));
 
        DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
                      port_name(intel_dig_port->base.port));
@@ -2424,7 +2509,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        if ((pp & PANEL_POWER_ON) == 0)
                intel_dp->panel_power_off_time = ktime_get_boottime();
 
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_put(dev_priv,
+                               intel_aux_power_domain(intel_dig_port));
 }
 
 static void edp_panel_vdd_work(struct work_struct *__work)
@@ -2537,6 +2623,7 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
 static void edp_panel_off(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        u32 pp;
        i915_reg_t pp_ctrl_reg;
 
@@ -2546,10 +2633,10 @@ static void edp_panel_off(struct intel_dp *intel_dp)
                return;
 
        DRM_DEBUG_KMS("Turn eDP port %c panel power off\n",
-                     port_name(dp_to_dig_port(intel_dp)->base.port));
+                     port_name(dig_port->base.port));
 
        WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n",
-            port_name(dp_to_dig_port(intel_dp)->base.port));
+            port_name(dig_port->base.port));
 
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
@@ -2568,7 +2655,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
        intel_dp->panel_power_off_time = ktime_get_boottime();
 
        /* We got a reference when we enabled the VDD. */
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_put(dev_priv, intel_aux_power_domain(dig_port));
 }
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
@@ -2788,6 +2875,22 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
                intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
 }
 
+void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state,
+                                          bool enable)
+{
+       int ret;
+
+       if (!crtc_state->dsc_params.compression_enable)
+               return;
+
+       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE,
+                                enable ? DP_DECOMPRESSION_EN : 0);
+       if (ret < 0)
+               DRM_DEBUG_KMS("Failed to %s sink decompression state\n",
+                             enable ? "enable" : "disable");
+}
+
 /* If the sink supports it, try to set the power state appropriately */
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
 {
@@ -3900,6 +4003,40 @@ intel_dp_read_dpcd(struct intel_dp *intel_dp)
        return intel_dp->dpcd[DP_DPCD_REV] != 0;
 }
 
+static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp)
+{
+       /*
+        * Clear the cached register set to avoid using stale values
+        * for the sinks that do not support DSC.
+        */
+       memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
+
+       /* Clear fec_capable to avoid using stale values */
+       intel_dp->fec_capable = 0;
+
+       /* Cache the DSC DPCD if eDP or DP rev >= 1.4 */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x14 ||
+           intel_dp->edp_dpcd[0] >= DP_EDP_14) {
+               if (drm_dp_dpcd_read(&intel_dp->aux, DP_DSC_SUPPORT,
+                                    intel_dp->dsc_dpcd,
+                                    sizeof(intel_dp->dsc_dpcd)) < 0)
+                       DRM_ERROR("Failed to read DPCD register 0x%x\n",
+                                 DP_DSC_SUPPORT);
+
+               DRM_DEBUG_KMS("DSC DPCD: %*ph\n",
+                             (int)sizeof(intel_dp->dsc_dpcd),
+                             intel_dp->dsc_dpcd);
+
+               /* FEC is supported only on DP 1.4 */
+               if (!intel_dp_is_edp(intel_dp) &&
+                   drm_dp_dpcd_readb(&intel_dp->aux, DP_FEC_CAPABILITY,
+                                     &intel_dp->fec_capable) < 0)
+                       DRM_ERROR("Failed to read FEC DPCD register\n");
+
+               DRM_DEBUG_KMS("FEC CAPABILITY: %x\n", intel_dp->fec_capable);
+       }
+}
+
 static bool
 intel_edp_init_dpcd(struct intel_dp *intel_dp)
 {
@@ -3976,6 +4113,10 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
 
        intel_dp_set_common_rates(intel_dp);
 
+       /* Read the eDP DSC DPCD registers */
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               intel_dp_get_dsc_sink_cap(intel_dp);
+
        return true;
 }
 
@@ -3983,8 +4124,6 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
 static bool
 intel_dp_get_dpcd(struct intel_dp *intel_dp)
 {
-       u8 sink_count;
-
        if (!intel_dp_read_dpcd(intel_dp))
                return false;
 
@@ -3994,25 +4133,35 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
                intel_dp_set_common_rates(intel_dp);
        }
 
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &sink_count) <= 0)
-               return false;
-
        /*
-        * Sink count can change between short pulse hpd hence
-        * a member variable in intel_dp will track any changes
-        * between short pulse interrupts.
+        * Some eDP panels do not set a valid value for sink count, that is why
+        * it don't care about read it here and in intel_edp_init_dpcd().
         */
-       intel_dp->sink_count = DP_GET_SINK_COUNT(sink_count);
+       if (!intel_dp_is_edp(intel_dp)) {
+               u8 count;
+               ssize_t r;
 
-       /*
-        * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
-        * a dongle is present but no display. Unless we require to know
-        * if a dongle is present or not, we don't need to update
-        * downstream port information. So, an early return here saves
-        * time from performing other operations which are not required.
-        */
-       if (!intel_dp_is_edp(intel_dp) && !intel_dp->sink_count)
-               return false;
+               r = drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &count);
+               if (r < 1)
+                       return false;
+
+               /*
+                * Sink count can change between short pulse hpd hence
+                * a member variable in intel_dp will track any changes
+                * between short pulse interrupts.
+                */
+               intel_dp->sink_count = DP_GET_SINK_COUNT(count);
+
+               /*
+                * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that
+                * a dongle is present but no display. Unless we require to know
+                * if a dongle is present or not, we don't need to update
+                * downstream port information. So, an early return here saves
+                * time from performing other operations which are not required.
+                */
+               if (!intel_dp->sink_count)
+                       return false;
+       }
 
        if (!drm_dp_is_branch(intel_dp->dpcd))
                return true; /* native DP sink */
@@ -4029,16 +4178,10 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 }
 
 static bool
-intel_dp_can_mst(struct intel_dp *intel_dp)
+intel_dp_sink_can_mst(struct intel_dp *intel_dp)
 {
        u8 mstm_cap;
 
-       if (!i915_modparams.enable_dp_mst)
-               return false;
-
-       if (!intel_dp->can_mst)
-               return false;
-
        if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
                return false;
 
@@ -4048,33 +4191,35 @@ intel_dp_can_mst(struct intel_dp *intel_dp)
        return mstm_cap & DP_MST_CAP;
 }
 
+static bool
+intel_dp_can_mst(struct intel_dp *intel_dp)
+{
+       return i915_modparams.enable_dp_mst &&
+               intel_dp->can_mst &&
+               intel_dp_sink_can_mst(intel_dp);
+}
+
 static void
 intel_dp_configure_mst(struct intel_dp *intel_dp)
 {
-       if (!i915_modparams.enable_dp_mst)
-               return;
+       struct intel_encoder *encoder =
+               &dp_to_dig_port(intel_dp)->base;
+       bool sink_can_mst = intel_dp_sink_can_mst(intel_dp);
+
+       DRM_DEBUG_KMS("MST support? port %c: %s, sink: %s, modparam: %s\n",
+                     port_name(encoder->port), yesno(intel_dp->can_mst),
+                     yesno(sink_can_mst), yesno(i915_modparams.enable_dp_mst));
 
        if (!intel_dp->can_mst)
                return;
 
-       intel_dp->is_mst = intel_dp_can_mst(intel_dp);
-
-       if (intel_dp->is_mst)
-               DRM_DEBUG_KMS("Sink is MST capable\n");
-       else
-               DRM_DEBUG_KMS("Sink is not MST capable\n");
+       intel_dp->is_mst = sink_can_mst &&
+               i915_modparams.enable_dp_mst;
 
        drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
                                        intel_dp->is_mst);
 }
 
-static bool
-intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
-{
-       return drm_dp_dpcd_readb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR,
-                                sink_irq_vector) == 1;
-}
-
 static bool
 intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
 {
@@ -4083,6 +4228,91 @@ intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
                DP_DPRX_ESI_LEN;
 }
 
+u16 intel_dp_dsc_get_output_bpp(int link_clock, uint8_t lane_count,
+                               int mode_clock, int mode_hdisplay)
+{
+       u16 bits_per_pixel, max_bpp_small_joiner_ram;
+       int i;
+
+       /*
+        * Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)*
+        * (LinkSymbolClock)* 8 * ((100-FECOverhead)/100)*(TimeSlotsPerMTP)
+        * FECOverhead = 2.4%, for SST -> TimeSlotsPerMTP is 1,
+        * for MST -> TimeSlotsPerMTP has to be calculated
+        */
+       bits_per_pixel = (link_clock * lane_count * 8 *
+                         DP_DSC_FEC_OVERHEAD_FACTOR) /
+               mode_clock;
+
+       /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
+       max_bpp_small_joiner_ram = DP_DSC_MAX_SMALL_JOINER_RAM_BUFFER /
+               mode_hdisplay;
+
+       /*
+        * Greatest allowed DSC BPP = MIN (output BPP from avaialble Link BW
+        * check, output bpp from small joiner RAM check)
+        */
+       bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram);
+
+       /* Error out if the max bpp is less than smallest allowed valid bpp */
+       if (bits_per_pixel < valid_dsc_bpp[0]) {
+               DRM_DEBUG_KMS("Unsupported BPP %d\n", bits_per_pixel);
+               return 0;
+       }
+
+       /* Find the nearest match in the array of known BPPs from VESA */
+       for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
+               if (bits_per_pixel < valid_dsc_bpp[i + 1])
+                       break;
+       }
+       bits_per_pixel = valid_dsc_bpp[i];
+
+       /*
+        * Compressed BPP in U6.4 format so multiply by 16, for Gen 11,
+        * fractional part is 0
+        */
+       return bits_per_pixel << 4;
+}
+
+u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
+                               int mode_clock,
+                               int mode_hdisplay)
+{
+       u8 min_slice_count, i;
+       int max_slice_width;
+
+       if (mode_clock <= DP_DSC_PEAK_PIXEL_RATE)
+               min_slice_count = DIV_ROUND_UP(mode_clock,
+                                              DP_DSC_MAX_ENC_THROUGHPUT_0);
+       else
+               min_slice_count = DIV_ROUND_UP(mode_clock,
+                                              DP_DSC_MAX_ENC_THROUGHPUT_1);
+
+       max_slice_width = drm_dp_dsc_sink_max_slice_width(intel_dp->dsc_dpcd);
+       if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) {
+               DRM_DEBUG_KMS("Unsupported slice width %d by DP DSC Sink device\n",
+                             max_slice_width);
+               return 0;
+       }
+       /* Also take into account max slice width */
+       min_slice_count = min_t(uint8_t, min_slice_count,
+                               DIV_ROUND_UP(mode_hdisplay,
+                                            max_slice_width));
+
+       /* Find the closest match to the valid slice count values */
+       for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) {
+               if (valid_dsc_slicecount[i] >
+                   drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
+                                                   false))
+                       break;
+               if (min_slice_count  <= valid_dsc_slicecount[i])
+                       return valid_dsc_slicecount[i];
+       }
+
+       DRM_DEBUG_KMS("Unsupported Slice Count %d\n", min_slice_count);
+       return 0;
+}
+
 static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp)
 {
        int status = 0;
@@ -4341,6 +4571,17 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
        if (!intel_dp->link_trained)
                return false;
 
+       /*
+        * While PSR source HW is enabled, it will control main-link sending
+        * frames, enabling and disabling it so trying to do a retrain will fail
+        * as the link would or not be on or it could mix training patterns
+        * and frame data at the same time causing retrain to fail.
+        * Also when exiting PSR, HW will retrain the link anyways fixing
+        * any link status error.
+        */
+       if (intel_psr_enabled(intel_dp))
+               return false;
+
        if (!intel_dp_get_link_status(intel_dp, link_status))
                return false;
 
@@ -4403,7 +4644,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
 
        /* Suppress underruns caused by re-training */
        intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
-       if (crtc->config->has_pch_encoder)
+       if (crtc_state->has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv,
                                                      intel_crtc_pch_transcoder(crtc), false);
 
@@ -4414,7 +4655,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
        intel_wait_for_vblank(dev_priv, crtc->pipe);
 
        intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true);
-       if (crtc->config->has_pch_encoder)
+       if (crtc_state->has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev_priv,
                                                      intel_crtc_pch_transcoder(crtc), true);
 
@@ -4462,6 +4703,29 @@ static bool intel_dp_hotplug(struct intel_encoder *encoder,
        return changed;
 }
 
+static void intel_dp_check_service_irq(struct intel_dp *intel_dp)
+{
+       u8 val;
+
+       if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
+               return;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux,
+                             DP_DEVICE_SERVICE_IRQ_VECTOR, &val) != 1 || !val)
+               return;
+
+       drm_dp_dpcd_writeb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, val);
+
+       if (val & DP_AUTOMATED_TEST_REQUEST)
+               intel_dp_handle_test_request(intel_dp);
+
+       if (val & DP_CP_IRQ)
+               intel_hdcp_check_link(intel_dp->attached_connector);
+
+       if (val & DP_SINK_SPECIFIC_IRQ)
+               DRM_DEBUG_DRIVER("Sink specific irq unhandled\n");
+}
+
 /*
  * According to DP spec
  * 5.1.2:
@@ -4479,7 +4743,6 @@ static bool
 intel_dp_short_pulse(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       u8 sink_irq_vector = 0;
        u8 old_sink_count = intel_dp->sink_count;
        bool ret;
 
@@ -4502,20 +4765,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
                return false;
        }
 
-       /* Try to read the source of the interrupt */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
-           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
-           sink_irq_vector != 0) {
-               /* Clear interrupt source */
-               drm_dp_dpcd_writeb(&intel_dp->aux,
-                                  DP_DEVICE_SERVICE_IRQ_VECTOR,
-                                  sink_irq_vector);
-
-               if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
-                       intel_dp_handle_test_request(intel_dp);
-               if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
-                       DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
-       }
+       intel_dp_check_service_irq(intel_dp);
 
        /* Handle CEC interrupts, if any */
        drm_dp_cec_irq(&intel_dp->aux);
@@ -4810,6 +5060,9 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv,
                              type_str);
 }
 
+static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv,
+                                 struct intel_digital_port *dig_port);
+
 /*
  * This function implements the first part of the Connect Flow described by our
  * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading
@@ -4864,9 +5117,7 @@ static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv,
        if (dig_port->tc_type == TC_PORT_TYPEC &&
            !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) {
                DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port);
-               val = I915_READ(PORT_TX_DFLEXDPCSSS);
-               val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port);
-               I915_WRITE(PORT_TX_DFLEXDPCSSS, val);
+               icl_tc_phy_disconnect(dev_priv, dig_port);
                return false;
        }
 
@@ -4881,21 +5132,24 @@ static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv,
                                  struct intel_digital_port *dig_port)
 {
        enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
-       u32 val;
 
-       if (dig_port->tc_type != TC_PORT_LEGACY &&
-           dig_port->tc_type != TC_PORT_TYPEC)
+       if (dig_port->tc_type == TC_PORT_UNKNOWN)
                return;
 
        /*
-        * This function may be called many times in a row without an HPD event
-        * in between, so try to avoid the write when we can.
+        * TBT disconnection flow is read the live status, what was done in
+        * caller.
         */
-       val = I915_READ(PORT_TX_DFLEXDPCSSS);
-       if (val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port)) {
+       if (dig_port->tc_type == TC_PORT_TYPEC ||
+           dig_port->tc_type == TC_PORT_LEGACY) {
+               u32 val;
+
+               val = I915_READ(PORT_TX_DFLEXDPCSSS);
                val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port);
                I915_WRITE(PORT_TX_DFLEXDPCSSS, val);
        }
+
+       dig_port->tc_type = TC_PORT_UNKNOWN;
 }
 
 /*
@@ -4945,19 +5199,14 @@ static bool icl_digital_port_connected(struct intel_encoder *encoder)
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
 
-       switch (encoder->hpd_pin) {
-       case HPD_PORT_A:
-       case HPD_PORT_B:
+       if (intel_port_is_combophy(dev_priv, encoder->port))
                return icl_combo_port_connected(dev_priv, dig_port);
-       case HPD_PORT_C:
-       case HPD_PORT_D:
-       case HPD_PORT_E:
-       case HPD_PORT_F:
+       else if (intel_port_is_tc(dev_priv, encoder->port))
                return icl_tc_port_connected(dev_priv, dig_port);
-       default:
+       else
                MISSING_CASE(encoder->hpd_pin);
-               return false;
-       }
+
+       return false;
 }
 
 /*
@@ -4982,20 +5231,23 @@ bool intel_digital_port_connected(struct intel_encoder *encoder)
                        return g4x_digital_port_connected(encoder);
        }
 
-       if (IS_GEN5(dev_priv))
-               return ilk_digital_port_connected(encoder);
-       else if (IS_GEN6(dev_priv))
-               return snb_digital_port_connected(encoder);
-       else if (IS_GEN7(dev_priv))
-               return ivb_digital_port_connected(encoder);
-       else if (IS_GEN8(dev_priv))
-               return bdw_digital_port_connected(encoder);
+       if (INTEL_GEN(dev_priv) >= 11)
+               return icl_digital_port_connected(encoder);
+       else if (IS_GEN10(dev_priv) || IS_GEN9_BC(dev_priv))
+               return spt_digital_port_connected(encoder);
        else if (IS_GEN9_LP(dev_priv))
                return bxt_digital_port_connected(encoder);
-       else if (IS_GEN9_BC(dev_priv) || IS_GEN10(dev_priv))
-               return spt_digital_port_connected(encoder);
-       else
-               return icl_digital_port_connected(encoder);
+       else if (IS_GEN8(dev_priv))
+               return bdw_digital_port_connected(encoder);
+       else if (IS_GEN7(dev_priv))
+               return ivb_digital_port_connected(encoder);
+       else if (IS_GEN6(dev_priv))
+               return snb_digital_port_connected(encoder);
+       else if (IS_GEN5(dev_priv))
+               return ilk_digital_port_connected(encoder);
+
+       MISSING_CASE(INTEL_GEN(dev_priv));
+       return false;
 }
 
 static struct edid *
@@ -5042,28 +5294,35 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
 }
 
 static int
-intel_dp_long_pulse(struct intel_connector *connector,
-                   struct drm_modeset_acquire_ctx *ctx)
+intel_dp_detect(struct drm_connector *connector,
+               struct drm_modeset_acquire_ctx *ctx,
+               bool force)
 {
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &dig_port->base;
        enum drm_connector_status status;
-       u8 sink_irq_vector = 0;
+       enum intel_display_power_domain aux_domain =
+               intel_aux_power_domain(dig_port);
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
        WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
 
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv, aux_domain);
 
        /* Can't disconnect eDP */
        if (intel_dp_is_edp(intel_dp))
                status = edp_detect(intel_dp);
-       else if (intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base))
+       else if (intel_digital_port_connected(encoder))
                status = intel_dp_detect_dpcd(intel_dp);
        else
                status = connector_status_disconnected;
 
        if (status == connector_status_disconnected) {
                memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
+               memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
 
                if (intel_dp->is_mst) {
                        DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n",
@@ -5089,6 +5348,10 @@ intel_dp_long_pulse(struct intel_connector *connector,
 
        intel_dp_print_rates(intel_dp);
 
+       /* Read DP Sink DSC Cap DPCD regs for DP v1.4 */
+       if (INTEL_GEN(dev_priv) >= 11)
+               intel_dp_get_dsc_sink_cap(intel_dp);
+
        drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
                         drm_dp_is_branch(intel_dp->dpcd));
 
@@ -5109,9 +5372,13 @@ intel_dp_long_pulse(struct intel_connector *connector,
         * with an IRQ_HPD, so force a link status check.
         */
        if (!intel_dp_is_edp(intel_dp)) {
-               struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+               int ret;
 
-               intel_dp_retrain_link(encoder, ctx);
+               ret = intel_dp_retrain_link(encoder, ctx);
+               if (ret) {
+                       intel_display_power_put(dev_priv, aux_domain);
+                       return ret;
+               }
        }
 
        /*
@@ -5123,61 +5390,17 @@ intel_dp_long_pulse(struct intel_connector *connector,
        intel_dp->aux.i2c_defer_count = 0;
 
        intel_dp_set_edid(intel_dp);
-       if (intel_dp_is_edp(intel_dp) || connector->detect_edid)
+       if (intel_dp_is_edp(intel_dp) ||
+           to_intel_connector(connector)->detect_edid)
                status = connector_status_connected;
-       intel_dp->detect_done = true;
 
-       /* Try to read the source of the interrupt */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
-           intel_dp_get_sink_irq(intel_dp, &sink_irq_vector) &&
-           sink_irq_vector != 0) {
-               /* Clear interrupt source */
-               drm_dp_dpcd_writeb(&intel_dp->aux,
-                                  DP_DEVICE_SERVICE_IRQ_VECTOR,
-                                  sink_irq_vector);
-
-               if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
-                       intel_dp_handle_test_request(intel_dp);
-               if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
-                       DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
-       }
+       intel_dp_check_service_irq(intel_dp);
 
 out:
        if (status != connector_status_connected && !intel_dp->is_mst)
                intel_dp_unset_edid(intel_dp);
 
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
-       return status;
-}
-
-static int
-intel_dp_detect(struct drm_connector *connector,
-               struct drm_modeset_acquire_ctx *ctx,
-               bool force)
-{
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       int status = connector->status;
-
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
-
-       /* If full detect is not performed yet, do a full detect */
-       if (!intel_dp->detect_done) {
-               struct drm_crtc *crtc;
-               int ret;
-
-               crtc = connector->state->crtc;
-               if (crtc) {
-                       ret = drm_modeset_lock(&crtc->mutex, ctx);
-                       if (ret)
-                               return ret;
-               }
-
-               status = intel_dp_long_pulse(intel_dp->attached_connector, ctx);
-       }
-
-       intel_dp->detect_done = false;
-
+       intel_display_power_put(dev_priv, aux_domain);
        return status;
 }
 
@@ -5185,8 +5408,11 @@ static void
 intel_dp_force(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &dig_port->base;
        struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
+       enum intel_display_power_domain aux_domain =
+               intel_aux_power_domain(dig_port);
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
@@ -5195,11 +5421,11 @@ intel_dp_force(struct drm_connector *connector)
        if (connector->status != connector_status_connected)
                return;
 
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv, aux_domain);
 
        intel_dp_set_edid(intel_dp);
 
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_put(dev_priv, aux_domain);
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
@@ -5264,27 +5490,6 @@ intel_dp_connector_unregister(struct drm_connector *connector)
        intel_connector_unregister(connector);
 }
 
-static void
-intel_dp_connector_destroy(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       kfree(intel_connector->detect_edid);
-
-       if (!IS_ERR_OR_NULL(intel_connector->edid))
-               kfree(intel_connector->edid);
-
-       /*
-        * Can't call intel_dp_is_edp() since the encoder may have been
-        * destroyed already.
-        */
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-               intel_panel_fini(&intel_connector->panel);
-
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
@@ -5348,7 +5553,8 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
        dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
                                     an, DRM_HDCP_AN_LEN);
        if (dpcd_ret != DRM_HDCP_AN_LEN) {
-               DRM_ERROR("Failed to write An over DP/AUX (%zd)\n", dpcd_ret);
+               DRM_DEBUG_KMS("Failed to write An over DP/AUX (%zd)\n",
+                             dpcd_ret);
                return dpcd_ret >= 0 ? -EIO : dpcd_ret;
        }
 
@@ -5364,10 +5570,10 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
                                rxbuf, sizeof(rxbuf),
                                DP_AUX_CH_CTL_AUX_AKSV_SELECT);
        if (ret < 0) {
-               DRM_ERROR("Write Aksv over DP/AUX failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Write Aksv over DP/AUX failed (%d)\n", ret);
                return ret;
        } else if (ret == 0) {
-               DRM_ERROR("Aksv write over DP/AUX was empty\n");
+               DRM_DEBUG_KMS("Aksv write over DP/AUX was empty\n");
                return -EIO;
        }
 
@@ -5382,7 +5588,7 @@ static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
                               DRM_HDCP_KSV_LEN);
        if (ret != DRM_HDCP_KSV_LEN) {
-               DRM_ERROR("Read Bksv from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read Bksv from DP/AUX failed (%zd)\n", ret);
                return ret >= 0 ? -EIO : ret;
        }
        return 0;
@@ -5400,7 +5606,7 @@ static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BINFO,
                               bstatus, DRM_HDCP_BSTATUS_LEN);
        if (ret != DRM_HDCP_BSTATUS_LEN) {
-               DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
                return ret >= 0 ? -EIO : ret;
        }
        return 0;
@@ -5415,7 +5621,7 @@ int intel_dp_hdcp_read_bcaps(struct intel_digital_port *intel_dig_port,
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
                               bcaps, 1);
        if (ret != 1) {
-               DRM_ERROR("Read bcaps from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read bcaps from DP/AUX failed (%zd)\n", ret);
                return ret >= 0 ? -EIO : ret;
        }
 
@@ -5445,7 +5651,7 @@ int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
                               ri_prime, DRM_HDCP_RI_LEN);
        if (ret != DRM_HDCP_RI_LEN) {
-               DRM_ERROR("Read Ri' from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read Ri' from DP/AUX failed (%zd)\n", ret);
                return ret >= 0 ? -EIO : ret;
        }
        return 0;
@@ -5460,7 +5666,7 @@ int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
                               &bstatus, 1);
        if (ret != 1) {
-               DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
                return ret >= 0 ? -EIO : ret;
        }
        *ksv_ready = bstatus & DP_BSTATUS_READY;
@@ -5482,8 +5688,8 @@ int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
                                       ksv_fifo + i * DRM_HDCP_KSV_LEN,
                                       len);
                if (ret != len) {
-                       DRM_ERROR("Read ksv[%d] from DP/AUX failed (%zd)\n", i,
-                                 ret);
+                       DRM_DEBUG_KMS("Read ksv[%d] from DP/AUX failed (%zd)\n",
+                                     i, ret);
                        return ret >= 0 ? -EIO : ret;
                }
        }
@@ -5503,7 +5709,7 @@ int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
                               DP_AUX_HDCP_V_PRIME(i), part,
                               DRM_HDCP_V_PRIME_PART_LEN);
        if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
-               DRM_ERROR("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
+               DRM_DEBUG_KMS("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
                return ret >= 0 ? -EIO : ret;
        }
        return 0;
@@ -5526,7 +5732,7 @@ bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
        ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
                               &bstatus, 1);
        if (ret != 1) {
-               DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+               DRM_DEBUG_KMS("Read bstatus from DP/AUX failed (%zd)\n", ret);
                return false;
        }
 
@@ -5565,6 +5771,7 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
 static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -5578,7 +5785,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
         * indefinitely.
         */
        DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv, intel_aux_power_domain(dig_port));
 
        edp_panel_vdd_schedule_off(intel_dp);
 }
@@ -5631,7 +5838,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .atomic_set_property = intel_digital_connector_atomic_set_property,
        .late_register = intel_dp_connector_register,
        .early_unregister = intel_dp_connector_unregister,
-       .destroy = intel_dp_connector_destroy,
+       .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
@@ -5673,11 +5880,11 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 
        if (long_hpd) {
                intel_dp->reset_link_params = true;
-               intel_dp->detect_done = false;
                return IRQ_NONE;
        }
 
-       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_get(dev_priv,
+                               intel_aux_power_domain(intel_dig_port));
 
        if (intel_dp->is_mst) {
                if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
@@ -5690,7 +5897,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                        intel_dp->is_mst = false;
                        drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
                                                        intel_dp->is_mst);
-                       intel_dp->detect_done = false;
                        goto put_power;
                }
        }
@@ -5700,19 +5906,15 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 
                handled = intel_dp_short_pulse(intel_dp);
 
-               /* Short pulse can signify loss of hdcp authentication */
-               intel_hdcp_check_link(intel_dp->attached_connector);
-
-               if (!handled) {
-                       intel_dp->detect_done = false;
+               if (!handled)
                        goto put_power;
-               }
        }
 
        ret = IRQ_HANDLED;
 
 put_power:
-       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
+       intel_display_power_put(dev_priv,
+                               intel_aux_power_domain(intel_dig_port));
 
        return ret;
 }
@@ -5743,6 +5945,10 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
                intel_attach_force_audio_property(connector);
 
        intel_attach_broadcast_rgb_property(connector);
+       if (HAS_GMCH_DISPLAY(dev_priv))
+               drm_connector_attach_max_bpc_property(connector, 6, 10);
+       else if (INTEL_GEN(dev_priv) >= 5)
+               drm_connector_attach_max_bpc_property(connector, 6, 12);
 
        if (intel_dp_is_edp(intel_dp)) {
                u32 allowed_scalers;
@@ -6099,10 +6305,10 @@ static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
        if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
                switch (index) {
                case DRRS_HIGH_RR:
-                       intel_dp_set_m_n(intel_crtc, M1_N1);
+                       intel_dp_set_m_n(crtc_state, M1_N1);
                        break;
                case DRRS_LOW_RR:
-                       intel_dp_set_m_n(intel_crtc, M2_N2);
+                       intel_dp_set_m_n(crtc_state, M2_N2);
                        break;
                case DRRS_MAX_RR:
                default:
@@ -6422,6 +6628,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        if (!intel_dp_is_edp(intel_dp))
                return true;
 
+       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, edp_panel_vdd_work);
+
        /*
         * On IBX/CPT we may get here with LVDS already registered. Since the
         * driver uses the only internal power sequencer available for both
@@ -6514,6 +6722,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        intel_connector->panel.backlight.power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector, pipe);
 
+       if (fixed_mode)
+               drm_connector_init_panel_orientation_property(
+                       connector, fixed_mode->hdisplay, fixed_mode->vdisplay);
+
        return true;
 
 out_vdd_off:
@@ -6624,9 +6836,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 
        intel_dp_aux_init(intel_dp);
 
-       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-                         edp_panel_vdd_work);
-
        intel_connector_attach_encoder(intel_connector, intel_encoder);
 
        if (HAS_DDI(dev_priv))
@@ -6743,6 +6952,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
        if (port != PORT_A)
                intel_infoframe_init(intel_dig_port);
 
+       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
        if (!intel_dp_init_connector(intel_dig_port, intel_connector))
                goto err_init_connector;
 
index a911691dbd0fdd1837c8cfadec09f8d39eb7ac7d..4de247ddf05f80a89fc4d84aeaf93112c4d468f2 100644 (file)
@@ -51,6 +51,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->has_pch_encoder = false;
        bpp = 24;
        if (intel_dp->compliance.test_data.bpc) {
@@ -208,12 +209,25 @@ static void intel_mst_pre_pll_enable_dp(struct intel_encoder *encoder,
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
 
-       if (intel_dp->active_mst_links == 0 &&
-           intel_dig_port->base.pre_pll_enable)
+       if (intel_dp->active_mst_links == 0)
                intel_dig_port->base.pre_pll_enable(&intel_dig_port->base,
                                                    pipe_config, NULL);
 }
 
+static void intel_mst_post_pll_disable_dp(struct intel_encoder *encoder,
+                                         const struct intel_crtc_state *old_crtc_state,
+                                         const struct drm_connector_state *old_conn_state)
+{
+       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+       struct intel_digital_port *intel_dig_port = intel_mst->primary;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       if (intel_dp->active_mst_links == 0)
+               intel_dig_port->base.post_pll_disable(&intel_dig_port->base,
+                                                     old_crtc_state,
+                                                     old_conn_state);
+}
+
 static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
                                    const struct intel_crtc_state *pipe_config,
                                    const struct drm_connector_state *conn_state)
@@ -335,24 +349,12 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force)
                                      intel_connector->port);
 }
 
-static void
-intel_dp_mst_connector_destroy(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       if (!IS_ERR_OR_NULL(intel_connector->edid))
-               kfree(intel_connector->edid);
-
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
        .detect = intel_dp_mst_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_dp_mst_connector_destroy,
+       .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
@@ -560,6 +562,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum
        intel_encoder->disable = intel_mst_disable_dp;
        intel_encoder->post_disable = intel_mst_post_disable_dp;
        intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp;
+       intel_encoder->post_pll_disable = intel_mst_post_pll_disable_dp;
        intel_encoder->pre_enable = intel_mst_pre_enable_dp;
        intel_encoder->enable = intel_mst_enable_dp;
        intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
index 00b3ab656b06d0f2d49bb87922d78813299f9752..3c7f10d1765824ba32d0899b6e50e84d488518e8 100644 (file)
@@ -748,7 +748,7 @@ void chv_data_lane_soft_reset(struct intel_encoder *encoder,
                val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
 
-       if (crtc->config->lane_count > 2) {
+       if (crtc_state->lane_count > 2) {
                val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
                if (reset)
                        val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
@@ -765,7 +765,7 @@ void chv_data_lane_soft_reset(struct intel_encoder *encoder,
                val |= DPIO_PCS_CLK_SOFT_RESET;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
 
-       if (crtc->config->lane_count > 2) {
+       if (crtc_state->lane_count > 2) {
                val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
                val |= CHV_PCS_REQ_SOFTRESET_EN;
                if (reset)
index e6cac9225536a6ce39d44d6f898e6577b042dba0..d513ca875c67693cf508c389367febdd3ae320d0 100644 (file)
@@ -126,16 +126,16 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
 
 /**
  * intel_prepare_shared_dpll - call a dpll's prepare hook
- * @crtc: CRTC which has a shared dpll
+ * @crtc_state: CRTC, and its state, which has a shared dpll
  *
  * This calls the PLL's prepare hook if it has one and if the PLL is not
  * already enabled. The prepare hook is platform specific.
  */
-void intel_prepare_shared_dpll(struct intel_crtc *crtc)
+void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
 
        if (WARN_ON(pll == NULL))
                return;
@@ -154,15 +154,15 @@ void intel_prepare_shared_dpll(struct intel_crtc *crtc)
 
 /**
  * intel_enable_shared_dpll - enable a CRTC's shared DPLL
- * @crtc: CRTC which has a shared DPLL
+ * @crtc_state: CRTC, and its state, which has a shared DPLL
  *
  * Enable the shared DPLL used by @crtc.
  */
-void intel_enable_shared_dpll(struct intel_crtc *crtc)
+void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state)
 {
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
        unsigned int crtc_mask = drm_crtc_mask(&crtc->base);
        unsigned int old_mask;
 
@@ -199,14 +199,15 @@ out:
 
 /**
  * intel_disable_shared_dpll - disable a CRTC's shared DPLL
- * @crtc: CRTC which has a shared DPLL
+ * @crtc_state: CRTC, and its state, which has a shared DPLL
  *
  * Disable the shared DPLL used by @crtc.
  */
-void intel_disable_shared_dpll(struct intel_crtc *crtc)
+void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state)
 {
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+       struct intel_shared_dpll *pll = crtc_state->shared_dpll;
        unsigned int crtc_mask = drm_crtc_mask(&crtc->base);
 
        /* PCH only available on ILK+ */
@@ -409,14 +410,6 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
                                 struct intel_shared_dpll *pll)
 {
        const enum intel_dpll_id id = pll->info->id;
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_crtc *crtc;
-
-       /* Make sure no transcoder isn't still depending on us. */
-       for_each_intel_crtc(dev, crtc) {
-               if (crtc->config->shared_dpll == pll)
-                       assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
-       }
 
        I915_WRITE(PCH_DPLL(id), 0);
        POSTING_READ(PCH_DPLL(id));
@@ -2530,7 +2523,8 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,
 
        if (intel_port_is_tc(dev_priv, encoder->port))
                ret = icl_calc_tbt_pll(dev_priv, clock, &pll_params);
-       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
+                intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
                ret = cnl_ddi_calculate_wrpll(clock, dev_priv, &pll_params);
        else
                ret = icl_calc_dp_combo_pll(dev_priv, clock, &pll_params);
@@ -2628,11 +2622,16 @@ static enum port icl_mg_pll_id_to_port(enum intel_dpll_id id)
        return id - DPLL_ID_ICL_MGPLL1 + PORT_C;
 }
 
-static enum intel_dpll_id icl_port_to_mg_pll_id(enum port port)
+enum intel_dpll_id icl_port_to_mg_pll_id(enum port port)
 {
        return port - PORT_C + DPLL_ID_ICL_MGPLL1;
 }
 
+bool intel_dpll_is_combophy(enum intel_dpll_id id)
+{
+       return id == DPLL_ID_ICL_DPLL0 || id == DPLL_ID_ICL_DPLL1;
+}
+
 static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
                                     uint32_t *target_dco_khz,
                                     struct intel_dpll_hw_state *state)
@@ -2874,8 +2873,8 @@ static struct intel_shared_dpll *
 icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
             struct intel_encoder *encoder)
 {
-       struct intel_digital_port *intel_dig_port =
-                       enc_to_dig_port(&encoder->base);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *intel_dig_port;
        struct intel_shared_dpll *pll;
        struct intel_dpll_hw_state pll_state = {};
        enum port port = encoder->port;
@@ -2883,18 +2882,21 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
        int clock = crtc_state->port_clock;
        bool ret;
 
-       switch (port) {
-       case PORT_A:
-       case PORT_B:
+       if (intel_port_is_combophy(dev_priv, port)) {
                min = DPLL_ID_ICL_DPLL0;
                max = DPLL_ID_ICL_DPLL1;
                ret = icl_calc_dpll_state(crtc_state, encoder, clock,
                                          &pll_state);
-               break;
-       case PORT_C:
-       case PORT_D:
-       case PORT_E:
-       case PORT_F:
+       } else if (intel_port_is_tc(dev_priv, port)) {
+               if (encoder->type == INTEL_OUTPUT_DP_MST) {
+                       struct intel_dp_mst_encoder *mst_encoder;
+
+                       mst_encoder = enc_to_mst(&encoder->base);
+                       intel_dig_port = mst_encoder->primary;
+               } else {
+                       intel_dig_port = enc_to_dig_port(&encoder->base);
+               }
+
                if (intel_dig_port->tc_type == TC_PORT_TBT) {
                        min = DPLL_ID_ICL_TBTPLL;
                        max = min;
@@ -2906,8 +2908,7 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
                        ret = icl_calc_mg_pll_state(crtc_state, encoder, clock,
                                                    &pll_state);
                }
-               break;
-       default:
+       } else {
                MISSING_CASE(port);
                return NULL;
        }
@@ -2932,21 +2933,16 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 
 static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id)
 {
-       switch (id) {
-       default:
-               MISSING_CASE(id);
-               /* fall through */
-       case DPLL_ID_ICL_DPLL0:
-       case DPLL_ID_ICL_DPLL1:
+       if (intel_dpll_is_combophy(id))
                return CNL_DPLL_ENABLE(id);
-       case DPLL_ID_ICL_TBTPLL:
+       else if (id == DPLL_ID_ICL_TBTPLL)
                return TBT_PLL_ENABLE;
-       case DPLL_ID_ICL_MGPLL1:
-       case DPLL_ID_ICL_MGPLL2:
-       case DPLL_ID_ICL_MGPLL3:
-       case DPLL_ID_ICL_MGPLL4:
+       else
+               /*
+                * TODO: Make MG_PLL macros use
+                * tc port id instead of port id
+                */
                return MG_PLL_ENABLE(icl_mg_pll_id_to_port(id));
-       }
 }
 
 static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -2965,17 +2961,11 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
        if (!(val & PLL_ENABLE))
                goto out;
 
-       switch (id) {
-       case DPLL_ID_ICL_DPLL0:
-       case DPLL_ID_ICL_DPLL1:
-       case DPLL_ID_ICL_TBTPLL:
+       if (intel_dpll_is_combophy(id) ||
+           id == DPLL_ID_ICL_TBTPLL) {
                hw_state->cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(id));
                hw_state->cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(id));
-               break;
-       case DPLL_ID_ICL_MGPLL1:
-       case DPLL_ID_ICL_MGPLL2:
-       case DPLL_ID_ICL_MGPLL3:
-       case DPLL_ID_ICL_MGPLL4:
+       } else {
                port = icl_mg_pll_id_to_port(id);
                hw_state->mg_refclkin_ctl = I915_READ(MG_REFCLKIN_CTL(port));
                hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK;
@@ -3013,9 +3003,6 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
 
                hw_state->mg_pll_tdc_coldst_bias &= hw_state->mg_pll_tdc_coldst_bias_mask;
                hw_state->mg_pll_bias &= hw_state->mg_pll_bias_mask;
-               break;
-       default:
-               MISSING_CASE(id);
        }
 
        ret = true;
@@ -3104,21 +3091,10 @@ static void icl_pll_enable(struct drm_i915_private *dev_priv,
                                    PLL_POWER_STATE, 1))
                DRM_ERROR("PLL %d Power not enabled\n", id);
 
-       switch (id) {
-       case DPLL_ID_ICL_DPLL0:
-       case DPLL_ID_ICL_DPLL1:
-       case DPLL_ID_ICL_TBTPLL:
+       if (intel_dpll_is_combophy(id) || id == DPLL_ID_ICL_TBTPLL)
                icl_dpll_write(dev_priv, pll);
-               break;
-       case DPLL_ID_ICL_MGPLL1:
-       case DPLL_ID_ICL_MGPLL2:
-       case DPLL_ID_ICL_MGPLL3:
-       case DPLL_ID_ICL_MGPLL4:
+       else
                icl_mg_pll_write(dev_priv, pll);
-               break;
-       default:
-               MISSING_CASE(id);
-       }
 
        /*
         * DVFS pre sequence would be here, but in our driver the cdclk code
index bf0de8a4dc6378c9bd6de5432449ec1afac10bd1..a033d8f06d4a80f726b13287067a6953b326f14d 100644 (file)
@@ -334,9 +334,9 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
 void intel_release_shared_dpll(struct intel_shared_dpll *dpll,
                               struct intel_crtc *crtc,
                               struct drm_atomic_state *state);
-void intel_prepare_shared_dpll(struct intel_crtc *crtc);
-void intel_enable_shared_dpll(struct intel_crtc *crtc);
-void intel_disable_shared_dpll(struct intel_crtc *crtc);
+void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state);
+void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state);
+void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state);
 void intel_shared_dpll_swap_state(struct drm_atomic_state *state);
 void intel_shared_dpll_init(struct drm_device *dev);
 
@@ -345,5 +345,7 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv,
 int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv,
                               uint32_t pll_id);
 int cnl_hdmi_pll_ref_clock(struct drm_i915_private *dev_priv);
+enum intel_dpll_id icl_port_to_mg_pll_id(enum port port);
+bool intel_dpll_is_combophy(enum intel_dpll_id id);
 
 #endif /* _INTEL_DPLL_MGR_H_ */
index db6fa1d0cbdae3efea1e3ddb1c3ce43bf5f8a10e..f94a04b4ad8788bcc1d8f9ca3073eaa00f33648a 100644 (file)
@@ -381,6 +381,15 @@ struct intel_hdcp_shim {
                            bool *hdcp_capable);
 };
 
+struct intel_hdcp {
+       const struct intel_hdcp_shim *shim;
+       /* Mutex for hdcp state of the connector */
+       struct mutex mutex;
+       u64 value;
+       struct delayed_work check_work;
+       struct work_struct prop_work;
+};
+
 struct intel_connector {
        struct drm_connector base;
        /*
@@ -413,11 +422,7 @@ struct intel_connector {
        /* Work struct to schedule a uevent on link train failure */
        struct work_struct modeset_retry_work;
 
-       const struct intel_hdcp_shim *hdcp_shim;
-       struct mutex hdcp_mutex;
-       uint64_t hdcp_value; /* protected by hdcp_mutex */
-       struct delayed_work hdcp_check_work;
-       struct work_struct hdcp_prop_work;
+       struct intel_hdcp hdcp;
 };
 
 struct intel_digital_connector_state {
@@ -539,6 +544,26 @@ struct intel_plane_state {
         */
        int scaler_id;
 
+       /*
+        * linked_plane:
+        *
+        * ICL planar formats require 2 planes that are updated as pairs.
+        * This member is used to make sure the other plane is also updated
+        * when required, and for update_slave() to find the correct
+        * plane_state to pass as argument.
+        */
+       struct intel_plane *linked_plane;
+
+       /*
+        * slave:
+        * If set don't update use the linked plane's state for updating
+        * this plane during atomic commit with the update_slave() callback.
+        *
+        * It's also used by the watermark code to ignore wm calculations on
+        * this plane. They're calculated by the linked plane's wm code.
+        */
+       u32 slave;
+
        struct drm_intel_sprite_colorkey ckey;
 };
 
@@ -681,6 +706,8 @@ struct intel_crtc_wm_state {
                        /* gen9+ only needs 1-step wm programming */
                        struct skl_pipe_wm optimal;
                        struct skl_ddb_entry ddb;
+                       struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES];
+                       struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES];
                } skl;
 
                struct {
@@ -713,6 +740,13 @@ struct intel_crtc_wm_state {
        bool need_postvbl_update;
 };
 
+enum intel_output_format {
+       INTEL_OUTPUT_FORMAT_INVALID,
+       INTEL_OUTPUT_FORMAT_RGB,
+       INTEL_OUTPUT_FORMAT_YCBCR420,
+       INTEL_OUTPUT_FORMAT_YCBCR444,
+};
+
 struct intel_crtc_state {
        struct drm_crtc_state base;
 
@@ -894,14 +928,32 @@ struct intel_crtc_state {
        u8 active_planes;
        u8 nv12_planes;
 
+       /* bitmask of planes that will be updated during the commit */
+       u8 update_planes;
+
        /* HDMI scrambling status */
        bool hdmi_scrambling;
 
        /* HDMI High TMDS char rate ratio */
        bool hdmi_high_tmds_clock_ratio;
 
-       /* output format is YCBCR 4:2:0 */
-       bool ycbcr420;
+       /* Output format RGB/YCBCR etc */
+       enum intel_output_format output_format;
+
+       /* Output down scaling is done in LSPCON device */
+       bool lspcon_downsampling;
+
+       /* Display Stream compression state */
+       struct {
+               bool compression_enable;
+               bool dsc_split;
+               u16 compressed_bpp;
+               u8 slice_count;
+       } dsc_params;
+       struct drm_dsc_config dp_dsc_cfg;
+
+       /* Forward Error correction State */
+       bool fec_enable;
 };
 
 struct intel_crtc {
@@ -974,8 +1026,11 @@ struct intel_plane {
        void (*update_plane)(struct intel_plane *plane,
                             const struct intel_crtc_state *crtc_state,
                             const struct intel_plane_state *plane_state);
+       void (*update_slave)(struct intel_plane *plane,
+                            const struct intel_crtc_state *crtc_state,
+                            const struct intel_plane_state *plane_state);
        void (*disable_plane)(struct intel_plane *plane,
-                             struct intel_crtc *crtc);
+                             const struct intel_crtc_state *crtc_state);
        bool (*get_hw_state)(struct intel_plane *plane, enum pipe *pipe);
        int (*check_plane)(struct intel_crtc_state *crtc_state,
                           struct intel_plane_state *plane_state);
@@ -1071,13 +1126,13 @@ struct intel_dp {
        bool link_mst;
        bool link_trained;
        bool has_audio;
-       bool detect_done;
        bool reset_link_params;
-       enum aux_ch aux_ch;
        uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
        uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
        uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
        uint8_t edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
+       u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
+       u8 fec_capable;
        /* source rates */
        int num_source_rates;
        const int *source_rates;
@@ -1095,7 +1150,6 @@ struct intel_dp {
        /* sink or branch descriptor */
        struct drm_dp_desc desc;
        struct drm_dp_aux aux;
-       enum intel_display_power_domain aux_power_domain;
        uint8_t train_set[4];
        int panel_power_up_delay;
        int panel_power_down_delay;
@@ -1157,9 +1211,15 @@ struct intel_dp {
        struct intel_dp_compliance compliance;
 };
 
+enum lspcon_vendor {
+       LSPCON_VENDOR_MCA,
+       LSPCON_VENDOR_PARADE
+};
+
 struct intel_lspcon {
        bool active;
        enum drm_lspcon_mode mode;
+       enum lspcon_vendor vendor;
 };
 
 struct intel_digital_port {
@@ -1171,18 +1231,20 @@ struct intel_digital_port {
        enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
        bool release_cl2_override;
        uint8_t max_lanes;
+       /* Used for DP and ICL+ TypeC/DP and TypeC/HDMI ports. */
+       enum aux_ch aux_ch;
        enum intel_display_power_domain ddi_io_power_domain;
        enum tc_port_type tc_type;
 
-       void (*write_infoframe)(struct drm_encoder *encoder,
+       void (*write_infoframe)(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len);
-       void (*set_infoframes)(struct drm_encoder *encoder,
+       void (*set_infoframes)(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state);
-       bool (*infoframe_enabled)(struct drm_encoder *encoder,
+       bool (*infoframe_enabled)(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config);
 };
 
@@ -1282,6 +1344,12 @@ enc_to_dig_port(struct drm_encoder *encoder)
                return NULL;
 }
 
+static inline struct intel_digital_port *
+conn_to_dig_port(struct intel_connector *connector)
+{
+       return enc_to_dig_port(&intel_attached_encoder(&connector->base)->base);
+}
+
 static inline struct intel_dp_mst_encoder *
 enc_to_mst(struct drm_encoder *encoder)
 {
@@ -1307,6 +1375,12 @@ static inline bool intel_encoder_is_dp(struct intel_encoder *encoder)
        }
 }
 
+static inline struct intel_lspcon *
+enc_to_intel_lspcon(struct drm_encoder *encoder)
+{
+       return &enc_to_dig_port(encoder)->lspcon;
+}
+
 static inline struct intel_digital_port *
 dp_to_dig_port(struct intel_dp *intel_dp)
 {
@@ -1331,6 +1405,27 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
        return container_of(intel_hdmi, struct intel_digital_port, hdmi);
 }
 
+static inline struct intel_plane_state *
+intel_atomic_get_plane_state(struct intel_atomic_state *state,
+                                struct intel_plane *plane)
+{
+       struct drm_plane_state *ret =
+               drm_atomic_get_plane_state(&state->base, &plane->base);
+
+       if (IS_ERR(ret))
+               return ERR_CAST(ret);
+
+       return to_intel_plane_state(ret);
+}
+
+static inline struct intel_plane_state *
+intel_atomic_get_old_plane_state(struct intel_atomic_state *state,
+                                struct intel_plane *plane)
+{
+       return to_intel_plane_state(drm_atomic_get_old_plane_state(&state->base,
+                                                                  &plane->base));
+}
+
 static inline struct intel_plane_state *
 intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
                                 struct intel_plane *plane)
@@ -1439,12 +1534,9 @@ u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder,
                                 u8 voltage_swing);
 int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
                                     bool enable);
-void icl_map_plls_to_ports(struct drm_crtc *crtc,
-                          struct intel_crtc_state *crtc_state,
-                          struct drm_atomic_state *old_state);
-void icl_unmap_plls_to_ports(struct drm_crtc *crtc,
-                            struct intel_crtc_state *crtc_state,
-                            struct drm_atomic_state *old_state);
+void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
+int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                       enum intel_dpll_id pll_id);
 
 unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
                                   int color_plane, unsigned int height);
@@ -1489,7 +1581,6 @@ void intel_dump_cdclk_state(const struct intel_cdclk_state *cdclk_state,
 void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
 void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
 enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc);
-void intel_update_rawclk(struct drm_i915_private *dev_priv);
 int vlv_get_hpll_vco(struct drm_i915_private *dev_priv);
 int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
                      const char *name, u32 reg, int ref_freq);
@@ -1510,20 +1601,12 @@ void intel_mark_idle(struct drm_i915_private *dev_priv);
 int intel_display_suspend(struct drm_device *dev);
 void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
 void intel_encoder_destroy(struct drm_encoder *encoder);
-int intel_connector_init(struct intel_connector *);
-struct intel_connector *intel_connector_alloc(void);
-void intel_connector_free(struct intel_connector *connector);
-bool intel_connector_get_hw_state(struct intel_connector *connector);
-void intel_connector_attach_encoder(struct intel_connector *connector,
-                                   struct intel_encoder *encoder);
 struct drm_display_mode *
 intel_encoder_current_mode(struct intel_encoder *encoder);
 bool intel_port_is_combophy(struct drm_i915_private *dev_priv, enum port port);
 bool intel_port_is_tc(struct drm_i915_private *dev_priv, enum port port);
 enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv,
                              enum port port);
-
-enum pipe intel_get_pipe_from_connector(struct intel_connector *connector);
 int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv);
 enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
@@ -1629,9 +1712,11 @@ void bxt_enable_dc9(struct drm_i915_private *dev_priv);
 void bxt_disable_dc9(struct drm_i915_private *dev_priv);
 void gen9_enable_dc5(struct drm_i915_private *dev_priv);
 unsigned int skl_cdclk_get_vco(unsigned int freq);
+void skl_enable_dc6(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
                      struct intel_crtc_state *pipe_config);
-void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n);
+void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state,
+                     enum link_m_n_set m_n);
 int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
 bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock,
                        struct dpll *best_clock);
@@ -1642,6 +1727,8 @@ bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state);
 void hsw_enable_ips(const struct intel_crtc_state *crtc_state);
 void hsw_disable_ips(const struct intel_crtc_state *crtc_state);
 enum intel_display_power_domain intel_port_to_power_domain(enum port port);
+enum intel_display_power_domain
+intel_aux_power_domain(struct intel_digital_port *dig_port);
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
                                 struct intel_crtc_state *pipe_config);
 void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
@@ -1671,6 +1758,24 @@ unsigned int i9xx_plane_max_stride(struct intel_plane *plane,
                                   u32 pixel_format, u64 modifier,
                                   unsigned int rotation);
 
+/* intel_connector.c */
+int intel_connector_init(struct intel_connector *connector);
+struct intel_connector *intel_connector_alloc(void);
+void intel_connector_free(struct intel_connector *connector);
+void intel_connector_destroy(struct drm_connector *connector);
+int intel_connector_register(struct drm_connector *connector);
+void intel_connector_unregister(struct drm_connector *connector);
+void intel_connector_attach_encoder(struct intel_connector *connector,
+                                   struct intel_encoder *encoder);
+bool intel_connector_get_hw_state(struct intel_connector *connector);
+enum pipe intel_connector_get_pipe(struct intel_connector *connector);
+int intel_connector_update_modes(struct drm_connector *connector,
+                                struct edid *edid);
+int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
+void intel_attach_force_audio_property(struct drm_connector *connector);
+void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
+void intel_attach_aspect_ratio_property(struct drm_connector *connector);
+
 /* intel_csr.c */
 void intel_csr_ucode_init(struct drm_i915_private *);
 void intel_csr_load_program(struct drm_i915_private *);
@@ -1696,6 +1801,9 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 int intel_dp_retrain_link(struct intel_encoder *encoder,
                          struct drm_modeset_acquire_ctx *ctx);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
+                                          const struct intel_crtc_state *crtc_state,
+                                          bool enable);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
 void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
@@ -1729,9 +1837,6 @@ void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
                               unsigned int frontbuffer_bits);
 void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
                          unsigned int frontbuffer_bits);
-void icl_program_mg_dp_mode(struct intel_dp *intel_dp);
-void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port);
-void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port);
 
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
@@ -1749,6 +1854,16 @@ bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
 bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
 bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
+uint16_t intel_dp_dsc_get_output_bpp(int link_clock, uint8_t lane_count,
+                                    int mode_clock, int mode_hdisplay);
+uint8_t intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, int mode_clock,
+                                    int mode_hdisplay);
+
+/* intel_vdsc.c */
+int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config);
+enum intel_display_power_domain
+intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
 
 static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
 {
@@ -1769,6 +1884,9 @@ void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
 /* vlv_dsi.c */
 void vlv_dsi_init(struct drm_i915_private *dev_priv);
 
+/* icl_dsi.c */
+void icl_dsi_init(struct drm_i915_private *dev_priv);
+
 /* intel_dsi_dcs_backlight.c */
 int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
 
@@ -1859,7 +1977,6 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
 void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
 void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
 
-
 /* intel_lvds.c */
 bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
                             i915_reg_t lvds_reg, enum pipe *pipe);
@@ -1867,19 +1984,9 @@ void intel_lvds_init(struct drm_i915_private *dev_priv);
 struct intel_encoder *intel_get_lvds_encoder(struct drm_device *dev);
 bool intel_is_dual_link_lvds(struct drm_device *dev);
 
-
-/* intel_modes.c */
-int intel_connector_update_modes(struct drm_connector *connector,
-                                struct edid *edid);
-int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-void intel_attach_force_audio_property(struct drm_connector *connector);
-void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
-void intel_attach_aspect_ratio_property(struct drm_connector *connector);
-
-
 /* intel_overlay.c */
-void intel_setup_overlay(struct drm_i915_private *dev_priv);
-void intel_cleanup_overlay(struct drm_i915_private *dev_priv);
+void intel_overlay_setup(struct drm_i915_private *dev_priv);
+void intel_overlay_cleanup(struct drm_i915_private *dev_priv);
 int intel_overlay_switch_off(struct intel_overlay *overlay);
 int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv);
@@ -1908,7 +2015,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector,
 void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
                                  const struct drm_connector_state *conn_state);
 void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state);
-void intel_panel_destroy_backlight(struct drm_connector *connector);
 extern struct drm_display_mode *intel_find_panel_downclock(
                                struct drm_i915_private *dev_priv,
                                struct drm_display_mode *fixed_mode,
@@ -1937,6 +2043,7 @@ int intel_hdcp_enable(struct intel_connector *connector);
 int intel_hdcp_disable(struct intel_connector *connector);
 int intel_hdcp_check_link(struct intel_connector *connector);
 bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
+bool intel_hdcp_capable(struct intel_connector *connector);
 
 /* intel_psr.c */
 #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
@@ -1962,12 +2069,18 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir);
 void intel_psr_short_pulse(struct intel_dp *intel_dp);
 int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state,
                            u32 *out_value);
+bool intel_psr_enabled(struct intel_dp *intel_dp);
+
+/* intel_quirks.c */
+void intel_init_quirks(struct drm_i915_private *dev_priv);
 
 /* intel_runtime_pm.c */
 int intel_power_domains_init(struct drm_i915_private *);
 void intel_power_domains_cleanup(struct drm_i915_private *dev_priv);
 void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
 void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv);
+void icl_display_core_init(struct drm_i915_private *dev_priv, bool resume);
+void icl_display_core_uninit(struct drm_i915_private *dev_priv);
 void intel_power_domains_enable(struct drm_i915_private *dev_priv);
 void intel_power_domains_disable(struct drm_i915_private *dev_priv);
 
@@ -2091,6 +2204,9 @@ void g4x_wm_get_hw_state(struct drm_device *dev);
 void vlv_wm_get_hw_state(struct drm_device *dev);
 void ilk_wm_get_hw_state(struct drm_device *dev);
 void skl_wm_get_hw_state(struct drm_device *dev);
+void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
+                              struct skl_ddb_entry *ddb_y,
+                              struct skl_ddb_entry *ddb_uv);
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
                          struct skl_ddb_allocation *ddb /* out */);
 void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc,
@@ -2102,10 +2218,13 @@ int intel_enable_sagv(struct drm_i915_private *dev_priv);
 int intel_disable_sagv(struct drm_i915_private *dev_priv);
 bool skl_wm_level_equals(const struct skl_wm_level *l1,
                         const struct skl_wm_level *l2);
-bool skl_ddb_allocation_overlaps(struct drm_i915_private *dev_priv,
-                                const struct skl_ddb_entry **entries,
-                                const struct skl_ddb_entry *ddb,
-                                int ignore);
+bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
+                                const struct skl_ddb_entry entries[],
+                                int num_entries, int ignore_idx);
+void skl_write_plane_wm(struct intel_plane *plane,
+                       const struct intel_crtc_state *crtc_state);
+void skl_write_cursor_wm(struct intel_plane *plane,
+                        const struct intel_crtc_state *crtc_state);
 bool ilk_disable_lp_wm(struct drm_device *dev);
 int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
                                  struct intel_crtc_state *cstate);
@@ -2128,23 +2247,29 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
                                    struct drm_file *file_priv);
 void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state);
 void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state);
-void skl_update_plane(struct intel_plane *plane,
-                     const struct intel_crtc_state *crtc_state,
-                     const struct intel_plane_state *plane_state);
-void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc);
-bool skl_plane_get_hw_state(struct intel_plane *plane, enum pipe *pipe);
-bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
-                      enum pipe pipe, enum plane_id plane_id);
-bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
-                         enum pipe pipe, enum plane_id plane_id);
-unsigned int skl_plane_max_stride(struct intel_plane *plane,
-                                 u32 pixel_format, u64 modifier,
-                                 unsigned int rotation);
-int skl_plane_check(struct intel_crtc_state *crtc_state,
-                   struct intel_plane_state *plane_state);
 int intel_plane_check_stride(const struct intel_plane_state *plane_state);
 int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);
 int chv_plane_check_rotation(const struct intel_plane_state *plane_state);
+struct intel_plane *
+skl_universal_plane_create(struct drm_i915_private *dev_priv,
+                          enum pipe pipe, enum plane_id plane_id);
+
+static inline bool icl_is_nv12_y_plane(enum plane_id id)
+{
+       /* Don't need to do a gen check, these planes are only available on gen11 */
+       if (id == PLANE_SPRITE4 || id == PLANE_SPRITE5)
+               return true;
+
+       return false;
+}
+
+static inline bool icl_is_hdr_plane(struct intel_plane *plane)
+{
+       if (INTEL_GEN(to_i915(plane->base.dev)) < 11)
+               return false;
+
+       return plane->id < PLANE_SPRITE2;
+}
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_i915_private *dev_priv);
@@ -2186,11 +2311,16 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
                               struct intel_crtc_state *crtc_state);
 
 /* intel_atomic_plane.c */
-struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
+struct intel_plane *intel_plane_alloc(void);
+void intel_plane_free(struct intel_plane *plane);
 struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
 void intel_plane_destroy_state(struct drm_plane *plane,
                               struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
+void skl_update_planes_on_crtc(struct intel_atomic_state *state,
+                              struct intel_crtc *crtc);
+void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
+                               struct intel_crtc *crtc);
 int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
                                        struct intel_crtc_state *crtc_state,
                                        const struct intel_plane_state *old_plane_state,
@@ -2206,6 +2336,18 @@ void intel_color_load_luts(struct drm_crtc_state *crtc_state);
 bool lspcon_init(struct intel_digital_port *intel_dig_port);
 void lspcon_resume(struct intel_lspcon *lspcon);
 void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *buf, ssize_t len);
+void lspcon_set_infoframes(struct intel_encoder *encoder,
+                          bool enable,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state);
+bool lspcon_infoframe_enabled(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config);
+void lspcon_ycbcr420_config(struct drm_connector *connector,
+                           struct intel_crtc_state *crtc_state);
 
 /* intel_pipe_crc.c */
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
new file mode 100644 (file)
index 0000000..5fec02a
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include "intel_dsi.h"
+
+int intel_dsi_bitrate(const struct intel_dsi *intel_dsi)
+{
+       int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+
+       if (WARN_ON(bpp < 0))
+               bpp = 16;
+
+       return intel_dsi->pclk * bpp / intel_dsi->lane_count;
+}
+
+int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi)
+{
+       switch (intel_dsi->escape_clk_div) {
+       default:
+       case 0:
+               return 50;
+       case 1:
+               return 100;
+       case 2:
+               return 200;
+       }
+}
+
+int intel_dsi_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_display_mode *mode;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (!intel_connector->panel.fixed_mode) {
+               DRM_DEBUG_KMS("no fixed mode\n");
+               return 0;
+       }
+
+       mode = drm_mode_duplicate(connector->dev,
+                                 intel_connector->panel.fixed_mode);
+       if (!mode) {
+               DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
+               return 0;
+       }
+
+       drm_mode_probed_add(connector, mode);
+       return 1;
+}
+
+enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
+                                         struct drm_display_mode *mode)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+               if (fixed_mode->clock > max_dotclk)
+                       return MODE_CLOCK_HIGH;
+       }
+
+       return MODE_OK;
+}
+
+struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+                                          const struct mipi_dsi_host_ops *funcs,
+                                          enum port port)
+{
+       struct intel_dsi_host *host;
+       struct mipi_dsi_device *device;
+
+       host = kzalloc(sizeof(*host), GFP_KERNEL);
+       if (!host)
+               return NULL;
+
+       host->base.ops = funcs;
+       host->intel_dsi = intel_dsi;
+       host->port = port;
+
+       /*
+        * We should call mipi_dsi_host_register(&host->base) here, but we don't
+        * have a host->dev, and we don't have OF stuff either. So just use the
+        * dsi framework as a library and hope for the best. Create the dsi
+        * devices by ourselves here too. Need to be careful though, because we
+        * don't initialize any of the driver model devices here.
+        */
+       device = kzalloc(sizeof(*device), GFP_KERNEL);
+       if (!device) {
+               kfree(host);
+               return NULL;
+       }
+
+       device->host = &host->base;
+       host->device = device;
+
+       return host;
+}
+
+enum drm_panel_orientation
+intel_dsi_get_panel_orientation(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum drm_panel_orientation orientation;
+
+       orientation = dev_priv->vbt.dsi.orientation;
+       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               return orientation;
+
+       orientation = dev_priv->vbt.orientation;
+       if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               return orientation;
+
+       return DRM_MODE_PANEL_ORIENTATION_NORMAL;
+}
index ad7c1cb329836510d7263988a258a8be7f6e9623..d968f1f13e0923b7793d5ed944bc9a1fc5049c23 100644 (file)
@@ -81,14 +81,21 @@ struct intel_dsi {
        u16 dcs_backlight_ports;
        u16 dcs_cabc_ports;
 
+       /* RGB or BGR */
+       bool bgr_enabled;
+
        u8 pixel_overlap;
        u32 port_bits;
        u32 bw_timer;
        u32 dphy_reg;
+
+       /* data lanes dphy timing */
+       u32 dphy_data_lane_reg;
        u32 video_frmt_cfg_bits;
        u16 lp_byte_clk;
 
        /* timeouts in byte clocks */
+       u16 hs_tx_timeout;
        u16 lp_rx_timeout;
        u16 turn_arnd_val;
        u16 rst_timer_val;
@@ -129,9 +136,36 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
        return container_of(encoder, struct intel_dsi, base.base);
 }
 
+static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
+{
+       return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
+}
+
+static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
+{
+       return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE;
+}
+
+static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder)
+{
+       return enc_to_intel_dsi(&encoder->base)->ports;
+}
+
+/* intel_dsi.c */
+int intel_dsi_bitrate(const struct intel_dsi *intel_dsi);
+int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi);
+enum drm_panel_orientation
+intel_dsi_get_panel_orientation(struct intel_connector *connector);
+
 /* vlv_dsi.c */
 void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
 enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
+int intel_dsi_get_modes(struct drm_connector *connector);
+enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector,
+                                         struct drm_display_mode *mode);
+struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+                                          const struct mipi_dsi_host_ops *funcs,
+                                          enum port port);
 
 /* vlv_dsi_pll.c */
 int vlv_dsi_pll_compute(struct intel_encoder *encoder,
@@ -158,5 +192,6 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id);
 int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi);
 void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
                                 enum mipi_seq seq_id);
+void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec);
 
 #endif /* _INTEL_DSI_H */
index ac83d6b89ae0c36c236ffc5bd155d86f045f7526..a1a8b3790e616261c73383a22a1a08724f1d6f64 100644 (file)
@@ -103,6 +103,18 @@ static struct gpio_map vlv_gpio_table[] = {
 #define CHV_GPIO_PAD_CFG1(f, i)                (0x4400 + (f) * 0x400 + (i) * 8 + 4)
 #define  CHV_GPIO_CFGLOCK              (1 << 31)
 
+/* ICL DSI Display GPIO Pins */
+#define  ICL_GPIO_DDSP_HPD_A           0
+#define  ICL_GPIO_L_VDDEN_1            1
+#define  ICL_GPIO_L_BKLTEN_1           2
+#define  ICL_GPIO_DDPA_CTRLCLK_1       3
+#define  ICL_GPIO_DDPA_CTRLDATA_1      4
+#define  ICL_GPIO_DDSP_HPD_B           5
+#define  ICL_GPIO_L_VDDEN_2            6
+#define  ICL_GPIO_L_BKLTEN_2           7
+#define  ICL_GPIO_DDPA_CTRLCLK_2       8
+#define  ICL_GPIO_DDPA_CTRLDATA_2      9
+
 static inline enum port intel_dsi_seq_port_to_port(u8 port)
 {
        return port ? PORT_C : PORT_A;
@@ -111,6 +123,7 @@ static inline enum port intel_dsi_seq_port_to_port(u8 port)
 static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
                                       const u8 *data)
 {
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
        struct mipi_dsi_device *dsi_device;
        u8 type, flags, seq_port;
        u16 len;
@@ -181,7 +194,8 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
                break;
        }
 
-       vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
+       if (!IS_ICELAKE(dev_priv))
+               vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
 
 out:
        data += len;
@@ -322,6 +336,12 @@ static void bxt_exec_gpio(struct drm_i915_private *dev_priv,
        gpiod_set_value(gpio_desc, value);
 }
 
+static void icl_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
+{
+       DRM_DEBUG_KMS("Skipping ICL GPIO element execution\n");
+}
+
 static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
 {
        struct drm_device *dev = intel_dsi->base.base.dev;
@@ -345,7 +365,9 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
        /* pull up/down */
        value = *data++ & 1;
 
-       if (IS_VALLEYVIEW(dev_priv))
+       if (IS_ICELAKE(dev_priv))
+               icl_exec_gpio(dev_priv, gpio_source, gpio_index, value);
+       else if (IS_VALLEYVIEW(dev_priv))
                vlv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
        else if (IS_CHERRYVIEW(dev_priv))
                chv_exec_gpio(dev_priv, gpio_source, gpio_number, value);
@@ -481,6 +503,17 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
        }
 }
 
+void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+
+       /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
+       if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
+               return;
+
+       msleep(msec);
+}
+
 int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi)
 {
        struct intel_connector *connector = intel_dsi->attached_connector;
@@ -499,110 +532,125 @@ int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi)
        return 1;
 }
 
-bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
+#define ICL_PREPARE_CNT_MAX    0x7
+#define ICL_CLK_ZERO_CNT_MAX   0xf
+#define ICL_TRAIL_CNT_MAX      0x7
+#define ICL_TCLK_PRE_CNT_MAX   0x3
+#define ICL_TCLK_POST_CNT_MAX  0x7
+#define ICL_HS_ZERO_CNT_MAX    0xf
+#define ICL_EXIT_ZERO_CNT_MAX  0x7
+
+static void icl_dphy_param_init(struct intel_dsi *intel_dsi)
 {
        struct drm_device *dev = intel_dsi->base.base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
-       struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
-       struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
-       u32 bpp;
-       u32 tlpx_ns, extra_byte_count, bitrate, tlpx_ui;
-       u32 ui_num, ui_den;
+       u32 tlpx_ns;
        u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
        u32 ths_prepare_ns, tclk_trail_ns;
-       u32 tclk_prepare_clkzero, ths_prepare_hszero;
-       u32 lp_to_hs_switch, hs_to_lp_switch;
-       u32 pclk, computed_ddr;
-       u32 mul;
-       u16 burst_mode_ratio;
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
-       intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
-       intel_dsi->lane_count = mipi_config->lane_cnt + 1;
-       intel_dsi->pixel_format =
-                       pixel_format_from_register_bits(
-                               mipi_config->videomode_color_format << 7);
-       bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       u32 hs_zero_cnt;
+       u32 tclk_pre_cnt, tclk_post_cnt;
 
-       intel_dsi->dual_link = mipi_config->dual_link;
-       intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
-       intel_dsi->operation_mode = mipi_config->is_cmd_mode;
-       intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
-       intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
-       intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout;
-       intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout;
-       intel_dsi->rst_timer_val = mipi_config->device_reset_timer;
-       intel_dsi->init_count = mipi_config->master_init_timer;
-       intel_dsi->bw_timer = mipi_config->dbi_bw_timer;
-       intel_dsi->video_frmt_cfg_bits =
-               mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
+       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
 
-       pclk = mode->clock;
+       tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail);
+       ths_prepare_ns = max(mipi_config->ths_prepare,
+                            mipi_config->tclk_prepare);
 
-       /* In dual link mode each port needs half of pixel clock */
-       if (intel_dsi->dual_link) {
-               pclk = pclk / 2;
+       /*
+        * prepare cnt in escape clocks
+        * this field represents a hexadecimal value with a precision
+        * of 1.2 – i.e. the most significant bit is the integer
+        * and the least significant 2 bits are fraction bits.
+        * so, the field can represent a range of 0.25 to 1.75
+        */
+       prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * 4, tlpx_ns);
+       if (prepare_cnt > ICL_PREPARE_CNT_MAX) {
+               DRM_DEBUG_KMS("prepare_cnt out of range (%d)\n", prepare_cnt);
+               prepare_cnt = ICL_PREPARE_CNT_MAX;
+       }
 
-               /* we can enable pixel_overlap if needed by panel. In this
-                * case we need to increase the pixelclock for extra pixels
-                */
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
-                       pclk += DIV_ROUND_UP(mode->vtotal *
-                                               intel_dsi->pixel_overlap *
-                                               60, 1000);
-               }
+       /* clk zero count in escape clocks */
+       clk_zero_cnt = DIV_ROUND_UP(mipi_config->tclk_prepare_clkzero -
+                                   ths_prepare_ns, tlpx_ns);
+       if (clk_zero_cnt > ICL_CLK_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("clk_zero_cnt out of range (%d)\n", clk_zero_cnt);
+               clk_zero_cnt = ICL_CLK_ZERO_CNT_MAX;
        }
 
-       /* Burst Mode Ratio
-        * Target ddr frequency from VBT / non burst ddr freq
-        * multiply by 100 to preserve remainder
-        */
-       if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
-               if (mipi_config->target_burst_mode_freq) {
-                       computed_ddr = (pclk * bpp) / intel_dsi->lane_count;
+       /* trail cnt in escape clocks*/
+       trail_cnt = DIV_ROUND_UP(tclk_trail_ns, tlpx_ns);
+       if (trail_cnt > ICL_TRAIL_CNT_MAX) {
+               DRM_DEBUG_KMS("trail_cnt out of range (%d)\n", trail_cnt);
+               trail_cnt = ICL_TRAIL_CNT_MAX;
+       }
 
-                       if (mipi_config->target_burst_mode_freq <
-                                                               computed_ddr) {
-                               DRM_ERROR("Burst mode freq is less than computed\n");
-                               return false;
-                       }
+       /* tclk pre count in escape clocks */
+       tclk_pre_cnt = DIV_ROUND_UP(mipi_config->tclk_pre, tlpx_ns);
+       if (tclk_pre_cnt > ICL_TCLK_PRE_CNT_MAX) {
+               DRM_DEBUG_KMS("tclk_pre_cnt out of range (%d)\n", tclk_pre_cnt);
+               tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX;
+       }
 
-                       burst_mode_ratio = DIV_ROUND_UP(
-                               mipi_config->target_burst_mode_freq * 100,
-                               computed_ddr);
+       /* tclk post count in escape clocks */
+       tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns);
+       if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) {
+               DRM_DEBUG_KMS("tclk_post_cnt out of range (%d)\n", tclk_post_cnt);
+               tclk_post_cnt = ICL_TCLK_POST_CNT_MAX;
+       }
 
-                       pclk = DIV_ROUND_UP(pclk * burst_mode_ratio, 100);
-               } else {
-                       DRM_ERROR("Burst mode target is not set\n");
-                       return false;
-               }
-       } else
-               burst_mode_ratio = 100;
+       /* hs zero cnt in escape clocks */
+       hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero -
+                                  ths_prepare_ns, tlpx_ns);
+       if (hs_zero_cnt > ICL_HS_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("hs_zero_cnt out of range (%d)\n", hs_zero_cnt);
+               hs_zero_cnt = ICL_HS_ZERO_CNT_MAX;
+       }
 
-       intel_dsi->burst_mode_ratio = burst_mode_ratio;
-       intel_dsi->pclk = pclk;
+       /* hs exit zero cnt in escape clocks */
+       exit_zero_cnt = DIV_ROUND_UP(mipi_config->ths_exit, tlpx_ns);
+       if (exit_zero_cnt > ICL_EXIT_ZERO_CNT_MAX) {
+               DRM_DEBUG_KMS("exit_zero_cnt out of range (%d)\n", exit_zero_cnt);
+               exit_zero_cnt = ICL_EXIT_ZERO_CNT_MAX;
+       }
 
-       bitrate = (pclk * bpp) / intel_dsi->lane_count;
+       /* clock lane dphy timings */
+       intel_dsi->dphy_reg = (CLK_PREPARE_OVERRIDE |
+                              CLK_PREPARE(prepare_cnt) |
+                              CLK_ZERO_OVERRIDE |
+                              CLK_ZERO(clk_zero_cnt) |
+                              CLK_PRE_OVERRIDE |
+                              CLK_PRE(tclk_pre_cnt) |
+                              CLK_POST_OVERRIDE |
+                              CLK_POST(tclk_post_cnt) |
+                              CLK_TRAIL_OVERRIDE |
+                              CLK_TRAIL(trail_cnt));
+
+       /* data lanes dphy timings */
+       intel_dsi->dphy_data_lane_reg = (HS_PREPARE_OVERRIDE |
+                                        HS_PREPARE(prepare_cnt) |
+                                        HS_ZERO_OVERRIDE |
+                                        HS_ZERO(hs_zero_cnt) |
+                                        HS_TRAIL_OVERRIDE |
+                                        HS_TRAIL(trail_cnt) |
+                                        HS_EXIT_OVERRIDE |
+                                        HS_EXIT(exit_zero_cnt));
+}
 
-       switch (intel_dsi->escape_clk_div) {
-       case 0:
-               tlpx_ns = 50;
-               break;
-       case 1:
-               tlpx_ns = 100;
-               break;
+static void vlv_dphy_param_init(struct intel_dsi *intel_dsi)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
+       u32 tlpx_ns, extra_byte_count, tlpx_ui;
+       u32 ui_num, ui_den;
+       u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
+       u32 ths_prepare_ns, tclk_trail_ns;
+       u32 tclk_prepare_clkzero, ths_prepare_hszero;
+       u32 lp_to_hs_switch, hs_to_lp_switch;
+       u32 mul;
 
-       case 2:
-               tlpx_ns = 200;
-               break;
-       default:
-               tlpx_ns = 50;
-               break;
-       }
+       tlpx_ns = intel_dsi_tlpx_ns(intel_dsi);
 
        switch (intel_dsi->lane_count) {
        case 1:
@@ -620,7 +668,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
 
        /* in Kbps */
        ui_num = NS_KHZ_RATIO;
-       ui_den = bitrate;
+       ui_den = intel_dsi_bitrate(intel_dsi);
 
        tclk_prepare_clkzero = mipi_config->tclk_prepare_clkzero;
        ths_prepare_hszero = mipi_config->ths_prepare_hszero;
@@ -746,6 +794,88 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
                DIV_ROUND_UP(2 * tlpx_ui + trail_cnt * 2 + 8,
                        8);
        intel_dsi->clk_hs_to_lp_count += extra_byte_count;
+}
+
+bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
+       struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
+       struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
+       u16 burst_mode_ratio;
+       enum port port;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
+       intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
+       intel_dsi->lane_count = mipi_config->lane_cnt + 1;
+       intel_dsi->pixel_format =
+                       pixel_format_from_register_bits(
+                               mipi_config->videomode_color_format << 7);
+
+       intel_dsi->dual_link = mipi_config->dual_link;
+       intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
+       intel_dsi->operation_mode = mipi_config->is_cmd_mode;
+       intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
+       intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
+       intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout;
+       intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout;
+       intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout;
+       intel_dsi->rst_timer_val = mipi_config->device_reset_timer;
+       intel_dsi->init_count = mipi_config->master_init_timer;
+       intel_dsi->bw_timer = mipi_config->dbi_bw_timer;
+       intel_dsi->video_frmt_cfg_bits =
+               mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
+       intel_dsi->bgr_enabled = mipi_config->rgb_flip;
+
+       /* Starting point, adjusted depending on dual link and burst mode */
+       intel_dsi->pclk = mode->clock;
+
+       /* In dual link mode each port needs half of pixel clock */
+       if (intel_dsi->dual_link) {
+               intel_dsi->pclk /= 2;
+
+               /* we can enable pixel_overlap if needed by panel. In this
+                * case we need to increase the pixelclock for extra pixels
+                */
+               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+                       intel_dsi->pclk += DIV_ROUND_UP(mode->vtotal * intel_dsi->pixel_overlap * 60, 1000);
+               }
+       }
+
+       /* Burst Mode Ratio
+        * Target ddr frequency from VBT / non burst ddr freq
+        * multiply by 100 to preserve remainder
+        */
+       if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+               if (mipi_config->target_burst_mode_freq) {
+                       u32 bitrate = intel_dsi_bitrate(intel_dsi);
+
+                       if (mipi_config->target_burst_mode_freq < bitrate) {
+                               DRM_ERROR("Burst mode freq is less than computed\n");
+                               return false;
+                       }
+
+                       burst_mode_ratio = DIV_ROUND_UP(
+                               mipi_config->target_burst_mode_freq * 100,
+                               bitrate);
+
+                       intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100);
+               } else {
+                       DRM_ERROR("Burst mode target is not set\n");
+                       return false;
+               }
+       } else
+               burst_mode_ratio = 100;
+
+       intel_dsi->burst_mode_ratio = burst_mode_ratio;
+
+       if (IS_ICELAKE(dev_priv))
+               icl_dphy_param_init(intel_dsi);
+       else
+               vlv_dphy_param_init(intel_dsi);
 
        DRM_DEBUG_KMS("Pclk %d\n", intel_dsi->pclk);
        DRM_DEBUG_KMS("Pixel overlap %d\n", intel_dsi->pixel_overlap);
index 4e142ff49708537b33b113f34248b0c213f1ab5e..0042a7f69387780f6f1d5c105ca9cae43d41713d 100644 (file)
@@ -256,6 +256,7 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        return true;
 }
 
@@ -333,18 +334,11 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
        return 0;
 }
 
-static void intel_dvo_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-       intel_panel_fini(&to_intel_connector(connector)->panel);
-       kfree(connector);
-}
-
 static const struct drm_connector_funcs intel_dvo_connector_funcs = {
        .detect = intel_dvo_detect,
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_dvo_destroy,
+       .destroy = intel_connector_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
index 76b5f94ea6cb62a38c42bec9d4da03c638489480..af2873403009103730ac07d95556c3d9a04ee517 100644 (file)
@@ -273,13 +273,13 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
        BUILD_BUG_ON(MAX_ENGINE_CLASS >= BIT(GEN11_ENGINE_CLASS_WIDTH));
        BUILD_BUG_ON(MAX_ENGINE_INSTANCE >= BIT(GEN11_ENGINE_INSTANCE_WIDTH));
 
-       if (GEM_WARN_ON(info->class > MAX_ENGINE_CLASS))
+       if (GEM_DEBUG_WARN_ON(info->class > MAX_ENGINE_CLASS))
                return -EINVAL;
 
-       if (GEM_WARN_ON(info->instance > MAX_ENGINE_INSTANCE))
+       if (GEM_DEBUG_WARN_ON(info->instance > MAX_ENGINE_INSTANCE))
                return -EINVAL;
 
-       if (GEM_WARN_ON(dev_priv->engine_class[info->class][info->instance]))
+       if (GEM_DEBUG_WARN_ON(dev_priv->engine_class[info->class][info->instance]))
                return -EINVAL;
 
        GEM_BUG_ON(dev_priv->engine[id]);
@@ -335,7 +335,10 @@ int intel_engines_init_mmio(struct drm_i915_private *dev_priv)
 
        WARN_ON(ring_mask == 0);
        WARN_ON(ring_mask &
-               GENMASK(sizeof(mask) * BITS_PER_BYTE - 1, I915_NUM_ENGINES));
+               GENMASK(BITS_PER_TYPE(mask) - 1, I915_NUM_ENGINES));
+
+       if (i915_inject_load_failure())
+               return -ENODEV;
 
        for (i = 0; i < ARRAY_SIZE(intel_engines); i++) {
                if (!HAS_ENGINE(dev_priv, i))
@@ -399,7 +402,7 @@ int intel_engines_init(struct drm_i915_private *dev_priv)
                err = -EINVAL;
                err_id = id;
 
-               if (GEM_WARN_ON(!init))
+               if (GEM_DEBUG_WARN_ON(!init))
                        goto cleanup;
 
                err = init(engine);
@@ -463,7 +466,7 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine)
        struct intel_engine_execlists * const execlists = &engine->execlists;
 
        execlists->port_mask = 1;
-       BUILD_BUG_ON_NOT_POWER_OF_2(execlists_num_ports(execlists));
+       GEM_BUG_ON(!is_power_of_2(execlists_num_ports(execlists)));
        GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS);
 
        execlists->queue_priority = INT_MIN;
@@ -482,7 +485,7 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine)
 void intel_engine_setup_common(struct intel_engine_cs *engine)
 {
        i915_timeline_init(engine->i915, &engine->timeline, engine->name);
-       lockdep_set_subclass(&engine->timeline.lock, TIMELINE_ENGINE);
+       i915_timeline_set_subclass(&engine->timeline, TIMELINE_ENGINE);
 
        intel_engine_init_execlist(engine);
        intel_engine_init_hangcheck(engine);
@@ -679,7 +682,9 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 
        i915_timeline_fini(&engine->timeline);
 
+       intel_wa_list_free(&engine->ctx_wa_list);
        intel_wa_list_free(&engine->wa_list);
+       intel_wa_list_free(&engine->whitelist);
 }
 
 u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
@@ -769,7 +774,7 @@ u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv)
        u32 slice = fls(sseu->slice_mask);
        u32 subslice = fls(sseu->subslice_mask[slice]);
 
-       if (INTEL_GEN(dev_priv) == 10)
+       if (IS_GEN10(dev_priv))
                mcr_s_ss_select = GEN8_MCR_SLICE(slice) |
                                  GEN8_MCR_SUBSLICE(subslice);
        else if (INTEL_GEN(dev_priv) >= 11)
@@ -1494,10 +1499,10 @@ void intel_engine_dump(struct intel_engine_cs *engine,
        count = 0;
        drm_printf(m, "\t\tQueue priority: %d\n", execlists->queue_priority);
        for (rb = rb_first_cached(&execlists->queue); rb; rb = rb_next(rb)) {
-               struct i915_priolist *p =
-                       rb_entry(rb, typeof(*p), node);
+               struct i915_priolist *p = rb_entry(rb, typeof(*p), node);
+               int i;
 
-               list_for_each_entry(rq, &p->requests, sched.link) {
+               priolist_for_each_request(rq, p, i) {
                        if (count++ < MAX_REQUESTS_TO_SHOW - 1)
                                print_request(m, rq, "\t\tQ ");
                        else
@@ -1519,8 +1524,10 @@ void intel_engine_dump(struct intel_engine_cs *engine,
        for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
                struct intel_wait *w = rb_entry(rb, typeof(*w), node);
 
-               drm_printf(m, "\t%s [%d] waiting for %x\n",
-                          w->tsk->comm, w->tsk->pid, w->seqno);
+               drm_printf(m, "\t%s [%d:%c] waiting for %x\n",
+                          w->tsk->comm, w->tsk->pid,
+                          task_state_to_char(w->tsk),
+                          w->seqno);
        }
        spin_unlock(&b->rb_lock);
        local_irq_restore(flags);
index 74d425c700ef092e9012042605d142282f0685c7..f23570c44323b1ad324654fce53d3802de464ffc 100644 (file)
@@ -84,7 +84,7 @@ static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv,
        int lines;
 
        intel_fbc_get_plane_source_size(cache, NULL, &lines);
-       if (INTEL_GEN(dev_priv) == 7)
+       if (IS_GEN7(dev_priv))
                lines = min(lines, 2048);
        else if (INTEL_GEN(dev_priv) >= 8)
                lines = min(lines, 2560);
@@ -674,6 +674,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
        cache->plane.adjusted_y = plane_state->color_plane[0].y;
        cache->plane.y = plane_state->base.src.y1 >> 16;
 
+       cache->plane.pixel_blend_mode = plane_state->base.pixel_blend_mode;
+
        if (!cache->plane.visible)
                return;
 
@@ -748,6 +750,12 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
                return false;
        }
 
+       if (cache->plane.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE &&
+           cache->fb.format->has_alpha) {
+               fbc->no_fbc_reason = "per-pixel alpha blending is incompatible with FBC";
+               return false;
+       }
+
        /* WaFbcExceedCdClockThreshold:hsw,bdw */
        if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
            cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk.hw.cdclk * 95 / 100) {
@@ -1301,7 +1309,7 @@ void intel_fbc_init(struct drm_i915_private *dev_priv)
        fbc->active = false;
 
        if (need_fbc_vtd_wa(dev_priv))
-               mkwrite_device_info(dev_priv)->has_fbc = false;
+               mkwrite_device_info(dev_priv)->display.has_fbc = false;
 
        i915_modparams.enable_fbc = intel_sanitize_fbc_option(dev_priv);
        DRM_DEBUG_KMS("Sanitized enable_fbc value: %d\n",
index f99332972b7ab5f0e947af3d8f7fb4eb6294f26b..fb5bb5b32a6034d152516ae11c15913e2f97597d 100644 (file)
@@ -593,7 +593,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
                 * pipe.  Note we need to use the selected fb's pitch and bpp
                 * rather than the current pipe's, since they differ.
                 */
-               cur_size = intel_crtc->config->base.adjusted_mode.crtc_hdisplay;
+               cur_size = crtc->state->adjusted_mode.crtc_hdisplay;
                cur_size = cur_size * fb->base.format->cpp[0];
                if (fb->base.pitches[0] < cur_size) {
                        DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
@@ -603,13 +603,13 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
                        break;
                }
 
-               cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
+               cur_size = crtc->state->adjusted_mode.crtc_vdisplay;
                cur_size = intel_fb_align_height(&fb->base, 0, cur_size);
                cur_size *= fb->base.pitches[0];
                DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
                              pipe_name(intel_crtc->pipe),
-                             intel_crtc->config->base.adjusted_mode.crtc_hdisplay,
-                             intel_crtc->config->base.adjusted_mode.crtc_vdisplay,
+                             crtc->state->adjusted_mode.crtc_hdisplay,
+                             crtc->state->adjusted_mode.crtc_vdisplay,
                              fb->base.format->cpp[0] * 8,
                              cur_size);
 
@@ -672,7 +672,7 @@ int intel_fbdev_init(struct drm_device *dev)
        struct intel_fbdev *ifbdev;
        int ret;
 
-       if (WARN_ON(INTEL_INFO(dev_priv)->num_pipes == 0))
+       if (WARN_ON(!HAS_DISPLAY(dev_priv)))
                return -ENODEV;
 
        ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
index 230aea69385d4fb5e682d7991e5bc252a7012b6d..8660af3fd75566468651d03dd1eecca4429abbe1 100644 (file)
@@ -50,7 +50,8 @@ void intel_guc_init_send_regs(struct intel_guc *guc)
        unsigned int i;
 
        guc->send_regs.base = i915_mmio_reg_offset(SOFT_SCRATCH(0));
-       guc->send_regs.count = SOFT_SCRATCH_COUNT - 1;
+       guc->send_regs.count = GUC_MAX_MMIO_MSG_LEN;
+       BUILD_BUG_ON(GUC_MAX_MMIO_MSG_LEN > SOFT_SCRATCH_COUNT);
 
        for (i = 0; i < guc->send_regs.count; i++) {
                fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
@@ -521,6 +522,44 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset)
        return intel_guc_send(guc, action, ARRAY_SIZE(action));
 }
 
+/*
+ * The ENTER/EXIT_S_STATE actions queue the save/restore operation in GuC FW and
+ * then return, so waiting on the H2G is not enough to guarantee GuC is done.
+ * When all the processing is done, GuC writes INTEL_GUC_SLEEP_STATE_SUCCESS to
+ * scratch register 14, so we can poll on that. Note that GuC does not ensure
+ * that the value in the register is different from
+ * INTEL_GUC_SLEEP_STATE_SUCCESS while the action is in progress so we need to
+ * take care of that ourselves as well.
+ */
+static int guc_sleep_state_action(struct intel_guc *guc,
+                                 const u32 *action, u32 len)
+{
+       struct drm_i915_private *dev_priv = guc_to_i915(guc);
+       int ret;
+       u32 status;
+
+       I915_WRITE(SOFT_SCRATCH(14), INTEL_GUC_SLEEP_STATE_INVALID_MASK);
+
+       ret = intel_guc_send(guc, action, len);
+       if (ret)
+               return ret;
+
+       ret = __intel_wait_for_register(dev_priv, SOFT_SCRATCH(14),
+                                       INTEL_GUC_SLEEP_STATE_INVALID_MASK,
+                                       0, 0, 10, &status);
+       if (ret)
+               return ret;
+
+       if (status != INTEL_GUC_SLEEP_STATE_SUCCESS) {
+               DRM_ERROR("GuC failed to change sleep state. "
+                         "action=0x%x, err=%u\n",
+                         action[0], status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 /**
  * intel_guc_suspend() - notify GuC entering suspend state
  * @guc:       the guc
@@ -533,7 +572,7 @@ int intel_guc_suspend(struct intel_guc *guc)
                intel_guc_ggtt_offset(guc, guc->shared_data)
        };
 
-       return intel_guc_send(guc, data, ARRAY_SIZE(data));
+       return guc_sleep_state_action(guc, data, ARRAY_SIZE(data));
 }
 
 /**
@@ -571,7 +610,7 @@ int intel_guc_resume(struct intel_guc *guc)
                intel_guc_ggtt_offset(guc, guc->shared_data)
        };
 
-       return intel_guc_send(guc, data, ARRAY_SIZE(data));
+       return guc_sleep_state_action(guc, data, ARRAY_SIZE(data));
 }
 
 /**
index ad42faf48c46a3f3773ce6eae1c9702b8379c041..0f1c4f9ebfd886581ac11beefb477ee047e0ab55 100644 (file)
@@ -95,6 +95,11 @@ struct intel_guc {
        void (*notify)(struct intel_guc *guc);
 };
 
+static inline bool intel_guc_is_alive(struct intel_guc *guc)
+{
+       return intel_uc_fw_is_loaded(&guc->fw);
+}
+
 static
 inline int intel_guc_send(struct intel_guc *guc, const u32 *action, u32 len)
 {
index a9e6fcce467c62a7e9b0e3035a181bbe46cd007f..a67144ee5ceb6c93a30f8a48f9d5314166e7cb94 100644 (file)
@@ -78,7 +78,8 @@ static void guc_fw_select(struct intel_uc_fw *guc_fw)
                guc_fw->major_ver_wanted = KBL_FW_MAJOR;
                guc_fw->minor_ver_wanted = KBL_FW_MINOR;
        } else {
-               DRM_WARN("%s: No firmware known for this platform!\n",
+               dev_info(dev_priv->drm.dev,
+                        "%s: No firmware known for this platform!\n",
                         intel_uc_fw_type_repr(guc_fw->type));
        }
 }
@@ -125,66 +126,26 @@ static void guc_prepare_xfer(struct intel_guc *guc)
 }
 
 /* Copy RSA signature from the fw image to HW for verification */
-static int guc_xfer_rsa(struct intel_guc *guc, struct i915_vma *vma)
+static void guc_xfer_rsa(struct intel_guc *guc, struct i915_vma *vma)
 {
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       struct intel_uc_fw *guc_fw = &guc->fw;
-       struct sg_table *sg = vma->pages;
        u32 rsa[UOS_RSA_SCRATCH_COUNT];
        int i;
 
-       if (sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa),
-                              guc_fw->rsa_offset) != sizeof(rsa))
-               return -EINVAL;
+       sg_pcopy_to_buffer(vma->pages->sgl, vma->pages->nents,
+                          rsa, sizeof(rsa), guc->fw.rsa_offset);
 
        for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++)
                I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
-
-       return 0;
 }
 
-/*
- * Transfer the firmware image to RAM for execution by the microcontroller.
- *
- * Architecturally, the DMA engine is bidirectional, and can potentially even
- * transfer between GTT locations. This functionality is left out of the API
- * for now as there is no need for it.
- */
-static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma)
+static bool guc_xfer_completed(struct intel_guc *guc, u32 *status)
 {
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       struct intel_uc_fw *guc_fw = &guc->fw;
-       unsigned long offset;
-       u32 status;
-       int ret;
-
-       /*
-        * The header plus uCode will be copied to WOPCM via DMA, excluding any
-        * other components
-        */
-       I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
-
-       /* Set the source address for the new blob */
-       offset = intel_guc_ggtt_offset(guc, vma) + guc_fw->header_offset;
-       I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
-       I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
 
-       /*
-        * Set the DMA destination. Current uCode expects the code to be
-        * loaded at 8k; locations below this are used for the stack.
-        */
-       I915_WRITE(DMA_ADDR_1_LOW, 0x2000);
-       I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
-
-       /* Finally start the DMA */
-       I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA));
-
-       /* Wait for DMA to finish */
-       ret = __intel_wait_for_register_fw(dev_priv, DMA_CTRL, START_DMA, 0,
-                                          2, 100, &status);
-       DRM_DEBUG_DRIVER("GuC DMA status %#x\n", status);
-
-       return ret;
+       /* Did we complete the xfer? */
+       *status = I915_READ(DMA_CTRL);
+       return !(*status & START_DMA);
 }
 
 /*
@@ -217,8 +178,8 @@ static int guc_wait_ucode(struct intel_guc *guc)
         * NB: Docs recommend not using the interrupt for completion.
         * Measurements indicate this should take no more than 20ms, so a
         * timeout here indicates that the GuC has failed and is unusable.
-        * (Higher levels of the driver will attempt to fall back to
-        * execlist mode if this happens.)
+        * (Higher levels of the driver may decide to reset the GuC and
+        * attempt the ucode load again if this happens.)
         */
        ret = wait_for(guc_ready(guc, &status), 100);
        DRM_DEBUG_DRIVER("GuC status %#x\n", status);
@@ -228,9 +189,51 @@ static int guc_wait_ucode(struct intel_guc *guc)
                ret = -ENOEXEC;
        }
 
+       if (ret == 0 && !guc_xfer_completed(guc, &status)) {
+               DRM_ERROR("GuC is ready, but the xfer %08x is incomplete\n",
+                         status);
+               ret = -ENXIO;
+       }
+
        return ret;
 }
 
+/*
+ * Transfer the firmware image to RAM for execution by the microcontroller.
+ *
+ * Architecturally, the DMA engine is bidirectional, and can potentially even
+ * transfer between GTT locations. This functionality is left out of the API
+ * for now as there is no need for it.
+ */
+static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma)
+{
+       struct drm_i915_private *dev_priv = guc_to_i915(guc);
+       struct intel_uc_fw *guc_fw = &guc->fw;
+       unsigned long offset;
+
+       /*
+        * The header plus uCode will be copied to WOPCM via DMA, excluding any
+        * other components
+        */
+       I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
+
+       /* Set the source address for the new blob */
+       offset = intel_guc_ggtt_offset(guc, vma) + guc_fw->header_offset;
+       I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
+       I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
+
+       /*
+        * Set the DMA destination. Current uCode expects the code to be
+        * loaded at 8k; locations below this are used for the stack.
+        */
+       I915_WRITE(DMA_ADDR_1_LOW, 0x2000);
+       I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
+
+       /* Finally start the DMA */
+       I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA));
+
+       return guc_wait_ucode(guc);
+}
 /*
  * Load the GuC firmware blob into the MinuteIA.
  */
@@ -251,17 +254,9 @@ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma)
         * by the DMA engine in one operation, whereas the RSA signature is
         * loaded via MMIO.
         */
-       ret = guc_xfer_rsa(guc, vma);
-       if (ret)
-               DRM_WARN("GuC firmware signature xfer error %d\n", ret);
+       guc_xfer_rsa(guc, vma);
 
        ret = guc_xfer_ucode(guc, vma);
-       if (ret)
-               DRM_WARN("GuC firmware code xfer error %d\n", ret);
-
-       ret = guc_wait_ucode(guc);
-       if (ret)
-               DRM_ERROR("GuC firmware xfer error %d\n", ret);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
index 8382d591c7842bb3f292fb3e62558c57b3b6a135..b2f5148f4f173a2f63097997886499e6b7160920 100644 (file)
 #define GUC_VIDEO_ENGINE2              4
 #define GUC_MAX_ENGINES_NUM            (GUC_VIDEO_ENGINE2 + 1)
 
+#define GUC_DOORBELL_INVALID           256
+
+#define GUC_DB_SIZE                    (PAGE_SIZE)
+#define GUC_WQ_SIZE                    (PAGE_SIZE * 2)
+
 /* Work queue item header definitions */
 #define WQ_STATUS_ACTIVE               1
 #define WQ_STATUS_SUSPENDED            2
@@ -59,9 +64,6 @@
 #define WQ_RING_TAIL_MAX               0x7FF   /* 2^11 QWords */
 #define WQ_RING_TAIL_MASK              (WQ_RING_TAIL_MAX << WQ_RING_TAIL_SHIFT)
 
-#define GUC_DOORBELL_ENABLED           1
-#define GUC_DOORBELL_DISABLED          0
-
 #define GUC_STAGE_DESC_ATTR_ACTIVE     BIT(0)
 #define GUC_STAGE_DESC_ATTR_PENDING_DB BIT(1)
 #define GUC_STAGE_DESC_ATTR_KERNEL     BIT(2)
@@ -219,26 +221,6 @@ struct uc_css_header {
        u32 header_info;
 } __packed;
 
-struct guc_doorbell_info {
-       u32 db_status;
-       u32 cookie;
-       u32 reserved[14];
-} __packed;
-
-union guc_doorbell_qw {
-       struct {
-               u32 db_status;
-               u32 cookie;
-       };
-       u64 value_qw;
-} __packed;
-
-#define GUC_NUM_DOORBELLS      256
-#define GUC_DOORBELL_INVALID   (GUC_NUM_DOORBELLS)
-
-#define GUC_DB_SIZE                    (PAGE_SIZE)
-#define GUC_WQ_SIZE                    (PAGE_SIZE * 2)
-
 /* Work item for submitting workloads into work queue of GuC. */
 struct guc_wq_item {
        u32 header;
@@ -601,7 +583,9 @@ struct guc_shared_ctx_data {
  * registers, where first register holds data treated as message header,
  * and other registers are used to hold message payload.
  *
- * For Gen9+, GuC uses software scratch registers 0xC180-0xC1B8
+ * For Gen9+, GuC uses software scratch registers 0xC180-0xC1B8,
+ * but no H2G command takes more than 8 parameters and the GuC FW
+ * itself uses an 8-element array to store the H2G message.
  *
  *      +-----------+---------+---------+---------+
  *      |  MMIO[0]  | MMIO[1] |   ...   | MMIO[n] |
@@ -633,6 +617,8 @@ struct guc_shared_ctx_data {
  *   field.
  */
 
+#define GUC_MAX_MMIO_MSG_LEN           8
+
 #define INTEL_GUC_MSG_TYPE_SHIFT       28
 #define INTEL_GUC_MSG_TYPE_MASK                (0xF << INTEL_GUC_MSG_TYPE_SHIFT)
 #define INTEL_GUC_MSG_DATA_SHIFT       16
@@ -687,6 +673,13 @@ enum intel_guc_report_status {
        INTEL_GUC_REPORT_STATUS_COMPLETE = 0x4,
 };
 
+enum intel_guc_sleep_state_status {
+       INTEL_GUC_SLEEP_STATE_SUCCESS = 0x0,
+       INTEL_GUC_SLEEP_STATE_PREEMPT_TO_IDLE_FAILED = 0x1,
+       INTEL_GUC_SLEEP_STATE_ENGINE_RESET_FAILED = 0x2
+#define INTEL_GUC_SLEEP_STATE_INVALID_MASK 0x80000000
+};
+
 #define GUC_LOG_CONTROL_LOGGING_ENABLED        (1 << 0)
 #define GUC_LOG_CONTROL_VERBOSITY_SHIFT        4
 #define GUC_LOG_CONTROL_VERBOSITY_MASK (0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT)
index d86084742a4a0e32e4ce982c954bc440cb26059e..57e7ad522c2fed3d0166b0e7fb6a79e73de572b4 100644 (file)
 #define GUC_SEND_INTERRUPT             _MMIO(0xc4c8)
 #define   GUC_SEND_TRIGGER               (1<<0)
 
+#define GUC_NUM_DOORBELLS              256
+
+/* format of the HW-monitored doorbell cacheline */
+struct guc_doorbell_info {
+       u32 db_status;
+#define GUC_DOORBELL_DISABLED          0
+#define GUC_DOORBELL_ENABLED           1
+
+       u32 cookie;
+       u32 reserved[14];
+} __packed;
+
 #define GEN8_DRBREGL(x)                        _MMIO(0x1000 + (x) * 8)
 #define   GEN8_DRB_VALID                 (1<<0)
 #define GEN8_DRBREGU(x)                        _MMIO(0x1000 + (x) * 8 + 4)
index a81f04d46e87650b7185a6508afe9d4f72567ddd..1570dcbe249c0c8c6b9c8755bf0a89e2a8b2368b 100644 (file)
@@ -192,7 +192,15 @@ static struct guc_doorbell_info *__get_doorbell(struct intel_guc_client *client)
        return client->vaddr + client->doorbell_offset;
 }
 
-static void __create_doorbell(struct intel_guc_client *client)
+static bool __doorbell_valid(struct intel_guc *guc, u16 db_id)
+{
+       struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+       GEM_BUG_ON(db_id >= GUC_NUM_DOORBELLS);
+       return I915_READ(GEN8_DRBREGL(db_id)) & GEN8_DRB_VALID;
+}
+
+static void __init_doorbell(struct intel_guc_client *client)
 {
        struct guc_doorbell_info *doorbell;
 
@@ -201,21 +209,19 @@ static void __create_doorbell(struct intel_guc_client *client)
        doorbell->cookie = 0;
 }
 
-static void __destroy_doorbell(struct intel_guc_client *client)
+static void __fini_doorbell(struct intel_guc_client *client)
 {
-       struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
        struct guc_doorbell_info *doorbell;
        u16 db_id = client->doorbell_id;
 
        doorbell = __get_doorbell(client);
        doorbell->db_status = GUC_DOORBELL_DISABLED;
-       doorbell->cookie = 0;
 
        /* Doorbell release flow requires that we wait for GEN8_DRB_VALID bit
         * to go to zero after updating db_status before we call the GuC to
         * release the doorbell
         */
-       if (wait_for_us(!(I915_READ(GEN8_DRBREGL(db_id)) & GEN8_DRB_VALID), 10))
+       if (wait_for_us(!__doorbell_valid(client->guc, db_id), 10))
                WARN_ONCE(true, "Doorbell never became invalid after disable\n");
 }
 
@@ -227,11 +233,11 @@ static int create_doorbell(struct intel_guc_client *client)
                return -ENODEV; /* internal setup error, should never happen */
 
        __update_doorbell_desc(client, client->doorbell_id);
-       __create_doorbell(client);
+       __init_doorbell(client);
 
        ret = __guc_allocate_doorbell(client->guc, client->stage_id);
        if (ret) {
-               __destroy_doorbell(client);
+               __fini_doorbell(client);
                __update_doorbell_desc(client, GUC_DOORBELL_INVALID);
                DRM_DEBUG_DRIVER("Couldn't create client %u doorbell: %d\n",
                                 client->stage_id, ret);
@@ -247,7 +253,7 @@ static int destroy_doorbell(struct intel_guc_client *client)
 
        GEM_BUG_ON(!has_doorbell(client));
 
-       __destroy_doorbell(client);
+       __fini_doorbell(client);
        ret = __guc_deallocate_doorbell(client->guc, client->stage_id);
        if (ret)
                DRM_ERROR("Couldn't destroy client %u doorbell: %d\n",
@@ -282,8 +288,7 @@ __get_process_desc(struct intel_guc_client *client)
 /*
  * Initialise the process descriptor shared with the GuC firmware.
  */
-static void guc_proc_desc_init(struct intel_guc *guc,
-                              struct intel_guc_client *client)
+static void guc_proc_desc_init(struct intel_guc_client *client)
 {
        struct guc_process_desc *desc;
 
@@ -304,6 +309,14 @@ static void guc_proc_desc_init(struct intel_guc *guc,
        desc->priority = client->priority;
 }
 
+static void guc_proc_desc_fini(struct intel_guc_client *client)
+{
+       struct guc_process_desc *desc;
+
+       desc = __get_process_desc(client);
+       memset(desc, 0, sizeof(*desc));
+}
+
 static int guc_stage_desc_pool_create(struct intel_guc *guc)
 {
        struct i915_vma *vma;
@@ -341,9 +354,9 @@ static void guc_stage_desc_pool_destroy(struct intel_guc *guc)
  * data structures relating to this client (doorbell, process descriptor,
  * write queue, etc).
  */
-static void guc_stage_desc_init(struct intel_guc *guc,
-                               struct intel_guc_client *client)
+static void guc_stage_desc_init(struct intel_guc_client *client)
 {
+       struct intel_guc *guc = client->guc;
        struct drm_i915_private *dev_priv = guc_to_i915(guc);
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx = client->owner;
@@ -424,8 +437,7 @@ static void guc_stage_desc_init(struct intel_guc *guc,
        desc->desc_private = ptr_to_u64(client);
 }
 
-static void guc_stage_desc_fini(struct intel_guc *guc,
-                               struct intel_guc_client *client)
+static void guc_stage_desc_fini(struct intel_guc_client *client)
 {
        struct guc_stage_desc *desc;
 
@@ -486,14 +498,6 @@ static void guc_wq_item_append(struct intel_guc_client *client,
        WRITE_ONCE(desc->tail, (wq_off + wqi_size) & (GUC_WQ_SIZE - 1));
 }
 
-static void guc_reset_wq(struct intel_guc_client *client)
-{
-       struct guc_process_desc *desc = __get_process_desc(client);
-
-       desc->head = 0;
-       desc->tail = 0;
-}
-
 static void guc_ring_doorbell(struct intel_guc_client *client)
 {
        struct guc_doorbell_info *db;
@@ -746,30 +750,28 @@ static bool __guc_dequeue(struct intel_engine_cs *engine)
        while ((rb = rb_first_cached(&execlists->queue))) {
                struct i915_priolist *p = to_priolist(rb);
                struct i915_request *rq, *rn;
+               int i;
 
-               list_for_each_entry_safe(rq, rn, &p->requests, sched.link) {
+               priolist_for_each_request_consume(rq, rn, p, i) {
                        if (last && rq->hw_context != last->hw_context) {
-                               if (port == last_port) {
-                                       __list_del_many(&p->requests,
-                                                       &rq->sched.link);
+                               if (port == last_port)
                                        goto done;
-                               }
 
                                if (submit)
                                        port_assign(port, last);
                                port++;
                        }
 
-                       INIT_LIST_HEAD(&rq->sched.link);
+                       list_del_init(&rq->sched.link);
 
                        __i915_request_submit(rq);
                        trace_i915_request_in(rq, port_index(port, execlists));
+
                        last = rq;
                        submit = true;
                }
 
                rb_erase_cached(&p->node, &execlists->queue);
-               INIT_LIST_HEAD(&p->requests);
                if (p->priority != I915_PRIORITY_NORMAL)
                        kmem_cache_free(engine->i915->priorities, p);
        }
@@ -791,19 +793,8 @@ done:
 
 static void guc_dequeue(struct intel_engine_cs *engine)
 {
-       unsigned long flags;
-       bool submit;
-
-       local_irq_save(flags);
-
-       spin_lock(&engine->timeline.lock);
-       submit = __guc_dequeue(engine);
-       spin_unlock(&engine->timeline.lock);
-
-       if (submit)
+       if (__guc_dequeue(engine))
                guc_submit(engine);
-
-       local_irq_restore(flags);
 }
 
 static void guc_submission_tasklet(unsigned long data)
@@ -812,6 +803,9 @@ static void guc_submission_tasklet(unsigned long data)
        struct intel_engine_execlists * const execlists = &engine->execlists;
        struct execlist_port *port = execlists->port;
        struct i915_request *rq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&engine->timeline.lock, flags);
 
        rq = port_request(port);
        while (rq && i915_request_completed(rq)) {
@@ -835,6 +829,8 @@ static void guc_submission_tasklet(unsigned long data)
 
        if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT))
                guc_dequeue(engine);
+
+       spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 static struct i915_request *
@@ -877,72 +873,31 @@ guc_reset_prepare(struct intel_engine_cs *engine)
 /* Check that a doorbell register is in the expected state */
 static bool doorbell_ok(struct intel_guc *guc, u16 db_id)
 {
-       struct drm_i915_private *dev_priv = guc_to_i915(guc);
-       u32 drbregl;
        bool valid;
 
-       GEM_BUG_ON(db_id >= GUC_DOORBELL_INVALID);
+       GEM_BUG_ON(db_id >= GUC_NUM_DOORBELLS);
 
-       drbregl = I915_READ(GEN8_DRBREGL(db_id));
-       valid = drbregl & GEN8_DRB_VALID;
+       valid = __doorbell_valid(guc, db_id);
 
        if (test_bit(db_id, guc->doorbell_bitmap) == valid)
                return true;
 
-       DRM_DEBUG_DRIVER("Doorbell %d has unexpected state (0x%x): valid=%s\n",
-                        db_id, drbregl, yesno(valid));
+       DRM_DEBUG_DRIVER("Doorbell %u has unexpected state: valid=%s\n",
+                        db_id, yesno(valid));
 
        return false;
 }
 
 static bool guc_verify_doorbells(struct intel_guc *guc)
 {
+       bool doorbells_ok = true;
        u16 db_id;
 
        for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id)
                if (!doorbell_ok(guc, db_id))
-                       return false;
-
-       return true;
-}
-
-static int guc_clients_doorbell_init(struct intel_guc *guc)
-{
-       int ret;
-
-       ret = create_doorbell(guc->execbuf_client);
-       if (ret)
-               return ret;
-
-       if (guc->preempt_client) {
-               ret = create_doorbell(guc->preempt_client);
-               if (ret) {
-                       destroy_doorbell(guc->execbuf_client);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void guc_clients_doorbell_fini(struct intel_guc *guc)
-{
-       /*
-        * By the time we're here, GuC has already been reset.
-        * Instead of trying (in vain) to communicate with it, let's just
-        * cleanup the doorbell HW and our internal state.
-        */
-       if (guc->preempt_client) {
-               __destroy_doorbell(guc->preempt_client);
-               __update_doorbell_desc(guc->preempt_client,
-                                      GUC_DOORBELL_INVALID);
-       }
+                       doorbells_ok = false;
 
-       if (guc->execbuf_client) {
-               __destroy_doorbell(guc->execbuf_client);
-               __update_doorbell_desc(guc->execbuf_client,
-                                      GUC_DOORBELL_INVALID);
-       }
+       return doorbells_ok;
 }
 
 /**
@@ -1005,6 +960,10 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
        }
        client->vaddr = vaddr;
 
+       ret = reserve_doorbell(client);
+       if (ret)
+               goto err_vaddr;
+
        client->doorbell_offset = __select_cacheline(guc);
 
        /*
@@ -1017,13 +976,6 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
        else
                client->proc_desc_offset = (GUC_DB_SIZE / 2);
 
-       guc_proc_desc_init(guc, client);
-       guc_stage_desc_init(guc, client);
-
-       ret = reserve_doorbell(client);
-       if (ret)
-               goto err_vaddr;
-
        DRM_DEBUG_DRIVER("new priority %u client %p for engine(s) 0x%x: stage_id %u\n",
                         priority, client, client->engines, client->stage_id);
        DRM_DEBUG_DRIVER("doorbell id %u, cacheline offset 0x%lx\n",
@@ -1045,7 +997,6 @@ err_client:
 static void guc_client_free(struct intel_guc_client *client)
 {
        unreserve_doorbell(client);
-       guc_stage_desc_fini(client->guc, client);
        i915_vma_unpin_and_release(&client->vma, I915_VMA_RELEASE_MAP);
        ida_simple_remove(&client->guc->stage_ids, client->stage_id);
        kfree(client);
@@ -1112,6 +1063,69 @@ static void guc_clients_destroy(struct intel_guc *guc)
                guc_client_free(client);
 }
 
+static int __guc_client_enable(struct intel_guc_client *client)
+{
+       int ret;
+
+       guc_proc_desc_init(client);
+       guc_stage_desc_init(client);
+
+       ret = create_doorbell(client);
+       if (ret)
+               goto fail;
+
+       return 0;
+
+fail:
+       guc_stage_desc_fini(client);
+       guc_proc_desc_fini(client);
+       return ret;
+}
+
+static void __guc_client_disable(struct intel_guc_client *client)
+{
+       /*
+        * By the time we're here, GuC may have already been reset. if that is
+        * the case, instead of trying (in vain) to communicate with it, let's
+        * just cleanup the doorbell HW and our internal state.
+        */
+       if (intel_guc_is_alive(client->guc))
+               destroy_doorbell(client);
+       else
+               __fini_doorbell(client);
+
+       guc_stage_desc_fini(client);
+       guc_proc_desc_fini(client);
+}
+
+static int guc_clients_enable(struct intel_guc *guc)
+{
+       int ret;
+
+       ret = __guc_client_enable(guc->execbuf_client);
+       if (ret)
+               return ret;
+
+       if (guc->preempt_client) {
+               ret = __guc_client_enable(guc->preempt_client);
+               if (ret) {
+                       __guc_client_disable(guc->execbuf_client);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void guc_clients_disable(struct intel_guc *guc)
+{
+       if (guc->preempt_client)
+               __guc_client_disable(guc->preempt_client);
+
+       if (guc->execbuf_client)
+               __guc_client_disable(guc->execbuf_client);
+}
+
 /*
  * Set up the memory resources to be shared with the GuC (via the GGTT)
  * at firmware loading time.
@@ -1295,15 +1309,11 @@ int intel_guc_submission_enable(struct intel_guc *guc)
 
        GEM_BUG_ON(!guc->execbuf_client);
 
-       guc_reset_wq(guc->execbuf_client);
-       if (guc->preempt_client)
-               guc_reset_wq(guc->preempt_client);
-
        err = intel_guc_sample_forcewake(guc);
        if (err)
                return err;
 
-       err = guc_clients_doorbell_init(guc);
+       err = guc_clients_enable(guc);
        if (err)
                return err;
 
@@ -1325,7 +1335,7 @@ void intel_guc_submission_disable(struct intel_guc *guc)
        GEM_BUG_ON(dev_priv->gt.awake); /* GT should be parked first */
 
        guc_interrupts_release(dev_priv);
-       guc_clients_doorbell_fini(guc);
+       guc_clients_disable(guc);
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
index 26e48fc95543244bb163f5f0f7d5370bda11ed59..1bf487f9425404cb85b3b5f5ef3bb43be32a0405 100644 (file)
 
 #define KEY_LOAD_TRIES 5
 
+static
+bool intel_hdcp_is_ksv_valid(u8 *ksv)
+{
+       int i, ones = 0;
+       /* KSV has 20 1's and 20 0's */
+       for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
+               ones += hweight8(ksv[i]);
+       if (ones != 20)
+               return false;
+
+       return true;
+}
+
+static
+int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port,
+                              const struct intel_hdcp_shim *shim, u8 *bksv)
+{
+       int ret, i, tries = 2;
+
+       /* HDCP spec states that we must retry the bksv if it is invalid */
+       for (i = 0; i < tries; i++) {
+               ret = shim->read_bksv(intel_dig_port, bksv);
+               if (ret)
+                       return ret;
+               if (intel_hdcp_is_ksv_valid(bksv))
+                       break;
+       }
+       if (i == tries) {
+               DRM_DEBUG_KMS("Bksv is invalid\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/* Is HDCP1.4 capable on Platform and Sink */
+bool intel_hdcp_capable(struct intel_connector *connector)
+{
+       struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
+       const struct intel_hdcp_shim *shim = connector->hdcp.shim;
+       bool capable = false;
+       u8 bksv[5];
+
+       if (!shim)
+               return capable;
+
+       if (shim->hdcp_capable) {
+               shim->hdcp_capable(intel_dig_port, &capable);
+       } else {
+               if (!intel_hdcp_read_valid_bksv(intel_dig_port, shim, bksv))
+                       capable = true;
+       }
+
+       return capable;
+}
+
 static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port,
                                    const struct intel_hdcp_shim *shim)
 {
@@ -167,18 +223,6 @@ u32 intel_hdcp_get_repeater_ctl(struct intel_digital_port *intel_dig_port)
        return -EINVAL;
 }
 
-static
-bool intel_hdcp_is_ksv_valid(u8 *ksv)
-{
-       int i, ones = 0;
-       /* KSV has 20 1's and 20 0's */
-       for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
-               ones += hweight8(ksv[i]);
-       if (ones != 20)
-               return false;
-       return true;
-}
-
 static
 int intel_hdcp_validate_v_prime(struct intel_digital_port *intel_dig_port,
                                const struct intel_hdcp_shim *shim,
@@ -383,7 +427,7 @@ int intel_hdcp_validate_v_prime(struct intel_digital_port *intel_dig_port,
        if (intel_wait_for_register(dev_priv, HDCP_REP_CTL,
                                    HDCP_SHA1_COMPLETE,
                                    HDCP_SHA1_COMPLETE, 1)) {
-               DRM_DEBUG_KMS("Timed out waiting for SHA1 complete\n");
+               DRM_ERROR("Timed out waiting for SHA1 complete\n");
                return -ETIMEDOUT;
        }
        if (!(I915_READ(HDCP_REP_CTL) & HDCP_SHA1_V_MATCH)) {
@@ -404,7 +448,7 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port,
 
        ret = intel_hdcp_poll_ksv_fifo(intel_dig_port, shim);
        if (ret) {
-               DRM_ERROR("KSV list failed to become ready (%d)\n", ret);
+               DRM_DEBUG_KMS("KSV list failed to become ready (%d)\n", ret);
                return ret;
        }
 
@@ -414,7 +458,7 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port,
 
        if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
            DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
-               DRM_ERROR("Max Topology Limit Exceeded\n");
+               DRM_DEBUG_KMS("Max Topology Limit Exceeded\n");
                return -EPERM;
        }
 
@@ -450,7 +494,7 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port,
        }
 
        if (i == tries) {
-               DRM_ERROR("V Prime validation failed.(%d)\n", ret);
+               DRM_DEBUG_KMS("V Prime validation failed.(%d)\n", ret);
                goto err;
        }
 
@@ -499,7 +543,7 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
                if (ret)
                        return ret;
                if (!hdcp_capable) {
-                       DRM_ERROR("Panel is not HDCP capable\n");
+                       DRM_DEBUG_KMS("Panel is not HDCP capable\n");
                        return -EINVAL;
                }
        }
@@ -527,18 +571,9 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
 
        memset(&bksv, 0, sizeof(bksv));
 
-       /* HDCP spec states that we must retry the bksv if it is invalid */
-       for (i = 0; i < tries; i++) {
-               ret = shim->read_bksv(intel_dig_port, bksv.shim);
-               if (ret)
-                       return ret;
-               if (intel_hdcp_is_ksv_valid(bksv.shim))
-                       break;
-       }
-       if (i == tries) {
-               DRM_ERROR("HDCP failed, Bksv is invalid\n");
-               return -ENODEV;
-       }
+       ret = intel_hdcp_read_valid_bksv(intel_dig_port, shim, bksv.shim);
+       if (ret < 0)
+               return ret;
 
        I915_WRITE(PORT_HDCP_BKSVLO(port), bksv.reg[0]);
        I915_WRITE(PORT_HDCP_BKSVHI(port), bksv.reg[1]);
@@ -594,8 +629,8 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
        }
 
        if (i == tries) {
-               DRM_ERROR("Timed out waiting for Ri prime match (%x)\n",
-                         I915_READ(PORT_HDCP_STATUS(port)));
+               DRM_DEBUG_KMS("Timed out waiting for Ri prime match (%x)\n",
+                             I915_READ(PORT_HDCP_STATUS(port)));
                return -ETIMEDOUT;
        }
 
@@ -618,14 +653,9 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
        return 0;
 }
 
-static
-struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector)
-{
-       return enc_to_dig_port(&intel_attached_encoder(&connector->base)->base);
-}
-
 static int _intel_hdcp_disable(struct intel_connector *connector)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
        struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
        enum port port = intel_dig_port->base.port;
@@ -641,7 +671,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
                return -ETIMEDOUT;
        }
 
-       ret = connector->hdcp_shim->toggle_signalling(intel_dig_port, false);
+       ret = hdcp->shim->toggle_signalling(intel_dig_port, false);
        if (ret) {
                DRM_ERROR("Failed to disable HDCP signalling\n");
                return ret;
@@ -653,6 +683,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
 
 static int _intel_hdcp_enable(struct intel_connector *connector)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
        int i, ret, tries = 3;
 
@@ -677,8 +708,7 @@ static int _intel_hdcp_enable(struct intel_connector *connector)
 
        /* Incase of authentication failures, HDCP spec expects reauth. */
        for (i = 0; i < tries; i++) {
-               ret = intel_hdcp_auth(conn_to_dig_port(connector),
-                                     connector->hdcp_shim);
+               ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->shim);
                if (!ret)
                        return 0;
 
@@ -688,42 +718,50 @@ static int _intel_hdcp_enable(struct intel_connector *connector)
                _intel_hdcp_disable(connector);
        }
 
-       DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
+       DRM_DEBUG_KMS("HDCP authentication failed (%d tries/%d)\n", tries, ret);
        return ret;
 }
 
+static inline
+struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
+{
+       return container_of(hdcp, struct intel_connector, hdcp);
+}
+
 static void intel_hdcp_check_work(struct work_struct *work)
 {
-       struct intel_connector *connector = container_of(to_delayed_work(work),
-                                                        struct intel_connector,
-                                                        hdcp_check_work);
+       struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
+                                              struct intel_hdcp,
+                                              check_work);
+       struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
+
        if (!intel_hdcp_check_link(connector))
-               schedule_delayed_work(&connector->hdcp_check_work,
+               schedule_delayed_work(&hdcp->check_work,
                                      DRM_HDCP_CHECK_PERIOD_MS);
 }
 
 static void intel_hdcp_prop_work(struct work_struct *work)
 {
-       struct intel_connector *connector = container_of(work,
-                                                        struct intel_connector,
-                                                        hdcp_prop_work);
+       struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
+                                              prop_work);
+       struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
        struct drm_device *dev = connector->base.dev;
        struct drm_connector_state *state;
 
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       mutex_lock(&connector->hdcp_mutex);
+       mutex_lock(&hdcp->mutex);
 
        /*
         * This worker is only used to flip between ENABLED/DESIRED. Either of
-        * those to UNDESIRED is handled by core. If hdcp_value == UNDESIRED,
+        * those to UNDESIRED is handled by core. If value == UNDESIRED,
         * we're running just after hdcp has been disabled, so just exit
         */
-       if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+       if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
                state = connector->base.state;
-               state->content_protection = connector->hdcp_value;
+               state->content_protection = hdcp->value;
        }
 
-       mutex_unlock(&connector->hdcp_mutex);
+       mutex_unlock(&hdcp->mutex);
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
 }
 
@@ -735,8 +773,9 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
 }
 
 int intel_hdcp_init(struct intel_connector *connector,
-                   const struct intel_hdcp_shim *hdcp_shim)
+                   const struct intel_hdcp_shim *shim)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        int ret;
 
        ret = drm_connector_attach_content_protection_property(
@@ -744,51 +783,53 @@ int intel_hdcp_init(struct intel_connector *connector,
        if (ret)
                return ret;
 
-       connector->hdcp_shim = hdcp_shim;
-       mutex_init(&connector->hdcp_mutex);
-       INIT_DELAYED_WORK(&connector->hdcp_check_work, intel_hdcp_check_work);
-       INIT_WORK(&connector->hdcp_prop_work, intel_hdcp_prop_work);
+       hdcp->shim = shim;
+       mutex_init(&hdcp->mutex);
+       INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
+       INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
        return 0;
 }
 
 int intel_hdcp_enable(struct intel_connector *connector)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        int ret;
 
-       if (!connector->hdcp_shim)
+       if (!hdcp->shim)
                return -ENOENT;
 
-       mutex_lock(&connector->hdcp_mutex);
+       mutex_lock(&hdcp->mutex);
 
        ret = _intel_hdcp_enable(connector);
        if (ret)
                goto out;
 
-       connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
-       schedule_work(&connector->hdcp_prop_work);
-       schedule_delayed_work(&connector->hdcp_check_work,
+       hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+       schedule_work(&hdcp->prop_work);
+       schedule_delayed_work(&hdcp->check_work,
                              DRM_HDCP_CHECK_PERIOD_MS);
 out:
-       mutex_unlock(&connector->hdcp_mutex);
+       mutex_unlock(&hdcp->mutex);
        return ret;
 }
 
 int intel_hdcp_disable(struct intel_connector *connector)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        int ret = 0;
 
-       if (!connector->hdcp_shim)
+       if (!hdcp->shim)
                return -ENOENT;
 
-       mutex_lock(&connector->hdcp_mutex);
+       mutex_lock(&hdcp->mutex);
 
-       if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-               connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+       if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+               hdcp->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
                ret = _intel_hdcp_disable(connector);
        }
 
-       mutex_unlock(&connector->hdcp_mutex);
-       cancel_delayed_work_sync(&connector->hdcp_check_work);
+       mutex_unlock(&hdcp->mutex);
+       cancel_delayed_work_sync(&hdcp->check_work);
        return ret;
 }
 
@@ -828,17 +869,18 @@ void intel_hdcp_atomic_check(struct drm_connector *connector,
 /* Implements Part 3 of the HDCP authorization procedure */
 int intel_hdcp_check_link(struct intel_connector *connector)
 {
+       struct intel_hdcp *hdcp = &connector->hdcp;
        struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
        struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
        enum port port = intel_dig_port->base.port;
        int ret = 0;
 
-       if (!connector->hdcp_shim)
+       if (!hdcp->shim)
                return -ENOENT;
 
-       mutex_lock(&connector->hdcp_mutex);
+       mutex_lock(&hdcp->mutex);
 
-       if (connector->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+       if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
                goto out;
 
        if (!(I915_READ(PORT_HDCP_STATUS(port)) & HDCP_STATUS_ENC)) {
@@ -846,17 +888,15 @@ int intel_hdcp_check_link(struct intel_connector *connector)
                          connector->base.name, connector->base.base.id,
                          I915_READ(PORT_HDCP_STATUS(port)));
                ret = -ENXIO;
-               connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
-               schedule_work(&connector->hdcp_prop_work);
+               hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               schedule_work(&hdcp->prop_work);
                goto out;
        }
 
-       if (connector->hdcp_shim->check_link(intel_dig_port)) {
-               if (connector->hdcp_value !=
-                   DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-                       connector->hdcp_value =
-                               DRM_MODE_CONTENT_PROTECTION_ENABLED;
-                       schedule_work(&connector->hdcp_prop_work);
+       if (hdcp->shim->check_link(intel_dig_port)) {
+               if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+                       hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+                       schedule_work(&hdcp->prop_work);
                }
                goto out;
        }
@@ -867,20 +907,20 @@ int intel_hdcp_check_link(struct intel_connector *connector)
        ret = _intel_hdcp_disable(connector);
        if (ret) {
                DRM_ERROR("Failed to disable hdcp (%d)\n", ret);
-               connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
-               schedule_work(&connector->hdcp_prop_work);
+               hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               schedule_work(&hdcp->prop_work);
                goto out;
        }
 
        ret = _intel_hdcp_enable(connector);
        if (ret) {
-               DRM_ERROR("Failed to enable hdcp (%d)\n", ret);
-               connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
-               schedule_work(&connector->hdcp_prop_work);
+               DRM_DEBUG_KMS("Failed to enable hdcp (%d)\n", ret);
+               hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               schedule_work(&hdcp->prop_work);
                goto out;
        }
 
 out:
-       mutex_unlock(&connector->hdcp_mutex);
+       mutex_unlock(&hdcp->mutex);
        return ret;
 }
index a2dab0b6bde6a6a1034b8dcc76c27e03b1004f27..07e803a604bddada573810e15eef3c01975a9dd8 100644 (file)
@@ -115,6 +115,8 @@ static u32 hsw_infoframe_enable(unsigned int type)
        switch (type) {
        case DP_SDP_VSC:
                return VIDEO_DIP_ENABLE_VSC_HSW;
+       case DP_SDP_PPS:
+               return VDIP_ENABLE_PPS;
        case HDMI_INFOFRAME_TYPE_AVI:
                return VIDEO_DIP_ENABLE_AVI_HSW;
        case HDMI_INFOFRAME_TYPE_SPD:
@@ -136,6 +138,8 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
        switch (type) {
        case DP_SDP_VSC:
                return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
+       case DP_SDP_PPS:
+               return ICL_VIDEO_DIP_PPS_DATA(cpu_transcoder, i);
        case HDMI_INFOFRAME_TYPE_AVI:
                return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
        case HDMI_INFOFRAME_TYPE_SPD:
@@ -148,14 +152,25 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
        }
 }
 
-static void g4x_write_infoframe(struct drm_encoder *encoder,
+static int hsw_dip_data_size(unsigned int type)
+{
+       switch (type) {
+       case DP_SDP_VSC:
+               return VIDEO_DIP_VSC_DATA_SIZE;
+       case DP_SDP_PPS:
+               return VIDEO_DIP_PPS_DATA_SIZE;
+       default:
+               return VIDEO_DIP_DATA_SIZE;
+       }
+}
+
+static void g4x_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
 {
        const u32 *data = frame;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(VIDEO_DIP_CTL);
        int i;
 
@@ -186,31 +201,29 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
        POSTING_READ(VIDEO_DIP_CTL);
 }
 
-static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
+static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(VIDEO_DIP_CTL);
 
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
 
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
 
        return val & (VIDEO_DIP_ENABLE_AVI |
                      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
 }
 
-static void ibx_write_infoframe(struct drm_encoder *encoder,
+static void ibx_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
 {
        const u32 *data = frame;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
@@ -243,11 +256,10 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
        POSTING_READ(reg);
 }
 
-static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
+static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
        u32 val = I915_READ(reg);
@@ -255,7 +267,7 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
 
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
 
        return val & (VIDEO_DIP_ENABLE_AVI |
@@ -263,14 +275,13 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void cpt_write_infoframe(struct drm_encoder *encoder,
+static void cpt_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
 {
        const u32 *data = frame;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
@@ -306,10 +317,10 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
        POSTING_READ(reg);
 }
 
-static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
+static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
 
@@ -321,14 +332,13 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void vlv_write_infoframe(struct drm_encoder *encoder,
+static void vlv_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
 {
        const u32 *data = frame;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
@@ -361,18 +371,17 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
        POSTING_READ(reg);
 }
 
-static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
+static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
        u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
 
        if ((val & VIDEO_DIP_ENABLE) == 0)
                return false;
 
-       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+       if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
                return false;
 
        return val & (VIDEO_DIP_ENABLE_AVI |
@@ -380,21 +389,21 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
                      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void hsw_write_infoframe(struct drm_encoder *encoder,
+static void hsw_write_infoframe(struct intel_encoder *encoder,
                                const struct intel_crtc_state *crtc_state,
                                unsigned int type,
                                const void *frame, ssize_t len)
 {
        const u32 *data = frame;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
        i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
-       int data_size = type == DP_SDP_VSC ?
-               VIDEO_DIP_VSC_DATA_SIZE : VIDEO_DIP_DATA_SIZE;
+       int data_size;
        int i;
        u32 val = I915_READ(ctl_reg);
 
+       data_size = hsw_dip_data_size(type);
+
        val &= ~hsw_infoframe_enable(type);
        I915_WRITE(ctl_reg, val);
 
@@ -415,10 +424,10 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
        POSTING_READ(ctl_reg);
 }
 
-static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
+static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *pipe_config)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
 
        return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
@@ -443,11 +452,11 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
  * trick them by giving an offset into the buffer and moving back the header
  * bytes by one.
  */
-static void intel_write_infoframe(struct drm_encoder *encoder,
+static void intel_write_infoframe(struct intel_encoder *encoder,
                                  const struct intel_crtc_state *crtc_state,
                                  union hdmi_infoframe *frame)
 {
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        u8 buffer[VIDEO_DIP_DATA_SIZE];
        ssize_t len;
 
@@ -457,24 +466,25 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
                return;
 
        /* Insert the 'hole' (see big comment above) at position 3 */
-       buffer[0] = buffer[1];
-       buffer[1] = buffer[2];
-       buffer[2] = buffer[3];
+       memmove(&buffer[0], &buffer[1], 3);
        buffer[3] = 0;
        len++;
 
-       intel_dig_port->write_infoframe(encoder, crtc_state, frame->any.type, buffer, len);
+       intel_dig_port->write_infoframe(encoder,
+                                       crtc_state,
+                                       frame->any.type, buffer, len);
 }
 
-static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state,
                                         const struct drm_connector_state *conn_state)
 {
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        const struct drm_display_mode *adjusted_mode =
                &crtc_state->base.adjusted_mode;
        struct drm_connector *connector = &intel_hdmi->attached_connector->base;
-       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
+       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported ||
+          connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
        union hdmi_infoframe frame;
        int ret;
 
@@ -486,8 +496,10 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
                return;
        }
 
-       if (crtc_state->ycbcr420)
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
                frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+       else if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+               frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
        else
                frame.avi.colorspace = HDMI_COLORSPACE_RGB;
 
@@ -502,10 +514,11 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
                                            conn_state);
 
        /* TODO: handle pixel repetition for YCBCR420 outputs */
-       intel_write_infoframe(encoder, crtc_state, &frame);
+       intel_write_infoframe(encoder, crtc_state,
+                             &frame);
 }
 
-static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state)
 {
        union hdmi_infoframe frame;
@@ -519,11 +532,12 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
 
        frame.spd.sdi = HDMI_SPD_SDI_PC;
 
-       intel_write_infoframe(encoder, crtc_state, &frame);
+       intel_write_infoframe(encoder, crtc_state,
+                             &frame);
 }
 
 static void
-intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
+intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
                              const struct intel_crtc_state *crtc_state,
                              const struct drm_connector_state *conn_state)
 {
@@ -536,20 +550,21 @@ intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
        if (ret < 0)
                return;
 
-       intel_write_infoframe(encoder, crtc_state, &frame);
+       intel_write_infoframe(encoder, crtc_state,
+                             &frame);
 }
 
-static void g4x_set_infoframes(struct drm_encoder *encoder,
+static void g4x_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        i915_reg_t reg = VIDEO_DIP_CTL;
        u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -657,11 +672,11 @@ static bool gcp_default_phase_possible(int pipe_bpp,
                 mode->crtc_htotal/2 % pixels_per_group == 0);
 }
 
-static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
+static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
                                         const struct intel_crtc_state *crtc_state,
                                         const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        i915_reg_t reg;
        u32 val = 0;
@@ -689,18 +704,18 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
        return val != 0;
 }
 
-static void ibx_set_infoframes(struct drm_encoder *encoder,
+static void ibx_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -742,14 +757,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void cpt_set_infoframes(struct drm_encoder *encoder,
+static void cpt_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
 
@@ -785,18 +800,17 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void vlv_set_infoframes(struct drm_encoder *encoder,
+static void vlv_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
-       u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+       u32 port = VIDEO_DIP_PORT(encoder->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -838,12 +852,12 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
        intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void hsw_set_infoframes(struct drm_encoder *encoder,
+static void hsw_set_infoframes(struct intel_encoder *encoder,
                               bool enable,
                               const struct intel_crtc_state *crtc_state,
                               const struct drm_connector_state *conn_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
        u32 val = I915_READ(reg);
 
@@ -965,13 +979,13 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
                                    DRM_HDCP_AN_LEN);
        if (ret) {
-               DRM_ERROR("Write An over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Write An over DDC failed (%d)\n", ret);
                return ret;
        }
 
        ret = intel_gmbus_output_aksv(adapter);
        if (ret < 0) {
-               DRM_ERROR("Failed to output aksv (%d)\n", ret);
+               DRM_DEBUG_KMS("Failed to output aksv (%d)\n", ret);
                return ret;
        }
        return 0;
@@ -984,7 +998,7 @@ static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
                                   DRM_HDCP_KSV_LEN);
        if (ret)
-               DRM_ERROR("Read Bksv over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read Bksv over DDC failed (%d)\n", ret);
        return ret;
 }
 
@@ -996,7 +1010,7 @@ int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
                                   bstatus, DRM_HDCP_BSTATUS_LEN);
        if (ret)
-               DRM_ERROR("Read bstatus over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read bstatus over DDC failed (%d)\n", ret);
        return ret;
 }
 
@@ -1009,7 +1023,7 @@ int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
 
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
        if (ret) {
-               DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
                return ret;
        }
        *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
@@ -1024,7 +1038,7 @@ int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
                                   ri_prime, DRM_HDCP_RI_LEN);
        if (ret)
-               DRM_ERROR("Read Ri' over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read Ri' over DDC failed (%d)\n", ret);
        return ret;
 }
 
@@ -1037,7 +1051,7 @@ int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
 
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
        if (ret) {
-               DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read bcaps over DDC failed (%d)\n", ret);
                return ret;
        }
        *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
@@ -1052,7 +1066,7 @@ int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
                                   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
        if (ret) {
-               DRM_ERROR("Read ksv fifo over DDC failed (%d)\n", ret);
+               DRM_DEBUG_KMS("Read ksv fifo over DDC failed (%d)\n", ret);
                return ret;
        }
        return 0;
@@ -1070,7 +1084,7 @@ int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
        ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
                                   part, DRM_HDCP_V_PRIME_PART_LEN);
        if (ret)
-               DRM_ERROR("Read V'[%d] over DDC failed (%d)\n", i, ret);
+               DRM_DEBUG_KMS("Read V'[%d] over DDC failed (%d)\n", i, ret);
        return ret;
 }
 
@@ -1217,7 +1231,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
        if (tmp & HDMI_MODE_SELECT_HDMI)
                pipe_config->has_hdmi_sink = true;
 
-       if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
+       if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
                pipe_config->has_infoframe = true;
 
        if (tmp & SDVO_AUDIO_ENABLE)
@@ -1438,7 +1452,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder,
                intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
        }
 
-       intel_dig_port->set_infoframes(&encoder->base, false,
+       intel_dig_port->set_infoframes(encoder,
+                                      false,
                                       old_crtc_state, old_conn_state);
 
        intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
@@ -1597,6 +1612,8 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
        struct drm_atomic_state *state = crtc_state->base.state;
        struct drm_connector_state *connector_state;
        struct drm_connector *connector;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
        int i;
 
        if (HAS_GMCH_DISPLAY(dev_priv))
@@ -1624,7 +1641,7 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
                if (connector_state->crtc != crtc_state->base.crtc)
                        continue;
 
-               if (crtc_state->ycbcr420) {
+               if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
                        const struct drm_hdmi_info *hdmi = &info->hdmi;
 
                        if (bpc == 12 && !(hdmi->y420_dc_modes &
@@ -1645,7 +1662,14 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
 
        /* Display WA #1139: glk */
        if (bpc == 12 && IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) &&
-           crtc_state->base.adjusted_mode.htotal > 5460)
+           adjusted_mode->htotal > 5460)
+               return false;
+
+       /* Display Wa_1405510057:icl */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+           bpc == 10 && IS_ICELAKE(dev_priv) &&
+           (adjusted_mode->crtc_hblank_end -
+            adjusted_mode->crtc_hblank_start) % 8 == 2)
                return false;
 
        return true;
@@ -1669,7 +1693,7 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector,
        *clock_12bpc /= 2;
        *clock_10bpc /= 2;
        *clock_8bpc /= 2;
-       config->ycbcr420 = true;
+       config->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
 
        /* YCBCR 420 output conversion needs a scaler */
        if (skl_update_scaler_crtc(config)) {
@@ -1703,6 +1727,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
 
        if (pipe_config->has_hdmi_sink)
@@ -1973,7 +1998,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
 
        intel_hdmi_prepare(encoder, pipe_config);
 
-       intel_dig_port->set_infoframes(&encoder->base,
+       intel_dig_port->set_infoframes(encoder,
                                       pipe_config->has_infoframe,
                                       pipe_config, conn_state);
 }
@@ -1991,7 +2016,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
        vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
                                 0x2b247878);
 
-       dport->set_infoframes(&encoder->base,
+       dport->set_infoframes(encoder,
                              pipe_config->has_infoframe,
                              pipe_config, conn_state);
 
@@ -2062,7 +2087,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
        /* Use 800mV-0dB */
        chv_set_phy_signal_level(encoder, 128, 102, false);
 
-       dport->set_infoframes(&encoder->base,
+       dport->set_infoframes(encoder,
                              pipe_config->has_infoframe,
                              pipe_config, conn_state);
 
@@ -2074,13 +2099,26 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
        chv_phy_release_cl2_override(encoder);
 }
 
+static int
+intel_hdmi_connector_register(struct drm_connector *connector)
+{
+       int ret;
+
+       ret = intel_connector_register(connector);
+       if (ret)
+               return ret;
+
+       i915_debugfs_connector_add(connector);
+
+       return ret;
+}
+
 static void intel_hdmi_destroy(struct drm_connector *connector)
 {
        if (intel_attached_hdmi(connector)->cec_notifier)
                cec_notifier_put(intel_attached_hdmi(connector)->cec_notifier);
-       kfree(to_intel_connector(connector)->detect_edid);
-       drm_connector_cleanup(connector);
-       kfree(connector);
+
+       intel_connector_destroy(connector);
 }
 
 static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
@@ -2089,7 +2127,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_digital_connector_atomic_get_property,
        .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .late_register = intel_connector_register,
+       .late_register = intel_hdmi_connector_register,
        .early_unregister = intel_connector_unregister,
        .destroy = intel_hdmi_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -2109,11 +2147,16 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
 static void
 intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
 {
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+
        intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
        intel_attach_aspect_ratio_property(connector);
        drm_connector_attach_content_type_property(connector);
        connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
+
+       if (!HAS_GMCH_DISPLAY(dev_priv))
+               drm_connector_attach_max_bpc_property(connector, 8, 12);
 }
 
 /*
@@ -2324,9 +2367,18 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
                intel_dig_port->set_infoframes = g4x_set_infoframes;
                intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
        } else if (HAS_DDI(dev_priv)) {
-               intel_dig_port->write_infoframe = hsw_write_infoframe;
-               intel_dig_port->set_infoframes = hsw_set_infoframes;
-               intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
+               if (intel_dig_port->lspcon.active) {
+                       intel_dig_port->write_infoframe =
+                                       lspcon_write_infoframe;
+                       intel_dig_port->set_infoframes = lspcon_set_infoframes;
+                       intel_dig_port->infoframe_enabled =
+                                               lspcon_infoframe_enabled;
+               } else {
+                       intel_dig_port->set_infoframes = hsw_set_infoframes;
+                       intel_dig_port->infoframe_enabled =
+                                               hsw_infoframe_enabled;
+                       intel_dig_port->write_infoframe = hsw_write_infoframe;
+               }
        } else if (HAS_PCH_IBX(dev_priv)) {
                intel_dig_port->write_infoframe = ibx_write_infoframe;
                intel_dig_port->set_infoframes = ibx_set_infoframes;
@@ -2485,5 +2537,6 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
 
        intel_infoframe_init(intel_dig_port);
 
+       intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
        intel_hdmi_init_connector(intel_dig_port, intel_connector);
 }
index 9a801813023728e2e0a05bb5feba1f8415eb3269..e24174d08fedb55ca4619e61cb96570deab6bc52 100644 (file)
@@ -114,51 +114,68 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
 #define HPD_STORM_REENABLE_DELAY       (2 * 60 * 1000)
 
 /**
- * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin
+ * intel_hpd_irq_storm_detect - gather stats and detect HPD IRQ storm on a pin
  * @dev_priv: private driver data pointer
  * @pin: the pin to gather stats on
+ * @long_hpd: whether the HPD IRQ was long or short
  *
- * Gather stats about HPD irqs from the specified @pin, and detect irq
+ * Gather stats about HPD IRQs from the specified @pin, and detect IRQ
  * storms. Only the pin specific stats and state are changed, the caller is
  * responsible for further action.
  *
- * The number of irqs that are allowed within @HPD_STORM_DETECT_PERIOD is
+ * The number of IRQs that are allowed within @HPD_STORM_DETECT_PERIOD is
  * stored in @dev_priv->hotplug.hpd_storm_threshold which defaults to
- * @HPD_STORM_DEFAULT_THRESHOLD. If this threshold is exceeded, it's
- * considered an irq storm and the irq state is set to @HPD_MARK_DISABLED.
+ * @HPD_STORM_DEFAULT_THRESHOLD. Long IRQs count as +10 to this threshold, and
+ * short IRQs count as +1. If this threshold is exceeded, it's considered an
+ * IRQ storm and the IRQ state is set to @HPD_MARK_DISABLED.
+ *
+ * By default, most systems will only count long IRQs towards
+ * &dev_priv->hotplug.hpd_storm_threshold. However, some older systems also
+ * suffer from short IRQ storms and must also track these. Because short IRQ
+ * storms are naturally caused by sideband interactions with DP MST devices,
+ * short IRQ detection is only enabled for systems without DP MST support.
+ * Systems which are new enough to support DP MST are far less likely to
+ * suffer from IRQ storms at all, so this is fine.
  *
  * The HPD threshold can be controlled through i915_hpd_storm_ctl in debugfs,
  * and should only be adjusted for automated hotplug testing.
  *
- * Return true if an irq storm was detected on @pin.
+ * Return true if an IRQ storm was detected on @pin.
  */
 static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv,
-                                      enum hpd_pin pin)
+                                      enum hpd_pin pin, bool long_hpd)
 {
-       unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies;
+       struct i915_hotplug *hpd = &dev_priv->hotplug;
+       unsigned long start = hpd->stats[pin].last_jiffies;
        unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD);
-       const int threshold = dev_priv->hotplug.hpd_storm_threshold;
+       const int increment = long_hpd ? 10 : 1;
+       const int threshold = hpd->hpd_storm_threshold;
        bool storm = false;
 
+       if (!threshold ||
+           (!long_hpd && !dev_priv->hotplug.hpd_short_storm_enabled))
+               return false;
+
        if (!time_in_range(jiffies, start, end)) {
-               dev_priv->hotplug.stats[pin].last_jiffies = jiffies;
-               dev_priv->hotplug.stats[pin].count = 0;
-               DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin);
-       } else if (dev_priv->hotplug.stats[pin].count > threshold &&
-                  threshold) {
-               dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED;
+               hpd->stats[pin].last_jiffies = jiffies;
+               hpd->stats[pin].count = 0;
+       }
+
+       hpd->stats[pin].count += increment;
+       if (hpd->stats[pin].count > threshold) {
+               hpd->stats[pin].state = HPD_MARK_DISABLED;
                DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin);
                storm = true;
        } else {
-               dev_priv->hotplug.stats[pin].count++;
                DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin,
-                             dev_priv->hotplug.stats[pin].count);
+                             hpd->stats[pin].count);
        }
 
        return storm;
 }
 
-static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv)
+static void
+intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = &dev_priv->drm;
        struct intel_connector *intel_connector;
@@ -348,8 +365,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
        hpd_event_bits = dev_priv->hotplug.event_bits;
        dev_priv->hotplug.event_bits = 0;
 
-       /* Disable hotplug on connectors that hit an irq storm. */
-       intel_hpd_irq_storm_disable(dev_priv);
+       /* Enable polling for connectors which had HPD IRQ storms */
+       intel_hpd_irq_storm_switch_to_polling(dev_priv);
 
        spin_unlock_irq(&dev_priv->irq_lock);
 
@@ -474,15 +491,17 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
                        queue_hp = true;
                }
 
-               if (!long_hpd)
-                       continue;
-
-               if (intel_hpd_irq_storm_detect(dev_priv, pin)) {
+               if (intel_hpd_irq_storm_detect(dev_priv, pin, long_hpd)) {
                        dev_priv->hotplug.event_bits &= ~BIT(pin);
                        storm_detected = true;
+                       queue_hp = true;
                }
        }
 
+       /*
+        * Disable any IRQs that storms were detected on. Polling enablement
+        * happens later in our hotplug work.
+        */
        if (storm_detected && dev_priv->display_irqs_enabled)
                dev_priv->display.hpd_irq_setup(dev_priv);
        spin_unlock(&dev_priv->irq_lock);
index 37ef540dd280a2986942d4fb8688de39c4cc8e66..bc27b691d8248473abd207138817f10b55971751 100644 (file)
@@ -108,13 +108,14 @@ fail:
  * This function reads status register to verify if HuC
  * firmware was successfully loaded.
  *
- * Returns positive value if HuC firmware is loaded and verified
- * and -ENODEV if HuC is not present.
+ * Returns: 1 if HuC firmware is loaded and verified,
+ * 0 if HuC firmware is not loaded and -ENODEV if HuC
+ * is not present on this platform.
  */
 int intel_huc_check_status(struct intel_huc *huc)
 {
        struct drm_i915_private *dev_priv = huc_to_i915(huc);
-       u32 status;
+       bool status;
 
        if (!HAS_HUC(dev_priv))
                return -ENODEV;
index 33d87ab93fdd4bd81a221daf9a039e84510d592d..802d0394ccc4ad82d92e244cce2109313c84b9a2 100644 (file)
@@ -817,7 +817,7 @@ int intel_setup_gmbus(struct drm_i915_private *dev_priv)
        unsigned int pin;
        int ret;
 
-       if (INTEL_INFO(dev_priv)->num_pipes == 0)
+       if (!HAS_DISPLAY(dev_priv))
                return 0;
 
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
index 58d1d3d47dd31ed7aa150f6b9865eb05e0a170b7..4be167dcd209ba9a9d43be93821eb59ecb1e275b 100644 (file)
@@ -259,63 +259,6 @@ intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
        ce->lrc_desc = desc;
 }
 
-static struct i915_priolist *
-lookup_priolist(struct intel_engine_cs *engine, int prio)
-{
-       struct intel_engine_execlists * const execlists = &engine->execlists;
-       struct i915_priolist *p;
-       struct rb_node **parent, *rb;
-       bool first = true;
-
-       if (unlikely(execlists->no_priolist))
-               prio = I915_PRIORITY_NORMAL;
-
-find_priolist:
-       /* most positive priority is scheduled first, equal priorities fifo */
-       rb = NULL;
-       parent = &execlists->queue.rb_root.rb_node;
-       while (*parent) {
-               rb = *parent;
-               p = to_priolist(rb);
-               if (prio > p->priority) {
-                       parent = &rb->rb_left;
-               } else if (prio < p->priority) {
-                       parent = &rb->rb_right;
-                       first = false;
-               } else {
-                       return p;
-               }
-       }
-
-       if (prio == I915_PRIORITY_NORMAL) {
-               p = &execlists->default_priolist;
-       } else {
-               p = kmem_cache_alloc(engine->i915->priorities, GFP_ATOMIC);
-               /* Convert an allocation failure to a priority bump */
-               if (unlikely(!p)) {
-                       prio = I915_PRIORITY_NORMAL; /* recurses just once */
-
-                       /* To maintain ordering with all rendering, after an
-                        * allocation failure we have to disable all scheduling.
-                        * Requests will then be executed in fifo, and schedule
-                        * will ensure that dependencies are emitted in fifo.
-                        * There will be still some reordering with existing
-                        * requests, so if userspace lied about their
-                        * dependencies that reordering may be visible.
-                        */
-                       execlists->no_priolist = true;
-                       goto find_priolist;
-               }
-       }
-
-       p->priority = prio;
-       INIT_LIST_HEAD(&p->requests);
-       rb_link_node(&p->node, rb, parent);
-       rb_insert_color_cached(&p->node, &execlists->queue, first);
-
-       return p;
-}
-
 static void unwind_wa_tail(struct i915_request *rq)
 {
        rq->tail = intel_ring_wrap(rq->ring, rq->wa_tail - WA_TAIL_BYTES);
@@ -324,9 +267,9 @@ static void unwind_wa_tail(struct i915_request *rq)
 
 static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
 {
-       struct i915_request *rq, *rn;
-       struct i915_priolist *uninitialized_var(p);
-       int last_prio = I915_PRIORITY_INVALID;
+       struct i915_request *rq, *rn, *active = NULL;
+       struct list_head *uninitialized_var(pl);
+       int prio = I915_PRIORITY_INVALID | I915_PRIORITY_NEWCLIENT;
 
        lockdep_assert_held(&engine->timeline.lock);
 
@@ -334,19 +277,34 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
                                         &engine->timeline.requests,
                                         link) {
                if (i915_request_completed(rq))
-                       return;
+                       break;
 
                __i915_request_unsubmit(rq);
                unwind_wa_tail(rq);
 
+               GEM_BUG_ON(rq->hw_context->active);
+
                GEM_BUG_ON(rq_prio(rq) == I915_PRIORITY_INVALID);
-               if (rq_prio(rq) != last_prio) {
-                       last_prio = rq_prio(rq);
-                       p = lookup_priolist(engine, last_prio);
+               if (rq_prio(rq) != prio) {
+                       prio = rq_prio(rq);
+                       pl = i915_sched_lookup_priolist(engine, prio);
                }
+               GEM_BUG_ON(RB_EMPTY_ROOT(&engine->execlists.queue.rb_root));
 
-               GEM_BUG_ON(p->priority != rq_prio(rq));
-               list_add(&rq->sched.link, &p->requests);
+               list_add(&rq->sched.link, pl);
+
+               active = rq;
+       }
+
+       /*
+        * The active request is now effectively the start of a new client
+        * stream, so give it the equivalent small priority bump to prevent
+        * it being gazumped a second time by another peer.
+        */
+       if (!(prio & I915_PRIORITY_NEWCLIENT)) {
+               prio |= I915_PRIORITY_NEWCLIENT;
+               list_move_tail(&active->sched.link,
+                              i915_sched_lookup_priolist(engine, prio));
        }
 }
 
@@ -355,13 +313,8 @@ execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists)
 {
        struct intel_engine_cs *engine =
                container_of(execlists, typeof(*engine), execlists);
-       unsigned long flags;
-
-       spin_lock_irqsave(&engine->timeline.lock, flags);
 
        __unwind_incomplete_requests(engine);
-
-       spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 static inline void
@@ -394,13 +347,17 @@ execlists_user_end(struct intel_engine_execlists *execlists)
 static inline void
 execlists_context_schedule_in(struct i915_request *rq)
 {
+       GEM_BUG_ON(rq->hw_context->active);
+
        execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_IN);
        intel_engine_context_in(rq->engine);
+       rq->hw_context->active = rq->engine;
 }
 
 static inline void
 execlists_context_schedule_out(struct i915_request *rq, unsigned long status)
 {
+       rq->hw_context->active = NULL;
        intel_engine_context_out(rq->engine);
        execlists_context_status_change(rq, status);
        trace_i915_request_out(rq);
@@ -417,9 +374,8 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
 
 static u64 execlists_update_context(struct i915_request *rq)
 {
+       struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt;
        struct intel_context *ce = rq->hw_context;
-       struct i915_hw_ppgtt *ppgtt =
-               rq->gem_context->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
        u32 *reg_state = ce->lrc_reg_state;
 
        reg_state[CTX_RING_TAIL+1] = intel_ring_set_tail(rq->ring, rq->tail);
@@ -430,7 +386,7 @@ static u64 execlists_update_context(struct i915_request *rq)
         * PML4 is allocated during ppgtt init, so this is not needed
         * in 48-bit mode.
         */
-       if (ppgtt && !i915_vm_is_48bit(&ppgtt->vm))
+       if (!i915_vm_is_48bit(&ppgtt->vm))
                execlists_update_context_pdps(ppgtt, reg_state);
 
        /*
@@ -686,8 +642,9 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
        while ((rb = rb_first_cached(&execlists->queue))) {
                struct i915_priolist *p = to_priolist(rb);
                struct i915_request *rq, *rn;
+               int i;
 
-               list_for_each_entry_safe(rq, rn, &p->requests, sched.link) {
+               priolist_for_each_request_consume(rq, rn, p, i) {
                        /*
                         * Can we combine this request with the current port?
                         * It has to be the same context/ringbuffer and not
@@ -706,11 +663,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
                                 * combine this request with the last, then we
                                 * are done.
                                 */
-                               if (port == last_port) {
-                                       __list_del_many(&p->requests,
-                                                       &rq->sched.link);
+                               if (port == last_port)
                                        goto done;
-                               }
 
                                /*
                                 * If GVT overrides us we only ever submit
@@ -720,11 +674,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
                                 * request) to the second port.
                                 */
                                if (ctx_single_port_submission(last->hw_context) ||
-                                   ctx_single_port_submission(rq->hw_context)) {
-                                       __list_del_many(&p->requests,
-                                                       &rq->sched.link);
+                                   ctx_single_port_submission(rq->hw_context))
                                        goto done;
-                               }
 
                                GEM_BUG_ON(last->hw_context == rq->hw_context);
 
@@ -735,15 +686,16 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
                                GEM_BUG_ON(port_isset(port));
                        }
 
-                       INIT_LIST_HEAD(&rq->sched.link);
+                       list_del_init(&rq->sched.link);
+
                        __i915_request_submit(rq);
                        trace_i915_request_in(rq, port_index(port, execlists));
+
                        last = rq;
                        submit = true;
                }
 
                rb_erase_cached(&p->node, &execlists->queue);
-               INIT_LIST_HEAD(&p->requests);
                if (p->priority != I915_PRIORITY_NORMAL)
                        kmem_cache_free(engine->i915->priorities, p);
        }
@@ -820,6 +772,8 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists)
 
 static void reset_csb_pointers(struct intel_engine_execlists *execlists)
 {
+       const unsigned int reset_value = GEN8_CSB_ENTRIES - 1;
+
        /*
         * After a reset, the HW starts writing into CSB entry [0]. We
         * therefore have to set our HEAD pointer back one entry so that
@@ -829,8 +783,8 @@ static void reset_csb_pointers(struct intel_engine_execlists *execlists)
         * inline comparison of our cached head position against the last HW
         * write works even before the first interrupt.
         */
-       execlists->csb_head = execlists->csb_write_reset;
-       WRITE_ONCE(*execlists->csb_write, execlists->csb_write_reset);
+       execlists->csb_head = reset_value;
+       WRITE_ONCE(*execlists->csb_write, reset_value);
 }
 
 static void nop_submission_tasklet(unsigned long data)
@@ -871,27 +825,34 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
        /* Mark all executing requests as skipped. */
        list_for_each_entry(rq, &engine->timeline.requests, link) {
                GEM_BUG_ON(!rq->global_seqno);
-               if (!i915_request_completed(rq))
-                       dma_fence_set_error(&rq->fence, -EIO);
+
+               if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
+                       continue;
+
+               dma_fence_set_error(&rq->fence, -EIO);
        }
 
        /* Flush the queued requests to the timeline list (for retiring). */
        while ((rb = rb_first_cached(&execlists->queue))) {
                struct i915_priolist *p = to_priolist(rb);
+               int i;
 
-               list_for_each_entry_safe(rq, rn, &p->requests, sched.link) {
-                       INIT_LIST_HEAD(&rq->sched.link);
+               priolist_for_each_request_consume(rq, rn, p, i) {
+                       list_del_init(&rq->sched.link);
 
                        dma_fence_set_error(&rq->fence, -EIO);
                        __i915_request_submit(rq);
                }
 
                rb_erase_cached(&p->node, &execlists->queue);
-               INIT_LIST_HEAD(&p->requests);
                if (p->priority != I915_PRIORITY_NORMAL)
                        kmem_cache_free(engine->i915->priorities, p);
        }
 
+       intel_write_status_page(engine,
+                               I915_GEM_HWS_INDEX,
+                               intel_engine_last_submit(engine));
+
        /* Remaining _unready_ requests will be nop'ed when submitted */
 
        execlists->queue_priority = INT_MIN;
@@ -1093,13 +1054,7 @@ static void queue_request(struct intel_engine_cs *engine,
                          struct i915_sched_node *node,
                          int prio)
 {
-       list_add_tail(&node->link,
-                     &lookup_priolist(engine, prio)->requests);
-}
-
-static void __update_queue(struct intel_engine_cs *engine, int prio)
-{
-       engine->execlists.queue_priority = prio;
+       list_add_tail(&node->link, i915_sched_lookup_priolist(engine, prio));
 }
 
 static void __submit_queue_imm(struct intel_engine_cs *engine)
@@ -1118,7 +1073,7 @@ static void __submit_queue_imm(struct intel_engine_cs *engine)
 static void submit_queue(struct intel_engine_cs *engine, int prio)
 {
        if (prio > engine->execlists.queue_priority) {
-               __update_queue(engine, prio);
+               engine->execlists.queue_priority = prio;
                __submit_queue_imm(engine);
        }
 }
@@ -1141,139 +1096,6 @@ static void execlists_submit_request(struct i915_request *request)
        spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
-static struct i915_request *sched_to_request(struct i915_sched_node *node)
-{
-       return container_of(node, struct i915_request, sched);
-}
-
-static struct intel_engine_cs *
-sched_lock_engine(struct i915_sched_node *node, struct intel_engine_cs *locked)
-{
-       struct intel_engine_cs *engine = sched_to_request(node)->engine;
-
-       GEM_BUG_ON(!locked);
-
-       if (engine != locked) {
-               spin_unlock(&locked->timeline.lock);
-               spin_lock(&engine->timeline.lock);
-       }
-
-       return engine;
-}
-
-static void execlists_schedule(struct i915_request *request,
-                              const struct i915_sched_attr *attr)
-{
-       struct i915_priolist *uninitialized_var(pl);
-       struct intel_engine_cs *engine, *last;
-       struct i915_dependency *dep, *p;
-       struct i915_dependency stack;
-       const int prio = attr->priority;
-       LIST_HEAD(dfs);
-
-       GEM_BUG_ON(prio == I915_PRIORITY_INVALID);
-
-       if (i915_request_completed(request))
-               return;
-
-       if (prio <= READ_ONCE(request->sched.attr.priority))
-               return;
-
-       /* Need BKL in order to use the temporary link inside i915_dependency */
-       lockdep_assert_held(&request->i915->drm.struct_mutex);
-
-       stack.signaler = &request->sched;
-       list_add(&stack.dfs_link, &dfs);
-
-       /*
-        * Recursively bump all dependent priorities to match the new request.
-        *
-        * A naive approach would be to use recursion:
-        * static void update_priorities(struct i915_sched_node *node, prio) {
-        *      list_for_each_entry(dep, &node->signalers_list, signal_link)
-        *              update_priorities(dep->signal, prio)
-        *      queue_request(node);
-        * }
-        * but that may have unlimited recursion depth and so runs a very
-        * real risk of overunning the kernel stack. Instead, we build
-        * a flat list of all dependencies starting with the current request.
-        * As we walk the list of dependencies, we add all of its dependencies
-        * to the end of the list (this may include an already visited
-        * request) and continue to walk onwards onto the new dependencies. The
-        * end result is a topological list of requests in reverse order, the
-        * last element in the list is the request we must execute first.
-        */
-       list_for_each_entry(dep, &dfs, dfs_link) {
-               struct i915_sched_node *node = dep->signaler;
-
-               /*
-                * Within an engine, there can be no cycle, but we may
-                * refer to the same dependency chain multiple times
-                * (redundant dependencies are not eliminated) and across
-                * engines.
-                */
-               list_for_each_entry(p, &node->signalers_list, signal_link) {
-                       GEM_BUG_ON(p == dep); /* no cycles! */
-
-                       if (i915_sched_node_signaled(p->signaler))
-                               continue;
-
-                       GEM_BUG_ON(p->signaler->attr.priority < node->attr.priority);
-                       if (prio > READ_ONCE(p->signaler->attr.priority))
-                               list_move_tail(&p->dfs_link, &dfs);
-               }
-       }
-
-       /*
-        * If we didn't need to bump any existing priorities, and we haven't
-        * yet submitted this request (i.e. there is no potential race with
-        * execlists_submit_request()), we can set our own priority and skip
-        * acquiring the engine locks.
-        */
-       if (request->sched.attr.priority == I915_PRIORITY_INVALID) {
-               GEM_BUG_ON(!list_empty(&request->sched.link));
-               request->sched.attr = *attr;
-               if (stack.dfs_link.next == stack.dfs_link.prev)
-                       return;
-               __list_del_entry(&stack.dfs_link);
-       }
-
-       last = NULL;
-       engine = request->engine;
-       spin_lock_irq(&engine->timeline.lock);
-
-       /* Fifo and depth-first replacement ensure our deps execute before us */
-       list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
-               struct i915_sched_node *node = dep->signaler;
-
-               INIT_LIST_HEAD(&dep->dfs_link);
-
-               engine = sched_lock_engine(node, engine);
-
-               if (prio <= node->attr.priority)
-                       continue;
-
-               node->attr.priority = prio;
-               if (!list_empty(&node->link)) {
-                       if (last != engine) {
-                               pl = lookup_priolist(engine, prio);
-                               last = engine;
-                       }
-                       GEM_BUG_ON(pl->priority != prio);
-                       list_move_tail(&node->link, &pl->requests);
-               }
-
-               if (prio > engine->execlists.queue_priority &&
-                   i915_sw_fence_done(&sched_to_request(node)->submit)) {
-                       /* defer submission until after all of our updates */
-                       __update_queue(engine, prio);
-                       tasklet_hi_schedule(&engine->execlists.tasklet);
-               }
-       }
-
-       spin_unlock_irq(&engine->timeline.lock);
-}
-
 static void execlists_context_destroy(struct intel_context *ce)
 {
        GEM_BUG_ON(ce->pin_count);
@@ -1289,6 +1111,28 @@ static void execlists_context_destroy(struct intel_context *ce)
 
 static void execlists_context_unpin(struct intel_context *ce)
 {
+       struct intel_engine_cs *engine;
+
+       /*
+        * The tasklet may still be using a pointer to our state, via an
+        * old request. However, since we know we only unpin the context
+        * on retirement of the following request, we know that the last
+        * request referencing us will have had a completion CS interrupt.
+        * If we see that it is still active, it means that the tasklet hasn't
+        * had the chance to run yet; let it run before we teardown the
+        * reference it may use.
+        */
+       engine = READ_ONCE(ce->active);
+       if (unlikely(engine)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&engine->timeline.lock, flags);
+               process_csb(engine);
+               spin_unlock_irqrestore(&engine->timeline.lock, flags);
+
+               GEM_BUG_ON(READ_ONCE(ce->active));
+       }
+
        i915_gem_context_unpin_hw_id(ce->gem_context);
 
        intel_ring_unpin(ce->ring);
@@ -1392,6 +1236,7 @@ execlists_context_pin(struct intel_engine_cs *engine,
        struct intel_context *ce = to_intel_context(ctx, engine);
 
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
+       GEM_BUG_ON(!ctx->ppgtt);
 
        if (likely(ce->pin_count++))
                return ce;
@@ -1571,18 +1416,6 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch)
 
        batch = emit_lri(batch, lri, ARRAY_SIZE(lri));
 
-       /* WaClearSlmSpaceAtContextSwitch:kbl */
-       /* Actual scratch location is at 128 bytes offset */
-       if (IS_KBL_REVID(engine->i915, 0, KBL_REVID_A0)) {
-               batch = gen8_emit_pipe_control(batch,
-                                              PIPE_CONTROL_FLUSH_L3 |
-                                              PIPE_CONTROL_GLOBAL_GTT_IVB |
-                                              PIPE_CONTROL_CS_STALL |
-                                              PIPE_CONTROL_QW_WRITE,
-                                              i915_scratch_offset(engine->i915)
-                                              + 2 * CACHELINE_BYTES);
-       }
-
        /* WaMediaPoolStateCmdInWABB:bxt,glk */
        if (HAS_POOLED_EU(engine->i915)) {
                /*
@@ -1697,7 +1530,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
        unsigned int i;
        int ret;
 
-       if (GEM_WARN_ON(engine->id != RCS))
+       if (GEM_DEBUG_WARN_ON(engine->id != RCS))
                return -EINVAL;
 
        switch (INTEL_GEN(engine->i915)) {
@@ -1736,8 +1569,8 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
         */
        for (i = 0; i < ARRAY_SIZE(wa_bb_fn); i++) {
                wa_bb[i]->offset = batch_ptr - batch;
-               if (GEM_WARN_ON(!IS_ALIGNED(wa_bb[i]->offset,
-                                           CACHELINE_BYTES))) {
+               if (GEM_DEBUG_WARN_ON(!IS_ALIGNED(wa_bb[i]->offset,
+                                                 CACHELINE_BYTES))) {
                        ret = -EINVAL;
                        break;
                }
@@ -1825,7 +1658,7 @@ static int gen8_init_render_ring(struct intel_engine_cs *engine)
        if (ret)
                return ret;
 
-       intel_whitelist_workarounds_apply(engine);
+       intel_engine_apply_whitelist(engine);
 
        /* We need to disable the AsyncFlip performance optimisations in order
         * to use MI_WAIT_FOR_EVENT within the CS. It should already be
@@ -1848,7 +1681,7 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
        if (ret)
                return ret;
 
-       intel_whitelist_workarounds_apply(engine);
+       intel_engine_apply_whitelist(engine);
 
        return 0;
 }
@@ -1922,7 +1755,7 @@ static void execlists_reset(struct intel_engine_cs *engine,
        unsigned long flags;
        u32 *regs;
 
-       GEM_TRACE("%s request global=%x, current=%d\n",
+       GEM_TRACE("%s request global=%d, current=%d\n",
                  engine->name, request ? request->global_seqno : 0,
                  intel_engine_get_seqno(engine));
 
@@ -2049,8 +1882,7 @@ static int gen8_emit_bb_start(struct i915_request *rq,
         * it is unsafe in case of lite-restore (because the ctx is
         * not idle). PML4 is allocated during ppgtt init so this is
         * not needed in 48-bit.*/
-       if (rq->gem_context->ppgtt &&
-           (intel_engine_flag(rq->engine) & rq->gem_context->ppgtt->pd_dirty_rings) &&
+       if ((intel_engine_flag(rq->engine) & rq->gem_context->ppgtt->pd_dirty_rings) &&
            !i915_vm_is_48bit(&rq->gem_context->ppgtt->vm) &&
            !intel_vgpu_active(rq->i915)) {
                ret = intel_logical_ring_emit_pdps(rq);
@@ -2129,7 +1961,7 @@ static int gen8_emit_flush(struct i915_request *request, u32 mode)
 
        if (mode & EMIT_INVALIDATE) {
                cmd |= MI_INVALIDATE_TLB;
-               if (request->engine->id == VCS)
+               if (request->engine->class == VIDEO_DECODE_CLASS)
                        cmd |= MI_INVALIDATE_BSD;
        }
 
@@ -2261,7 +2093,7 @@ static int gen8_init_rcs_context(struct i915_request *rq)
 {
        int ret;
 
-       ret = intel_ctx_workarounds_emit(rq);
+       ret = intel_engine_emit_ctx_wa(rq);
        if (ret)
                return ret;
 
@@ -2314,7 +2146,7 @@ void intel_execlists_set_default_submission(struct intel_engine_cs *engine)
 {
        engine->submit_request = execlists_submit_request;
        engine->cancel_requests = execlists_cancel_requests;
-       engine->schedule = execlists_schedule;
+       engine->schedule = i915_schedule;
        engine->execlists.tasklet.func = execlists_submission_tasklet;
 
        engine->reset.prepare = execlists_reset_prepare;
@@ -2402,12 +2234,6 @@ logical_ring_setup(struct intel_engine_cs *engine)
        logical_ring_default_irqs(engine);
 }
 
-static bool csb_force_mmio(struct drm_i915_private *i915)
-{
-       /* Older GVT emulation depends upon intercepting CSB mmio */
-       return intel_vgpu_active(i915) && !intel_vgpu_has_hwsp_emulation(i915);
-}
-
 static int logical_ring_init(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *i915 = engine->i915;
@@ -2437,24 +2263,12 @@ static int logical_ring_init(struct intel_engine_cs *engine)
                        upper_32_bits(ce->lrc_desc);
        }
 
-       execlists->csb_read =
-               i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine));
-       if (csb_force_mmio(i915)) {
-               execlists->csb_status = (u32 __force *)
-                       (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0)));
+       execlists->csb_status =
+               &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX];
 
-               execlists->csb_write = (u32 __force *)execlists->csb_read;
-               execlists->csb_write_reset =
-                       _MASKED_FIELD(GEN8_CSB_WRITE_PTR_MASK,
-                                     GEN8_CSB_ENTRIES - 1);
-       } else {
-               execlists->csb_status =
-                       &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX];
+       execlists->csb_write =
+               &engine->status_page.page_addr[intel_hws_csb_write_index(i915)];
 
-               execlists->csb_write =
-                       &engine->status_page.page_addr[intel_hws_csb_write_index(i915)];
-               execlists->csb_write_reset = GEN8_CSB_ENTRIES - 1;
-       }
        reset_csb_pointers(execlists);
 
        return 0;
@@ -2495,6 +2309,7 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
                          ret);
        }
 
+       intel_engine_init_whitelist(engine);
        intel_engine_init_workarounds(engine);
 
        return 0;
@@ -2646,7 +2461,6 @@ static void execlists_init_reg_state(u32 *regs,
                                     struct intel_ring *ring)
 {
        struct drm_i915_private *dev_priv = engine->i915;
-       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: dev_priv->mm.aliasing_ppgtt;
        u32 base = engine->mmio_base;
        bool rcs = engine->class == RENDER_CLASS;
 
@@ -2718,12 +2532,12 @@ static void execlists_init_reg_state(u32 *regs,
        CTX_REG(regs, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(engine, 0), 0);
        CTX_REG(regs, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(engine, 0), 0);
 
-       if (ppgtt && i915_vm_is_48bit(&ppgtt->vm)) {
+       if (i915_vm_is_48bit(&ctx->ppgtt->vm)) {
                /* 64b PPGTT (48bit canonical)
                 * PDP0_DESCRIPTOR contains the base address to PML4 and
                 * other PDP Descriptors are ignored.
                 */
-               ASSIGN_CTX_PML4(ppgtt, regs);
+               ASSIGN_CTX_PML4(ctx->ppgtt, regs);
        }
 
        if (rcs) {
index 3e085c5f2b81bfa87daf161bd96e3eb01da5d4ac..96a8d9524b0c24445972e99c5a3bc958f379b739 100644 (file)
 #include <drm/drm_dp_dual_mode_helper.h>
 #include "intel_drv.h"
 
+/* LSPCON OUI Vendor ID(signatures) */
+#define LSPCON_VENDOR_PARADE_OUI 0x001CF8
+#define LSPCON_VENDOR_MCA_OUI 0x0060AD
+
+/* AUX addresses to write MCA AVI IF */
+#define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
+#define LSPCON_MCA_AVI_IF_CTRL 0x5DF
+#define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
+#define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
+
+/* AUX addresses to write Parade AVI IF */
+#define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
+#define LSPCON_PARADE_AVI_IF_CTRL 0x51E
+#define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
+#define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
+
 static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
 {
        struct intel_digital_port *dig_port =
@@ -50,6 +66,40 @@ static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
        }
 }
 
+static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
+{
+       struct intel_dp *dp = lspcon_to_intel_dp(lspcon);
+       struct drm_dp_dpcd_ident *ident;
+       u32 vendor_oui;
+
+       if (drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd))) {
+               DRM_ERROR("Can't read description\n");
+               return false;
+       }
+
+       ident = &dp->desc.ident;
+       vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
+                     ident->oui[2];
+
+       switch (vendor_oui) {
+       case LSPCON_VENDOR_MCA_OUI:
+               lspcon->vendor = LSPCON_VENDOR_MCA;
+               DRM_DEBUG_KMS("Vendor: Mega Chips\n");
+               break;
+
+       case LSPCON_VENDOR_PARADE_OUI:
+               lspcon->vendor = LSPCON_VENDOR_PARADE;
+               DRM_DEBUG_KMS("Vendor: Parade Tech\n");
+               break;
+
+       default:
+               DRM_ERROR("Invalid/Unknown vendor OUI\n");
+               return false;
+       }
+
+       return true;
+}
+
 static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
 {
        enum drm_lspcon_mode current_mode;
@@ -130,6 +180,21 @@ static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
        return true;
 }
 
+void lspcon_ycbcr420_config(struct drm_connector *connector,
+                           struct intel_crtc_state *crtc_state)
+{
+       const struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_mode *adjusted_mode =
+                                       &crtc_state->base.adjusted_mode;
+
+       if (drm_mode_is_420_only(info, adjusted_mode) &&
+           connector->ycbcr_420_allowed) {
+               crtc_state->port_clock /= 2;
+               crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
+               crtc_state->lspcon_downsampling = true;
+       }
+}
+
 static bool lspcon_probe(struct intel_lspcon *lspcon)
 {
        int retry;
@@ -159,7 +224,18 @@ static bool lspcon_probe(struct intel_lspcon *lspcon)
        /* Yay ... got a LSPCON device */
        DRM_DEBUG_KMS("LSPCON detected\n");
        lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
-       lspcon->active = true;
+
+       /*
+        * In the SW state machine, lets Put LSPCON in PCON mode only.
+        * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
+        * 2.0 sinks.
+        */
+       if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
+               if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
+                       DRM_ERROR("LSPCON mode change to PCON failed\n");
+                       return false;
+               }
+       }
        return true;
 }
 
@@ -185,6 +261,255 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
        DRM_DEBUG_KMS("LSPCON DP descriptor mismatch after resume\n");
 }
 
+static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
+{
+       u8 avi_if_ctrl;
+       u8 retry;
+       ssize_t ret;
+
+       /* Check if LSPCON FW is ready for data */
+       for (retry = 0; retry < 5; retry++) {
+               if (retry)
+                       usleep_range(200, 300);
+
+               ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
+                                      &avi_if_ctrl, 1);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to read AVI IF control\n");
+                       return false;
+               }
+
+               if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
+                       return true;
+       }
+
+       DRM_ERROR("Parade FW not ready to accept AVI IF\n");
+       return false;
+}
+
+static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
+                                                 uint8_t *avi_buf)
+{
+       u8 avi_if_ctrl;
+       u8 block_count = 0;
+       u8 *data;
+       uint16_t reg;
+       ssize_t ret;
+
+       while (block_count < 4) {
+               if (!lspcon_parade_fw_ready(aux)) {
+                       DRM_DEBUG_KMS("LSPCON FW not ready, block %d\n",
+                                     block_count);
+                       return false;
+               }
+
+               reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
+               data = avi_buf + block_count * 8;
+               ret = drm_dp_dpcd_write(aux, reg, data, 8);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to write AVI IF block %d\n",
+                                 block_count);
+                       return false;
+               }
+
+               /*
+                * Once a block of data is written, we have to inform the FW
+                * about this by writing into avi infoframe control register:
+                * - set the kickoff bit[7] to 1
+                * - write the block no. to bits[1:0]
+                */
+               reg = LSPCON_PARADE_AVI_IF_CTRL;
+               avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
+               ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
+               if (ret < 0) {
+                       DRM_ERROR("Failed to update (0x%x), block %d\n",
+                                 reg, block_count);
+                       return false;
+               }
+
+               block_count++;
+       }
+
+       DRM_DEBUG_KMS("Wrote AVI IF blocks successfully\n");
+       return true;
+}
+
+static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
+                                              const uint8_t *frame,
+                                              ssize_t len)
+{
+       uint8_t avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
+
+       /*
+        * Parade's frames contains 32 bytes of data, divided
+        * into 4 frames:
+        *      Token byte (first byte of first frame, must be non-zero)
+        *      HB0 to HB2       from AVI IF (3 bytes header)
+        *      PB0 to PB27 from AVI IF (28 bytes data)
+        * So it should look like this
+        *      first block: | <token> <HB0-HB2> <DB0-DB3> |
+        *      next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
+        */
+
+       if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
+               DRM_ERROR("Invalid length of infoframes\n");
+               return false;
+       }
+
+       memcpy(&avi_if[1], frame, len);
+
+       if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
+               DRM_DEBUG_KMS("Failed to write infoframe blocks\n");
+               return false;
+       }
+
+       return true;
+}
+
+static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
+                                           const uint8_t *buffer, ssize_t len)
+{
+       int ret;
+       uint32_t val = 0;
+       uint32_t retry;
+       uint16_t reg;
+       const uint8_t *data = buffer;
+
+       reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
+       while (val < len) {
+               /* DPCD write for AVI IF can fail on a slow FW day, so retry */
+               for (retry = 0; retry < 5; retry++) {
+                       ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
+                       if (ret == 1) {
+                               break;
+                       } else if (retry < 4) {
+                               mdelay(50);
+                               continue;
+                       } else {
+                               DRM_ERROR("DPCD write failed at:0x%x\n", reg);
+                               return false;
+                       }
+               }
+               val++; reg++; data++;
+       }
+
+       val = 0;
+       reg = LSPCON_MCA_AVI_IF_CTRL;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
+       val &= ~LSPCON_MCA_AVI_IF_HANDLED;
+       val |= LSPCON_MCA_AVI_IF_KICKOFF;
+
+       ret = drm_dp_dpcd_write(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       val = 0;
+       ret = drm_dp_dpcd_read(aux, reg, &val, 1);
+       if (ret < 0) {
+               DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
+               return false;
+       }
+
+       if (val == LSPCON_MCA_AVI_IF_HANDLED)
+               DRM_DEBUG_KMS("AVI IF handled by FW\n");
+
+       return true;
+}
+
+void lspcon_write_infoframe(struct intel_encoder *encoder,
+                           const struct intel_crtc_state *crtc_state,
+                           unsigned int type,
+                           const void *frame, ssize_t len)
+{
+       bool ret;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_lspcon *lspcon = enc_to_intel_lspcon(&encoder->base);
+
+       /* LSPCON only needs AVI IF */
+       if (type != HDMI_INFOFRAME_TYPE_AVI)
+               return;
+
+       if (lspcon->vendor == LSPCON_VENDOR_MCA)
+               ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
+                                                     frame, len);
+       else
+               ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
+                                                        frame, len);
+
+       if (!ret) {
+               DRM_ERROR("Failed to write AVI infoframes\n");
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("AVI infoframes updated successfully\n");
+}
+
+void lspcon_set_infoframes(struct intel_encoder *encoder,
+                          bool enable,
+                          const struct intel_crtc_state *crtc_state,
+                          const struct drm_connector_state *conn_state)
+{
+       ssize_t ret;
+       union hdmi_infoframe frame;
+       uint8_t buf[VIDEO_DIP_DATA_SIZE];
+       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+       struct intel_lspcon *lspcon = &dig_port->lspcon;
+       struct intel_dp *intel_dp = &dig_port->dp;
+       struct drm_connector *connector = &intel_dp->attached_connector->base;
+       const struct drm_display_mode *mode = &crtc_state->base.adjusted_mode;
+       bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
+
+       if (!lspcon->active) {
+               DRM_ERROR("Writing infoframes while LSPCON disabled ?\n");
+               return;
+       }
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
+                                                      mode, is_hdmi2_sink);
+       if (ret < 0) {
+               DRM_ERROR("couldn't fill AVI infoframe\n");
+               return;
+       }
+
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
+               if (crtc_state->lspcon_downsampling)
+                       frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+               else
+                       frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+       } else {
+               frame.avi.colorspace = HDMI_COLORSPACE_RGB;
+       }
+
+       drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode,
+                                          crtc_state->limited_color_range ?
+                                          HDMI_QUANTIZATION_RANGE_LIMITED :
+                                          HDMI_QUANTIZATION_RANGE_FULL,
+                                          false, is_hdmi2_sink);
+
+       ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
+       if (ret < 0) {
+               DRM_ERROR("Failed to pack AVI IF\n");
+               return;
+       }
+
+       dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
+                                 buf, ret);
+}
+
+bool lspcon_infoframe_enabled(struct intel_encoder *encoder,
+                             const struct intel_crtc_state *pipe_config)
+{
+       return enc_to_intel_lspcon(&encoder->base)->active;
+}
+
 void lspcon_resume(struct intel_lspcon *lspcon)
 {
        enum drm_lspcon_mode expected_mode;
@@ -216,6 +541,7 @@ bool lspcon_init(struct intel_digital_port *intel_dig_port)
        struct intel_lspcon *lspcon = &intel_dig_port->lspcon;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_connector *connector = &dp->attached_connector->base;
 
        if (!HAS_LSPCON(dev_priv)) {
                DRM_ERROR("LSPCON is not supported on this platform\n");
@@ -230,25 +556,18 @@ bool lspcon_init(struct intel_digital_port *intel_dig_port)
                return false;
        }
 
-       /*
-       * In the SW state machine, lets Put LSPCON in PCON mode only.
-       * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
-       * 2.0 sinks.
-       */
-       if (lspcon->active && lspcon->mode != DRM_LSPCON_MODE_PCON) {
-               if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
-                       DRM_ERROR("LSPCON mode change to PCON failed\n");
-                       return false;
-               }
-       }
-
        if (!intel_dp_read_dpcd(dp)) {
                DRM_ERROR("LSPCON DPCD read failed\n");
                return false;
        }
 
-       drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd));
+       if (!lspcon_detect_vendor(lspcon)) {
+               DRM_ERROR("LSPCON vendor detection failed\n");
+               return false;
+       }
 
+       connector->ycbcr_420_allowed = true;
+       lspcon->active = true;
        DRM_DEBUG_KMS("Success: LSPCON init\n");
        return true;
 }
index f9f3b0885ba595be9dad319ee78060c0ec731a0c..e6c5d985ea0afd9d6f8eadb45228dad3ee6323f0 100644 (file)
 #include <linux/acpi.h>
 
 /* Private structure for the integrated LVDS support */
-struct intel_lvds_connector {
-       struct intel_connector base;
-};
-
 struct intel_lvds_pps {
        /* 100us units */
        int t1_t2;
@@ -70,7 +66,7 @@ struct intel_lvds_encoder {
        struct intel_lvds_pps init_pps;
        u32 init_lvds_val;
 
-       struct intel_lvds_connector *attached_connector;
+       struct intel_connector *attached_connector;
 };
 
 static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
@@ -78,11 +74,6 @@ static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
        return container_of(encoder, struct intel_lvds_encoder, base.base);
 }
 
-static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *connector)
-{
-       return container_of(connector, struct intel_lvds_connector, base.base);
-}
-
 bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv,
                             i915_reg_t lvds_reg, enum pipe *pipe)
 {
@@ -396,7 +387,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
        struct intel_lvds_encoder *lvds_encoder =
                to_lvds_encoder(&intel_encoder->base);
        struct intel_connector *intel_connector =
-               &lvds_encoder->attached_connector->base;
+               lvds_encoder->attached_connector;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
        struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
        unsigned int lvds_bpp;
@@ -418,6 +409,8 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
                pipe_config->pipe_bpp = lvds_bpp;
        }
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+
        /*
         * We have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
@@ -461,15 +454,15 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
-       struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector);
+       struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
 
        /* use cached edid if we have one */
-       if (!IS_ERR_OR_NULL(lvds_connector->base.edid))
-               return drm_add_edid_modes(connector, lvds_connector->base.edid);
+       if (!IS_ERR_OR_NULL(intel_connector->edid))
+               return drm_add_edid_modes(connector, intel_connector->edid);
 
-       mode = drm_mode_duplicate(dev, lvds_connector->base.panel.fixed_mode);
+       mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode);
        if (mode == NULL)
                return 0;
 
@@ -477,27 +470,6 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
        return 1;
 }
 
-/**
- * intel_lvds_destroy - unregister and free LVDS structures
- * @connector: connector to free
- *
- * Unregister the DDC bus for this connector then free the driver private
- * structure.
- */
-static void intel_lvds_destroy(struct drm_connector *connector)
-{
-       struct intel_lvds_connector *lvds_connector =
-               to_lvds_connector(connector);
-
-       if (!IS_ERR_OR_NULL(lvds_connector->base.edid))
-               kfree(lvds_connector->base.edid);
-
-       intel_panel_fini(&lvds_connector->base.panel);
-
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
        .get_modes = intel_lvds_get_modes,
        .mode_valid = intel_lvds_mode_valid,
@@ -511,7 +483,7 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
        .atomic_set_property = intel_digital_connector_atomic_set_property,
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_lvds_destroy,
+       .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
@@ -802,8 +774,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
                return i915_modparams.lvds_channel_mode == 2;
 
        /* single channel LVDS is limited to 112 MHz */
-       if (lvds_encoder->attached_connector->base.panel.fixed_mode->clock
-           > 112999)
+       if (lvds_encoder->attached_connector->panel.fixed_mode->clock > 112999)
                return true;
 
        if (dmi_check_system(intel_dual_link_lvds))
@@ -858,7 +829,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
        struct drm_device *dev = &dev_priv->drm;
        struct intel_lvds_encoder *lvds_encoder;
        struct intel_encoder *intel_encoder;
-       struct intel_lvds_connector *lvds_connector;
        struct intel_connector *intel_connector;
        struct drm_connector *connector;
        struct drm_encoder *encoder;
@@ -911,23 +881,16 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
        if (!lvds_encoder)
                return;
 
-       lvds_connector = kzalloc(sizeof(*lvds_connector), GFP_KERNEL);
-       if (!lvds_connector) {
-               kfree(lvds_encoder);
-               return;
-       }
-
-       if (intel_connector_init(&lvds_connector->base) < 0) {
-               kfree(lvds_connector);
+       intel_connector = intel_connector_alloc();
+       if (!intel_connector) {
                kfree(lvds_encoder);
                return;
        }
 
-       lvds_encoder->attached_connector = lvds_connector;
+       lvds_encoder->attached_connector = intel_connector;
 
        intel_encoder = &lvds_encoder->base;
        encoder = &intel_encoder->base;
-       intel_connector = &lvds_connector->base;
        connector = &intel_connector->base;
        drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
                           DRM_MODE_CONNECTOR_LVDS);
@@ -1008,7 +971,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
        } else {
                edid = ERR_PTR(-ENOENT);
        }
-       lvds_connector->base.edid = edid;
+       intel_connector->edid = edid;
 
        list_for_each_entry(scan, &connector->probed_modes, head) {
                if (scan->type & DRM_MODE_TYPE_PREFERRED) {
@@ -1072,6 +1035,6 @@ failed:
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
        kfree(lvds_encoder);
-       kfree(lvds_connector);
+       intel_connector_free(intel_connector);
        return;
 }
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
deleted file mode 100644 (file)
index ca44bf3..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007, 2010 Intel Corporation
- *   Jesse Barnes <jesse.barnes@intel.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (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.
- */
-
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <drm/drm_edid.h>
-#include <drm/drmP.h>
-#include "intel_drv.h"
-#include "i915_drv.h"
-
-/**
- * intel_connector_update_modes - update connector from edid
- * @connector: DRM connector device to use
- * @edid: previously read EDID information
- */
-int intel_connector_update_modes(struct drm_connector *connector,
-                               struct edid *edid)
-{
-       int ret;
-
-       drm_connector_update_edid_property(connector, edid);
-       ret = drm_add_edid_modes(connector, edid);
-
-       return ret;
-}
-
-/**
- * intel_ddc_get_modes - get modelist from monitor
- * @connector: DRM connector device to use
- * @adapter: i2c adapter
- *
- * Fetch the EDID information from @connector using the DDC bus.
- */
-int intel_ddc_get_modes(struct drm_connector *connector,
-                       struct i2c_adapter *adapter)
-{
-       struct edid *edid;
-       int ret;
-
-       edid = drm_get_edid(connector, adapter);
-       if (!edid)
-               return 0;
-
-       ret = intel_connector_update_modes(connector, edid);
-       kfree(edid);
-
-       return ret;
-}
-
-static const struct drm_prop_enum_list force_audio_names[] = {
-       { HDMI_AUDIO_OFF_DVI, "force-dvi" },
-       { HDMI_AUDIO_OFF, "off" },
-       { HDMI_AUDIO_AUTO, "auto" },
-       { HDMI_AUDIO_ON, "on" },
-};
-
-void
-intel_attach_force_audio_property(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_property *prop;
-
-       prop = dev_priv->force_audio_property;
-       if (prop == NULL) {
-               prop = drm_property_create_enum(dev, 0,
-                                          "audio",
-                                          force_audio_names,
-                                          ARRAY_SIZE(force_audio_names));
-               if (prop == NULL)
-                       return;
-
-               dev_priv->force_audio_property = prop;
-       }
-       drm_object_attach_property(&connector->base, prop, 0);
-}
-
-static const struct drm_prop_enum_list broadcast_rgb_names[] = {
-       { INTEL_BROADCAST_RGB_AUTO, "Automatic" },
-       { INTEL_BROADCAST_RGB_FULL, "Full" },
-       { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" },
-};
-
-void
-intel_attach_broadcast_rgb_property(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_property *prop;
-
-       prop = dev_priv->broadcast_rgb_property;
-       if (prop == NULL) {
-               prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
-                                          "Broadcast RGB",
-                                          broadcast_rgb_names,
-                                          ARRAY_SIZE(broadcast_rgb_names));
-               if (prop == NULL)
-                       return;
-
-               dev_priv->broadcast_rgb_property = prop;
-       }
-
-       drm_object_attach_property(&connector->base, prop, 0);
-}
-
-void
-intel_attach_aspect_ratio_property(struct drm_connector *connector)
-{
-       if (!drm_mode_create_aspect_ratio_property(connector->dev))
-               drm_object_attach_property(&connector->base,
-                       connector->dev->mode_config.aspect_ratio_property,
-                       DRM_MODE_PICTURE_ASPECT_NONE);
-}
index e034b4166d322f8182a9f31bcfb1cd224c686214..b8f106d9ecf8b1be6286b2dfaeac1c5188629528 100644 (file)
@@ -773,70 +773,6 @@ static void intel_setup_cadls(struct drm_i915_private *dev_priv)
                opregion->acpi->cadl[i] = 0;
 }
 
-void intel_opregion_register(struct drm_i915_private *dev_priv)
-{
-       struct intel_opregion *opregion = &dev_priv->opregion;
-
-       if (!opregion->header)
-               return;
-
-       if (opregion->acpi) {
-               intel_didl_outputs(dev_priv);
-               intel_setup_cadls(dev_priv);
-
-               /* Notify BIOS we are ready to handle ACPI video ext notifs.
-                * Right now, all the events are handled by the ACPI video module.
-                * We don't actually need to do anything with them. */
-               opregion->acpi->csts = 0;
-               opregion->acpi->drdy = 1;
-
-               opregion->acpi_notifier.notifier_call = intel_opregion_video_event;
-               register_acpi_notifier(&opregion->acpi_notifier);
-       }
-
-       if (opregion->asle) {
-               opregion->asle->tche = ASLE_TCHE_BLC_EN;
-               opregion->asle->ardy = ASLE_ARDY_READY;
-       }
-}
-
-void intel_opregion_unregister(struct drm_i915_private *dev_priv)
-{
-       struct intel_opregion *opregion = &dev_priv->opregion;
-
-       if (!opregion->header)
-               return;
-
-       if (opregion->asle)
-               opregion->asle->ardy = ASLE_ARDY_NOT_READY;
-
-       cancel_work_sync(&dev_priv->opregion.asle_work);
-
-       if (opregion->acpi) {
-               opregion->acpi->drdy = 0;
-
-               unregister_acpi_notifier(&opregion->acpi_notifier);
-               opregion->acpi_notifier.notifier_call = NULL;
-       }
-
-       /* just clear all opregion memory pointers now */
-       memunmap(opregion->header);
-       if (opregion->rvda) {
-               memunmap(opregion->rvda);
-               opregion->rvda = NULL;
-       }
-       if (opregion->vbt_firmware) {
-               kfree(opregion->vbt_firmware);
-               opregion->vbt_firmware = NULL;
-       }
-       opregion->header = NULL;
-       opregion->acpi = NULL;
-       opregion->swsci = NULL;
-       opregion->asle = NULL;
-       opregion->vbt = NULL;
-       opregion->lid_state = NULL;
-}
-
 static void swsci_setup(struct drm_i915_private *dev_priv)
 {
        struct intel_opregion *opregion = &dev_priv->opregion;
@@ -1115,3 +1051,97 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
 
        return ret - 1;
 }
+
+void intel_opregion_register(struct drm_i915_private *i915)
+{
+       struct intel_opregion *opregion = &i915->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               opregion->acpi_notifier.notifier_call =
+                       intel_opregion_video_event;
+               register_acpi_notifier(&opregion->acpi_notifier);
+       }
+
+       intel_opregion_resume(i915);
+}
+
+void intel_opregion_resume(struct drm_i915_private *i915)
+{
+       struct intel_opregion *opregion = &i915->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               intel_didl_outputs(i915);
+               intel_setup_cadls(i915);
+
+               /*
+                * Notify BIOS we are ready to handle ACPI video ext notifs.
+                * Right now, all the events are handled by the ACPI video
+                * module. We don't actually need to do anything with them.
+                */
+               opregion->acpi->csts = 0;
+               opregion->acpi->drdy = 1;
+       }
+
+       if (opregion->asle) {
+               opregion->asle->tche = ASLE_TCHE_BLC_EN;
+               opregion->asle->ardy = ASLE_ARDY_READY;
+       }
+
+       intel_opregion_notify_adapter(i915, PCI_D0);
+}
+
+void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state)
+{
+       struct intel_opregion *opregion = &i915->opregion;
+
+       if (!opregion->header)
+               return;
+
+       intel_opregion_notify_adapter(i915, state);
+
+       if (opregion->asle)
+               opregion->asle->ardy = ASLE_ARDY_NOT_READY;
+
+       cancel_work_sync(&i915->opregion.asle_work);
+
+       if (opregion->acpi)
+               opregion->acpi->drdy = 0;
+}
+
+void intel_opregion_unregister(struct drm_i915_private *i915)
+{
+       struct intel_opregion *opregion = &i915->opregion;
+
+       intel_opregion_suspend(i915, PCI_D1);
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi_notifier.notifier_call) {
+               unregister_acpi_notifier(&opregion->acpi_notifier);
+               opregion->acpi_notifier.notifier_call = NULL;
+       }
+
+       /* just clear all opregion memory pointers now */
+       memunmap(opregion->header);
+       if (opregion->rvda) {
+               memunmap(opregion->rvda);
+               opregion->rvda = NULL;
+       }
+       if (opregion->vbt_firmware) {
+               kfree(opregion->vbt_firmware);
+               opregion->vbt_firmware = NULL;
+       }
+       opregion->header = NULL;
+       opregion->acpi = NULL;
+       opregion->swsci = NULL;
+       opregion->asle = NULL;
+       opregion->vbt = NULL;
+       opregion->lid_state = NULL;
+}
index e8498a8cda3d1c9850f386bb00bfef90622fa12c..4aa68ffbd30eba9d895517b1cbe0c2c48c825578 100644 (file)
@@ -57,8 +57,14 @@ struct intel_opregion {
 #ifdef CONFIG_ACPI
 
 int intel_opregion_setup(struct drm_i915_private *dev_priv);
+
 void intel_opregion_register(struct drm_i915_private *dev_priv);
 void intel_opregion_unregister(struct drm_i915_private *dev_priv);
+
+void intel_opregion_resume(struct drm_i915_private *dev_priv);
+void intel_opregion_suspend(struct drm_i915_private *dev_priv,
+                           pci_power_t state);
+
 void intel_opregion_asle_intr(struct drm_i915_private *dev_priv);
 int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
                                  bool enable);
@@ -81,6 +87,15 @@ static inline void intel_opregion_unregister(struct drm_i915_private *dev_priv)
 {
 }
 
+static inline void intel_opregion_resume(struct drm_i915_private *dev_priv)
+{
+}
+
+static inline void intel_opregion_suspend(struct drm_i915_private *dev_priv,
+                                         pci_power_t state)
+{
+}
+
 static inline void intel_opregion_asle_intr(struct drm_i915_private *dev_priv)
 {
 }
index 72eb7e48e8bc0c8f0e721f4bbfe3acc458b33ed5..20ea7c99d13a06e73a52b8d5b69866b8f35a32ad 100644 (file)
@@ -1338,7 +1338,7 @@ err_put_bo:
        return err;
 }
 
-void intel_setup_overlay(struct drm_i915_private *dev_priv)
+void intel_overlay_setup(struct drm_i915_private *dev_priv)
 {
        struct intel_overlay *overlay;
        int ret;
@@ -1387,7 +1387,7 @@ out_free:
        kfree(overlay);
 }
 
-void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
+void intel_overlay_cleanup(struct drm_i915_private *dev_priv)
 {
        struct intel_overlay *overlay;
 
index 4a9f139e7b7383c8f244bac833679c3b5302214b..e6cd7b55c0182425cb7eb3bc32c9250d8cf7f601 100644 (file)
@@ -111,7 +111,7 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
        /* Native modes don't need fitting */
        if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
            adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h &&
-           !pipe_config->ycbcr420)
+           pipe_config->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
                goto done;
 
        switch (fitting_mode) {
@@ -505,7 +505,7 @@ static u32 _vlv_get_backlight(struct drm_i915_private *dev_priv, enum pipe pipe)
 static u32 vlv_get_backlight(struct intel_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       enum pipe pipe = intel_connector_get_pipe(connector);
 
        return _vlv_get_backlight(dev_priv, pipe);
 }
@@ -763,7 +763,7 @@ static void pwm_disable_backlight(const struct drm_connector_state *old_conn_sta
        struct intel_panel *panel = &connector->panel;
 
        /* Disable the backlight */
-       pwm_config(panel->backlight.pwm, 0, CRC_PMIC_PWM_PERIOD_NS);
+       intel_panel_actually_set_backlight(old_conn_state, 0);
        usleep_range(2000, 3000);
        pwm_disable(panel->backlight.pwm);
 }
@@ -1814,11 +1814,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
        return 0;
 }
 
-void intel_panel_destroy_backlight(struct drm_connector *connector)
+static void intel_panel_destroy_backlight(struct intel_panel *panel)
 {
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct intel_panel *panel = &intel_connector->panel;
-
        /* dispose of the pwm */
        if (panel->backlight.pwm)
                pwm_put(panel->backlight.pwm);
@@ -1923,6 +1920,8 @@ void intel_panel_fini(struct intel_panel *panel)
        struct intel_connector *intel_connector =
                container_of(panel, struct intel_connector, panel);
 
+       intel_panel_destroy_backlight(panel);
+
        if (panel->fixed_mode)
                drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
 
index 3fe358db12768f23a2fcf7fe971821c4cac3f1b9..a26b4eddda252659d94f5c6cab89b895ddf348a9 100644 (file)
@@ -3198,7 +3198,8 @@ static int ilk_compute_intermediate_wm(struct drm_device *dev,
         * and after the vblank.
         */
        *a = newstate->wm.ilk.optimal;
-       if (!newstate->base.active || drm_atomic_crtc_needs_modeset(&newstate->base))
+       if (!newstate->base.active || drm_atomic_crtc_needs_modeset(&newstate->base) ||
+           intel_state->skip_intermediate_wm)
                return 0;
 
        a->pipe_enabled |= b->pipe_enabled;
@@ -3650,15 +3651,8 @@ static bool skl_needs_memory_bw_wa(struct intel_atomic_state *state)
 static bool
 intel_has_sagv(struct drm_i915_private *dev_priv)
 {
-       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) ||
-           IS_CANNONLAKE(dev_priv))
-               return true;
-
-       if (IS_SKYLAKE(dev_priv) &&
-           dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED)
-               return true;
-
-       return false;
+       return (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) &&
+               dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED;
 }
 
 /*
@@ -3822,7 +3816,7 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state)
 
 static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
                              const struct intel_crtc_state *cstate,
-                             const unsigned int total_data_rate,
+                             const u64 total_data_rate,
                              const int num_active,
                              struct skl_ddb_allocation *ddb)
 {
@@ -3836,12 +3830,12 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
                return ddb_size - 4; /* 4 blocks for bypass path allocation */
 
        adjusted_mode = &cstate->base.adjusted_mode;
-       total_data_bw = (u64)total_data_rate * drm_mode_vrefresh(adjusted_mode);
+       total_data_bw = total_data_rate * drm_mode_vrefresh(adjusted_mode);
 
        /*
         * 12GB/s is maximum BW supported by single DBuf slice.
         */
-       if (total_data_bw >= GBps(12) || num_active > 1) {
+       if (num_active > 1 || total_data_bw >= GBps(12)) {
                ddb->enabled_slices = 2;
        } else {
                ddb->enabled_slices = 1;
@@ -3852,16 +3846,15 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
 }
 
 static void
-skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
+skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
                                   const struct intel_crtc_state *cstate,
-                                  const unsigned int total_data_rate,
+                                  const u64 total_data_rate,
                                   struct skl_ddb_allocation *ddb,
                                   struct skl_ddb_entry *alloc, /* out */
                                   int *num_active /* out */)
 {
        struct drm_atomic_state *state = cstate->base.state;
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *for_crtc = cstate->base.crtc;
        const struct drm_crtc_state *crtc_state;
        const struct drm_crtc *crtc;
@@ -3958,73 +3951,68 @@ static void
 skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
                           const enum pipe pipe,
                           const enum plane_id plane_id,
-                          struct skl_ddb_allocation *ddb /* out */)
+                          struct skl_ddb_entry *ddb_y,
+                          struct skl_ddb_entry *ddb_uv)
 {
-       u32 val, val2 = 0;
-       int fourcc, pixel_format;
+       u32 val, val2;
+       u32 fourcc = 0;
 
        /* Cursor doesn't support NV12/planar, so no extra calculation needed */
        if (plane_id == PLANE_CURSOR) {
                val = I915_READ(CUR_BUF_CFG(pipe));
-               skl_ddb_entry_init_from_hw(dev_priv,
-                                          &ddb->plane[pipe][plane_id], val);
+               skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
                return;
        }
 
        val = I915_READ(PLANE_CTL(pipe, plane_id));
 
        /* No DDB allocated for disabled planes */
-       if (!(val & PLANE_CTL_ENABLE))
-               return;
-
-       pixel_format = val & PLANE_CTL_FORMAT_MASK;
-       fourcc = skl_format_to_fourcc(pixel_format,
-                                     val & PLANE_CTL_ORDER_RGBX,
-                                     val & PLANE_CTL_ALPHA_MASK);
+       if (val & PLANE_CTL_ENABLE)
+               fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK,
+                                             val & PLANE_CTL_ORDER_RGBX,
+                                             val & PLANE_CTL_ALPHA_MASK);
 
-       val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
-       /*
-        * FIXME: add proper NV12 support for ICL. Avoid reading unclaimed
-        * registers for now.
-        */
-       if (INTEL_GEN(dev_priv) < 11)
+       if (INTEL_GEN(dev_priv) >= 11) {
+               val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
+               skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
+       } else {
+               val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
                val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id));
 
-       if (fourcc == DRM_FORMAT_NV12) {
-               skl_ddb_entry_init_from_hw(dev_priv,
-                                          &ddb->plane[pipe][plane_id], val2);
-               skl_ddb_entry_init_from_hw(dev_priv,
-                                          &ddb->uv_plane[pipe][plane_id], val);
-       } else {
-               skl_ddb_entry_init_from_hw(dev_priv,
-                                          &ddb->plane[pipe][plane_id], val);
+               if (fourcc == DRM_FORMAT_NV12)
+                       swap(val, val2);
+
+               skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
+               skl_ddb_entry_init_from_hw(dev_priv, ddb_uv, val2);
        }
 }
 
-void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
-                         struct skl_ddb_allocation *ddb /* out */)
+void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
+                              struct skl_ddb_entry *ddb_y,
+                              struct skl_ddb_entry *ddb_uv)
 {
-       struct intel_crtc *crtc;
-
-       memset(ddb, 0, sizeof(*ddb));
-
-       ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum intel_display_power_domain power_domain;
+       enum pipe pipe = crtc->pipe;
+       enum plane_id plane_id;
 
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               enum intel_display_power_domain power_domain;
-               enum plane_id plane_id;
-               enum pipe pipe = crtc->pipe;
+       power_domain = POWER_DOMAIN_PIPE(pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+               return;
 
-               power_domain = POWER_DOMAIN_PIPE(pipe);
-               if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
-                       continue;
+       for_each_plane_id_on_crtc(crtc, plane_id)
+               skl_ddb_get_hw_plane_state(dev_priv, pipe,
+                                          plane_id,
+                                          &ddb_y[plane_id],
+                                          &ddb_uv[plane_id]);
 
-               for_each_plane_id_on_crtc(crtc, plane_id)
-                       skl_ddb_get_hw_plane_state(dev_priv, pipe,
-                                                  plane_id, ddb);
+       intel_display_power_put(dev_priv, power_domain);
+}
 
-               intel_display_power_put(dev_priv, power_domain);
-       }
+void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
+                         struct skl_ddb_allocation *ddb /* out */)
+{
+       ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
 }
 
 /*
@@ -4177,23 +4165,24 @@ int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
        return 0;
 }
 
-static unsigned int
+static u64
 skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
-                            const struct drm_plane_state *pstate,
+                            const struct intel_plane_state *intel_pstate,
                             const int plane)
 {
-       struct intel_plane *intel_plane = to_intel_plane(pstate->plane);
-       struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate);
+       struct intel_plane *intel_plane =
+               to_intel_plane(intel_pstate->base.plane);
        uint32_t data_rate;
        uint32_t width = 0, height = 0;
        struct drm_framebuffer *fb;
        u32 format;
        uint_fixed_16_16_t down_scale_amount;
+       u64 rate;
 
        if (!intel_pstate->base.visible)
                return 0;
 
-       fb = pstate->fb;
+       fb = intel_pstate->base.fb;
        format = fb->format->format;
 
        if (intel_plane->id == PLANE_CURSOR)
@@ -4215,28 +4204,26 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
                height /= 2;
        }
 
-       data_rate = width * height * fb->format->cpp[plane];
+       data_rate = width * height;
 
        down_scale_amount = skl_plane_downscale_amount(cstate, intel_pstate);
 
-       return mul_round_up_u32_fixed16(data_rate, down_scale_amount);
+       rate = mul_round_up_u32_fixed16(data_rate, down_scale_amount);
+
+       rate *= fb->format->cpp[plane];
+       return rate;
 }
 
-/*
- * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching
- * a 8192x4096@32bpp framebuffer:
- *   3 * 4096 * 8192  * 4 < 2^32
- */
-static unsigned int
+static u64
 skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate,
-                                unsigned int *plane_data_rate,
-                                unsigned int *uv_plane_data_rate)
+                                u64 *plane_data_rate,
+                                u64 *uv_plane_data_rate)
 {
        struct drm_crtc_state *cstate = &intel_cstate->base;
        struct drm_atomic_state *state = cstate->state;
        struct drm_plane *plane;
        const struct drm_plane_state *pstate;
-       unsigned int total_data_rate = 0;
+       u64 total_data_rate = 0;
 
        if (WARN_ON(!state))
                return 0;
@@ -4244,26 +4231,81 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate,
        /* Calculate and cache data rate for each plane */
        drm_atomic_crtc_state_for_each_plane_state(plane, pstate, cstate) {
                enum plane_id plane_id = to_intel_plane(plane)->id;
-               unsigned int rate;
+               u64 rate;
+               const struct intel_plane_state *intel_pstate =
+                       to_intel_plane_state(pstate);
 
                /* packed/y */
                rate = skl_plane_relative_data_rate(intel_cstate,
-                                                   pstate, 0);
+                                                   intel_pstate, 0);
                plane_data_rate[plane_id] = rate;
-
                total_data_rate += rate;
 
                /* uv-plane */
                rate = skl_plane_relative_data_rate(intel_cstate,
-                                                   pstate, 1);
+                                                   intel_pstate, 1);
                uv_plane_data_rate[plane_id] = rate;
-
                total_data_rate += rate;
        }
 
        return total_data_rate;
 }
 
+static u64
+icl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate,
+                                u64 *plane_data_rate)
+{
+       struct drm_crtc_state *cstate = &intel_cstate->base;
+       struct drm_atomic_state *state = cstate->state;
+       struct drm_plane *plane;
+       const struct drm_plane_state *pstate;
+       u64 total_data_rate = 0;
+
+       if (WARN_ON(!state))
+               return 0;
+
+       /* Calculate and cache data rate for each plane */
+       drm_atomic_crtc_state_for_each_plane_state(plane, pstate, cstate) {
+               const struct intel_plane_state *intel_pstate =
+                       to_intel_plane_state(pstate);
+               enum plane_id plane_id = to_intel_plane(plane)->id;
+               u64 rate;
+
+               if (!intel_pstate->linked_plane) {
+                       rate = skl_plane_relative_data_rate(intel_cstate,
+                                                           intel_pstate, 0);
+                       plane_data_rate[plane_id] = rate;
+                       total_data_rate += rate;
+               } else {
+                       enum plane_id y_plane_id;
+
+                       /*
+                        * The slave plane might not iterate in
+                        * drm_atomic_crtc_state_for_each_plane_state(),
+                        * and needs the master plane state which may be
+                        * NULL if we try get_new_plane_state(), so we
+                        * always calculate from the master.
+                        */
+                       if (intel_pstate->slave)
+                               continue;
+
+                       /* Y plane rate is calculated on the slave */
+                       rate = skl_plane_relative_data_rate(intel_cstate,
+                                                           intel_pstate, 0);
+                       y_plane_id = intel_pstate->linked_plane->id;
+                       plane_data_rate[y_plane_id] = rate;
+                       total_data_rate += rate;
+
+                       rate = skl_plane_relative_data_rate(intel_cstate,
+                                                           intel_pstate, 1);
+                       plane_data_rate[plane_id] = rate;
+                       total_data_rate += rate;
+               }
+       }
+
+       return total_data_rate;
+}
+
 static uint16_t
 skl_ddb_min_alloc(const struct drm_plane_state *pstate, const int plane)
 {
@@ -4336,15 +4378,25 @@ skl_ddb_calc_min(const struct intel_crtc_state *cstate, int num_active,
 
        drm_atomic_crtc_state_for_each_plane_state(plane, pstate, &cstate->base) {
                enum plane_id plane_id = to_intel_plane(plane)->id;
+               struct intel_plane_state *plane_state = to_intel_plane_state(pstate);
 
                if (plane_id == PLANE_CURSOR)
                        continue;
 
-               if (!pstate->visible)
+               /* slave plane must be invisible and calculated from master */
+               if (!pstate->visible || WARN_ON(plane_state->slave))
                        continue;
 
-               minimum[plane_id] = skl_ddb_min_alloc(pstate, 0);
-               uv_minimum[plane_id] = skl_ddb_min_alloc(pstate, 1);
+               if (!plane_state->linked_plane) {
+                       minimum[plane_id] = skl_ddb_min_alloc(pstate, 0);
+                       uv_minimum[plane_id] = skl_ddb_min_alloc(pstate, 1);
+               } else {
+                       enum plane_id y_plane_id =
+                               plane_state->linked_plane->id;
+
+                       minimum[y_plane_id] = skl_ddb_min_alloc(pstate, 0);
+                       minimum[plane_id] = skl_ddb_min_alloc(pstate, 1);
+               }
        }
 
        minimum[PLANE_CURSOR] = skl_cursor_allocation(num_active);
@@ -4356,23 +4408,22 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 {
        struct drm_atomic_state *state = cstate->base.state;
        struct drm_crtc *crtc = cstate->base.crtc;
-       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum pipe pipe = intel_crtc->pipe;
        struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb;
        uint16_t alloc_size, start;
        uint16_t minimum[I915_MAX_PLANES] = {};
        uint16_t uv_minimum[I915_MAX_PLANES] = {};
-       unsigned int total_data_rate;
+       u64 total_data_rate;
        enum plane_id plane_id;
        int num_active;
-       unsigned int plane_data_rate[I915_MAX_PLANES] = {};
-       unsigned int uv_plane_data_rate[I915_MAX_PLANES] = {};
+       u64 plane_data_rate[I915_MAX_PLANES] = {};
+       u64 uv_plane_data_rate[I915_MAX_PLANES] = {};
        uint16_t total_min_blocks = 0;
 
        /* Clear the partitioning for disabled planes. */
-       memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
-       memset(ddb->uv_plane[pipe], 0, sizeof(ddb->uv_plane[pipe]));
+       memset(cstate->wm.skl.plane_ddb_y, 0, sizeof(cstate->wm.skl.plane_ddb_y));
+       memset(cstate->wm.skl.plane_ddb_uv, 0, sizeof(cstate->wm.skl.plane_ddb_uv));
 
        if (WARN_ON(!state))
                return 0;
@@ -4382,11 +4433,18 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                return 0;
        }
 
-       total_data_rate = skl_get_total_relative_data_rate(cstate,
-                                                          plane_data_rate,
-                                                          uv_plane_data_rate);
-       skl_ddb_get_pipe_allocation_limits(dev, cstate, total_data_rate, ddb,
-                                          alloc, &num_active);
+       if (INTEL_GEN(dev_priv) < 11)
+               total_data_rate =
+                       skl_get_total_relative_data_rate(cstate,
+                                                        plane_data_rate,
+                                                        uv_plane_data_rate);
+       else
+               total_data_rate =
+                       icl_get_total_relative_data_rate(cstate,
+                                                        plane_data_rate);
+
+       skl_ddb_get_pipe_allocation_limits(dev_priv, cstate, total_data_rate,
+                                          ddb, alloc, &num_active);
        alloc_size = skl_ddb_entry_size(alloc);
        if (alloc_size == 0)
                return 0;
@@ -4412,8 +4470,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
        }
 
        alloc_size -= total_min_blocks;
-       ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
-       ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
+       cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].start = alloc->end - minimum[PLANE_CURSOR];
+       cstate->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end;
 
        /*
         * 2. Distribute the remaining space in proportion to the amount of
@@ -4426,7 +4484,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 
        start = alloc->start;
        for_each_plane_id_on_crtc(intel_crtc, plane_id) {
-               unsigned int data_rate, uv_data_rate;
+               u64 data_rate, uv_data_rate;
                uint16_t plane_blocks, uv_plane_blocks;
 
                if (plane_id == PLANE_CURSOR)
@@ -4440,13 +4498,12 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                 * result is < available as data_rate / total_data_rate < 1
                 */
                plane_blocks = minimum[plane_id];
-               plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
-                                       total_data_rate);
+               plane_blocks += div64_u64(alloc_size * data_rate, total_data_rate);
 
                /* Leave disabled planes at (0,0) */
                if (data_rate) {
-                       ddb->plane[pipe][plane_id].start = start;
-                       ddb->plane[pipe][plane_id].end = start + plane_blocks;
+                       cstate->wm.skl.plane_ddb_y[plane_id].start = start;
+                       cstate->wm.skl.plane_ddb_y[plane_id].end = start + plane_blocks;
                }
 
                start += plane_blocks;
@@ -4455,12 +4512,14 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                uv_data_rate = uv_plane_data_rate[plane_id];
 
                uv_plane_blocks = uv_minimum[plane_id];
-               uv_plane_blocks += div_u64((uint64_t)alloc_size * uv_data_rate,
-                                          total_data_rate);
+               uv_plane_blocks += div64_u64(alloc_size * uv_data_rate, total_data_rate);
+
+               /* Gen11+ uses a separate plane for UV watermarks */
+               WARN_ON(INTEL_GEN(dev_priv) >= 11 && uv_plane_blocks);
 
                if (uv_data_rate) {
-                       ddb->uv_plane[pipe][plane_id].start = start;
-                       ddb->uv_plane[pipe][plane_id].end =
+                       cstate->wm.skl.plane_ddb_uv[plane_id].start = start;
+                       cstate->wm.skl.plane_ddb_uv[plane_id].end =
                                start + uv_plane_blocks;
                }
 
@@ -4514,7 +4573,7 @@ static uint_fixed_16_16_t skl_wm_method2(uint32_t pixel_rate,
 }
 
 static uint_fixed_16_16_t
-intel_get_linetime_us(struct intel_crtc_state *cstate)
+intel_get_linetime_us(const struct intel_crtc_state *cstate)
 {
        uint32_t pixel_rate;
        uint32_t crtc_htotal;
@@ -4557,12 +4616,12 @@ skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *cstate,
 }
 
 static int
-skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
-                           struct intel_crtc_state *cstate,
+skl_compute_plane_wm_params(const struct intel_crtc_state *cstate,
                            const struct intel_plane_state *intel_pstate,
-                           struct skl_wm_params *wp, int plane_id)
+                           struct skl_wm_params *wp, int color_plane)
 {
        struct intel_plane *plane = to_intel_plane(intel_pstate->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        const struct drm_plane_state *pstate = &intel_pstate->base;
        const struct drm_framebuffer *fb = pstate->fb;
        uint32_t interm_pbpl;
@@ -4570,11 +4629,8 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
                to_intel_atomic_state(cstate->base.state);
        bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state);
 
-       if (!intel_wm_plane_visible(cstate, intel_pstate))
-               return 0;
-
        /* only NV12 format has two planes */
-       if (plane_id == 1 && fb->format->format != DRM_FORMAT_NV12) {
+       if (color_plane == 1 && fb->format->format != DRM_FORMAT_NV12) {
                DRM_DEBUG_KMS("Non NV12 format have single plane\n");
                return -EINVAL;
        }
@@ -4599,10 +4655,10 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
                wp->width = drm_rect_width(&intel_pstate->base.src) >> 16;
        }
 
-       if (plane_id == 1 && wp->is_planar)
+       if (color_plane == 1 && wp->is_planar)
                wp->width /= 2;
 
-       wp->cpp = fb->format->cpp[plane_id];
+       wp->cpp = fb->format->cpp[color_plane];
        wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate,
                                                             intel_pstate);
 
@@ -4664,8 +4720,7 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
        return 0;
 }
 
-static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
-                               struct intel_crtc_state *cstate,
+static int skl_compute_plane_wm(const struct intel_crtc_state *cstate,
                                const struct intel_plane_state *intel_pstate,
                                uint16_t ddb_allocation,
                                int level,
@@ -4673,6 +4728,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
                                const struct skl_wm_level *result_prev,
                                struct skl_wm_level *result /* out */)
 {
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_pstate->base.plane->dev);
        const struct drm_plane_state *pstate = &intel_pstate->base;
        uint32_t latency = dev_priv->wm.skl_latency[level];
        uint_fixed_16_16_t method1, method2;
@@ -4683,11 +4740,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state);
        uint32_t min_disp_buf_needed;
 
-       if (latency == 0 ||
-           !intel_wm_plane_visible(cstate, intel_pstate)) {
-               result->plane_en = false;
-               return 0;
-       }
+       if (latency == 0)
+               return level == 0 ? -EINVAL : 0;
 
        /* Display WA #1141: kbl,cfl */
        if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) ||
@@ -4710,15 +4764,24 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        } else {
                if ((wp->cpp * cstate->base.adjusted_mode.crtc_htotal /
                     wp->dbuf_block_size < 1) &&
-                    (wp->plane_bytes_per_line / wp->dbuf_block_size < 1))
+                    (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) {
                        selected_result = method2;
-               else if (ddb_allocation >=
-                        fixed16_to_u32_round_up(wp->plane_blocks_per_line))
-                       selected_result = min_fixed16(method1, method2);
-               else if (latency >= wp->linetime_us)
-                       selected_result = min_fixed16(method1, method2);
-               else
+               } else if (ddb_allocation >=
+                        fixed16_to_u32_round_up(wp->plane_blocks_per_line)) {
+                       if (IS_GEN9(dev_priv) &&
+                           !IS_GEMINILAKE(dev_priv))
+                               selected_result = min_fixed16(method1, method2);
+                       else
+                               selected_result = method2;
+               } else if (latency >= wp->linetime_us) {
+                       if (IS_GEN9(dev_priv) &&
+                           !IS_GEMINILAKE(dev_priv))
+                               selected_result = min_fixed16(method1, method2);
+                       else
+                               selected_result = method2;
+               } else {
                        selected_result = method1;
+               }
        }
 
        res_blocks = fixed16_to_u32_round_up(selected_result) + 1;
@@ -4775,8 +4838,6 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        if ((level > 0 && res_lines > 31) ||
            res_blocks >= ddb_allocation ||
            min_disp_buf_needed >= ddb_allocation) {
-               result->plane_en = false;
-
                /*
                 * If there are no valid level 0 watermarks, then we can't
                 * support this display configuration.
@@ -4794,17 +4855,6 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
                }
        }
 
-       /*
-        * Display WA #826 (SKL:ALL, BXT:ALL) & #1059 (CNL:A)
-        * disable wm level 1-7 on NV12 planes
-        */
-       if (wp->is_planar && level >= 1 &&
-           (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv) ||
-            IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_A0))) {
-               result->plane_en = false;
-               return 0;
-       }
-
        /* The number of lines are ignored for the level 0 watermark. */
        result->plane_res_b = res_blocks;
        result->plane_res_l = res_lines;
@@ -4814,43 +4864,22 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 }
 
 static int
-skl_compute_wm_levels(const struct drm_i915_private *dev_priv,
-                     struct skl_ddb_allocation *ddb,
-                     struct intel_crtc_state *cstate,
+skl_compute_wm_levels(const struct intel_crtc_state *cstate,
                      const struct intel_plane_state *intel_pstate,
+                     uint16_t ddb_blocks,
                      const struct skl_wm_params *wm_params,
-                     struct skl_plane_wm *wm,
-                     int plane_id)
+                     struct skl_wm_level *levels)
 {
-       struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
-       struct drm_plane *plane = intel_pstate->base.plane;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-       uint16_t ddb_blocks;
-       enum pipe pipe = intel_crtc->pipe;
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_pstate->base.plane->dev);
        int level, max_level = ilk_wm_max_level(dev_priv);
-       enum plane_id intel_plane_id = intel_plane->id;
+       struct skl_wm_level *result_prev = &levels[0];
        int ret;
 
-       if (WARN_ON(!intel_pstate->base.fb))
-               return -EINVAL;
-
-       ddb_blocks = plane_id ?
-                    skl_ddb_entry_size(&ddb->uv_plane[pipe][intel_plane_id]) :
-                    skl_ddb_entry_size(&ddb->plane[pipe][intel_plane_id]);
-
        for (level = 0; level <= max_level; level++) {
-               struct skl_wm_level *result = plane_id ? &wm->uv_wm[level] :
-                                                         &wm->wm[level];
-               struct skl_wm_level *result_prev;
+               struct skl_wm_level *result = &levels[level];
 
-               if (level)
-                       result_prev = plane_id ? &wm->uv_wm[level - 1] :
-                                                 &wm->wm[level - 1];
-               else
-                       result_prev = plane_id ? &wm->uv_wm[0] : &wm->wm[0];
-
-               ret = skl_compute_plane_wm(dev_priv,
-                                          cstate,
+               ret = skl_compute_plane_wm(cstate,
                                           intel_pstate,
                                           ddb_blocks,
                                           level,
@@ -4859,16 +4888,15 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv,
                                           result);
                if (ret)
                        return ret;
-       }
 
-       if (intel_pstate->base.fb->format->format == DRM_FORMAT_NV12)
-               wm->is_planar = true;
+               result_prev = result;
+       }
 
        return 0;
 }
 
 static uint32_t
-skl_compute_linetime_wm(struct intel_crtc_state *cstate)
+skl_compute_linetime_wm(const struct intel_crtc_state *cstate)
 {
        struct drm_atomic_state *state = cstate->base.state;
        struct drm_i915_private *dev_priv = to_i915(state->dev);
@@ -4890,42 +4918,50 @@ skl_compute_linetime_wm(struct intel_crtc_state *cstate)
        return linetime_wm;
 }
 
-static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
-                                     struct skl_wm_params *wp,
-                                     struct skl_wm_level *wm_l0,
-                                     uint16_t ddb_allocation,
-                                     struct skl_wm_level *trans_wm /* out */)
+static void skl_compute_transition_wm(const struct intel_crtc_state *cstate,
+                                     const struct skl_wm_params *wp,
+                                     struct skl_plane_wm *wm,
+                                     uint16_t ddb_allocation)
 {
        struct drm_device *dev = cstate->base.crtc->dev;
        const struct drm_i915_private *dev_priv = to_i915(dev);
        uint16_t trans_min, trans_y_tile_min;
        const uint16_t trans_amount = 10; /* This is configurable amount */
-       uint16_t trans_offset_b, res_blocks;
-
-       if (!cstate->base.active)
-               goto exit;
+       uint16_t wm0_sel_res_b, trans_offset_b, res_blocks;
 
        /* Transition WM are not recommended by HW team for GEN9 */
        if (INTEL_GEN(dev_priv) <= 9)
-               goto exit;
+               return;
 
        /* Transition WM don't make any sense if ipc is disabled */
        if (!dev_priv->ipc_enabled)
-               goto exit;
+               return;
 
-       trans_min = 0;
-       if (INTEL_GEN(dev_priv) >= 10)
+       trans_min = 14;
+       if (INTEL_GEN(dev_priv) >= 11)
                trans_min = 4;
 
        trans_offset_b = trans_min + trans_amount;
 
+       /*
+        * The spec asks for Selected Result Blocks for wm0 (the real value),
+        * not Result Blocks (the integer value). Pay attention to the capital
+        * letters. The value wm_l0->plane_res_b is actually Result Blocks, but
+        * since Result Blocks is the ceiling of Selected Result Blocks plus 1,
+        * and since we later will have to get the ceiling of the sum in the
+        * transition watermarks calculation, we can just pretend Selected
+        * Result Blocks is Result Blocks minus 1 and it should work for the
+        * current platforms.
+        */
+       wm0_sel_res_b = wm->wm[0].plane_res_b - 1;
+
        if (wp->y_tiled) {
                trans_y_tile_min = (uint16_t) mul_round_up_u32_fixed16(2,
                                                        wp->y_tile_minimum);
-               res_blocks = max(wm_l0->plane_res_b, trans_y_tile_min) +
+               res_blocks = max(wm0_sel_res_b, trans_y_tile_min) +
                                trans_offset_b;
        } else {
-               res_blocks = wm_l0->plane_res_b + trans_offset_b;
+               res_blocks = wm0_sel_res_b + trans_offset_b;
 
                /* WA BUG:1938466 add one block for non y-tile planes */
                if (IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_A0))
@@ -4936,25 +4972,132 @@ static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
        res_blocks += 1;
 
        if (res_blocks < ddb_allocation) {
-               trans_wm->plane_res_b = res_blocks;
-               trans_wm->plane_en = true;
-               return;
+               wm->trans_wm.plane_res_b = res_blocks;
+               wm->trans_wm.plane_en = true;
+       }
+}
+
+static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
+                                    const struct intel_plane_state *plane_state,
+                                    enum plane_id plane_id, int color_plane)
+{
+       struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+       u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_y[plane_id]);
+       struct skl_wm_params wm_params;
+       int ret;
+
+       ret = skl_compute_plane_wm_params(crtc_state, plane_state,
+                                         &wm_params, color_plane);
+       if (ret)
+               return ret;
+
+       ret = skl_compute_wm_levels(crtc_state, plane_state,
+                                   ddb_blocks, &wm_params, wm->wm);
+       if (ret)
+               return ret;
+
+       skl_compute_transition_wm(crtc_state, &wm_params, wm, ddb_blocks);
+
+       return 0;
+}
+
+static int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
+                                const struct intel_plane_state *plane_state,
+                                enum plane_id plane_id)
+{
+       struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
+       u16 ddb_blocks = skl_ddb_entry_size(&crtc_state->wm.skl.plane_ddb_uv[plane_id]);
+       struct skl_wm_params wm_params;
+       int ret;
+
+       wm->is_planar = true;
+
+       /* uv plane watermarks must also be validated for NV12/Planar */
+       ret = skl_compute_plane_wm_params(crtc_state, plane_state,
+                                         &wm_params, 1);
+       if (ret)
+               return ret;
+
+       ret = skl_compute_wm_levels(crtc_state, plane_state,
+                                   ddb_blocks, &wm_params, wm->uv_wm);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int skl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
+                             struct intel_crtc_state *crtc_state,
+                             const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       enum plane_id plane_id = plane->id;
+       int ret;
+
+       if (!intel_wm_plane_visible(crtc_state, plane_state))
+               return 0;
+
+       ret = skl_build_plane_wm_single(crtc_state, plane_state,
+                                       plane_id, 0);
+       if (ret)
+               return ret;
+
+       if (fb->format->is_yuv && fb->format->num_planes > 1) {
+               ret = skl_build_plane_wm_uv(crtc_state, plane_state,
+                                           plane_id);
+               if (ret)
+                       return ret;
        }
 
-exit:
-       trans_wm->plane_en = false;
+       return 0;
+}
+
+static int icl_build_plane_wm(struct skl_pipe_wm *pipe_wm,
+                             struct intel_crtc_state *crtc_state,
+                             const struct intel_plane_state *plane_state)
+{
+       enum plane_id plane_id = to_intel_plane(plane_state->base.plane)->id;
+       int ret;
+
+       /* Watermarks calculated in master */
+       if (plane_state->slave)
+               return 0;
+
+       if (plane_state->linked_plane) {
+               const struct drm_framebuffer *fb = plane_state->base.fb;
+               enum plane_id y_plane_id = plane_state->linked_plane->id;
+
+               WARN_ON(!intel_wm_plane_visible(crtc_state, plane_state));
+               WARN_ON(!fb->format->is_yuv ||
+                       fb->format->num_planes == 1);
+
+               ret = skl_build_plane_wm_single(crtc_state, plane_state,
+                                               y_plane_id, 0);
+               if (ret)
+                       return ret;
+
+               ret = skl_build_plane_wm_single(crtc_state, plane_state,
+                                               plane_id, 1);
+               if (ret)
+                       return ret;
+       } else if (intel_wm_plane_visible(crtc_state, plane_state)) {
+               ret = skl_build_plane_wm_single(crtc_state, plane_state,
+                                               plane_id, 0);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
-                            struct skl_ddb_allocation *ddb,
                             struct skl_pipe_wm *pipe_wm)
 {
-       struct drm_device *dev = cstate->base.crtc->dev;
+       struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
        struct drm_crtc_state *crtc_state = &cstate->base;
-       const struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_plane *plane;
        const struct drm_plane_state *pstate;
-       struct skl_plane_wm *wm;
        int ret;
 
        /*
@@ -4966,44 +5109,15 @@ static int skl_build_pipe_wm(struct intel_crtc_state *cstate,
        drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
                const struct intel_plane_state *intel_pstate =
                                                to_intel_plane_state(pstate);
-               enum plane_id plane_id = to_intel_plane(plane)->id;
-               struct skl_wm_params wm_params;
-               enum pipe pipe = to_intel_crtc(cstate->base.crtc)->pipe;
-               uint16_t ddb_blocks;
 
-               wm = &pipe_wm->planes[plane_id];
-               ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]);
-
-               ret = skl_compute_plane_wm_params(dev_priv, cstate,
-                                                 intel_pstate, &wm_params, 0);
-               if (ret)
-                       return ret;
-
-               ret = skl_compute_wm_levels(dev_priv, ddb, cstate,
-                                           intel_pstate, &wm_params, wm, 0);
+               if (INTEL_GEN(dev_priv) >= 11)
+                       ret = icl_build_plane_wm(pipe_wm,
+                                                cstate, intel_pstate);
+               else
+                       ret = skl_build_plane_wm(pipe_wm,
+                                                cstate, intel_pstate);
                if (ret)
                        return ret;
-
-               skl_compute_transition_wm(cstate, &wm_params, &wm->wm[0],
-                                         ddb_blocks, &wm->trans_wm);
-
-               /* uv plane watermarks must also be validated for NV12/Planar */
-               if (wm_params.is_planar) {
-                       memset(&wm_params, 0, sizeof(struct skl_wm_params));
-                       wm->is_planar = true;
-
-                       ret = skl_compute_plane_wm_params(dev_priv, cstate,
-                                                         intel_pstate,
-                                                         &wm_params, 1);
-                       if (ret)
-                               return ret;
-
-                       ret = skl_compute_wm_levels(dev_priv, ddb, cstate,
-                                                   intel_pstate, &wm_params,
-                                                   wm, 1);
-                       if (ret)
-                               return ret;
-               }
        }
 
        pipe_wm->linetime = skl_compute_linetime_wm(cstate);
@@ -5016,9 +5130,9 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
                                const struct skl_ddb_entry *entry)
 {
        if (entry->end)
-               I915_WRITE(reg, (entry->end - 1) << 16 | entry->start);
+               I915_WRITE_FW(reg, (entry->end - 1) << 16 | entry->start);
        else
-               I915_WRITE(reg, 0);
+               I915_WRITE_FW(reg, 0);
 }
 
 static void skl_write_wm_level(struct drm_i915_private *dev_priv,
@@ -5033,19 +5147,22 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
                val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
        }
 
-       I915_WRITE(reg, val);
+       I915_WRITE_FW(reg, val);
 }
 
-static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
-                              const struct skl_plane_wm *wm,
-                              const struct skl_ddb_allocation *ddb,
-                              enum plane_id plane_id)
+void skl_write_plane_wm(struct intel_plane *plane,
+                       const struct intel_crtc_state *crtc_state)
 {
-       struct drm_crtc *crtc = &intel_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        int level, max_level = ilk_wm_max_level(dev_priv);
-       enum pipe pipe = intel_crtc->pipe;
+       enum plane_id plane_id = plane->id;
+       enum pipe pipe = plane->pipe;
+       const struct skl_plane_wm *wm =
+               &crtc_state->wm.skl.optimal.planes[plane_id];
+       const struct skl_ddb_entry *ddb_y =
+               &crtc_state->wm.skl.plane_ddb_y[plane_id];
+       const struct skl_ddb_entry *ddb_uv =
+               &crtc_state->wm.skl.plane_ddb_uv[plane_id];
 
        for (level = 0; level <= max_level; level++) {
                skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
@@ -5054,35 +5171,32 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
        skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
                           &wm->trans_wm);
 
-       skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
-                           &ddb->plane[pipe][plane_id]);
-       /* FIXME: add proper NV12 support for ICL. */
-       if (INTEL_GEN(dev_priv) >= 11)
-               return skl_ddb_entry_write(dev_priv,
-                                          PLANE_BUF_CFG(pipe, plane_id),
-                                          &ddb->plane[pipe][plane_id]);
-       if (wm->is_planar) {
-               skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
-                                   &ddb->uv_plane[pipe][plane_id]);
+       if (INTEL_GEN(dev_priv) >= 11) {
                skl_ddb_entry_write(dev_priv,
-                                   PLANE_NV12_BUF_CFG(pipe, plane_id),
-                                   &ddb->plane[pipe][plane_id]);
-       } else {
-               skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
-                                   &ddb->plane[pipe][plane_id]);
-               I915_WRITE(PLANE_NV12_BUF_CFG(pipe, plane_id), 0x0);
+                                   PLANE_BUF_CFG(pipe, plane_id), ddb_y);
+               return;
        }
+
+       if (wm->is_planar)
+               swap(ddb_y, ddb_uv);
+
+       skl_ddb_entry_write(dev_priv,
+                           PLANE_BUF_CFG(pipe, plane_id), ddb_y);
+       skl_ddb_entry_write(dev_priv,
+                           PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv);
 }
 
-static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
-                               const struct skl_plane_wm *wm,
-                               const struct skl_ddb_allocation *ddb)
+void skl_write_cursor_wm(struct intel_plane *plane,
+                        const struct intel_crtc_state *crtc_state)
 {
-       struct drm_crtc *crtc = &intel_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        int level, max_level = ilk_wm_max_level(dev_priv);
-       enum pipe pipe = intel_crtc->pipe;
+       enum plane_id plane_id = plane->id;
+       enum pipe pipe = plane->pipe;
+       const struct skl_plane_wm *wm =
+               &crtc_state->wm.skl.optimal.planes[plane_id];
+       const struct skl_ddb_entry *ddb =
+               &crtc_state->wm.skl.plane_ddb_y[plane_id];
 
        for (level = 0; level <= max_level; level++) {
                skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
@@ -5090,22 +5204,30 @@ static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
        }
        skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
 
-       skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
-                           &ddb->plane[pipe][PLANE_CURSOR]);
+       skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
 }
 
 bool skl_wm_level_equals(const struct skl_wm_level *l1,
                         const struct skl_wm_level *l2)
 {
-       if (l1->plane_en != l2->plane_en)
-               return false;
+       return l1->plane_en == l2->plane_en &&
+               l1->plane_res_l == l2->plane_res_l &&
+               l1->plane_res_b == l2->plane_res_b;
+}
 
-       /* If both planes aren't enabled, the rest shouldn't matter */
-       if (!l1->plane_en)
-               return true;
+static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv,
+                               const struct skl_plane_wm *wm1,
+                               const struct skl_plane_wm *wm2)
+{
+       int level, max_level = ilk_wm_max_level(dev_priv);
 
-       return (l1->plane_res_l == l2->plane_res_l &&
-               l1->plane_res_b == l2->plane_res_b);
+       for (level = 0; level <= max_level; level++) {
+               if (!skl_wm_level_equals(&wm1->wm[level], &wm2->wm[level]) ||
+                   !skl_wm_level_equals(&wm1->uv_wm[level], &wm2->uv_wm[level]))
+                       return false;
+       }
+
+       return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm);
 }
 
 static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
@@ -5114,16 +5236,15 @@ static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
        return a->start < b->end && b->start < a->end;
 }
 
-bool skl_ddb_allocation_overlaps(struct drm_i915_private *dev_priv,
-                                const struct skl_ddb_entry **entries,
-                                const struct skl_ddb_entry *ddb,
-                                int ignore)
+bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
+                                const struct skl_ddb_entry entries[],
+                                int num_entries, int ignore_idx)
 {
-       enum pipe pipe;
+       int i;
 
-       for_each_pipe(dev_priv, pipe) {
-               if (pipe != ignore && entries[pipe] &&
-                   skl_ddb_entries_overlap(ddb, entries[pipe]))
+       for (i = 0; i < num_entries; i++) {
+               if (i != ignore_idx &&
+                   skl_ddb_entries_overlap(ddb, &entries[i]))
                        return true;
        }
 
@@ -5133,13 +5254,12 @@ bool skl_ddb_allocation_overlaps(struct drm_i915_private *dev_priv,
 static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
                              const struct skl_pipe_wm *old_pipe_wm,
                              struct skl_pipe_wm *pipe_wm, /* out */
-                             struct skl_ddb_allocation *ddb, /* out */
                              bool *changed /* out */)
 {
        struct intel_crtc_state *intel_cstate = to_intel_crtc_state(cstate);
        int ret;
 
-       ret = skl_build_pipe_wm(intel_cstate, ddb, pipe_wm);
+       ret = skl_build_pipe_wm(intel_cstate, pipe_wm);
        if (ret)
                return ret;
 
@@ -5165,32 +5285,29 @@ pipes_modified(struct drm_atomic_state *state)
 }
 
 static int
-skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
+skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
+                           struct intel_crtc_state *new_crtc_state)
 {
-       struct drm_atomic_state *state = cstate->base.state;
-       struct drm_device *dev = state->dev;
-       struct drm_crtc *crtc = cstate->base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
-       struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
-       struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
-       struct drm_plane_state *plane_state;
-       struct drm_plane *plane;
-       enum pipe pipe = intel_crtc->pipe;
+       struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->base.state);
+       struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_plane *plane;
 
-       drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) {
-               enum plane_id plane_id = to_intel_plane(plane)->id;
+       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+               struct intel_plane_state *plane_state;
+               enum plane_id plane_id = plane->id;
 
-               if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id],
-                                       &new_ddb->plane[pipe][plane_id]) &&
-                   skl_ddb_entry_equal(&cur_ddb->uv_plane[pipe][plane_id],
-                                       &new_ddb->uv_plane[pipe][plane_id]))
+               if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id],
+                                       &new_crtc_state->wm.skl.plane_ddb_y[plane_id]) &&
+                   skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id],
+                                       &new_crtc_state->wm.skl.plane_ddb_uv[plane_id]))
                        continue;
 
-               plane_state = drm_atomic_get_plane_state(state, plane);
+               plane_state = intel_atomic_get_plane_state(state, plane);
                if (IS_ERR(plane_state))
                        return PTR_ERR(plane_state);
+
+               new_crtc_state->update_planes |= BIT(plane_id);
        }
 
        return 0;
@@ -5202,18 +5319,21 @@ skl_compute_ddb(struct drm_atomic_state *state)
        const struct drm_i915_private *dev_priv = to_i915(state->dev);
        struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb;
+       struct intel_crtc_state *old_crtc_state;
+       struct intel_crtc_state *new_crtc_state;
        struct intel_crtc *crtc;
-       struct intel_crtc_state *cstate;
        int ret, i;
 
        memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb));
 
-       for_each_new_intel_crtc_in_state(intel_state, crtc, cstate, i) {
-               ret = skl_allocate_pipe_ddb(cstate, ddb);
+       for_each_oldnew_intel_crtc_in_state(intel_state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               ret = skl_allocate_pipe_ddb(new_crtc_state, ddb);
                if (ret)
                        return ret;
 
-               ret = skl_ddb_add_affected_planes(cstate);
+               ret = skl_ddb_add_affected_planes(old_crtc_state,
+                                                 new_crtc_state);
                if (ret)
                        return ret;
        }
@@ -5222,38 +5342,31 @@ skl_compute_ddb(struct drm_atomic_state *state)
 }
 
 static void
-skl_print_wm_changes(const struct drm_atomic_state *state)
+skl_print_wm_changes(struct intel_atomic_state *state)
 {
-       const struct drm_device *dev = state->dev;
-       const struct drm_i915_private *dev_priv = to_i915(dev);
-       const struct intel_atomic_state *intel_state =
-               to_intel_atomic_state(state);
-       const struct drm_crtc *crtc;
-       const struct drm_crtc_state *cstate;
-       const struct intel_plane *intel_plane;
-       const struct skl_ddb_allocation *old_ddb = &dev_priv->wm.skl_hw.ddb;
-       const struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       const struct intel_crtc_state *old_crtc_state;
+       const struct intel_crtc_state *new_crtc_state;
+       struct intel_plane *plane;
+       struct intel_crtc *crtc;
        int i;
 
-       for_each_new_crtc_in_state(state, crtc, cstate, i) {
-               const struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               enum pipe pipe = intel_crtc->pipe;
-
-               for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
-                       enum plane_id plane_id = intel_plane->id;
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i) {
+               for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+                       enum plane_id plane_id = plane->id;
                        const struct skl_ddb_entry *old, *new;
 
-                       old = &old_ddb->plane[pipe][plane_id];
-                       new = &new_ddb->plane[pipe][plane_id];
+                       old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id];
+                       new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id];
 
                        if (skl_ddb_entry_equal(old, new))
                                continue;
 
-                       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] ddb (%d - %d) -> (%d - %d)\n",
-                                        intel_plane->base.base.id,
-                                        intel_plane->base.name,
-                                        old->start, old->end,
-                                        new->start, new->end);
+                       DRM_DEBUG_KMS("[PLANE:%d:%s] ddb (%d - %d) -> (%d - %d)\n",
+                                     plane->base.base.id, plane->base.name,
+                                     old->start, old->end,
+                                     new->start, new->end);
                }
        }
 }
@@ -5348,6 +5461,66 @@ skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed)
        return 0;
 }
 
+/*
+ * To make sure the cursor watermark registers are always consistent
+ * with our computed state the following scenario needs special
+ * treatment:
+ *
+ * 1. enable cursor
+ * 2. move cursor entirely offscreen
+ * 3. disable cursor
+ *
+ * Step 2. does call .disable_plane() but does not zero the watermarks
+ * (since we consider an offscreen cursor still active for the purposes
+ * of watermarks). Step 3. would not normally call .disable_plane()
+ * because the actual plane visibility isn't changing, and we don't
+ * deallocate the cursor ddb until the pipe gets disabled. So we must
+ * force step 3. to call .disable_plane() to update the watermark
+ * registers properly.
+ *
+ * Other planes do not suffer from this issues as their watermarks are
+ * calculated based on the actual plane visibility. The only time this
+ * can trigger for the other planes is during the initial readout as the
+ * default value of the watermarks registers is not zero.
+ */
+static int skl_wm_add_affected_planes(struct intel_atomic_state *state,
+                                     struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
+       struct intel_crtc_state *new_crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       struct intel_plane *plane;
+
+       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+               struct intel_plane_state *plane_state;
+               enum plane_id plane_id = plane->id;
+
+               /*
+                * Force a full wm update for every plane on modeset.
+                * Required because the reset value of the wm registers
+                * is non-zero, whereas we want all disabled planes to
+                * have zero watermarks. So if we turn off the relevant
+                * power well the hardware state will go out of sync
+                * with the software state.
+                */
+               if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) &&
+                   skl_plane_wm_equals(dev_priv,
+                                       &old_crtc_state->wm.skl.optimal.planes[plane_id],
+                                       &new_crtc_state->wm.skl.optimal.planes[plane_id]))
+                       continue;
+
+               plane_state = intel_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state))
+                       return PTR_ERR(plane_state);
+
+               new_crtc_state->update_planes |= BIT(plane_id);
+       }
+
+       return 0;
+}
+
 static int
 skl_compute_wm(struct drm_atomic_state *state)
 {
@@ -5387,8 +5560,12 @@ skl_compute_wm(struct drm_atomic_state *state)
                        &to_intel_crtc_state(crtc->state)->wm.skl.optimal;
 
                pipe_wm = &intel_cstate->wm.skl.optimal;
-               ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm,
-                                        &results->ddb, &changed);
+               ret = skl_update_pipe_wm(cstate, old_pipe_wm, pipe_wm, &changed);
+               if (ret)
+                       return ret;
+
+               ret = skl_wm_add_affected_planes(intel_state,
+                                                to_intel_crtc(crtc));
                if (ret)
                        return ret;
 
@@ -5402,7 +5579,7 @@ skl_compute_wm(struct drm_atomic_state *state)
                intel_cstate->update_wm_pre = true;
        }
 
-       skl_print_wm_changes(state);
+       skl_print_wm_changes(intel_state);
 
        return 0;
 }
@@ -5413,23 +5590,12 @@ static void skl_atomic_update_crtc_wm(struct intel_atomic_state *state,
        struct intel_crtc *crtc = to_intel_crtc(cstate->base.crtc);
        struct drm_i915_private *dev_priv = to_i915(state->base.dev);
        struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
-       const struct skl_ddb_allocation *ddb = &state->wm_results.ddb;
        enum pipe pipe = crtc->pipe;
-       enum plane_id plane_id;
 
        if (!(state->wm_results.dirty_pipes & drm_crtc_mask(&crtc->base)))
                return;
 
        I915_WRITE(PIPE_WM_LINETIME(pipe), pipe_wm->linetime);
-
-       for_each_plane_id_on_crtc(crtc, plane_id) {
-               if (plane_id != PLANE_CURSOR)
-                       skl_write_plane_wm(crtc, &pipe_wm->planes[plane_id],
-                                          ddb, plane_id);
-               else
-                       skl_write_cursor_wm(crtc, &pipe_wm->planes[plane_id],
-                                           ddb);
-       }
 }
 
 static void skl_initial_wm(struct intel_atomic_state *state,
@@ -5439,8 +5605,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct skl_ddb_values *results = &state->wm_results;
-       struct skl_ddb_values *hw_vals = &dev_priv->wm.skl_hw;
-       enum pipe pipe = intel_crtc->pipe;
 
        if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0)
                return;
@@ -5450,11 +5614,6 @@ static void skl_initial_wm(struct intel_atomic_state *state,
        if (cstate->base.active_changed)
                skl_atomic_update_crtc_wm(state, cstate);
 
-       memcpy(hw_vals->ddb.uv_plane[pipe], results->ddb.uv_plane[pipe],
-              sizeof(hw_vals->ddb.uv_plane[pipe]));
-       memcpy(hw_vals->ddb.plane[pipe], results->ddb.plane[pipe],
-              sizeof(hw_vals->ddb.plane[pipe]));
-
        mutex_unlock(&dev_priv->wm.wm_mutex);
 }
 
@@ -5605,13 +5764,6 @@ void skl_wm_get_hw_state(struct drm_device *dev)
        if (dev_priv->active_crtcs) {
                /* Fully recompute DDB on first atomic commit */
                dev_priv->wm.distrust_bios_wm = true;
-       } else {
-               /*
-                * Easy/common case; just sanitize DDB now if everything off
-                * Keep dbuf slice info intact
-                */
-               memset(ddb->plane, 0, sizeof(ddb->plane));
-               memset(ddb->uv_plane, 0, sizeof(ddb->uv_plane));
        }
 }
 
@@ -6155,14 +6307,8 @@ void intel_enable_ipc(struct drm_i915_private *dev_priv)
 {
        u32 val;
 
-       /* Display WA #0477 WaDisableIPC: skl */
-       if (IS_SKYLAKE(dev_priv))
-               dev_priv->ipc_enabled = false;
-
-       /* Display WA #1141: SKL:all KBL:all CFL */
-       if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) &&
-           !dev_priv->dram_info.symmetric_memory)
-               dev_priv->ipc_enabled = false;
+       if (!HAS_IPC(dev_priv))
+               return;
 
        val = I915_READ(DISP_ARB_CTL2);
 
@@ -6176,11 +6322,15 @@ void intel_enable_ipc(struct drm_i915_private *dev_priv)
 
 void intel_init_ipc(struct drm_i915_private *dev_priv)
 {
-       dev_priv->ipc_enabled = false;
        if (!HAS_IPC(dev_priv))
                return;
 
-       dev_priv->ipc_enabled = true;
+       /* Display WA #1141: SKL:all KBL:all CFL */
+       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
+               dev_priv->ipc_enabled = dev_priv->dram_info.symmetric_memory;
+       else
+               dev_priv->ipc_enabled = true;
+
        intel_enable_ipc(dev_priv);
 }
 
@@ -8774,6 +8924,10 @@ static void icl_init_clock_gating(struct drm_i915_private *dev_priv)
        /* This is not an Wa. Enable to reduce Sampler power */
        I915_WRITE(GEN10_DFR_RATIO_EN_AND_CHICKEN,
                   I915_READ(GEN10_DFR_RATIO_EN_AND_CHICKEN) & ~DFR_DISABLE);
+
+       /* WaEnable32PlaneMode:icl */
+       I915_WRITE(GEN9_CSFE_CHICKEN1_RCS,
+                  _MASKED_BIT_ENABLE(GEN11_ENABLE_32_PLANE_MODE));
 }
 
 static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -9351,8 +9505,6 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
 /* Set up chip specific power management-related functions */
 void intel_init_pm(struct drm_i915_private *dev_priv)
 {
-       intel_fbc_init(dev_priv);
-
        /* For cxsr */
        if (IS_PINEVIEW(dev_priv))
                i915_pineview_get_mem_freq(dev_priv);
index b6838b525502ea68f8d472dbd703d51bfa1d6561..419e563425239951bdaa43bc05dae5c83c5484d5 100644 (file)
@@ -71,6 +71,14 @@ static bool psr_global_enabled(u32 debug)
 static bool intel_psr2_enabled(struct drm_i915_private *dev_priv,
                               const struct intel_crtc_state *crtc_state)
 {
+       /* Disable PSR2 by default for all platforms */
+       if (i915_modparams.enable_psr == -1)
+               return false;
+
+       /* Cannot enable DSC and PSR2 simultaneously */
+       WARN_ON(crtc_state->dsc_params.compression_enable &&
+               crtc_state->has_psr2);
+
        switch (dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK) {
        case I915_PSR_DEBUG_FORCE_PSR1:
                return false;
@@ -79,25 +87,42 @@ static bool intel_psr2_enabled(struct drm_i915_private *dev_priv,
        }
 }
 
+static int edp_psr_shift(enum transcoder cpu_transcoder)
+{
+       switch (cpu_transcoder) {
+       case TRANSCODER_A:
+               return EDP_PSR_TRANSCODER_A_SHIFT;
+       case TRANSCODER_B:
+               return EDP_PSR_TRANSCODER_B_SHIFT;
+       case TRANSCODER_C:
+               return EDP_PSR_TRANSCODER_C_SHIFT;
+       default:
+               MISSING_CASE(cpu_transcoder);
+               /* fallthrough */
+       case TRANSCODER_EDP:
+               return EDP_PSR_TRANSCODER_EDP_SHIFT;
+       }
+}
+
 void intel_psr_irq_control(struct drm_i915_private *dev_priv, u32 debug)
 {
        u32 debug_mask, mask;
+       enum transcoder cpu_transcoder;
+       u32 transcoders = BIT(TRANSCODER_EDP);
+
+       if (INTEL_GEN(dev_priv) >= 8)
+               transcoders |= BIT(TRANSCODER_A) |
+                              BIT(TRANSCODER_B) |
+                              BIT(TRANSCODER_C);
+
+       debug_mask = 0;
+       mask = 0;
+       for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, transcoders) {
+               int shift = edp_psr_shift(cpu_transcoder);
 
-       mask = EDP_PSR_ERROR(TRANSCODER_EDP);
-       debug_mask = EDP_PSR_POST_EXIT(TRANSCODER_EDP) |
-                    EDP_PSR_PRE_ENTRY(TRANSCODER_EDP);
-
-       if (INTEL_GEN(dev_priv) >= 8) {
-               mask |= EDP_PSR_ERROR(TRANSCODER_A) |
-                       EDP_PSR_ERROR(TRANSCODER_B) |
-                       EDP_PSR_ERROR(TRANSCODER_C);
-
-               debug_mask |= EDP_PSR_POST_EXIT(TRANSCODER_A) |
-                             EDP_PSR_PRE_ENTRY(TRANSCODER_A) |
-                             EDP_PSR_POST_EXIT(TRANSCODER_B) |
-                             EDP_PSR_PRE_ENTRY(TRANSCODER_B) |
-                             EDP_PSR_POST_EXIT(TRANSCODER_C) |
-                             EDP_PSR_PRE_ENTRY(TRANSCODER_C);
+               mask |= EDP_PSR_ERROR(shift);
+               debug_mask |= EDP_PSR_POST_EXIT(shift) |
+                             EDP_PSR_PRE_ENTRY(shift);
        }
 
        if (debug & I915_PSR_DEBUG_IRQ)
@@ -148,6 +173,7 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir)
        u32 transcoders = BIT(TRANSCODER_EDP);
        enum transcoder cpu_transcoder;
        ktime_t time_ns =  ktime_get();
+       u32 mask = 0;
 
        if (INTEL_GEN(dev_priv) >= 8)
                transcoders |= BIT(TRANSCODER_A) |
@@ -155,18 +181,32 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir)
                               BIT(TRANSCODER_C);
 
        for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, transcoders) {
-               /* FIXME: Exit PSR and link train manually when this happens. */
-               if (psr_iir & EDP_PSR_ERROR(cpu_transcoder))
-                       DRM_DEBUG_KMS("[transcoder %s] PSR aux error\n",
-                                     transcoder_name(cpu_transcoder));
+               int shift = edp_psr_shift(cpu_transcoder);
+
+               if (psr_iir & EDP_PSR_ERROR(shift)) {
+                       DRM_WARN("[transcoder %s] PSR aux error\n",
+                                transcoder_name(cpu_transcoder));
+
+                       dev_priv->psr.irq_aux_error = true;
 
-               if (psr_iir & EDP_PSR_PRE_ENTRY(cpu_transcoder)) {
+                       /*
+                        * If this interruption is not masked it will keep
+                        * interrupting so fast that it prevents the scheduled
+                        * work to run.
+                        * Also after a PSR error, we don't want to arm PSR
+                        * again so we don't care about unmask the interruption
+                        * or unset irq_aux_error.
+                        */
+                       mask |= EDP_PSR_ERROR(shift);
+               }
+
+               if (psr_iir & EDP_PSR_PRE_ENTRY(shift)) {
                        dev_priv->psr.last_entry_attempt = time_ns;
                        DRM_DEBUG_KMS("[transcoder %s] PSR entry attempt in 2 vblanks\n",
                                      transcoder_name(cpu_transcoder));
                }
 
-               if (psr_iir & EDP_PSR_POST_EXIT(cpu_transcoder)) {
+               if (psr_iir & EDP_PSR_POST_EXIT(shift)) {
                        dev_priv->psr.last_exit = time_ns;
                        DRM_DEBUG_KMS("[transcoder %s] PSR exit completed\n",
                                      transcoder_name(cpu_transcoder));
@@ -180,6 +220,13 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir)
                        }
                }
        }
+
+       if (mask) {
+               mask |= I915_READ(EDP_PSR_IMR);
+               I915_WRITE(EDP_PSR_IMR, mask);
+
+               schedule_work(&dev_priv->psr.work);
+       }
 }
 
 static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
@@ -294,7 +341,8 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp,
                psr_vsc.sdp_header.HB3 = 0x8;
        }
 
-       intel_dig_port->write_infoframe(&intel_dig_port->base.base, crtc_state,
+       intel_dig_port->write_infoframe(&intel_dig_port->base,
+                                       crtc_state,
                                        DP_SDP_VSC, &psr_vsc, sizeof(psr_vsc));
 }
 
@@ -458,6 +506,16 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
        if (!dev_priv->psr.sink_psr2_support)
                return false;
 
+       /*
+        * DSC and PSR2 cannot be enabled simultaneously. If a requested
+        * resolution requires DSC to be enabled, priority is given to DSC
+        * over PSR2.
+        */
+       if (crtc_state->dsc_params.compression_enable) {
+               DRM_DEBUG_KMS("PSR2 cannot be enabled since DSC is enabled\n");
+               return false;
+       }
+
        if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
                psr_max_h = 4096;
                psr_max_v = 2304;
@@ -503,10 +561,8 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
                return;
        }
 
-       if (IS_HASWELL(dev_priv) &&
-           I915_READ(HSW_STEREO_3D_CTL(crtc_state->cpu_transcoder)) &
-                     S3D_ENABLE) {
-               DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
+       if (dev_priv->psr.sink_not_reliable) {
+               DRM_DEBUG_KMS("PSR sink implementation is not reliable\n");
                return;
        }
 
@@ -553,11 +609,31 @@ static void intel_psr_activate(struct intel_dp *intel_dp)
        dev_priv->psr.active = true;
 }
 
+static i915_reg_t gen9_chicken_trans_reg(struct drm_i915_private *dev_priv,
+                                        enum transcoder cpu_transcoder)
+{
+       static const i915_reg_t regs[] = {
+               [TRANSCODER_A] = CHICKEN_TRANS_A,
+               [TRANSCODER_B] = CHICKEN_TRANS_B,
+               [TRANSCODER_C] = CHICKEN_TRANS_C,
+               [TRANSCODER_EDP] = CHICKEN_TRANS_EDP,
+       };
+
+       WARN_ON(INTEL_GEN(dev_priv) < 9);
+
+       if (WARN_ON(cpu_transcoder >= ARRAY_SIZE(regs) ||
+                   !regs[cpu_transcoder].reg))
+               cpu_transcoder = TRANSCODER_A;
+
+       return regs[cpu_transcoder];
+}
+
 static void intel_psr_enable_source(struct intel_dp *intel_dp,
                                    const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
        enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 mask;
 
        /* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+
         * use hardcoded values PSR AUX transactions
@@ -566,37 +642,34 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
                hsw_psr_setup_aux(intel_dp);
 
        if (dev_priv->psr.psr2_enabled) {
-               u32 chicken = I915_READ(CHICKEN_TRANS(cpu_transcoder));
+               i915_reg_t reg = gen9_chicken_trans_reg(dev_priv,
+                                                       cpu_transcoder);
+               u32 chicken = I915_READ(reg);
 
-               if (INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv))
+               if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv))
                        chicken |= (PSR2_VSC_ENABLE_PROG_HEADER
                                   | PSR2_ADD_VERTICAL_LINE_COUNT);
 
                else
                        chicken &= ~VSC_DATA_SEL_SOFTWARE_CONTROL;
-               I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken);
-
-               I915_WRITE(EDP_PSR_DEBUG,
-                          EDP_PSR_DEBUG_MASK_MEMUP |
-                          EDP_PSR_DEBUG_MASK_HPD |
-                          EDP_PSR_DEBUG_MASK_LPSP |
-                          EDP_PSR_DEBUG_MASK_MAX_SLEEP |
-                          EDP_PSR_DEBUG_MASK_DISP_REG_WRITE);
-       } else {
-               /*
-                * Per Spec: Avoid continuous PSR exit by masking MEMUP
-                * and HPD. also mask LPSP to avoid dependency on other
-                * drivers that might block runtime_pm besides
-                * preventing  other hw tracking issues now we can rely
-                * on frontbuffer tracking.
-                */
-               I915_WRITE(EDP_PSR_DEBUG,
-                          EDP_PSR_DEBUG_MASK_MEMUP |
-                          EDP_PSR_DEBUG_MASK_HPD |
-                          EDP_PSR_DEBUG_MASK_LPSP |
-                          EDP_PSR_DEBUG_MASK_DISP_REG_WRITE |
-                          EDP_PSR_DEBUG_MASK_MAX_SLEEP);
+               I915_WRITE(reg, chicken);
        }
+
+       /*
+        * Per Spec: Avoid continuous PSR exit by masking MEMUP and HPD also
+        * mask LPSP to avoid dependency on other drivers that might block
+        * runtime_pm besides preventing  other hw tracking issues now we
+        * can rely on frontbuffer tracking.
+        */
+       mask = EDP_PSR_DEBUG_MASK_MEMUP |
+              EDP_PSR_DEBUG_MASK_HPD |
+              EDP_PSR_DEBUG_MASK_LPSP |
+              EDP_PSR_DEBUG_MASK_MAX_SLEEP;
+
+       if (INTEL_GEN(dev_priv) < 11)
+               mask |= EDP_PSR_DEBUG_MASK_DISP_REG_WRITE;
+
+       I915_WRITE(EDP_PSR_DEBUG, mask);
 }
 
 static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
@@ -646,6 +719,7 @@ void intel_psr_enable(struct intel_dp *intel_dp,
        dev_priv->psr.psr2_enabled = intel_psr2_enabled(dev_priv, crtc_state);
        dev_priv->psr.busy_frontbuffer_bits = 0;
        dev_priv->psr.prepared = true;
+       dev_priv->psr.pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
 
        if (psr_global_enabled(dev_priv->psr.debug))
                intel_psr_enable_locked(dev_priv, crtc_state);
@@ -656,49 +730,34 @@ unlock:
        mutex_unlock(&dev_priv->psr.lock);
 }
 
-static void
-intel_psr_disable_source(struct intel_dp *intel_dp)
+static void intel_psr_exit(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-
-       if (dev_priv->psr.active) {
-               i915_reg_t psr_status;
-               u32 psr_status_mask;
-
-               if (dev_priv->psr.psr2_enabled) {
-                       psr_status = EDP_PSR2_STATUS;
-                       psr_status_mask = EDP_PSR2_STATUS_STATE_MASK;
-
-                       I915_WRITE(EDP_PSR2_CTL,
-                                  I915_READ(EDP_PSR2_CTL) &
-                                  ~(EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE));
-
-               } else {
-                       psr_status = EDP_PSR_STATUS;
-                       psr_status_mask = EDP_PSR_STATUS_STATE_MASK;
-
-                       I915_WRITE(EDP_PSR_CTL,
-                                  I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
-               }
+       u32 val;
 
-               /* Wait till PSR is idle */
-               if (intel_wait_for_register(dev_priv,
-                                           psr_status, psr_status_mask, 0,
-                                           2000))
-                       DRM_ERROR("Timed out waiting for PSR Idle State\n");
+       if (!dev_priv->psr.active) {
+               if (INTEL_GEN(dev_priv) >= 9)
+                       WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
+               WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
+               return;
+       }
 
-               dev_priv->psr.active = false;
+       if (dev_priv->psr.psr2_enabled) {
+               val = I915_READ(EDP_PSR2_CTL);
+               WARN_ON(!(val & EDP_PSR2_ENABLE));
+               I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE);
        } else {
-               if (dev_priv->psr.psr2_enabled)
-                       WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
-               else
-                       WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
+               val = I915_READ(EDP_PSR_CTL);
+               WARN_ON(!(val & EDP_PSR_ENABLE));
+               I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
        }
+       dev_priv->psr.active = false;
 }
 
 static void intel_psr_disable_locked(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       i915_reg_t psr_status;
+       u32 psr_status_mask;
 
        lockdep_assert_held(&dev_priv->psr.lock);
 
@@ -707,7 +766,21 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Disabling PSR%s\n",
                      dev_priv->psr.psr2_enabled ? "2" : "1");
-       intel_psr_disable_source(intel_dp);
+
+       intel_psr_exit(dev_priv);
+
+       if (dev_priv->psr.psr2_enabled) {
+               psr_status = EDP_PSR2_STATUS;
+               psr_status_mask = EDP_PSR2_STATUS_STATE_MASK;
+       } else {
+               psr_status = EDP_PSR_STATUS;
+               psr_status_mask = EDP_PSR_STATUS_STATE_MASK;
+       }
+
+       /* Wait till PSR is idle */
+       if (intel_wait_for_register(dev_priv, psr_status, psr_status_mask, 0,
+                                   2000))
+               DRM_ERROR("Timed out waiting PSR idle state\n");
 
        /* Disable PSR on Sink */
        drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0);
@@ -893,6 +966,16 @@ int intel_psr_set_debugfs_mode(struct drm_i915_private *dev_priv,
        return ret;
 }
 
+static void intel_psr_handle_irq(struct drm_i915_private *dev_priv)
+{
+       struct i915_psr *psr = &dev_priv->psr;
+
+       intel_psr_disable_locked(psr->dp);
+       psr->sink_not_reliable = true;
+       /* let's make sure that sink is awaken */
+       drm_dp_dpcd_writeb(&psr->dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+}
+
 static void intel_psr_work(struct work_struct *work)
 {
        struct drm_i915_private *dev_priv =
@@ -903,6 +986,9 @@ static void intel_psr_work(struct work_struct *work)
        if (!dev_priv->psr.enabled)
                goto unlock;
 
+       if (READ_ONCE(dev_priv->psr.irq_aux_error))
+               intel_psr_handle_irq(dev_priv);
+
        /*
         * We have to make sure PSR is ready for re-enable
         * otherwise it keeps disabled until next full enable/disable cycle.
@@ -925,25 +1011,6 @@ unlock:
        mutex_unlock(&dev_priv->psr.lock);
 }
 
-static void intel_psr_exit(struct drm_i915_private *dev_priv)
-{
-       u32 val;
-
-       if (!dev_priv->psr.active)
-               return;
-
-       if (dev_priv->psr.psr2_enabled) {
-               val = I915_READ(EDP_PSR2_CTL);
-               WARN_ON(!(val & EDP_PSR2_ENABLE));
-               I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE);
-       } else {
-               val = I915_READ(EDP_PSR_CTL);
-               WARN_ON(!(val & EDP_PSR_ENABLE));
-               I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
-       }
-       dev_priv->psr.active = false;
-}
-
 /**
  * intel_psr_invalidate - Invalidade PSR
  * @dev_priv: i915 device
@@ -960,9 +1027,6 @@ static void intel_psr_exit(struct drm_i915_private *dev_priv)
 void intel_psr_invalidate(struct drm_i915_private *dev_priv,
                          unsigned frontbuffer_bits, enum fb_op_origin origin)
 {
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
        if (!CAN_PSR(dev_priv))
                return;
 
@@ -975,10 +1039,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
                return;
        }
 
-       crtc = dp_to_dig_port(dev_priv->psr.dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(dev_priv->psr.pipe);
        dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits;
 
        if (frontbuffer_bits)
@@ -1003,9 +1064,6 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
 void intel_psr_flush(struct drm_i915_private *dev_priv,
                     unsigned frontbuffer_bits, enum fb_op_origin origin)
 {
-       struct drm_crtc *crtc;
-       enum pipe pipe;
-
        if (!CAN_PSR(dev_priv))
                return;
 
@@ -1018,28 +1076,21 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
                return;
        }
 
-       crtc = dp_to_dig_port(dev_priv->psr.dp)->base.base.crtc;
-       pipe = to_intel_crtc(crtc)->pipe;
-
-       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+       frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(dev_priv->psr.pipe);
        dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits;
 
        /* By definition flush = invalidate + flush */
        if (frontbuffer_bits) {
-               if (dev_priv->psr.psr2_enabled) {
-                       intel_psr_exit(dev_priv);
-               } else {
-                       /*
-                        * Display WA #0884: all
-                        * This documented WA for bxt can be safely applied
-                        * broadly so we can force HW tracking to exit PSR
-                        * instead of disabling and re-enabling.
-                        * Workaround tells us to write 0 to CUR_SURFLIVE_A,
-                        * but it makes more sense write to the current active
-                        * pipe.
-                        */
-                       I915_WRITE(CURSURFLIVE(pipe), 0);
-               }
+               /*
+                * Display WA #0884: all
+                * This documented WA for bxt can be safely applied
+                * broadly so we can force HW tracking to exit PSR
+                * instead of disabling and re-enabling.
+                * Workaround tells us to write 0 to CUR_SURFLIVE_A,
+                * but it makes more sense write to the current active
+                * pipe.
+                */
+               I915_WRITE(CURSURFLIVE(dev_priv->psr.pipe), 0);
        }
 
        if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
@@ -1056,6 +1107,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
  */
 void intel_psr_init(struct drm_i915_private *dev_priv)
 {
+       u32 val;
+
        if (!HAS_PSR(dev_priv))
                return;
 
@@ -1065,11 +1118,24 @@ void intel_psr_init(struct drm_i915_private *dev_priv)
        if (!dev_priv->psr.sink_support)
                return;
 
-       if (i915_modparams.enable_psr == -1) {
-               i915_modparams.enable_psr = dev_priv->vbt.psr.enable;
+       if (i915_modparams.enable_psr == -1)
+               if (INTEL_GEN(dev_priv) < 9 || !dev_priv->vbt.psr.enable)
+                       i915_modparams.enable_psr = 0;
 
-               /* Per platform default: all disabled. */
-               i915_modparams.enable_psr = 0;
+       /*
+        * If a PSR error happened and the driver is reloaded, the EDP_PSR_IIR
+        * will still keep the error set even after the reset done in the
+        * irq_preinstall and irq_uninstall hooks.
+        * And enabling in this situation cause the screen to freeze in the
+        * first time that PSR HW tries to activate so lets keep PSR disabled
+        * to avoid any rendering problems.
+        */
+       val = I915_READ(EDP_PSR_IIR);
+       val &= EDP_PSR_ERROR(edp_psr_shift(TRANSCODER_EDP));
+       if (val) {
+               DRM_DEBUG_KMS("PSR interruption error set\n");
+               dev_priv->psr.sink_not_reliable = true;
+               return;
        }
 
        /* Set link_standby x link_off defaults */
@@ -1109,6 +1175,7 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
        if ((val & DP_PSR_SINK_STATE_MASK) == DP_PSR_SINK_INTERNAL_ERROR) {
                DRM_DEBUG_KMS("PSR sink internal error, disabling PSR\n");
                intel_psr_disable_locked(intel_dp);
+               psr->sink_not_reliable = true;
        }
 
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_ERROR_STATUS, &val) != 1) {
@@ -1126,12 +1193,27 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
        if (val & ~errors)
                DRM_ERROR("PSR_ERROR_STATUS unhandled errors %x\n",
                          val & ~errors);
-       if (val & errors)
+       if (val & errors) {
                intel_psr_disable_locked(intel_dp);
+               psr->sink_not_reliable = true;
+       }
        /* clear status register */
        drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_ERROR_STATUS, val);
-
-       /* TODO: handle PSR2 errors */
 exit:
        mutex_unlock(&psr->lock);
 }
+
+bool intel_psr_enabled(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+       bool ret;
+
+       if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp))
+               return false;
+
+       mutex_lock(&dev_priv->psr.lock);
+       ret = (dev_priv->psr.dp == intel_dp && dev_priv->psr.enabled);
+       mutex_unlock(&dev_priv->psr.lock);
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_quirks.c b/drivers/gpu/drm/i915/intel_quirks.c
new file mode 100644 (file)
index 0000000..ec2b0fc
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include <linux/dmi.h>
+
+#include "intel_drv.h"
+
+/*
+ * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
+ */
+static void quirk_ssc_force_disable(struct drm_i915_private *i915)
+{
+       i915->quirks |= QUIRK_LVDS_SSC_DISABLE;
+       DRM_INFO("applying lvds SSC disable quirk\n");
+}
+
+/*
+ * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
+ * brightness value
+ */
+static void quirk_invert_brightness(struct drm_i915_private *i915)
+{
+       i915->quirks |= QUIRK_INVERT_BRIGHTNESS;
+       DRM_INFO("applying inverted panel brightness quirk\n");
+}
+
+/* Some VBT's incorrectly indicate no backlight is present */
+static void quirk_backlight_present(struct drm_i915_private *i915)
+{
+       i915->quirks |= QUIRK_BACKLIGHT_PRESENT;
+       DRM_INFO("applying backlight present quirk\n");
+}
+
+/* Toshiba Satellite P50-C-18C requires T12 delay to be min 800ms
+ * which is 300 ms greater than eDP spec T12 min.
+ */
+static void quirk_increase_t12_delay(struct drm_i915_private *i915)
+{
+       i915->quirks |= QUIRK_INCREASE_T12_DELAY;
+       DRM_INFO("Applying T12 delay quirk\n");
+}
+
+/*
+ * GeminiLake NUC HDMI outputs require additional off time
+ * this allows the onboard retimer to correctly sync to signal
+ */
+static void quirk_increase_ddi_disabled_time(struct drm_i915_private *i915)
+{
+       i915->quirks |= QUIRK_INCREASE_DDI_DISABLED_TIME;
+       DRM_INFO("Applying Increase DDI Disabled quirk\n");
+}
+
+struct intel_quirk {
+       int device;
+       int subsystem_vendor;
+       int subsystem_device;
+       void (*hook)(struct drm_i915_private *i915);
+};
+
+/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
+struct intel_dmi_quirk {
+       void (*hook)(struct drm_i915_private *i915);
+       const struct dmi_system_id (*dmi_id_list)[];
+};
+
+static int intel_dmi_reverse_brightness(const struct dmi_system_id *id)
+{
+       DRM_INFO("Backlight polarity reversed on %s\n", id->ident);
+       return 1;
+}
+
+static const struct intel_dmi_quirk intel_dmi_quirks[] = {
+       {
+               .dmi_id_list = &(const struct dmi_system_id[]) {
+                       {
+                               .callback = intel_dmi_reverse_brightness,
+                               .ident = "NCR Corporation",
+                               .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"),
+                                           DMI_MATCH(DMI_PRODUCT_NAME, ""),
+                               },
+                       },
+                       { }  /* terminating entry */
+               },
+               .hook = quirk_invert_brightness,
+       },
+};
+
+static struct intel_quirk intel_quirks[] = {
+       /* Lenovo U160 cannot use SSC on LVDS */
+       { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
+
+       /* Sony Vaio Y cannot use SSC on LVDS */
+       { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
+
+       /* Acer Aspire 5734Z must invert backlight brightness */
+       { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
+
+       /* Acer/eMachines G725 */
+       { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
+
+       /* Acer/eMachines e725 */
+       { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
+
+       /* Acer/Packard Bell NCL20 */
+       { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
+
+       /* Acer Aspire 4736Z */
+       { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
+
+       /* Acer Aspire 5336 */
+       { 0x2a42, 0x1025, 0x048a, quirk_invert_brightness },
+
+       /* Acer C720 and C720P Chromebooks (Celeron 2955U) have backlights */
+       { 0x0a06, 0x1025, 0x0a11, quirk_backlight_present },
+
+       /* Acer C720 Chromebook (Core i3 4005U) */
+       { 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
+
+       /* Apple Macbook 2,1 (Core 2 T7400) */
+       { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
+
+       /* Apple Macbook 4,1 */
+       { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
+
+       /* Toshiba CB35 Chromebook (Celeron 2955U) */
+       { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
+
+       /* HP Chromebook 14 (Celeron 2955U) */
+       { 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
+
+       /* Dell Chromebook 11 */
+       { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
+
+       /* Dell Chromebook 11 (2015 version) */
+       { 0x0a16, 0x1028, 0x0a35, quirk_backlight_present },
+
+       /* Toshiba Satellite P50-C-18C */
+       { 0x191B, 0x1179, 0xF840, quirk_increase_t12_delay },
+
+       /* GeminiLake NUC */
+       { 0x3185, 0x8086, 0x2072, quirk_increase_ddi_disabled_time },
+       { 0x3184, 0x8086, 0x2072, quirk_increase_ddi_disabled_time },
+       /* ASRock ITX*/
+       { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
+       { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
+};
+
+void intel_init_quirks(struct drm_i915_private *i915)
+{
+       struct pci_dev *d = i915->drm.pdev;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) {
+               struct intel_quirk *q = &intel_quirks[i];
+
+               if (d->device == q->device &&
+                   (d->subsystem_vendor == q->subsystem_vendor ||
+                    q->subsystem_vendor == PCI_ANY_ID) &&
+                   (d->subsystem_device == q->subsystem_device ||
+                    q->subsystem_device == PCI_ANY_ID))
+                       q->hook(i915);
+       }
+       for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) {
+               if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0)
+                       intel_dmi_quirks[i].hook(i915);
+       }
+}
index 1f8d2a66c791fee7a4e279942324015d6add1371..fbeaec3994e7fff3d4a72f94225dd85fa536c832 100644 (file)
@@ -533,6 +533,13 @@ static int init_ring_common(struct intel_engine_cs *engine)
 
        intel_engine_reset_breadcrumbs(engine);
 
+       if (HAS_LEGACY_SEMAPHORES(engine->i915)) {
+               I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
+               I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
+               if (HAS_VEBOX(dev_priv))
+                       I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
+       }
+
        /* Enforce ordering by reading HEAD register back */
        I915_READ_HEAD(engine);
 
@@ -550,10 +557,11 @@ static int init_ring_common(struct intel_engine_cs *engine)
        /* Check that the ring offsets point within the ring! */
        GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->head));
        GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->tail));
-
        intel_ring_update_space(ring);
+
+       /* First wake the ring up to an empty/idle ring */
        I915_WRITE_HEAD(engine, ring->head);
-       I915_WRITE_TAIL(engine, ring->tail);
+       I915_WRITE_TAIL(engine, ring->head);
        (void)I915_READ_TAIL(engine);
 
        I915_WRITE_CTL(engine, RING_CTL_SIZE(ring->size) | RING_VALID);
@@ -578,6 +586,12 @@ static int init_ring_common(struct intel_engine_cs *engine)
        if (INTEL_GEN(dev_priv) > 2)
                I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
 
+       /* Now awake, let it get started */
+       if (ring->tail != ring->head) {
+               I915_WRITE_TAIL(engine, ring->tail);
+               (void)I915_READ_TAIL(engine);
+       }
+
        /* Papering over lost _interrupts_ immediately following the restart */
        intel_engine_wakeup(engine);
 out:
@@ -612,7 +626,9 @@ static void skip_request(struct i915_request *rq)
 
 static void reset_ring(struct intel_engine_cs *engine, struct i915_request *rq)
 {
-       GEM_TRACE("%s seqno=%x\n", engine->name, rq ? rq->global_seqno : 0);
+       GEM_TRACE("%s request global=%d, current=%d\n",
+                 engine->name, rq ? rq->global_seqno : 0,
+                 intel_engine_get_seqno(engine));
 
        /*
         * Try to restore the logical GPU state to match the continuation
@@ -644,7 +660,7 @@ static int intel_rcs_ctx_init(struct i915_request *rq)
 {
        int ret;
 
-       ret = intel_ctx_workarounds_emit(rq);
+       ret = intel_engine_emit_ctx_wa(rq);
        if (ret != 0)
                return ret;
 
@@ -662,8 +678,6 @@ static int init_render_ring(struct intel_engine_cs *engine)
        if (ret)
                return ret;
 
-       intel_whitelist_workarounds_apply(engine);
-
        /* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
        if (IS_GEN(dev_priv, 4, 6))
                I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
@@ -745,9 +759,18 @@ static void cancel_requests(struct intel_engine_cs *engine)
        /* Mark all submitted requests as skipped. */
        list_for_each_entry(request, &engine->timeline.requests, link) {
                GEM_BUG_ON(!request->global_seqno);
-               if (!i915_request_completed(request))
-                       dma_fence_set_error(&request->fence, -EIO);
+
+               if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+                            &request->fence.flags))
+                       continue;
+
+               dma_fence_set_error(&request->fence, -EIO);
        }
+
+       intel_write_status_page(engine,
+                               I915_GEM_HWS_INDEX,
+                               intel_engine_last_submit(engine));
+
        /* Remaining _unready_ requests will be nop'ed when submitted */
 
        spin_unlock_irqrestore(&engine->timeline.lock, flags);
@@ -1061,8 +1084,7 @@ i915_emit_bb_start(struct i915_request *rq,
 int intel_ring_pin(struct intel_ring *ring)
 {
        struct i915_vma *vma = ring->vma;
-       enum i915_map_type map =
-               HAS_LLC(vma->vm->i915) ? I915_MAP_WB : I915_MAP_WC;
+       enum i915_map_type map = i915_coherent_map_type(vma->vm->i915);
        unsigned int flags;
        void *addr;
        int ret;
index 767a7192c969751da0fce60a0874523049bc1de2..72edaa7ff4114fc61894f298f8d3952e8c5855c9 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: MIT */
 #ifndef _INTEL_RINGBUFFER_H_
 #define _INTEL_RINGBUFFER_H_
 
@@ -94,11 +94,11 @@ hangcheck_action_to_str(const enum intel_engine_hangcheck_action a)
 #define I915_MAX_SUBSLICES 8
 
 #define instdone_slice_mask(dev_priv__) \
-       (INTEL_GEN(dev_priv__) == 7 ? \
+       (IS_GEN7(dev_priv__) ? \
         1 : INTEL_INFO(dev_priv__)->sseu.slice_mask)
 
 #define instdone_subslice_mask(dev_priv__) \
-       (INTEL_GEN(dev_priv__) == 7 ? \
+       (IS_GEN7(dev_priv__) ? \
         1 : INTEL_INFO(dev_priv__)->sseu.subslice_mask[0])
 
 #define for_each_instdone_slice_subslice(dev_priv__, slice__, subslice__) \
@@ -191,11 +191,22 @@ enum intel_engine_id {
 };
 
 struct i915_priolist {
+       struct list_head requests[I915_PRIORITY_COUNT];
        struct rb_node node;
-       struct list_head requests;
+       unsigned long used;
        int priority;
 };
 
+#define priolist_for_each_request(it, plist, idx) \
+       for (idx = 0; idx < ARRAY_SIZE((plist)->requests); idx++) \
+               list_for_each_entry(it, &(plist)->requests[idx], sched.link)
+
+#define priolist_for_each_request_consume(it, n, plist, idx) \
+       for (; (idx = ffs((plist)->used)); (plist)->used &= ~BIT(idx - 1)) \
+               list_for_each_entry_safe(it, n, \
+                                        &(plist)->requests[idx - 1], \
+                                        sched.link)
+
 struct st_preempt_hang {
        struct completion completion;
        bool inject_hang;
@@ -302,13 +313,6 @@ struct intel_engine_execlists {
         */
        struct rb_root_cached queue;
 
-       /**
-        * @csb_read: control register for Context Switch buffer
-        *
-        * Note this register is always in mmio.
-        */
-       u32 __iomem *csb_read;
-
        /**
         * @csb_write: control register for Context Switch buffer
         *
@@ -328,15 +332,6 @@ struct intel_engine_execlists {
         */
        u32 preempt_complete_status;
 
-       /**
-        * @csb_write_reset: reset value for CSB write pointer
-        *
-        * As the CSB write pointer maybe either in HWSP or as a field
-        * inside an mmio register, we want to reprogram it slightly
-        * differently to avoid later confusion.
-        */
-       u32 csb_write_reset;
-
        /**
         * @csb_head: context status buffer head
         */
@@ -441,7 +436,9 @@ struct intel_engine_cs {
 
        struct intel_hw_status_page status_page;
        struct i915_ctx_workarounds wa_ctx;
+       struct i915_wa_list ctx_wa_list;
        struct i915_wa_list wa_list;
+       struct i915_wa_list whitelist;
 
        u32             irq_keep_mask; /* always keep these interrupts */
        u32             irq_enable_mask; /* bitmask to enable ring interrupt */
@@ -488,11 +485,10 @@ struct intel_engine_cs {
         */
        void            (*submit_request)(struct i915_request *rq);
 
-       /* Call when the priority on a request has changed and it and its
+       /*
+        * Call when the priority on a request has changed and it and its
         * dependencies may need rescheduling. Note the request itself may
         * not be ready to run!
-        *
-        * Called under the struct_mutex.
         */
        void            (*schedule)(struct i915_request *request,
                                    const struct i915_sched_attr *attr);
index 44e4491a4918994b80ddde101042368263abf8d1..4350a5270423c1b924a5e69a75ea0ff27b0ec31f 100644 (file)
@@ -76,6 +76,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
                return "TRANSCODER_C";
        case POWER_DOMAIN_TRANSCODER_EDP:
                return "TRANSCODER_EDP";
+       case POWER_DOMAIN_TRANSCODER_EDP_VDSC:
+               return "TRANSCODER_EDP_VDSC";
        case POWER_DOMAIN_TRANSCODER_DSI_A:
                return "TRANSCODER_DSI_A";
        case POWER_DOMAIN_TRANSCODER_DSI_C:
@@ -208,7 +210,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
 
        is_enabled = true;
 
-       for_each_power_domain_well_rev(dev_priv, power_well, BIT_ULL(domain)) {
+       for_each_power_domain_well_reverse(dev_priv, power_well, BIT_ULL(domain)) {
                if (power_well->desc->always_on)
                        continue;
 
@@ -436,6 +438,15 @@ icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
        I915_WRITE(ICL_PORT_CL_DW12(port), val | ICL_LANE_ENABLE_AUX);
 
        hsw_wait_for_power_well_enable(dev_priv, power_well);
+
+       /* Display WA #1178: icl */
+       if (IS_ICELAKE(dev_priv) &&
+           pw_idx >= ICL_PW_CTL_IDX_AUX_A && pw_idx <= ICL_PW_CTL_IDX_AUX_B &&
+           !intel_bios_is_port_edp(dev_priv, port)) {
+               val = I915_READ(ICL_AUX_ANAOVRD1(pw_idx));
+               val |= ICL_AUX_ANAOVRD1_ENABLE | ICL_AUX_ANAOVRD1_LDO_BYPASS;
+               I915_WRITE(ICL_AUX_ANAOVRD1(pw_idx), val);
+       }
 }
 
 static void
@@ -456,6 +467,25 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
        hsw_wait_for_power_well_disable(dev_priv, power_well);
 }
 
+#define ICL_AUX_PW_TO_CH(pw_idx)       \
+       ((pw_idx) - ICL_PW_CTL_IDX_AUX_A + AUX_CH_A)
+
+static void
+icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
+                                struct i915_power_well *power_well)
+{
+       enum aux_ch aux_ch = ICL_AUX_PW_TO_CH(power_well->desc->hsw.idx);
+       u32 val;
+
+       val = I915_READ(DP_AUX_CH_CTL(aux_ch));
+       val &= ~DP_AUX_CH_CTL_TBT_IO;
+       if (power_well->desc->hsw.is_tc_tbt)
+               val |= DP_AUX_CH_CTL_TBT_IO;
+       I915_WRITE(DP_AUX_CH_CTL(aux_ch), val);
+
+       hsw_power_well_enable(dev_priv, power_well);
+}
+
 /*
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
@@ -465,11 +495,25 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
        const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+       enum i915_power_well_id id = power_well->desc->id;
        int pw_idx = power_well->desc->hsw.idx;
        u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx) |
                   HSW_PWR_WELL_CTL_STATE(pw_idx);
+       u32 val;
+
+       val = I915_READ(regs->driver);
 
-       return (I915_READ(regs->driver) & mask) == mask;
+       /*
+        * On GEN9 big core due to a DMC bug the driver's request bits for PW1
+        * and the MISC_IO PW will be not restored, so check instead for the
+        * BIOS's own request bits, which are forced-on for these power wells
+        * when exiting DC5/6.
+        */
+       if (IS_GEN9(dev_priv) && !IS_GEN9_LP(dev_priv) &&
+           (id == SKL_DISP_PW_1 || id == SKL_DISP_PW_MISC_IO))
+               val |= I915_READ(regs->bios);
+
+       return (val & mask) == mask;
 }
 
 static void assert_can_enable_dc9(struct drm_i915_private *dev_priv)
@@ -551,7 +595,9 @@ static u32 gen9_dc_mask(struct drm_i915_private *dev_priv)
        u32 mask;
 
        mask = DC_STATE_EN_UPTO_DC5;
-       if (IS_GEN9_LP(dev_priv))
+       if (INTEL_GEN(dev_priv) >= 11)
+               mask |= DC_STATE_EN_UPTO_DC6 | DC_STATE_EN_DC9;
+       else if (IS_GEN9_LP(dev_priv))
                mask |= DC_STATE_EN_DC9;
        else
                mask |= DC_STATE_EN_UPTO_DC6;
@@ -624,8 +670,13 @@ void bxt_enable_dc9(struct drm_i915_private *dev_priv)
        assert_can_enable_dc9(dev_priv);
 
        DRM_DEBUG_KMS("Enabling DC9\n");
-
-       intel_power_sequencer_reset(dev_priv);
+       /*
+        * Power sequencer reset is not needed on
+        * platforms with South Display Engine on PCH,
+        * because PPS registers are always on.
+        */
+       if (!HAS_PCH_SPLIT(dev_priv))
+               intel_power_sequencer_reset(dev_priv);
        gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
 }
 
@@ -707,7 +758,7 @@ static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
        assert_csr_loaded(dev_priv);
 }
 
-static void skl_enable_dc6(struct drm_i915_private *dev_priv)
+void skl_enable_dc6(struct drm_i915_private *dev_priv)
 {
        assert_can_enable_dc6(dev_priv);
 
@@ -808,6 +859,14 @@ static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
 
        if (IS_GEN9_LP(dev_priv))
                bxt_verify_ddi_phy_power_wells(dev_priv);
+
+       if (INTEL_GEN(dev_priv) >= 11)
+               /*
+                * DMC retains HW context only for port A, the other combo
+                * PHY's HW context for port B is lost after DC transitions,
+                * so we need to restore it manually.
+                */
+               icl_combo_phys_init(dev_priv);
 }
 
 static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
@@ -1608,7 +1667,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
             intel_display_power_domain_str(domain));
        power_domains->domain_use_count[domain]--;
 
-       for_each_power_domain_well_rev(dev_priv, power_well, BIT_ULL(domain))
+       for_each_power_domain_well_reverse(dev_priv, power_well, BIT_ULL(domain))
                intel_power_well_put(dev_priv, power_well);
 
        mutex_unlock(&power_domains->lock);
@@ -1971,9 +2030,9 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
         */
 #define ICL_PW_2_POWER_DOMAINS (                       \
        ICL_PW_3_POWER_DOMAINS |                        \
+       BIT_ULL(POWER_DOMAIN_TRANSCODER_EDP_VDSC) |             \
        BIT_ULL(POWER_DOMAIN_INIT))
        /*
-        * - eDP/DSI VDSC
         * - KVMR (HW control)
         */
 #define ICL_DISPLAY_DC_OFF_POWER_DOMAINS (             \
@@ -2041,7 +2100,7 @@ static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = {
 static const struct i915_power_well_desc i9xx_always_on_power_well[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2058,7 +2117,7 @@ static const struct i915_power_well_ops i830_pipes_power_well_ops = {
 static const struct i915_power_well_desc i830_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2102,7 +2161,7 @@ static const struct i915_power_well_regs hsw_power_well_regs = {
 static const struct i915_power_well_desc hsw_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2123,7 +2182,7 @@ static const struct i915_power_well_desc hsw_power_wells[] = {
 static const struct i915_power_well_desc bdw_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2166,7 +2225,7 @@ static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
 static const struct i915_power_well_desc vlv_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2242,7 +2301,7 @@ static const struct i915_power_well_desc vlv_power_wells[] = {
 static const struct i915_power_well_desc chv_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2293,7 +2352,7 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 static const struct i915_power_well_desc skl_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2301,6 +2360,7 @@ static const struct i915_power_well_desc skl_power_wells[] = {
        {
                .name = "power well 1",
                /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_1,
@@ -2313,6 +2373,7 @@ static const struct i915_power_well_desc skl_power_wells[] = {
        {
                .name = "MISC IO power well",
                /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_MISC_IO,
@@ -2385,13 +2446,15 @@ static const struct i915_power_well_desc skl_power_wells[] = {
 static const struct i915_power_well_desc bxt_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
        },
        {
                .name = "power well 1",
+               /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_1,
@@ -2443,7 +2506,7 @@ static const struct i915_power_well_desc bxt_power_wells[] = {
 static const struct i915_power_well_desc glk_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2451,6 +2514,7 @@ static const struct i915_power_well_desc glk_power_wells[] = {
        {
                .name = "power well 1",
                /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_1,
@@ -2571,7 +2635,7 @@ static const struct i915_power_well_desc glk_power_wells[] = {
 static const struct i915_power_well_desc cnl_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2579,6 +2643,7 @@ static const struct i915_power_well_desc cnl_power_wells[] = {
        {
                .name = "power well 1",
                /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_1,
@@ -2716,6 +2781,13 @@ static const struct i915_power_well_ops icl_combo_phy_aux_power_well_ops = {
        .is_enabled = hsw_power_well_enabled,
 };
 
+static const struct i915_power_well_ops icl_tc_phy_aux_power_well_ops = {
+       .sync_hw = hsw_power_well_sync_hw,
+       .enable = icl_tc_phy_aux_power_well_enable,
+       .disable = hsw_power_well_disable,
+       .is_enabled = hsw_power_well_enabled,
+};
+
 static const struct i915_power_well_regs icl_aux_power_well_regs = {
        .bios   = ICL_PWR_WELL_CTL_AUX1,
        .driver = ICL_PWR_WELL_CTL_AUX2,
@@ -2731,7 +2803,7 @@ static const struct i915_power_well_regs icl_ddi_power_well_regs = {
 static const struct i915_power_well_desc icl_power_wells[] = {
        {
                .name = "always-on",
-               .always_on = 1,
+               .always_on = true,
                .domains = POWER_DOMAIN_MASK,
                .ops = &i9xx_always_on_power_well_ops,
                .id = DISP_PW_ID_NONE,
@@ -2739,6 +2811,7 @@ static const struct i915_power_well_desc icl_power_wells[] = {
        {
                .name = "power well 1",
                /* Handled by the DMC firmware */
+               .always_on = true,
                .domains = 0,
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_1,
@@ -2861,81 +2934,89 @@ static const struct i915_power_well_desc icl_power_wells[] = {
        {
                .name = "AUX C",
                .domains = ICL_AUX_C_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_C,
+                       .hsw.is_tc_tbt = false,
                },
        },
        {
                .name = "AUX D",
                .domains = ICL_AUX_D_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_D,
+                       .hsw.is_tc_tbt = false,
                },
        },
        {
                .name = "AUX E",
                .domains = ICL_AUX_E_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_E,
+                       .hsw.is_tc_tbt = false,
                },
        },
        {
                .name = "AUX F",
                .domains = ICL_AUX_F_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_F,
+                       .hsw.is_tc_tbt = false,
                },
        },
        {
                .name = "AUX TBT1",
                .domains = ICL_AUX_TBT1_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT1,
+                       .hsw.is_tc_tbt = true,
                },
        },
        {
                .name = "AUX TBT2",
                .domains = ICL_AUX_TBT2_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT2,
+                       .hsw.is_tc_tbt = true,
                },
        },
        {
                .name = "AUX TBT3",
                .domains = ICL_AUX_TBT3_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT3,
+                       .hsw.is_tc_tbt = true,
                },
        },
        {
                .name = "AUX TBT4",
                .domains = ICL_AUX_TBT4_IO_POWER_DOMAINS,
-               .ops = &hsw_power_well_ops,
+               .ops = &icl_tc_phy_aux_power_well_ops,
                .id = DISP_PW_ID_NONE,
                {
                        .hsw.regs = &icl_aux_power_well_regs,
                        .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT4,
+                       .hsw.is_tc_tbt = true,
                },
        },
        {
@@ -2969,17 +3050,20 @@ static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
        int requested_dc;
        int max_dc;
 
-       if (IS_GEN9_BC(dev_priv) || INTEL_INFO(dev_priv)->gen >= 10) {
+       if (INTEL_GEN(dev_priv) >= 11) {
                max_dc = 2;
-               mask = 0;
-       } else if (IS_GEN9_LP(dev_priv)) {
-               max_dc = 1;
                /*
                 * DC9 has a separate HW flow from the rest of the DC states,
                 * not depending on the DMC firmware. It's needed by system
                 * suspend/resume, so allow it unconditionally.
                 */
                mask = DC_STATE_EN_DC9;
+       } else if (IS_GEN10(dev_priv) || IS_GEN9_BC(dev_priv)) {
+               max_dc = 2;
+               mask = 0;
+       } else if (IS_GEN9_LP(dev_priv)) {
+               max_dc = 1;
+               mask = DC_STATE_EN_DC9;
        } else {
                max_dc = 0;
                mask = 0;
@@ -3075,12 +3159,6 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
         */
        if (IS_ICELAKE(dev_priv)) {
                err = set_power_wells(power_domains, icl_power_wells);
-       } else if (IS_HASWELL(dev_priv)) {
-               err = set_power_wells(power_domains, hsw_power_wells);
-       } else if (IS_BROADWELL(dev_priv)) {
-               err = set_power_wells(power_domains, bdw_power_wells);
-       } else if (IS_GEN9_BC(dev_priv)) {
-               err = set_power_wells(power_domains, skl_power_wells);
        } else if (IS_CANNONLAKE(dev_priv)) {
                err = set_power_wells(power_domains, cnl_power_wells);
 
@@ -3092,13 +3170,18 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
                 */
                if (!IS_CNL_WITH_PORT_F(dev_priv))
                        power_domains->power_well_count -= 2;
-
-       } else if (IS_BROXTON(dev_priv)) {
-               err = set_power_wells(power_domains, bxt_power_wells);
        } else if (IS_GEMINILAKE(dev_priv)) {
                err = set_power_wells(power_domains, glk_power_wells);
+       } else if (IS_BROXTON(dev_priv)) {
+               err = set_power_wells(power_domains, bxt_power_wells);
+       } else if (IS_GEN9_BC(dev_priv)) {
+               err = set_power_wells(power_domains, skl_power_wells);
        } else if (IS_CHERRYVIEW(dev_priv)) {
                err = set_power_wells(power_domains, chv_power_wells);
+       } else if (IS_BROADWELL(dev_priv)) {
+               err = set_power_wells(power_domains, bdw_power_wells);
+       } else if (IS_HASWELL(dev_priv)) {
+               err = set_power_wells(power_domains, hsw_power_wells);
        } else if (IS_VALLEYVIEW(dev_priv)) {
                err = set_power_wells(power_domains, vlv_power_wells);
        } else if (IS_I830(dev_priv)) {
@@ -3238,18 +3321,40 @@ static void icl_mbus_init(struct drm_i915_private *dev_priv)
        I915_WRITE(MBUS_ABOX_CTL, val);
 }
 
+static void intel_pch_reset_handshake(struct drm_i915_private *dev_priv,
+                                     bool enable)
+{
+       i915_reg_t reg;
+       u32 reset_bits, val;
+
+       if (IS_IVYBRIDGE(dev_priv)) {
+               reg = GEN7_MSG_CTL;
+               reset_bits = WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK;
+       } else {
+               reg = HSW_NDE_RSTWRN_OPT;
+               reset_bits = RESET_PCH_HANDSHAKE_ENABLE;
+       }
+
+       val = I915_READ(reg);
+
+       if (enable)
+               val |= reset_bits;
+       else
+               val &= ~reset_bits;
+
+       I915_WRITE(reg, val);
+}
+
 static void skl_display_core_init(struct drm_i915_private *dev_priv,
                                   bool resume)
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       uint32_t val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
        /* enable PCH reset handshake */
-       val = I915_READ(HSW_NDE_RSTWRN_OPT);
-       I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
+       intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
 
        /* enable PG1 and Misc I/O */
        mutex_lock(&power_domains->lock);
@@ -3305,7 +3410,6 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv,
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       uint32_t val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
@@ -3315,9 +3419,7 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv,
         * Move the handshake programming to initialization sequence.
         * Previously was left up to BIOS.
         */
-       val = I915_READ(HSW_NDE_RSTWRN_OPT);
-       val &= ~RESET_PCH_HANDSHAKE_ENABLE;
-       I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
+       intel_pch_reset_handshake(dev_priv, false);
 
        /* Enable PG1 */
        mutex_lock(&power_domains->lock);
@@ -3363,101 +3465,18 @@ void bxt_display_core_uninit(struct drm_i915_private *dev_priv)
        usleep_range(10, 30);           /* 10 us delay per Bspec */
 }
 
-enum {
-       PROCMON_0_85V_DOT_0,
-       PROCMON_0_95V_DOT_0,
-       PROCMON_0_95V_DOT_1,
-       PROCMON_1_05V_DOT_0,
-       PROCMON_1_05V_DOT_1,
-};
-
-static const struct cnl_procmon {
-       u32 dw1, dw9, dw10;
-} cnl_procmon_values[] = {
-       [PROCMON_0_85V_DOT_0] =
-               { .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, },
-       [PROCMON_0_95V_DOT_0] =
-               { .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, },
-       [PROCMON_0_95V_DOT_1] =
-               { .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, },
-       [PROCMON_1_05V_DOT_0] =
-               { .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, },
-       [PROCMON_1_05V_DOT_1] =
-               { .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, },
-};
-
-/*
- * CNL has just one set of registers, while ICL has two sets: one for port A and
- * the other for port B. The CNL registers are equivalent to the ICL port A
- * registers, that's why we call the ICL macros even though the function has CNL
- * on its name.
- */
-static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
-                                      enum port port)
-{
-       const struct cnl_procmon *procmon;
-       u32 val;
-
-       val = I915_READ(ICL_PORT_COMP_DW3(port));
-       switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
-       default:
-               MISSING_CASE(val);
-               /* fall through */
-       case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0:
-               procmon = &cnl_procmon_values[PROCMON_0_85V_DOT_0];
-               break;
-       case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_0:
-               procmon = &cnl_procmon_values[PROCMON_0_95V_DOT_0];
-               break;
-       case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_1:
-               procmon = &cnl_procmon_values[PROCMON_0_95V_DOT_1];
-               break;
-       case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_0:
-               procmon = &cnl_procmon_values[PROCMON_1_05V_DOT_0];
-               break;
-       case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_1:
-               procmon = &cnl_procmon_values[PROCMON_1_05V_DOT_1];
-               break;
-       }
-
-       val = I915_READ(ICL_PORT_COMP_DW1(port));
-       val &= ~((0xff << 16) | 0xff);
-       val |= procmon->dw1;
-       I915_WRITE(ICL_PORT_COMP_DW1(port), val);
-
-       I915_WRITE(ICL_PORT_COMP_DW9(port), procmon->dw9);
-       I915_WRITE(ICL_PORT_COMP_DW10(port), procmon->dw10);
-}
-
 static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume)
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       u32 val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
        /* 1. Enable PCH Reset Handshake */
-       val = I915_READ(HSW_NDE_RSTWRN_OPT);
-       val |= RESET_PCH_HANDSHAKE_ENABLE;
-       I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
-
-       /* 2. Enable Comp */
-       val = I915_READ(CHICKEN_MISC_2);
-       val &= ~CNL_COMP_PWR_DOWN;
-       I915_WRITE(CHICKEN_MISC_2, val);
-
-       /* Dummy PORT_A to get the correct CNL register from the ICL macro */
-       cnl_set_procmon_ref_values(dev_priv, PORT_A);
+       intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
 
-       val = I915_READ(CNL_PORT_COMP_DW0);
-       val |= COMP_INIT;
-       I915_WRITE(CNL_PORT_COMP_DW0, val);
-
-       /* 3. */
-       val = I915_READ(CNL_PORT_CL1CM_DW5);
-       val |= CL_POWER_DOWN_ENABLE;
-       I915_WRITE(CNL_PORT_CL1CM_DW5, val);
+       /* 2-3. */
+       cnl_combo_phys_init(dev_priv);
 
        /*
         * 4. Enable Power Well 1 (PG1).
@@ -3482,7 +3501,6 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv)
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       u32 val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
@@ -3506,44 +3524,23 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv)
 
        usleep_range(10, 30);           /* 10 us delay per Bspec */
 
-       /* 5. Disable Comp */
-       val = I915_READ(CHICKEN_MISC_2);
-       val |= CNL_COMP_PWR_DOWN;
-       I915_WRITE(CHICKEN_MISC_2, val);
+       /* 5. */
+       cnl_combo_phys_uninit(dev_priv);
 }
 
-static void icl_display_core_init(struct drm_i915_private *dev_priv,
-                                 bool resume)
+void icl_display_core_init(struct drm_i915_private *dev_priv,
+                          bool resume)
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       enum port port;
-       u32 val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
        /* 1. Enable PCH reset handshake. */
-       val = I915_READ(HSW_NDE_RSTWRN_OPT);
-       val |= RESET_PCH_HANDSHAKE_ENABLE;
-       I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
-
-       for (port = PORT_A; port <= PORT_B; port++) {
-               /* 2. Enable DDI combo PHY comp. */
-               val = I915_READ(ICL_PHY_MISC(port));
-               val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
-               I915_WRITE(ICL_PHY_MISC(port), val);
-
-               cnl_set_procmon_ref_values(dev_priv, port);
-
-               val = I915_READ(ICL_PORT_COMP_DW0(port));
-               val |= COMP_INIT;
-               I915_WRITE(ICL_PORT_COMP_DW0(port), val);
-
-               /* 3. Set power down enable. */
-               val = I915_READ(ICL_PORT_CL_DW5(port));
-               val |= CL_POWER_DOWN_ENABLE;
-               I915_WRITE(ICL_PORT_CL_DW5(port), val);
-       }
+       intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
+
+       /* 2-3. */
+       icl_combo_phys_init(dev_priv);
 
        /*
         * 4. Enable Power Well 1 (PG1).
@@ -3567,12 +3564,10 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
                intel_csr_load_program(dev_priv);
 }
 
-static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
+void icl_display_core_uninit(struct drm_i915_private *dev_priv)
 {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *well;
-       enum port port;
-       u32 val;
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 
@@ -3594,12 +3589,8 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
        intel_power_well_disable(dev_priv, well);
        mutex_unlock(&power_domains->lock);
 
-       /* 5. Disable Comp */
-       for (port = PORT_A; port <= PORT_B; port++) {
-               val = I915_READ(ICL_PHY_MISC(port));
-               val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
-               I915_WRITE(ICL_PHY_MISC(port), val);
-       }
+       /* 5. */
+       icl_combo_phys_uninit(dev_priv);
 }
 
 static void chv_phy_control_init(struct drm_i915_private *dev_priv)
@@ -3757,7 +3748,8 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
                mutex_lock(&power_domains->lock);
                vlv_cmnlane_wa(dev_priv);
                mutex_unlock(&power_domains->lock);
-       }
+       } else if (IS_IVYBRIDGE(dev_priv) || INTEL_GEN(dev_priv) >= 7)
+               intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
 
        /*
         * Keep all power wells enabled for any dependent HW access during
@@ -3951,14 +3943,6 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
                int domains_count;
                bool enabled;
 
-               /*
-                * Power wells not belonging to any domain (like the MISC_IO
-                * and PW1 power wells) are under FW control, so ignore them,
-                * since their state can change asynchronously.
-                */
-               if (!power_well->desc->domains)
-                       continue;
-
                enabled = power_well->desc->ops->is_enabled(dev_priv,
                                                            power_well);
                if ((power_well->count || power_well->desc->always_on) !=
index 701372e512a80663c75e42484663d6184f976f38..5805ec1aba122495736167c0f66ee86cd5da249d 100644 (file)
@@ -105,11 +105,6 @@ struct intel_sdvo {
        bool has_hdmi_audio;
        bool rgb_quant_range_selectable;
 
-       /**
-        * This is sdvo fixed pannel mode pointer
-        */
-       struct drm_display_mode *sdvo_lvds_fixed_mode;
-
        /* DDC bus used by this SDVO encoder */
        uint8_t ddc_bus;
 
@@ -765,10 +760,14 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
        args.height = height;
        args.interlace = 0;
 
-       if (IS_LVDS(intel_sdvo_connector) &&
-          (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width ||
-           intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height))
-               args.scaled = 1;
+       if (IS_LVDS(intel_sdvo_connector)) {
+               const struct drm_display_mode *fixed_mode =
+                       intel_sdvo_connector->base.panel.fixed_mode;
+
+               if (fixed_mode->hdisplay != width ||
+                   fixed_mode->vdisplay != height)
+                       args.scaled = 1;
+       }
 
        return intel_sdvo_set_value(intel_sdvo,
                                    SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
@@ -1123,6 +1122,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 
        DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
        pipe_config->pipe_bpp = 8*3;
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
        if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
                pipe_config->has_pch_encoder = true;
@@ -1144,7 +1144,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
                pipe_config->sdvo_tv_clock = true;
        } else if (IS_LVDS(intel_sdvo_connector)) {
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-                                                            intel_sdvo->sdvo_lvds_fixed_mode))
+                                                            intel_sdvo_connector->base.panel.fixed_mode))
                        return false;
 
                (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
@@ -1301,7 +1301,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
        /* lvds has a special fixed output timing. */
        if (IS_LVDS(intel_sdvo_connector))
                intel_sdvo_get_dtd_from_mode(&output_dtd,
-                                            intel_sdvo->sdvo_lvds_fixed_mode);
+                                            intel_sdvo_connector->base.panel.fixed_mode);
        else
                intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
        if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
@@ -1642,10 +1642,13 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
                return MODE_CLOCK_HIGH;
 
        if (IS_LVDS(intel_sdvo_connector)) {
-               if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay)
+               const struct drm_display_mode *fixed_mode =
+                       intel_sdvo_connector->base.panel.fixed_mode;
+
+               if (mode->hdisplay > fixed_mode->hdisplay)
                        return MODE_PANEL;
 
-               if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay)
+               if (mode->vdisplay > fixed_mode->vdisplay)
                        return MODE_PANEL;
        }
 
@@ -2058,14 +2061,6 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
        return !list_empty(&connector->probed_modes);
 }
 
-static void intel_sdvo_destroy(struct drm_connector *connector)
-{
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-
-       drm_connector_cleanup(connector);
-       kfree(intel_sdvo_connector);
-}
-
 static int
 intel_sdvo_connector_atomic_get_property(struct drm_connector *connector,
                                         const struct drm_connector_state *state,
@@ -2228,7 +2223,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
        .atomic_set_property = intel_sdvo_connector_atomic_set_property,
        .late_register = intel_sdvo_connector_register,
        .early_unregister = intel_sdvo_connector_unregister,
-       .destroy = intel_sdvo_destroy,
+       .destroy = intel_connector_destroy,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
 };
@@ -2267,10 +2262,6 @@ static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
        struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder));
 
-       if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
-               drm_mode_destroy(encoder->dev,
-                                intel_sdvo->sdvo_lvds_fixed_mode);
-
        i2c_del_adapter(&intel_sdvo->ddc);
        intel_encoder_destroy(encoder);
 }
@@ -2583,7 +2574,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
        return true;
 
 err:
-       intel_sdvo_destroy(connector);
+       intel_connector_destroy(connector);
        return false;
 }
 
@@ -2663,19 +2654,22 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 
        list_for_each_entry(mode, &connector->probed_modes, head) {
                if (mode->type & DRM_MODE_TYPE_PREFERRED) {
-                       intel_sdvo->sdvo_lvds_fixed_mode =
+                       struct drm_display_mode *fixed_mode =
                                drm_mode_duplicate(connector->dev, mode);
+
+                       intel_panel_init(&intel_connector->panel,
+                                        fixed_mode, NULL);
                        break;
                }
        }
 
-       if (!intel_sdvo->sdvo_lvds_fixed_mode)
+       if (!intel_connector->panel.fixed_mode)
                goto err;
 
        return true;
 
 err:
-       intel_sdvo_destroy(connector);
+       intel_connector_destroy(connector);
        return false;
 }
 
@@ -2745,7 +2739,7 @@ static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
                                 &dev->mode_config.connector_list, head) {
                if (intel_attached_encoder(connector) == &intel_sdvo->base) {
                        drm_connector_unregister(connector);
-                       intel_sdvo_destroy(connector);
+                       intel_connector_destroy(connector);
                }
        }
 }
index d3090a7537bb9576c89f69d17541eadbf9353d8c..d2e003d8f3dbe64247cac7de9baf6a6fcaa0c986 100644 (file)
@@ -40,6 +40,7 @@
 #include "intel_frontbuffer.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include <drm/drm_color_mgmt.h>
 
 int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
                             int usecs)
@@ -275,17 +276,24 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
        src->y2 = (src_y + src_h) << 16;
 
        if (fb->format->is_yuv &&
-           fb->format->format != DRM_FORMAT_NV12 &&
            (src_x & 1 || src_w & 1)) {
                DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n",
                              src_x, src_w);
                return -EINVAL;
        }
 
+       if (fb->format->is_yuv &&
+           fb->format->num_planes > 1 &&
+           (src_y & 1 || src_h & 1)) {
+               DRM_DEBUG_KMS("src y/h (%u, %u) must be a multiple of 2 for planar YUV planes\n",
+                             src_y, src_h);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
-unsigned int
+static unsigned int
 skl_plane_max_stride(struct intel_plane *plane,
                     u32 pixel_format, u64 modifier,
                     unsigned int rotation)
@@ -328,7 +336,8 @@ skl_program_scaler(struct intel_plane *plane,
                                      0, INT_MAX);
 
        /* TODO: handle sub-pixel coordinates */
-       if (plane_state->base.fb->format->format == DRM_FORMAT_NV12) {
+       if (plane_state->base.fb->format->format == DRM_FORMAT_NV12 &&
+           !icl_is_hdr_plane(plane)) {
                y_hphase = skl_scaler_calc_phase(1, hscale, false);
                y_vphase = skl_scaler_calc_phase(1, vscale, false);
 
@@ -346,7 +355,6 @@ skl_program_scaler(struct intel_plane *plane,
 
        I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id),
                      PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode);
-       I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
        I915_WRITE_FW(SKL_PS_VPHASE(pipe, scaler_id),
                      PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
        I915_WRITE_FW(SKL_PS_HPHASE(pipe, scaler_id),
@@ -355,70 +363,239 @@ skl_program_scaler(struct intel_plane *plane,
        I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id), (crtc_w << 16) | crtc_h);
 }
 
-void
-skl_update_plane(struct intel_plane *plane,
-                const struct intel_crtc_state *crtc_state,
-                const struct intel_plane_state *plane_state)
+/* Preoffset values for YUV to RGB Conversion */
+#define PREOFF_YUV_TO_RGB_HI           0x1800
+#define PREOFF_YUV_TO_RGB_ME           0x1F00
+#define PREOFF_YUV_TO_RGB_LO           0x1800
+
+#define  ROFF(x)          (((x) & 0xffff) << 16)
+#define  GOFF(x)          (((x) & 0xffff) << 0)
+#define  BOFF(x)          (((x) & 0xffff) << 16)
+
+static void
+icl_program_input_csc(struct intel_plane *plane,
+                     const struct intel_crtc_state *crtc_state,
+                     const struct intel_plane_state *plane_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+       enum pipe pipe = plane->pipe;
+       enum plane_id plane_id = plane->id;
+
+       static const u16 input_csc_matrix[][9] = {
+               /*
+                * BT.601 full range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.000, 0.000, 1.371,
+                *  1.000, -0.336, -0.698,
+                *  1.000, 1.732, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT601] = {
+                       0x7AF8, 0x7800, 0x0,
+                       0x8B28, 0x7800, 0x9AC0,
+                       0x0, 0x7800, 0x7DD8,
+               },
+               /*
+                * BT.709 full range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.000, 0.000, 1.574,
+                *  1.000, -0.187, -0.468,
+                *  1.000, 1.855, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT709] = {
+                       0x7C98, 0x7800, 0x0,
+                       0x9EF8, 0x7800, 0xABF8,
+                       0x0, 0x7800,  0x7ED8,
+               },
+       };
+
+       /* Matrix for Limited Range to Full Range Conversion */
+       static const u16 input_csc_matrix_lr[][9] = {
+               /*
+                * BT.601 Limted range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.164384, 0.000, 1.596370,
+                *  1.138393, -0.382500, -0.794598,
+                *  1.138393, 1.971696, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT601] = {
+                       0x7CC8, 0x7950, 0x0,
+                       0x8CB8, 0x7918, 0x9C40,
+                       0x0, 0x7918, 0x7FC8,
+               },
+               /*
+                * BT.709 Limited range YCbCr -> full range RGB
+                * The matrix required is :
+                * [1.164, 0.000, 1.833671,
+                *  1.138393, -0.213249, -0.532909,
+                *  1.138393, 2.112402, 0.0000]
+                */
+               [DRM_COLOR_YCBCR_BT709] = {
+                       0x7EA8, 0x7950, 0x0,
+                       0x8888, 0x7918, 0xADA8,
+                       0x0, 0x7918,  0x6870,
+               },
+       };
+       const u16 *csc;
+
+       if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
+               csc = input_csc_matrix[plane_state->base.color_encoding];
+       else
+               csc = input_csc_matrix_lr[plane_state->base.color_encoding];
+
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), ROFF(csc[0]) |
+                     GOFF(csc[1]));
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1), BOFF(csc[2]));
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2), ROFF(csc[3]) |
+                     GOFF(csc[4]));
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3), BOFF(csc[5]));
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4), ROFF(csc[6]) |
+                     GOFF(csc[7]));
+       I915_WRITE_FW(PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5), BOFF(csc[8]));
+
+       I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
+                     PREOFF_YUV_TO_RGB_HI);
+       I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
+                     PREOFF_YUV_TO_RGB_ME);
+       I915_WRITE_FW(PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
+                     PREOFF_YUV_TO_RGB_LO);
+       I915_WRITE_FW(PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0);
+       I915_WRITE_FW(PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0);
+       I915_WRITE_FW(PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0);
+}
+
+static void
+skl_program_plane(struct intel_plane *plane,
+                 const struct intel_crtc_state *crtc_state,
+                 const struct intel_plane_state *plane_state,
+                 int color_plane, bool slave, u32 plane_ctl)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum plane_id plane_id = plane->id;
        enum pipe pipe = plane->pipe;
-       u32 plane_ctl = plane_state->ctl;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
-       u32 surf_addr = plane_state->color_plane[0].offset;
-       u32 stride = skl_plane_stride(plane_state, 0);
+       u32 surf_addr = plane_state->color_plane[color_plane].offset;
+       u32 stride = skl_plane_stride(plane_state, color_plane);
        u32 aux_stride = skl_plane_stride(plane_state, 1);
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
-       uint32_t x = plane_state->color_plane[0].x;
-       uint32_t y = plane_state->color_plane[0].y;
+       uint32_t x = plane_state->color_plane[color_plane].x;
+       uint32_t y = plane_state->color_plane[color_plane].y;
        uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
        uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
+       struct intel_plane *linked = plane_state->linked_plane;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       u8 alpha = plane_state->base.alpha >> 8;
        unsigned long irqflags;
+       u32 keymsk, keymax;
 
        /* Sizes are 0 based */
        src_w--;
        src_h--;
 
-       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
 
-       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
-               I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
-                             plane_state->color_ctl);
+       keymsk = key->channel_mask & 0x3ffffff;
+       if (alpha < 0xff)
+               keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
 
-       if (key->flags) {
-               I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
-               I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value);
-               I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask);
+       /* The scaler will handle the output position */
+       if (plane_state->scaler_id >= 0) {
+               crtc_x = 0;
+               crtc_y = 0;
        }
 
-       I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
        I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride);
+       I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x);
        I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
        I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id),
                      (plane_state->color_plane[1].offset - surf_addr) | aux_stride);
-       I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
-                     (plane_state->color_plane[1].y << 16) |
-                     plane_state->color_plane[1].x);
 
-       if (plane_state->scaler_id >= 0) {
-               skl_program_scaler(plane, crtc_state, plane_state);
+       if (icl_is_hdr_plane(plane)) {
+               u32 cus_ctl = 0;
+
+               if (linked) {
+                       /* Enable and use MPEG-2 chroma siting */
+                       cus_ctl = PLANE_CUS_ENABLE |
+                               PLANE_CUS_HPHASE_0 |
+                               PLANE_CUS_VPHASE_SIGN_NEGATIVE |
+                               PLANE_CUS_VPHASE_0_25;
+
+                       if (linked->id == PLANE_SPRITE5)
+                               cus_ctl |= PLANE_CUS_PLANE_7;
+                       else if (linked->id == PLANE_SPRITE4)
+                               cus_ctl |= PLANE_CUS_PLANE_6;
+                       else
+                               MISSING_CASE(linked->id);
+               }
 
-               I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0);
-       } else {
-               I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x);
+               I915_WRITE_FW(PLANE_CUS_CTL(pipe, plane_id), cus_ctl);
        }
 
+       if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+               I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
+                             plane_state->color_ctl);
+
+       if (fb->format->is_yuv && icl_is_hdr_plane(plane))
+               icl_program_input_csc(plane, crtc_state, plane_state);
+
+       skl_write_plane_wm(plane, crtc_state);
+
+       I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
+       I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), keymsk);
+       I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), keymax);
+
+       I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
+
+       if (INTEL_GEN(dev_priv) < 11)
+               I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id),
+                             (plane_state->color_plane[1].y << 16) |
+                             plane_state->color_plane[1].x);
+
+       /*
+        * The control register self-arms if the plane was previously
+        * disabled. Try to make the plane enable atomic by writing
+        * the control register just before the surface register.
+        */
        I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl);
        I915_WRITE_FW(PLANE_SURF(pipe, plane_id),
                      intel_plane_ggtt_offset(plane_state) + surf_addr);
-       POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
+
+       if (!slave && plane_state->scaler_id >= 0)
+               skl_program_scaler(plane, crtc_state, plane_state);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-void
-skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+static void
+skl_update_plane(struct intel_plane *plane,
+                const struct intel_crtc_state *crtc_state,
+                const struct intel_plane_state *plane_state)
+{
+       int color_plane = 0;
+
+       if (plane_state->linked_plane) {
+               /* Program the UV plane */
+               color_plane = 1;
+       }
+
+       skl_program_plane(plane, crtc_state, plane_state,
+                         color_plane, false, plane_state->ctl);
+}
+
+static void
+icl_update_slave(struct intel_plane *plane,
+                const struct intel_crtc_state *crtc_state,
+                const struct intel_plane_state *plane_state)
+{
+       skl_program_plane(plane, crtc_state, plane_state, 0, true,
+                         plane_state->ctl | PLANE_CTL_YUV420_Y_PLANE);
+}
+
+static void
+skl_disable_plane(struct intel_plane *plane,
+                 const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum plane_id plane_id = plane->id;
@@ -427,15 +604,15 @@ skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
-       I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
+       skl_write_plane_wm(plane, crtc_state);
 
+       I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
        I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);
-       POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-bool
+static bool
 skl_plane_get_hw_state(struct intel_plane *plane,
                       enum pipe *pipe)
 {
@@ -628,7 +805,6 @@ vlv_update_plane(struct intel_plane *plane,
                 const struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
        enum plane_id plane_id = plane->id;
        u32 sprctl = plane_state->ctl;
@@ -651,38 +827,41 @@ vlv_update_plane(struct intel_plane *plane,
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
-       vlv_update_clrc(plane_state);
+       I915_WRITE_FW(SPSTRIDE(pipe, plane_id),
+                     plane_state->color_plane[0].stride);
+       I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x);
+       I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
+       I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0);
 
        if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
                chv_update_csc(plane_state);
 
        if (key->flags) {
                I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);
-               I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
                I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask);
+               I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
        }
-       I915_WRITE_FW(SPSTRIDE(pipe, plane_id),
-                     plane_state->color_plane[0].stride);
-       I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x);
 
-       if (fb->modifier == I915_FORMAT_MOD_X_TILED)
-               I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x);
-       else
-               I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset);
+       I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset);
+       I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x);
 
-       I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0);
-
-       I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
+       /*
+        * The control register self-arms if the plane was previously
+        * disabled. Try to make the plane enable atomic by writing
+        * the control register just before the surface register.
+        */
        I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl);
        I915_WRITE_FW(SPSURF(pipe, plane_id),
                      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
-       POSTING_READ_FW(SPSURF(pipe, plane_id));
+
+       vlv_update_clrc(plane_state);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void
-vlv_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+vlv_disable_plane(struct intel_plane *plane,
+                 const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum pipe pipe = plane->pipe;
@@ -692,9 +871,7 @@ vlv_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
        I915_WRITE_FW(SPCNTR(pipe, plane_id), 0);
-
        I915_WRITE_FW(SPSURF(pipe, plane_id), 0);
-       POSTING_READ_FW(SPSURF(pipe, plane_id));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -789,7 +966,6 @@ ivb_update_plane(struct intel_plane *plane,
                 const struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
        u32 sprctl = plane_state->ctl, sprscale = 0;
        u32 sprsurf_offset = plane_state->color_plane[0].offset;
@@ -818,37 +994,42 @@ ivb_update_plane(struct intel_plane *plane,
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
+       I915_WRITE_FW(SPRSTRIDE(pipe), plane_state->color_plane[0].stride);
+       I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
+       I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
+       if (IS_IVYBRIDGE(dev_priv))
+               I915_WRITE_FW(SPRSCALE(pipe), sprscale);
+
        if (key->flags) {
                I915_WRITE_FW(SPRKEYVAL(pipe), key->min_value);
-               I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value);
                I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask);
+               I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value);
        }
 
-       I915_WRITE_FW(SPRSTRIDE(pipe), plane_state->color_plane[0].stride);
-       I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
-
        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
         * register */
-       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                I915_WRITE_FW(SPROFFSET(pipe), (y << 16) | x);
-       else if (fb->modifier == I915_FORMAT_MOD_X_TILED)
-               I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x);
-       else
+       } else {
                I915_WRITE_FW(SPRLINOFF(pipe), linear_offset);
+               I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x);
+       }
 
-       I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
-       if (IS_IVYBRIDGE(dev_priv))
-               I915_WRITE_FW(SPRSCALE(pipe), sprscale);
+       /*
+        * The control register self-arms if the plane was previously
+        * disabled. Try to make the plane enable atomic by writing
+        * the control register just before the surface register.
+        */
        I915_WRITE_FW(SPRCTL(pipe), sprctl);
        I915_WRITE_FW(SPRSURF(pipe),
                      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
-       POSTING_READ_FW(SPRSURF(pipe));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void
-ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+ivb_disable_plane(struct intel_plane *plane,
+                 const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum pipe pipe = plane->pipe;
@@ -857,12 +1038,10 @@ ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
        I915_WRITE_FW(SPRCTL(pipe), 0);
-       /* Can't leave the scaler enabled... */
+       /* Disable the scaler */
        if (IS_IVYBRIDGE(dev_priv))
                I915_WRITE_FW(SPRSCALE(pipe), 0);
-
        I915_WRITE_FW(SPRSURF(pipe), 0);
-       POSTING_READ_FW(SPRSURF(pipe));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -961,7 +1140,6 @@ g4x_update_plane(struct intel_plane *plane,
                 const struct intel_plane_state *plane_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct drm_framebuffer *fb = plane_state->base.fb;
        enum pipe pipe = plane->pipe;
        u32 dvscntr = plane_state->ctl, dvsscale = 0;
        u32 dvssurf_offset = plane_state->color_plane[0].offset;
@@ -990,32 +1168,35 @@ g4x_update_plane(struct intel_plane *plane,
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
+       I915_WRITE_FW(DVSSTRIDE(pipe), plane_state->color_plane[0].stride);
+       I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
+       I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
+       I915_WRITE_FW(DVSSCALE(pipe), dvsscale);
+
        if (key->flags) {
                I915_WRITE_FW(DVSKEYVAL(pipe), key->min_value);
-               I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value);
                I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask);
+               I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value);
        }
 
-       I915_WRITE_FW(DVSSTRIDE(pipe), plane_state->color_plane[0].stride);
-       I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
-
-       if (fb->modifier == I915_FORMAT_MOD_X_TILED)
-               I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x);
-       else
-               I915_WRITE_FW(DVSLINOFF(pipe), linear_offset);
+       I915_WRITE_FW(DVSLINOFF(pipe), linear_offset);
+       I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x);
 
-       I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
-       I915_WRITE_FW(DVSSCALE(pipe), dvsscale);
+       /*
+        * The control register self-arms if the plane was previously
+        * disabled. Try to make the plane enable atomic by writing
+        * the control register just before the surface register.
+        */
        I915_WRITE_FW(DVSCNTR(pipe), dvscntr);
        I915_WRITE_FW(DVSSURF(pipe),
                      intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
-       POSTING_READ_FW(DVSSURF(pipe));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void
-g4x_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+g4x_disable_plane(struct intel_plane *plane,
+                 const struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        enum pipe pipe = plane->pipe;
@@ -1026,9 +1207,7 @@ g4x_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
        I915_WRITE_FW(DVSCNTR(pipe), 0);
        /* Disable the scaler */
        I915_WRITE_FW(DVSSCALE(pipe), 0);
-
        I915_WRITE_FW(DVSSURF(pipe), 0);
-       POSTING_READ_FW(DVSSURF(pipe));
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -1054,6 +1233,19 @@ g4x_plane_get_hw_state(struct intel_plane *plane,
        return ret;
 }
 
+static bool intel_fb_scalable(const struct drm_framebuffer *fb)
+{
+       if (!fb)
+               return false;
+
+       switch (fb->format->format) {
+       case DRM_FORMAT_C8:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static int
 g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
                         struct intel_plane_state *plane_state)
@@ -1121,18 +1313,18 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state,
 {
        struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       int max_scale, min_scale;
+       int min_scale = DRM_PLANE_HELPER_NO_SCALING;
+       int max_scale = DRM_PLANE_HELPER_NO_SCALING;
        int ret;
 
-       if (INTEL_GEN(dev_priv) < 7) {
-               min_scale = 1;
-               max_scale = 16 << 16;
-       } else if (IS_IVYBRIDGE(dev_priv)) {
-               min_scale = 1;
-               max_scale = 2 << 16;
-       } else {
-               min_scale = DRM_PLANE_HELPER_NO_SCALING;
-               max_scale = DRM_PLANE_HELPER_NO_SCALING;
+       if (intel_fb_scalable(plane_state->base.fb)) {
+               if (INTEL_GEN(dev_priv) < 7) {
+                       min_scale = 1;
+                       max_scale = 16 << 16;
+               } else if (IS_IVYBRIDGE(dev_priv)) {
+                       min_scale = 1;
+                       max_scale = 2 << 16;
+               }
        }
 
        ret = drm_atomic_helper_check_plane_state(&plane_state->base,
@@ -1219,6 +1411,8 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state,
 static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
                              const struct intel_plane_state *plane_state)
 {
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
        const struct drm_framebuffer *fb = plane_state->base.fb;
        unsigned int rotation = plane_state->base.rotation;
        struct drm_format_name_buf format_name;
@@ -1247,13 +1441,17 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
                }
 
                /*
-                * 90/270 is not allowed with RGB64 16:16:16:16,
-                * RGB 16-bit 5:6:5, and Indexed 8-bit.
-                * TBD: Add RGB64 case once its added in supported format list.
+                * 90/270 is not allowed with RGB64 16:16:16:16 and
+                * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards.
+                * TBD: Add RGB64 case once its added in supported format
+                * list.
                 */
                switch (fb->format->format) {
-               case DRM_FORMAT_C8:
                case DRM_FORMAT_RGB565:
+                       if (INTEL_GEN(dev_priv) >= 11)
+                               break;
+                       /* fall through */
+               case DRM_FORMAT_C8:
                        DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n",
                                      drm_get_format_name(fb->format->format,
                                                          &format_name));
@@ -1307,12 +1505,31 @@ static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_s
        return 0;
 }
 
-int skl_plane_check(struct intel_crtc_state *crtc_state,
-                   struct intel_plane_state *plane_state)
+static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state)
+{
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       unsigned int rotation = plane_state->base.rotation;
+       int src_w = drm_rect_width(&plane_state->base.src) >> 16;
+
+       /* Display WA #1106 */
+       if (fb->format->format == DRM_FORMAT_NV12 && src_w & 3 &&
+           (rotation == DRM_MODE_ROTATE_270 ||
+            rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) {
+               DRM_DEBUG_KMS("src width must be multiple of 4 for rotated NV12\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int skl_plane_check(struct intel_crtc_state *crtc_state,
+                          struct intel_plane_state *plane_state)
 {
        struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       int max_scale, min_scale;
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       int min_scale = DRM_PLANE_HELPER_NO_SCALING;
+       int max_scale = DRM_PLANE_HELPER_NO_SCALING;
        int ret;
 
        ret = skl_plane_check_fb(crtc_state, plane_state);
@@ -1320,15 +1537,9 @@ int skl_plane_check(struct intel_crtc_state *crtc_state,
                return ret;
 
        /* use scaler when colorkey is not required */
-       if (!plane_state->ckey.flags) {
-               const struct drm_framebuffer *fb = plane_state->base.fb;
-
+       if (!plane_state->ckey.flags && intel_fb_scalable(fb)) {
                min_scale = 1;
-               max_scale = skl_max_scale(crtc_state,
-                                         fb ? fb->format->format : 0);
-       } else {
-               min_scale = DRM_PLANE_HELPER_NO_SCALING;
-               max_scale = DRM_PLANE_HELPER_NO_SCALING;
+               max_scale = skl_max_scale(crtc_state, fb->format->format);
        }
 
        ret = drm_atomic_helper_check_plane_state(&plane_state->base,
@@ -1349,10 +1560,18 @@ int skl_plane_check(struct intel_crtc_state *crtc_state,
        if (ret)
                return ret;
 
+       ret = skl_plane_check_nv12_rotation(plane_state);
+       if (ret)
+               return ret;
+
        ret = skl_check_plane_surface(plane_state);
        if (ret)
                return ret;
 
+       /* HW only has 8 bits pixel precision, disable plane if invisible */
+       if (!(plane_state->base.alpha >> 8))
+               plane_state->base.visible = false;
+
        plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);
 
        if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
@@ -1517,24 +1736,30 @@ static const uint32_t vlv_plane_formats[] = {
        DRM_FORMAT_VYUY,
 };
 
-static uint32_t skl_plane_formats[] = {
+static const uint32_t skl_plane_formats[] = {
+       DRM_FORMAT_C8,
        DRM_FORMAT_RGB565,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_ABGR8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
        DRM_FORMAT_YUYV,
        DRM_FORMAT_YVYU,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_VYUY,
 };
 
-static uint32_t skl_planar_formats[] = {
+static const uint32_t skl_planar_formats[] = {
+       DRM_FORMAT_C8,
        DRM_FORMAT_RGB565,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_ABGR8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
        DRM_FORMAT_YUYV,
        DRM_FORMAT_YVYU,
        DRM_FORMAT_UYVY,
@@ -1739,8 +1964,36 @@ static const struct drm_plane_funcs skl_plane_funcs = {
        .format_mod_supported = skl_plane_format_mod_supported,
 };
 
-bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
-                      enum pipe pipe, enum plane_id plane_id)
+static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, enum plane_id plane_id)
+{
+       if (!HAS_FBC(dev_priv))
+               return false;
+
+       return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
+}
+
+static bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
+                                enum pipe pipe, enum plane_id plane_id)
+{
+       if (INTEL_GEN(dev_priv) >= 11)
+               return plane_id <= PLANE_SPRITE3;
+
+       /* Display WA #0870: skl, bxt */
+       if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv))
+               return false;
+
+       if (IS_GEN9(dev_priv) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C)
+               return false;
+
+       if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0)
+               return false;
+
+       return true;
+}
+
+static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, enum plane_id plane_id)
 {
        if (plane_id == PLANE_CURSOR)
                return false;
@@ -1757,109 +2010,173 @@ bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
 }
 
 struct intel_plane *
-intel_sprite_plane_create(struct drm_i915_private *dev_priv,
-                         enum pipe pipe, int plane)
+skl_universal_plane_create(struct drm_i915_private *dev_priv,
+                          enum pipe pipe, enum plane_id plane_id)
 {
-       struct intel_plane *intel_plane = NULL;
-       struct intel_plane_state *state = NULL;
-       const struct drm_plane_funcs *plane_funcs;
-       unsigned long possible_crtcs;
-       const uint32_t *plane_formats;
-       const uint64_t *modifiers;
+       struct intel_plane *plane;
+       enum drm_plane_type plane_type;
        unsigned int supported_rotations;
-       int num_plane_formats;
+       unsigned int possible_crtcs;
+       const u64 *modifiers;
+       const u32 *formats;
+       int num_formats;
        int ret;
 
-       intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);
-       if (!intel_plane) {
-               ret = -ENOMEM;
-               goto fail;
+       plane = intel_plane_alloc();
+       if (IS_ERR(plane))
+               return plane;
+
+       plane->pipe = pipe;
+       plane->id = plane_id;
+       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id);
+
+       plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id);
+       if (plane->has_fbc) {
+               struct intel_fbc *fbc = &dev_priv->fbc;
+
+               fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
        }
 
-       state = intel_create_plane_state(&intel_plane->base);
-       if (!state) {
-               ret = -ENOMEM;
-               goto fail;
+       plane->max_stride = skl_plane_max_stride;
+       plane->update_plane = skl_update_plane;
+       plane->disable_plane = skl_disable_plane;
+       plane->get_hw_state = skl_plane_get_hw_state;
+       plane->check_plane = skl_plane_check;
+       if (icl_is_nv12_y_plane(plane_id))
+               plane->update_slave = icl_update_slave;
+
+       if (skl_plane_has_planar(dev_priv, pipe, plane_id)) {
+               formats = skl_planar_formats;
+               num_formats = ARRAY_SIZE(skl_planar_formats);
+       } else {
+               formats = skl_plane_formats;
+               num_formats = ARRAY_SIZE(skl_plane_formats);
        }
-       intel_plane->base.state = &state->base;
 
-       if (INTEL_GEN(dev_priv) >= 9) {
-               state->scaler_id = -1;
+       plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id);
+       if (plane->has_ccs)
+               modifiers = skl_plane_format_modifiers_ccs;
+       else
+               modifiers = skl_plane_format_modifiers_noccs;
 
-               intel_plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
-                                                        PLANE_SPRITE0 + plane);
+       if (plane_id == PLANE_PRIMARY)
+               plane_type = DRM_PLANE_TYPE_PRIMARY;
+       else
+               plane_type = DRM_PLANE_TYPE_OVERLAY;
 
-               intel_plane->max_stride = skl_plane_max_stride;
-               intel_plane->update_plane = skl_update_plane;
-               intel_plane->disable_plane = skl_disable_plane;
-               intel_plane->get_hw_state = skl_plane_get_hw_state;
-               intel_plane->check_plane = skl_plane_check;
+       possible_crtcs = BIT(pipe);
 
-               if (skl_plane_has_planar(dev_priv, pipe,
-                                        PLANE_SPRITE0 + plane)) {
-                       plane_formats = skl_planar_formats;
-                       num_plane_formats = ARRAY_SIZE(skl_planar_formats);
-               } else {
-                       plane_formats = skl_plane_formats;
-                       num_plane_formats = ARRAY_SIZE(skl_plane_formats);
-               }
+       ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                      possible_crtcs, &skl_plane_funcs,
+                                      formats, num_formats, modifiers,
+                                      plane_type,
+                                      "plane %d%c", plane_id + 1,
+                                      pipe_name(pipe));
+       if (ret)
+               goto fail;
+
+       supported_rotations =
+               DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
+               DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
+
+       if (INTEL_GEN(dev_priv) >= 10)
+               supported_rotations |= DRM_MODE_REFLECT_X;
+
+       drm_plane_create_rotation_property(&plane->base,
+                                          DRM_MODE_ROTATE_0,
+                                          supported_rotations);
+
+       drm_plane_create_color_properties(&plane->base,
+                                         BIT(DRM_COLOR_YCBCR_BT601) |
+                                         BIT(DRM_COLOR_YCBCR_BT709),
+                                         BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+                                         BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+                                         DRM_COLOR_YCBCR_BT709,
+                                         DRM_COLOR_YCBCR_LIMITED_RANGE);
+
+       drm_plane_create_alpha_property(&plane->base);
+       drm_plane_create_blend_mode_property(&plane->base,
+                                            BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+                                            BIT(DRM_MODE_BLEND_PREMULTI) |
+                                            BIT(DRM_MODE_BLEND_COVERAGE));
+
+       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
+
+       return plane;
 
-               if (intel_plane->has_ccs)
-                       modifiers = skl_plane_format_modifiers_ccs;
-               else
-                       modifiers = skl_plane_format_modifiers_noccs;
-
-               plane_funcs = &skl_plane_funcs;
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               intel_plane->max_stride = i9xx_plane_max_stride;
-               intel_plane->update_plane = vlv_update_plane;
-               intel_plane->disable_plane = vlv_disable_plane;
-               intel_plane->get_hw_state = vlv_plane_get_hw_state;
-               intel_plane->check_plane = vlv_sprite_check;
-
-               plane_formats = vlv_plane_formats;
-               num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
+fail:
+       intel_plane_free(plane);
+
+       return ERR_PTR(ret);
+}
+
+struct intel_plane *
+intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+                         enum pipe pipe, int sprite)
+{
+       struct intel_plane *plane;
+       const struct drm_plane_funcs *plane_funcs;
+       unsigned long possible_crtcs;
+       unsigned int supported_rotations;
+       const u64 *modifiers;
+       const u32 *formats;
+       int num_formats;
+       int ret;
+
+       if (INTEL_GEN(dev_priv) >= 9)
+               return skl_universal_plane_create(dev_priv, pipe,
+                                                 PLANE_SPRITE0 + sprite);
+
+       plane = intel_plane_alloc();
+       if (IS_ERR(plane))
+               return plane;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               plane->max_stride = i9xx_plane_max_stride;
+               plane->update_plane = vlv_update_plane;
+               plane->disable_plane = vlv_disable_plane;
+               plane->get_hw_state = vlv_plane_get_hw_state;
+               plane->check_plane = vlv_sprite_check;
+
+               formats = vlv_plane_formats;
+               num_formats = ARRAY_SIZE(vlv_plane_formats);
                modifiers = i9xx_plane_format_modifiers;
 
                plane_funcs = &vlv_sprite_funcs;
        } else if (INTEL_GEN(dev_priv) >= 7) {
-               intel_plane->max_stride = g4x_sprite_max_stride;
-               intel_plane->update_plane = ivb_update_plane;
-               intel_plane->disable_plane = ivb_disable_plane;
-               intel_plane->get_hw_state = ivb_plane_get_hw_state;
-               intel_plane->check_plane = g4x_sprite_check;
-
-               plane_formats = snb_plane_formats;
-               num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+               plane->max_stride = g4x_sprite_max_stride;
+               plane->update_plane = ivb_update_plane;
+               plane->disable_plane = ivb_disable_plane;
+               plane->get_hw_state = ivb_plane_get_hw_state;
+               plane->check_plane = g4x_sprite_check;
+
+               formats = snb_plane_formats;
+               num_formats = ARRAY_SIZE(snb_plane_formats);
                modifiers = i9xx_plane_format_modifiers;
 
                plane_funcs = &snb_sprite_funcs;
        } else {
-               intel_plane->max_stride = g4x_sprite_max_stride;
-               intel_plane->update_plane = g4x_update_plane;
-               intel_plane->disable_plane = g4x_disable_plane;
-               intel_plane->get_hw_state = g4x_plane_get_hw_state;
-               intel_plane->check_plane = g4x_sprite_check;
+               plane->max_stride = g4x_sprite_max_stride;
+               plane->update_plane = g4x_update_plane;
+               plane->disable_plane = g4x_disable_plane;
+               plane->get_hw_state = g4x_plane_get_hw_state;
+               plane->check_plane = g4x_sprite_check;
 
                modifiers = i9xx_plane_format_modifiers;
                if (IS_GEN6(dev_priv)) {
-                       plane_formats = snb_plane_formats;
-                       num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+                       formats = snb_plane_formats;
+                       num_formats = ARRAY_SIZE(snb_plane_formats);
 
                        plane_funcs = &snb_sprite_funcs;
                } else {
-                       plane_formats = g4x_plane_formats;
-                       num_plane_formats = ARRAY_SIZE(g4x_plane_formats);
+                       formats = g4x_plane_formats;
+                       num_formats = ARRAY_SIZE(g4x_plane_formats);
 
                        plane_funcs = &g4x_sprite_funcs;
                }
        }
 
-       if (INTEL_GEN(dev_priv) >= 9) {
-               supported_rotations =
-                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-                       DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
-       } else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
+       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
                supported_rotations =
                        DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
                        DRM_MODE_REFLECT_X;
@@ -1868,35 +2185,25 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
                        DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
        }
 
-       intel_plane->pipe = pipe;
-       intel_plane->i9xx_plane = plane;
-       intel_plane->id = PLANE_SPRITE0 + plane;
-       intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id);
+       plane->pipe = pipe;
+       plane->id = PLANE_SPRITE0 + sprite;
+       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
 
-       possible_crtcs = (1 << pipe);
+       possible_crtcs = BIT(pipe);
 
-       if (INTEL_GEN(dev_priv) >= 9)
-               ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
-                                              possible_crtcs, plane_funcs,
-                                              plane_formats, num_plane_formats,
-                                              modifiers,
-                                              DRM_PLANE_TYPE_OVERLAY,
-                                              "plane %d%c", plane + 2, pipe_name(pipe));
-       else
-               ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
-                                              possible_crtcs, plane_funcs,
-                                              plane_formats, num_plane_formats,
-                                              modifiers,
-                                              DRM_PLANE_TYPE_OVERLAY,
-                                              "sprite %c", sprite_name(pipe, plane));
+       ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+                                      possible_crtcs, plane_funcs,
+                                      formats, num_formats, modifiers,
+                                      DRM_PLANE_TYPE_OVERLAY,
+                                      "sprite %c", sprite_name(pipe, sprite));
        if (ret)
                goto fail;
 
-       drm_plane_create_rotation_property(&intel_plane->base,
+       drm_plane_create_rotation_property(&plane->base,
                                           DRM_MODE_ROTATE_0,
                                           supported_rotations);
 
-       drm_plane_create_color_properties(&intel_plane->base,
+       drm_plane_create_color_properties(&plane->base,
                                          BIT(DRM_COLOR_YCBCR_BT601) |
                                          BIT(DRM_COLOR_YCBCR_BT709),
                                          BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
@@ -1904,13 +2211,12 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
                                          DRM_COLOR_YCBCR_BT709,
                                          DRM_COLOR_YCBCR_LIMITED_RANGE);
 
-       drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
+       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
 
-       return intel_plane;
+       return plane;
 
 fail:
-       kfree(state);
-       kfree(intel_plane);
+       intel_plane_free(plane);
 
        return ERR_PTR(ret);
 }
index b5b04cb892e945b747f20702b5740b4af572644f..860f306a23bafbda312d63bafb2039ce67b91069 100644 (file)
@@ -885,6 +885,7 @@ intel_tv_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return false;
 
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        adjusted_mode->crtc_clock = tv_mode->clock;
        DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
        pipe_config->pipe_bpp = 8*3;
@@ -1377,17 +1378,10 @@ intel_tv_get_modes(struct drm_connector *connector)
        return count;
 }
 
-static void
-intel_tv_destroy(struct drm_connector *connector)
-{
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_tv_destroy,
+       .destroy = intel_connector_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
index b1b3e81b6e241568e4d54986062fb8a2ea7a5b7d..b34c318b238dad37a027aad52b5a920e2c73f3dc 100644 (file)
@@ -376,7 +376,7 @@ int intel_uc_init_hw(struct drm_i915_private *i915)
 
                intel_guc_init_params(guc);
                ret = intel_guc_fw_upload(guc);
-               if (ret == 0 || ret != -EAGAIN)
+               if (ret == 0 || ret != -ETIMEDOUT)
                        break;
 
                DRM_DEBUG_DRIVER("GuC fw load failed: %d; will reset and "
index 87910aa8326760eb21172b685cd24ac6308032c4..0e3bd580e267ffe569c9897cacaf1ce807cb501e 100644 (file)
@@ -115,9 +115,14 @@ static inline bool intel_uc_fw_is_selected(struct intel_uc_fw *uc_fw)
        return uc_fw->path != NULL;
 }
 
+static inline bool intel_uc_fw_is_loaded(struct intel_uc_fw *uc_fw)
+{
+       return uc_fw->load_status == INTEL_UC_FIRMWARE_SUCCESS;
+}
+
 static inline void intel_uc_fw_sanitize(struct intel_uc_fw *uc_fw)
 {
-       if (uc_fw->load_status == INTEL_UC_FIRMWARE_SUCCESS)
+       if (intel_uc_fw_is_loaded(uc_fw))
                uc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
 }
 
index 3ad302c66254bb0b74703fa44df4e305a5013a33..9289515108c3182a6b0aa363639a631eed97e7a0 100644 (file)
@@ -1437,7 +1437,7 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv)
                                       FORCEWAKE_MEDIA_VEBOX_GEN11(i),
                                       FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
                }
-       } else if (IS_GEN9(dev_priv) || IS_GEN10(dev_priv)) {
+       } else if (IS_GEN10(dev_priv) || IS_GEN9(dev_priv)) {
                dev_priv->uncore.funcs.force_wake_get =
                        fw_domains_get_with_fallback;
                dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
index bba98cf83cbd9d1c0348e42acb5f8fba98a106dc..bf3662ad5fed1ebcb3a49a870ccdd2de4de3fbeb 100644 (file)
@@ -326,6 +326,13 @@ enum vbt_gmbus_ddi {
        ICL_DDC_BUS_PORT_4,
 };
 
+#define DP_AUX_A 0x40
+#define DP_AUX_B 0x10
+#define DP_AUX_C 0x20
+#define DP_AUX_D 0x30
+#define DP_AUX_E 0x50
+#define DP_AUX_F 0x60
+
 #define VBT_DP_MAX_LINK_RATE_HBR3      0
 #define VBT_DP_MAX_LINK_RATE_HBR2      1
 #define VBT_DP_MAX_LINK_RATE_HBR       2
diff --git a/drivers/gpu/drm/i915/intel_vdsc.c b/drivers/gpu/drm/i915/intel_vdsc.c
new file mode 100644 (file)
index 0000000..c56ba0e
--- /dev/null
@@ -0,0 +1,1088 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Author: Gaurav K Singh <gaurav.k.singh@intel.com>
+ *         Manasi Navare <manasi.d.navare@intel.com>
+ */
+
+#include <drm/drmP.h>
+#include <drm/i915_drm.h>
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+enum ROW_INDEX_BPP {
+       ROW_INDEX_6BPP = 0,
+       ROW_INDEX_8BPP,
+       ROW_INDEX_10BPP,
+       ROW_INDEX_12BPP,
+       ROW_INDEX_15BPP,
+       MAX_ROW_INDEX
+};
+
+enum COLUMN_INDEX_BPC {
+       COLUMN_INDEX_8BPC = 0,
+       COLUMN_INDEX_10BPC,
+       COLUMN_INDEX_12BPC,
+       COLUMN_INDEX_14BPC,
+       COLUMN_INDEX_16BPC,
+       MAX_COLUMN_INDEX
+};
+
+#define DSC_SUPPORTED_VERSION_MIN              1
+
+/* From DSC_v1.11 spec, rc_parameter_Set syntax element typically constant */
+static u16 rc_buf_thresh[] = {
+       896, 1792, 2688, 3584, 4480, 5376, 6272, 6720, 7168, 7616,
+       7744, 7872, 8000, 8064
+};
+
+struct rc_parameters {
+       u16 initial_xmit_delay;
+       u8 first_line_bpg_offset;
+       u16 initial_offset;
+       u8 flatness_min_qp;
+       u8 flatness_max_qp;
+       u8 rc_quant_incr_limit0;
+       u8 rc_quant_incr_limit1;
+       struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES];
+};
+
+/*
+ * Selected Rate Control Related Parameter Recommended Values
+ * from DSC_v1.11 spec & C Model release: DSC_model_20161212
+ */
+static struct rc_parameters rc_params[][MAX_COLUMN_INDEX] = {
+{
+       /* 6BPP/8BPC */
+       { 768, 15, 6144, 3, 13, 11, 11, {
+               { 0, 4, 0 }, { 1, 6, -2 }, { 3, 8, -2 }, { 4, 8, -4 },
+               { 5, 9, -6 }, { 5, 9, -6 }, { 6, 9, -6 }, { 6, 10, -8 },
+               { 7, 11, -8 }, { 8, 12, -10 }, { 9, 12, -10 }, { 10, 12, -12 },
+               { 10, 12, -12 }, { 11, 12, -12 }, { 13, 14, -12 }
+               }
+       },
+       /* 6BPP/10BPC */
+       { 768, 15, 6144, 7, 17, 15, 15, {
+               { 0, 8, 0 }, { 3, 10, -2 }, { 7, 12, -2 }, { 8, 12, -4 },
+               { 9, 13, -6 }, { 9, 13, -6 }, { 10, 13, -6 }, { 10, 14, -8 },
+               { 11, 15, -8 }, { 12, 16, -10 }, { 13, 16, -10 },
+               { 14, 16, -12 }, { 14, 16, -12 }, { 15, 16, -12 },
+               { 17, 18, -12 }
+               }
+       },
+       /* 6BPP/12BPC */
+       { 768, 15, 6144, 11, 21, 19, 19, {
+               { 0, 12, 0 }, { 5, 14, -2 }, { 11, 16, -2 }, { 12, 16, -4 },
+               { 13, 17, -6 }, { 13, 17, -6 }, { 14, 17, -6 }, { 14, 18, -8 },
+               { 15, 19, -8 }, { 16, 20, -10 }, { 17, 20, -10 },
+               { 18, 20, -12 }, { 18, 20, -12 }, { 19, 20, -12 },
+               { 21, 22, -12 }
+               }
+       },
+       /* 6BPP/14BPC */
+       { 768, 15, 6144, 15, 25, 23, 27, {
+               { 0, 16, 0 }, { 7, 18, -2 }, { 15, 20, -2 }, { 16, 20, -4 },
+               { 17, 21, -6 }, { 17, 21, -6 }, { 18, 21, -6 }, { 18, 22, -8 },
+               { 19, 23, -8 }, { 20, 24, -10 }, { 21, 24, -10 },
+               { 22, 24, -12 }, { 22, 24, -12 }, { 23, 24, -12 },
+               { 25, 26, -12 }
+               }
+       },
+       /* 6BPP/16BPC */
+       { 768, 15, 6144, 19, 29, 27, 27, {
+               { 0, 20, 0 }, { 9, 22, -2 }, { 19, 24, -2 }, { 20, 24, -4 },
+               { 21, 25, -6 }, { 21, 25, -6 }, { 22, 25, -6 }, { 22, 26, -8 },
+               { 23, 27, -8 }, { 24, 28, -10 }, { 25, 28, -10 },
+               { 26, 28, -12 }, { 26, 28, -12 }, { 27, 28, -12 },
+               { 29, 30, -12 }
+               }
+       },
+},
+{
+       /* 8BPP/8BPC */
+       { 512, 12, 6144, 3, 12, 11, 11, {
+               { 0, 4, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 }, { 5, 12, -12 },
+               { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+               }
+       },
+       /* 8BPP/10BPC */
+       { 512, 12, 6144, 7, 16, 15, 15, {
+               { 0, 4, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 5, 10, -2 },
+               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+               }
+       },
+       /* 8BPP/12BPC */
+       { 512, 12, 6144, 11, 20, 19, 19, {
+               { 0, 12, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 9, 14, -2 },
+               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+               { 21, 23, -12 }
+               }
+       },
+       /* 8BPP/14BPC */
+       { 512, 12, 6144, 15, 24, 23, 23, {
+               { 0, 12, 0 }, { 5, 13, 0 }, { 11, 15, 0 }, { 12, 17, -2 },
+               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 21, -8 }, { 15, 22, -10 }, { 17, 22, -10 },
+               { 17, 23, -12 }, { 17, 23, -12 }, { 21, 24, -12 },
+               { 24, 25, -12 }
+               }
+       },
+       /* 8BPP/16BPC */
+       { 512, 12, 6144, 19, 28, 27, 27, {
+               { 0, 12, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 15, 20, -2 },
+               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 25, -8 }, { 19, 26, -10 }, { 21, 26, -10 },
+               { 21, 27, -12 }, { 21, 27, -12 }, { 25, 28, -12 },
+               { 28, 29, -12 }
+               }
+       },
+},
+{
+       /* 10BPP/8BPC */
+       { 410, 15, 5632, 3, 12, 11, 11, {
+               { 0, 3, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 2, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 9, -10 }, { 5, 10, -10 }, { 5, 10, -10 },
+               { 5, 11, -12 }, { 7, 11, -12 }, { 11, 12, -12 }
+               }
+       },
+       /* 10BPP/10BPC */
+       { 410, 15, 5632, 7, 16, 15, 15, {
+               { 0, 7, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 6, 10, -2 },
+               { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 13, -10 }, { 9, 14, -10 }, { 9, 14, -10 },
+               { 9, 15, -12 }, { 11, 15, -12 }, { 15, 16, -12 }
+               }
+       },
+       /* 10BPP/12BPC */
+       { 410, 15, 5632, 11, 20, 19, 19, {
+               { 0, 11, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 10, 14, -2 },
+               { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 17, -10 }, { 13, 18, -10 },
+               { 13, 18, -10 }, { 13, 19, -12 }, { 15, 19, -12 },
+               { 19, 20, -12 }
+               }
+       },
+       /* 10BPP/14BPC */
+       { 410, 15, 5632, 15, 24, 23, 23, {
+               { 0, 11, 2 }, { 5, 13, 0 }, { 11, 15, 0 }, { 13, 18, -2 },
+               { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 21, -8 }, { 15, 21, -10 }, { 17, 22, -10 },
+               { 17, 22, -10 }, { 17, 23, -12 }, { 19, 23, -12 },
+               { 23, 24, -12 }
+               }
+       },
+       /* 10BPP/16BPC */
+       { 410, 15, 5632, 19, 28, 27, 27, {
+               { 0, 11, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 16, 20, -2 },
+               { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 25, -8 }, { 19, 25, -10 }, { 21, 26, -10 },
+               { 21, 26, -10 }, { 21, 27, -12 }, { 23, 27, -12 },
+               { 27, 28, -12 }
+               }
+       },
+},
+{
+       /* 12BPP/8BPC */
+       { 341, 15, 2048, 3, 12, 11, 11, {
+               { 0, 2, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+               { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+               { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 },
+               { 5, 12, -12 }, { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+               }
+       },
+       /* 12BPP/10BPC */
+       { 341, 15, 2048, 7, 16, 15, 15, {
+               { 0, 2, 2 }, { 2, 5, 0 }, { 3, 7, 0 }, { 4, 8, -2 },
+               { 6, 9, -4 }, { 7, 10, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+               { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+               { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+               }
+       },
+       /* 12BPP/12BPC */
+       { 341, 15, 2048, 11, 20, 19, 19, {
+               { 0, 6, 2 }, { 4, 9, 0 }, { 7, 11, 0 }, { 8, 12, -2 },
+               { 10, 13, -4 }, { 11, 14, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+               { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+               { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+               { 21, 23, -12 }
+               }
+       },
+       /* 12BPP/14BPC */
+       { 341, 15, 2048, 15, 24, 23, 23, {
+               { 0, 6, 2 }, { 7, 10, 0 }, { 9, 13, 0 }, { 11, 16, -2 },
+               { 14, 17, -4 }, { 15, 18, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+               { 15, 20, -8 }, { 15, 21, -10 }, { 17, 21, -10 },
+               { 17, 21, -12 }, { 17, 21, -12 }, { 19, 22, -12 },
+               { 22, 23, -12 }
+               }
+       },
+       /* 12BPP/16BPC */
+       { 341, 15, 2048, 19, 28, 27, 27, {
+               { 0, 6, 2 }, { 6, 11, 0 }, { 11, 15, 0 }, { 14, 18, -2 },
+               { 18, 21, -4 }, { 19, 22, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+               { 19, 24, -8 }, { 19, 25, -10 }, { 21, 25, -10 },
+               { 21, 25, -12 }, { 21, 25, -12 }, { 23, 26, -12 },
+               { 26, 27, -12 }
+               }
+       },
+},
+{
+       /* 15BPP/8BPC */
+       { 273, 15, 2048, 3, 12, 11, 11, {
+               { 0, 0, 10 }, { 0, 1, 8 }, { 0, 1, 6 }, { 0, 2, 4 },
+               { 1, 2, 2 }, { 1, 3, 0 }, { 1, 3, -2 }, { 2, 4, -4 },
+               { 2, 5, -6 }, { 3, 5, -8 }, { 4, 6, -10 }, { 4, 7, -10 },
+               { 5, 7, -12 }, { 7, 8, -12 }, { 8, 9, -12 }
+               }
+       },
+       /* 15BPP/10BPC */
+       { 273, 15, 2048, 7, 16, 15, 15, {
+               { 0, 2, 10 }, { 2, 5, 8 }, { 3, 5, 6 }, { 4, 6, 4 },
+               { 5, 6, 2 }, { 5, 7, 0 }, { 5, 7, -2 }, { 6, 8, -4 },
+               { 6, 9, -6 }, { 7, 9, -8 }, { 8, 10, -10 }, { 8, 11, -10 },
+               { 9, 11, -12 }, { 11, 12, -12 }, { 12, 13, -12 }
+               }
+       },
+       /* 15BPP/12BPC */
+       { 273, 15, 2048, 11, 20, 19, 19, {
+               { 0, 4, 10 }, { 2, 7, 8 }, { 4, 9, 6 }, { 6, 11, 4 },
+               { 9, 11, 2 }, { 9, 11, 0 }, { 9, 12, -2 }, { 10, 12, -4 },
+               { 11, 13, -6 }, { 11, 13, -8 }, { 12, 14, -10 },
+               { 13, 15, -10 }, { 13, 15, -12 }, { 15, 16, -12 },
+               { 16, 17, -12 }
+               }
+       },
+       /* 15BPP/14BPC */
+       { 273, 15, 2048, 15, 24, 23, 23, {
+               { 0, 4, 10 }, { 3, 8, 8 }, { 6, 11, 6 }, { 9, 14, 4 },
+               { 13, 15, 2 }, { 13, 15, 0 }, { 13, 16, -2 }, { 14, 16, -4 },
+               { 15, 17, -6 }, { 15, 17, -8 }, { 16, 18, -10 },
+               { 17, 19, -10 }, { 17, 19, -12 }, { 19, 20, -12 },
+               { 20, 21, -12 }
+               }
+       },
+       /* 15BPP/16BPC */
+       { 273, 15, 2048, 19, 28, 27, 27, {
+               { 0, 4, 10 }, { 4, 9, 8 }, { 8, 13, 6 }, { 12, 17, 4 },
+               { 17, 19, 2 }, { 17, 20, 0 }, { 17, 20, -2 }, { 18, 20, -4 },
+               { 19, 21, -6 }, { 19, 21, -8 }, { 20, 22, -10 },
+               { 21, 23, -10 }, { 21, 23, -12 }, { 23, 24, -12 },
+               { 24, 25, -12 }
+               }
+       }
+}
+
+};
+
+static int get_row_index_for_rc_params(u16 compressed_bpp)
+{
+       switch (compressed_bpp) {
+       case 6:
+               return ROW_INDEX_6BPP;
+       case 8:
+               return ROW_INDEX_8BPP;
+       case 10:
+               return ROW_INDEX_10BPP;
+       case 12:
+               return ROW_INDEX_12BPP;
+       case 15:
+               return ROW_INDEX_15BPP;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int get_column_index_for_rc_params(u8 bits_per_component)
+{
+       switch (bits_per_component) {
+       case 8:
+               return COLUMN_INDEX_8BPC;
+       case 10:
+               return COLUMN_INDEX_10BPC;
+       case 12:
+               return COLUMN_INDEX_12BPC;
+       case 14:
+               return COLUMN_INDEX_14BPC;
+       case 16:
+               return COLUMN_INDEX_16BPC;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int intel_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg)
+{
+       unsigned long groups_per_line = 0;
+       unsigned long groups_total = 0;
+       unsigned long num_extra_mux_bits = 0;
+       unsigned long slice_bits = 0;
+       unsigned long hrd_delay = 0;
+       unsigned long final_scale = 0;
+       unsigned long rbs_min = 0;
+
+       /* Number of groups used to code each line of a slice */
+       groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width,
+                                      DSC_RC_PIXELS_PER_GROUP);
+
+       /* chunksize in Bytes */
+       vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width *
+                                                 vdsc_cfg->bits_per_pixel,
+                                                 (8 * 16));
+
+       if (vdsc_cfg->convert_rgb)
+               num_extra_mux_bits = 3 * (vdsc_cfg->mux_word_size +
+                                         (4 * vdsc_cfg->bits_per_component + 4)
+                                         - 2);
+       else
+               num_extra_mux_bits = 3 * vdsc_cfg->mux_word_size +
+                       (4 * vdsc_cfg->bits_per_component + 4) +
+                       2 * (4 * vdsc_cfg->bits_per_component) - 2;
+       /* Number of bits in one Slice */
+       slice_bits = 8 * vdsc_cfg->slice_chunk_size * vdsc_cfg->slice_height;
+
+       while ((num_extra_mux_bits > 0) &&
+              ((slice_bits - num_extra_mux_bits) % vdsc_cfg->mux_word_size))
+               num_extra_mux_bits--;
+
+       if (groups_per_line < vdsc_cfg->initial_scale_value - 8)
+               vdsc_cfg->initial_scale_value = groups_per_line + 8;
+
+       /* scale_decrement_interval calculation according to DSC spec 1.11 */
+       if (vdsc_cfg->initial_scale_value > 8)
+               vdsc_cfg->scale_decrement_interval = groups_per_line /
+                       (vdsc_cfg->initial_scale_value - 8);
+       else
+               vdsc_cfg->scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX;
+
+       vdsc_cfg->final_offset = vdsc_cfg->rc_model_size -
+               (vdsc_cfg->initial_xmit_delay *
+                vdsc_cfg->bits_per_pixel + 8) / 16 + num_extra_mux_bits;
+
+       if (vdsc_cfg->final_offset >= vdsc_cfg->rc_model_size) {
+               DRM_DEBUG_KMS("FinalOfs < RcModelSze for this InitialXmitDelay\n");
+               return -ERANGE;
+       }
+
+       final_scale = (vdsc_cfg->rc_model_size * 8) /
+               (vdsc_cfg->rc_model_size - vdsc_cfg->final_offset);
+       if (vdsc_cfg->slice_height > 1)
+               /*
+                * NflBpgOffset is 16 bit value with 11 fractional bits
+                * hence we multiply by 2^11 for preserving the
+                * fractional part
+                */
+               vdsc_cfg->nfl_bpg_offset = DIV_ROUND_UP((vdsc_cfg->first_line_bpg_offset << 11),
+                                                       (vdsc_cfg->slice_height - 1));
+       else
+               vdsc_cfg->nfl_bpg_offset = 0;
+
+       /* 2^16 - 1 */
+       if (vdsc_cfg->nfl_bpg_offset > 65535) {
+               DRM_DEBUG_KMS("NflBpgOffset is too large for this slice height\n");
+               return -ERANGE;
+       }
+
+       /* Number of groups used to code the entire slice */
+       groups_total = groups_per_line * vdsc_cfg->slice_height;
+
+       /* slice_bpg_offset is 16 bit value with 11 fractional bits */
+       vdsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((vdsc_cfg->rc_model_size -
+                                                   vdsc_cfg->initial_offset +
+                                                   num_extra_mux_bits) << 11),
+                                                 groups_total);
+
+       if (final_scale > 9) {
+               /*
+                * ScaleIncrementInterval =
+                * finaloffset/((NflBpgOffset + SliceBpgOffset)*8(finalscale - 1.125))
+                * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional value,
+                * we need divide by 2^11 from pstDscCfg values
+                */
+               vdsc_cfg->scale_increment_interval =
+                               (vdsc_cfg->final_offset * (1 << 11)) /
+                               ((vdsc_cfg->nfl_bpg_offset +
+                               vdsc_cfg->slice_bpg_offset) *
+                               (final_scale - 9));
+       } else {
+               /*
+                * If finalScaleValue is less than or equal to 9, a value of 0 should
+                * be used to disable the scale increment at the end of the slice
+                */
+               vdsc_cfg->scale_increment_interval = 0;
+       }
+
+       if (vdsc_cfg->scale_increment_interval > 65535) {
+               DRM_DEBUG_KMS("ScaleIncrementInterval is large for slice height\n");
+               return -ERANGE;
+       }
+
+       /*
+        * DSC spec mentions that bits_per_pixel specifies the target
+        * bits/pixel (bpp) rate that is used by the encoder,
+        * in steps of 1/16 of a bit per pixel
+        */
+       rbs_min = vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset +
+               DIV_ROUND_UP(vdsc_cfg->initial_xmit_delay *
+                            vdsc_cfg->bits_per_pixel, 16) +
+               groups_per_line * vdsc_cfg->first_line_bpg_offset;
+
+       hrd_delay = DIV_ROUND_UP((rbs_min * 16), vdsc_cfg->bits_per_pixel);
+       vdsc_cfg->rc_bits = (hrd_delay * vdsc_cfg->bits_per_pixel) / 16;
+       vdsc_cfg->initial_dec_delay = hrd_delay - vdsc_cfg->initial_xmit_delay;
+
+       return 0;
+}
+
+int intel_dp_compute_dsc_params(struct intel_dp *intel_dp,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_dsc_config *vdsc_cfg = &pipe_config->dp_dsc_cfg;
+       u16 compressed_bpp = pipe_config->dsc_params.compressed_bpp;
+       u8 i = 0;
+       int row_index = 0;
+       int column_index = 0;
+       u8 line_buf_depth = 0;
+
+       vdsc_cfg->pic_width = pipe_config->base.adjusted_mode.crtc_hdisplay;
+       vdsc_cfg->pic_height = pipe_config->base.adjusted_mode.crtc_vdisplay;
+       vdsc_cfg->slice_width = DIV_ROUND_UP(vdsc_cfg->pic_width,
+                                            pipe_config->dsc_params.slice_count);
+       /*
+        * Slice Height of 8 works for all currently available panels. So start
+        * with that if pic_height is an integral multiple of 8.
+        * Eventually add logic to try multiple slice heights.
+        */
+       if (vdsc_cfg->pic_height % 8 == 0)
+               vdsc_cfg->slice_height = 8;
+       else if (vdsc_cfg->pic_height % 4 == 0)
+               vdsc_cfg->slice_height = 4;
+       else
+               vdsc_cfg->slice_height = 2;
+
+       /* Values filled from DSC Sink DPCD */
+       vdsc_cfg->dsc_version_major =
+               (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+                DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT;
+       vdsc_cfg->dsc_version_minor =
+               min(DSC_SUPPORTED_VERSION_MIN,
+                   (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+                    DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT);
+
+       vdsc_cfg->convert_rgb = intel_dp->dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] &
+               DP_DSC_RGB;
+
+       line_buf_depth = drm_dp_dsc_sink_line_buf_depth(intel_dp->dsc_dpcd);
+       if (!line_buf_depth) {
+               DRM_DEBUG_KMS("DSC Sink Line Buffer Depth invalid\n");
+               return -EINVAL;
+       }
+       if (vdsc_cfg->dsc_version_minor == 2)
+               vdsc_cfg->line_buf_depth = (line_buf_depth == DSC_1_2_MAX_LINEBUF_DEPTH_BITS) ?
+                       DSC_1_2_MAX_LINEBUF_DEPTH_VAL : line_buf_depth;
+       else
+               vdsc_cfg->line_buf_depth = (line_buf_depth > DSC_1_1_MAX_LINEBUF_DEPTH_BITS) ?
+                       DSC_1_1_MAX_LINEBUF_DEPTH_BITS : line_buf_depth;
+
+       /* Gen 11 does not support YCbCr */
+       vdsc_cfg->enable422 = false;
+       /* Gen 11 does not support VBR */
+       vdsc_cfg->vbr_enable = false;
+       vdsc_cfg->block_pred_enable =
+                       intel_dp->dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] &
+               DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
+
+       /* Gen 11 only supports integral values of bpp */
+       vdsc_cfg->bits_per_pixel = compressed_bpp << 4;
+       vdsc_cfg->bits_per_component = pipe_config->pipe_bpp / 3;
+
+       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
+               /*
+                * six 0s are appended to the lsb of each threshold value
+                * internally in h/w.
+                * Only 8 bits are allowed for programming RcBufThreshold
+                */
+               vdsc_cfg->rc_buf_thresh[i] = rc_buf_thresh[i] >> 6;
+       }
+
+       /*
+        * For 6bpp, RC Buffer threshold 12 and 13 need a different value
+        * as per C Model
+        */
+       if (compressed_bpp == 6) {
+               vdsc_cfg->rc_buf_thresh[12] = 0x7C;
+               vdsc_cfg->rc_buf_thresh[13] = 0x7D;
+       }
+
+       row_index = get_row_index_for_rc_params(compressed_bpp);
+       column_index =
+               get_column_index_for_rc_params(vdsc_cfg->bits_per_component);
+
+       if (row_index < 0 || column_index < 0)
+               return -EINVAL;
+
+       vdsc_cfg->first_line_bpg_offset =
+               rc_params[row_index][column_index].first_line_bpg_offset;
+       vdsc_cfg->initial_xmit_delay =
+               rc_params[row_index][column_index].initial_xmit_delay;
+       vdsc_cfg->initial_offset =
+               rc_params[row_index][column_index].initial_offset;
+       vdsc_cfg->flatness_min_qp =
+               rc_params[row_index][column_index].flatness_min_qp;
+       vdsc_cfg->flatness_max_qp =
+               rc_params[row_index][column_index].flatness_max_qp;
+       vdsc_cfg->rc_quant_incr_limit0 =
+               rc_params[row_index][column_index].rc_quant_incr_limit0;
+       vdsc_cfg->rc_quant_incr_limit1 =
+               rc_params[row_index][column_index].rc_quant_incr_limit1;
+
+       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+               vdsc_cfg->rc_range_params[i].range_min_qp =
+                       rc_params[row_index][column_index].rc_range_params[i].range_min_qp;
+               vdsc_cfg->rc_range_params[i].range_max_qp =
+                       rc_params[row_index][column_index].rc_range_params[i].range_max_qp;
+               /*
+                * Range BPG Offset uses 2's complement and is only a 6 bits. So
+                * mask it to get only 6 bits.
+                */
+               vdsc_cfg->rc_range_params[i].range_bpg_offset =
+                       rc_params[row_index][column_index].rc_range_params[i].range_bpg_offset &
+                       DSC_RANGE_BPG_OFFSET_MASK;
+       }
+
+       /*
+        * BitsPerComponent value determines mux_word_size:
+        * When BitsPerComponent is 12bpc, muxWordSize will be equal to 64 bits
+        * When BitsPerComponent is 8 or 10bpc, muxWordSize will be equal to
+        * 48 bits
+        */
+       if (vdsc_cfg->bits_per_component == 8 ||
+           vdsc_cfg->bits_per_component == 10)
+               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+       else if (vdsc_cfg->bits_per_component == 12)
+               vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
+
+       /* RC_MODEL_SIZE is a constant across all configurations */
+       vdsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
+       /* InitialScaleValue is a 6 bit value with 3 fractional bits (U3.3) */
+       vdsc_cfg->initial_scale_value = (vdsc_cfg->rc_model_size << 3) /
+               (vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset);
+
+       return intel_compute_rc_parameters(vdsc_cfg);
+}
+
+enum intel_display_power_domain
+intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
+{
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+
+       /*
+        * On ICL VDSC/joining for eDP transcoder uses a separate power well PW2
+        * This requires POWER_DOMAIN_TRANSCODER_EDP_VDSC power domain.
+        * For any other transcoder, VDSC/joining uses the power well associated
+        * with the pipe/transcoder in use. Hence another reference on the
+        * transcoder power domain will suffice.
+        */
+       if (cpu_transcoder == TRANSCODER_EDP)
+               return POWER_DOMAIN_TRANSCODER_EDP_VDSC;
+       else
+               return POWER_DOMAIN_TRANSCODER(cpu_transcoder);
+}
+
+static void intel_configure_pps_for_dsc_encoder(struct intel_encoder *encoder,
+                                               const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
+       enum pipe pipe = crtc->pipe;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       u32 pps_val = 0;
+       u32 rc_buf_thresh_dword[4];
+       u32 rc_range_params_dword[8];
+       u8 num_vdsc_instances = (crtc_state->dsc_params.dsc_split) ? 2 : 1;
+       int i = 0;
+
+       /* Populate PICTURE_PARAMETER_SET_0 registers */
+       pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
+               DSC_VER_MIN_SHIFT |
+               vdsc_cfg->bits_per_component << DSC_BPC_SHIFT |
+               vdsc_cfg->line_buf_depth << DSC_LINE_BUF_DEPTH_SHIFT;
+       if (vdsc_cfg->block_pred_enable)
+               pps_val |= DSC_BLOCK_PREDICTION;
+       if (vdsc_cfg->convert_rgb)
+               pps_val |= DSC_COLOR_SPACE_CONVERSION;
+       if (vdsc_cfg->enable422)
+               pps_val |= DSC_422_ENABLE;
+       if (vdsc_cfg->vbr_enable)
+               pps_val |= DSC_VBR_ENABLE;
+       DRM_INFO("PPS0 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_0, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_0, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_1 registers */
+       pps_val = 0;
+       pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel);
+       DRM_INFO("PPS1 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_1, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_1, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_2 registers */
+       pps_val = 0;
+       pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) |
+               DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances);
+       DRM_INFO("PPS2 = 0x%08x\n", pps_val);
+       if (encoder->type == INTEL_OUTPUT_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_2, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_2, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_3 registers */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) |
+               DSC_SLICE_WIDTH(vdsc_cfg->slice_width);
+       DRM_INFO("PPS3 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_3, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_3, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_4 registers */
+       pps_val = 0;
+       pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) |
+               DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay);
+       DRM_INFO("PPS4 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_4, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_4, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_5 registers */
+       pps_val = 0;
+       pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) |
+               DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval);
+       DRM_INFO("PPS5 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_5, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_5, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_6 registers */
+       pps_val = 0;
+       pps_val |= DSC_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) |
+               DSC_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) |
+               DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) |
+               DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp);
+       DRM_INFO("PPS6 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_6, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_6, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_7 registers */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) |
+               DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset);
+       DRM_INFO("PPS7 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_7, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_7, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_8 registers */
+       pps_val = 0;
+       pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) |
+               DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset);
+       DRM_INFO("PPS8 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_8, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_8, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_9 registers */
+       pps_val = 0;
+       pps_val |= DSC_RC_MODEL_SIZE(DSC_RC_MODEL_SIZE_CONST) |
+               DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST);
+       DRM_INFO("PPS9 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_9, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_9, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe),
+                                  pps_val);
+       }
+
+       /* Populate PICTURE_PARAMETER_SET_10 registers */
+       pps_val = 0;
+       pps_val |= DSC_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) |
+               DSC_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) |
+               DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) |
+               DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST);
+       DRM_INFO("PPS10 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_10, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_10, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe),
+                                  pps_val);
+       }
+
+       /* Populate Picture parameter set 16 */
+       pps_val = 0;
+       pps_val |= DSC_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) |
+               DSC_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) /
+                                  vdsc_cfg->slice_width) |
+               DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height /
+                                       vdsc_cfg->slice_height);
+       DRM_INFO("PPS16 = 0x%08x\n", pps_val);
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_PICTURE_PARAMETER_SET_16, pps_val);
+               /*
+                * If 2 VDSC instances are needed, configure PPS for second
+                * VDSC
+                */
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(DSCC_PICTURE_PARAMETER_SET_16, pps_val);
+       } else {
+               I915_WRITE(ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe), pps_val);
+               if (crtc_state->dsc_params.dsc_split)
+                       I915_WRITE(ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe),
+                                  pps_val);
+       }
+
+       /* Populate the RC_BUF_THRESH registers */
+       memset(rc_buf_thresh_dword, 0, sizeof(rc_buf_thresh_dword));
+       for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
+               rc_buf_thresh_dword[i / 4] |=
+                       (u32)(vdsc_cfg->rc_buf_thresh[i] <<
+                             BITS_PER_BYTE * (i % 4));
+               DRM_INFO(" RC_BUF_THRESH%d = 0x%08x\n", i,
+                        rc_buf_thresh_dword[i / 4]);
+       }
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_0_UDW, rc_buf_thresh_dword[1]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_1, rc_buf_thresh_dword[2]);
+               I915_WRITE(DSCA_RC_BUF_THRESH_1_UDW, rc_buf_thresh_dword[3]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(DSCC_RC_BUF_THRESH_0,
+                                  rc_buf_thresh_dword[0]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_0_UDW,
+                                  rc_buf_thresh_dword[1]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_1,
+                                  rc_buf_thresh_dword[2]);
+                       I915_WRITE(DSCC_RC_BUF_THRESH_1_UDW,
+                                  rc_buf_thresh_dword[3]);
+               }
+       } else {
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0(pipe),
+                          rc_buf_thresh_dword[0]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_0_UDW(pipe),
+                          rc_buf_thresh_dword[1]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1(pipe),
+                          rc_buf_thresh_dword[2]);
+               I915_WRITE(ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe),
+                          rc_buf_thresh_dword[3]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0(pipe),
+                                  rc_buf_thresh_dword[0]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_0_UDW(pipe),
+                                  rc_buf_thresh_dword[1]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1(pipe),
+                                  rc_buf_thresh_dword[2]);
+                       I915_WRITE(ICL_DSC1_RC_BUF_THRESH_1_UDW(pipe),
+                                  rc_buf_thresh_dword[3]);
+               }
+       }
+
+       /* Populate the RC_RANGE_PARAMETERS registers */
+       memset(rc_range_params_dword, 0, sizeof(rc_range_params_dword));
+       for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+               rc_range_params_dword[i / 2] |=
+                       (u32)(((vdsc_cfg->rc_range_params[i].range_bpg_offset <<
+                               RC_BPG_OFFSET_SHIFT) |
+                              (vdsc_cfg->rc_range_params[i].range_max_qp <<
+                               RC_MAX_QP_SHIFT) |
+                              (vdsc_cfg->rc_range_params[i].range_min_qp <<
+                               RC_MIN_QP_SHIFT)) << 16 * (i % 2));
+               DRM_INFO(" RC_RANGE_PARAM_%d = 0x%08x\n", i,
+                        rc_range_params_dword[i / 2]);
+       }
+       if (cpu_transcoder == TRANSCODER_EDP) {
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0,
+                          rc_range_params_dword[0]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_0_UDW,
+                          rc_range_params_dword[1]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1,
+                          rc_range_params_dword[2]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_1_UDW,
+                          rc_range_params_dword[3]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2,
+                          rc_range_params_dword[4]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_2_UDW,
+                          rc_range_params_dword[5]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3,
+                          rc_range_params_dword[6]);
+               I915_WRITE(DSCA_RC_RANGE_PARAMETERS_3_UDW,
+                          rc_range_params_dword[7]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0,
+                                  rc_range_params_dword[0]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_0_UDW,
+                                  rc_range_params_dword[1]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1,
+                                  rc_range_params_dword[2]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_1_UDW,
+                                  rc_range_params_dword[3]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2,
+                                  rc_range_params_dword[4]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_2_UDW,
+                                  rc_range_params_dword[5]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3,
+                                  rc_range_params_dword[6]);
+                       I915_WRITE(DSCC_RC_RANGE_PARAMETERS_3_UDW,
+                                  rc_range_params_dword[7]);
+               }
+       } else {
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe),
+                          rc_range_params_dword[0]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe),
+                          rc_range_params_dword[1]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe),
+                          rc_range_params_dword[2]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe),
+                          rc_range_params_dword[3]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe),
+                          rc_range_params_dword[4]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe),
+                          rc_range_params_dword[5]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe),
+                          rc_range_params_dword[6]);
+               I915_WRITE(ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe),
+                          rc_range_params_dword[7]);
+               if (crtc_state->dsc_params.dsc_split) {
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe),
+                                  rc_range_params_dword[0]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe),
+                                  rc_range_params_dword[1]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe),
+                                  rc_range_params_dword[2]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe),
+                                  rc_range_params_dword[3]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe),
+                                  rc_range_params_dword[4]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe),
+                                  rc_range_params_dword[5]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe),
+                                  rc_range_params_dword[6]);
+                       I915_WRITE(ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe),
+                                  rc_range_params_dword[7]);
+               }
+       }
+}
+
+static void intel_dp_write_dsc_pps_sdp(struct intel_encoder *encoder,
+                                      const struct intel_crtc_state *crtc_state)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       const struct drm_dsc_config *vdsc_cfg = &crtc_state->dp_dsc_cfg;
+       struct drm_dsc_pps_infoframe dp_dsc_pps_sdp;
+
+       /* Prepare DP SDP PPS header as per DP 1.4 spec, Table 2-123 */
+       drm_dsc_dp_pps_header_init(&dp_dsc_pps_sdp);
+
+       /* Fill the PPS payload bytes as per DSC spec 1.2 Table 4-1 */
+       drm_dsc_pps_infoframe_pack(&dp_dsc_pps_sdp, vdsc_cfg);
+
+       intel_dig_port->write_infoframe(encoder, crtc_state,
+                                       DP_SDP_PPS, &dp_dsc_pps_sdp,
+                                       sizeof(dp_dsc_pps_sdp));
+}
+
+void intel_dsc_enable(struct intel_encoder *encoder,
+                     const struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = crtc->pipe;
+       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+       u32 dss_ctl1_val = 0;
+       u32 dss_ctl2_val = 0;
+
+       if (!crtc_state->dsc_params.compression_enable)
+               return;
+
+       /* Enable Power wells for VDSC/joining */
+       intel_display_power_get(dev_priv,
+                               intel_dsc_power_domain(crtc_state));
+
+       intel_configure_pps_for_dsc_encoder(encoder, crtc_state);
+
+       intel_dp_write_dsc_pps_sdp(encoder, crtc_state);
+
+       if (crtc_state->cpu_transcoder == TRANSCODER_EDP) {
+               dss_ctl1_reg = DSS_CTL1;
+               dss_ctl2_reg = DSS_CTL2;
+       } else {
+               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
+               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+       }
+       dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
+       if (crtc_state->dsc_params.dsc_split) {
+               dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
+               dss_ctl1_val |= JOINER_ENABLE;
+       }
+       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
+       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
+}
+
+void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+       u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
+
+       if (!old_crtc_state->dsc_params.compression_enable)
+               return;
+
+       if (old_crtc_state->cpu_transcoder == TRANSCODER_EDP) {
+               dss_ctl1_reg = DSS_CTL1;
+               dss_ctl2_reg = DSS_CTL2;
+       } else {
+               dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
+               dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+       }
+       dss_ctl1_val = I915_READ(dss_ctl1_reg);
+       if (dss_ctl1_val & JOINER_ENABLE)
+               dss_ctl1_val &= ~JOINER_ENABLE;
+       I915_WRITE(dss_ctl1_reg, dss_ctl1_val);
+
+       dss_ctl2_val = I915_READ(dss_ctl2_reg);
+       if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
+           dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
+               dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
+                                 RIGHT_BRANCH_VDSC_ENABLE);
+       I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
+
+       /* Disable Power wells for VDSC/joining */
+       intel_display_power_put(dev_priv,
+                               intel_dsc_power_domain(old_crtc_state));
+}
index 6e580891db96fa9350bfa2a2f9a68be50703229b..4f41e326f3f3fd77e0a8d519e1f33933a5a0d92b 100644 (file)
@@ -53,67 +53,107 @@ static void wa_init_start(struct i915_wa_list *wal, const char *name)
        wal->name = name;
 }
 
+#define WA_LIST_CHUNK (1 << 4)
+
 static void wa_init_finish(struct i915_wa_list *wal)
 {
+       /* Trim unused entries. */
+       if (!IS_ALIGNED(wal->count, WA_LIST_CHUNK)) {
+               struct i915_wa *list = kmemdup(wal->list,
+                                              wal->count * sizeof(*list),
+                                              GFP_KERNEL);
+
+               if (list) {
+                       kfree(wal->list);
+                       wal->list = list;
+               }
+       }
+
        if (!wal->count)
                return;
 
        DRM_DEBUG_DRIVER("Initialized %u %s workarounds\n",
-                        wal->count, wal->name);
+                        wal->wa_count, wal->name);
 }
 
-static void wa_add(struct drm_i915_private *i915,
-                  i915_reg_t reg, const u32 mask, const u32 val)
+static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa)
 {
-       struct i915_workarounds *wa = &i915->workarounds;
-       unsigned int start = 0, end = wa->count;
-       unsigned int addr = i915_mmio_reg_offset(reg);
-       struct i915_wa_reg *r;
+       unsigned int addr = i915_mmio_reg_offset(wa->reg);
+       unsigned int start = 0, end = wal->count;
+       const unsigned int grow = WA_LIST_CHUNK;
+       struct i915_wa *wa_;
+
+       GEM_BUG_ON(!is_power_of_2(grow));
+
+       if (IS_ALIGNED(wal->count, grow)) { /* Either uninitialized or full. */
+               struct i915_wa *list;
+
+               list = kmalloc_array(ALIGN(wal->count + 1, grow), sizeof(*wa),
+                                    GFP_KERNEL);
+               if (!list) {
+                       DRM_ERROR("No space for workaround init!\n");
+                       return;
+               }
+
+               if (wal->list)
+                       memcpy(list, wal->list, sizeof(*wa) * wal->count);
+
+               wal->list = list;
+       }
 
        while (start < end) {
                unsigned int mid = start + (end - start) / 2;
 
-               if (wa->reg[mid].addr < addr) {
+               if (i915_mmio_reg_offset(wal->list[mid].reg) < addr) {
                        start = mid + 1;
-               } else if (wa->reg[mid].addr > addr) {
+               } else if (i915_mmio_reg_offset(wal->list[mid].reg) > addr) {
                        end = mid;
                } else {
-                       r = &wa->reg[mid];
+                       wa_ = &wal->list[mid];
 
-                       if ((mask & ~r->mask) == 0) {
+                       if ((wa->mask & ~wa_->mask) == 0) {
                                DRM_ERROR("Discarding overwritten w/a for reg %04x (mask: %08x, value: %08x)\n",
-                                         addr, r->mask, r->value);
+                                         i915_mmio_reg_offset(wa_->reg),
+                                         wa_->mask, wa_->val);
 
-                               r->value &= ~mask;
+                               wa_->val &= ~wa->mask;
                        }
 
-                       r->value |= val;
-                       r->mask  |= mask;
+                       wal->wa_count++;
+                       wa_->val |= wa->val;
+                       wa_->mask |= wa->mask;
                        return;
                }
        }
 
-       if (WARN_ON_ONCE(wa->count >= I915_MAX_WA_REGS)) {
-               DRM_ERROR("Dropping w/a for reg %04x (mask: %08x, value: %08x)\n",
-                         addr, mask, val);
-               return;
-       }
-
-       r = &wa->reg[wa->count++];
-       r->addr  = addr;
-       r->value = val;
-       r->mask  = mask;
+       wal->wa_count++;
+       wa_ = &wal->list[wal->count++];
+       *wa_ = *wa;
 
-       while (r-- > wa->reg) {
-               GEM_BUG_ON(r[0].addr == r[1].addr);
-               if (r[1].addr > r[0].addr)
+       while (wa_-- > wal->list) {
+               GEM_BUG_ON(i915_mmio_reg_offset(wa_[0].reg) ==
+                          i915_mmio_reg_offset(wa_[1].reg));
+               if (i915_mmio_reg_offset(wa_[1].reg) >
+                   i915_mmio_reg_offset(wa_[0].reg))
                        break;
 
-               swap(r[1], r[0]);
+               swap(wa_[1], wa_[0]);
        }
 }
 
-#define WA_REG(addr, mask, val) wa_add(dev_priv, (addr), (mask), (val))
+static void
+__wa_add(struct i915_wa_list *wal, i915_reg_t reg, u32 mask, u32 val)
+{
+       struct i915_wa wa = {
+               .reg = reg,
+               .mask = mask,
+               .val = val
+       };
+
+       _wa_add(wal, &wa);
+}
+
+#define WA_REG(addr, mask, val) __wa_add(wal, (addr), (mask), (val))
 
 #define WA_SET_BIT_MASKED(addr, mask) \
        WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
@@ -124,8 +164,10 @@ static void wa_add(struct drm_i915_private *i915,
 #define WA_SET_FIELD_MASKED(addr, mask, value) \
        WA_REG(addr, (mask), _MASKED_FIELD(mask, value))
 
-static int gen8_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void gen8_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
+
        WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
 
        /* WaDisableAsyncFlipPerfMode:bdw,chv */
@@ -169,17 +211,14 @@ static int gen8_ctx_workarounds_init(struct drm_i915_private *dev_priv)
        WA_SET_FIELD_MASKED(GEN7_GT_MODE,
                            GEN6_WIZ_HASHING_MASK,
                            GEN6_WIZ_HASHING_16x4);
-
-       return 0;
 }
 
-static int bdw_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void bdw_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       ret = gen8_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       gen8_ctx_workarounds_init(engine);
 
        /* WaDisableThreadStallDopClockGating:bdw (pre-production) */
        WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
@@ -199,31 +238,28 @@ static int bdw_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                          /* WaForceContextSaveRestoreNonCoherent:bdw */
                          HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
                          /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
-                         (IS_BDW_GT3(dev_priv) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
-
-       return 0;
+                         (IS_BDW_GT3(i915) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
 }
 
-static int chv_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void chv_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       ret = gen8_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       gen8_ctx_workarounds_init(engine);
 
        /* WaDisableThreadStallDopClockGating:chv */
        WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
 
        /* Improve HiZ throughput on CHV. */
        WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
-
-       return 0;
 }
 
-static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       if (HAS_LLC(dev_priv)) {
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
+
+       if (HAS_LLC(i915)) {
                /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl
                 *
                 * Must match Display Engine. See
@@ -242,7 +278,7 @@ static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                          PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
 
        /* Syncing dependencies between camera and graphics:skl,bxt,kbl */
-       if (!IS_COFFEELAKE(dev_priv))
+       if (!IS_COFFEELAKE(i915))
                WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
                                  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
 
@@ -285,9 +321,7 @@ static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                          HDC_FORCE_NON_COHERENT);
 
        /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */
-       if (IS_SKYLAKE(dev_priv) ||
-           IS_KABYLAKE(dev_priv) ||
-           IS_COFFEELAKE(dev_priv))
+       if (IS_SKYLAKE(i915) || IS_KABYLAKE(i915) || IS_COFFEELAKE(i915))
                WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
                                  GEN8_SAMPLER_POWER_BYPASS_DIS);
 
@@ -314,14 +348,14 @@ static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                            GEN9_PREEMPT_GPGPU_COMMAND_LEVEL);
 
        /* WaClearHIZ_WM_CHICKEN3:bxt,glk */
-       if (IS_GEN9_LP(dev_priv))
+       if (IS_GEN9_LP(i915))
                WA_SET_BIT_MASKED(GEN9_WM_CHICKEN3, GEN9_FACTOR_IN_CLR_VAL_HIZ);
-
-       return 0;
 }
 
-static int skl_tune_iz_hashing(struct drm_i915_private *dev_priv)
+static void skl_tune_iz_hashing(struct intel_engine_cs *engine)
 {
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
        u8 vals[3] = { 0, 0, 0 };
        unsigned int i;
 
@@ -332,7 +366,7 @@ static int skl_tune_iz_hashing(struct drm_i915_private *dev_priv)
                 * Only consider slices where one, and only one, subslice has 7
                 * EUs
                 */
-               if (!is_power_of_2(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]))
+               if (!is_power_of_2(INTEL_INFO(i915)->sseu.subslice_7eu[i]))
                        continue;
 
                /*
@@ -341,12 +375,12 @@ static int skl_tune_iz_hashing(struct drm_i915_private *dev_priv)
                 *
                 * ->    0 <= ss <= 3;
                 */
-               ss = ffs(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]) - 1;
+               ss = ffs(INTEL_INFO(i915)->sseu.subslice_7eu[i]) - 1;
                vals[i] = 3 - ss;
        }
 
        if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
-               return 0;
+               return;
 
        /* Tune IZ hashing. See intel_device_info_runtime_init() */
        WA_SET_FIELD_MASKED(GEN7_GT_MODE,
@@ -356,28 +390,19 @@ static int skl_tune_iz_hashing(struct drm_i915_private *dev_priv)
                            GEN9_IZ_HASHING(2, vals[2]) |
                            GEN9_IZ_HASHING(1, vals[1]) |
                            GEN9_IZ_HASHING(0, vals[0]));
-
-       return 0;
 }
 
-static int skl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void skl_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
-
-       ret = gen9_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
-
-       return skl_tune_iz_hashing(dev_priv);
+       gen9_ctx_workarounds_init(engine);
+       skl_tune_iz_hashing(engine);
 }
 
-static int bxt_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void bxt_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       ret = gen9_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       gen9_ctx_workarounds_init(engine);
 
        /* WaDisableThreadStallDopClockGating:bxt */
        WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
@@ -386,57 +411,41 @@ static int bxt_ctx_workarounds_init(struct drm_i915_private *dev_priv)
        /* WaToEnableHwFixForPushConstHWBug:bxt */
        WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
                          GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
-
-       return 0;
 }
 
-static int kbl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
-
-       ret = gen9_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */
-       if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0))
-               WA_SET_BIT_MASKED(HDC_CHICKEN0,
-                                 HDC_FENCE_DEST_SLM_DISABLE);
+       gen9_ctx_workarounds_init(engine);
 
        /* WaToEnableHwFixForPushConstHWBug:kbl */
-       if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER))
+       if (IS_KBL_REVID(i915, KBL_REVID_C0, REVID_FOREVER))
                WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
                                  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
 
        /* WaDisableSbeCacheDispatchPortSharing:kbl */
        WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1,
                          GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
-
-       return 0;
 }
 
-static int glk_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void glk_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       ret = gen9_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       gen9_ctx_workarounds_init(engine);
 
        /* WaToEnableHwFixForPushConstHWBug:glk */
        WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
                          GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
-
-       return 0;
 }
 
-static int cfl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
-       int ret;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
 
-       ret = gen9_ctx_workarounds_init(dev_priv);
-       if (ret)
-               return ret;
+       gen9_ctx_workarounds_init(engine);
 
        /* WaToEnableHwFixForPushConstHWBug:cfl */
        WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
@@ -445,18 +454,19 @@ static int cfl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
        /* WaDisableSbeCacheDispatchPortSharing:cfl */
        WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1,
                          GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
-
-       return 0;
 }
 
-static int cnl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void cnl_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
+
        /* WaForceContextSaveRestoreNonCoherent:cnl */
        WA_SET_BIT_MASKED(CNL_HDC_CHICKEN0,
                          HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT);
 
        /* WaThrottleEUPerfToAvoidTDBackPressure:cnl(pre-prod) */
-       if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0))
+       if (IS_CNL_REVID(i915, CNL_REVID_B0, CNL_REVID_B0))
                WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, THROTTLE_12_5);
 
        /* WaDisableReplayBufferBankArbitrationOptimization:cnl */
@@ -464,7 +474,7 @@ static int cnl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                          GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
 
        /* WaDisableEnhancedSBEVertexCaching:cnl (pre-prod) */
-       if (IS_CNL_REVID(dev_priv, 0, CNL_REVID_B0))
+       if (IS_CNL_REVID(i915, 0, CNL_REVID_B0))
                WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
                                  GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE);
 
@@ -484,16 +494,17 @@ static int cnl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
 
        /* WaDisableEarlyEOT:cnl */
        WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, DISABLE_EARLY_EOT);
-
-       return 0;
 }
 
-static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+static void icl_ctx_workarounds_init(struct intel_engine_cs *engine)
 {
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
+
        /* Wa_1604370585:icl (pre-prod)
         * Formerly known as WaPushConstantDereferenceHoldDisable
         */
-       if (IS_ICL_REVID(dev_priv, ICL_REVID_A0, ICL_REVID_B0))
+       if (IS_ICL_REVID(i915, ICL_REVID_A0, ICL_REVID_B0))
                WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
                                  PUSH_CONSTANT_DEREF_DISABLE);
 
@@ -509,7 +520,7 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
        /* Wa_2006611047:icl (pre-prod)
         * Formerly known as WaDisableImprovedTdlClkGating
         */
-       if (IS_ICL_REVID(dev_priv, ICL_REVID_A0, ICL_REVID_A0))
+       if (IS_ICL_REVID(i915, ICL_REVID_A0, ICL_REVID_A0))
                WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
                                  GEN11_TDL_CLOCK_GATING_FIX_DISABLE);
 
@@ -518,70 +529,67 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv)
                          GEN11_STATE_CACHE_REDIRECT_TO_CS);
 
        /* Wa_2006665173:icl (pre-prod) */
-       if (IS_ICL_REVID(dev_priv, ICL_REVID_A0, ICL_REVID_A0))
+       if (IS_ICL_REVID(i915, ICL_REVID_A0, ICL_REVID_A0))
                WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3,
                                  GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC);
-
-       return 0;
 }
 
-int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv)
+void intel_engine_init_ctx_wa(struct intel_engine_cs *engine)
 {
-       int err = 0;
-
-       dev_priv->workarounds.count = 0;
-
-       if (INTEL_GEN(dev_priv) < 8)
-               err = 0;
-       else if (IS_BROADWELL(dev_priv))
-               err = bdw_ctx_workarounds_init(dev_priv);
-       else if (IS_CHERRYVIEW(dev_priv))
-               err = chv_ctx_workarounds_init(dev_priv);
-       else if (IS_SKYLAKE(dev_priv))
-               err = skl_ctx_workarounds_init(dev_priv);
-       else if (IS_BROXTON(dev_priv))
-               err = bxt_ctx_workarounds_init(dev_priv);
-       else if (IS_KABYLAKE(dev_priv))
-               err = kbl_ctx_workarounds_init(dev_priv);
-       else if (IS_GEMINILAKE(dev_priv))
-               err = glk_ctx_workarounds_init(dev_priv);
-       else if (IS_COFFEELAKE(dev_priv))
-               err = cfl_ctx_workarounds_init(dev_priv);
-       else if (IS_CANNONLAKE(dev_priv))
-               err = cnl_ctx_workarounds_init(dev_priv);
-       else if (IS_ICELAKE(dev_priv))
-               err = icl_ctx_workarounds_init(dev_priv);
+       struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *wal = &engine->ctx_wa_list;
+
+       wa_init_start(wal, "context");
+
+       if (INTEL_GEN(i915) < 8)
+               return;
+       else if (IS_BROADWELL(i915))
+               bdw_ctx_workarounds_init(engine);
+       else if (IS_CHERRYVIEW(i915))
+               chv_ctx_workarounds_init(engine);
+       else if (IS_SKYLAKE(i915))
+               skl_ctx_workarounds_init(engine);
+       else if (IS_BROXTON(i915))
+               bxt_ctx_workarounds_init(engine);
+       else if (IS_KABYLAKE(i915))
+               kbl_ctx_workarounds_init(engine);
+       else if (IS_GEMINILAKE(i915))
+               glk_ctx_workarounds_init(engine);
+       else if (IS_COFFEELAKE(i915))
+               cfl_ctx_workarounds_init(engine);
+       else if (IS_CANNONLAKE(i915))
+               cnl_ctx_workarounds_init(engine);
+       else if (IS_ICELAKE(i915))
+               icl_ctx_workarounds_init(engine);
        else
-               MISSING_CASE(INTEL_GEN(dev_priv));
-       if (err)
-               return err;
+               MISSING_CASE(INTEL_GEN(i915));
 
-       DRM_DEBUG_DRIVER("Number of context specific w/a: %d\n",
-                        dev_priv->workarounds.count);
-       return 0;
+       wa_init_finish(wal);
 }
 
-int intel_ctx_workarounds_emit(struct i915_request *rq)
+int intel_engine_emit_ctx_wa(struct i915_request *rq)
 {
-       struct i915_workarounds *w = &rq->i915->workarounds;
+       struct i915_wa_list *wal = &rq->engine->ctx_wa_list;
+       struct i915_wa *wa;
+       unsigned int i;
        u32 *cs;
-       int ret, i;
+       int ret;
 
-       if (w->count == 0)
+       if (wal->count == 0)
                return 0;
 
        ret = rq->engine->emit_flush(rq, EMIT_BARRIER);
        if (ret)
                return ret;
 
-       cs = intel_ring_begin(rq, (w->count * 2 + 2));
+       cs = intel_ring_begin(rq, (wal->count * 2 + 2));
        if (IS_ERR(cs))
                return PTR_ERR(cs);
 
-       *cs++ = MI_LOAD_REGISTER_IMM(w->count);
-       for (i = 0; i < w->count; i++) {
-               *cs++ = w->reg[i].addr;
-               *cs++ = w->reg[i].value;
+       *cs++ = MI_LOAD_REGISTER_IMM(wal->count);
+       for (i = 0, wa = wal->list; i < wal->count; i++, wa++) {
+               *cs++ = i915_mmio_reg_offset(wa->reg);
+               *cs++ = wa->val;
        }
        *cs++ = MI_NOOP;
 
@@ -594,32 +602,6 @@ int intel_ctx_workarounds_emit(struct i915_request *rq)
        return 0;
 }
 
-static void
-wal_add(struct i915_wa_list *wal, const struct i915_wa *wa)
-{
-       const unsigned int grow = 1 << 4;
-
-       GEM_BUG_ON(!is_power_of_2(grow));
-
-       if (IS_ALIGNED(wal->count, grow)) { /* Either uninitialized or full. */
-               struct i915_wa *list;
-
-               list = kmalloc_array(ALIGN(wal->count + 1, grow), sizeof(*wa),
-                                    GFP_KERNEL);
-               if (!list) {
-                       DRM_ERROR("No space for workaround init!\n");
-                       return;
-               }
-
-               if (wal->list)
-                       memcpy(list, wal->list, sizeof(*wa) * wal->count);
-
-               wal->list = list;
-       }
-
-       wal->list[wal->count++] = *wa;
-}
-
 static void
 wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
 {
@@ -629,7 +611,7 @@ wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
                .val = _MASKED_BIT_ENABLE(val)
        };
 
-       wal_add(wal, &wa);
+       _wa_add(wal, &wa);
 }
 
 static void
@@ -642,7 +624,7 @@ wa_write_masked_or(struct i915_wa_list *wal, i915_reg_t reg, u32 mask,
                .val = val
        };
 
-       wal_add(wal, &wa);
+       _wa_add(wal, &wa);
 }
 
 static void
@@ -982,29 +964,54 @@ void intel_gt_apply_workarounds(struct drm_i915_private *dev_priv)
        wa_list_apply(dev_priv, &dev_priv->gt_wa_list);
 }
 
-struct whitelist {
-       i915_reg_t reg[RING_MAX_NONPRIV_SLOTS];
-       unsigned int count;
-       u32 nopid;
-};
+static bool
+wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from)
+{
+       if ((cur ^ wa->val) & wa->mask) {
+               DRM_ERROR("%s workaround lost on %s! (%x=%x/%x, expected %x, mask=%x)\n",
+                         name, from, i915_mmio_reg_offset(wa->reg), cur,
+                         cur & wa->mask, wa->val, wa->mask);
+
+               return false;
+       }
+
+       return true;
+}
 
-static void whitelist_reg(struct whitelist *w, i915_reg_t reg)
+static bool wa_list_verify(struct drm_i915_private *dev_priv,
+                          const struct i915_wa_list *wal,
+                          const char *from)
 {
-       if (GEM_WARN_ON(w->count >= RING_MAX_NONPRIV_SLOTS))
-               return;
+       struct i915_wa *wa;
+       unsigned int i;
+       bool ok = true;
 
-       w->reg[w->count++] = reg;
+       for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
+               ok &= wa_verify(wa, I915_READ(wa->reg), wal->name, from);
+
+       return ok;
 }
 
-static void bdw_whitelist_build(struct whitelist *w)
+bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv,
+                                const char *from)
 {
+       return wa_list_verify(dev_priv, &dev_priv->gt_wa_list, from);
 }
 
-static void chv_whitelist_build(struct whitelist *w)
+static void
+whitelist_reg(struct i915_wa_list *wal, i915_reg_t reg)
 {
+       struct i915_wa wa = {
+               .reg = reg
+       };
+
+       if (GEM_DEBUG_WARN_ON(wal->count >= RING_MAX_NONPRIV_SLOTS))
+               return;
+
+       _wa_add(wal, &wa);
 }
 
-static void gen9_whitelist_build(struct whitelist *w)
+static void gen9_whitelist_build(struct i915_wa_list *w)
 {
        /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */
        whitelist_reg(w, GEN9_CTX_PREEMPT_REG);
@@ -1016,7 +1023,7 @@ static void gen9_whitelist_build(struct whitelist *w)
        whitelist_reg(w, GEN8_HDC_CHICKEN1);
 }
 
-static void skl_whitelist_build(struct whitelist *w)
+static void skl_whitelist_build(struct i915_wa_list *w)
 {
        gen9_whitelist_build(w);
 
@@ -1024,12 +1031,12 @@ static void skl_whitelist_build(struct whitelist *w)
        whitelist_reg(w, GEN8_L3SQCREG4);
 }
 
-static void bxt_whitelist_build(struct whitelist *w)
+static void bxt_whitelist_build(struct i915_wa_list *w)
 {
        gen9_whitelist_build(w);
 }
 
-static void kbl_whitelist_build(struct whitelist *w)
+static void kbl_whitelist_build(struct i915_wa_list *w)
 {
        gen9_whitelist_build(w);
 
@@ -1037,7 +1044,7 @@ static void kbl_whitelist_build(struct whitelist *w)
        whitelist_reg(w, GEN8_L3SQCREG4);
 }
 
-static void glk_whitelist_build(struct whitelist *w)
+static void glk_whitelist_build(struct i915_wa_list *w)
 {
        gen9_whitelist_build(w);
 
@@ -1045,37 +1052,41 @@ static void glk_whitelist_build(struct whitelist *w)
        whitelist_reg(w, GEN9_SLICE_COMMON_ECO_CHICKEN1);
 }
 
-static void cfl_whitelist_build(struct whitelist *w)
+static void cfl_whitelist_build(struct i915_wa_list *w)
 {
        gen9_whitelist_build(w);
 }
 
-static void cnl_whitelist_build(struct whitelist *w)
+static void cnl_whitelist_build(struct i915_wa_list *w)
 {
        /* WaEnablePreemptionGranularityControlByUMD:cnl */
        whitelist_reg(w, GEN8_CS_CHICKEN1);
 }
 
-static void icl_whitelist_build(struct whitelist *w)
+static void icl_whitelist_build(struct i915_wa_list *w)
 {
+       /* WaAllowUMDToModifyHalfSliceChicken7:icl */
+       whitelist_reg(w, GEN9_HALF_SLICE_CHICKEN7);
+
+       /* WaAllowUMDToModifySamplerMode:icl */
+       whitelist_reg(w, GEN10_SAMPLER_MODE);
 }
 
-static struct whitelist *whitelist_build(struct intel_engine_cs *engine,
-                                        struct whitelist *w)
+void intel_engine_init_whitelist(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *i915 = engine->i915;
+       struct i915_wa_list *w = &engine->whitelist;
 
        GEM_BUG_ON(engine->id != RCS);
 
-       w->count = 0;
-       w->nopid = i915_mmio_reg_offset(RING_NOPID(engine->mmio_base));
+       wa_init_start(w, "whitelist");
 
        if (INTEL_GEN(i915) < 8)
-               return NULL;
+               return;
        else if (IS_BROADWELL(i915))
-               bdw_whitelist_build(w);
+               return;
        else if (IS_CHERRYVIEW(i915))
-               chv_whitelist_build(w);
+               return;
        else if (IS_SKYLAKE(i915))
                skl_whitelist_build(w);
        else if (IS_BROXTON(i915))
@@ -1093,37 +1104,30 @@ static struct whitelist *whitelist_build(struct intel_engine_cs *engine,
        else
                MISSING_CASE(INTEL_GEN(i915));
 
-       return w;
+       wa_init_finish(w);
 }
 
-static void whitelist_apply(struct intel_engine_cs *engine,
-                           const struct whitelist *w)
+void intel_engine_apply_whitelist(struct intel_engine_cs *engine)
 {
        struct drm_i915_private *dev_priv = engine->i915;
+       const struct i915_wa_list *wal = &engine->whitelist;
        const u32 base = engine->mmio_base;
+       struct i915_wa *wa;
        unsigned int i;
 
-       if (!w)
+       if (!wal->count)
                return;
 
-       intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL);
-
-       for (i = 0; i < w->count; i++)
-               I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i),
-                             i915_mmio_reg_offset(w->reg[i]));
+       for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
+               I915_WRITE(RING_FORCE_TO_NONPRIV(base, i),
+                          i915_mmio_reg_offset(wa->reg));
 
        /* And clear the rest just in case of garbage */
        for (; i < RING_MAX_NONPRIV_SLOTS; i++)
-               I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i), w->nopid);
+               I915_WRITE(RING_FORCE_TO_NONPRIV(base, i),
+                          i915_mmio_reg_offset(RING_NOPID(base)));
 
-       intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL);
-}
-
-void intel_whitelist_workarounds_apply(struct intel_engine_cs *engine)
-{
-       struct whitelist w;
-
-       whitelist_apply(engine, whitelist_build(engine, &w));
+       DRM_DEBUG_DRIVER("Applied %u %s workarounds\n", wal->count, wal->name);
 }
 
 static void rcs_engine_wa_init(struct intel_engine_cs *engine)
@@ -1171,17 +1175,19 @@ static void rcs_engine_wa_init(struct intel_engine_cs *engine)
                            GEN8_L3SQCREG4,
                            GEN11_LQSC_CLEAN_EVICT_DISABLE);
 
-               /* Wa_1604302699:icl */
-               wa_write_or(wal,
-                           GEN10_L3_CHICKEN_MODE_REGISTER,
-                           GEN11_I2M_WRITE_DISABLE);
-
                /* WaForwardProgressSoftReset:icl */
                wa_write_or(wal,
                            GEN10_SCRATCH_LNCF2,
                            PMFLUSHDONE_LNICRSDROP |
                            PMFLUSH_GAPL3UNBLOCK |
                            PMFLUSHDONE_LNEBLK);
+
+               /* Wa_1406609255:icl (pre-prod) */
+               if (IS_ICL_REVID(i915, ICL_REVID_A0, ICL_REVID_B0))
+                       wa_write_or(wal,
+                                   GEN7_SARCHKMD,
+                                   GEN7_DISABLE_DEMAND_PREFETCH |
+                                   GEN7_DISABLE_SAMPLER_PREFETCH);
        }
 
        if (IS_GEN9(i915) || IS_CANNONLAKE(i915)) {
@@ -1267,5 +1273,11 @@ void intel_engine_apply_workarounds(struct intel_engine_cs *engine)
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+static bool intel_engine_verify_workarounds(struct intel_engine_cs *engine,
+                                           const char *from)
+{
+       return wa_list_verify(engine->i915, &engine->wa_list, from);
+}
+
 #include "selftests/intel_workarounds.c"
 #endif
index 979695a539648cee1fa4b7e870a9d12a6c4d5892..7c734714b05edc51027e269197602abefc541813 100644 (file)
@@ -19,6 +19,7 @@ struct i915_wa_list {
        const char      *name;
        struct i915_wa  *list;
        unsigned int    count;
+       unsigned int    wa_count;
 };
 
 static inline void intel_wa_list_free(struct i915_wa_list *wal)
@@ -27,13 +28,16 @@ static inline void intel_wa_list_free(struct i915_wa_list *wal)
        memset(wal, 0, sizeof(*wal));
 }
 
-int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv);
-int intel_ctx_workarounds_emit(struct i915_request *rq);
+void intel_engine_init_ctx_wa(struct intel_engine_cs *engine);
+int intel_engine_emit_ctx_wa(struct i915_request *rq);
 
 void intel_gt_init_workarounds(struct drm_i915_private *dev_priv);
 void intel_gt_apply_workarounds(struct drm_i915_private *dev_priv);
+bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv,
+                                const char *from);
 
-void intel_whitelist_workarounds_apply(struct intel_engine_cs *engine);
+void intel_engine_init_whitelist(struct intel_engine_cs *engine);
+void intel_engine_apply_whitelist(struct intel_engine_cs *engine);
 
 void intel_engine_init_workarounds(struct intel_engine_cs *engine);
 void intel_engine_apply_workarounds(struct intel_engine_cs *engine);
index 5c22f2c8d4cfee20337d484a9eb227c3c6adcb34..26c065c8d2c0a7e3b550dc96fa94ee611daae296 100644 (file)
@@ -1135,7 +1135,8 @@ static int igt_write_huge(struct i915_gem_context *ctx,
        n = 0;
        for_each_engine(engine, i915, id) {
                if (!intel_engine_can_store_dword(engine)) {
-                       pr_info("store-dword-imm not supported on engine=%u\n", id);
+                       pr_info("store-dword-imm not supported on engine=%u\n",
+                               id);
                        continue;
                }
                engines[n++] = engine;
@@ -1167,17 +1168,30 @@ static int igt_write_huge(struct i915_gem_context *ctx,
                engine = engines[order[i] % n];
                i = (i + 1) % (n * I915_NUM_ENGINES);
 
-               err = __igt_write_huge(ctx, engine, obj, size, offset_low, dword, num + 1);
+               /*
+                * In order to utilize 64K pages we need to both pad the vma
+                * size and ensure the vma offset is at the start of the pt
+                * boundary, however to improve coverage we opt for testing both
+                * aligned and unaligned offsets.
+                */
+               if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K)
+                       offset_low = round_down(offset_low,
+                                               I915_GTT_PAGE_SIZE_2M);
+
+               err = __igt_write_huge(ctx, engine, obj, size, offset_low,
+                                      dword, num + 1);
                if (err)
                        break;
 
-               err = __igt_write_huge(ctx, engine, obj, size, offset_high, dword, num + 1);
+               err = __igt_write_huge(ctx, engine, obj, size, offset_high,
+                                      dword, num + 1);
                if (err)
                        break;
 
                if (igt_timeout(end_time,
                                "%s timed out on engine=%u, offset_low=%llx offset_high=%llx, max_page_size=%x\n",
-                               __func__, engine->id, offset_low, offset_high, max_page_size))
+                               __func__, engine->id, offset_low, offset_high,
+                               max_page_size))
                        break;
        }
 
@@ -1436,7 +1450,7 @@ static int igt_ppgtt_pin_update(void *arg)
         * huge-gtt-pages.
         */
 
-       if (!USES_FULL_48BIT_PPGTT(dev_priv)) {
+       if (!HAS_FULL_48BIT_PPGTT(dev_priv)) {
                pr_info("48b PPGTT not supported, skipping\n");
                return 0;
        }
@@ -1687,10 +1701,9 @@ int i915_gem_huge_page_mock_selftests(void)
                SUBTEST(igt_mock_ppgtt_huge_fill),
                SUBTEST(igt_mock_ppgtt_64K),
        };
-       int saved_ppgtt = i915_modparams.enable_ppgtt;
        struct drm_i915_private *dev_priv;
-       struct pci_dev *pdev;
        struct i915_hw_ppgtt *ppgtt;
+       struct pci_dev *pdev;
        int err;
 
        dev_priv = mock_gem_device();
@@ -1698,7 +1711,7 @@ int i915_gem_huge_page_mock_selftests(void)
                return -ENOMEM;
 
        /* Pretend to be a device which supports the 48b PPGTT */
-       i915_modparams.enable_ppgtt = 3;
+       mkwrite_device_info(dev_priv)->ppgtt = INTEL_PPGTT_FULL_4LVL;
 
        pdev = dev_priv->drm.pdev;
        dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39));
@@ -1731,9 +1744,6 @@ out_close:
 
 out_unlock:
        mutex_unlock(&dev_priv->drm.struct_mutex);
-
-       i915_modparams.enable_ppgtt = saved_ppgtt;
-
        drm_dev_put(&dev_priv->drm);
 
        return err;
@@ -1753,7 +1763,7 @@ int i915_gem_huge_page_live_selftests(struct drm_i915_private *dev_priv)
        struct i915_gem_context *ctx;
        int err;
 
-       if (!USES_PPGTT(dev_priv)) {
+       if (!HAS_PPGTT(dev_priv)) {
                pr_info("PPGTT not supported, skipping live-selftests\n");
                return 0;
        }
index 76df25aa90c92b9da8f8a91ec785a54d82b13a8c..7d82043aff1099c82a35fde7fe0bce2f4b454bcb 100644 (file)
@@ -39,7 +39,8 @@ struct live_test {
        const char *func;
        const char *name;
 
-       unsigned int reset_count;
+       unsigned int reset_global;
+       unsigned int reset_engine[I915_NUM_ENGINES];
 };
 
 static int begin_live_test(struct live_test *t,
@@ -47,6 +48,8 @@ static int begin_live_test(struct live_test *t,
                           const char *func,
                           const char *name)
 {
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        int err;
 
        t->i915 = i915;
@@ -63,7 +66,11 @@ static int begin_live_test(struct live_test *t,
        }
 
        i915->gpu_error.missed_irq_rings = 0;
-       t->reset_count = i915_reset_count(&i915->gpu_error);
+       t->reset_global = i915_reset_count(&i915->gpu_error);
+
+       for_each_engine(engine, i915, id)
+               t->reset_engine[id] =
+                       i915_reset_engine_count(&i915->gpu_error, engine);
 
        return 0;
 }
@@ -71,14 +78,28 @@ static int begin_live_test(struct live_test *t,
 static int end_live_test(struct live_test *t)
 {
        struct drm_i915_private *i915 = t->i915;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
 
        if (igt_flush_test(i915, I915_WAIT_LOCKED))
                return -EIO;
 
-       if (t->reset_count != i915_reset_count(&i915->gpu_error)) {
+       if (t->reset_global != i915_reset_count(&i915->gpu_error)) {
                pr_err("%s(%s): GPU was reset %d times!\n",
                       t->func, t->name,
-                      i915_reset_count(&i915->gpu_error) - t->reset_count);
+                      i915_reset_count(&i915->gpu_error) - t->reset_global);
+               return -EIO;
+       }
+
+       for_each_engine(engine, i915, id) {
+               if (t->reset_engine[id] ==
+                   i915_reset_engine_count(&i915->gpu_error, engine))
+                       continue;
+
+               pr_err("%s(%s): engine '%s' was reset %d times!\n",
+                      t->func, t->name, engine->name,
+                      i915_reset_engine_count(&i915->gpu_error, engine) -
+                      t->reset_engine[id]);
                return -EIO;
        }
 
@@ -531,11 +552,11 @@ static int igt_ctx_exec(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct drm_i915_gem_object *obj = NULL;
+       unsigned long ncontexts, ndwords, dw;
        struct drm_file *file;
        IGT_TIMEOUT(end_time);
        LIST_HEAD(objects);
-       unsigned long ncontexts, ndwords, dw;
-       bool first_shared_gtt = true;
+       struct live_test t;
        int err = -ENODEV;
 
        /*
@@ -553,6 +574,10 @@ static int igt_ctx_exec(void *arg)
 
        mutex_lock(&i915->drm.struct_mutex);
 
+       err = begin_live_test(&t, i915, __func__, "");
+       if (err)
+               goto out_unlock;
+
        ncontexts = 0;
        ndwords = 0;
        dw = 0;
@@ -561,12 +586,7 @@ static int igt_ctx_exec(void *arg)
                struct i915_gem_context *ctx;
                unsigned int id;
 
-               if (first_shared_gtt) {
-                       ctx = __create_hw_context(i915, file->driver_priv);
-                       first_shared_gtt = false;
-               } else {
-                       ctx = i915_gem_create_context(i915, file->driver_priv);
-               }
+               ctx = i915_gem_create_context(i915, file->driver_priv);
                if (IS_ERR(ctx)) {
                        err = PTR_ERR(ctx);
                        goto out_unlock;
@@ -622,7 +642,7 @@ static int igt_ctx_exec(void *arg)
        }
 
 out_unlock:
-       if (igt_flush_test(i915, I915_WAIT_LOCKED))
+       if (end_live_test(&t))
                err = -EIO;
        mutex_unlock(&i915->drm.struct_mutex);
 
@@ -634,13 +654,14 @@ static int igt_ctx_readonly(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct drm_i915_gem_object *obj = NULL;
+       struct i915_gem_context *ctx;
+       struct i915_hw_ppgtt *ppgtt;
+       unsigned long ndwords, dw;
        struct drm_file *file;
        I915_RND_STATE(prng);
        IGT_TIMEOUT(end_time);
        LIST_HEAD(objects);
-       struct i915_gem_context *ctx;
-       struct i915_hw_ppgtt *ppgtt;
-       unsigned long ndwords, dw;
+       struct live_test t;
        int err = -ENODEV;
 
        /*
@@ -655,6 +676,10 @@ static int igt_ctx_readonly(void *arg)
 
        mutex_lock(&i915->drm.struct_mutex);
 
+       err = begin_live_test(&t, i915, __func__, "");
+       if (err)
+               goto out_unlock;
+
        ctx = i915_gem_create_context(i915, file->driver_priv);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
@@ -727,7 +752,324 @@ static int igt_ctx_readonly(void *arg)
        }
 
 out_unlock:
-       if (igt_flush_test(i915, I915_WAIT_LOCKED))
+       if (end_live_test(&t))
+               err = -EIO;
+       mutex_unlock(&i915->drm.struct_mutex);
+
+       mock_file_free(i915, file);
+       return err;
+}
+
+static int check_scratch(struct i915_gem_context *ctx, u64 offset)
+{
+       struct drm_mm_node *node =
+               __drm_mm_interval_first(&ctx->ppgtt->vm.mm,
+                                       offset, offset + sizeof(u32) - 1);
+       if (!node || node->start > offset)
+               return 0;
+
+       GEM_BUG_ON(offset >= node->start + node->size);
+
+       pr_err("Target offset 0x%08x_%08x overlaps with a node in the mm!\n",
+              upper_32_bits(offset), lower_32_bits(offset));
+       return -EINVAL;
+}
+
+static int write_to_scratch(struct i915_gem_context *ctx,
+                           struct intel_engine_cs *engine,
+                           u64 offset, u32 value)
+{
+       struct drm_i915_private *i915 = ctx->i915;
+       struct drm_i915_gem_object *obj;
+       struct i915_request *rq;
+       struct i915_vma *vma;
+       u32 *cmd;
+       int err;
+
+       GEM_BUG_ON(offset < I915_GTT_PAGE_SIZE);
+
+       obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
+
+       cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
+       if (IS_ERR(cmd)) {
+               err = PTR_ERR(cmd);
+               goto err;
+       }
+
+       *cmd++ = MI_STORE_DWORD_IMM_GEN4;
+       if (INTEL_GEN(i915) >= 8) {
+               *cmd++ = lower_32_bits(offset);
+               *cmd++ = upper_32_bits(offset);
+       } else {
+               *cmd++ = 0;
+               *cmd++ = offset;
+       }
+       *cmd++ = value;
+       *cmd = MI_BATCH_BUFFER_END;
+       i915_gem_object_unpin_map(obj);
+
+       err = i915_gem_object_set_to_gtt_domain(obj, false);
+       if (err)
+               goto err;
+
+       vma = i915_vma_instance(obj, &ctx->ppgtt->vm, NULL);
+       if (IS_ERR(vma)) {
+               err = PTR_ERR(vma);
+               goto err;
+       }
+
+       err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_OFFSET_FIXED);
+       if (err)
+               goto err;
+
+       err = check_scratch(ctx, offset);
+       if (err)
+               goto err_unpin;
+
+       rq = i915_request_alloc(engine, ctx);
+       if (IS_ERR(rq)) {
+               err = PTR_ERR(rq);
+               goto err_unpin;
+       }
+
+       err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, 0);
+       if (err)
+               goto err_request;
+
+       err = i915_vma_move_to_active(vma, rq, 0);
+       if (err)
+               goto skip_request;
+
+       i915_gem_object_set_active_reference(obj);
+       i915_vma_unpin(vma);
+       i915_vma_close(vma);
+
+       i915_request_add(rq);
+
+       return 0;
+
+skip_request:
+       i915_request_skip(rq, err);
+err_request:
+       i915_request_add(rq);
+err_unpin:
+       i915_vma_unpin(vma);
+err:
+       i915_gem_object_put(obj);
+       return err;
+}
+
+static int read_from_scratch(struct i915_gem_context *ctx,
+                            struct intel_engine_cs *engine,
+                            u64 offset, u32 *value)
+{
+       struct drm_i915_private *i915 = ctx->i915;
+       struct drm_i915_gem_object *obj;
+       const u32 RCS_GPR0 = 0x2600; /* not all engines have their own GPR! */
+       const u32 result = 0x100;
+       struct i915_request *rq;
+       struct i915_vma *vma;
+       u32 *cmd;
+       int err;
+
+       GEM_BUG_ON(offset < I915_GTT_PAGE_SIZE);
+
+       obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
+
+       cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
+       if (IS_ERR(cmd)) {
+               err = PTR_ERR(cmd);
+               goto err;
+       }
+
+       memset(cmd, POISON_INUSE, PAGE_SIZE);
+       if (INTEL_GEN(i915) >= 8) {
+               *cmd++ = MI_LOAD_REGISTER_MEM_GEN8;
+               *cmd++ = RCS_GPR0;
+               *cmd++ = lower_32_bits(offset);
+               *cmd++ = upper_32_bits(offset);
+               *cmd++ = MI_STORE_REGISTER_MEM_GEN8;
+               *cmd++ = RCS_GPR0;
+               *cmd++ = result;
+               *cmd++ = 0;
+       } else {
+               *cmd++ = MI_LOAD_REGISTER_MEM;
+               *cmd++ = RCS_GPR0;
+               *cmd++ = offset;
+               *cmd++ = MI_STORE_REGISTER_MEM;
+               *cmd++ = RCS_GPR0;
+               *cmd++ = result;
+       }
+       *cmd = MI_BATCH_BUFFER_END;
+       i915_gem_object_unpin_map(obj);
+
+       err = i915_gem_object_set_to_gtt_domain(obj, false);
+       if (err)
+               goto err;
+
+       vma = i915_vma_instance(obj, &ctx->ppgtt->vm, NULL);
+       if (IS_ERR(vma)) {
+               err = PTR_ERR(vma);
+               goto err;
+       }
+
+       err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_OFFSET_FIXED);
+       if (err)
+               goto err;
+
+       err = check_scratch(ctx, offset);
+       if (err)
+               goto err_unpin;
+
+       rq = i915_request_alloc(engine, ctx);
+       if (IS_ERR(rq)) {
+               err = PTR_ERR(rq);
+               goto err_unpin;
+       }
+
+       err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, 0);
+       if (err)
+               goto err_request;
+
+       err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+       if (err)
+               goto skip_request;
+
+       i915_vma_unpin(vma);
+       i915_vma_close(vma);
+
+       i915_request_add(rq);
+
+       err = i915_gem_object_set_to_cpu_domain(obj, false);
+       if (err)
+               goto err;
+
+       cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
+       if (IS_ERR(cmd)) {
+               err = PTR_ERR(cmd);
+               goto err;
+       }
+
+       *value = cmd[result / sizeof(*cmd)];
+       i915_gem_object_unpin_map(obj);
+       i915_gem_object_put(obj);
+
+       return 0;
+
+skip_request:
+       i915_request_skip(rq, err);
+err_request:
+       i915_request_add(rq);
+err_unpin:
+       i915_vma_unpin(vma);
+err:
+       i915_gem_object_put(obj);
+       return err;
+}
+
+static int igt_vm_isolation(void *arg)
+{
+       struct drm_i915_private *i915 = arg;
+       struct i915_gem_context *ctx_a, *ctx_b;
+       struct intel_engine_cs *engine;
+       struct drm_file *file;
+       I915_RND_STATE(prng);
+       unsigned long count;
+       struct live_test t;
+       unsigned int id;
+       u64 vm_total;
+       int err;
+
+       if (INTEL_GEN(i915) < 7)
+               return 0;
+
+       /*
+        * The simple goal here is that a write into one context is not
+        * observed in a second (separate page tables and scratch).
+        */
+
+       file = mock_file(i915);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       mutex_lock(&i915->drm.struct_mutex);
+
+       err = begin_live_test(&t, i915, __func__, "");
+       if (err)
+               goto out_unlock;
+
+       ctx_a = i915_gem_create_context(i915, file->driver_priv);
+       if (IS_ERR(ctx_a)) {
+               err = PTR_ERR(ctx_a);
+               goto out_unlock;
+       }
+
+       ctx_b = i915_gem_create_context(i915, file->driver_priv);
+       if (IS_ERR(ctx_b)) {
+               err = PTR_ERR(ctx_b);
+               goto out_unlock;
+       }
+
+       /* We can only test vm isolation, if the vm are distinct */
+       if (ctx_a->ppgtt == ctx_b->ppgtt)
+               goto out_unlock;
+
+       vm_total = ctx_a->ppgtt->vm.total;
+       GEM_BUG_ON(ctx_b->ppgtt->vm.total != vm_total);
+       vm_total -= I915_GTT_PAGE_SIZE;
+
+       intel_runtime_pm_get(i915);
+
+       count = 0;
+       for_each_engine(engine, i915, id) {
+               IGT_TIMEOUT(end_time);
+               unsigned long this = 0;
+
+               if (!intel_engine_can_store_dword(engine))
+                       continue;
+
+               while (!__igt_timeout(end_time, NULL)) {
+                       u32 value = 0xc5c5c5c5;
+                       u64 offset;
+
+                       div64_u64_rem(i915_prandom_u64_state(&prng),
+                                     vm_total, &offset);
+                       offset &= ~sizeof(u32);
+                       offset += I915_GTT_PAGE_SIZE;
+
+                       err = write_to_scratch(ctx_a, engine,
+                                              offset, 0xdeadbeef);
+                       if (err == 0)
+                               err = read_from_scratch(ctx_b, engine,
+                                                       offset, &value);
+                       if (err)
+                               goto out_rpm;
+
+                       if (value) {
+                               pr_err("%s: Read %08x from scratch (offset 0x%08x_%08x), after %lu reads!\n",
+                                      engine->name, value,
+                                      upper_32_bits(offset),
+                                      lower_32_bits(offset),
+                                      this);
+                               err = -EINVAL;
+                               goto out_rpm;
+                       }
+
+                       this++;
+               }
+               count += this;
+       }
+       pr_info("Checked %lu scratch offsets across %d engines\n",
+               count, INTEL_INFO(i915)->num_rings);
+
+out_rpm:
+       intel_runtime_pm_put(i915);
+out_unlock:
+       if (end_live_test(&t))
                err = -EIO;
        mutex_unlock(&i915->drm.struct_mutex);
 
@@ -865,33 +1207,6 @@ out_unlock:
        return err;
 }
 
-static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915)
-{
-       struct drm_i915_gem_object *obj;
-       int err;
-
-       err = i915_gem_init_aliasing_ppgtt(i915);
-       if (err)
-               return err;
-
-       list_for_each_entry(obj, &i915->mm.bound_list, mm.link) {
-               struct i915_vma *vma;
-
-               vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL);
-               if (IS_ERR(vma))
-                       continue;
-
-               vma->flags &= ~I915_VMA_LOCAL_BIND;
-       }
-
-       return 0;
-}
-
-static void fake_aliasing_ppgtt_disable(struct drm_i915_private *i915)
-{
-       i915_gem_fini_aliasing_ppgtt(i915);
-}
-
 int i915_gem_context_mock_selftests(void)
 {
        static const struct i915_subtest tests[] = {
@@ -917,32 +1232,11 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv)
                SUBTEST(live_nop_switch),
                SUBTEST(igt_ctx_exec),
                SUBTEST(igt_ctx_readonly),
+               SUBTEST(igt_vm_isolation),
        };
-       bool fake_alias = false;
-       int err;
 
        if (i915_terminally_wedged(&dev_priv->gpu_error))
                return 0;
 
-       /* Install a fake aliasing gtt for exercise */
-       if (USES_PPGTT(dev_priv) && !dev_priv->mm.aliasing_ppgtt) {
-               mutex_lock(&dev_priv->drm.struct_mutex);
-               err = fake_aliasing_ppgtt_enable(dev_priv);
-               mutex_unlock(&dev_priv->drm.struct_mutex);
-               if (err)
-                       return err;
-
-               GEM_BUG_ON(!dev_priv->mm.aliasing_ppgtt);
-               fake_alias = true;
-       }
-
-       err = i915_subtests(tests, dev_priv);
-
-       if (fake_alias) {
-               mutex_lock(&dev_priv->drm.struct_mutex);
-               fake_aliasing_ppgtt_disable(dev_priv);
-               mutex_unlock(&dev_priv->drm.struct_mutex);
-       }
-
-       return err;
+       return i915_subtests(tests, dev_priv);
 }
index 128ad1cf0647a0986d83625669062382fb55a7b0..4365979d82228fa83c275f8a0f43b0ca6d11df60 100644 (file)
@@ -351,7 +351,7 @@ static int igt_evict_contexts(void *arg)
         * where the GTT space of the request is separate from the GGTT
         * allocation required to build the request.
         */
-       if (!USES_FULL_PPGTT(i915))
+       if (!HAS_FULL_PPGTT(i915))
                return 0;
 
        mutex_lock(&i915->drm.struct_mutex);
index 127d8151367177dea04bf5c121b2331e46d1accc..69fe86b30fbb79aaea1c8d8ece1edffe03c9d684 100644 (file)
@@ -153,7 +153,7 @@ static int igt_ppgtt_alloc(void *arg)
 
        /* Allocate a ppggt and try to fill the entire range */
 
-       if (!USES_PPGTT(dev_priv))
+       if (!HAS_PPGTT(dev_priv))
                return 0;
 
        ppgtt = __hw_ppgtt_create(dev_priv);
@@ -1001,7 +1001,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv,
        IGT_TIMEOUT(end_time);
        int err;
 
-       if (!USES_FULL_PPGTT(dev_priv))
+       if (!HAS_FULL_PPGTT(dev_priv))
                return 0;
 
        file = mock_file(dev_priv);
diff --git a/drivers/gpu/drm/i915/selftests/igt_reset.c b/drivers/gpu/drm/i915/selftests/igt_reset.c
new file mode 100644 (file)
index 0000000..208a966
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include "igt_reset.h"
+
+#include "../i915_drv.h"
+#include "../intel_ringbuffer.h"
+
+void igt_global_reset_lock(struct drm_i915_private *i915)
+{
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+
+       pr_debug("%s: current gpu_error=%08lx\n",
+                __func__, i915->gpu_error.flags);
+
+       while (test_and_set_bit(I915_RESET_BACKOFF, &i915->gpu_error.flags))
+               wait_event(i915->gpu_error.reset_queue,
+                          !test_bit(I915_RESET_BACKOFF,
+                                    &i915->gpu_error.flags));
+
+       for_each_engine(engine, i915, id) {
+               while (test_and_set_bit(I915_RESET_ENGINE + id,
+                                       &i915->gpu_error.flags))
+                       wait_on_bit(&i915->gpu_error.flags,
+                                   I915_RESET_ENGINE + id,
+                                   TASK_UNINTERRUPTIBLE);
+       }
+}
+
+void igt_global_reset_unlock(struct drm_i915_private *i915)
+{
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+
+       for_each_engine(engine, i915, id)
+               clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags);
+
+       clear_bit(I915_RESET_BACKOFF, &i915->gpu_error.flags);
+       wake_up_all(&i915->gpu_error.reset_queue);
+}
diff --git a/drivers/gpu/drm/i915/selftests/igt_reset.h b/drivers/gpu/drm/i915/selftests/igt_reset.h
new file mode 100644 (file)
index 0000000..5f0234d
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#ifndef __I915_SELFTESTS_IGT_RESET_H__
+#define __I915_SELFTESTS_IGT_RESET_H__
+
+#include "../i915_drv.h"
+
+void igt_global_reset_lock(struct drm_i915_private *i915);
+void igt_global_reset_unlock(struct drm_i915_private *i915);
+
+#endif
diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c
new file mode 100644 (file)
index 0000000..8cd34f6
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include "igt_spinner.h"
+
+int igt_spinner_init(struct igt_spinner *spin, struct drm_i915_private *i915)
+{
+       unsigned int mode;
+       void *vaddr;
+       int err;
+
+       GEM_BUG_ON(INTEL_GEN(i915) < 8);
+
+       memset(spin, 0, sizeof(*spin));
+       spin->i915 = i915;
+
+       spin->hws = i915_gem_object_create_internal(i915, PAGE_SIZE);
+       if (IS_ERR(spin->hws)) {
+               err = PTR_ERR(spin->hws);
+               goto err;
+       }
+
+       spin->obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+       if (IS_ERR(spin->obj)) {
+               err = PTR_ERR(spin->obj);
+               goto err_hws;
+       }
+
+       i915_gem_object_set_cache_level(spin->hws, I915_CACHE_LLC);
+       vaddr = i915_gem_object_pin_map(spin->hws, I915_MAP_WB);
+       if (IS_ERR(vaddr)) {
+               err = PTR_ERR(vaddr);
+               goto err_obj;
+       }
+       spin->seqno = memset(vaddr, 0xff, PAGE_SIZE);
+
+       mode = i915_coherent_map_type(i915);
+       vaddr = i915_gem_object_pin_map(spin->obj, mode);
+       if (IS_ERR(vaddr)) {
+               err = PTR_ERR(vaddr);
+               goto err_unpin_hws;
+       }
+       spin->batch = vaddr;
+
+       return 0;
+
+err_unpin_hws:
+       i915_gem_object_unpin_map(spin->hws);
+err_obj:
+       i915_gem_object_put(spin->obj);
+err_hws:
+       i915_gem_object_put(spin->hws);
+err:
+       return err;
+}
+
+static unsigned int seqno_offset(u64 fence)
+{
+       return offset_in_page(sizeof(u32) * fence);
+}
+
+static u64 hws_address(const struct i915_vma *hws,
+                      const struct i915_request *rq)
+{
+       return hws->node.start + seqno_offset(rq->fence.context);
+}
+
+static int emit_recurse_batch(struct igt_spinner *spin,
+                             struct i915_request *rq,
+                             u32 arbitration_command)
+{
+       struct i915_address_space *vm = &rq->gem_context->ppgtt->vm;
+       struct i915_vma *hws, *vma;
+       u32 *batch;
+       int err;
+
+       vma = i915_vma_instance(spin->obj, vm, NULL);
+       if (IS_ERR(vma))
+               return PTR_ERR(vma);
+
+       hws = i915_vma_instance(spin->hws, vm, NULL);
+       if (IS_ERR(hws))
+               return PTR_ERR(hws);
+
+       err = i915_vma_pin(vma, 0, 0, PIN_USER);
+       if (err)
+               return err;
+
+       err = i915_vma_pin(hws, 0, 0, PIN_USER);
+       if (err)
+               goto unpin_vma;
+
+       err = i915_vma_move_to_active(vma, rq, 0);
+       if (err)
+               goto unpin_hws;
+
+       if (!i915_gem_object_has_active_reference(vma->obj)) {
+               i915_gem_object_get(vma->obj);
+               i915_gem_object_set_active_reference(vma->obj);
+       }
+
+       err = i915_vma_move_to_active(hws, rq, 0);
+       if (err)
+               goto unpin_hws;
+
+       if (!i915_gem_object_has_active_reference(hws->obj)) {
+               i915_gem_object_get(hws->obj);
+               i915_gem_object_set_active_reference(hws->obj);
+       }
+
+       batch = spin->batch;
+
+       *batch++ = MI_STORE_DWORD_IMM_GEN4;
+       *batch++ = lower_32_bits(hws_address(hws, rq));
+       *batch++ = upper_32_bits(hws_address(hws, rq));
+       *batch++ = rq->fence.seqno;
+
+       *batch++ = arbitration_command;
+
+       *batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+       *batch++ = lower_32_bits(vma->node.start);
+       *batch++ = upper_32_bits(vma->node.start);
+       *batch++ = MI_BATCH_BUFFER_END; /* not reached */
+
+       i915_gem_chipset_flush(spin->i915);
+
+       err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0);
+
+unpin_hws:
+       i915_vma_unpin(hws);
+unpin_vma:
+       i915_vma_unpin(vma);
+       return err;
+}
+
+struct i915_request *
+igt_spinner_create_request(struct igt_spinner *spin,
+                          struct i915_gem_context *ctx,
+                          struct intel_engine_cs *engine,
+                          u32 arbitration_command)
+{
+       struct i915_request *rq;
+       int err;
+
+       rq = i915_request_alloc(engine, ctx);
+       if (IS_ERR(rq))
+               return rq;
+
+       err = emit_recurse_batch(spin, rq, arbitration_command);
+       if (err) {
+               i915_request_add(rq);
+               return ERR_PTR(err);
+       }
+
+       return rq;
+}
+
+static u32
+hws_seqno(const struct igt_spinner *spin, const struct i915_request *rq)
+{
+       u32 *seqno = spin->seqno + seqno_offset(rq->fence.context);
+
+       return READ_ONCE(*seqno);
+}
+
+void igt_spinner_end(struct igt_spinner *spin)
+{
+       *spin->batch = MI_BATCH_BUFFER_END;
+       i915_gem_chipset_flush(spin->i915);
+}
+
+void igt_spinner_fini(struct igt_spinner *spin)
+{
+       igt_spinner_end(spin);
+
+       i915_gem_object_unpin_map(spin->obj);
+       i915_gem_object_put(spin->obj);
+
+       i915_gem_object_unpin_map(spin->hws);
+       i915_gem_object_put(spin->hws);
+}
+
+bool igt_wait_for_spinner(struct igt_spinner *spin, struct i915_request *rq)
+{
+       if (!wait_event_timeout(rq->execute,
+                               READ_ONCE(rq->global_seqno),
+                               msecs_to_jiffies(10)))
+               return false;
+
+       return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq),
+                                              rq->fence.seqno),
+                            10) &&
+                wait_for(i915_seqno_passed(hws_seqno(spin, rq),
+                                           rq->fence.seqno),
+                         1000));
+}
diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.h b/drivers/gpu/drm/i915/selftests/igt_spinner.h
new file mode 100644 (file)
index 0000000..391777c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#ifndef __I915_SELFTESTS_IGT_SPINNER_H__
+#define __I915_SELFTESTS_IGT_SPINNER_H__
+
+#include "../i915_selftest.h"
+
+#include "../i915_drv.h"
+#include "../i915_request.h"
+#include "../intel_ringbuffer.h"
+#include "../i915_gem_context.h"
+
+struct igt_spinner {
+       struct drm_i915_private *i915;
+       struct drm_i915_gem_object *hws;
+       struct drm_i915_gem_object *obj;
+       u32 *batch;
+       void *seqno;
+};
+
+int igt_spinner_init(struct igt_spinner *spin, struct drm_i915_private *i915);
+void igt_spinner_fini(struct igt_spinner *spin);
+
+struct i915_request *
+igt_spinner_create_request(struct igt_spinner *spin,
+                          struct i915_gem_context *ctx,
+                          struct intel_engine_cs *engine,
+                          u32 arbitration_command);
+void igt_spinner_end(struct igt_spinner *spin);
+
+bool igt_wait_for_spinner(struct igt_spinner *spin, struct i915_request *rq);
+
+#endif
index 0c0ab82b6228f84090d50806406350b820fa3ef9..32cba4cae31afad754a8e66df51bd01bdaff19cf 100644 (file)
@@ -159,6 +159,7 @@ static int igt_guc_clients(void *args)
         * Get rid of clients created during driver load because the test will
         * recreate them.
         */
+       guc_clients_disable(guc);
        guc_clients_destroy(guc);
        if (guc->execbuf_client || guc->preempt_client) {
                pr_err("guc_clients_destroy lied!\n");
@@ -197,8 +198,8 @@ static int igt_guc_clients(void *args)
                goto out;
        }
 
-       /* Now create the doorbells */
-       guc_clients_doorbell_init(guc);
+       /* Now enable the clients */
+       guc_clients_enable(guc);
 
        /* each client should now have received a doorbell */
        if (!client_doorbell_in_sync(guc->execbuf_client) ||
@@ -212,63 +213,17 @@ static int igt_guc_clients(void *args)
         * Basic test - an attempt to reallocate a valid doorbell to the
         * client it is currently assigned should not cause a failure.
         */
-       err = guc_clients_doorbell_init(guc);
-       if (err)
-               goto out;
-
-       /*
-        * Negative test - a client with no doorbell (invalid db id).
-        * After destroying the doorbell, the db id is changed to
-        * GUC_DOORBELL_INVALID and the firmware will reject any attempt to
-        * allocate a doorbell with an invalid id (db has to be reserved before
-        * allocation).
-        */
-       destroy_doorbell(guc->execbuf_client);
-       if (client_doorbell_in_sync(guc->execbuf_client)) {
-               pr_err("destroy db did not work\n");
-               err = -EINVAL;
-               goto out;
-       }
-
-       unreserve_doorbell(guc->execbuf_client);
-
-       __create_doorbell(guc->execbuf_client);
-       err = __guc_allocate_doorbell(guc, guc->execbuf_client->stage_id);
-       if (err != -EIO) {
-               pr_err("unexpected (err = %d)", err);
-               goto out_db;
-       }
-
-       if (!available_dbs(guc, guc->execbuf_client->priority)) {
-               pr_err("doorbell not available when it should\n");
-               err = -EIO;
-               goto out_db;
-       }
-
-out_db:
-       /* clean after test */
-       __destroy_doorbell(guc->execbuf_client);
-       err = reserve_doorbell(guc->execbuf_client);
-       if (err) {
-               pr_err("failed to reserve back the doorbell back\n");
-       }
        err = create_doorbell(guc->execbuf_client);
-       if (err) {
-               pr_err("recreate doorbell failed\n");
-               goto out;
-       }
 
 out:
        /*
         * Leave clean state for other test, plus the driver always destroy the
         * clients during unload.
         */
-       destroy_doorbell(guc->execbuf_client);
-       if (guc->preempt_client)
-               destroy_doorbell(guc->preempt_client);
+       guc_clients_disable(guc);
        guc_clients_destroy(guc);
        guc_clients_create(guc);
-       guc_clients_doorbell_init(guc);
+       guc_clients_enable(guc);
 unlock:
        intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
@@ -352,7 +307,7 @@ static int igt_guc_doorbells(void *arg)
 
                db_id = clients[i]->doorbell_id;
 
-               err = create_doorbell(clients[i]);
+               err = __guc_client_enable(clients[i]);
                if (err) {
                        pr_err("[%d] Failed to create a doorbell\n", i);
                        goto out;
@@ -378,7 +333,7 @@ static int igt_guc_doorbells(void *arg)
 out:
        for (i = 0; i < ATTEMPTS; i++)
                if (!IS_ERR_OR_NULL(clients[i])) {
-                       destroy_doorbell(clients[i]);
+                       __guc_client_disable(clients[i]);
                        guc_client_free(clients[i]);
                }
 unlock:
index db378226ac105e4df702bccfd795097cdd695180..40efbed611de8d80e8734e223d91fd5604e1d4f3 100644 (file)
@@ -27,6 +27,7 @@
 #include "../i915_selftest.h"
 #include "i915_random.h"
 #include "igt_flush_test.h"
+#include "igt_reset.h"
 #include "igt_wedge_me.h"
 
 #include "mock_context.h"
@@ -76,7 +77,7 @@ static int hang_init(struct hang *h, struct drm_i915_private *i915)
        h->seqno = memset(vaddr, 0xff, PAGE_SIZE);
 
        vaddr = i915_gem_object_pin_map(h->obj,
-                                       HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC);
+                                       i915_coherent_map_type(i915));
        if (IS_ERR(vaddr)) {
                err = PTR_ERR(vaddr);
                goto err_unpin_hws;
@@ -234,7 +235,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
                        return ERR_CAST(obj);
 
                vaddr = i915_gem_object_pin_map(obj,
-                                               HAS_LLC(h->i915) ? I915_MAP_WB : I915_MAP_WC);
+                                               i915_coherent_map_type(h->i915));
                if (IS_ERR(vaddr)) {
                        i915_gem_object_put(obj);
                        return ERR_CAST(vaddr);
@@ -308,6 +309,7 @@ static int igt_hang_sanitycheck(void *arg)
                goto unlock;
 
        for_each_engine(engine, i915, id) {
+               struct igt_wedge_me w;
                long timeout;
 
                if (!intel_engine_can_store_dword(engine))
@@ -328,9 +330,14 @@ static int igt_hang_sanitycheck(void *arg)
 
                i915_request_add(rq);
 
-               timeout = i915_request_wait(rq,
-                                           I915_WAIT_LOCKED,
-                                           MAX_SCHEDULE_TIMEOUT);
+               timeout = 0;
+               igt_wedge_on_timeout(&w, i915, HZ / 10 /* 100ms timeout*/)
+                       timeout = i915_request_wait(rq,
+                                                   I915_WAIT_LOCKED,
+                                                   MAX_SCHEDULE_TIMEOUT);
+               if (i915_terminally_wedged(&i915->gpu_error))
+                       timeout = -EIO;
+
                i915_request_put(rq);
 
                if (timeout < 0) {
@@ -348,40 +355,6 @@ unlock:
        return err;
 }
 
-static void global_reset_lock(struct drm_i915_private *i915)
-{
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-
-       pr_debug("%s: current gpu_error=%08lx\n",
-                __func__, i915->gpu_error.flags);
-
-       while (test_and_set_bit(I915_RESET_BACKOFF, &i915->gpu_error.flags))
-               wait_event(i915->gpu_error.reset_queue,
-                          !test_bit(I915_RESET_BACKOFF,
-                                    &i915->gpu_error.flags));
-
-       for_each_engine(engine, i915, id) {
-               while (test_and_set_bit(I915_RESET_ENGINE + id,
-                                       &i915->gpu_error.flags))
-                       wait_on_bit(&i915->gpu_error.flags,
-                                   I915_RESET_ENGINE + id,
-                                   TASK_UNINTERRUPTIBLE);
-       }
-}
-
-static void global_reset_unlock(struct drm_i915_private *i915)
-{
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-
-       for_each_engine(engine, i915, id)
-               clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags);
-
-       clear_bit(I915_RESET_BACKOFF, &i915->gpu_error.flags);
-       wake_up_all(&i915->gpu_error.reset_queue);
-}
-
 static int igt_global_reset(void *arg)
 {
        struct drm_i915_private *i915 = arg;
@@ -390,7 +363,7 @@ static int igt_global_reset(void *arg)
 
        /* Check that we can issue a global GPU reset */
 
-       global_reset_lock(i915);
+       igt_global_reset_lock(i915);
        set_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags);
 
        mutex_lock(&i915->drm.struct_mutex);
@@ -405,7 +378,7 @@ static int igt_global_reset(void *arg)
        mutex_unlock(&i915->drm.struct_mutex);
 
        GEM_BUG_ON(test_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags));
-       global_reset_unlock(i915);
+       igt_global_reset_unlock(i915);
 
        if (i915_terminally_wedged(&i915->gpu_error))
                err = -EIO;
@@ -936,7 +909,7 @@ static int igt_reset_wait(void *arg)
 
        /* Check that we detect a stuck waiter and issue a reset */
 
-       global_reset_lock(i915);
+       igt_global_reset_lock(i915);
 
        mutex_lock(&i915->drm.struct_mutex);
        err = hang_init(&h, i915);
@@ -988,7 +961,7 @@ fini:
        hang_fini(&h);
 unlock:
        mutex_unlock(&i915->drm.struct_mutex);
-       global_reset_unlock(i915);
+       igt_global_reset_unlock(i915);
 
        if (i915_terminally_wedged(&i915->gpu_error))
                return -EIO;
@@ -1066,7 +1039,7 @@ static int __igt_reset_evict_vma(struct drm_i915_private *i915,
 
        /* Check that we can recover an unbind stuck on a hanging request */
 
-       global_reset_lock(i915);
+       igt_global_reset_lock(i915);
 
        mutex_lock(&i915->drm.struct_mutex);
        err = hang_init(&h, i915);
@@ -1150,6 +1123,7 @@ static int __igt_reset_evict_vma(struct drm_i915_private *i915,
                tsk = NULL;
                goto out_reset;
        }
+       get_task_struct(tsk);
 
        wait_for_completion(&arg.completion);
 
@@ -1172,6 +1146,8 @@ out_reset:
                /* The reset, even indirectly, should take less than 10ms. */
                igt_wedge_on_timeout(&w, i915, HZ / 10 /* 100ms timeout*/)
                        err = kthread_stop(tsk);
+
+               put_task_struct(tsk);
        }
 
        mutex_lock(&i915->drm.struct_mutex);
@@ -1183,7 +1159,7 @@ fini:
        hang_fini(&h);
 unlock:
        mutex_unlock(&i915->drm.struct_mutex);
-       global_reset_unlock(i915);
+       igt_global_reset_unlock(i915);
 
        if (i915_terminally_wedged(&i915->gpu_error))
                return -EIO;
@@ -1263,7 +1239,7 @@ static int igt_reset_queue(void *arg)
 
        /* Check that we replay pending requests following a hang */
 
-       global_reset_lock(i915);
+       igt_global_reset_lock(i915);
 
        mutex_lock(&i915->drm.struct_mutex);
        err = hang_init(&h, i915);
@@ -1394,7 +1370,7 @@ fini:
        hang_fini(&h);
 unlock:
        mutex_unlock(&i915->drm.struct_mutex);
-       global_reset_unlock(i915);
+       igt_global_reset_unlock(i915);
 
        if (i915_terminally_wedged(&i915->gpu_error))
                return -EIO;
index 1aea7a8f2224a325652448966e59f0974c9a0e10..ca461e3a5f27ffe8bd85b9f0dc4e17078ff5468d 100644 (file)
 
 #include "../i915_selftest.h"
 #include "igt_flush_test.h"
+#include "igt_spinner.h"
+#include "i915_random.h"
 
 #include "mock_context.h"
 
-struct spinner {
-       struct drm_i915_private *i915;
-       struct drm_i915_gem_object *hws;
-       struct drm_i915_gem_object *obj;
-       u32 *batch;
-       void *seqno;
-};
-
-static int spinner_init(struct spinner *spin, struct drm_i915_private *i915)
-{
-       unsigned int mode;
-       void *vaddr;
-       int err;
-
-       GEM_BUG_ON(INTEL_GEN(i915) < 8);
-
-       memset(spin, 0, sizeof(*spin));
-       spin->i915 = i915;
-
-       spin->hws = i915_gem_object_create_internal(i915, PAGE_SIZE);
-       if (IS_ERR(spin->hws)) {
-               err = PTR_ERR(spin->hws);
-               goto err;
-       }
-
-       spin->obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
-       if (IS_ERR(spin->obj)) {
-               err = PTR_ERR(spin->obj);
-               goto err_hws;
-       }
-
-       i915_gem_object_set_cache_level(spin->hws, I915_CACHE_LLC);
-       vaddr = i915_gem_object_pin_map(spin->hws, I915_MAP_WB);
-       if (IS_ERR(vaddr)) {
-               err = PTR_ERR(vaddr);
-               goto err_obj;
-       }
-       spin->seqno = memset(vaddr, 0xff, PAGE_SIZE);
-
-       mode = HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC;
-       vaddr = i915_gem_object_pin_map(spin->obj, mode);
-       if (IS_ERR(vaddr)) {
-               err = PTR_ERR(vaddr);
-               goto err_unpin_hws;
-       }
-       spin->batch = vaddr;
-
-       return 0;
-
-err_unpin_hws:
-       i915_gem_object_unpin_map(spin->hws);
-err_obj:
-       i915_gem_object_put(spin->obj);
-err_hws:
-       i915_gem_object_put(spin->hws);
-err:
-       return err;
-}
-
-static unsigned int seqno_offset(u64 fence)
-{
-       return offset_in_page(sizeof(u32) * fence);
-}
-
-static u64 hws_address(const struct i915_vma *hws,
-                      const struct i915_request *rq)
-{
-       return hws->node.start + seqno_offset(rq->fence.context);
-}
-
-static int emit_recurse_batch(struct spinner *spin,
-                             struct i915_request *rq,
-                             u32 arbitration_command)
-{
-       struct i915_address_space *vm = &rq->gem_context->ppgtt->vm;
-       struct i915_vma *hws, *vma;
-       u32 *batch;
-       int err;
-
-       vma = i915_vma_instance(spin->obj, vm, NULL);
-       if (IS_ERR(vma))
-               return PTR_ERR(vma);
-
-       hws = i915_vma_instance(spin->hws, vm, NULL);
-       if (IS_ERR(hws))
-               return PTR_ERR(hws);
-
-       err = i915_vma_pin(vma, 0, 0, PIN_USER);
-       if (err)
-               return err;
-
-       err = i915_vma_pin(hws, 0, 0, PIN_USER);
-       if (err)
-               goto unpin_vma;
-
-       err = i915_vma_move_to_active(vma, rq, 0);
-       if (err)
-               goto unpin_hws;
-
-       if (!i915_gem_object_has_active_reference(vma->obj)) {
-               i915_gem_object_get(vma->obj);
-               i915_gem_object_set_active_reference(vma->obj);
-       }
-
-       err = i915_vma_move_to_active(hws, rq, 0);
-       if (err)
-               goto unpin_hws;
-
-       if (!i915_gem_object_has_active_reference(hws->obj)) {
-               i915_gem_object_get(hws->obj);
-               i915_gem_object_set_active_reference(hws->obj);
-       }
-
-       batch = spin->batch;
-
-       *batch++ = MI_STORE_DWORD_IMM_GEN4;
-       *batch++ = lower_32_bits(hws_address(hws, rq));
-       *batch++ = upper_32_bits(hws_address(hws, rq));
-       *batch++ = rq->fence.seqno;
-
-       *batch++ = arbitration_command;
-
-       *batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
-       *batch++ = lower_32_bits(vma->node.start);
-       *batch++ = upper_32_bits(vma->node.start);
-       *batch++ = MI_BATCH_BUFFER_END; /* not reached */
-
-       i915_gem_chipset_flush(spin->i915);
-
-       err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0);
-
-unpin_hws:
-       i915_vma_unpin(hws);
-unpin_vma:
-       i915_vma_unpin(vma);
-       return err;
-}
-
-static struct i915_request *
-spinner_create_request(struct spinner *spin,
-                      struct i915_gem_context *ctx,
-                      struct intel_engine_cs *engine,
-                      u32 arbitration_command)
-{
-       struct i915_request *rq;
-       int err;
-
-       rq = i915_request_alloc(engine, ctx);
-       if (IS_ERR(rq))
-               return rq;
-
-       err = emit_recurse_batch(spin, rq, arbitration_command);
-       if (err) {
-               i915_request_add(rq);
-               return ERR_PTR(err);
-       }
-
-       return rq;
-}
-
-static u32 hws_seqno(const struct spinner *spin, const struct i915_request *rq)
-{
-       u32 *seqno = spin->seqno + seqno_offset(rq->fence.context);
-
-       return READ_ONCE(*seqno);
-}
-
-static void spinner_end(struct spinner *spin)
-{
-       *spin->batch = MI_BATCH_BUFFER_END;
-       i915_gem_chipset_flush(spin->i915);
-}
-
-static void spinner_fini(struct spinner *spin)
-{
-       spinner_end(spin);
-
-       i915_gem_object_unpin_map(spin->obj);
-       i915_gem_object_put(spin->obj);
-
-       i915_gem_object_unpin_map(spin->hws);
-       i915_gem_object_put(spin->hws);
-}
-
-static bool wait_for_spinner(struct spinner *spin, struct i915_request *rq)
-{
-       if (!wait_event_timeout(rq->execute,
-                               READ_ONCE(rq->global_seqno),
-                               msecs_to_jiffies(10)))
-               return false;
-
-       return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq),
-                                              rq->fence.seqno),
-                            10) &&
-                wait_for(i915_seqno_passed(hws_seqno(spin, rq),
-                                           rq->fence.seqno),
-                         1000));
-}
-
 static int live_sanitycheck(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct intel_engine_cs *engine;
        struct i915_gem_context *ctx;
        enum intel_engine_id id;
-       struct spinner spin;
+       struct igt_spinner spin;
        int err = -ENOMEM;
 
        if (!HAS_LOGICAL_RING_CONTEXTS(i915))
@@ -223,7 +26,7 @@ static int live_sanitycheck(void *arg)
        mutex_lock(&i915->drm.struct_mutex);
        intel_runtime_pm_get(i915);
 
-       if (spinner_init(&spin, i915))
+       if (igt_spinner_init(&spin, i915))
                goto err_unlock;
 
        ctx = kernel_context(i915);
@@ -233,14 +36,14 @@ static int live_sanitycheck(void *arg)
        for_each_engine(engine, i915, id) {
                struct i915_request *rq;
 
-               rq = spinner_create_request(&spin, ctx, engine, MI_NOOP);
+               rq = igt_spinner_create_request(&spin, ctx, engine, MI_NOOP);
                if (IS_ERR(rq)) {
                        err = PTR_ERR(rq);
                        goto err_ctx;
                }
 
                i915_request_add(rq);
-               if (!wait_for_spinner(&spin, rq)) {
+               if (!igt_wait_for_spinner(&spin, rq)) {
                        GEM_TRACE("spinner failed to start\n");
                        GEM_TRACE_DUMP();
                        i915_gem_set_wedged(i915);
@@ -248,7 +51,7 @@ static int live_sanitycheck(void *arg)
                        goto err_ctx;
                }
 
-               spinner_end(&spin);
+               igt_spinner_end(&spin);
                if (igt_flush_test(i915, I915_WAIT_LOCKED)) {
                        err = -EIO;
                        goto err_ctx;
@@ -259,7 +62,7 @@ static int live_sanitycheck(void *arg)
 err_ctx:
        kernel_context_close(ctx);
 err_spin:
-       spinner_fini(&spin);
+       igt_spinner_fini(&spin);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
        intel_runtime_pm_put(i915);
@@ -271,7 +74,7 @@ static int live_preempt(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct i915_gem_context *ctx_hi, *ctx_lo;
-       struct spinner spin_hi, spin_lo;
+       struct igt_spinner spin_hi, spin_lo;
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
        int err = -ENOMEM;
@@ -282,34 +85,36 @@ static int live_preempt(void *arg)
        mutex_lock(&i915->drm.struct_mutex);
        intel_runtime_pm_get(i915);
 
-       if (spinner_init(&spin_hi, i915))
+       if (igt_spinner_init(&spin_hi, i915))
                goto err_unlock;
 
-       if (spinner_init(&spin_lo, i915))
+       if (igt_spinner_init(&spin_lo, i915))
                goto err_spin_hi;
 
        ctx_hi = kernel_context(i915);
        if (!ctx_hi)
                goto err_spin_lo;
-       ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
+       ctx_hi->sched.priority =
+               I915_USER_PRIORITY(I915_CONTEXT_MAX_USER_PRIORITY);
 
        ctx_lo = kernel_context(i915);
        if (!ctx_lo)
                goto err_ctx_hi;
-       ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
+       ctx_lo->sched.priority =
+               I915_USER_PRIORITY(I915_CONTEXT_MIN_USER_PRIORITY);
 
        for_each_engine(engine, i915, id) {
                struct i915_request *rq;
 
-               rq = spinner_create_request(&spin_lo, ctx_lo, engine,
-                                           MI_ARB_CHECK);
+               rq = igt_spinner_create_request(&spin_lo, ctx_lo, engine,
+                                               MI_ARB_CHECK);
                if (IS_ERR(rq)) {
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
 
                i915_request_add(rq);
-               if (!wait_for_spinner(&spin_lo, rq)) {
+               if (!igt_wait_for_spinner(&spin_lo, rq)) {
                        GEM_TRACE("lo spinner failed to start\n");
                        GEM_TRACE_DUMP();
                        i915_gem_set_wedged(i915);
@@ -317,16 +122,16 @@ static int live_preempt(void *arg)
                        goto err_ctx_lo;
                }
 
-               rq = spinner_create_request(&spin_hi, ctx_hi, engine,
-                                           MI_ARB_CHECK);
+               rq = igt_spinner_create_request(&spin_hi, ctx_hi, engine,
+                                               MI_ARB_CHECK);
                if (IS_ERR(rq)) {
-                       spinner_end(&spin_lo);
+                       igt_spinner_end(&spin_lo);
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
 
                i915_request_add(rq);
-               if (!wait_for_spinner(&spin_hi, rq)) {
+               if (!igt_wait_for_spinner(&spin_hi, rq)) {
                        GEM_TRACE("hi spinner failed to start\n");
                        GEM_TRACE_DUMP();
                        i915_gem_set_wedged(i915);
@@ -334,8 +139,8 @@ static int live_preempt(void *arg)
                        goto err_ctx_lo;
                }
 
-               spinner_end(&spin_hi);
-               spinner_end(&spin_lo);
+               igt_spinner_end(&spin_hi);
+               igt_spinner_end(&spin_lo);
                if (igt_flush_test(i915, I915_WAIT_LOCKED)) {
                        err = -EIO;
                        goto err_ctx_lo;
@@ -348,9 +153,9 @@ err_ctx_lo:
 err_ctx_hi:
        kernel_context_close(ctx_hi);
 err_spin_lo:
-       spinner_fini(&spin_lo);
+       igt_spinner_fini(&spin_lo);
 err_spin_hi:
-       spinner_fini(&spin_hi);
+       igt_spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
        intel_runtime_pm_put(i915);
@@ -362,7 +167,7 @@ static int live_late_preempt(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct i915_gem_context *ctx_hi, *ctx_lo;
-       struct spinner spin_hi, spin_lo;
+       struct igt_spinner spin_hi, spin_lo;
        struct intel_engine_cs *engine;
        struct i915_sched_attr attr = {};
        enum intel_engine_id id;
@@ -374,10 +179,10 @@ static int live_late_preempt(void *arg)
        mutex_lock(&i915->drm.struct_mutex);
        intel_runtime_pm_get(i915);
 
-       if (spinner_init(&spin_hi, i915))
+       if (igt_spinner_init(&spin_hi, i915))
                goto err_unlock;
 
-       if (spinner_init(&spin_lo, i915))
+       if (igt_spinner_init(&spin_lo, i915))
                goto err_spin_hi;
 
        ctx_hi = kernel_context(i915);
@@ -391,43 +196,44 @@ static int live_late_preempt(void *arg)
        for_each_engine(engine, i915, id) {
                struct i915_request *rq;
 
-               rq = spinner_create_request(&spin_lo, ctx_lo, engine,
-                                           MI_ARB_CHECK);
+               rq = igt_spinner_create_request(&spin_lo, ctx_lo, engine,
+                                               MI_ARB_CHECK);
                if (IS_ERR(rq)) {
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
 
                i915_request_add(rq);
-               if (!wait_for_spinner(&spin_lo, rq)) {
+               if (!igt_wait_for_spinner(&spin_lo, rq)) {
                        pr_err("First context failed to start\n");
                        goto err_wedged;
                }
 
-               rq = spinner_create_request(&spin_hi, ctx_hi, engine, MI_NOOP);
+               rq = igt_spinner_create_request(&spin_hi, ctx_hi, engine,
+                                               MI_NOOP);
                if (IS_ERR(rq)) {
-                       spinner_end(&spin_lo);
+                       igt_spinner_end(&spin_lo);
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
 
                i915_request_add(rq);
-               if (wait_for_spinner(&spin_hi, rq)) {
+               if (igt_wait_for_spinner(&spin_hi, rq)) {
                        pr_err("Second context overtook first?\n");
                        goto err_wedged;
                }
 
-               attr.priority = I915_PRIORITY_MAX;
+               attr.priority = I915_USER_PRIORITY(I915_PRIORITY_MAX);
                engine->schedule(rq, &attr);
 
-               if (!wait_for_spinner(&spin_hi, rq)) {
+               if (!igt_wait_for_spinner(&spin_hi, rq)) {
                        pr_err("High priority context failed to preempt the low priority context\n");
                        GEM_TRACE_DUMP();
                        goto err_wedged;
                }
 
-               spinner_end(&spin_hi);
-               spinner_end(&spin_lo);
+               igt_spinner_end(&spin_hi);
+               igt_spinner_end(&spin_lo);
                if (igt_flush_test(i915, I915_WAIT_LOCKED)) {
                        err = -EIO;
                        goto err_ctx_lo;
@@ -440,9 +246,9 @@ err_ctx_lo:
 err_ctx_hi:
        kernel_context_close(ctx_hi);
 err_spin_lo:
-       spinner_fini(&spin_lo);
+       igt_spinner_fini(&spin_lo);
 err_spin_hi:
-       spinner_fini(&spin_hi);
+       igt_spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
        intel_runtime_pm_put(i915);
@@ -450,8 +256,8 @@ err_unlock:
        return err;
 
 err_wedged:
-       spinner_end(&spin_hi);
-       spinner_end(&spin_lo);
+       igt_spinner_end(&spin_hi);
+       igt_spinner_end(&spin_lo);
        i915_gem_set_wedged(i915);
        err = -EIO;
        goto err_ctx_lo;
@@ -461,7 +267,7 @@ static int live_preempt_hang(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct i915_gem_context *ctx_hi, *ctx_lo;
-       struct spinner spin_hi, spin_lo;
+       struct igt_spinner spin_hi, spin_lo;
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
        int err = -ENOMEM;
@@ -475,10 +281,10 @@ static int live_preempt_hang(void *arg)
        mutex_lock(&i915->drm.struct_mutex);
        intel_runtime_pm_get(i915);
 
-       if (spinner_init(&spin_hi, i915))
+       if (igt_spinner_init(&spin_hi, i915))
                goto err_unlock;
 
-       if (spinner_init(&spin_lo, i915))
+       if (igt_spinner_init(&spin_lo, i915))
                goto err_spin_hi;
 
        ctx_hi = kernel_context(i915);
@@ -497,15 +303,15 @@ static int live_preempt_hang(void *arg)
                if (!intel_engine_has_preemption(engine))
                        continue;
 
-               rq = spinner_create_request(&spin_lo, ctx_lo, engine,
-                                           MI_ARB_CHECK);
+               rq = igt_spinner_create_request(&spin_lo, ctx_lo, engine,
+                                               MI_ARB_CHECK);
                if (IS_ERR(rq)) {
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
 
                i915_request_add(rq);
-               if (!wait_for_spinner(&spin_lo, rq)) {
+               if (!igt_wait_for_spinner(&spin_lo, rq)) {
                        GEM_TRACE("lo spinner failed to start\n");
                        GEM_TRACE_DUMP();
                        i915_gem_set_wedged(i915);
@@ -513,10 +319,10 @@ static int live_preempt_hang(void *arg)
                        goto err_ctx_lo;
                }
 
-               rq = spinner_create_request(&spin_hi, ctx_hi, engine,
-                                           MI_ARB_CHECK);
+               rq = igt_spinner_create_request(&spin_hi, ctx_hi, engine,
+                                               MI_ARB_CHECK);
                if (IS_ERR(rq)) {
-                       spinner_end(&spin_lo);
+                       igt_spinner_end(&spin_lo);
                        err = PTR_ERR(rq);
                        goto err_ctx_lo;
                }
@@ -541,7 +347,7 @@ static int live_preempt_hang(void *arg)
 
                engine->execlists.preempt_hang.inject_hang = false;
 
-               if (!wait_for_spinner(&spin_hi, rq)) {
+               if (!igt_wait_for_spinner(&spin_hi, rq)) {
                        GEM_TRACE("hi spinner failed to start\n");
                        GEM_TRACE_DUMP();
                        i915_gem_set_wedged(i915);
@@ -549,8 +355,8 @@ static int live_preempt_hang(void *arg)
                        goto err_ctx_lo;
                }
 
-               spinner_end(&spin_hi);
-               spinner_end(&spin_lo);
+               igt_spinner_end(&spin_hi);
+               igt_spinner_end(&spin_lo);
                if (igt_flush_test(i915, I915_WAIT_LOCKED)) {
                        err = -EIO;
                        goto err_ctx_lo;
@@ -563,9 +369,9 @@ err_ctx_lo:
 err_ctx_hi:
        kernel_context_close(ctx_hi);
 err_spin_lo:
-       spinner_fini(&spin_lo);
+       igt_spinner_fini(&spin_lo);
 err_spin_hi:
-       spinner_fini(&spin_hi);
+       igt_spinner_fini(&spin_hi);
 err_unlock:
        igt_flush_test(i915, I915_WAIT_LOCKED);
        intel_runtime_pm_put(i915);
@@ -573,6 +379,261 @@ err_unlock:
        return err;
 }
 
+static int random_range(struct rnd_state *rnd, int min, int max)
+{
+       return i915_prandom_u32_max_state(max - min, rnd) + min;
+}
+
+static int random_priority(struct rnd_state *rnd)
+{
+       return random_range(rnd, I915_PRIORITY_MIN, I915_PRIORITY_MAX);
+}
+
+struct preempt_smoke {
+       struct drm_i915_private *i915;
+       struct i915_gem_context **contexts;
+       struct intel_engine_cs *engine;
+       struct drm_i915_gem_object *batch;
+       unsigned int ncontext;
+       struct rnd_state prng;
+       unsigned long count;
+};
+
+static struct i915_gem_context *smoke_context(struct preempt_smoke *smoke)
+{
+       return smoke->contexts[i915_prandom_u32_max_state(smoke->ncontext,
+                                                         &smoke->prng)];
+}
+
+static int smoke_submit(struct preempt_smoke *smoke,
+                       struct i915_gem_context *ctx, int prio,
+                       struct drm_i915_gem_object *batch)
+{
+       struct i915_request *rq;
+       struct i915_vma *vma = NULL;
+       int err = 0;
+
+       if (batch) {
+               vma = i915_vma_instance(batch, &ctx->ppgtt->vm, NULL);
+               if (IS_ERR(vma))
+                       return PTR_ERR(vma);
+
+               err = i915_vma_pin(vma, 0, 0, PIN_USER);
+               if (err)
+                       return err;
+       }
+
+       ctx->sched.priority = prio;
+
+       rq = i915_request_alloc(smoke->engine, ctx);
+       if (IS_ERR(rq)) {
+               err = PTR_ERR(rq);
+               goto unpin;
+       }
+
+       if (vma) {
+               err = rq->engine->emit_bb_start(rq,
+                                               vma->node.start,
+                                               PAGE_SIZE, 0);
+               if (!err)
+                       err = i915_vma_move_to_active(vma, rq, 0);
+       }
+
+       i915_request_add(rq);
+
+unpin:
+       if (vma)
+               i915_vma_unpin(vma);
+
+       return err;
+}
+
+static int smoke_crescendo_thread(void *arg)
+{
+       struct preempt_smoke *smoke = arg;
+       IGT_TIMEOUT(end_time);
+       unsigned long count;
+
+       count = 0;
+       do {
+               struct i915_gem_context *ctx = smoke_context(smoke);
+               int err;
+
+               mutex_lock(&smoke->i915->drm.struct_mutex);
+               err = smoke_submit(smoke,
+                                  ctx, count % I915_PRIORITY_MAX,
+                                  smoke->batch);
+               mutex_unlock(&smoke->i915->drm.struct_mutex);
+               if (err)
+                       return err;
+
+               count++;
+       } while (!__igt_timeout(end_time, NULL));
+
+       smoke->count = count;
+       return 0;
+}
+
+static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
+#define BATCH BIT(0)
+{
+       struct task_struct *tsk[I915_NUM_ENGINES] = {};
+       struct preempt_smoke arg[I915_NUM_ENGINES];
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       unsigned long count;
+       int err = 0;
+
+       mutex_unlock(&smoke->i915->drm.struct_mutex);
+
+       for_each_engine(engine, smoke->i915, id) {
+               arg[id] = *smoke;
+               arg[id].engine = engine;
+               if (!(flags & BATCH))
+                       arg[id].batch = NULL;
+               arg[id].count = 0;
+
+               tsk[id] = kthread_run(smoke_crescendo_thread, &arg,
+                                     "igt/smoke:%d", id);
+               if (IS_ERR(tsk[id])) {
+                       err = PTR_ERR(tsk[id]);
+                       break;
+               }
+               get_task_struct(tsk[id]);
+       }
+
+       count = 0;
+       for_each_engine(engine, smoke->i915, id) {
+               int status;
+
+               if (IS_ERR_OR_NULL(tsk[id]))
+                       continue;
+
+               status = kthread_stop(tsk[id]);
+               if (status && !err)
+                       err = status;
+
+               count += arg[id].count;
+
+               put_task_struct(tsk[id]);
+       }
+
+       mutex_lock(&smoke->i915->drm.struct_mutex);
+
+       pr_info("Submitted %lu crescendo:%x requests across %d engines and %d contexts\n",
+               count, flags,
+               INTEL_INFO(smoke->i915)->num_rings, smoke->ncontext);
+       return 0;
+}
+
+static int smoke_random(struct preempt_smoke *smoke, unsigned int flags)
+{
+       enum intel_engine_id id;
+       IGT_TIMEOUT(end_time);
+       unsigned long count;
+
+       count = 0;
+       do {
+               for_each_engine(smoke->engine, smoke->i915, id) {
+                       struct i915_gem_context *ctx = smoke_context(smoke);
+                       int err;
+
+                       err = smoke_submit(smoke,
+                                          ctx, random_priority(&smoke->prng),
+                                          flags & BATCH ? smoke->batch : NULL);
+                       if (err)
+                               return err;
+
+                       count++;
+               }
+       } while (!__igt_timeout(end_time, NULL));
+
+       pr_info("Submitted %lu random:%x requests across %d engines and %d contexts\n",
+               count, flags,
+               INTEL_INFO(smoke->i915)->num_rings, smoke->ncontext);
+       return 0;
+}
+
+static int live_preempt_smoke(void *arg)
+{
+       struct preempt_smoke smoke = {
+               .i915 = arg,
+               .prng = I915_RND_STATE_INITIALIZER(i915_selftest.random_seed),
+               .ncontext = 1024,
+       };
+       const unsigned int phase[] = { 0, BATCH };
+       int err = -ENOMEM;
+       u32 *cs;
+       int n;
+
+       if (!HAS_LOGICAL_RING_PREEMPTION(smoke.i915))
+               return 0;
+
+       smoke.contexts = kmalloc_array(smoke.ncontext,
+                                      sizeof(*smoke.contexts),
+                                      GFP_KERNEL);
+       if (!smoke.contexts)
+               return -ENOMEM;
+
+       mutex_lock(&smoke.i915->drm.struct_mutex);
+       intel_runtime_pm_get(smoke.i915);
+
+       smoke.batch = i915_gem_object_create_internal(smoke.i915, PAGE_SIZE);
+       if (IS_ERR(smoke.batch)) {
+               err = PTR_ERR(smoke.batch);
+               goto err_unlock;
+       }
+
+       cs = i915_gem_object_pin_map(smoke.batch, I915_MAP_WB);
+       if (IS_ERR(cs)) {
+               err = PTR_ERR(cs);
+               goto err_batch;
+       }
+       for (n = 0; n < PAGE_SIZE / sizeof(*cs) - 1; n++)
+               cs[n] = MI_ARB_CHECK;
+       cs[n] = MI_BATCH_BUFFER_END;
+       i915_gem_object_unpin_map(smoke.batch);
+
+       err = i915_gem_object_set_to_gtt_domain(smoke.batch, false);
+       if (err)
+               goto err_batch;
+
+       for (n = 0; n < smoke.ncontext; n++) {
+               smoke.contexts[n] = kernel_context(smoke.i915);
+               if (!smoke.contexts[n])
+                       goto err_ctx;
+       }
+
+       for (n = 0; n < ARRAY_SIZE(phase); n++) {
+               err = smoke_crescendo(&smoke, phase[n]);
+               if (err)
+                       goto err_ctx;
+
+               err = smoke_random(&smoke, phase[n]);
+               if (err)
+                       goto err_ctx;
+       }
+
+err_ctx:
+       if (igt_flush_test(smoke.i915, I915_WAIT_LOCKED))
+               err = -EIO;
+
+       for (n = 0; n < smoke.ncontext; n++) {
+               if (!smoke.contexts[n])
+                       break;
+               kernel_context_close(smoke.contexts[n]);
+       }
+
+err_batch:
+       i915_gem_object_put(smoke.batch);
+err_unlock:
+       intel_runtime_pm_put(smoke.i915);
+       mutex_unlock(&smoke.i915->drm.struct_mutex);
+       kfree(smoke.contexts);
+
+       return err;
+}
+
 int intel_execlists_live_selftests(struct drm_i915_private *i915)
 {
        static const struct i915_subtest tests[] = {
@@ -580,6 +641,7 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
                SUBTEST(live_preempt),
                SUBTEST(live_late_preempt),
                SUBTEST(live_preempt_hang),
+               SUBTEST(live_preempt_smoke),
        };
 
        if (!HAS_EXECLISTS(i915))
index d1a0923d2f383ea974ee5edbc6c59d3b074eaae7..67017d5175b8c6cfcb8c5df8b2a90314f517b621 100644 (file)
@@ -6,6 +6,9 @@
 
 #include "../i915_selftest.h"
 
+#include "igt_flush_test.h"
+#include "igt_reset.h"
+#include "igt_spinner.h"
 #include "igt_wedge_me.h"
 #include "mock_context.h"
 
@@ -91,17 +94,23 @@ err_obj:
        return ERR_PTR(err);
 }
 
-static u32 get_whitelist_reg(const struct whitelist *w, unsigned int i)
+static u32
+get_whitelist_reg(const struct intel_engine_cs *engine, unsigned int i)
 {
-       return i < w->count ? i915_mmio_reg_offset(w->reg[i]) : w->nopid;
+       i915_reg_t reg = i < engine->whitelist.count ?
+                        engine->whitelist.list[i].reg :
+                        RING_NOPID(engine->mmio_base);
+
+       return i915_mmio_reg_offset(reg);
 }
 
-static void print_results(const struct whitelist *w, const u32 *results)
+static void
+print_results(const struct intel_engine_cs *engine, const u32 *results)
 {
        unsigned int i;
 
        for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
-               u32 expected = get_whitelist_reg(w, i);
+               u32 expected = get_whitelist_reg(engine, i);
                u32 actual = results[i];
 
                pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n",
@@ -109,8 +118,7 @@ static void print_results(const struct whitelist *w, const u32 *results)
        }
 }
 
-static int check_whitelist(const struct whitelist *w,
-                          struct i915_gem_context *ctx,
+static int check_whitelist(struct i915_gem_context *ctx,
                           struct intel_engine_cs *engine)
 {
        struct drm_i915_gem_object *results;
@@ -138,11 +146,11 @@ static int check_whitelist(const struct whitelist *w,
        }
 
        for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
-               u32 expected = get_whitelist_reg(w, i);
+               u32 expected = get_whitelist_reg(engine, i);
                u32 actual = vaddr[i];
 
                if (expected != actual) {
-                       print_results(w, vaddr);
+                       print_results(engine, vaddr);
                        pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n",
                               i, expected, actual);
 
@@ -159,66 +167,107 @@ out_put:
 
 static int do_device_reset(struct intel_engine_cs *engine)
 {
-       i915_reset(engine->i915, ENGINE_MASK(engine->id), NULL);
+       set_bit(I915_RESET_HANDOFF, &engine->i915->gpu_error.flags);
+       i915_reset(engine->i915, ENGINE_MASK(engine->id), "live_workarounds");
        return 0;
 }
 
 static int do_engine_reset(struct intel_engine_cs *engine)
 {
-       return i915_reset_engine(engine, NULL);
+       return i915_reset_engine(engine, "live_workarounds");
 }
 
-static int switch_to_scratch_context(struct intel_engine_cs *engine)
+static int
+switch_to_scratch_context(struct intel_engine_cs *engine,
+                         struct igt_spinner *spin)
 {
        struct i915_gem_context *ctx;
        struct i915_request *rq;
+       int err = 0;
 
        ctx = kernel_context(engine->i915);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
        intel_runtime_pm_get(engine->i915);
-       rq = i915_request_alloc(engine, ctx);
+
+       if (spin)
+               rq = igt_spinner_create_request(spin, ctx, engine, MI_NOOP);
+       else
+               rq = i915_request_alloc(engine, ctx);
+
        intel_runtime_pm_put(engine->i915);
 
        kernel_context_close(ctx);
-       if (IS_ERR(rq))
-               return PTR_ERR(rq);
+
+       if (IS_ERR(rq)) {
+               spin = NULL;
+               err = PTR_ERR(rq);
+               goto err;
+       }
 
        i915_request_add(rq);
 
-       return 0;
+       if (spin && !igt_wait_for_spinner(spin, rq)) {
+               pr_err("Spinner failed to start\n");
+               err = -ETIMEDOUT;
+       }
+
+err:
+       if (err && spin)
+               igt_spinner_end(spin);
+
+       return err;
 }
 
 static int check_whitelist_across_reset(struct intel_engine_cs *engine,
                                        int (*reset)(struct intel_engine_cs *),
-                                       const struct whitelist *w,
                                        const char *name)
 {
+       struct drm_i915_private *i915 = engine->i915;
+       bool want_spin = reset == do_engine_reset;
        struct i915_gem_context *ctx;
+       struct igt_spinner spin;
        int err;
 
-       ctx = kernel_context(engine->i915);
+       pr_info("Checking %d whitelisted registers (RING_NONPRIV) [%s]\n",
+               engine->whitelist.count, name);
+
+       if (want_spin) {
+               err = igt_spinner_init(&spin, i915);
+               if (err)
+                       return err;
+       }
+
+       ctx = kernel_context(i915);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       err = check_whitelist(w, ctx, engine);
+       err = check_whitelist(ctx, engine);
        if (err) {
                pr_err("Invalid whitelist *before* %s reset!\n", name);
                goto out;
        }
 
-       err = switch_to_scratch_context(engine);
+       err = switch_to_scratch_context(engine, want_spin ? &spin : NULL);
        if (err)
                goto out;
 
+       intel_runtime_pm_get(i915);
        err = reset(engine);
+       intel_runtime_pm_put(i915);
+
+       if (want_spin) {
+               igt_spinner_end(&spin);
+               igt_spinner_fini(&spin);
+       }
+
        if (err) {
                pr_err("%s reset failed\n", name);
                goto out;
        }
 
-       err = check_whitelist(w, ctx, engine);
+       err = check_whitelist(ctx, engine);
        if (err) {
                pr_err("Whitelist not preserved in context across %s reset!\n",
                       name);
@@ -227,11 +276,11 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine,
 
        kernel_context_close(ctx);
 
-       ctx = kernel_context(engine->i915);
+       ctx = kernel_context(i915);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       err = check_whitelist(w, ctx, engine);
+       err = check_whitelist(ctx, engine);
        if (err) {
                pr_err("Invalid whitelist *after* %s reset in fresh context!\n",
                       name);
@@ -247,26 +296,18 @@ static int live_reset_whitelist(void *arg)
 {
        struct drm_i915_private *i915 = arg;
        struct intel_engine_cs *engine = i915->engine[RCS];
-       struct i915_gpu_error *error = &i915->gpu_error;
-       struct whitelist w;
        int err = 0;
 
        /* If we reset the gpu, we should not lose the RING_NONPRIV */
 
-       if (!engine)
-               return 0;
-
-       if (!whitelist_build(engine, &w))
+       if (!engine || engine->whitelist.count == 0)
                return 0;
 
-       pr_info("Checking %d whitelisted registers (RING_NONPRIV)\n", w.count);
-
-       set_bit(I915_RESET_BACKOFF, &error->flags);
-       set_bit(I915_RESET_ENGINE + engine->id, &error->flags);
+       igt_global_reset_lock(i915);
 
        if (intel_has_reset_engine(i915)) {
                err = check_whitelist_across_reset(engine,
-                                                  do_engine_reset, &w,
+                                                  do_engine_reset,
                                                   "engine");
                if (err)
                        goto out;
@@ -274,22 +315,156 @@ static int live_reset_whitelist(void *arg)
 
        if (intel_has_gpu_reset(i915)) {
                err = check_whitelist_across_reset(engine,
-                                                  do_device_reset, &w,
+                                                  do_device_reset,
                                                   "device");
                if (err)
                        goto out;
        }
 
 out:
-       clear_bit(I915_RESET_ENGINE + engine->id, &error->flags);
-       clear_bit(I915_RESET_BACKOFF, &error->flags);
+       igt_global_reset_unlock(i915);
        return err;
 }
 
+static bool verify_gt_engine_wa(struct drm_i915_private *i915, const char *str)
+{
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       bool ok = true;
+
+       ok &= intel_gt_verify_workarounds(i915, str);
+
+       for_each_engine(engine, i915, id)
+               ok &= intel_engine_verify_workarounds(engine, str);
+
+       return ok;
+}
+
+static int
+live_gpu_reset_gt_engine_workarounds(void *arg)
+{
+       struct drm_i915_private *i915 = arg;
+       struct i915_gpu_error *error = &i915->gpu_error;
+       bool ok;
+
+       if (!intel_has_gpu_reset(i915))
+               return 0;
+
+       pr_info("Verifying after GPU reset...\n");
+
+       igt_global_reset_lock(i915);
+
+       ok = verify_gt_engine_wa(i915, "before reset");
+       if (!ok)
+               goto out;
+
+       intel_runtime_pm_get(i915);
+       set_bit(I915_RESET_HANDOFF, &error->flags);
+       i915_reset(i915, ALL_ENGINES, "live_workarounds");
+       intel_runtime_pm_put(i915);
+
+       ok = verify_gt_engine_wa(i915, "after reset");
+
+out:
+       igt_global_reset_unlock(i915);
+
+       return ok ? 0 : -ESRCH;
+}
+
+static int
+live_engine_reset_gt_engine_workarounds(void *arg)
+{
+       struct drm_i915_private *i915 = arg;
+       struct intel_engine_cs *engine;
+       struct i915_gem_context *ctx;
+       struct igt_spinner spin;
+       enum intel_engine_id id;
+       struct i915_request *rq;
+       int ret = 0;
+
+       if (!intel_has_reset_engine(i915))
+               return 0;
+
+       ctx = kernel_context(i915);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       igt_global_reset_lock(i915);
+
+       for_each_engine(engine, i915, id) {
+               bool ok;
+
+               pr_info("Verifying after %s reset...\n", engine->name);
+
+               ok = verify_gt_engine_wa(i915, "before reset");
+               if (!ok) {
+                       ret = -ESRCH;
+                       goto err;
+               }
+
+               intel_runtime_pm_get(i915);
+               i915_reset_engine(engine, "live_workarounds");
+               intel_runtime_pm_put(i915);
+
+               ok = verify_gt_engine_wa(i915, "after idle reset");
+               if (!ok) {
+                       ret = -ESRCH;
+                       goto err;
+               }
+
+               ret = igt_spinner_init(&spin, i915);
+               if (ret)
+                       goto err;
+
+               intel_runtime_pm_get(i915);
+
+               rq = igt_spinner_create_request(&spin, ctx, engine, MI_NOOP);
+               if (IS_ERR(rq)) {
+                       ret = PTR_ERR(rq);
+                       igt_spinner_fini(&spin);
+                       intel_runtime_pm_put(i915);
+                       goto err;
+               }
+
+               i915_request_add(rq);
+
+               if (!igt_wait_for_spinner(&spin, rq)) {
+                       pr_err("Spinner failed to start\n");
+                       igt_spinner_fini(&spin);
+                       intel_runtime_pm_put(i915);
+                       ret = -ETIMEDOUT;
+                       goto err;
+               }
+
+               i915_reset_engine(engine, "live_workarounds");
+
+               intel_runtime_pm_put(i915);
+
+               igt_spinner_end(&spin);
+               igt_spinner_fini(&spin);
+
+               ok = verify_gt_engine_wa(i915, "after busy reset");
+               if (!ok) {
+                       ret = -ESRCH;
+                       goto err;
+               }
+       }
+
+err:
+       igt_global_reset_unlock(i915);
+       kernel_context_close(ctx);
+
+       igt_flush_test(i915, I915_WAIT_LOCKED);
+
+       return ret;
+}
+
 int intel_workarounds_live_selftests(struct drm_i915_private *i915)
 {
        static const struct i915_subtest tests[] = {
                SUBTEST(live_reset_whitelist),
+               SUBTEST(live_gpu_reset_gt_engine_workarounds),
+               SUBTEST(live_engine_reset_gt_engine_workarounds),
        };
        int err;
 
index 22a73da45ad58b9bfae36cd823c6a934c4262c49..d0c44c18db429cd064c55dd51439ef01087c5779 100644 (file)
@@ -200,7 +200,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
        engine->base.submit_request = mock_submit_request;
 
        i915_timeline_init(i915, &engine->base.timeline, engine->base.name);
-       lockdep_set_subclass(&engine->base.timeline.lock, TIMELINE_ENGINE);
+       i915_timeline_set_subclass(&engine->base.timeline, TIMELINE_ENGINE);
 
        intel_engine_init_breadcrumbs(&engine->base);
        engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
index 435a2c35ee8c4acd46d9f3fccd3c6dc700ad8b8d..361e962a7969044aba1c8464096edfa493b4d0c7 100644 (file)
@@ -206,39 +206,6 @@ static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
        .transfer = intel_dsi_host_transfer,
 };
 
-static struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
-                                                 enum port port)
-{
-       struct intel_dsi_host *host;
-       struct mipi_dsi_device *device;
-
-       host = kzalloc(sizeof(*host), GFP_KERNEL);
-       if (!host)
-               return NULL;
-
-       host->base.ops = &intel_dsi_host_ops;
-       host->intel_dsi = intel_dsi;
-       host->port = port;
-
-       /*
-        * We should call mipi_dsi_host_register(&host->base) here, but we don't
-        * have a host->dev, and we don't have OF stuff either. So just use the
-        * dsi framework as a library and hope for the best. Create the dsi
-        * devices by ourselves here too. Need to be careful though, because we
-        * don't initialize any of the driver model devices here.
-        */
-       device = kzalloc(sizeof(*device), GFP_KERNEL);
-       if (!device) {
-               kfree(host);
-               return NULL;
-       }
-
-       device->host = &host->base;
-       host->device = device;
-
-       return host;
-}
-
 /*
  * send a video mode command
  *
@@ -290,16 +257,6 @@ static void band_gap_reset(struct drm_i915_private *dev_priv)
        mutex_unlock(&dev_priv->sb_lock);
 }
 
-static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
-}
-
-static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE;
-}
-
 static bool intel_dsi_compute_config(struct intel_encoder *encoder,
                                     struct intel_crtc_state *pipe_config,
                                     struct drm_connector_state *conn_state)
@@ -314,6 +271,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
        int ret;
 
        DRM_DEBUG_KMS("\n");
+       pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
        if (fixed_mode) {
                intel_fixed_panel_mode(fixed_mode, adjusted_mode);
@@ -745,17 +703,6 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
                              const struct intel_crtc_state *pipe_config);
 static void intel_dsi_unprepare(struct intel_encoder *encoder);
 
-static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-
-       /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
-       if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
-               return;
-
-       msleep(msec);
-}
-
 /*
  * Panel enable/disable sequences from the VBT spec.
  *
@@ -793,6 +740,10 @@ static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
  * - wait t4                                           - wait t4
  */
 
+/*
+ * DSI port enable has to be done before pipe and plane enable, so we do it in
+ * the pre_enable hook instead of the enable hook.
+ */
 static void intel_dsi_pre_enable(struct intel_encoder *encoder,
                                 const struct intel_crtc_state *pipe_config,
                                 const struct drm_connector_state *conn_state)
@@ -894,17 +845,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
 }
 
-/*
- * DSI port enable has to be done before pipe and plane enable, so we do it in
- * the pre_enable hook.
- */
-static void intel_dsi_enable_nop(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       DRM_DEBUG_KMS("\n");
-}
-
 /*
  * DSI port disable has to be done after pipe and plane disable, so we do it in
  * the post_disable hook.
@@ -1272,31 +1212,6 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
        }
 }
 
-static enum drm_mode_status
-intel_dsi_mode_valid(struct drm_connector *connector,
-                    struct drm_display_mode *mode)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-               if (fixed_mode->clock > max_dotclk)
-                       return MODE_CLOCK_HIGH;
-       }
-
-       return MODE_OK;
-}
-
 /* return txclkesc cycles in terms of divider and duration in us */
 static u16 txclkesc(u32 divider, unsigned int us)
 {
@@ -1619,39 +1534,6 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder)
        }
 }
 
-static int intel_dsi_get_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_display_mode *mode;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (!intel_connector->panel.fixed_mode) {
-               DRM_DEBUG_KMS("no fixed mode\n");
-               return 0;
-       }
-
-       mode = drm_mode_duplicate(connector->dev,
-                                 intel_connector->panel.fixed_mode);
-       if (!mode) {
-               DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
-               return 0;
-       }
-
-       drm_mode_probed_add(connector, mode);
-       return 1;
-}
-
-static void intel_dsi_connector_destroy(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       DRM_DEBUG_KMS("\n");
-       intel_panel_fini(&intel_connector->panel);
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
 static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
@@ -1676,7 +1558,7 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs
 static const struct drm_connector_funcs intel_dsi_connector_funcs = {
        .late_register = intel_connector_register,
        .early_unregister = intel_connector_unregister,
-       .destroy = intel_dsi_connector_destroy,
+       .destroy = intel_connector_destroy,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .atomic_get_property = intel_digital_connector_atomic_get_property,
        .atomic_set_property = intel_digital_connector_atomic_set_property,
@@ -1684,27 +1566,57 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
        .atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
 
-static int intel_dsi_get_panel_orientation(struct intel_connector *connector)
+static enum drm_panel_orientation
+vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
-       enum i9xx_plane_id i9xx_plane;
+       struct intel_encoder *encoder = connector->encoder;
+       enum intel_display_power_domain power_domain;
+       enum drm_panel_orientation orientation;
+       struct intel_plane *plane;
+       struct intel_crtc *crtc;
+       enum pipe pipe;
        u32 val;
 
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               if (connector->encoder->crtc_mask == BIT(PIPE_B))
-                       i9xx_plane = PLANE_B;
-               else
-                       i9xx_plane = PLANE_A;
+       if (!encoder->get_hw_state(encoder, &pipe))
+               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
 
-               val = I915_READ(DSPCNTR(i9xx_plane));
-               if (val & DISPPLANE_ROTATE_180)
-                       orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
-       }
+       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
+       plane = to_intel_plane(crtc->base.primary);
+
+       power_domain = POWER_DOMAIN_PIPE(pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+               return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+
+       val = I915_READ(DSPCNTR(plane->i9xx_plane));
+
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+       else if (val & DISPPLANE_ROTATE_180)
+               orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+       else
+               orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+
+       intel_display_power_put(dev_priv, power_domain);
 
        return orientation;
 }
 
+static enum drm_panel_orientation
+vlv_dsi_get_panel_orientation(struct intel_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       enum drm_panel_orientation orientation;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               orientation = vlv_dsi_get_hw_panel_orientation(connector);
+               if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+                       return orientation;
+       }
+
+       return intel_dsi_get_panel_orientation(connector);
+}
+
 static void intel_dsi_add_properties(struct intel_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
@@ -1722,7 +1634,7 @@ static void intel_dsi_add_properties(struct intel_connector *connector)
                connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
 
                connector->base.display_info.panel_orientation =
-                       intel_dsi_get_panel_orientation(connector);
+                       vlv_dsi_get_panel_orientation(connector);
                drm_connector_init_panel_orientation_property(
                                &connector->base,
                                connector->panel.fixed_mode->hdisplay,
@@ -1773,7 +1685,6 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
 
        intel_encoder->compute_config = intel_dsi_compute_config;
        intel_encoder->pre_enable = intel_dsi_pre_enable;
-       intel_encoder->enable = intel_dsi_enable_nop;
        intel_encoder->disable = intel_dsi_disable;
        intel_encoder->post_disable = intel_dsi_post_disable;
        intel_encoder->get_hw_state = intel_dsi_get_hw_state;
@@ -1806,7 +1717,8 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
        for_each_dsi_port(port, intel_dsi->ports) {
                struct intel_dsi_host *host;
 
-               host = intel_dsi_host_init(intel_dsi, port);
+               host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops,
+                                          port);
                if (!host)
                        goto err;
 
index fe6becdcc29edc8dc4fd105c932375a53c5e5865..77a26fd3a44ac18da443172883efaee8d66b7af7 100644 (file)
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
  *
  * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 #include <linux/module.h>
 #include <linux/platform_device.h>
index 0e6942f21a4ea0879f10ba6f192035893cff0fa9..820c7e3878f0235d7ab9b4dd966a215ec7afa5b0 100644 (file)
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Freescale i.MX drm driver
  *
  * Copyright (C) 2011 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
  */
 #include <linux/component.h>
 #include <linux/device.h>
index 3bd0f8a18e748ca4be125d02a12bc50f7fe1bebc..2c5bbe3173537346e1ea0d5c0b0f0e011ea485e7 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * i.MX drm driver - LVDS display bridge
  *
  * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
index cffd3310240e5ddec86f13a2cce9b456d0c29d1f..293dd5752583bdad9148685f88c621d8f7840aa2 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * i.MX drm driver - Television Encoder (TVEv2)
  *
  * Copyright (C) 2013 Philipp Zabel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/clk.h>
@@ -442,7 +434,7 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-static struct clk_ops clk_tve_di_ops = {
+static const struct clk_ops clk_tve_di_ops = {
        .round_rate = clk_tve_di_round_rate,
        .set_rate = clk_tve_di_set_rate,
        .recalc_rate = clk_tve_di_recalc_rate,
index 7d4b710b837ac40d90704484c4b2dc731df851bf..058b53c0aa7ecd5c308fa4b222146e57f3281db4 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * i.MX IPUv3 Graphics driver
  *
  * Copyright (C) 2011 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 #include <linux/component.h>
 #include <linux/module.h>
index 40605fdf0e338529fb040adaf15bfbde23e864f6..c390924de93d978d3acb4200c846fe6b53f753c8 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * i.MX IPUv3 DP Overlay Planes
  *
  * Copyright (C) 2013 Philipp Zabel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <drm/drmP.h>
@@ -236,9 +228,15 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane)
 
 void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
 {
+       int ret;
+
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
+       ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
+       if (ret == -ETIMEDOUT) {
+               DRM_ERROR("[PLANE:%d] IDMAC timeout\n",
+                         ipu_plane->base.base.id);
+       }
 
        if (ipu_plane->dp && disable_dp_channel)
                ipu_dp_disable_channel(ipu_plane->dp, false);
index aefd04e18f935037d3694a653b9cefb25540916c..f3ce51121dd62f967dbf011353097488bef47f7a 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * i.MX drm driver - parallel display implementation
  *
  * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/component.h>
index 3ce51d8dfe1c8964f178cf38943282712abcd10f..c28b69f485555ba4cef15a1af2c4b745530d1ea9 100644 (file)
@@ -7,6 +7,7 @@ config DRM_MESON
        select DRM_GEM_CMA_HELPER
        select VIDEOMODE_HELPERS
        select REGMAP_MMIO
+       select MESON_CANVAS
 
 config DRM_MESON_DW_HDMI
        tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
index c5c4cc362f024b449ae76bb41bf625ed022264f5..7709f2fbb9f77eda97b2e8bd607e30412cb5c9da 100644 (file)
@@ -1,5 +1,5 @@
 meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
-meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o
 
 obj-$(CONFIG_DRM_MESON) += meson-drm.o
 obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
index 08f6073d967e04ce2e0f89650f656d08d953f9aa..5de11aa7c775ec8f191c7d3bc1b740f2b1ecfb28 100644 (file)
@@ -39,6 +39,7 @@
 #define CANVAS_WIDTH_HBIT       0
 #define CANVAS_HEIGHT_BIT       9
 #define CANVAS_BLKMODE_BIT      24
+#define CANVAS_ENDIAN_BIT      26
 #define DMC_CAV_LUT_ADDR       0x50 /* 0x14 offset in data sheet */
 #define CANVAS_LUT_WR_EN        (0x2 << 8)
 #define CANVAS_LUT_RD_EN        (0x1 << 8)
@@ -47,7 +48,8 @@ void meson_canvas_setup(struct meson_drm *priv,
                        uint32_t canvas_index, uint32_t addr,
                        uint32_t stride, uint32_t height,
                        unsigned int wrap,
-                       unsigned int blkmode)
+                       unsigned int blkmode,
+                       unsigned int endian)
 {
        unsigned int val;
 
@@ -60,7 +62,8 @@ void meson_canvas_setup(struct meson_drm *priv,
                                                CANVAS_WIDTH_HBIT) |
                (height << CANVAS_HEIGHT_BIT) |
                (wrap << 22) |
-               (blkmode << CANVAS_BLKMODE_BIT));
+               (blkmode << CANVAS_BLKMODE_BIT) |
+               (endian << CANVAS_ENDIAN_BIT));
 
        regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
                        CANVAS_LUT_WR_EN | canvas_index);
index af1759da4b275327377d73bdfe7d265bf40db497..85dbf26e2826a16fcbab87060b03c08a693e30f7 100644 (file)
@@ -23,6 +23,9 @@
 #define __MESON_CANVAS_H
 
 #define MESON_CANVAS_ID_OSD1   0x4e
+#define MESON_CANVAS_ID_VD1_0  0x60
+#define MESON_CANVAS_ID_VD1_1  0x61
+#define MESON_CANVAS_ID_VD1_2  0x62
 
 /* Canvas configuration. */
 #define MESON_CANVAS_WRAP_NONE 0x00
 #define        MESON_CANVAS_BLKMODE_32x32      0x01
 #define        MESON_CANVAS_BLKMODE_64x64      0x02
 
+#define MESON_CANVAS_ENDIAN_SWAP16     0x1
+#define MESON_CANVAS_ENDIAN_SWAP32     0x3
+#define MESON_CANVAS_ENDIAN_SWAP64     0x7
+#define MESON_CANVAS_ENDIAN_SWAP128    0xf
+
 void meson_canvas_setup(struct meson_drm *priv,
                        uint32_t canvas_index, uint32_t addr,
                        uint32_t stride, uint32_t height,
                        unsigned int wrap,
-                       unsigned int blkmode);
+                       unsigned int blkmode,
+                       unsigned int endian);
 
 #endif /* __MESON_CANVAS_H */
index 191b314f9e9e5ce92284beec9f4d27f54bdcc811..75d97f1b2e8fbf08e69b289f8a383ec4fd13291e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/bitfield.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -98,6 +99,10 @@ static void meson_crtc_enable(struct drm_crtc *crtc)
        writel(crtc_state->mode.hdisplay,
               priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
 
+       /* VD1 Preblend vertical start/end */
+       writel(FIELD_PREP(GENMASK(11, 0), 2303),
+                       priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END));
+
        writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
                            priv->io_base + _REG(VPP_MISC));
 
@@ -126,13 +131,19 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
        struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
        struct meson_drm *priv = meson_crtc->priv;
 
+       DRM_DEBUG_DRIVER("\n");
+
        drm_crtc_vblank_off(crtc);
 
        priv->viu.osd1_enabled = false;
        priv->viu.osd1_commit = false;
 
+       priv->viu.vd1_enabled = false;
+       priv->viu.vd1_commit = false;
+
        /* Disable VPP Postblend */
-       writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
+       writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND |
+                           VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0,
                            priv->io_base + _REG(VPP_MISC));
 
        if (crtc->state->event && !crtc->state->active) {
@@ -172,6 +183,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
        struct meson_drm *priv = meson_crtc->priv;
 
        priv->viu.osd1_commit = true;
+       priv->viu.vd1_commit = true;
 }
 
 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
@@ -200,26 +212,37 @@ void meson_crtc_irq(struct meson_drm *priv)
                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
                writel_relaxed(priv->viu.osd1_blk0_cfg[4],
                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
-
-               /* If output is interlace, make use of the Scaler */
-               if (priv->viu.osd1_interlace) {
-                       struct drm_plane *plane = priv->primary_plane;
-                       struct drm_plane_state *state = plane->state;
-                       struct drm_rect dest = {
-                               .x1 = state->crtc_x,
-                               .y1 = state->crtc_y,
-                               .x2 = state->crtc_x + state->crtc_w,
-                               .y2 = state->crtc_y + state->crtc_h,
-                       };
-
-                       meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
-               } else
-                       meson_vpp_disable_interlace_vscaler_osd1(priv);
-
-               meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
-                          priv->viu.osd1_addr, priv->viu.osd1_stride,
-                          priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
-                          MESON_CANVAS_BLKMODE_LINEAR);
+               writel_relaxed(priv->viu.osd_sc_ctrl0,
+                               priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+               writel_relaxed(priv->viu.osd_sc_i_wh_m1,
+                               priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
+               writel_relaxed(priv->viu.osd_sc_o_h_start_end,
+                               priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
+               writel_relaxed(priv->viu.osd_sc_o_v_start_end,
+                               priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
+               writel_relaxed(priv->viu.osd_sc_v_ini_phase,
+                               priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
+               writel_relaxed(priv->viu.osd_sc_v_phase_step,
+                               priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
+               writel_relaxed(priv->viu.osd_sc_h_ini_phase,
+                               priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE));
+               writel_relaxed(priv->viu.osd_sc_h_phase_step,
+                               priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP));
+               writel_relaxed(priv->viu.osd_sc_h_ctrl0,
+                               priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+               writel_relaxed(priv->viu.osd_sc_v_ctrl0,
+                               priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+
+               if (priv->canvas)
+                       meson_canvas_config(priv->canvas, priv->canvas_id_osd1,
+                               priv->viu.osd1_addr, priv->viu.osd1_stride,
+                               priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
+                               MESON_CANVAS_BLKMODE_LINEAR, 0);
+               else
+                       meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
+                               priv->viu.osd1_addr, priv->viu.osd1_stride,
+                               priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
+                               MESON_CANVAS_BLKMODE_LINEAR, 0);
 
                /* Enable OSD1 */
                writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
@@ -228,6 +251,206 @@ void meson_crtc_irq(struct meson_drm *priv)
                priv->viu.osd1_commit = false;
        }
 
+       /* Update the VD1 registers */
+       if (priv->viu.vd1_enabled && priv->viu.vd1_commit) {
+
+               switch (priv->viu.vd1_planes) {
+               case 3:
+                       if (priv->canvas)
+                               meson_canvas_config(priv->canvas,
+                                                   priv->canvas_id_vd1_2,
+                                                   priv->viu.vd1_addr2,
+                                                   priv->viu.vd1_stride2,
+                                                   priv->viu.vd1_height2,
+                                                   MESON_CANVAS_WRAP_NONE,
+                                                   MESON_CANVAS_BLKMODE_LINEAR,
+                                                   MESON_CANVAS_ENDIAN_SWAP64);
+                       else
+                               meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2,
+                                                  priv->viu.vd1_addr2,
+                                                  priv->viu.vd1_stride2,
+                                                  priv->viu.vd1_height2,
+                                                  MESON_CANVAS_WRAP_NONE,
+                                                  MESON_CANVAS_BLKMODE_LINEAR,
+                                                  MESON_CANVAS_ENDIAN_SWAP64);
+               /* fallthrough */
+               case 2:
+                       if (priv->canvas)
+                               meson_canvas_config(priv->canvas,
+                                                   priv->canvas_id_vd1_1,
+                                                   priv->viu.vd1_addr1,
+                                                   priv->viu.vd1_stride1,
+                                                   priv->viu.vd1_height1,
+                                                   MESON_CANVAS_WRAP_NONE,
+                                                   MESON_CANVAS_BLKMODE_LINEAR,
+                                                   MESON_CANVAS_ENDIAN_SWAP64);
+                       else
+                               meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1,
+                                                  priv->viu.vd1_addr2,
+                                                  priv->viu.vd1_stride2,
+                                                  priv->viu.vd1_height2,
+                                                  MESON_CANVAS_WRAP_NONE,
+                                                  MESON_CANVAS_BLKMODE_LINEAR,
+                                                  MESON_CANVAS_ENDIAN_SWAP64);
+               /* fallthrough */
+               case 1:
+                       if (priv->canvas)
+                               meson_canvas_config(priv->canvas,
+                                                   priv->canvas_id_vd1_0,
+                                                   priv->viu.vd1_addr0,
+                                                   priv->viu.vd1_stride0,
+                                                   priv->viu.vd1_height0,
+                                                   MESON_CANVAS_WRAP_NONE,
+                                                   MESON_CANVAS_BLKMODE_LINEAR,
+                                                   MESON_CANVAS_ENDIAN_SWAP64);
+                       else
+                               meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0,
+                                                  priv->viu.vd1_addr2,
+                                                  priv->viu.vd1_stride2,
+                                                  priv->viu.vd1_height2,
+                                                  MESON_CANVAS_WRAP_NONE,
+                                                  MESON_CANVAS_BLKMODE_LINEAR,
+                                                  MESON_CANVAS_ENDIAN_SWAP64);
+               };
+
+               writel_relaxed(priv->viu.vd1_if0_gen_reg,
+                               priv->io_base + _REG(VD1_IF0_GEN_REG));
+               writel_relaxed(priv->viu.vd1_if0_gen_reg,
+                               priv->io_base + _REG(VD2_IF0_GEN_REG));
+               writel_relaxed(priv->viu.vd1_if0_gen_reg2,
+                               priv->io_base + _REG(VD1_IF0_GEN_REG2));
+               writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
+                               priv->io_base + _REG(VIU_VD1_FMT_CTRL));
+               writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
+                               priv->io_base + _REG(VIU_VD2_FMT_CTRL));
+               writel_relaxed(priv->viu.viu_vd1_fmt_w,
+                               priv->io_base + _REG(VIU_VD1_FMT_W));
+               writel_relaxed(priv->viu.viu_vd1_fmt_w,
+                               priv->io_base + _REG(VIU_VD2_FMT_W));
+               writel_relaxed(priv->viu.vd1_if0_canvas0,
+                               priv->io_base + _REG(VD1_IF0_CANVAS0));
+               writel_relaxed(priv->viu.vd1_if0_canvas0,
+                               priv->io_base + _REG(VD1_IF0_CANVAS1));
+               writel_relaxed(priv->viu.vd1_if0_canvas0,
+                               priv->io_base + _REG(VD2_IF0_CANVAS0));
+               writel_relaxed(priv->viu.vd1_if0_canvas0,
+                               priv->io_base + _REG(VD2_IF0_CANVAS1));
+               writel_relaxed(priv->viu.vd1_if0_luma_x0,
+                               priv->io_base + _REG(VD1_IF0_LUMA_X0));
+               writel_relaxed(priv->viu.vd1_if0_luma_x0,
+                               priv->io_base + _REG(VD1_IF0_LUMA_X1));
+               writel_relaxed(priv->viu.vd1_if0_luma_x0,
+                               priv->io_base + _REG(VD2_IF0_LUMA_X0));
+               writel_relaxed(priv->viu.vd1_if0_luma_x0,
+                               priv->io_base + _REG(VD2_IF0_LUMA_X1));
+               writel_relaxed(priv->viu.vd1_if0_luma_y0,
+                               priv->io_base + _REG(VD1_IF0_LUMA_Y0));
+               writel_relaxed(priv->viu.vd1_if0_luma_y0,
+                               priv->io_base + _REG(VD1_IF0_LUMA_Y1));
+               writel_relaxed(priv->viu.vd1_if0_luma_y0,
+                               priv->io_base + _REG(VD2_IF0_LUMA_Y0));
+               writel_relaxed(priv->viu.vd1_if0_luma_y0,
+                               priv->io_base + _REG(VD2_IF0_LUMA_Y1));
+               writel_relaxed(priv->viu.vd1_if0_chroma_x0,
+                               priv->io_base + _REG(VD1_IF0_CHROMA_X0));
+               writel_relaxed(priv->viu.vd1_if0_chroma_x0,
+                               priv->io_base + _REG(VD1_IF0_CHROMA_X1));
+               writel_relaxed(priv->viu.vd1_if0_chroma_x0,
+                               priv->io_base + _REG(VD2_IF0_CHROMA_X0));
+               writel_relaxed(priv->viu.vd1_if0_chroma_x0,
+                               priv->io_base + _REG(VD2_IF0_CHROMA_X1));
+               writel_relaxed(priv->viu.vd1_if0_chroma_y0,
+                               priv->io_base + _REG(VD1_IF0_CHROMA_Y0));
+               writel_relaxed(priv->viu.vd1_if0_chroma_y0,
+                               priv->io_base + _REG(VD1_IF0_CHROMA_Y1));
+               writel_relaxed(priv->viu.vd1_if0_chroma_y0,
+                               priv->io_base + _REG(VD2_IF0_CHROMA_Y0));
+               writel_relaxed(priv->viu.vd1_if0_chroma_y0,
+                               priv->io_base + _REG(VD2_IF0_CHROMA_Y1));
+               writel_relaxed(priv->viu.vd1_if0_repeat_loop,
+                               priv->io_base + _REG(VD1_IF0_RPT_LOOP));
+               writel_relaxed(priv->viu.vd1_if0_repeat_loop,
+                               priv->io_base + _REG(VD2_IF0_RPT_LOOP));
+               writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
+                               priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
+                               priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
+                               priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
+                               priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
+                               priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
+                               priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
+                               priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT));
+               writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
+                               priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT));
+               writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL));
+               writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL));
+               writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL));
+               writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL));
+               writel_relaxed(priv->viu.vd1_range_map_y,
+                               priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y));
+               writel_relaxed(priv->viu.vd1_range_map_cb,
+                               priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB));
+               writel_relaxed(priv->viu.vd1_range_map_cr,
+                               priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR));
+               writel_relaxed(0x78404,
+                               priv->io_base + _REG(VPP_SC_MISC));
+               writel_relaxed(priv->viu.vpp_pic_in_height,
+                               priv->io_base + _REG(VPP_PIC_IN_HEIGHT));
+               writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end,
+                       priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END));
+               writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end,
+                       priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
+               writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end,
+                       priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END));
+               writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end,
+                       priv->io_base + _REG(VPP_BLEND_VD2_V_START_END));
+               writel_relaxed(priv->viu.vpp_hsc_region12_startp,
+                               priv->io_base + _REG(VPP_HSC_REGION12_STARTP));
+               writel_relaxed(priv->viu.vpp_hsc_region34_startp,
+                               priv->io_base + _REG(VPP_HSC_REGION34_STARTP));
+               writel_relaxed(priv->viu.vpp_hsc_region4_endp,
+                               priv->io_base + _REG(VPP_HSC_REGION4_ENDP));
+               writel_relaxed(priv->viu.vpp_hsc_start_phase_step,
+                               priv->io_base + _REG(VPP_HSC_START_PHASE_STEP));
+               writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope,
+                       priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE));
+               writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope,
+                       priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE));
+               writel_relaxed(priv->viu.vpp_line_in_length,
+                               priv->io_base + _REG(VPP_LINE_IN_LENGTH));
+               writel_relaxed(priv->viu.vpp_preblend_h_size,
+                               priv->io_base + _REG(VPP_PREBLEND_H_SIZE));
+               writel_relaxed(priv->viu.vpp_vsc_region12_startp,
+                               priv->io_base + _REG(VPP_VSC_REGION12_STARTP));
+               writel_relaxed(priv->viu.vpp_vsc_region34_startp,
+                               priv->io_base + _REG(VPP_VSC_REGION34_STARTP));
+               writel_relaxed(priv->viu.vpp_vsc_region4_endp,
+                               priv->io_base + _REG(VPP_VSC_REGION4_ENDP));
+               writel_relaxed(priv->viu.vpp_vsc_start_phase_step,
+                               priv->io_base + _REG(VPP_VSC_START_PHASE_STEP));
+               writel_relaxed(priv->viu.vpp_vsc_ini_phase,
+                               priv->io_base + _REG(VPP_VSC_INI_PHASE));
+               writel_relaxed(priv->viu.vpp_vsc_phase_ctrl,
+                               priv->io_base + _REG(VPP_VSC_PHASE_CTRL));
+               writel_relaxed(priv->viu.vpp_hsc_phase_ctrl,
+                               priv->io_base + _REG(VPP_HSC_PHASE_CTRL));
+               writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX));
+
+               /* Enable VD1 */
+               writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
+                                   VPP_COLOR_MNG_ENABLE,
+                                   VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
+                                   VPP_COLOR_MNG_ENABLE,
+                                   priv->io_base + _REG(VPP_MISC));
+
+               priv->viu.vd1_commit = false;
+       }
+
        drm_crtc_handle_vblank(priv->crtc);
 
        spin_lock_irqsave(&priv->drm->event_lock, flags);
index d3443125e66164a863fb41bfdb435a1ce13340b6..3ee4d4a4ecbae1e59c1fb5e0dfb873b24bf4497c 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "meson_drv.h"
 #include "meson_plane.h"
+#include "meson_overlay.h"
 #include "meson_crtc.h"
 #include "meson_venc_cvbs.h"
 
  * - Powering Up HDMI controller and PHY
  */
 
-static void meson_fb_output_poll_changed(struct drm_device *dev)
-{
-       struct meson_drm *priv = dev->dev_private;
-
-       drm_fbdev_cma_hotplug_event(priv->fbdev);
-}
-
 static const struct drm_mode_config_funcs meson_mode_config_funcs = {
-       .output_poll_changed = meson_fb_output_poll_changed,
        .atomic_check        = drm_atomic_helper_check,
        .atomic_commit       = drm_atomic_helper_commit,
        .fb_create           = drm_gem_fb_create,
@@ -216,24 +209,51 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
                goto free_drm;
        }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
-       if (!res) {
-               ret = -EINVAL;
-               goto free_drm;
-       }
-       /* Simply ioremap since it may be a shared register zone */
-       regs = devm_ioremap(dev, res->start, resource_size(res));
-       if (!regs) {
-               ret = -EADDRNOTAVAIL;
-               goto free_drm;
-       }
+       priv->canvas = meson_canvas_get(dev);
+       if (!IS_ERR(priv->canvas)) {
+               ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
+               if (ret)
+                       goto free_drm;
+               ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
+               if (ret) {
+                       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
+                       goto free_drm;
+               }
+               ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1);
+               if (ret) {
+                       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
+                       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
+                       goto free_drm;
+               }
+               ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2);
+               if (ret) {
+                       meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
+                       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
+                       meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
+                       goto free_drm;
+               }
+       } else {
+               priv->canvas = NULL;
 
-       priv->dmc = devm_regmap_init_mmio(dev, regs,
-                                         &meson_regmap_config);
-       if (IS_ERR(priv->dmc)) {
-               dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
-               ret = PTR_ERR(priv->dmc);
-               goto free_drm;
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
+               if (!res) {
+                       ret = -EINVAL;
+                       goto free_drm;
+               }
+               /* Simply ioremap since it may be a shared register zone */
+               regs = devm_ioremap(dev, res->start, resource_size(res));
+               if (!regs) {
+                       ret = -EADDRNOTAVAIL;
+                       goto free_drm;
+               }
+
+               priv->dmc = devm_regmap_init_mmio(dev, regs,
+                                                 &meson_regmap_config);
+               if (IS_ERR(priv->dmc)) {
+                       dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
+                       ret = PTR_ERR(priv->dmc);
+                       goto free_drm;
+               }
        }
 
        priv->vsync_irq = platform_get_irq(pdev, 0);
@@ -272,6 +292,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
        if (ret)
                goto free_drm;
 
+       ret = meson_overlay_create(priv);
+       if (ret)
+               goto free_drm;
+
        ret = meson_crtc_create(priv);
        if (ret)
                goto free_drm;
@@ -282,13 +306,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
        drm_mode_config_reset(drm);
 
-       priv->fbdev = drm_fbdev_cma_init(drm, 32,
-                                        drm->mode_config.num_connector);
-       if (IS_ERR(priv->fbdev)) {
-               ret = PTR_ERR(priv->fbdev);
-               goto free_drm;
-       }
-
        drm_kms_helper_poll_init(drm);
 
        platform_set_drvdata(pdev, priv);
@@ -297,6 +314,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
        if (ret)
                goto free_drm;
 
+       drm_fbdev_generic_setup(drm, 32);
+
        return 0;
 
 free_drm:
@@ -315,9 +334,15 @@ static void meson_drv_unbind(struct device *dev)
        struct drm_device *drm = dev_get_drvdata(dev);
        struct meson_drm *priv = drm->dev_private;
 
+       if (priv->canvas) {
+               meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
+               meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
+               meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
+               meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2);
+       }
+
        drm_dev_unregister(drm);
        drm_kms_helper_poll_fini(drm);
-       drm_fbdev_cma_fini(priv->fbdev);
        drm_mode_config_cleanup(drm);
        drm_dev_put(drm);
 
index 8450d6ac8c9bc1dcd049fd8c2205d1c5a8c7c924..4dccf4cd042a58010c78c2f3f0db1195501f22ff 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
+#include <linux/soc/amlogic/meson-canvas.h>
 #include <drm/drmP.h>
 
 struct meson_drm {
@@ -31,10 +32,16 @@ struct meson_drm {
        struct regmap *dmc;
        int vsync_irq;
 
+       struct meson_canvas *canvas;
+       u8 canvas_id_osd1;
+       u8 canvas_id_vd1_0;
+       u8 canvas_id_vd1_1;
+       u8 canvas_id_vd1_2;
+
        struct drm_device *drm;
        struct drm_crtc *crtc;
-       struct drm_fbdev_cma *fbdev;
        struct drm_plane *primary_plane;
+       struct drm_plane *overlay_plane;
 
        /* Components Data */
        struct {
@@ -46,6 +53,64 @@ struct meson_drm {
                uint32_t osd1_addr;
                uint32_t osd1_stride;
                uint32_t osd1_height;
+               uint32_t osd_sc_ctrl0;
+               uint32_t osd_sc_i_wh_m1;
+               uint32_t osd_sc_o_h_start_end;
+               uint32_t osd_sc_o_v_start_end;
+               uint32_t osd_sc_v_ini_phase;
+               uint32_t osd_sc_v_phase_step;
+               uint32_t osd_sc_h_ini_phase;
+               uint32_t osd_sc_h_phase_step;
+               uint32_t osd_sc_h_ctrl0;
+               uint32_t osd_sc_v_ctrl0;
+
+               bool vd1_enabled;
+               bool vd1_commit;
+               unsigned int vd1_planes;
+               uint32_t vd1_if0_gen_reg;
+               uint32_t vd1_if0_luma_x0;
+               uint32_t vd1_if0_luma_y0;
+               uint32_t vd1_if0_chroma_x0;
+               uint32_t vd1_if0_chroma_y0;
+               uint32_t vd1_if0_repeat_loop;
+               uint32_t vd1_if0_luma0_rpt_pat;
+               uint32_t vd1_if0_chroma0_rpt_pat;
+               uint32_t vd1_range_map_y;
+               uint32_t vd1_range_map_cb;
+               uint32_t vd1_range_map_cr;
+               uint32_t viu_vd1_fmt_w;
+               uint32_t vd1_if0_canvas0;
+               uint32_t vd1_if0_gen_reg2;
+               uint32_t viu_vd1_fmt_ctrl;
+               uint32_t vd1_addr0;
+               uint32_t vd1_addr1;
+               uint32_t vd1_addr2;
+               uint32_t vd1_stride0;
+               uint32_t vd1_stride1;
+               uint32_t vd1_stride2;
+               uint32_t vd1_height0;
+               uint32_t vd1_height1;
+               uint32_t vd1_height2;
+               uint32_t vpp_pic_in_height;
+               uint32_t vpp_postblend_vd1_h_start_end;
+               uint32_t vpp_postblend_vd1_v_start_end;
+               uint32_t vpp_hsc_region12_startp;
+               uint32_t vpp_hsc_region34_startp;
+               uint32_t vpp_hsc_region4_endp;
+               uint32_t vpp_hsc_start_phase_step;
+               uint32_t vpp_hsc_region1_phase_slope;
+               uint32_t vpp_hsc_region3_phase_slope;
+               uint32_t vpp_line_in_length;
+               uint32_t vpp_preblend_h_size;
+               uint32_t vpp_vsc_region12_startp;
+               uint32_t vpp_vsc_region34_startp;
+               uint32_t vpp_vsc_region4_endp;
+               uint32_t vpp_vsc_start_phase_step;
+               uint32_t vpp_vsc_ini_phase;
+               uint32_t vpp_vsc_phase_ctrl;
+               uint32_t vpp_hsc_phase_ctrl;
+               uint32_t vpp_blend_vd2_h_start_end;
+               uint32_t vpp_blend_vd2_v_start_end;
        } viu;
 
        struct {
index 2cb2ad26d71670c387b144dc34668567f1fa9c34..807111ebfdd97785ac2b6855a1af14dc5067a8f9 100644 (file)
@@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
        dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
                vclk_freq, venc_freq, hdmi_freq);
 
-       /* Finally filter by configurable vclk frequencies for VIC modes */
-       switch (vclk_freq) {
-       case 54000:
-       case 74250:
-       case 148500:
-       case 297000:
-       case 594000:
-               return MODE_OK;
-       }
-
-       return MODE_CLOCK_RANGE;
+       return meson_vclk_vic_supported_freq(vclk_freq);
 }
 
 /* Encoder */
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
new file mode 100644 (file)
index 0000000..691a9fd
--- /dev/null
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/bitfield.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_rect.h>
+
+#include "meson_overlay.h"
+#include "meson_vpp.h"
+#include "meson_viu.h"
+#include "meson_canvas.h"
+#include "meson_registers.h"
+
+/* VD1_IF0_GEN_REG */
+#define VD_URGENT_CHROMA               BIT(28)
+#define VD_URGENT_LUMA                 BIT(27)
+#define VD_HOLD_LINES(lines)           FIELD_PREP(GENMASK(24, 19), lines)
+#define VD_DEMUX_MODE_RGB              BIT(16)
+#define VD_BYTES_PER_PIXEL(val)                FIELD_PREP(GENMASK(15, 14), val)
+#define VD_CHRO_RPT_LASTL_CTRL         BIT(6)
+#define VD_LITTLE_ENDIAN               BIT(4)
+#define VD_SEPARATE_EN                 BIT(1)
+#define VD_ENABLE                      BIT(0)
+
+/* VD1_IF0_CANVAS0 */
+#define CANVAS_ADDR2(addr)             FIELD_PREP(GENMASK(23, 16), addr)
+#define CANVAS_ADDR1(addr)             FIELD_PREP(GENMASK(15, 8), addr)
+#define CANVAS_ADDR0(addr)             FIELD_PREP(GENMASK(7, 0), addr)
+
+/* VD1_IF0_LUMA_X0 VD1_IF0_CHROMA_X0 */
+#define VD_X_START(value)              FIELD_PREP(GENMASK(14, 0), value)
+#define VD_X_END(value)                        FIELD_PREP(GENMASK(30, 16), value)
+
+/* VD1_IF0_LUMA_Y0 VD1_IF0_CHROMA_Y0 */
+#define VD_Y_START(value)              FIELD_PREP(GENMASK(12, 0), value)
+#define VD_Y_END(value)                        FIELD_PREP(GENMASK(28, 16), value)
+
+/* VD1_IF0_GEN_REG2 */
+#define VD_COLOR_MAP(value)            FIELD_PREP(GENMASK(1, 0), value)
+
+/* VIU_VD1_FMT_CTRL */
+#define VD_HORZ_Y_C_RATIO(value)       FIELD_PREP(GENMASK(22, 21), value)
+#define VD_HORZ_FMT_EN                 BIT(20)
+#define VD_VERT_RPT_LINE0              BIT(16)
+#define VD_VERT_INITIAL_PHASE(value)   FIELD_PREP(GENMASK(11, 8), value)
+#define VD_VERT_PHASE_STEP(value)      FIELD_PREP(GENMASK(7, 1), value)
+#define VD_VERT_FMT_EN                 BIT(0)
+
+/* VPP_POSTBLEND_VD1_H_START_END */
+#define VD_H_END(value)                        FIELD_PREP(GENMASK(11, 0), value)
+#define VD_H_START(value)              FIELD_PREP(GENMASK(27, 16), value)
+
+/* VPP_POSTBLEND_VD1_V_START_END */
+#define VD_V_END(value)                        FIELD_PREP(GENMASK(11, 0), value)
+#define VD_V_START(value)              FIELD_PREP(GENMASK(27, 16), value)
+
+/* VPP_BLEND_VD2_V_START_END */
+#define VD2_V_END(value)               FIELD_PREP(GENMASK(11, 0), value)
+#define VD2_V_START(value)             FIELD_PREP(GENMASK(27, 16), value)
+
+/* VIU_VD1_FMT_W */
+#define VD_V_WIDTH(value)              FIELD_PREP(GENMASK(11, 0), value)
+#define VD_H_WIDTH(value)              FIELD_PREP(GENMASK(27, 16), value)
+
+/* VPP_HSC_REGION12_STARTP VPP_HSC_REGION34_STARTP */
+#define VD_REGION24_START(value)       FIELD_PREP(GENMASK(11, 0), value)
+#define VD_REGION13_END(value)         FIELD_PREP(GENMASK(27, 16), value)
+
+struct meson_overlay {
+       struct drm_plane base;
+       struct meson_drm *priv;
+};
+#define to_meson_overlay(x) container_of(x, struct meson_overlay, base)
+
+#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
+
+static int meson_overlay_atomic_check(struct drm_plane *plane,
+                                     struct drm_plane_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+
+       if (!state->crtc)
+               return 0;
+
+       crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+       if (IS_ERR(crtc_state))
+               return PTR_ERR(crtc_state);
+
+       return drm_atomic_helper_check_plane_state(state, crtc_state,
+                                                  FRAC_16_16(1, 5),
+                                                  FRAC_16_16(5, 1),
+                                                  true, true);
+}
+
+/* Takes a fixed 16.16 number and converts it to integer. */
+static inline int64_t fixed16_to_int(int64_t value)
+{
+       return value >> 16;
+}
+
+static const uint8_t skip_tab[6] = {
+       0x24, 0x04, 0x68, 0x48, 0x28, 0x08,
+};
+
+static void meson_overlay_get_vertical_phase(unsigned int ratio_y, int *phase,
+                                            int *repeat, bool interlace)
+{
+       int offset_in = 0;
+       int offset_out = 0;
+       int repeat_skip = 0;
+
+       if (!interlace && ratio_y > (1 << 18))
+               offset_out = (1 * ratio_y) >> 10;
+
+       while ((offset_in + (4 << 8)) <= offset_out) {
+               repeat_skip++;
+               offset_in += 4 << 8;
+       }
+
+       *phase = (offset_out - offset_in) >> 2;
+
+       if (*phase > 0x100)
+               repeat_skip++;
+
+       *phase = *phase & 0xff;
+
+       if (repeat_skip > 5)
+               repeat_skip = 5;
+
+       *repeat = skip_tab[repeat_skip];
+}
+
+static void meson_overlay_setup_scaler_params(struct meson_drm *priv,
+                                             struct drm_plane *plane,
+                                             bool interlace_mode)
+{
+       struct drm_crtc_state *crtc_state = priv->crtc->state;
+       int video_top, video_left, video_width, video_height;
+       struct drm_plane_state *state = plane->state;
+       unsigned int vd_start_lines, vd_end_lines;
+       unsigned int hd_start_lines, hd_end_lines;
+       unsigned int crtc_height, crtc_width;
+       unsigned int vsc_startp, vsc_endp;
+       unsigned int hsc_startp, hsc_endp;
+       unsigned int crop_top, crop_left;
+       int vphase, vphase_repeat_skip;
+       unsigned int ratio_x, ratio_y;
+       int temp_height, temp_width;
+       unsigned int w_in, h_in;
+       int temp, start, end;
+
+       if (!crtc_state) {
+               DRM_ERROR("Invalid crtc_state\n");
+               return;
+       }
+
+       crtc_height = crtc_state->mode.vdisplay;
+       crtc_width = crtc_state->mode.hdisplay;
+
+       w_in = fixed16_to_int(state->src_w);
+       h_in = fixed16_to_int(state->src_h);
+       crop_top = fixed16_to_int(state->src_x);
+       crop_left = fixed16_to_int(state->src_x);
+
+       video_top = state->crtc_y;
+       video_left = state->crtc_x;
+       video_width = state->crtc_w;
+       video_height = state->crtc_h;
+
+       DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n",
+                 crtc_width, crtc_height, interlace_mode);
+       DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n",
+                 w_in, h_in, crop_top, crop_left);
+       DRM_DEBUG("video top %d left %d width %d height %d\n",
+                 video_top, video_left, video_width, video_height);
+
+       ratio_x = (w_in << 18) / video_width;
+       ratio_y = (h_in << 18) / video_height;
+
+       if (ratio_x * video_width < (w_in << 18))
+               ratio_x++;
+
+       DRM_DEBUG("ratio x 0x%x y 0x%x\n", ratio_x, ratio_y);
+
+       meson_overlay_get_vertical_phase(ratio_y, &vphase, &vphase_repeat_skip,
+                                        interlace_mode);
+
+       DRM_DEBUG("vphase 0x%x skip %d\n", vphase, vphase_repeat_skip);
+
+       /* Vertical */
+
+       start = video_top + video_height / 2 - ((h_in << 17) / ratio_y);
+       end = (h_in << 18) / ratio_y + start - 1;
+
+       if (video_top < 0 && start < 0)
+               vd_start_lines = (-(start) * ratio_y) >> 18;
+       else if (start < video_top)
+               vd_start_lines = ((video_top - start) * ratio_y) >> 18;
+       else
+               vd_start_lines = 0;
+
+       if (video_top < 0)
+               temp_height = min_t(unsigned int,
+                                   video_top + video_height - 1,
+                                   crtc_height - 1);
+       else
+               temp_height = min_t(unsigned int,
+                                   video_top + video_height - 1,
+                                   crtc_height - 1) - video_top + 1;
+
+       temp = vd_start_lines + (temp_height * ratio_y >> 18);
+       vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1);
+
+       vd_start_lines += crop_left;
+       vd_end_lines += crop_left;
+
+       /*
+        * TOFIX: Input frames are handled and scaled like progressive frames,
+        * proper handling of interlaced field input frames need to be figured
+        * out using the proper framebuffer flags set by userspace.
+        */
+       if (interlace_mode) {
+               start >>= 1;
+               end >>= 1;
+       }
+
+       vsc_startp = max_t(int, start,
+                          max_t(int, 0, video_top));
+       vsc_endp = min_t(int, end,
+                        min_t(int, crtc_height - 1,
+                              video_top + video_height - 1));
+
+       DRM_DEBUG("vsc startp %d endp %d start_lines %d end_lines %d\n",
+                vsc_startp, vsc_endp, vd_start_lines, vd_end_lines);
+
+       /* Horizontal */
+
+       start = video_left + video_width / 2 - ((w_in << 17) / ratio_x);
+       end = (w_in << 18) / ratio_x + start - 1;
+
+       if (video_left < 0 && start < 0)
+               hd_start_lines = (-(start) * ratio_x) >> 18;
+       else if (start < video_left)
+               hd_start_lines = ((video_left - start) * ratio_x) >> 18;
+       else
+               hd_start_lines = 0;
+
+       if (video_left < 0)
+               temp_width = min_t(unsigned int,
+                                  video_left + video_width - 1,
+                                  crtc_width - 1);
+       else
+               temp_width = min_t(unsigned int,
+                                  video_left + video_width - 1,
+                                  crtc_width - 1) - video_left + 1;
+
+       temp = hd_start_lines + (temp_width * ratio_x >> 18);
+       hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1);
+
+       priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
+       hsc_startp = max_t(int, start, max_t(int, 0, video_left));
+       hsc_endp = min_t(int, end, min_t(int, crtc_width - 1,
+                                        video_left + video_width - 1));
+
+       hd_start_lines += crop_top;
+       hd_end_lines += crop_top;
+
+       DRM_DEBUG("hsc startp %d endp %d start_lines %d end_lines %d\n",
+                hsc_startp, hsc_endp, hd_start_lines, hd_end_lines);
+
+       priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
+
+       priv->viu.vpp_vsc_ini_phase = vphase << 8;
+       priv->viu.vpp_vsc_phase_ctrl = (1 << 13) | (4 << 8) |
+                                      vphase_repeat_skip;
+
+       priv->viu.vd1_if0_luma_x0 = VD_X_START(hd_start_lines) |
+                                   VD_X_END(hd_end_lines);
+       priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) |
+                                     VD_X_END(hd_end_lines >> 1);
+
+       priv->viu.viu_vd1_fmt_w =
+                       VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
+                       VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
+
+       priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) |
+                                   VD_Y_END(vd_end_lines);
+
+       priv->viu.vd1_if0_chroma_y0 = VD_Y_START(vd_start_lines >> 1) |
+                                     VD_Y_END(vd_end_lines >> 1);
+
+       priv->viu.vpp_pic_in_height = h_in;
+
+       priv->viu.vpp_postblend_vd1_h_start_end = VD_H_START(hsc_startp) |
+                                                 VD_H_END(hsc_endp);
+       priv->viu.vpp_blend_vd2_h_start_end = VD_H_START(hd_start_lines) |
+                                             VD_H_END(hd_end_lines);
+       priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) |
+                                           VD_REGION24_START(hsc_startp);
+       priv->viu.vpp_hsc_region34_startp =
+                               VD_REGION13_END(hsc_startp) |
+                               VD_REGION24_START(hsc_endp - hsc_startp);
+       priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp;
+       priv->viu.vpp_hsc_start_phase_step = ratio_x << 6;
+       priv->viu.vpp_hsc_region1_phase_slope = 0;
+       priv->viu.vpp_hsc_region3_phase_slope = 0;
+       priv->viu.vpp_hsc_phase_ctrl = (1 << 21) | (4 << 16);
+
+       priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
+       priv->viu.vpp_preblend_h_size = hd_end_lines - hd_start_lines + 1;
+
+       priv->viu.vpp_postblend_vd1_v_start_end = VD_V_START(vsc_startp) |
+                                                 VD_V_END(vsc_endp);
+       priv->viu.vpp_blend_vd2_v_start_end =
+                               VD2_V_START((vd_end_lines + 1) >> 1) |
+                               VD2_V_END(vd_end_lines);
+
+       priv->viu.vpp_vsc_region12_startp = 0;
+       priv->viu.vpp_vsc_region34_startp =
+                               VD_REGION13_END(vsc_endp - vsc_startp) |
+                               VD_REGION24_START(vsc_endp - vsc_startp);
+       priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp;
+       priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
+}
+
+static void meson_overlay_atomic_update(struct drm_plane *plane,
+                                       struct drm_plane_state *old_state)
+{
+       struct meson_overlay *meson_overlay = to_meson_overlay(plane);
+       struct drm_plane_state *state = plane->state;
+       struct drm_framebuffer *fb = state->fb;
+       struct meson_drm *priv = meson_overlay->priv;
+       struct drm_gem_cma_object *gem;
+       unsigned long flags;
+       bool interlace_mode;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       /* Fallback is canvas provider is not available */
+       if (!priv->canvas) {
+               priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0;
+               priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1;
+               priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2;
+       }
+
+       interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
+       spin_lock_irqsave(&priv->drm->event_lock, flags);
+
+       priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA |
+                                   VD_URGENT_LUMA |
+                                   VD_HOLD_LINES(9) |
+                                   VD_CHRO_RPT_LASTL_CTRL |
+                                   VD_ENABLE;
+
+       /* Setup scaler params */
+       meson_overlay_setup_scaler_params(priv, plane, interlace_mode);
+
+       priv->viu.vd1_if0_repeat_loop = 0;
+       priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0;
+       priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0;
+       priv->viu.vd1_range_map_y = 0;
+       priv->viu.vd1_range_map_cb = 0;
+       priv->viu.vd1_range_map_cr = 0;
+
+       /* Default values for RGB888/YUV444 */
+       priv->viu.vd1_if0_gen_reg2 = 0;
+       priv->viu.viu_vd1_fmt_ctrl = 0;
+
+       switch (fb->format->format) {
+       /* TOFIX DRM_FORMAT_RGB888 should be supported */
+       case DRM_FORMAT_YUYV:
+               priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1);
+               priv->viu.vd1_if0_canvas0 =
+                                       CANVAS_ADDR2(priv->canvas_id_vd1_0) |
+                                       CANVAS_ADDR1(priv->canvas_id_vd1_0) |
+                                       CANVAS_ADDR0(priv->canvas_id_vd1_0);
+               priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
+                                            VD_HORZ_FMT_EN |
+                                            VD_VERT_RPT_LINE0 |
+                                            VD_VERT_INITIAL_PHASE(12) |
+                                            VD_VERT_PHASE_STEP(16) | /* /2 */
+                                            VD_VERT_FMT_EN;
+               break;
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
+               priv->viu.vd1_if0_canvas0 =
+                                       CANVAS_ADDR2(priv->canvas_id_vd1_1) |
+                                       CANVAS_ADDR1(priv->canvas_id_vd1_1) |
+                                       CANVAS_ADDR0(priv->canvas_id_vd1_0);
+               if (fb->format->format == DRM_FORMAT_NV12)
+                       priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(1);
+               else
+                       priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(2);
+               priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
+                                            VD_HORZ_FMT_EN |
+                                            VD_VERT_RPT_LINE0 |
+                                            VD_VERT_INITIAL_PHASE(12) |
+                                            VD_VERT_PHASE_STEP(8) | /* /4 */
+                                            VD_VERT_FMT_EN;
+               break;
+       case DRM_FORMAT_YUV444:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YUV410:
+               priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
+               priv->viu.vd1_if0_canvas0 =
+                                       CANVAS_ADDR2(priv->canvas_id_vd1_2) |
+                                       CANVAS_ADDR1(priv->canvas_id_vd1_1) |
+                                       CANVAS_ADDR0(priv->canvas_id_vd1_0);
+               switch (fb->format->format) {
+               case DRM_FORMAT_YUV422:
+                       priv->viu.viu_vd1_fmt_ctrl =
+                                       VD_HORZ_Y_C_RATIO(1) | /* /2 */
+                                       VD_HORZ_FMT_EN |
+                                       VD_VERT_RPT_LINE0 |
+                                       VD_VERT_INITIAL_PHASE(12) |
+                                       VD_VERT_PHASE_STEP(16) | /* /2 */
+                                       VD_VERT_FMT_EN;
+                       break;
+               case DRM_FORMAT_YUV420:
+                       priv->viu.viu_vd1_fmt_ctrl =
+                                       VD_HORZ_Y_C_RATIO(1) | /* /2 */
+                                       VD_HORZ_FMT_EN |
+                                       VD_VERT_RPT_LINE0 |
+                                       VD_VERT_INITIAL_PHASE(12) |
+                                       VD_VERT_PHASE_STEP(8) | /* /4 */
+                                       VD_VERT_FMT_EN;
+                       break;
+               case DRM_FORMAT_YUV411:
+                       priv->viu.viu_vd1_fmt_ctrl =
+                                       VD_HORZ_Y_C_RATIO(2) | /* /4 */
+                                       VD_HORZ_FMT_EN |
+                                       VD_VERT_RPT_LINE0 |
+                                       VD_VERT_INITIAL_PHASE(12) |
+                                       VD_VERT_PHASE_STEP(16) | /* /2 */
+                                       VD_VERT_FMT_EN;
+                       break;
+               case DRM_FORMAT_YUV410:
+                       priv->viu.viu_vd1_fmt_ctrl =
+                                       VD_HORZ_Y_C_RATIO(2) | /* /4 */
+                                       VD_HORZ_FMT_EN |
+                                       VD_VERT_RPT_LINE0 |
+                                       VD_VERT_INITIAL_PHASE(12) |
+                                       VD_VERT_PHASE_STEP(8) | /* /4 */
+                                       VD_VERT_FMT_EN;
+                       break;
+               }
+               break;
+       }
+
+       /* Update Canvas with buffer address */
+       priv->viu.vd1_planes = drm_format_num_planes(fb->format->format);
+
+       switch (priv->viu.vd1_planes) {
+       case 3:
+               gem = drm_fb_cma_get_gem_obj(fb, 2);
+               priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2];
+               priv->viu.vd1_stride2 = fb->pitches[2];
+               priv->viu.vd1_height2 =
+                       drm_format_plane_height(fb->height,
+                                               fb->format->format, 2);
+               DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n",
+                        priv->viu.vd1_addr2,
+                        priv->viu.vd1_stride2,
+                        priv->viu.vd1_height2);
+       /* fallthrough */
+       case 2:
+               gem = drm_fb_cma_get_gem_obj(fb, 1);
+               priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1];
+               priv->viu.vd1_stride1 = fb->pitches[1];
+               priv->viu.vd1_height1 =
+                       drm_format_plane_height(fb->height,
+                                               fb->format->format, 1);
+               DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n",
+                        priv->viu.vd1_addr1,
+                        priv->viu.vd1_stride1,
+                        priv->viu.vd1_height1);
+       /* fallthrough */
+       case 1:
+               gem = drm_fb_cma_get_gem_obj(fb, 0);
+               priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0];
+               priv->viu.vd1_stride0 = fb->pitches[0];
+               priv->viu.vd1_height0 =
+                       drm_format_plane_height(fb->height,
+                                               fb->format->format, 0);
+               DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n",
+                        priv->viu.vd1_addr0,
+                        priv->viu.vd1_stride0,
+                        priv->viu.vd1_height0);
+       }
+
+       priv->viu.vd1_enabled = true;
+
+       spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+
+       DRM_DEBUG_DRIVER("\n");
+}
+
+static void meson_overlay_atomic_disable(struct drm_plane *plane,
+                                      struct drm_plane_state *old_state)
+{
+       struct meson_overlay *meson_overlay = to_meson_overlay(plane);
+       struct meson_drm *priv = meson_overlay->priv;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       priv->viu.vd1_enabled = false;
+
+       /* Disable VD1 */
+       writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0,
+                           priv->io_base + _REG(VPP_MISC));
+
+}
+
+static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {
+       .atomic_check   = meson_overlay_atomic_check,
+       .atomic_disable = meson_overlay_atomic_disable,
+       .atomic_update  = meson_overlay_atomic_update,
+       .prepare_fb     = drm_gem_fb_prepare_fb,
+};
+
+static const struct drm_plane_funcs meson_overlay_funcs = {
+       .update_plane           = drm_atomic_helper_update_plane,
+       .disable_plane          = drm_atomic_helper_disable_plane,
+       .destroy                = drm_plane_cleanup,
+       .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 const uint32_t supported_drm_formats[] = {
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_YUV444,
+       DRM_FORMAT_YUV422,
+       DRM_FORMAT_YUV420,
+       DRM_FORMAT_YUV411,
+       DRM_FORMAT_YUV410,
+};
+
+int meson_overlay_create(struct meson_drm *priv)
+{
+       struct meson_overlay *meson_overlay;
+       struct drm_plane *plane;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
+                                  GFP_KERNEL);
+       if (!meson_overlay)
+               return -ENOMEM;
+
+       meson_overlay->priv = priv;
+       plane = &meson_overlay->base;
+
+       drm_universal_plane_init(priv->drm, plane, 0xFF,
+                                &meson_overlay_funcs,
+                                supported_drm_formats,
+                                ARRAY_SIZE(supported_drm_formats),
+                                NULL,
+                                DRM_PLANE_TYPE_OVERLAY, "meson_overlay_plane");
+
+       drm_plane_helper_add(plane, &meson_overlay_helper_funcs);
+
+       priv->overlay_plane = plane;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/meson/meson_overlay.h b/drivers/gpu/drm/meson/meson_overlay.h
new file mode 100644 (file)
index 0000000..dae24f5
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef __MESON_OVERLAY_H
+#define __MESON_OVERLAY_H
+
+#include "meson_drv.h"
+
+int meson_overlay_create(struct meson_drm *priv);
+
+#endif /* __MESON_OVERLAY_H */
index 12c80dfcff59bc9cb40d2e4ccbf2dbb98b6af3a5..6119a02242788e051905251920ace61aa9b23df1 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/bitfield.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -31,6 +32,7 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_rect.h>
 
 #include "meson_plane.h"
 #include "meson_canvas.h"
 #include "meson_registers.h"
 
+/* OSD_SCI_WH_M1 */
+#define SCI_WH_M1_W(w)                 FIELD_PREP(GENMASK(28, 16), w)
+#define SCI_WH_M1_H(h)                 FIELD_PREP(GENMASK(12, 0), h)
+
+/* OSD_SCO_H_START_END */
+/* OSD_SCO_V_START_END */
+#define SCO_HV_START(start)            FIELD_PREP(GENMASK(27, 16), start)
+#define SCO_HV_END(end)                        FIELD_PREP(GENMASK(11, 0), end)
+
+/* OSD_SC_CTRL0 */
+#define SC_CTRL0_PATH_EN               BIT(3)
+#define SC_CTRL0_SEL_OSD1              BIT(2)
+
+/* OSD_VSC_CTRL0 */
+#define VSC_BANK_LEN(value)            FIELD_PREP(GENMASK(2, 0), value)
+#define VSC_TOP_INI_RCV_NUM(value)     FIELD_PREP(GENMASK(6, 3), value)
+#define VSC_TOP_RPT_L0_NUM(value)      FIELD_PREP(GENMASK(9, 8), value)
+#define VSC_BOT_INI_RCV_NUM(value)     FIELD_PREP(GENMASK(14, 11), value)
+#define VSC_BOT_RPT_L0_NUM(value)      FIELD_PREP(GENMASK(17, 16), value)
+#define VSC_PROG_INTERLACE             BIT(23)
+#define VSC_VERTICAL_SCALER_EN         BIT(24)
+
+/* OSD_VSC_INI_PHASE */
+#define VSC_INI_PHASE_BOT(bottom)      FIELD_PREP(GENMASK(31, 16), bottom)
+#define VSC_INI_PHASE_TOP(top)         FIELD_PREP(GENMASK(15, 0), top)
+
+/* OSD_HSC_CTRL0 */
+#define HSC_BANK_LENGTH(value)         FIELD_PREP(GENMASK(2, 0), value)
+#define HSC_INI_RCV_NUM0(value)                FIELD_PREP(GENMASK(6, 3), value)
+#define HSC_RPT_P0_NUM0(value)         FIELD_PREP(GENMASK(9, 8), value)
+#define HSC_HORIZ_SCALER_EN            BIT(22)
+
+/* VPP_OSD_VSC_PHASE_STEP */
+/* VPP_OSD_HSC_PHASE_STEP */
+#define SC_PHASE_STEP(value)           FIELD_PREP(GENMASK(27, 0), value)
+
 struct meson_plane {
        struct drm_plane base;
        struct meson_drm *priv;
+       bool enabled;
 };
 #define to_meson_plane(x) container_of(x, struct meson_plane, base)
 
+#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
+
 static int meson_plane_atomic_check(struct drm_plane *plane,
                                    struct drm_plane_state *state)
 {
@@ -57,10 +98,15 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
        if (IS_ERR(crtc_state))
                return PTR_ERR(crtc_state);
 
+       /*
+        * Only allow :
+        * - Upscaling up to 5x, vertical and horizontal
+        * - Final coordinates must match crtc size
+        */
        return drm_atomic_helper_check_plane_state(state, crtc_state,
+                                                  FRAC_16_16(1, 5),
                                                   DRM_PLANE_HELPER_NO_SCALING,
-                                                  DRM_PLANE_HELPER_NO_SCALING,
-                                                  true, true);
+                                                  false, true);
 }
 
 /* Takes a fixed 16.16 number and converts it to integer. */
@@ -74,22 +120,20 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
 {
        struct meson_plane *meson_plane = to_meson_plane(plane);
        struct drm_plane_state *state = plane->state;
-       struct drm_framebuffer *fb = state->fb;
+       struct drm_rect dest = drm_plane_state_dest(state);
        struct meson_drm *priv = meson_plane->priv;
+       struct drm_framebuffer *fb = state->fb;
        struct drm_gem_cma_object *gem;
-       struct drm_rect src = {
-               .x1 = (state->src_x),
-               .y1 = (state->src_y),
-               .x2 = (state->src_x + state->src_w),
-               .y2 = (state->src_y + state->src_h),
-       };
-       struct drm_rect dest = {
-               .x1 = state->crtc_x,
-               .y1 = state->crtc_y,
-               .x2 = state->crtc_x + state->crtc_w,
-               .y2 = state->crtc_y + state->crtc_h,
-       };
        unsigned long flags;
+       int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
+       int vsc_bot_rcv_num, vsc_bot_rpt_p0_num;
+       int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
+       int hf_phase_step, vf_phase_step;
+       int src_w, src_h, dst_w, dst_h;
+       int bot_ini_phase;
+       int hf_bank_len;
+       int vf_bank_len;
+       u8 canvas_id_osd1;
 
        /*
         * Update Coordinates
@@ -104,8 +148,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
                                   (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
                                   OSD_BLK0_ENABLE;
 
+       if (priv->canvas)
+               canvas_id_osd1 = priv->canvas_id_osd1;
+       else
+               canvas_id_osd1 = MESON_CANVAS_ID_OSD1;
+
        /* Set up BLK0 to point to the right canvas */
-       priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
+       priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) |
                                      OSD_ENDIANNESS_LE);
 
        /* On GXBB, Use the old non-HDR RGB2YUV converter */
@@ -137,23 +186,115 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
                break;
        };
 
+       /* Default scaler parameters */
+       vsc_bot_rcv_num = 0;
+       vsc_bot_rpt_p0_num = 0;
+       hf_bank_len = 4;
+       vf_bank_len = 4;
+
        if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
-               priv->viu.osd1_interlace = true;
+               vsc_bot_rcv_num = 6;
+               vsc_bot_rpt_p0_num = 2;
+       }
+
+       hsc_ini_rcv_num = hf_bank_len;
+       vsc_ini_rcv_num = vf_bank_len;
+       hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1;
+       vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1;
+
+       src_w = fixed16_to_int(state->src_w);
+       src_h = fixed16_to_int(state->src_h);
+       dst_w = state->crtc_w;
+       dst_h = state->crtc_h;
 
+       /*
+        * When the output is interlaced, the OSD must switch between
+        * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
+        * at each vsync.
+        * But the vertical scaler can provide such funtionnality if
+        * is configured for 2:1 scaling with interlace options enabled.
+        */
+       if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
                dest.y1 /= 2;
                dest.y2 /= 2;
-       } else
-               priv->viu.osd1_interlace = false;
+               dst_h /= 2;
+       }
+
+       hf_phase_step = ((src_w << 18) / dst_w) << 6;
+       vf_phase_step = (src_h << 20) / dst_h;
+
+       if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
+               bot_ini_phase = ((vf_phase_step / 2) >> 4);
+       else
+               bot_ini_phase = 0;
+
+       vf_phase_step = (vf_phase_step << 4);
+
+       /* In interlaced mode, scaler is always active */
+       if (src_h != dst_h || src_w != dst_w) {
+               priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) |
+                                          SCI_WH_M1_H(src_h - 1);
+               priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) |
+                                                SCO_HV_END(dest.x2 - 1);
+               priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) |
+                                                SCO_HV_END(dest.y2 - 1);
+               /* Enable OSD Scaler */
+               priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1;
+       } else {
+               priv->viu.osd_sc_i_wh_m1 = 0;
+               priv->viu.osd_sc_o_h_start_end = 0;
+               priv->viu.osd_sc_o_v_start_end = 0;
+               priv->viu.osd_sc_ctrl0 = 0;
+       }
+
+       /* In interlaced mode, vertical scaler is always active */
+       if (src_h != dst_h) {
+               priv->viu.osd_sc_v_ctrl0 =
+                                       VSC_BANK_LEN(vf_bank_len) |
+                                       VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) |
+                                       VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) |
+                                       VSC_VERTICAL_SCALER_EN;
+
+               if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
+                       priv->viu.osd_sc_v_ctrl0 |=
+                                       VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) |
+                                       VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) |
+                                       VSC_PROG_INTERLACE;
+
+               priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step);
+               priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase);
+       } else {
+               priv->viu.osd_sc_v_ctrl0 = 0;
+               priv->viu.osd_sc_v_phase_step = 0;
+               priv->viu.osd_sc_v_ini_phase = 0;
+       }
+
+       /* Horizontal scaler is only used if width does not match */
+       if (src_w != dst_w) {
+               priv->viu.osd_sc_h_ctrl0 =
+                                       HSC_BANK_LENGTH(hf_bank_len) |
+                                       HSC_INI_RCV_NUM0(hsc_ini_rcv_num) |
+                                       HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) |
+                                       HSC_HORIZ_SCALER_EN;
+               priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step);
+               priv->viu.osd_sc_h_ini_phase = 0;
+       } else {
+               priv->viu.osd_sc_h_ctrl0 = 0;
+               priv->viu.osd_sc_h_phase_step = 0;
+               priv->viu.osd_sc_h_ini_phase = 0;
+       }
 
        /*
         * The format of these registers is (x2 << 16 | x1),
         * where x2 is exclusive.
         * e.g. +30x1920 would be (1919 << 16) | 30
         */
-       priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) |
-                                       fixed16_to_int(src.x1);
-       priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) |
-                                       fixed16_to_int(src.y1);
+       priv->viu.osd1_blk0_cfg[1] =
+                               ((fixed16_to_int(state->src.x2) - 1) << 16) |
+                               fixed16_to_int(state->src.x1);
+       priv->viu.osd1_blk0_cfg[2] =
+                               ((fixed16_to_int(state->src.y2) - 1) << 16) |
+                               fixed16_to_int(state->src.y1);
        priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
        priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
 
@@ -164,6 +305,15 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
        priv->viu.osd1_stride = fb->pitches[0];
        priv->viu.osd1_height = fb->height;
 
+       if (!meson_plane->enabled) {
+               /* Reset OSD1 before enabling it on GXL+ SoCs */
+               if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+                   meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+                       meson_viu_osd1_reset(priv);
+
+               meson_plane->enabled = true;
+       }
+
        spin_unlock_irqrestore(&priv->drm->event_lock, flags);
 }
 
@@ -177,12 +327,15 @@ static void meson_plane_atomic_disable(struct drm_plane *plane,
        writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
                            priv->io_base + _REG(VPP_MISC));
 
+       meson_plane->enabled = false;
+
 }
 
 static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
        .atomic_check   = meson_plane_atomic_check,
        .atomic_disable = meson_plane_atomic_disable,
        .atomic_update  = meson_plane_atomic_update,
+       .prepare_fb     = drm_gem_fb_prepare_fb,
 };
 
 static const struct drm_plane_funcs meson_plane_funcs = {
index bca87143e54880864a528da2fd5043ce9ca18e46..5c7e02c703bc71561add10624995334f2dac80d8 100644 (file)
 #define VIU_OSD1_MATRIX_COEF22_30 0x1a9d
 #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e
 #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f
+#define VD1_IF0_GEN_REG3 0x1aa7
 #define VIU_OSD1_EOTF_CTL 0x1ad4
 #define VIU_OSD1_EOTF_COEF00_01 0x1ad5
 #define VIU_OSD1_EOTF_COEF02_10 0x1ad6
 #define VIU_OSD1_OETF_CTL 0x1adc
 #define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add
 #define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade
+#define AFBC_ENABLE 0x1ae0
 
 /* vpp */
 #define VPP_DUMMY_DATA 0x1d00
 #define                VPP_VD2_PREBLEND        BIT(15)
 #define                VPP_OSD1_PREBLEND       BIT(16)
 #define                VPP_OSD2_PREBLEND       BIT(17)
+#define                VPP_COLOR_MNG_ENABLE    BIT(28)
 #define VPP_OFIFO_SIZE 0x1d27
 #define VPP_FIFO_STATUS 0x1d28
 #define VPP_SMOKE_CTRL 0x1d29
index ae5473257f727cd446b2aba0b3dd172a86b276f1..f6ba35a405f8dea95f4ec531df0df46372ae8ffc 100644 (file)
 #define HDMI_PLL_RESET         BIT(28)
 #define HDMI_PLL_LOCK          BIT(31)
 
+#define FREQ_1000_1001(_freq)  DIV_ROUND_CLOSEST(_freq * 1000, 1001)
+
 /* VID PLL Dividers */
 enum {
        VID_PLL_DIV_1 = 0,
@@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
 enum {
 /* PLL O1 O2 O3 VP DV     EN TX */
 /* 4320 /4 /4 /1 /5 /1  => /2 /2 */
-       MESON_VCLK_HDMI_ENCI_54000 = 1,
+       MESON_VCLK_HDMI_ENCI_54000 = 0,
 /* 4320 /4 /4 /1 /5 /1  => /1 /2 */
        MESON_VCLK_HDMI_DDR_54000,
 /* 2970 /4 /1 /1 /5 /1  => /1 /2 */
@@ -339,6 +341,7 @@ enum {
 };
 
 struct meson_vclk_params {
+       unsigned int pixel_freq;
        unsigned int pll_base_freq;
        unsigned int pll_od1;
        unsigned int pll_od2;
@@ -347,6 +350,7 @@ struct meson_vclk_params {
        unsigned int vclk_div;
 } params[] = {
        [MESON_VCLK_HDMI_ENCI_54000] = {
+               .pixel_freq = 54000,
                .pll_base_freq = 4320000,
                .pll_od1 = 4,
                .pll_od2 = 4,
@@ -355,6 +359,7 @@ struct meson_vclk_params {
                .vclk_div = 1,
        },
        [MESON_VCLK_HDMI_DDR_54000] = {
+               .pixel_freq = 54000,
                .pll_base_freq = 4320000,
                .pll_od1 = 4,
                .pll_od2 = 4,
@@ -363,6 +368,7 @@ struct meson_vclk_params {
                .vclk_div = 1,
        },
        [MESON_VCLK_HDMI_DDR_148500] = {
+               .pixel_freq = 148500,
                .pll_base_freq = 2970000,
                .pll_od1 = 4,
                .pll_od2 = 1,
@@ -371,6 +377,7 @@ struct meson_vclk_params {
                .vclk_div = 1,
        },
        [MESON_VCLK_HDMI_74250] = {
+               .pixel_freq = 74250,
                .pll_base_freq = 2970000,
                .pll_od1 = 2,
                .pll_od2 = 2,
@@ -379,6 +386,7 @@ struct meson_vclk_params {
                .vclk_div = 1,
        },
        [MESON_VCLK_HDMI_148500] = {
+               .pixel_freq = 148500,
                .pll_base_freq = 2970000,
                .pll_od1 = 1,
                .pll_od2 = 2,
@@ -387,6 +395,7 @@ struct meson_vclk_params {
                .vclk_div = 1,
        },
        [MESON_VCLK_HDMI_297000] = {
+               .pixel_freq = 297000,
                .pll_base_freq = 2970000,
                .pll_od1 = 1,
                .pll_od2 = 1,
@@ -395,6 +404,7 @@ struct meson_vclk_params {
                .vclk_div = 2,
        },
        [MESON_VCLK_HDMI_594000] = {
+               .pixel_freq = 594000,
                .pll_base_freq = 5940000,
                .pll_od1 = 1,
                .pll_od2 = 1,
@@ -402,6 +412,7 @@ struct meson_vclk_params {
                .vid_pll_div = VID_PLL_DIV_5,
                .vclk_div = 1,
        },
+       { /* sentinel */ },
 };
 
 static inline unsigned int pll_od_to_reg(unsigned int od)
@@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
                  pll_freq);
 }
 
+enum drm_mode_status
+meson_vclk_vic_supported_freq(unsigned int freq)
+{
+       int i;
+
+       DRM_DEBUG_DRIVER("freq = %d\n", freq);
+
+       for (i = 0 ; params[i].pixel_freq ; ++i) {
+               DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
+                                i, params[i].pixel_freq,
+                                FREQ_1000_1001(params[i].pixel_freq));
+               /* Match strict frequency */
+               if (freq == params[i].pixel_freq)
+                       return MODE_OK;
+               /* Match 1000/1001 variant */
+               if (freq == FREQ_1000_1001(params[i].pixel_freq))
+                       return MODE_OK;
+       }
+
+       return MODE_CLOCK_RANGE;
+}
+EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq);
+
 static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
                           unsigned int od1, unsigned int od2, unsigned int od3,
                           unsigned int vid_pll_div, unsigned int vclk_div,
                           unsigned int hdmi_tx_div, unsigned int venc_div,
-                          bool hdmi_use_enci)
+                          bool hdmi_use_enci, bool vic_alternate_clock)
 {
+       unsigned int m = 0, frac = 0;
+
        /* Set HDMI-TX sys clock */
        regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
                           CTS_HDMI_SYS_SEL_MASK, 0);
@@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
        } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
                switch (pll_base_freq) {
                case 2970000:
-                       meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
-                                                 od1, od2, od3);
+                       m = 0x3d;
+                       frac = vic_alternate_clock ? 0xd02 : 0xe00;
                        break;
                case 4320000:
-                       meson_hdmi_pll_set_params(priv, 0x5a, 0,
-                                                 od1, od2, od3);
+                       m = vic_alternate_clock ? 0x59 : 0x5a;
+                       frac = vic_alternate_clock ? 0xe8f : 0;
                        break;
                case 5940000:
-                       meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
-                                                 od1, od2, od3);
+                       m = 0x7b;
+                       frac = vic_alternate_clock ? 0xa05 : 0xc00;
                        break;
                }
+
+               meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
        } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
                   meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
                switch (pll_base_freq) {
                case 2970000:
-                       meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
-                                                 od1, od2, od3);
+                       m = 0x7b;
+                       frac = vic_alternate_clock ? 0x281 : 0x300;
                        break;
                case 4320000:
-                       meson_hdmi_pll_set_params(priv, 0xb4, 0,
-                                                 od1, od2, od3);
+                       m = vic_alternate_clock ? 0xb3 : 0xb4;
+                       frac = vic_alternate_clock ? 0x347 : 0;
                        break;
                case 5940000:
-                       meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
-                                                 od1, od2, od3);
+                       m = 0xf7;
+                       frac = vic_alternate_clock ? 0x102 : 0x200;
                        break;
                }
+
+               meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
        }
 
        /* Setup vid_pll divider */
@@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                      unsigned int vclk_freq, unsigned int venc_freq,
                      unsigned int dac_freq, bool hdmi_use_enci)
 {
+       bool vic_alternate_clock = false;
        unsigned int freq;
        unsigned int hdmi_tx_div;
        unsigned int venc_div;
@@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                 * - encp encoder
                 */
                meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
-                              VID_PLL_DIV_5, 2, 1, 1, false);
+                              VID_PLL_DIV_5, 2, 1, 1, false, false);
                return;
        }
 
@@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                return;
        }
 
-       switch (vclk_freq) {
-       case 54000:
-               if (hdmi_use_enci)
-                       freq = MESON_VCLK_HDMI_ENCI_54000;
-               else
-                       freq = MESON_VCLK_HDMI_DDR_54000;
-               break;
-       case 74250:
-               freq = MESON_VCLK_HDMI_74250;
-               break;
-       case 148500:
-               if (dac_freq != 148500)
-                       freq = MESON_VCLK_HDMI_DDR_148500;
-               else
-                       freq = MESON_VCLK_HDMI_148500;
-               break;
-       case 297000:
-               freq = MESON_VCLK_HDMI_297000;
-               break;
-       case 594000:
-               freq = MESON_VCLK_HDMI_594000;
-               break;
-       default:
-               pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
-                      vclk_freq);
+       for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
+               if (vclk_freq == params[freq].pixel_freq ||
+                   vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
+                       if (vclk_freq != params[freq].pixel_freq)
+                               vic_alternate_clock = true;
+                       else
+                               vic_alternate_clock = false;
+
+                       if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
+                           !hdmi_use_enci)
+                               continue;
+
+                       if (freq == MESON_VCLK_HDMI_DDR_54000 &&
+                           hdmi_use_enci)
+                               continue;
+
+                       if (freq == MESON_VCLK_HDMI_DDR_148500 &&
+                           dac_freq == vclk_freq)
+                               continue;
+
+                       if (freq == MESON_VCLK_HDMI_148500 &&
+                           dac_freq != vclk_freq)
+                               continue;
+                       break;
+               }
+       }
+
+       if (!params[freq].pixel_freq) {
+               pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
                return;
        }
 
@@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                       params[freq].pll_od1, params[freq].pll_od2,
                       params[freq].pll_od3, params[freq].vid_pll_div,
                       params[freq].vclk_div, hdmi_tx_div, venc_div,
-                      hdmi_use_enci);
+                      hdmi_use_enci, vic_alternate_clock);
 }
 EXPORT_SYMBOL_GPL(meson_vclk_setup);
index 869fa3a3073e98c01c9a17a72463f7d060605b72..4bd8752da02ab02c2bd96d9115a2e3aa3e55959b 100644 (file)
@@ -32,6 +32,8 @@ enum {
 
 enum drm_mode_status
 meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
+enum drm_mode_status
+meson_vclk_vic_supported_freq(unsigned int freq);
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                      unsigned int vclk_freq, unsigned int venc_freq,
index be76f3d64bf2e7e1c85142a7d159228bf5905e6a..0ba04f6813e63f0428b37c1aa977bd50b15eeccb 100644 (file)
@@ -698,6 +698,132 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
        },
 };
 
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
+       .encp = {
+               .dvi_settings = 0x1,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x8,
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               .video_filt_ctrl = 0x1000,
+               .video_filt_ctrl_present = true,
+               /* video_ofld_voav_ofst */
+               .yfp1_htime = 140,
+               .yfp2_htime = 140+3840,
+               .max_pxcnt = 3840+1660-1,
+               .hspuls_begin = 2156+1920,
+               .hspuls_end = 44,
+               .hspuls_switch = 44,
+               .vspuls_begin = 140,
+               .vspuls_end = 2059+1920,
+               .vspuls_bline = 0,
+               .vspuls_eline = 4,
+               .havon_begin = 148,
+               .havon_end = 3987,
+               .vavon_bline = 89,
+               .vavon_eline = 2248,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 44,
+               .hso_end = 2156+1920,
+               .vso_begin = 2100+1920,
+               .vso_end = 2164+1920,
+               .vso_bline = 51,
+               .vso_eline = 53,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 2249,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
+       .encp = {
+               .dvi_settings = 0x1,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x8,
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               .video_filt_ctrl = 0x1000,
+               .video_filt_ctrl_present = true,
+               /* video_ofld_voav_ofst */
+               .yfp1_htime = 140,
+               .yfp2_htime = 140+3840,
+               .max_pxcnt = 3840+1440-1,
+               .hspuls_begin = 2156+1920,
+               .hspuls_end = 44,
+               .hspuls_switch = 44,
+               .vspuls_begin = 140,
+               .vspuls_end = 2059+1920,
+               .vspuls_bline = 0,
+               .vspuls_eline = 4,
+               .havon_begin = 148,
+               .havon_end = 3987,
+               .vavon_bline = 89,
+               .vavon_eline = 2248,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 44,
+               .hso_end = 2156+1920,
+               .vso_begin = 2100+1920,
+               .vso_end = 2164+1920,
+               .vso_bline = 51,
+               .vso_eline = 53,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 2249,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
+       .encp = {
+               .dvi_settings = 0x1,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x8,
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               .video_filt_ctrl = 0x1000,
+               .video_filt_ctrl_present = true,
+               /* video_ofld_voav_ofst */
+               .yfp1_htime = 140,
+               .yfp2_htime = 140+3840,
+               .max_pxcnt = 3840+560-1,
+               .hspuls_begin = 2156+1920,
+               .hspuls_end = 44,
+               .hspuls_switch = 44,
+               .vspuls_begin = 140,
+               .vspuls_end = 2059+1920,
+               .vspuls_bline = 0,
+               .vspuls_eline = 4,
+               .havon_begin = 148,
+               .havon_end = 3987,
+               .vavon_bline = 89,
+               .vavon_eline = 2248,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 44,
+               .hso_end = 2156+1920,
+               .vso_begin = 2100+1920,
+               .vso_end = 2164+1920,
+               .vso_bline = 51,
+               .vso_eline = 53,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 2249,
+       },
+};
+
 struct meson_hdmi_venc_vic_mode {
        unsigned int vic;
        union meson_hdmi_venc_mode *mode;
@@ -719,6 +845,9 @@ struct meson_hdmi_venc_vic_mode {
        { 34, &meson_hdmi_encp_mode_1080p30 },
        { 31, &meson_hdmi_encp_mode_1080p50 },
        { 16, &meson_hdmi_encp_mode_1080p60 },
+       { 93, &meson_hdmi_encp_mode_2160p24 },
+       { 94, &meson_hdmi_encp_mode_2160p25 },
+       { 95, &meson_hdmi_encp_mode_2160p30 },
        { 0, NULL}, /* sentinel */
 };
 
index 26a0857878bfd520fe3ebe43cfa85c60534ff66a..e46e05f50bad76c82df3fbb2d29e937b741266d3 100644 (file)
@@ -296,6 +296,33 @@ static void meson_viu_load_matrix(struct meson_drm *priv)
                                 true);
 }
 
+/* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
+void meson_viu_osd1_reset(struct meson_drm *priv)
+{
+       uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2;
+
+       /* Save these 2 registers state */
+       osd1_fifo_ctrl_stat = readl_relaxed(
+                               priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
+       osd1_ctrl_stat2 = readl_relaxed(
+                               priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+
+       /* Reset OSD1 */
+       writel_bits_relaxed(BIT(0), BIT(0),
+                           priv->io_base + _REG(VIU_SW_RESET));
+       writel_bits_relaxed(BIT(0), 0,
+                           priv->io_base + _REG(VIU_SW_RESET));
+
+       /* Rewrite these registers state lost in the reset */
+       writel_relaxed(osd1_fifo_ctrl_stat,
+                      priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
+       writel_relaxed(osd1_ctrl_stat2,
+                      priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+
+       /* Reload the conversion matrix */
+       meson_viu_load_matrix(priv);
+}
+
 void meson_viu_init(struct meson_drm *priv)
 {
        uint32_t reg;
@@ -329,6 +356,21 @@ void meson_viu_init(struct meson_drm *priv)
                            0xff << OSD_REPLACE_SHIFT,
                            priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
 
+       /* Disable VD1 AFBC */
+       /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */
+       writel_bits_relaxed(0x7 << 16, 0,
+                       priv->io_base + _REG(VIU_MISC_CTRL0));
+       /* afbc vd1 set=0 */
+       writel_bits_relaxed(BIT(20), 0,
+                       priv->io_base + _REG(VIU_MISC_CTRL0));
+       writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
+
+       writel_relaxed(0x00FF00C0,
+                       priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
+       writel_relaxed(0x00FF00C0,
+                       priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
+
+
        priv->viu.osd1_enabled = false;
        priv->viu.osd1_commit = false;
        priv->viu.osd1_interlace = false;
index 073b1910bd1b7326a0a57b7f31b8df037c443b18..0f84bddd2ff0ea7b9ec31870d25b94156146b98d 100644 (file)
@@ -59,6 +59,7 @@
 #define OSD_REPLACE_EN         BIT(14)
 #define OSD_REPLACE_SHIFT      6
 
+void meson_viu_osd1_reset(struct meson_drm *priv);
 void meson_viu_init(struct meson_drm *priv);
 
 #endif /* __MESON_VIU_H */
index 27356f81a0abeb18f2544c1c05ae23e8504d3ec4..f9efb431e9535728f9bd11acc0e957d6ef2fa23b 100644 (file)
@@ -51,52 +51,6 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux)
        writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
 }
 
-/*
- * When the output is interlaced, the OSD must switch between
- * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
- * at each vsync.
- * But the vertical scaler can provide such funtionnality if
- * is configured for 2:1 scaling with interlace options enabled.
- */
-void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv,
-                                           struct drm_rect *input)
-{
-       writel_relaxed(BIT(3) /* Enable scaler */ |
-                      BIT(2), /* Select OSD1 */
-                       priv->io_base + _REG(VPP_OSD_SC_CTRL0));
-
-       writel_relaxed(((drm_rect_width(input) - 1) << 16) |
-                      (drm_rect_height(input) - 1),
-                       priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
-       /* 2:1 scaling */
-       writel_relaxed(((input->x1) << 16) | (input->x2),
-                       priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
-       writel_relaxed(((input->y1 >> 1) << 16) | (input->y2 >> 1),
-                       priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
-
-       /* 2:1 scaling values */
-       writel_relaxed(BIT(16), priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
-       writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
-
-       writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
-
-       writel_relaxed((4 << 0) /* osd_vsc_bank_length */ |
-                      (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
-                      (1 << 8) /* osd_vsc_top_rpt_p0_num0 */ |
-                      (6 << 11) /* osd_vsc_bot_ini_rcv_num0 */ |
-                      (2 << 16) /* osd_vsc_bot_rpt_p0_num0 */ |
-                      BIT(23)  /* osd_prog_interlace */ |
-                      BIT(24), /* Enable vertical scaler */
-                       priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
-}
-
-void meson_vpp_disable_interlace_vscaler_osd1(struct meson_drm *priv)
-{
-       writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
-       writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
-       writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
-}
-
 static unsigned int vpp_filter_coefs_4point_bspline[] = {
        0x15561500, 0x14561600, 0x13561700, 0x12561800,
        0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
@@ -122,6 +76,31 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv,
                                priv->io_base + _REG(VPP_OSD_SCALE_COEF));
 }
 
+static const uint32_t vpp_filter_coefs_bicubic[] = {
+       0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
+       0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
+       0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
+       0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
+       0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
+       0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
+       0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
+       0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
+       0xf84848f8
+};
+
+static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv,
+                                                   const unsigned int *coefs,
+                                                   bool is_horizontal)
+{
+       int i;
+
+       writel_relaxed(is_horizontal ? BIT(8) : 0,
+                       priv->io_base + _REG(VPP_SCALE_COEF_IDX));
+       for (i = 0; i < 33; i++)
+               writel_relaxed(coefs[i],
+                               priv->io_base + _REG(VPP_SCALE_COEF));
+}
+
 void meson_vpp_init(struct meson_drm *priv)
 {
        /* set dummy data default YUV black */
@@ -150,17 +129,34 @@ void meson_vpp_init(struct meson_drm *priv)
 
        /* Force all planes off */
        writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
-                           VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND, 0,
+                           VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND |
+                           VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0,
                            priv->io_base + _REG(VPP_MISC));
 
+       /* Setup default VD settings */
+       writel_relaxed(4096,
+                       priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
+       writel_relaxed(4096,
+                       priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
+
        /* Disable Scalers */
        writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
        writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
        writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+       writel_relaxed(4 | (4 << 8) | BIT(15),
+                      priv->io_base + _REG(VPP_SC_MISC));
+
+       writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL));
 
        /* Write in the proper filter coefficients. */
        meson_vpp_write_scaling_filter_coefs(priv,
                                vpp_filter_coefs_4point_bspline, false);
        meson_vpp_write_scaling_filter_coefs(priv,
                                vpp_filter_coefs_4point_bspline, true);
+
+       /* Write the VD proper filter coefficients. */
+       meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
+                                               false);
+       meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
+                                               true);
 }
index 04f1dfba12e5993ead71b7ef1639ac208c0be938..0aaedc5548798ec32dd7133e3041ee8651cd3270 100644 (file)
@@ -212,8 +212,6 @@ struct mga_device {
        int fb_mtrr;
 
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
        } ttm;
 
index 05570f0de4d7118ed1c395a93b873451420be467..d96a9b32455e6f5814e7454f482e62068a557b1f 100644 (file)
@@ -36,63 +36,6 @@ mgag200_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct mga_device, ttm.bdev);
 }
 
-static int
-mgag200_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void
-mgag200_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int mgag200_ttm_global_init(struct mga_device *ast)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       global_ref = &ast->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &mgag200_ttm_mem_global_init;
-       global_ref->release = &mgag200_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       ast->ttm.bo_global_ref.mem_glob =
-               ast->ttm.mem_global_ref.object;
-       global_ref = &ast->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&ast->ttm.mem_global_ref);
-               return r;
-       }
-       return 0;
-}
-
-static void
-mgag200_ttm_global_release(struct mga_device *ast)
-{
-       if (ast->ttm.mem_global_ref.release == NULL)
-               return;
-
-       drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&ast->ttm.mem_global_ref);
-       ast->ttm.mem_global_ref.release = NULL;
-}
-
-
 static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct mgag200_bo *bo;
@@ -232,12 +175,7 @@ int mgag200_mm_init(struct mga_device *mdev)
        struct drm_device *dev = mdev->dev;
        struct ttm_bo_device *bdev = &mdev->ttm.bdev;
 
-       ret = mgag200_ttm_global_init(mdev);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&mdev->ttm.bdev,
-                                mdev->ttm.bo_global_ref.ref.object,
                                 &mgag200_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET,
@@ -268,8 +206,6 @@ void mgag200_mm_fini(struct mga_device *mdev)
 
        ttm_bo_device_release(&mdev->ttm.bdev);
 
-       mgag200_ttm_global_release(mdev);
-
        arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
                                pci_resource_len(dev->pdev, 0));
        arch_phys_wc_del(mdev->fb_mtrr);
index 843a9d40c05e33f5f13d1cbb7b09c751127940f2..cf549f1ed4032f4394374155049dc68effd8089c 100644 (file)
@@ -2,7 +2,7 @@
 config DRM_MSM
        tristate "MSM DRM"
        depends on DRM
-       depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+       depends on ARCH_QCOM || SOC_IMX5 || (ARM && COMPILE_TEST)
        depends on OF && COMMON_CLK
        depends on MMU
        select QCOM_MDT_LOADER if ARCH_QCOM
@@ -11,7 +11,7 @@ config DRM_MSM
        select DRM_PANEL
        select SHMEM
        select TMPFS
-       select QCOM_SCM
+       select QCOM_SCM if ARCH_QCOM
        select WANT_DEV_COREDUMP
        select SND_SOC_HDMI_CODEC if SND_SOC
        select SYNC_FILE
index 19ab521d4c3ad10cc368b8227b44b7bad5b328f6..56a70c74af4ed2e275da7255ed66907519bd5e6a 100644 (file)
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi
 msm-y := \
        adreno/adreno_device.o \
        adreno/adreno_gpu.o \
+       adreno/a2xx_gpu.o \
        adreno/a3xx_gpu.o \
        adreno/a4xx_gpu.o \
        adreno/a5xx_gpu.o \
@@ -14,6 +15,7 @@ msm-y := \
        adreno/a6xx_gpu.o \
        adreno/a6xx_gmu.o \
        adreno/a6xx_hfi.o \
+       adreno/a6xx_gpu_state.o \
        hdmi/hdmi.o \
        hdmi/hdmi_audio.o \
        hdmi/hdmi_bridge.o \
@@ -68,11 +70,9 @@ msm-y := \
        disp/dpu1/dpu_hw_util.o \
        disp/dpu1/dpu_hw_vbif.o \
        disp/dpu1/dpu_io_util.o \
-       disp/dpu1/dpu_irq.o \
        disp/dpu1/dpu_kms.o \
        disp/dpu1/dpu_mdss.o \
        disp/dpu1/dpu_plane.o \
-       disp/dpu1/dpu_power_handle.o \
        disp/dpu1/dpu_rm.o \
        disp/dpu1/dpu_vbif.o \
        msm_atomic.o \
@@ -90,10 +90,11 @@ msm-y := \
        msm_perf.o \
        msm_rd.o \
        msm_ringbuffer.o \
-       msm_submitqueue.o
+       msm_submitqueue.o \
+       msm_gpu_tracepoints.o \
+       msm_gpummu.o
 
-msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
-                         disp/dpu1/dpu_dbg.o
+msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
index 12b0ba270b5ebe3b2930603b23f28819f97f4b25..14eb52f3e605223f278bfa182c7cddee8aa868ec 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
@@ -239,7 +239,63 @@ enum sq_tex_swiz {
 enum sq_tex_filter {
        SQ_TEX_FILTER_POINT = 0,
        SQ_TEX_FILTER_BILINEAR = 1,
-       SQ_TEX_FILTER_BICUBIC = 2,
+       SQ_TEX_FILTER_BASEMAP = 2,
+       SQ_TEX_FILTER_USE_FETCH_CONST = 3,
+};
+
+enum sq_tex_aniso_filter {
+       SQ_TEX_ANISO_FILTER_DISABLED = 0,
+       SQ_TEX_ANISO_FILTER_MAX_1_1 = 1,
+       SQ_TEX_ANISO_FILTER_MAX_2_1 = 2,
+       SQ_TEX_ANISO_FILTER_MAX_4_1 = 3,
+       SQ_TEX_ANISO_FILTER_MAX_8_1 = 4,
+       SQ_TEX_ANISO_FILTER_MAX_16_1 = 5,
+       SQ_TEX_ANISO_FILTER_USE_FETCH_CONST = 7,
+};
+
+enum sq_tex_dimension {
+       SQ_TEX_DIMENSION_1D = 0,
+       SQ_TEX_DIMENSION_2D = 1,
+       SQ_TEX_DIMENSION_3D = 2,
+       SQ_TEX_DIMENSION_CUBE = 3,
+};
+
+enum sq_tex_border_color {
+       SQ_TEX_BORDER_COLOR_BLACK = 0,
+       SQ_TEX_BORDER_COLOR_WHITE = 1,
+       SQ_TEX_BORDER_COLOR_ACBYCR_BLACK = 2,
+       SQ_TEX_BORDER_COLOR_ACBCRY_BLACK = 3,
+};
+
+enum sq_tex_sign {
+       SQ_TEX_SIGN_UNISIGNED = 0,
+       SQ_TEX_SIGN_SIGNED = 1,
+       SQ_TEX_SIGN_UNISIGNED_BIASED = 2,
+       SQ_TEX_SIGN_GAMMA = 3,
+};
+
+enum sq_tex_endian {
+       SQ_TEX_ENDIAN_NONE = 0,
+       SQ_TEX_ENDIAN_8IN16 = 1,
+       SQ_TEX_ENDIAN_8IN32 = 2,
+       SQ_TEX_ENDIAN_16IN32 = 3,
+};
+
+enum sq_tex_clamp_policy {
+       SQ_TEX_CLAMP_POLICY_D3D = 0,
+       SQ_TEX_CLAMP_POLICY_OGL = 1,
+};
+
+enum sq_tex_num_format {
+       SQ_TEX_NUM_FORMAT_FRAC = 0,
+       SQ_TEX_NUM_FORMAT_INT = 1,
+};
+
+enum sq_tex_type {
+       SQ_TEX_TYPE_0 = 0,
+       SQ_TEX_TYPE_1 = 1,
+       SQ_TEX_TYPE_2 = 2,
+       SQ_TEX_TYPE_3 = 3,
 };
 
 #define REG_A2XX_RBBM_PATCH_RELEASE                            0x00000001
@@ -323,6 +379,18 @@ static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_cln
 }
 
 #define REG_A2XX_MH_MMU_VA_RANGE                               0x00000041
+#define A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS__MASK            0x00000fff
+#define A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS__SHIFT           0
+static inline uint32_t A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(uint32_t val)
+{
+       return ((val) << A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS__SHIFT) & A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS__MASK;
+}
+#define A2XX_MH_MMU_VA_RANGE_VA_BASE__MASK                     0xfffff000
+#define A2XX_MH_MMU_VA_RANGE_VA_BASE__SHIFT                    12
+static inline uint32_t A2XX_MH_MMU_VA_RANGE_VA_BASE(uint32_t val)
+{
+       return ((val) << A2XX_MH_MMU_VA_RANGE_VA_BASE__SHIFT) & A2XX_MH_MMU_VA_RANGE_VA_BASE__MASK;
+}
 
 #define REG_A2XX_MH_MMU_PT_BASE                                        0x00000042
 
@@ -331,6 +399,8 @@ static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_cln
 #define REG_A2XX_MH_MMU_TRAN_ERROR                             0x00000044
 
 #define REG_A2XX_MH_MMU_INVALIDATE                             0x00000045
+#define A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL                  0x00000001
+#define A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC                   0x00000002
 
 #define REG_A2XX_MH_MMU_MPU_BASE                               0x00000046
 
@@ -389,12 +459,19 @@ static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_cln
 #define REG_A2XX_RBBM_READ_ERROR                               0x000003b3
 
 #define REG_A2XX_RBBM_INT_CNTL                                 0x000003b4
+#define A2XX_RBBM_INT_CNTL_RDERR_INT_MASK                      0x00000001
+#define A2XX_RBBM_INT_CNTL_DISPLAY_UPDATE_INT_MASK             0x00000002
+#define A2XX_RBBM_INT_CNTL_GUI_IDLE_INT_MASK                   0x00080000
 
 #define REG_A2XX_RBBM_INT_STATUS                               0x000003b5
 
 #define REG_A2XX_RBBM_INT_ACK                                  0x000003b6
 
 #define REG_A2XX_MASTER_INT_SIGNAL                             0x000003b7
+#define A2XX_MASTER_INT_SIGNAL_MH_INT_STAT                     0x00000020
+#define A2XX_MASTER_INT_SIGNAL_SQ_INT_STAT                     0x04000000
+#define A2XX_MASTER_INT_SIGNAL_CP_INT_STAT                     0x40000000
+#define A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT                   0x80000000
 
 #define REG_A2XX_RBBM_PERIPHID1                                        0x000003f9
 
@@ -467,6 +544,19 @@ static inline uint32_t A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(uint32_t val)
 #define A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE                  0x02000000
 #define A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE                  0x04000000
 
+#define REG_A2XX_MH_INTERRUPT_MASK                             0x00000a42
+#define A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR                  0x00000001
+#define A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR                 0x00000002
+#define A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT                  0x00000004
+
+#define REG_A2XX_MH_INTERRUPT_STATUS                           0x00000a43
+
+#define REG_A2XX_MH_INTERRUPT_CLEAR                            0x00000a44
+
+#define REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1                     0x00000a54
+
+#define REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG2                     0x00000a55
+
 #define REG_A2XX_A220_VSC_BIN_SIZE                             0x00000c01
 #define A2XX_A220_VSC_BIN_SIZE_WIDTH__MASK                     0x0000001f
 #define A2XX_A220_VSC_BIN_SIZE_WIDTH__SHIFT                    0
@@ -648,6 +738,18 @@ static inline uint32_t A2XX_RB_BC_CONTROL_MEM_EXPORT_TIMEOUT_SELECT(uint32_t val
 #define REG_A2XX_RB_DEBUG_DATA                                 0x00000f27
 
 #define REG_A2XX_RB_SURFACE_INFO                               0x00002000
+#define A2XX_RB_SURFACE_INFO_SURFACE_PITCH__MASK               0x00003fff
+#define A2XX_RB_SURFACE_INFO_SURFACE_PITCH__SHIFT              0
+static inline uint32_t A2XX_RB_SURFACE_INFO_SURFACE_PITCH(uint32_t val)
+{
+       return ((val) << A2XX_RB_SURFACE_INFO_SURFACE_PITCH__SHIFT) & A2XX_RB_SURFACE_INFO_SURFACE_PITCH__MASK;
+}
+#define A2XX_RB_SURFACE_INFO_MSAA_SAMPLES__MASK                        0x0000c000
+#define A2XX_RB_SURFACE_INFO_MSAA_SAMPLES__SHIFT               14
+static inline uint32_t A2XX_RB_SURFACE_INFO_MSAA_SAMPLES(uint32_t val)
+{
+       return ((val) << A2XX_RB_SURFACE_INFO_MSAA_SAMPLES__SHIFT) & A2XX_RB_SURFACE_INFO_MSAA_SAMPLES__MASK;
+}
 
 #define REG_A2XX_RB_COLOR_INFO                                 0x00002001
 #define A2XX_RB_COLOR_INFO_FORMAT__MASK                                0x0000000f
@@ -679,7 +781,7 @@ static inline uint32_t A2XX_RB_COLOR_INFO_SWAP(uint32_t val)
 #define A2XX_RB_COLOR_INFO_BASE__SHIFT                         12
 static inline uint32_t A2XX_RB_COLOR_INFO_BASE(uint32_t val)
 {
-       return ((val >> 10) << A2XX_RB_COLOR_INFO_BASE__SHIFT) & A2XX_RB_COLOR_INFO_BASE__MASK;
+       return ((val >> 12) << A2XX_RB_COLOR_INFO_BASE__SHIFT) & A2XX_RB_COLOR_INFO_BASE__MASK;
 }
 
 #define REG_A2XX_RB_DEPTH_INFO                                 0x00002002
@@ -693,7 +795,7 @@ static inline uint32_t A2XX_RB_DEPTH_INFO_DEPTH_FORMAT(enum adreno_rb_depth_form
 #define A2XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT                   12
 static inline uint32_t A2XX_RB_DEPTH_INFO_DEPTH_BASE(uint32_t val)
 {
-       return ((val >> 10) << A2XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT) & A2XX_RB_DEPTH_INFO_DEPTH_BASE__MASK;
+       return ((val >> 12) << A2XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT) & A2XX_RB_DEPTH_INFO_DEPTH_BASE__MASK;
 }
 
 #define REG_A2XX_A225_RB_COLOR_INFO3                           0x00002005
@@ -1757,6 +1859,36 @@ static inline uint32_t A2XX_RB_COPY_DEST_OFFSET_Y(uint32_t val)
 #define REG_A2XX_COHER_STATUS_PM4                              0x00000a2b
 
 #define REG_A2XX_SQ_TEX_0                                      0x00000000
+#define A2XX_SQ_TEX_0_TYPE__MASK                               0x00000003
+#define A2XX_SQ_TEX_0_TYPE__SHIFT                              0
+static inline uint32_t A2XX_SQ_TEX_0_TYPE(enum sq_tex_type val)
+{
+       return ((val) << A2XX_SQ_TEX_0_TYPE__SHIFT) & A2XX_SQ_TEX_0_TYPE__MASK;
+}
+#define A2XX_SQ_TEX_0_SIGN_X__MASK                             0x0000000c
+#define A2XX_SQ_TEX_0_SIGN_X__SHIFT                            2
+static inline uint32_t A2XX_SQ_TEX_0_SIGN_X(enum sq_tex_sign val)
+{
+       return ((val) << A2XX_SQ_TEX_0_SIGN_X__SHIFT) & A2XX_SQ_TEX_0_SIGN_X__MASK;
+}
+#define A2XX_SQ_TEX_0_SIGN_Y__MASK                             0x00000030
+#define A2XX_SQ_TEX_0_SIGN_Y__SHIFT                            4
+static inline uint32_t A2XX_SQ_TEX_0_SIGN_Y(enum sq_tex_sign val)
+{
+       return ((val) << A2XX_SQ_TEX_0_SIGN_Y__SHIFT) & A2XX_SQ_TEX_0_SIGN_Y__MASK;
+}
+#define A2XX_SQ_TEX_0_SIGN_Z__MASK                             0x000000c0
+#define A2XX_SQ_TEX_0_SIGN_Z__SHIFT                            6
+static inline uint32_t A2XX_SQ_TEX_0_SIGN_Z(enum sq_tex_sign val)
+{
+       return ((val) << A2XX_SQ_TEX_0_SIGN_Z__SHIFT) & A2XX_SQ_TEX_0_SIGN_Z__MASK;
+}
+#define A2XX_SQ_TEX_0_SIGN_W__MASK                             0x00000300
+#define A2XX_SQ_TEX_0_SIGN_W__SHIFT                            8
+static inline uint32_t A2XX_SQ_TEX_0_SIGN_W(enum sq_tex_sign val)
+{
+       return ((val) << A2XX_SQ_TEX_0_SIGN_W__SHIFT) & A2XX_SQ_TEX_0_SIGN_W__MASK;
+}
 #define A2XX_SQ_TEX_0_CLAMP_X__MASK                            0x00001c00
 #define A2XX_SQ_TEX_0_CLAMP_X__SHIFT                           10
 static inline uint32_t A2XX_SQ_TEX_0_CLAMP_X(enum sq_tex_clamp val)
@@ -1775,14 +1907,46 @@ static inline uint32_t A2XX_SQ_TEX_0_CLAMP_Z(enum sq_tex_clamp val)
 {
        return ((val) << A2XX_SQ_TEX_0_CLAMP_Z__SHIFT) & A2XX_SQ_TEX_0_CLAMP_Z__MASK;
 }
-#define A2XX_SQ_TEX_0_PITCH__MASK                              0xffc00000
+#define A2XX_SQ_TEX_0_PITCH__MASK                              0x7fc00000
 #define A2XX_SQ_TEX_0_PITCH__SHIFT                             22
 static inline uint32_t A2XX_SQ_TEX_0_PITCH(uint32_t val)
 {
        return ((val >> 5) << A2XX_SQ_TEX_0_PITCH__SHIFT) & A2XX_SQ_TEX_0_PITCH__MASK;
 }
+#define A2XX_SQ_TEX_0_TILED                                    0x00000002
 
 #define REG_A2XX_SQ_TEX_1                                      0x00000001
+#define A2XX_SQ_TEX_1_FORMAT__MASK                             0x0000003f
+#define A2XX_SQ_TEX_1_FORMAT__SHIFT                            0
+static inline uint32_t A2XX_SQ_TEX_1_FORMAT(enum a2xx_sq_surfaceformat val)
+{
+       return ((val) << A2XX_SQ_TEX_1_FORMAT__SHIFT) & A2XX_SQ_TEX_1_FORMAT__MASK;
+}
+#define A2XX_SQ_TEX_1_ENDIANNESS__MASK                         0x000000c0
+#define A2XX_SQ_TEX_1_ENDIANNESS__SHIFT                                6
+static inline uint32_t A2XX_SQ_TEX_1_ENDIANNESS(enum sq_tex_endian val)
+{
+       return ((val) << A2XX_SQ_TEX_1_ENDIANNESS__SHIFT) & A2XX_SQ_TEX_1_ENDIANNESS__MASK;
+}
+#define A2XX_SQ_TEX_1_REQUEST_SIZE__MASK                       0x00000300
+#define A2XX_SQ_TEX_1_REQUEST_SIZE__SHIFT                      8
+static inline uint32_t A2XX_SQ_TEX_1_REQUEST_SIZE(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_1_REQUEST_SIZE__SHIFT) & A2XX_SQ_TEX_1_REQUEST_SIZE__MASK;
+}
+#define A2XX_SQ_TEX_1_STACKED                                  0x00000400
+#define A2XX_SQ_TEX_1_CLAMP_POLICY__MASK                       0x00000800
+#define A2XX_SQ_TEX_1_CLAMP_POLICY__SHIFT                      11
+static inline uint32_t A2XX_SQ_TEX_1_CLAMP_POLICY(enum sq_tex_clamp_policy val)
+{
+       return ((val) << A2XX_SQ_TEX_1_CLAMP_POLICY__SHIFT) & A2XX_SQ_TEX_1_CLAMP_POLICY__MASK;
+}
+#define A2XX_SQ_TEX_1_BASE_ADDRESS__MASK                       0xfffff000
+#define A2XX_SQ_TEX_1_BASE_ADDRESS__SHIFT                      12
+static inline uint32_t A2XX_SQ_TEX_1_BASE_ADDRESS(uint32_t val)
+{
+       return ((val >> 12) << A2XX_SQ_TEX_1_BASE_ADDRESS__SHIFT) & A2XX_SQ_TEX_1_BASE_ADDRESS__MASK;
+}
 
 #define REG_A2XX_SQ_TEX_2                                      0x00000002
 #define A2XX_SQ_TEX_2_WIDTH__MASK                              0x00001fff
@@ -1797,8 +1961,20 @@ static inline uint32_t A2XX_SQ_TEX_2_HEIGHT(uint32_t val)
 {
        return ((val) << A2XX_SQ_TEX_2_HEIGHT__SHIFT) & A2XX_SQ_TEX_2_HEIGHT__MASK;
 }
+#define A2XX_SQ_TEX_2_DEPTH__MASK                              0xfc000000
+#define A2XX_SQ_TEX_2_DEPTH__SHIFT                             26
+static inline uint32_t A2XX_SQ_TEX_2_DEPTH(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_2_DEPTH__SHIFT) & A2XX_SQ_TEX_2_DEPTH__MASK;
+}
 
 #define REG_A2XX_SQ_TEX_3                                      0x00000003
+#define A2XX_SQ_TEX_3_NUM_FORMAT__MASK                         0x00000001
+#define A2XX_SQ_TEX_3_NUM_FORMAT__SHIFT                                0
+static inline uint32_t A2XX_SQ_TEX_3_NUM_FORMAT(enum sq_tex_num_format val)
+{
+       return ((val) << A2XX_SQ_TEX_3_NUM_FORMAT__SHIFT) & A2XX_SQ_TEX_3_NUM_FORMAT__MASK;
+}
 #define A2XX_SQ_TEX_3_SWIZ_X__MASK                             0x0000000e
 #define A2XX_SQ_TEX_3_SWIZ_X__SHIFT                            1
 static inline uint32_t A2XX_SQ_TEX_3_SWIZ_X(enum sq_tex_swiz val)
@@ -1823,6 +1999,12 @@ static inline uint32_t A2XX_SQ_TEX_3_SWIZ_W(enum sq_tex_swiz val)
 {
        return ((val) << A2XX_SQ_TEX_3_SWIZ_W__SHIFT) & A2XX_SQ_TEX_3_SWIZ_W__MASK;
 }
+#define A2XX_SQ_TEX_3_EXP_ADJUST__MASK                         0x0007e000
+#define A2XX_SQ_TEX_3_EXP_ADJUST__SHIFT                                13
+static inline uint32_t A2XX_SQ_TEX_3_EXP_ADJUST(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_3_EXP_ADJUST__SHIFT) & A2XX_SQ_TEX_3_EXP_ADJUST__MASK;
+}
 #define A2XX_SQ_TEX_3_XY_MAG_FILTER__MASK                      0x00180000
 #define A2XX_SQ_TEX_3_XY_MAG_FILTER__SHIFT                     19
 static inline uint32_t A2XX_SQ_TEX_3_XY_MAG_FILTER(enum sq_tex_filter val)
@@ -1835,6 +2017,104 @@ static inline uint32_t A2XX_SQ_TEX_3_XY_MIN_FILTER(enum sq_tex_filter val)
 {
        return ((val) << A2XX_SQ_TEX_3_XY_MIN_FILTER__SHIFT) & A2XX_SQ_TEX_3_XY_MIN_FILTER__MASK;
 }
+#define A2XX_SQ_TEX_3_MIP_FILTER__MASK                         0x01800000
+#define A2XX_SQ_TEX_3_MIP_FILTER__SHIFT                                23
+static inline uint32_t A2XX_SQ_TEX_3_MIP_FILTER(enum sq_tex_filter val)
+{
+       return ((val) << A2XX_SQ_TEX_3_MIP_FILTER__SHIFT) & A2XX_SQ_TEX_3_MIP_FILTER__MASK;
+}
+#define A2XX_SQ_TEX_3_ANISO_FILTER__MASK                       0x0e000000
+#define A2XX_SQ_TEX_3_ANISO_FILTER__SHIFT                      25
+static inline uint32_t A2XX_SQ_TEX_3_ANISO_FILTER(enum sq_tex_aniso_filter val)
+{
+       return ((val) << A2XX_SQ_TEX_3_ANISO_FILTER__SHIFT) & A2XX_SQ_TEX_3_ANISO_FILTER__MASK;
+}
+#define A2XX_SQ_TEX_3_BORDER_SIZE__MASK                                0x80000000
+#define A2XX_SQ_TEX_3_BORDER_SIZE__SHIFT                       31
+static inline uint32_t A2XX_SQ_TEX_3_BORDER_SIZE(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_3_BORDER_SIZE__SHIFT) & A2XX_SQ_TEX_3_BORDER_SIZE__MASK;
+}
+
+#define REG_A2XX_SQ_TEX_4                                      0x00000004
+#define A2XX_SQ_TEX_4_VOL_MAG_FILTER__MASK                     0x00000001
+#define A2XX_SQ_TEX_4_VOL_MAG_FILTER__SHIFT                    0
+static inline uint32_t A2XX_SQ_TEX_4_VOL_MAG_FILTER(enum sq_tex_filter val)
+{
+       return ((val) << A2XX_SQ_TEX_4_VOL_MAG_FILTER__SHIFT) & A2XX_SQ_TEX_4_VOL_MAG_FILTER__MASK;
+}
+#define A2XX_SQ_TEX_4_VOL_MIN_FILTER__MASK                     0x00000002
+#define A2XX_SQ_TEX_4_VOL_MIN_FILTER__SHIFT                    1
+static inline uint32_t A2XX_SQ_TEX_4_VOL_MIN_FILTER(enum sq_tex_filter val)
+{
+       return ((val) << A2XX_SQ_TEX_4_VOL_MIN_FILTER__SHIFT) & A2XX_SQ_TEX_4_VOL_MIN_FILTER__MASK;
+}
+#define A2XX_SQ_TEX_4_MIP_MIN_LEVEL__MASK                      0x0000003c
+#define A2XX_SQ_TEX_4_MIP_MIN_LEVEL__SHIFT                     2
+static inline uint32_t A2XX_SQ_TEX_4_MIP_MIN_LEVEL(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_4_MIP_MIN_LEVEL__SHIFT) & A2XX_SQ_TEX_4_MIP_MIN_LEVEL__MASK;
+}
+#define A2XX_SQ_TEX_4_MIP_MAX_LEVEL__MASK                      0x000003c0
+#define A2XX_SQ_TEX_4_MIP_MAX_LEVEL__SHIFT                     6
+static inline uint32_t A2XX_SQ_TEX_4_MIP_MAX_LEVEL(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_4_MIP_MAX_LEVEL__SHIFT) & A2XX_SQ_TEX_4_MIP_MAX_LEVEL__MASK;
+}
+#define A2XX_SQ_TEX_4_MAX_ANISO_WALK                           0x00000400
+#define A2XX_SQ_TEX_4_MIN_ANISO_WALK                           0x00000800
+#define A2XX_SQ_TEX_4_LOD_BIAS__MASK                           0x003ff000
+#define A2XX_SQ_TEX_4_LOD_BIAS__SHIFT                          12
+static inline uint32_t A2XX_SQ_TEX_4_LOD_BIAS(float val)
+{
+       return ((((int32_t)(val * 32.0))) << A2XX_SQ_TEX_4_LOD_BIAS__SHIFT) & A2XX_SQ_TEX_4_LOD_BIAS__MASK;
+}
+#define A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_H__MASK                  0x07c00000
+#define A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_H__SHIFT                 22
+static inline uint32_t A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_H(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_H__SHIFT) & A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_H__MASK;
+}
+#define A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_V__MASK                  0xf8000000
+#define A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_V__SHIFT                 27
+static inline uint32_t A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_V(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_V__SHIFT) & A2XX_SQ_TEX_4_GRAD_EXP_ADJUST_V__MASK;
+}
+
+#define REG_A2XX_SQ_TEX_5                                      0x00000005
+#define A2XX_SQ_TEX_5_BORDER_COLOR__MASK                       0x00000003
+#define A2XX_SQ_TEX_5_BORDER_COLOR__SHIFT                      0
+static inline uint32_t A2XX_SQ_TEX_5_BORDER_COLOR(enum sq_tex_border_color val)
+{
+       return ((val) << A2XX_SQ_TEX_5_BORDER_COLOR__SHIFT) & A2XX_SQ_TEX_5_BORDER_COLOR__MASK;
+}
+#define A2XX_SQ_TEX_5_FORCE_BCW_MAX                            0x00000004
+#define A2XX_SQ_TEX_5_TRI_CLAMP__MASK                          0x00000018
+#define A2XX_SQ_TEX_5_TRI_CLAMP__SHIFT                         3
+static inline uint32_t A2XX_SQ_TEX_5_TRI_CLAMP(uint32_t val)
+{
+       return ((val) << A2XX_SQ_TEX_5_TRI_CLAMP__SHIFT) & A2XX_SQ_TEX_5_TRI_CLAMP__MASK;
+}
+#define A2XX_SQ_TEX_5_ANISO_BIAS__MASK                         0x000001e0
+#define A2XX_SQ_TEX_5_ANISO_BIAS__SHIFT                                5
+static inline uint32_t A2XX_SQ_TEX_5_ANISO_BIAS(float val)
+{
+       return ((((int32_t)(val * 1.0))) << A2XX_SQ_TEX_5_ANISO_BIAS__SHIFT) & A2XX_SQ_TEX_5_ANISO_BIAS__MASK;
+}
+#define A2XX_SQ_TEX_5_DIMENSION__MASK                          0x00000600
+#define A2XX_SQ_TEX_5_DIMENSION__SHIFT                         9
+static inline uint32_t A2XX_SQ_TEX_5_DIMENSION(enum sq_tex_dimension val)
+{
+       return ((val) << A2XX_SQ_TEX_5_DIMENSION__SHIFT) & A2XX_SQ_TEX_5_DIMENSION__MASK;
+}
+#define A2XX_SQ_TEX_5_PACKED_MIPS                              0x00000800
+#define A2XX_SQ_TEX_5_MIP_ADDRESS__MASK                                0xfffff000
+#define A2XX_SQ_TEX_5_MIP_ADDRESS__SHIFT                       12
+static inline uint32_t A2XX_SQ_TEX_5_MIP_ADDRESS(uint32_t val)
+{
+       return ((val >> 12) << A2XX_SQ_TEX_5_MIP_ADDRESS__SHIFT) & A2XX_SQ_TEX_5_MIP_ADDRESS__MASK;
+}
 
 
 #endif /* A2XX_XML */
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
new file mode 100644 (file)
index 0000000..1f83bc1
--- /dev/null
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#include "a2xx_gpu.h"
+#include "msm_gem.h"
+#include "msm_mmu.h"
+
+extern bool hang_debug;
+
+static void a2xx_dump(struct msm_gpu *gpu);
+static bool a2xx_idle(struct msm_gpu *gpu);
+
+static bool a2xx_me_init(struct msm_gpu *gpu)
+{
+       struct msm_ringbuffer *ring = gpu->rb[0];
+
+       OUT_PKT3(ring, CP_ME_INIT, 18);
+
+       /* All fields present (bits 9:0) */
+       OUT_RING(ring, 0x000003ff);
+       /* Disable/Enable Real-Time Stream processing (present but ignored) */
+       OUT_RING(ring, 0x00000000);
+       /* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
+       OUT_RING(ring, 0x00000000);
+
+       OUT_RING(ring, REG_A2XX_RB_SURFACE_INFO - 0x2000);
+       OUT_RING(ring, REG_A2XX_PA_SC_WINDOW_OFFSET - 0x2000);
+       OUT_RING(ring, REG_A2XX_VGT_MAX_VTX_INDX - 0x2000);
+       OUT_RING(ring, REG_A2XX_SQ_PROGRAM_CNTL - 0x2000);
+       OUT_RING(ring, REG_A2XX_RB_DEPTHCONTROL - 0x2000);
+       OUT_RING(ring, REG_A2XX_PA_SU_POINT_SIZE - 0x2000);
+       OUT_RING(ring, REG_A2XX_PA_SC_LINE_CNTL - 0x2000);
+       OUT_RING(ring, REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE - 0x2000);
+
+       /* Vertex and Pixel Shader Start Addresses in instructions
+        * (3 DWORDS per instruction) */
+       OUT_RING(ring, 0x80000180);
+       /* Maximum Contexts */
+       OUT_RING(ring, 0x00000001);
+       /* Write Confirm Interval and The CP will wait the
+        * wait_interval * 16 clocks between polling  */
+       OUT_RING(ring, 0x00000000);
+       /* NQ and External Memory Swap */
+       OUT_RING(ring, 0x00000000);
+       /* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
+       OUT_RING(ring, 0x200001f2);
+       /* Disable header dumping and Header dump address */
+       OUT_RING(ring, 0x00000000);
+       /* Header dump size */
+       OUT_RING(ring, 0x00000000);
+
+       /* enable protected mode */
+       OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
+       OUT_RING(ring, 1);
+
+       gpu->funcs->flush(gpu, ring);
+       return a2xx_idle(gpu);
+}
+
+static int a2xx_hw_init(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       dma_addr_t pt_base, tran_error;
+       uint32_t *ptr, len;
+       int i, ret;
+
+       msm_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error);
+
+       DBG("%s", gpu->name);
+
+       /* halt ME to avoid ucode upload issues on a20x */
+       gpu_write(gpu, REG_AXXX_CP_ME_CNTL, AXXX_CP_ME_CNTL_HALT);
+
+       gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
+       gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0xffffffff);
+
+       /* note: kgsl uses 0x00000001 after first reset on a22x */
+       gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0xffffffff);
+       msleep(30);
+       gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0x00000000);
+
+       if (adreno_is_a225(adreno_gpu))
+               gpu_write(gpu, REG_A2XX_SQ_FLOW_CONTROL, 0x18000000);
+
+       /* note: kgsl uses 0x0000ffff for a20x */
+       gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
+
+       /* MPU: physical range */
+       gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000);
+       gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
+
+       gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE |
+               A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
+               A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG));
+
+       /* same as parameters in adreno_gpu */
+       gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M |
+               A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff));
+
+       gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base);
+       gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error);
+
+       gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE,
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
+
+       gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
+               A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
+               A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(1) |
+               A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(8) |
+               A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE |
+               A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE);
+       if (!adreno_is_a20x(adreno_gpu))
+               gpu_write(gpu, REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1, 0x00032f07);
+
+       gpu_write(gpu, REG_A2XX_SQ_VS_PROGRAM, 0x00000000);
+       gpu_write(gpu, REG_A2XX_SQ_PS_PROGRAM, 0x00000000);
+
+       gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0); /* 0x200 for msm8960? */
+       gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0); /* 0x80/0x1a0 for a22x? */
+
+       /* note: gsl doesn't set this */
+       gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
+
+       gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL,
+               A2XX_RBBM_INT_CNTL_RDERR_INT_MASK);
+       gpu_write(gpu, REG_AXXX_CP_INT_CNTL,
+               AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK |
+               AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK |
+               AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK |
+               AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK |
+               AXXX_CP_INT_CNTL_IB_ERROR_MASK |
+               AXXX_CP_INT_CNTL_IB1_INT_MASK |
+               AXXX_CP_INT_CNTL_RB_INT_MASK);
+       gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
+       gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK,
+               A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR |
+               A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR |
+               A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT);
+
+       for (i = 3; i <= 5; i++)
+               if ((SZ_16K << i) == adreno_gpu->gmem)
+                       break;
+       gpu_write(gpu, REG_A2XX_RB_EDRAM_INFO, i);
+
+       ret = adreno_hw_init(gpu);
+       if (ret)
+               return ret;
+
+       /* NOTE: PM4/micro-engine firmware registers look to be the same
+        * for a2xx and a3xx.. we could possibly push that part down to
+        * adreno_gpu base class.  Or push both PM4 and PFP but
+        * parameterize the pfp ucode addr/data registers..
+        */
+
+       /* Load PM4: */
+       ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
+       len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
+       DBG("loading PM4 ucode version: %x", ptr[1]);
+
+       gpu_write(gpu, REG_AXXX_CP_DEBUG,
+                       AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
+       gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
+       for (i = 1; i < len; i++)
+               gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
+
+       /* Load PFP: */
+       ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
+       len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
+       DBG("loading PFP ucode version: %x", ptr[5]);
+
+       gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
+       for (i = 1; i < len; i++)
+               gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
+
+       gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
+
+       /* clear ME_HALT to start micro engine */
+       gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
+
+       return a2xx_me_init(gpu) ? 0 : -EINVAL;
+}
+
+static void a2xx_recover(struct msm_gpu *gpu)
+{
+       int i;
+
+       adreno_dump_info(gpu);
+
+       for (i = 0; i < 8; i++) {
+               printk("CP_SCRATCH_REG%d: %u\n", i,
+                       gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
+       }
+
+       /* dump registers before resetting gpu, if enabled: */
+       if (hang_debug)
+               a2xx_dump(gpu);
+
+       gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
+       gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
+       gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
+       adreno_recover(gpu);
+}
+
+static void a2xx_destroy(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
+
+       DBG("%s", gpu->name);
+
+       adreno_gpu_cleanup(adreno_gpu);
+
+       kfree(a2xx_gpu);
+}
+
+static bool a2xx_idle(struct msm_gpu *gpu)
+{
+       /* wait for ringbuffer to drain: */
+       if (!adreno_idle(gpu, gpu->rb[0]))
+               return false;
+
+       /* then wait for GPU to finish: */
+       if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
+                       A2XX_RBBM_STATUS_GUI_ACTIVE))) {
+               DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
+
+               /* TODO maybe we need to reset GPU here to recover from hang? */
+               return false;
+       }
+
+       return true;
+}
+
+static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
+{
+       uint32_t mstatus, status;
+
+       mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
+
+       if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
+               status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
+
+               dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
+               dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
+                       gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
+
+               gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
+       }
+
+       if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
+               status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
+
+               /* only RB_INT is expected */
+               if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
+                       dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
+
+               gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
+       }
+
+       if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
+               status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
+
+               dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
+
+               gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
+       }
+
+       msm_gpu_retire(gpu);
+
+       return IRQ_HANDLED;
+}
+
+static const unsigned int a200_registers[] = {
+       0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+       0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
+       0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
+       0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
+       0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
+       0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
+       0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
+       0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
+       0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
+       0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
+       0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
+       0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
+       0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+       0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+       0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+       0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
+       0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
+       0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
+       0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
+       0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
+       0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
+       0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
+       0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
+       0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
+       0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
+       ~0   /* sentinel */
+};
+
+static const unsigned int a220_registers[] = {
+       0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+       0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
+       0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
+       0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
+       0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
+       0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
+       0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
+       0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
+       0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
+       0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
+       0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
+       0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
+       0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
+       0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
+       0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
+       0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
+       0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
+       0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
+       0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
+       0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
+       0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
+       0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
+       0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
+       0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
+       0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
+       0x4900, 0x4900, 0x4908, 0x4908,
+       ~0   /* sentinel */
+};
+
+static const unsigned int a225_registers[] = {
+       0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+       0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
+       0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
+       0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
+       0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
+       0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
+       0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
+       0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
+       0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
+       0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
+       0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
+       0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
+       0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+       0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+       0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+       0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
+       0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
+       0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
+       0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
+       0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
+       0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
+       0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
+       0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
+       0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
+       0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
+       0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
+       0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
+       0x4908, 0x4908,
+       ~0   /* sentinel */
+};
+
+/* would be nice to not have to duplicate the _show() stuff with printk(): */
+static void a2xx_dump(struct msm_gpu *gpu)
+{
+       printk("status:   %08x\n",
+                       gpu_read(gpu, REG_A2XX_RBBM_STATUS));
+       adreno_dump(gpu);
+}
+
+static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
+
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       adreno_gpu_state_get(gpu, state);
+
+       state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
+
+       return state;
+}
+
+/* Register offset defines for A2XX - copy of A3XX */
+static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
+       REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
+       REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
+};
+
+static const struct adreno_gpu_funcs funcs = {
+       .base = {
+               .get_param = adreno_get_param,
+               .hw_init = a2xx_hw_init,
+               .pm_suspend = msm_gpu_pm_suspend,
+               .pm_resume = msm_gpu_pm_resume,
+               .recover = a2xx_recover,
+               .submit = adreno_submit,
+               .flush = adreno_flush,
+               .active_ring = adreno_active_ring,
+               .irq = a2xx_irq,
+               .destroy = a2xx_destroy,
+#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
+               .show = adreno_show,
+#endif
+               .gpu_state_get = a2xx_gpu_state_get,
+               .gpu_state_put = adreno_gpu_state_put,
+       },
+};
+
+static const struct msm_gpu_perfcntr perfcntrs[] = {
+/* TODO */
+};
+
+struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
+{
+       struct a2xx_gpu *a2xx_gpu = NULL;
+       struct adreno_gpu *adreno_gpu;
+       struct msm_gpu *gpu;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = priv->gpu_pdev;
+       int ret;
+
+       if (!pdev) {
+               dev_err(dev->dev, "no a2xx device\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
+       if (!a2xx_gpu) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       adreno_gpu = &a2xx_gpu->base;
+       gpu = &adreno_gpu->base;
+
+       gpu->perfcntrs = perfcntrs;
+       gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
+
+       if (adreno_is_a20x(adreno_gpu))
+               adreno_gpu->registers = a200_registers;
+       else if (adreno_is_a225(adreno_gpu))
+               adreno_gpu->registers = a225_registers;
+       else
+               adreno_gpu->registers = a220_registers;
+
+       adreno_gpu->reg_offsets = a2xx_register_offsets;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+       if (ret)
+               goto fail;
+
+       if (!gpu->aspace) {
+               dev_err(dev->dev, "No memory protection without MMU\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       return gpu;
+
+fail:
+       if (a2xx_gpu)
+               a2xx_destroy(&a2xx_gpu->base.base);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
new file mode 100644 (file)
index 0000000..02fba2c
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#ifndef __A2XX_GPU_H__
+#define __A2XX_GPU_H__
+
+#include "adreno_gpu.h"
+
+/* arrg, somehow fb.h is getting pulled in: */
+#undef ROP_COPY
+#undef ROP_XOR
+
+#include "a2xx.xml.h"
+
+struct a2xx_gpu {
+       struct adreno_gpu base;
+       bool pm_enabled;
+};
+#define to_a2xx_gpu(x) container_of(x, struct a2xx_gpu, base)
+
+#endif /* __A2XX_GPU_H__ */
index a89f7bb8b5cc057fcf0da9ba85d37c4e1c04a0a0..17059f242a98e0ac42f66e041fc4bb48a813a884 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
index 669c2d4b070dea4c711e0e8df9585d68dd810cd9..c3b4bc6e4155e27393510f8ff0accbceabf4955d 100644 (file)
@@ -481,7 +481,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        int ret;
 
        if (!pdev) {
-               dev_err(dev->dev, "no a3xx device\n");
+               DRM_DEV_ERROR(dev->dev, "no a3xx device\n");
                ret = -ENXIO;
                goto fail;
        }
@@ -528,7 +528,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
                 * to not be possible to restrict access, then we must
                 * implement a cmdstream validator.
                 */
-               dev_err(dev->dev, "No memory protection without IOMMU\n");
+               DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");
                ret = -ENXIO;
                goto fail;
        }
index 858690f528549abba1dca05145adf2f4d9fbcc90..9b51e25a9583ec72498f29b8b0542f3554f25e51 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
index 7c4e6dc1ed59961e0df2f14fcbc9805c5a2cc359..18f9a8e0bf3b535385e964f8c107ccf208f52d30 100644 (file)
@@ -561,7 +561,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
        int ret;
 
        if (!pdev) {
-               dev_err(dev->dev, "no a4xx device\n");
+               DRM_DEV_ERROR(dev->dev, "no a4xx device\n");
                ret = -ENXIO;
                goto fail;
        }
@@ -608,7 +608,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
                 * to not be possible to restrict access, then we must
                 * implement a cmdstream validator.
                 */
-               dev_err(dev->dev, "No memory protection without IOMMU\n");
+               DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");
                ret = -ENXIO;
                goto fail;
        }
index b4944cc0e62f903b3d4fa653bc0064e54db722ee..cf4fe14ddd6ec05c158fa173f0dbafbbdec8b3a2 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
index d2127b1c4eced57a0fa2233550258c17d449a33b..d9af3aff690f1613f2ca4a65328683b6a8a845f2 100644 (file)
@@ -130,15 +130,13 @@ reset_set(void *data, u64 val)
        adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
 
        if (a5xx_gpu->pm4_bo) {
-               if (a5xx_gpu->pm4_iova)
-                       msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
+               msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
                drm_gem_object_put(a5xx_gpu->pm4_bo);
                a5xx_gpu->pm4_bo = NULL;
        }
 
        if (a5xx_gpu->pfp_bo) {
-               if (a5xx_gpu->pfp_iova)
-                       msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
+               msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
                drm_gem_object_put(a5xx_gpu->pfp_bo);
                a5xx_gpu->pfp_bo = NULL;
        }
@@ -173,7 +171,7 @@ int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
                        minor->debugfs_root, minor);
 
        if (ret) {
-               dev_err(dev->dev, "could not install a5xx_debugfs_list\n");
+               DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
                return ret;
        }
 
index 48b5304f460cccf7249b31424e361670eada65f0..d5f5e56422f577f9fa6edd00fa1cd2be4575856f 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/soc/qcom/mdt_loader.h>
 #include <linux/pm_opp.h>
 #include <linux/nvmem-consumer.h>
-#include <linux/iopoll.h>
 #include <linux/slab.h>
 #include "msm_gem.h"
 #include "msm_mmu.h"
@@ -511,13 +510,16 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
                a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu,
                        adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova);
 
+
                if (IS_ERR(a5xx_gpu->pm4_bo)) {
                        ret = PTR_ERR(a5xx_gpu->pm4_bo);
                        a5xx_gpu->pm4_bo = NULL;
-                       dev_err(gpu->dev->dev, "could not allocate PM4: %d\n",
+                       DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PM4: %d\n",
                                ret);
                        return ret;
                }
+
+               msm_gem_object_set_name(a5xx_gpu->pm4_bo, "pm4fw");
        }
 
        if (!a5xx_gpu->pfp_bo) {
@@ -527,10 +529,12 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
                if (IS_ERR(a5xx_gpu->pfp_bo)) {
                        ret = PTR_ERR(a5xx_gpu->pfp_bo);
                        a5xx_gpu->pfp_bo = NULL;
-                       dev_err(gpu->dev->dev, "could not allocate PFP: %d\n",
+                       DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PFP: %d\n",
                                ret);
                        return ret;
                }
+
+               msm_gem_object_set_name(a5xx_gpu->pfp_bo, "pfpfw");
        }
 
        gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO,
@@ -841,20 +845,17 @@ static void a5xx_destroy(struct msm_gpu *gpu)
        a5xx_preempt_fini(gpu);
 
        if (a5xx_gpu->pm4_bo) {
-               if (a5xx_gpu->pm4_iova)
-                       msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
+               msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
                drm_gem_object_put_unlocked(a5xx_gpu->pm4_bo);
        }
 
        if (a5xx_gpu->pfp_bo) {
-               if (a5xx_gpu->pfp_iova)
-                       msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
+               msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
                drm_gem_object_put_unlocked(a5xx_gpu->pfp_bo);
        }
 
        if (a5xx_gpu->gpmu_bo) {
-               if (a5xx_gpu->gpmu_iova)
-                       msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace);
+               msm_gem_unpin_iova(a5xx_gpu->gpmu_bo, gpu->aspace);
                drm_gem_object_put_unlocked(a5xx_gpu->gpmu_bo);
        }
 
@@ -1028,7 +1029,7 @@ static void a5xx_fault_detect_irq(struct msm_gpu *gpu)
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu);
 
-       dev_err(dev->dev, "gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n",
+       DRM_DEV_ERROR(dev->dev, "gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n",
                ring ? ring->id : -1, ring ? ring->seqno : 0,
                gpu_read(gpu, REG_A5XX_RBBM_STATUS),
                gpu_read(gpu, REG_A5XX_CP_RB_RPTR),
@@ -1134,7 +1135,7 @@ static const u32 a5xx_registers[] = {
 
 static void a5xx_dump(struct msm_gpu *gpu)
 {
-       dev_info(gpu->dev->dev, "status:   %08x\n",
+       DRM_DEV_INFO(gpu->dev->dev, "status:   %08x\n",
                gpu_read(gpu, REG_A5XX_RBBM_STATUS));
        adreno_dump(gpu);
 }
@@ -1211,10 +1212,6 @@ struct a5xx_gpu_state {
        u32 *hlsqregs;
 };
 
-#define gpu_poll_timeout(gpu, addr, val, cond, interval, timeout) \
-       readl_poll_timeout((gpu)->mmio + ((addr) << 2), val, cond, \
-               interval, timeout)
-
 static int a5xx_crashdumper_init(struct msm_gpu *gpu,
                struct a5xx_crashdumper *dumper)
 {
@@ -1222,19 +1219,10 @@ static int a5xx_crashdumper_init(struct msm_gpu *gpu,
                SZ_1M, MSM_BO_UNCACHED, gpu->aspace,
                &dumper->bo, &dumper->iova);
 
-       if (IS_ERR(dumper->ptr))
-               return PTR_ERR(dumper->ptr);
-
-       return 0;
-}
-
-static void a5xx_crashdumper_free(struct msm_gpu *gpu,
-               struct a5xx_crashdumper *dumper)
-{
-       msm_gem_put_iova(dumper->bo, gpu->aspace);
-       msm_gem_put_vaddr(dumper->bo);
+       if (!IS_ERR(dumper->ptr))
+               msm_gem_object_set_name(dumper->bo, "crashdump");
 
-       drm_gem_object_put(dumper->bo);
+       return PTR_ERR_OR_ZERO(dumper->ptr);
 }
 
 static int a5xx_crashdumper_run(struct msm_gpu *gpu,
@@ -1329,7 +1317,7 @@ static void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu,
 
        if (a5xx_crashdumper_run(gpu, &dumper)) {
                kfree(a5xx_state->hlsqregs);
-               a5xx_crashdumper_free(gpu, &dumper);
+               msm_gem_kernel_put(dumper.bo, gpu->aspace, true);
                return;
        }
 
@@ -1337,7 +1325,7 @@ static void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu,
        memcpy(a5xx_state->hlsqregs, dumper.ptr + (256 * SZ_1K),
                count * sizeof(u32));
 
-       a5xx_crashdumper_free(gpu, &dumper);
+       msm_gem_kernel_put(dumper.bo, gpu->aspace, true);
 }
 
 static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu)
@@ -1508,7 +1496,7 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
        int ret;
 
        if (!pdev) {
-               dev_err(dev->dev, "No A5XX device is defined\n");
+               DRM_DEV_ERROR(dev->dev, "No A5XX device is defined\n");
                return ERR_PTR(-ENXIO);
        }
 
index 7a41e1c147e4208861076d1d6ab0ad9f1cff5a78..70e65c94e52514e1be323313c36e536de26ef76a 100644 (file)
@@ -298,7 +298,9 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
                MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace,
                &a5xx_gpu->gpmu_bo, &a5xx_gpu->gpmu_iova);
        if (IS_ERR(ptr))
-               goto err;
+               return;
+
+       msm_gem_object_set_name(a5xx_gpu->gpmu_bo, "gpmufw");
 
        while (cmds_size > 0) {
                int i;
@@ -317,15 +319,4 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 
        msm_gem_put_vaddr(a5xx_gpu->gpmu_bo);
        a5xx_gpu->gpmu_dwords = dwords;
-
-       return;
-err:
-       if (a5xx_gpu->gpmu_iova)
-               msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace);
-       if (a5xx_gpu->gpmu_bo)
-               drm_gem_object_put(a5xx_gpu->gpmu_bo);
-
-       a5xx_gpu->gpmu_bo = NULL;
-       a5xx_gpu->gpmu_iova = 0;
-       a5xx_gpu->gpmu_dwords = 0;
 }
index 4c357ead1be62956edf987080a40761e1f20d7b3..3d62310a535fbd1e3b746cc6c23bec3d81e1668c 100644 (file)
@@ -92,7 +92,7 @@ static void a5xx_preempt_timer(struct timer_list *t)
        if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED))
                return;
 
-       dev_err(dev->dev, "%s: preemption timed out\n", gpu->name);
+       DRM_DEV_ERROR(dev->dev, "%s: preemption timed out\n", gpu->name);
        queue_work(priv->wq, &gpu->recover_work);
 }
 
@@ -188,7 +188,7 @@ void a5xx_preempt_irq(struct msm_gpu *gpu)
        status = gpu_read(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL);
        if (unlikely(status)) {
                set_preempt_state(a5xx_gpu, PREEMPT_FAULTED);
-               dev_err(dev->dev, "%s: Preemption failed to complete\n",
+               DRM_DEV_ERROR(dev->dev, "%s: Preemption failed to complete\n",
                        gpu->name);
                queue_work(priv->wq, &gpu->recover_work);
                return;
@@ -245,6 +245,8 @@ static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu,
        if (IS_ERR(ptr))
                return PTR_ERR(ptr);
 
+       msm_gem_object_set_name(bo, "preempt");
+
        a5xx_gpu->preempt_bo[ring->id] = bo;
        a5xx_gpu->preempt_iova[ring->id] = iova;
        a5xx_gpu->preempt[ring->id] = ptr;
@@ -267,18 +269,8 @@ void a5xx_preempt_fini(struct msm_gpu *gpu)
        struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
        int i;
 
-       for (i = 0; i < gpu->nr_rings; i++) {
-               if (!a5xx_gpu->preempt_bo[i])
-                       continue;
-
-               msm_gem_put_vaddr(a5xx_gpu->preempt_bo[i]);
-
-               if (a5xx_gpu->preempt_iova[i])
-                       msm_gem_put_iova(a5xx_gpu->preempt_bo[i], gpu->aspace);
-
-               drm_gem_object_put(a5xx_gpu->preempt_bo[i]);
-               a5xx_gpu->preempt_bo[i] = NULL;
-       }
+       for (i = 0; i < gpu->nr_rings; i++)
+               msm_gem_kernel_put(a5xx_gpu->preempt_bo[i], gpu->aspace, true);
 }
 
 void a5xx_preempt_init(struct msm_gpu *gpu)
index a6f7c40454a6ea6a64633a3b202edace4a0bf9da..f44553ec3193577a0ee7f4ff6c8939ea3ff5b63e 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
@@ -501,7 +501,7 @@ enum a6xx_vfd_perfcounter_select {
        PERF_VFDP_VS_STAGE_WAVES = 22,
 };
 
-enum a6xx_hslq_perfcounter_select {
+enum a6xx_hlsq_perfcounter_select {
        PERF_HLSQ_BUSY_CYCLES = 0,
        PERF_HLSQ_STALL_CYCLES_UCHE = 1,
        PERF_HLSQ_STALL_CYCLES_SP_STATE = 2,
@@ -2959,6 +2959,8 @@ static inline uint32_t A6XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(uint32_t val)
 #define A6XX_GRAS_LRZ_CNTL_ENABLE                              0x00000001
 #define A6XX_GRAS_LRZ_CNTL_LRZ_WRITE                           0x00000002
 #define A6XX_GRAS_LRZ_CNTL_GREATER                             0x00000004
+#define A6XX_GRAS_LRZ_CNTL_UNK3                                        0x00000008
+#define A6XX_GRAS_LRZ_CNTL_UNK4                                        0x00000010
 
 #define REG_A6XX_GRAS_UNKNOWN_8101                             0x00008101
 
@@ -2997,6 +2999,13 @@ static inline uint32_t A6XX_GRAS_LRZ_BUFFER_PITCH_ARRAY_PITCH(uint32_t val)
 #define REG_A6XX_GRAS_UNKNOWN_8110                             0x00008110
 
 #define REG_A6XX_GRAS_2D_BLIT_CNTL                             0x00008400
+#define A6XX_GRAS_2D_BLIT_CNTL_COLOR_FORMAT__MASK              0x0000ff00
+#define A6XX_GRAS_2D_BLIT_CNTL_COLOR_FORMAT__SHIFT             8
+static inline uint32_t A6XX_GRAS_2D_BLIT_CNTL_COLOR_FORMAT(enum a6xx_color_fmt val)
+{
+       return ((val) << A6XX_GRAS_2D_BLIT_CNTL_COLOR_FORMAT__SHIFT) & A6XX_GRAS_2D_BLIT_CNTL_COLOR_FORMAT__MASK;
+}
+#define A6XX_GRAS_2D_BLIT_CNTL_SCISSOR                         0x00010000
 
 #define REG_A6XX_GRAS_2D_SRC_TL_X                              0x00008401
 #define A6XX_GRAS_2D_SRC_TL_X_X__MASK                          0x00ffff00
@@ -3449,6 +3458,7 @@ static inline uint32_t A6XX_RB_BLEND_CNTL_ENABLE_BLEND(uint32_t val)
        return ((val) << A6XX_RB_BLEND_CNTL_ENABLE_BLEND__SHIFT) & A6XX_RB_BLEND_CNTL_ENABLE_BLEND__MASK;
 }
 #define A6XX_RB_BLEND_CNTL_INDEPENDENT_BLEND                   0x00000100
+#define A6XX_RB_BLEND_CNTL_ALPHA_TO_COVERAGE                   0x00000400
 #define A6XX_RB_BLEND_CNTL_SAMPLE_MASK__MASK                   0xffff0000
 #define A6XX_RB_BLEND_CNTL_SAMPLE_MASK__SHIFT                  16
 static inline uint32_t A6XX_RB_BLEND_CNTL_SAMPLE_MASK(uint32_t val)
@@ -3642,6 +3652,9 @@ static inline uint32_t A6XX_RB_WINDOW_OFFSET_Y(uint32_t val)
 #define REG_A6XX_RB_SAMPLE_COUNT_CONTROL                       0x00008891
 #define A6XX_RB_SAMPLE_COUNT_CONTROL_COPY                      0x00000002
 
+#define REG_A6XX_RB_LRZ_CNTL                                   0x00008898
+#define A6XX_RB_LRZ_CNTL_ENABLE                                        0x00000001
+
 #define REG_A6XX_RB_UNKNOWN_88D0                               0x000088d0
 
 #define REG_A6XX_RB_BLIT_SCISSOR_TL                            0x000088d1
@@ -3674,6 +3687,14 @@ static inline uint32_t A6XX_RB_BLIT_SCISSOR_BR_Y(uint32_t val)
        return ((val) << A6XX_RB_BLIT_SCISSOR_BR_Y__SHIFT) & A6XX_RB_BLIT_SCISSOR_BR_Y__MASK;
 }
 
+#define REG_A6XX_RB_MSAA_CNTL                                  0x000088d5
+#define A6XX_RB_MSAA_CNTL_SAMPLES__MASK                                0x00000018
+#define A6XX_RB_MSAA_CNTL_SAMPLES__SHIFT                       3
+static inline uint32_t A6XX_RB_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val)
+{
+       return ((val) << A6XX_RB_MSAA_CNTL_SAMPLES__SHIFT) & A6XX_RB_MSAA_CNTL_SAMPLES__MASK;
+}
+
 #define REG_A6XX_RB_BLIT_BASE_GMEM                             0x000088d6
 
 #define REG_A6XX_RB_BLIT_DST_INFO                              0x000088d7
@@ -3684,6 +3705,12 @@ static inline uint32_t A6XX_RB_BLIT_DST_INFO_TILE_MODE(enum a6xx_tile_mode val)
        return ((val) << A6XX_RB_BLIT_DST_INFO_TILE_MODE__SHIFT) & A6XX_RB_BLIT_DST_INFO_TILE_MODE__MASK;
 }
 #define A6XX_RB_BLIT_DST_INFO_FLAGS                            0x00000004
+#define A6XX_RB_BLIT_DST_INFO_SAMPLES__MASK                    0x00000018
+#define A6XX_RB_BLIT_DST_INFO_SAMPLES__SHIFT                   3
+static inline uint32_t A6XX_RB_BLIT_DST_INFO_SAMPLES(enum a3xx_msaa_samples val)
+{
+       return ((val) << A6XX_RB_BLIT_DST_INFO_SAMPLES__SHIFT) & A6XX_RB_BLIT_DST_INFO_SAMPLES__MASK;
+}
 #define A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT__MASK               0x00007f80
 #define A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT__SHIFT              7
 static inline uint32_t A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(enum a6xx_color_fmt val)
@@ -3780,6 +3807,9 @@ static inline uint32_t A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT(enum a6xx_color_fmt val
 {
        return ((val) << A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT__SHIFT) & A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT__MASK;
 }
+#define A6XX_RB_2D_BLIT_CNTL_SCISSOR                           0x00010000
+
+#define REG_A6XX_RB_UNKNOWN_8C01                               0x00008c01
 
 #define REG_A6XX_RB_2D_DST_INFO                                        0x00008c17
 #define A6XX_RB_2D_DST_INFO_COLOR_FORMAT__MASK                 0x000000ff
@@ -4465,6 +4495,7 @@ static inline uint32_t A6XX_SP_FS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val)
 #define REG_A6XX_SP_BLEND_CNTL                                 0x0000a989
 #define A6XX_SP_BLEND_CNTL_ENABLED                             0x00000001
 #define A6XX_SP_BLEND_CNTL_UNK8                                        0x00000100
+#define A6XX_SP_BLEND_CNTL_ALPHA_TO_COVERAGE                   0x00000400
 
 #define REG_A6XX_SP_SRGB_CNTL                                  0x0000a98a
 #define A6XX_SP_SRGB_CNTL_SRGB_MRT0                            0x00000001
@@ -4643,6 +4674,8 @@ static inline uint32_t A6XX_SP_FS_CONFIG_NSAMP(uint32_t val)
 
 #define REG_A6XX_SP_UNKNOWN_AB20                               0x0000ab20
 
+#define REG_A6XX_SP_UNKNOWN_ACC0                               0x0000acc0
+
 #define REG_A6XX_SP_UNKNOWN_AE00                               0x0000ae00
 
 #define REG_A6XX_SP_UNKNOWN_AE03                               0x0000ae03
@@ -4700,11 +4733,34 @@ static inline uint32_t A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(enum a3xx_color_swap va
        return ((val) << A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP__SHIFT) & A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP__MASK;
 }
 #define A6XX_SP_PS_2D_SRC_INFO_FLAGS                           0x00001000
+#define A6XX_SP_PS_2D_SRC_INFO_FILTER                          0x00010000
+
+#define REG_A6XX_SP_PS_2D_SRC_SIZE                             0x0000b4c1
+#define A6XX_SP_PS_2D_SRC_SIZE_WIDTH__MASK                     0x00007fff
+#define A6XX_SP_PS_2D_SRC_SIZE_WIDTH__SHIFT                    0
+static inline uint32_t A6XX_SP_PS_2D_SRC_SIZE_WIDTH(uint32_t val)
+{
+       return ((val) << A6XX_SP_PS_2D_SRC_SIZE_WIDTH__SHIFT) & A6XX_SP_PS_2D_SRC_SIZE_WIDTH__MASK;
+}
+#define A6XX_SP_PS_2D_SRC_SIZE_HEIGHT__MASK                    0x3fff8000
+#define A6XX_SP_PS_2D_SRC_SIZE_HEIGHT__SHIFT                   15
+static inline uint32_t A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val) << A6XX_SP_PS_2D_SRC_SIZE_HEIGHT__SHIFT) & A6XX_SP_PS_2D_SRC_SIZE_HEIGHT__MASK;
+}
 
 #define REG_A6XX_SP_PS_2D_SRC_LO                               0x0000b4c2
 
 #define REG_A6XX_SP_PS_2D_SRC_HI                               0x0000b4c3
 
+#define REG_A6XX_SP_PS_2D_SRC_PITCH                            0x0000b4c4
+#define A6XX_SP_PS_2D_SRC_PITCH_PITCH__MASK                    0x01fffe00
+#define A6XX_SP_PS_2D_SRC_PITCH_PITCH__SHIFT                   9
+static inline uint32_t A6XX_SP_PS_2D_SRC_PITCH_PITCH(uint32_t val)
+{
+       return ((val >> 6) << A6XX_SP_PS_2D_SRC_PITCH_PITCH__SHIFT) & A6XX_SP_PS_2D_SRC_PITCH_PITCH__MASK;
+}
+
 #define REG_A6XX_SP_PS_2D_SRC_FLAGS_LO                         0x0000b4ca
 
 #define REG_A6XX_SP_PS_2D_SRC_FLAGS_HI                         0x0000b4cb
@@ -5033,6 +5089,12 @@ static inline uint32_t A6XX_TEX_CONST_0_MIPLVLS(uint32_t val)
 {
        return ((val) << A6XX_TEX_CONST_0_MIPLVLS__SHIFT) & A6XX_TEX_CONST_0_MIPLVLS__MASK;
 }
+#define A6XX_TEX_CONST_0_SAMPLES__MASK                         0x00300000
+#define A6XX_TEX_CONST_0_SAMPLES__SHIFT                                20
+static inline uint32_t A6XX_TEX_CONST_0_SAMPLES(enum a3xx_msaa_samples val)
+{
+       return ((val) << A6XX_TEX_CONST_0_SAMPLES__SHIFT) & A6XX_TEX_CONST_0_SAMPLES__MASK;
+}
 #define A6XX_TEX_CONST_0_FMT__MASK                             0x3fc00000
 #define A6XX_TEX_CONST_0_FMT__SHIFT                            22
 static inline uint32_t A6XX_TEX_CONST_0_FMT(enum a6xx_tex_fmt val)
@@ -5365,5 +5427,9 @@ static inline uint32_t A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1_BYTEL15(uint32_t val)
 
 #define REG_A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2                 0x00000030
 
+#define REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_0                   0x00000001
+
+#define REG_A6XX_CX_MISC_SYSTEM_CACHE_CNTL_1                   0x00000002
+
 
 #endif /* A6XX_XML */
index d4e98e5876bc4a7fbab76c9760c2e548afdfea73..c58e953fefa3b25343e1b7d3ebeb8ce1277c8b8f 100644 (file)
@@ -51,10 +51,31 @@ static irqreturn_t a6xx_hfi_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
+{
+       u32 val;
+
+       /* This can be called from gpu state code so make sure GMU is valid */
+       if (IS_ERR_OR_NULL(gmu->mmio))
+               return false;
+
+       val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
+
+       return !(val &
+               (A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_SPTPRAC_GDSC_POWER_OFF |
+               A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_SP_CLOCK_OFF));
+}
+
 /* Check to see if the GX rail is still powered */
-static bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
+bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
 {
-       u32 val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
+       u32 val;
+
+       /* This can be called from gpu state code so make sure GMU is valid */
+       if (IS_ERR_OR_NULL(gmu->mmio))
+               return false;
+
+       val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS);
 
        return !(val &
                (A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
@@ -153,7 +174,7 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
                val == 0xbabeface, 100, 10000);
 
        if (ret)
-               dev_err(gmu->dev, "GMU firmware initialization timed out\n");
+               DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
 
        return ret;
 }
@@ -168,7 +189,7 @@ static int a6xx_gmu_hfi_start(struct a6xx_gmu *gmu)
        ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_HFI_CTRL_STATUS, val,
                val & 1, 100, 10000);
        if (ret)
-               dev_err(gmu->dev, "Unable to start the HFI queues\n");
+               DRM_DEV_ERROR(gmu->dev, "Unable to start the HFI queues\n");
 
        return ret;
 }
@@ -209,7 +230,7 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
                val & (1 << ack), 100, 10000);
 
        if (ret)
-               dev_err(gmu->dev,
+               DRM_DEV_ERROR(gmu->dev,
                        "Timeout waiting for GMU OOB set %s: 0x%x\n",
                                name,
                                gmu_read(gmu, REG_A6XX_GMU_GMU2HOST_INTR_INFO));
@@ -251,7 +272,7 @@ static int a6xx_sptprac_enable(struct a6xx_gmu *gmu)
                (val & 0x38) == 0x28, 1, 100);
 
        if (ret) {
-               dev_err(gmu->dev, "Unable to power on SPTPRAC: 0x%x\n",
+               DRM_DEV_ERROR(gmu->dev, "Unable to power on SPTPRAC: 0x%x\n",
                        gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS));
        }
 
@@ -273,7 +294,7 @@ static void a6xx_sptprac_disable(struct a6xx_gmu *gmu)
                (val & 0x04), 100, 10000);
 
        if (ret)
-               dev_err(gmu->dev, "failed to power off SPTPRAC: 0x%x\n",
+               DRM_DEV_ERROR(gmu->dev, "failed to power off SPTPRAC: 0x%x\n",
                        gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS));
 }
 
@@ -317,7 +338,7 @@ static int a6xx_gmu_notify_slumber(struct a6xx_gmu *gmu)
                /* Check to see if the GMU really did slumber */
                if (gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE)
                        != 0x0f) {
-                       dev_err(gmu->dev, "The GMU did not go into slumber\n");
+                       DRM_DEV_ERROR(gmu->dev, "The GMU did not go into slumber\n");
                        ret = -ETIMEDOUT;
                }
        }
@@ -339,23 +360,27 @@ static int a6xx_rpmh_start(struct a6xx_gmu *gmu)
        ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_RSCC_CONTROL_ACK, val,
                val & (1 << 1), 100, 10000);
        if (ret) {
-               dev_err(gmu->dev, "Unable to power on the GPU RSC\n");
+               DRM_DEV_ERROR(gmu->dev, "Unable to power on the GPU RSC\n");
                return ret;
        }
 
        ret = gmu_poll_timeout(gmu, REG_A6XX_RSCC_SEQ_BUSY_DRV0, val,
                !val, 100, 10000);
 
-       if (!ret) {
-               gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 0);
-
-               /* Re-enable the power counter */
-               gmu_write(gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1);
-               return 0;
+       if (ret) {
+               DRM_DEV_ERROR(gmu->dev, "GPU RSC sequence stuck while waking up the GPU\n");
+               return ret;
        }
 
-       dev_err(gmu->dev, "GPU RSC sequence stuck while waking up the GPU\n");
-       return ret;
+       gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 0);
+
+       /* Set up CX GMU counter 0 to count busy ticks */
+       gmu_write(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xff000000);
+       gmu_rmw(gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, 0xff, 0x20);
+
+       /* Enable the power counter */
+       gmu_write(gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1);
+       return 0;
 }
 
 static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
@@ -368,7 +393,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
        ret = gmu_poll_timeout(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0,
                val, val & (1 << 16), 100, 10000);
        if (ret)
-               dev_err(gmu->dev, "Unable to power off the GPU RSC\n");
+               DRM_DEV_ERROR(gmu->dev, "Unable to power off the GPU RSC\n");
 
        gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 0);
 }
@@ -520,7 +545,7 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
 
                /* Sanity check the size of the firmware that was loaded */
                if (adreno_gpu->fw[ADRENO_FW_GMU]->size > 0x8000) {
-                       dev_err(gmu->dev,
+                       DRM_DEV_ERROR(gmu->dev,
                                "GMU firmware is bigger than the available region\n");
                        return -EINVAL;
                }
@@ -764,7 +789,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
                 */
 
                if (ret)
-                       dev_err(gmu->dev,
+                       DRM_DEV_ERROR(gmu->dev,
                                "Unable to slumber GMU: status = 0%x/0%x\n",
                                gmu_read(gmu,
                                        REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS),
@@ -843,7 +868,7 @@ static struct a6xx_gmu_bo *a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu,
                        IOMMU_READ | IOMMU_WRITE);
 
                if (ret) {
-                       dev_err(gmu->dev, "Unable to map GMU buffer object\n");
+                       DRM_DEV_ERROR(gmu->dev, "Unable to map GMU buffer object\n");
 
                        for (i = i - 1 ; i >= 0; i--)
                                iommu_unmap(gmu->domain,
@@ -969,12 +994,12 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes,
                }
 
                if (j == pri_count) {
-                       dev_err(dev,
+                       DRM_DEV_ERROR(dev,
                                "Level %u not found in in the RPMh list\n",
                                        level);
-                       dev_err(dev, "Available levels:\n");
+                       DRM_DEV_ERROR(dev, "Available levels:\n");
                        for (j = 0; j < pri_count; j++)
-                               dev_err(dev, "  %u\n", pri[j]);
+                               DRM_DEV_ERROR(dev, "  %u\n", pri[j]);
 
                        return -EINVAL;
                }
@@ -1081,7 +1106,7 @@ static int a6xx_gmu_pwrlevels_probe(struct a6xx_gmu *gmu)
         */
        ret = dev_pm_opp_of_add_table(gmu->dev);
        if (ret) {
-               dev_err(gmu->dev, "Unable to set the OPP table for the GMU\n");
+               DRM_DEV_ERROR(gmu->dev, "Unable to set the OPP table for the GMU\n");
                return ret;
        }
 
@@ -1122,13 +1147,13 @@ static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev,
                        IORESOURCE_MEM, name);
 
        if (!res) {
-               dev_err(&pdev->dev, "Unable to find the %s registers\n", name);
+               DRM_DEV_ERROR(&pdev->dev, "Unable to find the %s registers\n", name);
                return ERR_PTR(-EINVAL);
        }
 
        ret = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!ret) {
-               dev_err(&pdev->dev, "Unable to map the %s registers\n", name);
+               DRM_DEV_ERROR(&pdev->dev, "Unable to map the %s registers\n", name);
                return ERR_PTR(-EINVAL);
        }
 
@@ -1145,7 +1170,7 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev,
        ret = devm_request_irq(&pdev->dev, irq, handler, IRQF_TRIGGER_HIGH,
                name, gmu);
        if (ret) {
-               dev_err(&pdev->dev, "Unable to get interrupt %s\n", name);
+               DRM_DEV_ERROR(&pdev->dev, "Unable to get interrupt %s\n", name);
                return ret;
        }
 
index 35f765afae45b7e427faa837e51e56f021a6d487..c721d9165d8ec61a4ba0efd833de3bc67b74d40d 100644 (file)
@@ -164,4 +164,7 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu);
 int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state);
 void a6xx_hfi_stop(struct a6xx_gmu *gmu);
 
+bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu);
+bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu);
+
 #endif
index db56f263ed77fa35a9551d4b3b60726dfd9b6c3b..1cc1c135236b1a85a710de55a70f8c00ca6637ff 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
index 631257c297fd0db6bb74565f76859d5419c1f25a..fefe773c989e0760d0a29fee2c0b7224aa6d74ef 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "msm_gem.h"
 #include "msm_mmu.h"
+#include "msm_gpu_trace.h"
 #include "a6xx_gpu.h"
 #include "a6xx_gmu.xml.h"
 
@@ -67,13 +68,36 @@ static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
        gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
 }
 
+static void get_stats_counter(struct msm_ringbuffer *ring, u32 counter,
+               u64 iova)
+{
+       OUT_PKT7(ring, CP_REG_TO_MEM, 3);
+       OUT_RING(ring, counter | (1 << 30) | (2 << 18));
+       OUT_RING(ring, lower_32_bits(iova));
+       OUT_RING(ring, upper_32_bits(iova));
+}
+
 static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
        struct msm_file_private *ctx)
 {
+       unsigned int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
        struct msm_drm_private *priv = gpu->dev->dev_private;
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
        struct msm_ringbuffer *ring = submit->ring;
        unsigned int i;
 
+       get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP_0_LO,
+               rbmemptr_stats(ring, index, cpcycles_start));
+
+       /*
+        * For PM4 the GMU register offsets are calculated from the base of the
+        * GPU registers so we need to add 0x1a800 to the register value on A630
+        * to get the right value from PM4.
+        */
+       get_stats_counter(ring, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L + 0x1a800,
+               rbmemptr_stats(ring, index, alwayson_start));
+
        /* Invalidate CCU depth and color */
        OUT_PKT7(ring, CP_EVENT_WRITE, 1);
        OUT_RING(ring, PC_CCU_INVALIDATE_DEPTH);
@@ -98,6 +122,11 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                }
        }
 
+       get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP_0_LO,
+               rbmemptr_stats(ring, index, cpcycles_end));
+       get_stats_counter(ring, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L + 0x1a800,
+               rbmemptr_stats(ring, index, alwayson_end));
+
        /* Write the fence to the scratch register */
        OUT_PKT4(ring, REG_A6XX_CP_SCRATCH_REG(2), 1);
        OUT_RING(ring, submit->seqno);
@@ -112,6 +141,10 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
        OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence)));
        OUT_RING(ring, submit->seqno);
 
+       trace_msm_gpu_submit_flush(submit,
+               gmu_read64(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L,
+                       REG_A6XX_GMU_ALWAYS_ON_COUNTER_H));
+
        a6xx_flush(gpu, ring);
 }
 
@@ -300,6 +333,8 @@ static int a6xx_ucode_init(struct msm_gpu *gpu)
 
                        return ret;
                }
+
+               msm_gem_object_set_name(a6xx_gpu->sqe_bo, "sqefw");
        }
 
        gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE_LO,
@@ -387,14 +422,6 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
        /* Select CP0 to always count cycles */
        gpu_write(gpu, REG_A6XX_CP_PERFCTR_CP_SEL_0, PERF_CP_ALWAYS_COUNT);
 
-       /* FIXME: not sure if this should live here or in a6xx_gmu.c */
-       gmu_write(&a6xx_gpu->gmu,  REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK,
-               0xff000000);
-       gmu_rmw(&a6xx_gpu->gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0,
-               0xff, 0x20);
-       gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE,
-               0x01);
-
        gpu_write(gpu, REG_A6XX_RB_NC_MODE_CNTL, 2 << 1);
        gpu_write(gpu, REG_A6XX_TPL1_NC_MODE_CNTL, 2 << 1);
        gpu_write(gpu, REG_A6XX_SP_NC_MODE_CNTL, 2 << 1);
@@ -481,7 +508,7 @@ out:
 
 static void a6xx_dump(struct msm_gpu *gpu)
 {
-       dev_info(&gpu->pdev->dev, "status:   %08x\n",
+       DRM_DEV_INFO(&gpu->pdev->dev, "status:   %08x\n",
                        gpu_read(gpu, REG_A6XX_RBBM_STATUS));
        adreno_dump(gpu);
 }
@@ -498,7 +525,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
        adreno_dump_info(gpu);
 
        for (i = 0; i < 8; i++)
-               dev_info(&gpu->pdev->dev, "CP_SCRATCH_REG%d: %u\n", i,
+               DRM_DEV_INFO(&gpu->pdev->dev, "CP_SCRATCH_REG%d: %u\n", i,
                        gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(i)));
 
        if (hang_debug)
@@ -645,33 +672,6 @@ static const u32 a6xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
        REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_A6XX_CP_RB_CNTL),
 };
 
-static const u32 a6xx_registers[] = {
-       0x0000, 0x0002, 0x0010, 0x0010, 0x0012, 0x0012, 0x0018, 0x001b,
-       0x001e, 0x0032, 0x0038, 0x003c, 0x0042, 0x0042, 0x0044, 0x0044,
-       0x0047, 0x0047, 0x0056, 0x0056, 0x00ad, 0x00ae, 0x00b0, 0x00fb,
-       0x0100, 0x011d, 0x0200, 0x020d, 0x0210, 0x0213, 0x0218, 0x023d,
-       0x0400, 0x04f9, 0x0500, 0x0500, 0x0505, 0x050b, 0x050e, 0x0511,
-       0x0533, 0x0533, 0x0540, 0x0555, 0x0800, 0x0808, 0x0810, 0x0813,
-       0x0820, 0x0821, 0x0823, 0x0827, 0x0830, 0x0833, 0x0840, 0x0843,
-       0x084f, 0x086f, 0x0880, 0x088a, 0x08a0, 0x08ab, 0x08c0, 0x08c4,
-       0x08d0, 0x08dd, 0x08f0, 0x08f3, 0x0900, 0x0903, 0x0908, 0x0911,
-       0x0928, 0x093e, 0x0942, 0x094d, 0x0980, 0x0984, 0x098d, 0x0996,
-       0x0998, 0x099e, 0x09a0, 0x09a6, 0x09a8, 0x09ae, 0x09b0, 0x09b1,
-       0x09c2, 0x09c8, 0x0a00, 0x0a03, 0x0c00, 0x0c04, 0x0c06, 0x0c06,
-       0x0c10, 0x0cd9, 0x0e00, 0x0e0e, 0x0e10, 0x0e13, 0x0e17, 0x0e19,
-       0x0e1c, 0x0e2b, 0x0e30, 0x0e32, 0x0e38, 0x0e39, 0x8600, 0x8601,
-       0x8610, 0x861b, 0x8620, 0x8620, 0x8628, 0x862b, 0x8630, 0x8637,
-       0x8e01, 0x8e01, 0x8e04, 0x8e05, 0x8e07, 0x8e08, 0x8e0c, 0x8e0c,
-       0x8e10, 0x8e1c, 0x8e20, 0x8e25, 0x8e28, 0x8e28, 0x8e2c, 0x8e2f,
-       0x8e3b, 0x8e3e, 0x8e40, 0x8e43, 0x8e50, 0x8e5e, 0x8e70, 0x8e77,
-       0x9600, 0x9604, 0x9624, 0x9637, 0x9e00, 0x9e01, 0x9e03, 0x9e0e,
-       0x9e11, 0x9e16, 0x9e19, 0x9e19, 0x9e1c, 0x9e1c, 0x9e20, 0x9e23,
-       0x9e30, 0x9e31, 0x9e34, 0x9e34, 0x9e70, 0x9e72, 0x9e78, 0x9e79,
-       0x9e80, 0x9fff, 0xa600, 0xa601, 0xa603, 0xa603, 0xa60a, 0xa60a,
-       0xa610, 0xa617, 0xa630, 0xa630,
-       ~0
-};
-
 static int a6xx_pm_resume(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -724,14 +724,6 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
        return 0;
 }
 
-#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
-static void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
-               struct drm_printer *p)
-{
-       adreno_show(gpu, state, p);
-}
-#endif
-
 static struct msm_ringbuffer *a6xx_active_ring(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -746,8 +738,7 @@ static void a6xx_destroy(struct msm_gpu *gpu)
        struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
 
        if (a6xx_gpu->sqe_bo) {
-               if (a6xx_gpu->sqe_iova)
-                       msm_gem_put_iova(a6xx_gpu->sqe_bo, gpu->aspace);
+               msm_gem_unpin_iova(a6xx_gpu->sqe_bo, gpu->aspace);
                drm_gem_object_put_unlocked(a6xx_gpu->sqe_bo);
        }
 
@@ -796,6 +787,8 @@ static const struct adreno_gpu_funcs funcs = {
                .gpu_busy = a6xx_gpu_busy,
                .gpu_get_freq = a6xx_gmu_get_freq,
                .gpu_set_freq = a6xx_gmu_set_freq,
+               .gpu_state_get = a6xx_gpu_state_get,
+               .gpu_state_put = a6xx_gpu_state_put,
        },
        .get_timestamp = a6xx_get_timestamp,
 };
@@ -817,7 +810,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
        adreno_gpu = &a6xx_gpu->base;
        gpu = &adreno_gpu->base;
 
-       adreno_gpu->registers = a6xx_registers;
+       adreno_gpu->registers = NULL;
        adreno_gpu->reg_offsets = a6xx_register_offsets;
 
        ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
index 4127dcebc20254a960d4ad565353fa370f69ae8a..528a4cfe07cda3f5d0963ed341f7856c19d93b6f 100644 (file)
@@ -56,6 +56,14 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
 
 int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
 void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
+
 void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq);
 unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu);
+
+void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
+               struct drm_printer *p);
+
+struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu);
+int a6xx_gpu_state_put(struct msm_gpu_state *state);
+
 #endif /* __A6XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
new file mode 100644 (file)
index 0000000..e686331
--- /dev/null
@@ -0,0 +1,1165 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#include <linux/ascii85.h>
+#include "msm_gem.h"
+#include "a6xx_gpu.h"
+#include "a6xx_gmu.h"
+#include "a6xx_gpu_state.h"
+#include "a6xx_gmu.xml.h"
+
+struct a6xx_gpu_state_obj {
+       const void *handle;
+       u32 *data;
+};
+
+struct a6xx_gpu_state {
+       struct msm_gpu_state base;
+
+       struct a6xx_gpu_state_obj *gmu_registers;
+       int nr_gmu_registers;
+
+       struct a6xx_gpu_state_obj *registers;
+       int nr_registers;
+
+       struct a6xx_gpu_state_obj *shaders;
+       int nr_shaders;
+
+       struct a6xx_gpu_state_obj *clusters;
+       int nr_clusters;
+
+       struct a6xx_gpu_state_obj *dbgahb_clusters;
+       int nr_dbgahb_clusters;
+
+       struct a6xx_gpu_state_obj *indexed_regs;
+       int nr_indexed_regs;
+
+       struct a6xx_gpu_state_obj *debugbus;
+       int nr_debugbus;
+
+       struct a6xx_gpu_state_obj *vbif_debugbus;
+
+       struct a6xx_gpu_state_obj *cx_debugbus;
+       int nr_cx_debugbus;
+
+       struct list_head objs;
+};
+
+static inline int CRASHDUMP_WRITE(u64 *in, u32 reg, u32 val)
+{
+       in[0] = val;
+       in[1] = (((u64) reg) << 44 | (1 << 21) | 1);
+
+       return 2;
+}
+
+static inline int CRASHDUMP_READ(u64 *in, u32 reg, u32 dwords, u64 target)
+{
+       in[0] = target;
+       in[1] = (((u64) reg) << 44 | dwords);
+
+       return 2;
+}
+
+static inline int CRASHDUMP_FINI(u64 *in)
+{
+       in[0] = 0;
+       in[1] = 0;
+
+       return 2;
+}
+
+struct a6xx_crashdumper {
+       void *ptr;
+       struct drm_gem_object *bo;
+       u64 iova;
+};
+
+struct a6xx_state_memobj {
+       struct list_head node;
+       unsigned long long data[];
+};
+
+void *state_kcalloc(struct a6xx_gpu_state *a6xx_state, int nr, size_t objsize)
+{
+       struct a6xx_state_memobj *obj =
+               kzalloc((nr * objsize) + sizeof(*obj), GFP_KERNEL);
+
+       if (!obj)
+               return NULL;
+
+       list_add_tail(&obj->node, &a6xx_state->objs);
+       return &obj->data;
+}
+
+void *state_kmemdup(struct a6xx_gpu_state *a6xx_state, void *src,
+               size_t size)
+{
+       void *dst = state_kcalloc(a6xx_state, 1, size);
+
+       if (dst)
+               memcpy(dst, src, size);
+       return dst;
+}
+
+/*
+ * Allocate 1MB for the crashdumper scratch region - 8k for the script and
+ * the rest for the data
+ */
+#define A6XX_CD_DATA_OFFSET 8192
+#define A6XX_CD_DATA_SIZE  (SZ_1M - 8192)
+
+static int a6xx_crashdumper_init(struct msm_gpu *gpu,
+               struct a6xx_crashdumper *dumper)
+{
+       dumper->ptr = msm_gem_kernel_new_locked(gpu->dev,
+               SZ_1M, MSM_BO_UNCACHED, gpu->aspace,
+               &dumper->bo, &dumper->iova);
+
+       if (!IS_ERR(dumper->ptr))
+               msm_gem_object_set_name(dumper->bo, "crashdump");
+
+       return PTR_ERR_OR_ZERO(dumper->ptr);
+}
+
+static int a6xx_crashdumper_run(struct msm_gpu *gpu,
+               struct a6xx_crashdumper *dumper)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       u32 val;
+       int ret;
+
+       if (IS_ERR_OR_NULL(dumper->ptr))
+               return -EINVAL;
+
+       if (!a6xx_gmu_sptprac_is_on(&a6xx_gpu->gmu))
+               return -EINVAL;
+
+       /* Make sure all pending memory writes are posted */
+       wmb();
+
+       gpu_write64(gpu, REG_A6XX_CP_CRASH_SCRIPT_BASE_LO,
+               REG_A6XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova);
+
+       gpu_write(gpu, REG_A6XX_CP_CRASH_DUMP_CNTL, 1);
+
+       ret = gpu_poll_timeout(gpu, REG_A6XX_CP_CRASH_DUMP_STATUS, val,
+               val & 0x02, 100, 10000);
+
+       gpu_write(gpu, REG_A6XX_CP_CRASH_DUMP_CNTL, 0);
+
+       return ret;
+}
+
+/* read a value from the GX debug bus */
+static int debugbus_read(struct msm_gpu *gpu, u32 block, u32 offset,
+               u32 *data)
+{
+       u32 reg = A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_INDEX(offset) |
+               A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_BLK_SEL(block);
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_A, reg);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_B, reg);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_C, reg);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_D, reg);
+
+       /* Wait 1 us to make sure the data is flowing */
+       udelay(1);
+
+       data[0] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF2);
+       data[1] = gpu_read(gpu, REG_A6XX_DBGC_CFG_DBGBUS_TRACE_BUF1);
+
+       return 2;
+}
+
+#define cxdbg_write(ptr, offset, val) \
+       msm_writel((val), (ptr) + ((offset) << 2))
+
+#define cxdbg_read(ptr, offset) \
+       msm_readl((ptr) + ((offset) << 2))
+
+/* read a value from the CX debug bus */
+static int cx_debugbus_read(void *__iomem cxdbg, u32 block, u32 offset,
+               u32 *data)
+{
+       u32 reg = A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_INDEX(offset) |
+               A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_BLK_SEL(block);
+
+       cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_A, reg);
+       cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_B, reg);
+       cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_C, reg);
+       cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_D, reg);
+
+       /* Wait 1 us to make sure the data is flowing */
+       udelay(1);
+
+       data[0] = cxdbg_read(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2);
+       data[1] = cxdbg_read(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF1);
+
+       return 2;
+}
+
+/* Read a chunk of data from the VBIF debug bus */
+static int vbif_debugbus_read(struct msm_gpu *gpu, u32 ctrl0, u32 ctrl1,
+               u32 reg, int count, u32 *data)
+{
+       int i;
+
+       gpu_write(gpu, ctrl0, reg);
+
+       for (i = 0; i < count; i++) {
+               gpu_write(gpu, ctrl1, i);
+               data[i] = gpu_read(gpu, REG_A6XX_VBIF_TEST_BUS_OUT);
+       }
+
+       return count;
+}
+
+#define AXI_ARB_BLOCKS 2
+#define XIN_AXI_BLOCKS 5
+#define XIN_CORE_BLOCKS 4
+
+#define VBIF_DEBUGBUS_BLOCK_SIZE \
+       ((16 * AXI_ARB_BLOCKS) + \
+        (18 * XIN_AXI_BLOCKS) + \
+        (12 * XIN_CORE_BLOCKS))
+
+static void a6xx_get_vbif_debugbus_block(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               struct a6xx_gpu_state_obj *obj)
+{
+       u32 clk, *ptr;
+       int i;
+
+       obj->data = state_kcalloc(a6xx_state, VBIF_DEBUGBUS_BLOCK_SIZE,
+               sizeof(u32));
+       if (!obj->data)
+               return;
+
+       obj->handle = NULL;
+
+       /* Get the current clock setting */
+       clk = gpu_read(gpu, REG_A6XX_VBIF_CLKON);
+
+       /* Force on the bus so we can read it */
+       gpu_write(gpu, REG_A6XX_VBIF_CLKON,
+               clk | A6XX_VBIF_CLKON_FORCE_ON_TESTBUS);
+
+       /* We will read from BUS2 first, so disable BUS1 */
+       gpu_write(gpu, REG_A6XX_VBIF_TEST_BUS1_CTRL0, 0);
+
+       /* Enable the VBIF bus for reading */
+       gpu_write(gpu, REG_A6XX_VBIF_TEST_BUS_OUT_CTRL, 1);
+
+       ptr = obj->data;
+
+       for (i = 0; i < AXI_ARB_BLOCKS; i++)
+               ptr += vbif_debugbus_read(gpu,
+                       REG_A6XX_VBIF_TEST_BUS2_CTRL0,
+                       REG_A6XX_VBIF_TEST_BUS2_CTRL1,
+                       1 << (i + 16), 16, ptr);
+
+       for (i = 0; i < XIN_AXI_BLOCKS; i++)
+               ptr += vbif_debugbus_read(gpu,
+                       REG_A6XX_VBIF_TEST_BUS2_CTRL0,
+                       REG_A6XX_VBIF_TEST_BUS2_CTRL1,
+                       1 << i, 18, ptr);
+
+       /* Stop BUS2 so we can turn on BUS1 */
+       gpu_write(gpu, REG_A6XX_VBIF_TEST_BUS2_CTRL0, 0);
+
+       for (i = 0; i < XIN_CORE_BLOCKS; i++)
+               ptr += vbif_debugbus_read(gpu,
+                       REG_A6XX_VBIF_TEST_BUS1_CTRL0,
+                       REG_A6XX_VBIF_TEST_BUS1_CTRL1,
+                       1 << i, 12, ptr);
+
+       /* Restore the VBIF clock setting */
+       gpu_write(gpu, REG_A6XX_VBIF_CLKON, clk);
+}
+
+static void a6xx_get_debugbus_block(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_debugbus_block *block,
+               struct a6xx_gpu_state_obj *obj)
+{
+       int i;
+       u32 *ptr;
+
+       obj->data = state_kcalloc(a6xx_state, block->count, sizeof(u64));
+       if (!obj->data)
+               return;
+
+       obj->handle = block;
+
+       for (ptr = obj->data, i = 0; i < block->count; i++)
+               ptr += debugbus_read(gpu, block->id, i, ptr);
+}
+
+static void a6xx_get_cx_debugbus_block(void __iomem *cxdbg,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_debugbus_block *block,
+               struct a6xx_gpu_state_obj *obj)
+{
+       int i;
+       u32 *ptr;
+
+       obj->data = state_kcalloc(a6xx_state, block->count, sizeof(u64));
+       if (!obj->data)
+               return;
+
+       obj->handle = block;
+
+       for (ptr = obj->data, i = 0; i < block->count; i++)
+               ptr += cx_debugbus_read(cxdbg, block->id, i, ptr);
+}
+
+static void a6xx_get_debugbus(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state)
+{
+       struct resource *res;
+       void __iomem *cxdbg = NULL;
+
+       /* Set up the GX debug bus */
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLT,
+               A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT(0xf));
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM,
+               A6XX_DBGC_CFG_DBGBUS_CNTLM_ENABLE(0xf));
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, 0x76543210);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_1, 0xFEDCBA98);
+
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+       gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+
+       /* Set up the CX debug bus - it lives elsewhere in the system so do a
+        * temporary ioremap for the registers
+        */
+       res = platform_get_resource_byname(gpu->pdev, IORESOURCE_MEM,
+                       "cx_dbgc");
+
+       if (res)
+               cxdbg = ioremap(res->start, resource_size(res));
+
+       if (cxdbg) {
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLT,
+                       A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT(0xf));
+
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM,
+                       A6XX_DBGC_CFG_DBGBUS_CNTLM_ENABLE(0xf));
+
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0,
+                       0x76543210);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_1,
+                       0xFEDCBA98);
+
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+               cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+       }
+
+       a6xx_state->debugbus = state_kcalloc(a6xx_state,
+               ARRAY_SIZE(a6xx_debugbus_blocks),
+               sizeof(*a6xx_state->debugbus));
+
+       if (a6xx_state->debugbus) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++)
+                       a6xx_get_debugbus_block(gpu,
+                               a6xx_state,
+                               &a6xx_debugbus_blocks[i],
+                               &a6xx_state->debugbus[i]);
+
+               a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks);
+       }
+
+       a6xx_state->vbif_debugbus =
+               state_kcalloc(a6xx_state, 1,
+                       sizeof(*a6xx_state->vbif_debugbus));
+
+       if (a6xx_state->vbif_debugbus)
+               a6xx_get_vbif_debugbus_block(gpu, a6xx_state,
+                       a6xx_state->vbif_debugbus);
+
+       if (cxdbg) {
+               a6xx_state->cx_debugbus =
+                       state_kcalloc(a6xx_state,
+                       ARRAY_SIZE(a6xx_cx_debugbus_blocks),
+                       sizeof(*a6xx_state->cx_debugbus));
+
+               if (a6xx_state->cx_debugbus) {
+                       int i;
+
+                       for (i = 0; i < ARRAY_SIZE(a6xx_cx_debugbus_blocks); i++)
+                               a6xx_get_cx_debugbus_block(cxdbg,
+                                       a6xx_state,
+                                       &a6xx_cx_debugbus_blocks[i],
+                                       &a6xx_state->cx_debugbus[i]);
+
+                       a6xx_state->nr_cx_debugbus =
+                               ARRAY_SIZE(a6xx_cx_debugbus_blocks);
+               }
+
+               iounmap(cxdbg);
+       }
+}
+
+#define RANGE(reg, a) ((reg)[(a) + 1] - (reg)[(a)] + 1)
+
+/* Read a data cluster from behind the AHB aperture */
+static void a6xx_get_dbgahb_cluster(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_dbgahb_cluster *dbgahb,
+               struct a6xx_gpu_state_obj *obj,
+               struct a6xx_crashdumper *dumper)
+{
+       u64 *in = dumper->ptr;
+       u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
+       size_t datasize;
+       int i, regcount = 0;
+
+       for (i = 0; i < A6XX_NUM_CONTEXTS; i++) {
+               int j;
+
+               in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL,
+                       (dbgahb->statetype + i * 2) << 8);
+
+               for (j = 0; j < dbgahb->count; j += 2) {
+                       int count = RANGE(dbgahb->registers, j);
+                       u32 offset = REG_A6XX_HLSQ_DBG_AHB_READ_APERTURE +
+                               dbgahb->registers[j] - (dbgahb->base >> 2);
+
+                       in += CRASHDUMP_READ(in, offset, count, out);
+
+                       out += count * sizeof(u32);
+
+                       if (i == 0)
+                               regcount += count;
+               }
+       }
+
+       CRASHDUMP_FINI(in);
+
+       datasize = regcount * A6XX_NUM_CONTEXTS * sizeof(u32);
+
+       if (WARN_ON(datasize > A6XX_CD_DATA_SIZE))
+               return;
+
+       if (a6xx_crashdumper_run(gpu, dumper))
+               return;
+
+       obj->handle = dbgahb;
+       obj->data = state_kmemdup(a6xx_state, dumper->ptr + A6XX_CD_DATA_OFFSET,
+               datasize);
+}
+
+static void a6xx_get_dbgahb_clusters(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               struct a6xx_crashdumper *dumper)
+{
+       int i;
+
+       a6xx_state->dbgahb_clusters = state_kcalloc(a6xx_state,
+               ARRAY_SIZE(a6xx_dbgahb_clusters),
+               sizeof(*a6xx_state->dbgahb_clusters));
+
+       if (!a6xx_state->dbgahb_clusters)
+               return;
+
+       a6xx_state->nr_dbgahb_clusters = ARRAY_SIZE(a6xx_dbgahb_clusters);
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_dbgahb_clusters); i++)
+               a6xx_get_dbgahb_cluster(gpu, a6xx_state,
+                       &a6xx_dbgahb_clusters[i],
+                       &a6xx_state->dbgahb_clusters[i], dumper);
+}
+
+/* Read a data cluster from the CP aperture with the crashdumper */
+static void a6xx_get_cluster(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_cluster *cluster,
+               struct a6xx_gpu_state_obj *obj,
+               struct a6xx_crashdumper *dumper)
+{
+       u64 *in = dumper->ptr;
+       u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
+       size_t datasize;
+       int i, regcount = 0;
+
+       /* Some clusters need a selector register to be programmed too */
+       if (cluster->sel_reg)
+               in += CRASHDUMP_WRITE(in, cluster->sel_reg, cluster->sel_val);
+
+       for (i = 0; i < A6XX_NUM_CONTEXTS; i++) {
+               int j;
+
+               in += CRASHDUMP_WRITE(in, REG_A6XX_CP_APERTURE_CNTL_CD,
+                       (cluster->id << 8) | (i << 4) | i);
+
+               for (j = 0; j < cluster->count; j += 2) {
+                       int count = RANGE(cluster->registers, j);
+
+                       in += CRASHDUMP_READ(in, cluster->registers[j],
+                               count, out);
+
+                       out += count * sizeof(u32);
+
+                       if (i == 0)
+                               regcount += count;
+               }
+       }
+
+       CRASHDUMP_FINI(in);
+
+       datasize = regcount * A6XX_NUM_CONTEXTS * sizeof(u32);
+
+       if (WARN_ON(datasize > A6XX_CD_DATA_SIZE))
+               return;
+
+       if (a6xx_crashdumper_run(gpu, dumper))
+               return;
+
+       obj->handle = cluster;
+       obj->data = state_kmemdup(a6xx_state, dumper->ptr + A6XX_CD_DATA_OFFSET,
+               datasize);
+}
+
+static void a6xx_get_clusters(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               struct a6xx_crashdumper *dumper)
+{
+       int i;
+
+       a6xx_state->clusters = state_kcalloc(a6xx_state,
+               ARRAY_SIZE(a6xx_clusters), sizeof(*a6xx_state->clusters));
+
+       if (!a6xx_state->clusters)
+               return;
+
+       a6xx_state->nr_clusters = ARRAY_SIZE(a6xx_clusters);
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_clusters); i++)
+               a6xx_get_cluster(gpu, a6xx_state, &a6xx_clusters[i],
+                       &a6xx_state->clusters[i], dumper);
+}
+
+/* Read a shader / debug block from the HLSQ aperture with the crashdumper */
+static void a6xx_get_shader_block(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_shader_block *block,
+               struct a6xx_gpu_state_obj *obj,
+               struct a6xx_crashdumper *dumper)
+{
+       u64 *in = dumper->ptr;
+       size_t datasize = block->size * A6XX_NUM_SHADER_BANKS * sizeof(u32);
+       int i;
+
+       if (WARN_ON(datasize > A6XX_CD_DATA_SIZE))
+               return;
+
+       for (i = 0; i < A6XX_NUM_SHADER_BANKS; i++) {
+               in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL,
+                       (block->type << 8) | i);
+
+               in += CRASHDUMP_READ(in, REG_A6XX_HLSQ_DBG_AHB_READ_APERTURE,
+                       block->size, dumper->iova + A6XX_CD_DATA_OFFSET);
+       }
+
+       CRASHDUMP_FINI(in);
+
+       if (a6xx_crashdumper_run(gpu, dumper))
+               return;
+
+       obj->handle = block;
+       obj->data = state_kmemdup(a6xx_state, dumper->ptr + A6XX_CD_DATA_OFFSET,
+               datasize);
+}
+
+static void a6xx_get_shaders(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               struct a6xx_crashdumper *dumper)
+{
+       int i;
+
+       a6xx_state->shaders = state_kcalloc(a6xx_state,
+               ARRAY_SIZE(a6xx_shader_blocks), sizeof(*a6xx_state->shaders));
+
+       if (!a6xx_state->shaders)
+               return;
+
+       a6xx_state->nr_shaders = ARRAY_SIZE(a6xx_shader_blocks);
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_shader_blocks); i++)
+               a6xx_get_shader_block(gpu, a6xx_state, &a6xx_shader_blocks[i],
+                       &a6xx_state->shaders[i], dumper);
+}
+
+/* Read registers from behind the HLSQ aperture with the crashdumper */
+static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_registers *regs,
+               struct a6xx_gpu_state_obj *obj,
+               struct a6xx_crashdumper *dumper)
+
+{
+       u64 *in = dumper->ptr;
+       u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
+       int i, regcount = 0;
+
+       in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1);
+
+       for (i = 0; i < regs->count; i += 2) {
+               u32 count = RANGE(regs->registers, i);
+               u32 offset = REG_A6XX_HLSQ_DBG_AHB_READ_APERTURE +
+                       regs->registers[i] - (regs->val0 >> 2);
+
+               in += CRASHDUMP_READ(in, offset, count, out);
+
+               out += count * sizeof(u32);
+               regcount += count;
+       }
+
+       CRASHDUMP_FINI(in);
+
+       if (WARN_ON((regcount * sizeof(u32)) > A6XX_CD_DATA_SIZE))
+               return;
+
+       if (a6xx_crashdumper_run(gpu, dumper))
+               return;
+
+       obj->handle = regs;
+       obj->data = state_kmemdup(a6xx_state, dumper->ptr + A6XX_CD_DATA_OFFSET,
+               regcount * sizeof(u32));
+}
+
+/* Read a block of registers using the crashdumper */
+static void a6xx_get_crashdumper_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_registers *regs,
+               struct a6xx_gpu_state_obj *obj,
+               struct a6xx_crashdumper *dumper)
+
+{
+       u64 *in = dumper->ptr;
+       u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
+       int i, regcount = 0;
+
+       /* Some blocks might need to program a selector register first */
+       if (regs->val0)
+               in += CRASHDUMP_WRITE(in, regs->val0, regs->val1);
+
+       for (i = 0; i < regs->count; i += 2) {
+               u32 count = RANGE(regs->registers, i);
+
+               in += CRASHDUMP_READ(in, regs->registers[i], count, out);
+
+               out += count * sizeof(u32);
+               regcount += count;
+       }
+
+       CRASHDUMP_FINI(in);
+
+       if (WARN_ON((regcount * sizeof(u32)) > A6XX_CD_DATA_SIZE))
+               return;
+
+       if (a6xx_crashdumper_run(gpu, dumper))
+               return;
+
+       obj->handle = regs;
+       obj->data = state_kmemdup(a6xx_state, dumper->ptr + A6XX_CD_DATA_OFFSET,
+               regcount * sizeof(u32));
+}
+
+/* Read a block of registers via AHB */
+static void a6xx_get_ahb_gpu_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_registers *regs,
+               struct a6xx_gpu_state_obj *obj)
+{
+       int i, regcount = 0, index = 0;
+
+       for (i = 0; i < regs->count; i += 2)
+               regcount += RANGE(regs->registers, i);
+
+       obj->handle = (const void *) regs;
+       obj->data = state_kcalloc(a6xx_state, regcount, sizeof(u32));
+       if (!obj->data)
+               return;
+
+       for (i = 0; i < regs->count; i += 2) {
+               u32 count = RANGE(regs->registers, i);
+               int j;
+
+               for (j = 0; j < count; j++)
+                       obj->data[index++] = gpu_read(gpu,
+                               regs->registers[i] + j);
+       }
+}
+
+/* Read a block of GMU registers */
+static void _a6xx_get_gmu_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_registers *regs,
+               struct a6xx_gpu_state_obj *obj)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+       int i, regcount = 0, index = 0;
+
+       for (i = 0; i < regs->count; i += 2)
+               regcount += RANGE(regs->registers, i);
+
+       obj->handle = (const void *) regs;
+       obj->data = state_kcalloc(a6xx_state, regcount, sizeof(u32));
+       if (!obj->data)
+               return;
+
+       for (i = 0; i < regs->count; i += 2) {
+               u32 count = RANGE(regs->registers, i);
+               int j;
+
+               for (j = 0; j < count; j++)
+                       obj->data[index++] = gmu_read(gmu,
+                               regs->registers[i] + j);
+       }
+}
+
+static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+
+       a6xx_state->gmu_registers = state_kcalloc(a6xx_state,
+               2, sizeof(*a6xx_state->gmu_registers));
+
+       if (!a6xx_state->gmu_registers)
+               return;
+
+       a6xx_state->nr_gmu_registers = 2;
+
+       /* Get the CX GMU registers from AHB */
+       _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[0],
+               &a6xx_state->gmu_registers[0]);
+
+       if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+               return;
+
+       /* Set the fence to ALLOW mode so we can access the registers */
+       gpu_write(gpu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0);
+
+       _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[1],
+               &a6xx_state->gmu_registers[1]);
+}
+
+static void a6xx_get_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               struct a6xx_crashdumper *dumper)
+{
+       int i, count = ARRAY_SIZE(a6xx_ahb_reglist) +
+               ARRAY_SIZE(a6xx_reglist) +
+               ARRAY_SIZE(a6xx_hlsq_reglist);
+       int index = 0;
+
+       a6xx_state->registers = state_kcalloc(a6xx_state,
+               count, sizeof(*a6xx_state->registers));
+
+       if (!a6xx_state->registers)
+               return;
+
+       a6xx_state->nr_registers = count;
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_ahb_reglist); i++)
+               a6xx_get_ahb_gpu_registers(gpu,
+                       a6xx_state, &a6xx_ahb_reglist[i],
+                       &a6xx_state->registers[index++]);
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_reglist); i++)
+               a6xx_get_crashdumper_registers(gpu,
+                       a6xx_state, &a6xx_reglist[i],
+                       &a6xx_state->registers[index++],
+                       dumper);
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_hlsq_reglist); i++)
+               a6xx_get_crashdumper_hlsq_registers(gpu,
+                       a6xx_state, &a6xx_hlsq_reglist[i],
+                       &a6xx_state->registers[index++],
+                       dumper);
+}
+
+/* Read a block of data from an indexed register pair */
+static void a6xx_get_indexed_regs(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state,
+               const struct a6xx_indexed_registers *indexed,
+               struct a6xx_gpu_state_obj *obj)
+{
+       int i;
+
+       obj->handle = (const void *) indexed;
+       obj->data = state_kcalloc(a6xx_state, indexed->count, sizeof(u32));
+       if (!obj->data)
+               return;
+
+       /* All the indexed banks start at address 0 */
+       gpu_write(gpu, indexed->addr, 0);
+
+       /* Read the data - each read increments the internal address by 1 */
+       for (i = 0; i < indexed->count; i++)
+               obj->data[i] = gpu_read(gpu, indexed->data);
+}
+
+static void a6xx_get_indexed_registers(struct msm_gpu *gpu,
+               struct a6xx_gpu_state *a6xx_state)
+{
+       u32 mempool_size;
+       int count = ARRAY_SIZE(a6xx_indexed_reglist) + 1;
+       int i;
+
+       a6xx_state->indexed_regs = state_kcalloc(a6xx_state, count,
+               sizeof(a6xx_state->indexed_regs));
+       if (!a6xx_state->indexed_regs)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(a6xx_indexed_reglist); i++)
+               a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_indexed_reglist[i],
+                       &a6xx_state->indexed_regs[i]);
+
+       /* Set the CP mempool size to 0 to stabilize it while dumping */
+       mempool_size = gpu_read(gpu, REG_A6XX_CP_MEM_POOL_SIZE);
+       gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 0);
+
+       /* Get the contents of the CP mempool */
+       a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_cp_mempool_indexed,
+               &a6xx_state->indexed_regs[i]);
+
+       /*
+        * Offset 0x2000 in the mempool is the size - copy the saved size over
+        * so the data is consistent
+        */
+       a6xx_state->indexed_regs[i].data[0x2000] = mempool_size;
+
+       /* Restore the size in the hardware */
+       gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, mempool_size);
+
+       a6xx_state->nr_indexed_regs = count;
+}
+
+struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct a6xx_crashdumper dumper = { 0 };
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       struct a6xx_gpu_state *a6xx_state = kzalloc(sizeof(*a6xx_state),
+               GFP_KERNEL);
+
+       if (!a6xx_state)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&a6xx_state->objs);
+
+       /* Get the generic state from the adreno core */
+       adreno_gpu_state_get(gpu, &a6xx_state->base);
+
+       a6xx_get_gmu_registers(gpu, a6xx_state);
+
+       /* If GX isn't on the rest of the data isn't going to be accessible */
+       if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+               return &a6xx_state->base;
+
+       /* Get the banks of indexed registers */
+       a6xx_get_indexed_registers(gpu, a6xx_state);
+
+       /* Try to initialize the crashdumper */
+       if (!a6xx_crashdumper_init(gpu, &dumper)) {
+               a6xx_get_registers(gpu, a6xx_state, &dumper);
+               a6xx_get_shaders(gpu, a6xx_state, &dumper);
+               a6xx_get_clusters(gpu, a6xx_state, &dumper);
+               a6xx_get_dbgahb_clusters(gpu, a6xx_state, &dumper);
+
+               msm_gem_kernel_put(dumper.bo, gpu->aspace, true);
+       }
+
+       a6xx_get_debugbus(gpu, a6xx_state);
+
+       return  &a6xx_state->base;
+}
+
+void a6xx_gpu_state_destroy(struct kref *kref)
+{
+       struct a6xx_state_memobj *obj, *tmp;
+       struct msm_gpu_state *state = container_of(kref,
+                       struct msm_gpu_state, ref);
+       struct a6xx_gpu_state *a6xx_state = container_of(state,
+                       struct a6xx_gpu_state, base);
+
+       list_for_each_entry_safe(obj, tmp, &a6xx_state->objs, node)
+               kfree(obj);
+
+       adreno_gpu_state_destroy(state);
+       kfree(a6xx_state);
+}
+
+int a6xx_gpu_state_put(struct msm_gpu_state *state)
+{
+       if (IS_ERR_OR_NULL(state))
+               return 1;
+
+       return kref_put(&state->ref, a6xx_gpu_state_destroy);
+}
+
+static void a6xx_show_registers(const u32 *registers, u32 *data, size_t count,
+               struct drm_printer *p)
+{
+       int i, index = 0;
+
+       if (!data)
+               return;
+
+       for (i = 0; i < count; i += 2) {
+               u32 count = RANGE(registers, i);
+               u32 offset = registers[i];
+               int j;
+
+               for (j = 0; j < count; index++, offset++, j++) {
+                       if (data[index] == 0xdeafbead)
+                               continue;
+
+                       drm_printf(p, "  - { offset: 0x%06x, value: 0x%08x }\n",
+                               offset << 2, data[index]);
+               }
+       }
+}
+
+static void print_ascii85(struct drm_printer *p, size_t len, u32 *data)
+{
+       char out[ASCII85_BUFSZ];
+       long i, l, datalen = 0;
+
+       for (i = 0; i < len >> 2; i++) {
+               if (data[i])
+                       datalen = (i + 1) << 2;
+       }
+
+       if (datalen == 0)
+               return;
+
+       drm_puts(p, "    data: !!ascii85 |\n");
+       drm_puts(p, "      ");
+
+
+       l = ascii85_encode_len(datalen);
+
+       for (i = 0; i < l; i++)
+               drm_puts(p, ascii85_encode(data[i], out));
+
+       drm_puts(p, "\n");
+}
+
+static void print_name(struct drm_printer *p, const char *fmt, const char *name)
+{
+       drm_puts(p, fmt);
+       drm_puts(p, name);
+       drm_puts(p, "\n");
+}
+
+static void a6xx_show_shader(struct a6xx_gpu_state_obj *obj,
+               struct drm_printer *p)
+{
+       const struct a6xx_shader_block *block = obj->handle;
+       int i;
+
+       if (!obj->handle)
+               return;
+
+       print_name(p, "  - type: ", block->name);
+
+       for (i = 0; i < A6XX_NUM_SHADER_BANKS; i++) {
+               drm_printf(p, "    - bank: %d\n", i);
+               drm_printf(p, "      size: %d\n", block->size);
+
+               if (!obj->data)
+                       continue;
+
+               print_ascii85(p, block->size << 2,
+                       obj->data + (block->size * i));
+       }
+}
+
+static void a6xx_show_cluster_data(const u32 *registers, int size, u32 *data,
+               struct drm_printer *p)
+{
+       int ctx, index = 0;
+
+       for (ctx = 0; ctx < A6XX_NUM_CONTEXTS; ctx++) {
+               int j;
+
+               drm_printf(p, "    - context: %d\n", ctx);
+
+               for (j = 0; j < size; j += 2) {
+                       u32 count = RANGE(registers, j);
+                       u32 offset = registers[j];
+                       int k;
+
+                       for (k = 0; k < count; index++, offset++, k++) {
+                               if (data[index] == 0xdeafbead)
+                                       continue;
+
+                               drm_printf(p, "      - { offset: 0x%06x, value: 0x%08x }\n",
+                                       offset << 2, data[index]);
+                       }
+               }
+       }
+}
+
+static void a6xx_show_dbgahb_cluster(struct a6xx_gpu_state_obj *obj,
+               struct drm_printer *p)
+{
+       const struct a6xx_dbgahb_cluster *dbgahb = obj->handle;
+
+       if (dbgahb) {
+               print_name(p, "  - cluster-name: ", dbgahb->name);
+               a6xx_show_cluster_data(dbgahb->registers, dbgahb->count,
+                       obj->data, p);
+       }
+}
+
+static void a6xx_show_cluster(struct a6xx_gpu_state_obj *obj,
+               struct drm_printer *p)
+{
+       const struct a6xx_cluster *cluster = obj->handle;
+
+       if (cluster) {
+               print_name(p, "  - cluster-name: ", cluster->name);
+               a6xx_show_cluster_data(cluster->registers, cluster->count,
+                       obj->data, p);
+       }
+}
+
+static void a6xx_show_indexed_regs(struct a6xx_gpu_state_obj *obj,
+               struct drm_printer *p)
+{
+       const struct a6xx_indexed_registers *indexed = obj->handle;
+
+       if (!indexed)
+               return;
+
+       print_name(p, "  - regs-name: ", indexed->name);
+       drm_printf(p, "    dwords: %d\n", indexed->count);
+
+       print_ascii85(p, indexed->count << 2, obj->data);
+}
+
+static void a6xx_show_debugbus_block(const struct a6xx_debugbus_block *block,
+               u32 *data, struct drm_printer *p)
+{
+       if (block) {
+               print_name(p, "  - debugbus-block: ", block->name);
+
+               /*
+                * count for regular debugbus data is in quadwords,
+                * but print the size in dwords for consistency
+                */
+               drm_printf(p, "    count: %d\n", block->count << 1);
+
+               print_ascii85(p, block->count << 3, data);
+       }
+}
+
+static void a6xx_show_debugbus(struct a6xx_gpu_state *a6xx_state,
+               struct drm_printer *p)
+{
+       int i;
+
+       for (i = 0; i < a6xx_state->nr_debugbus; i++) {
+               struct a6xx_gpu_state_obj *obj = &a6xx_state->debugbus[i];
+
+               a6xx_show_debugbus_block(obj->handle, obj->data, p);
+       }
+
+       if (a6xx_state->vbif_debugbus) {
+               struct a6xx_gpu_state_obj *obj = a6xx_state->vbif_debugbus;
+
+               drm_puts(p, "  - debugbus-block: A6XX_DBGBUS_VBIF\n");
+               drm_printf(p, "    count: %d\n", VBIF_DEBUGBUS_BLOCK_SIZE);
+
+               /* vbif debugbus data is in dwords.  Confusing, huh? */
+               print_ascii85(p, VBIF_DEBUGBUS_BLOCK_SIZE << 2, obj->data);
+       }
+
+       for (i = 0; i < a6xx_state->nr_cx_debugbus; i++) {
+               struct a6xx_gpu_state_obj *obj = &a6xx_state->cx_debugbus[i];
+
+               a6xx_show_debugbus_block(obj->handle, obj->data, p);
+       }
+}
+
+void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
+               struct drm_printer *p)
+{
+       struct a6xx_gpu_state *a6xx_state = container_of(state,
+                       struct a6xx_gpu_state, base);
+       int i;
+
+       if (IS_ERR_OR_NULL(state))
+               return;
+
+       adreno_show(gpu, state, p);
+
+       drm_puts(p, "registers:\n");
+       for (i = 0; i < a6xx_state->nr_registers; i++) {
+               struct a6xx_gpu_state_obj *obj = &a6xx_state->registers[i];
+               const struct a6xx_registers *regs = obj->handle;
+
+               if (!obj->handle)
+                       continue;
+
+               a6xx_show_registers(regs->registers, obj->data, regs->count, p);
+       }
+
+       drm_puts(p, "registers-gmu:\n");
+       for (i = 0; i < a6xx_state->nr_gmu_registers; i++) {
+               struct a6xx_gpu_state_obj *obj = &a6xx_state->gmu_registers[i];
+               const struct a6xx_registers *regs = obj->handle;
+
+               if (!obj->handle)
+                       continue;
+
+               a6xx_show_registers(regs->registers, obj->data, regs->count, p);
+       }
+
+       drm_puts(p, "indexed-registers:\n");
+       for (i = 0; i < a6xx_state->nr_indexed_regs; i++)
+               a6xx_show_indexed_regs(&a6xx_state->indexed_regs[i], p);
+
+       drm_puts(p, "shader-blocks:\n");
+       for (i = 0; i < a6xx_state->nr_shaders; i++)
+               a6xx_show_shader(&a6xx_state->shaders[i], p);
+
+       drm_puts(p, "clusters:\n");
+       for (i = 0; i < a6xx_state->nr_clusters; i++)
+               a6xx_show_cluster(&a6xx_state->clusters[i], p);
+
+       for (i = 0; i < a6xx_state->nr_dbgahb_clusters; i++)
+               a6xx_show_dbgahb_cluster(&a6xx_state->dbgahb_clusters[i], p);
+
+       drm_puts(p, "debugbus:\n");
+       a6xx_show_debugbus(a6xx_state, p);
+}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
new file mode 100644 (file)
index 0000000..68cccfa
--- /dev/null
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#ifndef _A6XX_CRASH_DUMP_H_
+#define _A6XX_CRASH_DUMP_H_
+
+#include "a6xx.xml.h"
+
+#define A6XX_NUM_CONTEXTS 2
+#define A6XX_NUM_SHADER_BANKS 3
+
+static const u32 a6xx_gras_cluster[] = {
+       0x8000, 0x8006, 0x8010, 0x8092, 0x8094, 0x809d, 0x80a0, 0x80a6,
+       0x80af, 0x80f1, 0x8100, 0x8107, 0x8109, 0x8109, 0x8110, 0x8110,
+       0x8400, 0x840b,
+};
+
+static const u32 a6xx_ps_cluster_rac[] = {
+       0x8800, 0x8806, 0x8809, 0x8811, 0x8818, 0x881e, 0x8820, 0x8865,
+       0x8870, 0x8879, 0x8880, 0x8889, 0x8890, 0x8891, 0x8898, 0x8898,
+       0x88c0, 0x88c1, 0x88d0, 0x88e3, 0x8900, 0x890c, 0x890f, 0x891a,
+       0x8c00, 0x8c01, 0x8c08, 0x8c10, 0x8c17, 0x8c1f, 0x8c26, 0x8c33,
+};
+
+static const u32 a6xx_ps_cluster_rbp[] = {
+       0x88f0, 0x88f3, 0x890d, 0x890e, 0x8927, 0x8928, 0x8bf0, 0x8bf1,
+       0x8c02, 0x8c07, 0x8c11, 0x8c16, 0x8c20, 0x8c25,
+};
+
+static const u32 a6xx_ps_cluster[] = {
+       0x9200, 0x9216, 0x9218, 0x9236, 0x9300, 0x9306,
+};
+
+static const u32 a6xx_fe_cluster[] = {
+       0x9300, 0x9306, 0x9800, 0x9806, 0x9b00, 0x9b07, 0xa000, 0xa009,
+       0xa00e, 0xa0ef, 0xa0f8, 0xa0f8,
+};
+
+static const u32 a6xx_pc_vs_cluster[] = {
+       0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9b00, 0x9b07,
+};
+
+#define CLUSTER_FE    0
+#define CLUSTER_SP_VS 1
+#define CLUSTER_PC_VS 2
+#define CLUSTER_GRAS  3
+#define CLUSTER_SP_PS 4
+#define CLUSTER_PS    5
+
+#define CLUSTER(_id, _reg, _sel_reg, _sel_val) \
+       { .id = _id, .name = #_id,\
+               .registers = _reg, \
+               .count = ARRAY_SIZE(_reg), \
+               .sel_reg = _sel_reg, .sel_val = _sel_val }
+
+static const struct a6xx_cluster {
+       u32 id;
+       const char *name;
+       const u32 *registers;
+       size_t count;
+       u32 sel_reg;
+       u32 sel_val;
+} a6xx_clusters[] = {
+       CLUSTER(CLUSTER_GRAS, a6xx_gras_cluster, 0, 0),
+       CLUSTER(CLUSTER_PS, a6xx_ps_cluster_rac, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 0x0),
+       CLUSTER(CLUSTER_PS, a6xx_ps_cluster_rbp, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 0x9),
+       CLUSTER(CLUSTER_PS, a6xx_ps_cluster, 0, 0),
+       CLUSTER(CLUSTER_FE, a6xx_fe_cluster, 0, 0),
+       CLUSTER(CLUSTER_PC_VS, a6xx_pc_vs_cluster, 0, 0),
+};
+
+static const u32 a6xx_sp_vs_hlsq_cluster[] = {
+       0xb800, 0xb803, 0xb820, 0xb822,
+};
+
+static const u32 a6xx_sp_vs_sp_cluster[] = {
+       0xa800, 0xa824, 0xa830, 0xa83c, 0xa840, 0xa864, 0xa870, 0xa895,
+       0xa8a0, 0xa8af, 0xa8c0, 0xa8c3,
+};
+
+static const u32 a6xx_hlsq_duplicate_cluster[] = {
+       0xbb10, 0xbb11, 0xbb20, 0xbb29,
+};
+
+static const u32 a6xx_hlsq_2d_duplicate_cluster[] = {
+       0xbd80, 0xbd80,
+};
+
+static const u32 a6xx_sp_duplicate_cluster[] = {
+       0xab00, 0xab00, 0xab04, 0xab05, 0xab10, 0xab1b, 0xab20, 0xab20,
+};
+
+static const u32 a6xx_tp_duplicate_cluster[] = {
+       0xb300, 0xb307, 0xb309, 0xb309, 0xb380, 0xb382,
+};
+
+static const u32 a6xx_sp_ps_hlsq_cluster[] = {
+       0xb980, 0xb980, 0xb982, 0xb987, 0xb990, 0xb99b, 0xb9a0, 0xb9a2,
+       0xb9c0, 0xb9c9,
+};
+
+static const u32 a6xx_sp_ps_hlsq_2d_cluster[] = {
+       0xbd80, 0xbd80,
+};
+
+static const u32 a6xx_sp_ps_sp_cluster[] = {
+       0xa980, 0xa9a8, 0xa9b0, 0xa9bc, 0xa9d0, 0xa9d3, 0xa9e0, 0xa9f3,
+       0xaa00, 0xaa00, 0xaa30, 0xaa31,
+};
+
+static const u32 a6xx_sp_ps_sp_2d_cluster[] = {
+       0xacc0, 0xacc0,
+};
+
+static const u32 a6xx_sp_ps_tp_cluster[] = {
+       0xb180, 0xb183, 0xb190, 0xb191,
+};
+
+static const u32 a6xx_sp_ps_tp_2d_cluster[] = {
+       0xb4c0, 0xb4d1,
+};
+
+#define CLUSTER_DBGAHB(_id, _base, _type, _reg) \
+       { .name = #_id, .statetype = _type, .base = _base, \
+               .registers = _reg, .count = ARRAY_SIZE(_reg) }
+
+static const struct a6xx_dbgahb_cluster {
+       const char *name;
+       u32 statetype;
+       u32 base;
+       const u32 *registers;
+       size_t count;
+} a6xx_dbgahb_clusters[] = {
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002e000, 0x41, a6xx_sp_vs_hlsq_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002a000, 0x21, a6xx_sp_vs_sp_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002e000, 0x41, a6xx_hlsq_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002f000, 0x45, a6xx_hlsq_2d_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002a000, 0x21, a6xx_sp_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_VS, 0x0002c000, 0x1, a6xx_tp_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002e000, 0x42, a6xx_sp_ps_hlsq_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002f000, 0x46, a6xx_sp_ps_hlsq_2d_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002a000, 0x22, a6xx_sp_ps_sp_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002b000, 0x26, a6xx_sp_ps_sp_2d_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002c000, 0x2, a6xx_sp_ps_tp_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002d000, 0x6, a6xx_sp_ps_tp_2d_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002e000, 0x42, a6xx_hlsq_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002a000, 0x22, a6xx_sp_duplicate_cluster),
+       CLUSTER_DBGAHB(CLUSTER_SP_PS, 0x0002c000, 0x2, a6xx_tp_duplicate_cluster),
+};
+
+static const u32 a6xx_hlsq_registers[] = {
+       0xbe00, 0xbe01, 0xbe04, 0xbe05, 0xbe08, 0xbe09, 0xbe10, 0xbe15,
+       0xbe20, 0xbe23,
+};
+
+static const u32 a6xx_sp_registers[] = {
+       0xae00, 0xae04, 0xae0c, 0xae0c, 0xae0f, 0xae2b, 0xae30, 0xae32,
+       0xae35, 0xae35, 0xae3a, 0xae3f, 0xae50, 0xae52,
+};
+
+static const u32 a6xx_tp_registers[] = {
+       0xb600, 0xb601, 0xb604, 0xb605, 0xb610, 0xb61b, 0xb620, 0xb623,
+};
+
+struct a6xx_registers {
+       const u32 *registers;
+       size_t count;
+       u32 val0;
+       u32 val1;
+};
+
+#define HLSQ_DBG_REGS(_base, _type, _array) \
+       { .val0 = _base, .val1 = _type, .registers = _array, \
+               .count = ARRAY_SIZE(_array), }
+
+static const struct a6xx_registers a6xx_hlsq_reglist[] = {
+       HLSQ_DBG_REGS(0x0002F800, 0x40, a6xx_hlsq_registers),
+       HLSQ_DBG_REGS(0x0002B800, 0x20, a6xx_sp_registers),
+       HLSQ_DBG_REGS(0x0002D800, 0x0, a6xx_tp_registers),
+};
+
+#define SHADER(_type, _size) \
+       { .type = _type, .name = #_type, .size = _size }
+
+static const struct a6xx_shader_block {
+       const char *name;
+       u32 type;
+       u32 size;
+} a6xx_shader_blocks[] = {
+       SHADER(A6XX_TP0_TMO_DATA, 0x200),
+       SHADER(A6XX_TP0_SMO_DATA, 0x80),
+       SHADER(A6XX_TP0_MIPMAP_BASE_DATA, 0x3c0),
+       SHADER(A6XX_TP1_TMO_DATA, 0x200),
+       SHADER(A6XX_TP1_SMO_DATA, 0x80),
+       SHADER(A6XX_TP1_MIPMAP_BASE_DATA, 0x3c0),
+       SHADER(A6XX_SP_INST_DATA, 0x800),
+       SHADER(A6XX_SP_LB_0_DATA, 0x800),
+       SHADER(A6XX_SP_LB_1_DATA, 0x800),
+       SHADER(A6XX_SP_LB_2_DATA, 0x800),
+       SHADER(A6XX_SP_LB_3_DATA, 0x800),
+       SHADER(A6XX_SP_LB_4_DATA, 0x800),
+       SHADER(A6XX_SP_LB_5_DATA, 0x200),
+       SHADER(A6XX_SP_CB_BINDLESS_DATA, 0x2000),
+       SHADER(A6XX_SP_CB_LEGACY_DATA, 0x280),
+       SHADER(A6XX_SP_UAV_DATA, 0x80),
+       SHADER(A6XX_SP_INST_TAG, 0x80),
+       SHADER(A6XX_SP_CB_BINDLESS_TAG, 0x80),
+       SHADER(A6XX_SP_TMO_UMO_TAG, 0x80),
+       SHADER(A6XX_SP_SMO_TAG, 0x80),
+       SHADER(A6XX_SP_STATE_DATA, 0x3f),
+       SHADER(A6XX_HLSQ_CHUNK_CVS_RAM, 0x1c0),
+       SHADER(A6XX_HLSQ_CHUNK_CPS_RAM, 0x280),
+       SHADER(A6XX_HLSQ_CHUNK_CVS_RAM_TAG, 0x40),
+       SHADER(A6XX_HLSQ_CHUNK_CPS_RAM_TAG, 0x40),
+       SHADER(A6XX_HLSQ_ICB_CVS_CB_BASE_TAG, 0x4),
+       SHADER(A6XX_HLSQ_ICB_CPS_CB_BASE_TAG, 0x4),
+       SHADER(A6XX_HLSQ_CVS_MISC_RAM, 0x1c0),
+       SHADER(A6XX_HLSQ_CPS_MISC_RAM, 0x580),
+       SHADER(A6XX_HLSQ_INST_RAM, 0x800),
+       SHADER(A6XX_HLSQ_GFX_CVS_CONST_RAM, 0x800),
+       SHADER(A6XX_HLSQ_GFX_CPS_CONST_RAM, 0x800),
+       SHADER(A6XX_HLSQ_CVS_MISC_RAM_TAG, 0x8),
+       SHADER(A6XX_HLSQ_CPS_MISC_RAM_TAG, 0x4),
+       SHADER(A6XX_HLSQ_INST_RAM_TAG, 0x80),
+       SHADER(A6XX_HLSQ_GFX_CVS_CONST_RAM_TAG, 0xc),
+       SHADER(A6XX_HLSQ_GFX_CPS_CONST_RAM_TAG, 0x10),
+       SHADER(A6XX_HLSQ_PWR_REST_RAM, 0x28),
+       SHADER(A6XX_HLSQ_PWR_REST_TAG, 0x14),
+       SHADER(A6XX_HLSQ_DATAPATH_META, 0x40),
+       SHADER(A6XX_HLSQ_FRONTEND_META, 0x40),
+       SHADER(A6XX_HLSQ_INDIRECT_META, 0x40),
+};
+
+static const u32 a6xx_rb_rac_registers[] = {
+       0x8e04, 0x8e05, 0x8e07, 0x8e08, 0x8e10, 0x8e1c, 0x8e20, 0x8e25,
+       0x8e28, 0x8e28, 0x8e2c, 0x8e2f, 0x8e50, 0x8e52,
+};
+
+static const u32 a6xx_rb_rbp_registers[] = {
+       0x8e01, 0x8e01, 0x8e0c, 0x8e0c, 0x8e3b, 0x8e3e, 0x8e40, 0x8e43,
+       0x8e53, 0x8e5f, 0x8e70, 0x8e77,
+};
+
+static const u32 a6xx_registers[] = {
+       /* RBBM */
+       0x0000, 0x0002, 0x0010, 0x0010, 0x0012, 0x0012, 0x0018, 0x001b,
+       0x001e, 0x0032, 0x0038, 0x003c, 0x0042, 0x0042, 0x0044, 0x0044,
+       0x0047, 0x0047, 0x0056, 0x0056, 0x00ad, 0x00ae, 0x00b0, 0x00fb,
+       0x0100, 0x011d, 0x0200, 0x020d, 0x0218, 0x023d, 0x0400, 0x04f9,
+       0x0500, 0x0500, 0x0505, 0x050b, 0x050e, 0x0511, 0x0533, 0x0533,
+       0x0540, 0x0555,
+       /* CP */
+       0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0824,
+       0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0843, 0x084f, 0x086f,
+       0x0880, 0x088a, 0x08a0, 0x08ab, 0x08c0, 0x08c4, 0x08d0, 0x08dd,
+       0x08f0, 0x08f3, 0x0900, 0x0903, 0x0908, 0x0911, 0x0928, 0x093e,
+       0x0942, 0x094d, 0x0980, 0x0984, 0x098d, 0x0996, 0x0998, 0x099e,
+       0x09a0, 0x09a6, 0x09a8, 0x09ae, 0x09b0, 0x09b1, 0x09c2, 0x09c8,
+       0x0a00, 0x0a03,
+       /* VSC */
+       0x0c00, 0x0c04, 0x0c06, 0x0c06, 0x0c10, 0x0cd9, 0x0e00, 0x0e0e,
+       /* UCHE */
+       0x0e10, 0x0e13, 0x0e17, 0x0e19, 0x0e1c, 0x0e2b, 0x0e30, 0x0e32,
+       0x0e38, 0x0e39,
+       /* GRAS */
+       0x8600, 0x8601, 0x8610, 0x861b, 0x8620, 0x8620, 0x8628, 0x862b,
+       0x8630, 0x8637,
+       /* VPC */
+       0x9600, 0x9604, 0x9624, 0x9637,
+       /* PC */
+       0x9e00, 0x9e01, 0x9e03, 0x9e0e, 0x9e11, 0x9e16, 0x9e19, 0x9e19,
+       0x9e1c, 0x9e1c, 0x9e20, 0x9e23, 0x9e30, 0x9e31, 0x9e34, 0x9e34,
+       0x9e70, 0x9e72, 0x9e78, 0x9e79, 0x9e80, 0x9fff,
+       /* VFD */
+       0xa600, 0xa601, 0xa603, 0xa603, 0xa60a, 0xa60a, 0xa610, 0xa617,
+       0xa630, 0xa630,
+};
+
+#define REGS(_array, _sel_reg, _sel_val) \
+       { .registers = _array, .count = ARRAY_SIZE(_array), \
+               .val0 = _sel_reg, .val1 = _sel_val }
+
+static const struct a6xx_registers a6xx_reglist[] = {
+       REGS(a6xx_registers, 0, 0),
+       REGS(a6xx_rb_rac_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 0),
+       REGS(a6xx_rb_rbp_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 9),
+};
+
+static const u32 a6xx_ahb_registers[] = {
+       /* RBBM_STATUS - RBBM_STATUS3 */
+       0x210, 0x213,
+       /* CP_STATUS_1 */
+       0x825, 0x825,
+};
+
+static const u32 a6xx_vbif_registers[] = {
+       0x3000, 0x3007, 0x300c, 0x3014, 0x3018, 0x302d, 0x3030, 0x3031,
+       0x3034, 0x3036, 0x303c, 0x303d, 0x3040, 0x3040, 0x3042, 0x3042,
+       0x3049, 0x3049, 0x3058, 0x3058, 0x305a, 0x3061, 0x3064, 0x3068,
+       0x306c, 0x306d, 0x3080, 0x3088, 0x308b, 0x308c, 0x3090, 0x3094,
+       0x3098, 0x3098, 0x309c, 0x309c, 0x30c0, 0x30c0, 0x30c8, 0x30c8,
+       0x30d0, 0x30d0, 0x30d8, 0x30d8, 0x30e0, 0x30e0, 0x3100, 0x3100,
+       0x3108, 0x3108, 0x3110, 0x3110, 0x3118, 0x3118, 0x3120, 0x3120,
+       0x3124, 0x3125, 0x3129, 0x3129, 0x3131, 0x3131, 0x3154, 0x3154,
+       0x3156, 0x3156, 0x3158, 0x3158, 0x315a, 0x315a, 0x315c, 0x315c,
+       0x315e, 0x315e, 0x3160, 0x3160, 0x3162, 0x3162, 0x340c, 0x340c,
+       0x3410, 0x3410, 0x3800, 0x3801,
+};
+
+static const struct a6xx_registers a6xx_ahb_reglist[] = {
+       REGS(a6xx_ahb_registers, 0, 0),
+       REGS(a6xx_vbif_registers, 0, 0),
+};
+
+static const u32 a6xx_gmu_gx_registers[] = {
+       /* GMU GX */
+       0x0000, 0x0000, 0x0010, 0x0013, 0x0016, 0x0016, 0x0018, 0x001b,
+       0x001e, 0x001e, 0x0020, 0x0023, 0x0026, 0x0026, 0x0028, 0x002b,
+       0x002e, 0x002e, 0x0030, 0x0033, 0x0036, 0x0036, 0x0038, 0x003b,
+       0x003e, 0x003e, 0x0040, 0x0043, 0x0046, 0x0046, 0x0080, 0x0084,
+       0x0100, 0x012b, 0x0140, 0x0140,
+};
+
+static const u32 a6xx_gmu_cx_registers[] = {
+       /* GMU CX */
+       0x4c00, 0x4c07, 0x4c10, 0x4c12, 0x4d00, 0x4d00, 0x4d07, 0x4d0a,
+       0x5000, 0x5004, 0x5007, 0x5008, 0x500b, 0x500c, 0x500f, 0x501c,
+       0x5024, 0x502a, 0x502d, 0x5030, 0x5040, 0x5053, 0x5087, 0x5089,
+       0x50a0, 0x50a2, 0x50a4, 0x50af, 0x50c0, 0x50c3, 0x50d0, 0x50d0,
+       0x50e4, 0x50e4, 0x50e8, 0x50ec, 0x5100, 0x5103, 0x5140, 0x5140,
+       0x5142, 0x5144, 0x514c, 0x514d, 0x514f, 0x5151, 0x5154, 0x5154,
+       0x5157, 0x5158, 0x515d, 0x515d, 0x5162, 0x5162, 0x5164, 0x5165,
+       0x5180, 0x5186, 0x5190, 0x519e, 0x51c0, 0x51c0, 0x51c5, 0x51cc,
+       0x51e0, 0x51e2, 0x51f0, 0x51f0, 0x5200, 0x5201,
+       /* GPU RSCC */
+       0x8c8c, 0x8c8c, 0x8d01, 0x8d02, 0x8f40, 0x8f42, 0x8f44, 0x8f47,
+       0x8f4c, 0x8f87, 0x8fec, 0x8fef, 0x8ff4, 0x902f, 0x9094, 0x9097,
+       0x909c, 0x90d7, 0x913c, 0x913f, 0x9144, 0x917f,
+       /* GMU AO */
+       0x9300, 0x9316, 0x9400, 0x9400,
+       /* GPU CC */
+       0x9800, 0x9812, 0x9840, 0x9852, 0x9c00, 0x9c04, 0x9c07, 0x9c0b,
+       0x9c15, 0x9c1c, 0x9c1e, 0x9c2d, 0x9c3c, 0x9c3d, 0x9c3f, 0x9c40,
+       0x9c42, 0x9c49, 0x9c58, 0x9c5a, 0x9d40, 0x9d5e, 0xa000, 0xa002,
+       0xa400, 0xa402, 0xac00, 0xac02, 0xb000, 0xb002, 0xb400, 0xb402,
+       0xb800, 0xb802,
+       /* GPU CC ACD */
+       0xbc00, 0xbc16, 0xbc20, 0xbc27,
+};
+
+static const struct a6xx_registers a6xx_gmu_reglist[] = {
+       REGS(a6xx_gmu_cx_registers, 0, 0),
+       REGS(a6xx_gmu_gx_registers, 0, 0),
+};
+
+static const struct a6xx_indexed_registers {
+       const char *name;
+       u32 addr;
+       u32 data;
+       u32 count;
+} a6xx_indexed_reglist[] = {
+       { "CP_SEQ_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
+               REG_A6XX_CP_SQE_STAT_DATA, 0x33 },
+       { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR,
+               REG_A6XX_CP_DRAW_STATE_DATA, 0x100 },
+       { "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR,
+               REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x6000 },
+       { "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR,
+               REG_A6XX_CP_ROQ_DBG_DATA, 0x400 },
+};
+
+static const struct a6xx_indexed_registers a6xx_cp_mempool_indexed = {
+       "CP_MEMPOOOL", REG_A6XX_CP_MEM_POOL_DBG_ADDR,
+               REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060,
+};
+
+#define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count }
+
+static const struct a6xx_debugbus_block {
+       const char *name;
+       u32 id;
+       u32 count;
+} a6xx_debugbus_blocks[] = {
+       DEBUGBUS(A6XX_DBGBUS_CP, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_RBBM, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_HLSQ, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_UCHE, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_DPM, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TESS, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_PC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VFDP, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VPC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TSE, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_RAS, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VSC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_COM, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_LRZ, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_A2D, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_CCUFCHE, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_RBP, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_DCS, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_DBGC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_GMU_GX, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TPFCHE, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_GPC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_LARC, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_HLSQ_SPTP, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_RB_0, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_RB_1, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_UCHE_WRAPPER, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_CCU_0, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_CCU_1, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VFD_0, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VFD_1, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VFD_2, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_VFD_3, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_SP_0, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_SP_1, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TPL1_0, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TPL1_1, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TPL1_2, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_TPL1_3, 0x100),
+};
+
+static const struct a6xx_debugbus_block a6xx_cx_debugbus_blocks[] = {
+       DEBUGBUS(A6XX_DBGBUS_GMU_CX, 0x100),
+       DEBUGBUS(A6XX_DBGBUS_CX, 0x100),
+};
+
+#endif
index 6ff9baec2658cf7876f4806c99c0936c689f123a..eda11abc5f011f1a8ef8bab3feb19274d6c0277f 100644 (file)
@@ -91,7 +91,7 @@ static int a6xx_hfi_wait_for_ack(struct a6xx_gmu *gmu, u32 id, u32 seqnum,
                val & A6XX_GMU_GMU2HOST_INTR_INFO_MSGQ, 100, 5000);
 
        if (ret) {
-               dev_err(gmu->dev,
+               DRM_DEV_ERROR(gmu->dev,
                        "Message %s id %d timed out waiting for response\n",
                        a6xx_hfi_msg_id[id], seqnum);
                return -ETIMEDOUT;
@@ -110,7 +110,7 @@ static int a6xx_hfi_wait_for_ack(struct a6xx_gmu *gmu, u32 id, u32 seqnum,
 
                /* If the queue is empty our response never made it */
                if (!ret) {
-                       dev_err(gmu->dev,
+                       DRM_DEV_ERROR(gmu->dev,
                                "The HFI response queue is unexpectedly empty\n");
 
                        return -ENOENT;
@@ -120,20 +120,20 @@ static int a6xx_hfi_wait_for_ack(struct a6xx_gmu *gmu, u32 id, u32 seqnum,
                        struct a6xx_hfi_msg_error *error =
                                (struct a6xx_hfi_msg_error *) &resp;
 
-                       dev_err(gmu->dev, "GMU firmware error %d\n",
+                       DRM_DEV_ERROR(gmu->dev, "GMU firmware error %d\n",
                                error->code);
                        continue;
                }
 
                if (seqnum != HFI_HEADER_SEQNUM(resp.ret_header)) {
-                       dev_err(gmu->dev,
+                       DRM_DEV_ERROR(gmu->dev,
                                "Unexpected message id %d on the response queue\n",
                                HFI_HEADER_SEQNUM(resp.ret_header));
                        continue;
                }
 
                if (resp.error) {
-                       dev_err(gmu->dev,
+                       DRM_DEV_ERROR(gmu->dev,
                                "Message %s id %d returned error %d\n",
                                a6xx_hfi_msg_id[id], seqnum, resp.error);
                        return -EINVAL;
@@ -163,7 +163,7 @@ static int a6xx_hfi_send_msg(struct a6xx_gmu *gmu, int id,
 
        ret = a6xx_hfi_queue_write(gmu, queue, data, dwords);
        if (ret) {
-               dev_err(gmu->dev, "Unable to send message %s id %d\n",
+               DRM_DEV_ERROR(gmu->dev, "Unable to send message %s id %d\n",
                        a6xx_hfi_msg_id[id], seqnum);
                return ret;
        }
@@ -317,7 +317,7 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu)
                        continue;
 
                if (queue->header->read_index != queue->header->write_index)
-                       dev_err(gmu->dev, "HFI queue %d is not empty\n", i);
+                       DRM_DEV_ERROR(gmu->dev, "HFI queue %d is not empty\n", i);
 
                queue->header->read_index = 0;
                queue->header->write_index = 0;
index 1318959d504d05f7a5c4ce4237ed36ac3a12194a..641d3ba477b650ec2bae119f99136e6910007b71 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
@@ -339,6 +339,15 @@ static inline uint32_t AXXX_SCRATCH_UMSK_SWAP(uint32_t val)
 #define REG_AXXX_CP_STATE_DEBUG_DATA                           0x000001ed
 
 #define REG_AXXX_CP_INT_CNTL                                   0x000001f2
+#define AXXX_CP_INT_CNTL_SW_INT_MASK                           0x00080000
+#define AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK                  0x00800000
+#define AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK                     0x01000000
+#define AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK             0x02000000
+#define AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK               0x04000000
+#define AXXX_CP_INT_CNTL_IB_ERROR_MASK                         0x08000000
+#define AXXX_CP_INT_CNTL_IB2_INT_MASK                          0x20000000
+#define AXXX_CP_INT_CNTL_IB1_INT_MASK                          0x40000000
+#define AXXX_CP_INT_CNTL_RB_INT_MASK                           0x80000000
 
 #define REG_AXXX_CP_INT_STATUS                                 0x000001f3
 
index 86abdb2b3a9cdddc31e986163e17bc0f7c49bd5e..714ed6505e47bda1d107412e058d2c00c5877afa 100644 (file)
@@ -27,6 +27,39 @@ module_param_named(hang_debug, hang_debug, bool, 0600);
 
 static const struct adreno_info gpulist[] = {
        {
+               .rev   = ADRENO_REV(2, 0, 0, 0),
+               .revn  = 200,
+               .name  = "A200",
+               .fw = {
+                       [ADRENO_FW_PM4] = "yamato_pm4.fw",
+                       [ADRENO_FW_PFP] = "yamato_pfp.fw",
+               },
+               .gmem  = SZ_256K,
+               .inactive_period = DRM_MSM_INACTIVE_PERIOD,
+               .init  = a2xx_gpu_init,
+       }, { /* a200 on i.mx51 has only 128kib gmem */
+               .rev   = ADRENO_REV(2, 0, 0, 1),
+               .revn  = 201,
+               .name  = "A200",
+               .fw = {
+                       [ADRENO_FW_PM4] = "yamato_pm4.fw",
+                       [ADRENO_FW_PFP] = "yamato_pfp.fw",
+               },
+               .gmem  = SZ_128K,
+               .inactive_period = DRM_MSM_INACTIVE_PERIOD,
+               .init  = a2xx_gpu_init,
+       }, {
+               .rev   = ADRENO_REV(2, 2, 0, ANY_ID),
+               .revn  = 220,
+               .name  = "A220",
+               .fw = {
+                       [ADRENO_FW_PM4] = "leia_pm4_470.fw",
+                       [ADRENO_FW_PFP] = "leia_pfp_470.fw",
+               },
+               .gmem  = SZ_512K,
+               .inactive_period = DRM_MSM_INACTIVE_PERIOD,
+               .init  = a2xx_gpu_init,
+       }, {
                .rev   = ADRENO_REV(3, 0, 5, ANY_ID),
                .revn  = 305,
                .name  = "A305",
@@ -196,7 +229,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
 
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
-               dev_err(dev->dev, "Couldn't power up the GPU: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "Couldn't power up the GPU: %d\n", ret);
                return NULL;
        }
 
@@ -205,7 +238,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
        mutex_unlock(&dev->struct_mutex);
        pm_runtime_put_autosuspend(&pdev->dev);
        if (ret) {
-               dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
                return NULL;
        }
 
@@ -238,7 +271,8 @@ static int find_chipid(struct device *dev, struct adreno_rev *rev)
        if (ret == 0) {
                unsigned int r, patch;
 
-               if (sscanf(compat, "qcom,adreno-%u.%u", &r, &patch) == 2) {
+               if (sscanf(compat, "qcom,adreno-%u.%u", &r, &patch) == 2 ||
+                   sscanf(compat, "amd,imageon-%u.%u", &r, &patch) == 2) {
                        rev->core = r / 100;
                        r %= 100;
                        rev->major = r / 10;
@@ -253,7 +287,7 @@ static int find_chipid(struct device *dev, struct adreno_rev *rev)
        /* and if that fails, fall back to legacy "qcom,chipid" property: */
        ret = of_property_read_u32(node, "qcom,chipid", &chipid);
        if (ret) {
-               dev_err(dev, "could not parse qcom,chipid: %d\n", ret);
+               DRM_DEV_ERROR(dev, "could not parse qcom,chipid: %d\n", ret);
                return ret;
        }
 
@@ -274,6 +308,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
        static struct adreno_platform_config config = {};
        const struct adreno_info *info;
        struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
        struct msm_gpu *gpu;
        int ret;
 
@@ -296,6 +331,8 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
        DBG("Found GPU: %u.%u.%u.%u", config.rev.core, config.rev.major,
                config.rev.minor, config.rev.patchid);
 
+       priv->is_a2xx = config.rev.core == 2;
+
        gpu = info->init(drm);
        if (IS_ERR(gpu)) {
                dev_warn(drm->dev, "failed to load adreno gpu\n");
@@ -323,9 +360,37 @@ static const struct component_ops a3xx_ops = {
                .unbind = adreno_unbind,
 };
 
+static void adreno_device_register_headless(void)
+{
+       /* on imx5, we don't have a top-level mdp/dpu node
+        * this creates a dummy node for the driver for that case
+        */
+       struct platform_device_info dummy_info = {
+               .parent = NULL,
+               .name = "msm",
+               .id = -1,
+               .res = NULL,
+               .num_res = 0,
+               .data = NULL,
+               .size_data = 0,
+               .dma_mask = ~0,
+       };
+       platform_device_register_full(&dummy_info);
+}
+
 static int adreno_probe(struct platform_device *pdev)
 {
-       return component_add(&pdev->dev, &a3xx_ops);
+
+       int ret;
+
+       ret = component_add(&pdev->dev, &a3xx_ops);
+       if (ret)
+               return ret;
+
+       if (of_device_is_compatible(pdev->dev.of_node, "amd,imageon"))
+               adreno_device_register_headless();
+
+       return 0;
 }
 
 static int adreno_remove(struct platform_device *pdev)
@@ -337,6 +402,8 @@ static int adreno_remove(struct platform_device *pdev)
 static const struct of_device_id dt_match[] = {
        { .compatible = "qcom,adreno" },
        { .compatible = "qcom,adreno-3xx" },
+       /* for compatibility with imx5 gpu: */
+       { .compatible = "amd,imageon" },
        /* for backwards compat w/ downstream kgsl DT files: */
        { .compatible = "qcom,kgsl-3d0" },
        {}
index 93d70f4a2154e289be09a8dd6ae8a038e007ec7b..2e4372ef17a34fd2fc3028c6f8a543477ce54247 100644 (file)
@@ -89,12 +89,12 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname)
 
                ret = request_firmware_direct(&fw, newname, drm->dev);
                if (!ret) {
-                       dev_info(drm->dev, "loaded %s from new location\n",
+                       DRM_DEV_INFO(drm->dev, "loaded %s from new location\n",
                                newname);
                        adreno_gpu->fwloc = FW_LOCATION_NEW;
                        goto out;
                } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
-                       dev_err(drm->dev, "failed to load %s: %d\n",
+                       DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n",
                                newname, ret);
                        fw = ERR_PTR(ret);
                        goto out;
@@ -109,12 +109,12 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname)
 
                ret = request_firmware_direct(&fw, fwname, drm->dev);
                if (!ret) {
-                       dev_info(drm->dev, "loaded %s from legacy location\n",
+                       DRM_DEV_INFO(drm->dev, "loaded %s from legacy location\n",
                                newname);
                        adreno_gpu->fwloc = FW_LOCATION_LEGACY;
                        goto out;
                } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
-                       dev_err(drm->dev, "failed to load %s: %d\n",
+                       DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n",
                                fwname, ret);
                        fw = ERR_PTR(ret);
                        goto out;
@@ -130,19 +130,19 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname)
 
                ret = request_firmware(&fw, newname, drm->dev);
                if (!ret) {
-                       dev_info(drm->dev, "loaded %s with helper\n",
+                       DRM_DEV_INFO(drm->dev, "loaded %s with helper\n",
                                newname);
                        adreno_gpu->fwloc = FW_LOCATION_HELPER;
                        goto out;
                } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
-                       dev_err(drm->dev, "failed to load %s: %d\n",
+                       DRM_DEV_ERROR(drm->dev, "failed to load %s: %d\n",
                                newname, ret);
                        fw = ERR_PTR(ret);
                        goto out;
                }
        }
 
-       dev_err(drm->dev, "failed to load %s\n", fwname);
+       DRM_DEV_ERROR(drm->dev, "failed to load %s\n", fwname);
        fw = ERR_PTR(-ENOENT);
 out:
        kfree(newname);
@@ -209,14 +209,6 @@ int adreno_hw_init(struct msm_gpu *gpu)
                if (!ring)
                        continue;
 
-               ret = msm_gem_get_iova(ring->bo, gpu->aspace, &ring->iova);
-               if (ret) {
-                       ring->iova = 0;
-                       dev_err(gpu->dev->dev,
-                               "could not map ringbuffer %d: %d\n", i, ret);
-                       return ret;
-               }
-
                ring->cur = ring->start;
                ring->next = ring->start;
 
@@ -277,7 +269,7 @@ void adreno_recover(struct msm_gpu *gpu)
 
        ret = msm_gpu_hw_init(gpu);
        if (ret) {
-               dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
                /* hmm, oh well? */
        }
 }
@@ -319,16 +311,27 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                 */
                OUT_PKT3(ring, CP_EVENT_WRITE, 1);
                OUT_RING(ring, HLSQ_FLUSH);
-
-               OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
-               OUT_RING(ring, 0x00000000);
        }
 
-       /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
-       OUT_PKT3(ring, CP_EVENT_WRITE, 3);
-       OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
-       OUT_RING(ring, rbmemptr(ring, fence));
-       OUT_RING(ring, submit->seqno);
+       /* wait for idle before cache flush/interrupt */
+       OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
+       OUT_RING(ring, 0x00000000);
+
+       if (!adreno_is_a2xx(adreno_gpu)) {
+               /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
+               OUT_PKT3(ring, CP_EVENT_WRITE, 3);
+               OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
+               OUT_RING(ring, rbmemptr(ring, fence));
+               OUT_RING(ring, submit->seqno);
+       } else {
+               /* BIT(31) means something else on a2xx */
+               OUT_PKT3(ring, CP_EVENT_WRITE, 3);
+               OUT_RING(ring, CACHE_FLUSH_TS);
+               OUT_RING(ring, rbmemptr(ring, fence));
+               OUT_RING(ring, submit->seqno);
+               OUT_PKT3(ring, CP_INTERRUPT, 1);
+               OUT_RING(ring, 0x80000000);
+       }
 
 #if 0
        if (adreno_is_a3xx(adreno_gpu)) {
@@ -406,7 +409,7 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state)
                                size = j + 1;
 
                if (size) {
-                       state->ring[i].data = kmalloc(size << 2, GFP_KERNEL);
+                       state->ring[i].data = kvmalloc(size << 2, GFP_KERNEL);
                        if (state->ring[i].data) {
                                memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2);
                                state->ring[i].data_size = size << 2;
@@ -414,6 +417,10 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state)
                }
        }
 
+       /* Some targets prefer to collect their own registers */
+       if (!adreno_gpu->registers)
+               return 0;
+
        /* Count the number of registers */
        for (i = 0; adreno_gpu->registers[i] != ~0; i += 2)
                count += adreno_gpu->registers[i + 1] -
@@ -445,7 +452,7 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(state->ring); i++)
-               kfree(state->ring[i].data);
+               kvfree(state->ring[i].data);
 
        for (i = 0; state->bos && i < state->nr_bos; i++)
                kvfree(state->bos[i].data);
@@ -475,34 +482,74 @@ int adreno_gpu_state_put(struct msm_gpu_state *state)
 
 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
 
-static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len)
+static char *adreno_gpu_ascii85_encode(u32 *src, size_t len)
 {
+       void *buf;
+       size_t buf_itr = 0, buffer_size;
        char out[ASCII85_BUFSZ];
-       long l, datalen, i;
+       long l;
+       int i;
 
-       if (!ptr || !len)
-               return;
+       if (!src || !len)
+               return NULL;
+
+       l = ascii85_encode_len(len);
 
        /*
-        * Only dump the non-zero part of the buffer - rarely will any data
-        * completely fill the entire allocated size of the buffer
+        * Ascii85 outputs either a 5 byte string or a 1 byte string. So we
+        * account for the worst case of 5 bytes per dword plus the 1 for '\0'
         */
-       for (datalen = 0, i = 0; i < len >> 2; i++) {
-               if (ptr[i])
-                       datalen = (i << 2) + 1;
-       }
+       buffer_size = (l * 5) + 1;
+
+       buf = kvmalloc(buffer_size, GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       for (i = 0; i < l; i++)
+               buf_itr += snprintf(buf + buf_itr, buffer_size - buf_itr, "%s",
+                               ascii85_encode(src[i], out));
+
+       return buf;
+}
 
-       /* Skip printing the object if it is empty */
-       if (datalen == 0)
+/* len is expected to be in bytes */
+static void adreno_show_object(struct drm_printer *p, void **ptr, int len,
+               bool *encoded)
+{
+       if (!*ptr || !len)
                return;
 
-       l = ascii85_encode_len(datalen);
+       if (!*encoded) {
+               long datalen, i;
+               u32 *buf = *ptr;
+
+               /*
+                * Only dump the non-zero part of the buffer - rarely will
+                * any data completely fill the entire allocated size of
+                * the buffer.
+                */
+               for (datalen = 0, i = 0; i < len >> 2; i++)
+                       if (buf[i])
+                               datalen = ((i + 1) << 2);
+
+               /*
+                * If we reach here, then the originally captured binary buffer
+                * will be replaced with the ascii85 encoded string
+                */
+               *ptr = adreno_gpu_ascii85_encode(buf, datalen);
+
+               kvfree(buf);
+
+               *encoded = true;
+       }
+
+       if (!*ptr)
+               return;
 
        drm_puts(p, "    data: !!ascii85 |\n");
        drm_puts(p, "     ");
 
-       for (i = 0; i < l; i++)
-               drm_puts(p, ascii85_encode(ptr[i], out));
+       drm_puts(p, *ptr);
 
        drm_puts(p, "\n");
 }
@@ -534,8 +581,8 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
                drm_printf(p, "    wptr: %d\n", state->ring[i].wptr);
                drm_printf(p, "    size: %d\n", MSM_GPU_RINGBUFFER_SZ);
 
-               adreno_show_object(p, state->ring[i].data,
-                       state->ring[i].data_size);
+               adreno_show_object(p, &state->ring[i].data,
+                       state->ring[i].data_size, &state->ring[i].encoded);
        }
 
        if (state->bos) {
@@ -546,17 +593,19 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
                                state->bos[i].iova);
                        drm_printf(p, "    size: %zd\n", state->bos[i].size);
 
-                       adreno_show_object(p, state->bos[i].data,
-                               state->bos[i].size);
+                       adreno_show_object(p, &state->bos[i].data,
+                               state->bos[i].size, &state->bos[i].encoded);
                }
        }
 
-       drm_puts(p, "registers:\n");
+       if (state->nr_registers) {
+               drm_puts(p, "registers:\n");
 
-       for (i = 0; i < state->nr_registers; i++) {
-               drm_printf(p, "  - { offset: 0x%04x, value: 0x%08x }\n",
-                       state->registers[i * 2] << 2,
-                       state->registers[(i * 2) + 1]);
+               for (i = 0; i < state->nr_registers; i++) {
+                       drm_printf(p, "  - { offset: 0x%04x, value: 0x%08x }\n",
+                               state->registers[i * 2] << 2,
+                               state->registers[(i * 2) + 1]);
+               }
        }
 }
 #endif
@@ -595,6 +644,9 @@ void adreno_dump(struct msm_gpu *gpu)
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        int i;
 
+       if (!adreno_gpu->registers)
+               return;
+
        /* dump these out in a form that can be parsed by demsm: */
        printk("IO:region %s 00000000 00020000\n", gpu->name);
        for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
@@ -635,7 +687,7 @@ static int adreno_get_legacy_pwrlevels(struct device *dev)
 
        node = of_get_compatible_child(dev->of_node, "qcom,gpu-pwrlevels");
        if (!node) {
-               dev_err(dev, "Could not find the GPU powerlevels\n");
+               DRM_DEV_ERROR(dev, "Could not find the GPU powerlevels\n");
                return -ENXIO;
        }
 
@@ -674,7 +726,7 @@ static int adreno_get_pwrlevels(struct device *dev,
        else {
                ret = dev_pm_opp_of_add_table(dev);
                if (ret)
-                       dev_err(dev, "Unable to set the OPP table\n");
+                       DRM_DEV_ERROR(dev, "Unable to set the OPP table\n");
        }
 
        if (!ret) {
@@ -717,6 +769,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
        adreno_gpu_config.va_start = SZ_16M;
        adreno_gpu_config.va_end = 0xffffffff;
+       /* maximum range of a2xx mmu */
+       if (adreno_is_a2xx(adreno_gpu))
+               adreno_gpu_config.va_end = SZ_16M + 0xfff * SZ_64K;
 
        adreno_gpu_config.nr_rings = nr_rings;
 
index de6e6ee42fba139070dde05d68d39d6a0c470231..5db459bc28a730cf61ad27e73a64edafdf899b60 100644 (file)
@@ -21,6 +21,7 @@
 #define __ADRENO_GPU_H__
 
 #include <linux/firmware.h>
+#include <linux/iopoll.h>
 
 #include "msm_gpu.h"
 
@@ -154,6 +155,20 @@ struct adreno_platform_config {
        __ret;                                             \
 })
 
+static inline bool adreno_is_a2xx(struct adreno_gpu *gpu)
+{
+       return (gpu->revn < 300);
+}
+
+static inline bool adreno_is_a20x(struct adreno_gpu *gpu)
+{
+       return (gpu->revn < 210);
+}
+
+static inline bool adreno_is_a225(struct adreno_gpu *gpu)
+{
+       return gpu->revn == 225;
+}
 
 static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
 {
@@ -334,6 +349,7 @@ static inline void adreno_gpu_write(struct adreno_gpu *gpu,
                gpu_write(&gpu->base, reg - 1, data);
 }
 
+struct msm_gpu *a2xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a4xx_gpu_init(struct drm_device *dev);
 struct msm_gpu *a5xx_gpu_init(struct drm_device *dev);
@@ -375,4 +391,9 @@ static inline uint32_t get_wptr(struct msm_ringbuffer *ring)
        ((1 << 29) \
        ((ilog2((_len)) & 0x1F) << 24) | (((_reg) << 2) & 0xFFFFF))
 
+
+#define gpu_poll_timeout(gpu, addr, val, cond, interval, timeout) \
+       readl_poll_timeout((gpu)->mmio + ((addr) << 2), val, cond, \
+               interval, timeout)
+
 #endif /* __ADRENO_GPU_H__ */
index 15eb03bed984689404d75be4458b302295fd5efe..79b907ac0b4b5c725ae0e2895fbaac08e56d5dc3 100644 (file)
@@ -10,13 +10,13 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/envytools/rnndb/adreno.xml               (    501 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/freedreno_copyright.xml  (   1572 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  36805 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  13634 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  42585 bytes, from 2018-10-04 19:06:37)
+- /home/robclark/src/envytools/rnndb/adreno/a2xx.xml          (  42463 bytes, from 2018-11-19 13:44:03)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_common.xml (  14201 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/adreno_pm4.xml    (  43052 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml          (  83840 bytes, from 2018-07-03 19:37:13)
 - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml          ( 112086 bytes, from 2018-07-03 19:37:13)
-- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-10-04 19:06:37)
-- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 139581 bytes, from 2018-10-04 19:06:42)
+- /home/robclark/src/envytools/rnndb/adreno/a5xx.xml          ( 147240 bytes, from 2018-12-02 17:29:54)
+- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml          ( 140790 bytes, from 2018-12-02 17:29:54)
 - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml      (  10431 bytes, from 2018-09-14 13:03:07)
 - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml         (   1773 bytes, from 2018-07-03 19:37:13)
 
@@ -108,6 +108,13 @@ enum pc_di_src_sel {
        DI_SRC_SEL_RESERVED = 3,
 };
 
+enum pc_di_face_cull_sel {
+       DI_FACE_CULL_NONE = 0,
+       DI_FACE_CULL_FETCH = 1,
+       DI_FACE_BACKFACE_CULL = 2,
+       DI_FACE_FRONTFACE_CULL = 3,
+};
+
 enum pc_di_index_size {
        INDEX_SIZE_IGN = 0,
        INDEX_SIZE_16_BIT = 0,
@@ -356,6 +363,7 @@ enum a6xx_render_mode {
        RM6_GMEM = 4,
        RM6_BLIT2D = 5,
        RM6_RESOLVE = 6,
+       RM6_BLIT2DSCALE = 12,
 };
 
 enum pseudo_reg {
index 879c13fe74e05a1f4249f2ba1ad0591da3c8a237..e45c69044935696c13cb1ddd46f77d3c536d29be 100644 (file)
@@ -319,10 +319,8 @@ static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
        unsigned long irq_flags;
        int i, irq_count, enable_count, cb_count;
 
-       if (!irq_obj || !irq_obj->enable_counts || !irq_obj->irq_cb_tbl) {
-               DPU_ERROR("invalid parameters\n");
+       if (WARN_ON(!irq_obj->enable_counts || !irq_obj->irq_cb_tbl))
                return 0;
-       }
 
        for (i = 0; i < irq_obj->total_irqs; i++) {
                spin_lock_irqsave(&irq_obj->cb_lock, irq_flags);
@@ -343,31 +341,11 @@ static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
 
 DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_core_irq);
 
-int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
-               struct dentry *parent)
-{
-       dpu_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0600,
-                       parent, &dpu_kms->irq_obj,
-                       &dpu_debugfs_core_irq_fops);
-
-       return 0;
-}
-
-void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms)
-{
-       debugfs_remove(dpu_kms->irq_obj.debugfs_file);
-       dpu_kms->irq_obj.debugfs_file = NULL;
-}
-
-#else
-int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
+void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
                struct dentry *parent)
 {
-       return 0;
-}
-
-void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms)
-{
+       debugfs_create_file("core_irq", 0600, parent, &dpu_kms->irq_obj,
+               &dpu_debugfs_core_irq_fops);
 }
 #endif
 
@@ -376,10 +354,7 @@ void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms)
        struct msm_drm_private *priv;
        int i;
 
-       if (!dpu_kms) {
-               DPU_ERROR("invalid dpu_kms\n");
-               return;
-       } else if (!dpu_kms->dev) {
+       if (!dpu_kms->dev) {
                DPU_ERROR("invalid drm device\n");
                return;
        } else if (!dpu_kms->dev->dev_private) {
@@ -410,20 +385,12 @@ void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms)
        }
 }
 
-int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms)
-{
-       return 0;
-}
-
 void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms)
 {
        struct msm_drm_private *priv;
        int i;
 
-       if (!dpu_kms) {
-               DPU_ERROR("invalid dpu_kms\n");
-               return;
-       } else if (!dpu_kms->dev) {
+       if (!dpu_kms->dev) {
                DPU_ERROR("invalid drm device\n");
                return;
        } else if (!dpu_kms->dev->dev_private) {
index 5e98bba46af53059bb06381c5b8f786f60a57ed8..e9015a2b23fe040b4a4803df25acd069d346d999 100644 (file)
  */
 void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms);
 
-/**
- * dpu_core_irq_postinstall - perform post-installation of core IRQ handler
- * @dpu_kms:           DPU handle
- * @return:            0 if success; error code otherwise
- */
-int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms);
-
 /**
  * dpu_core_irq_uninstall - uninstall core IRQ handler
  * @dpu_kms:           DPU handle
@@ -139,15 +132,8 @@ int dpu_core_irq_unregister_callback(
  * dpu_debugfs_core_irq_init - register core irq debugfs
  * @dpu_kms: pointer to kms
  * @parent: debugfs directory root
- * @Return: 0 on success
  */
-int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
+void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
                struct dentry *parent);
 
-/**
- * dpu_debugfs_core_irq_destroy - deregister core irq debugfs
- * @dpu_kms: pointer to kms
- */
-void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms);
-
 #endif /* __DPU_CORE_IRQ_H__ */
index 41c5191f9056c9047bd07521b3abf9607149c1dc..9f20f397f77da858e028577e16c78158ff7afafc 100644 (file)
@@ -24,8 +24,6 @@
 #include "dpu_crtc.h"
 #include "dpu_core_perf.h"
 
-#define DPU_PERF_MODE_STRING_SIZE      128
-
 /**
  * enum dpu_perf_mode - performance tuning mode
  * @DPU_PERF_MODE_NORMAL: performance controlled by user mode client
@@ -57,31 +55,20 @@ static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
        return to_dpu_kms(priv->kms);
 }
 
-static bool _dpu_core_perf_crtc_is_power_on(struct drm_crtc *crtc)
-{
-       return dpu_crtc_is_enabled(crtc);
-}
-
 static bool _dpu_core_video_mode_intf_connected(struct drm_crtc *crtc)
 {
        struct drm_crtc *tmp_crtc;
-       bool intf_connected = false;
-
-       if (!crtc)
-               goto end;
 
        drm_for_each_crtc(tmp_crtc, crtc->dev) {
                if ((dpu_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) &&
-                               _dpu_core_perf_crtc_is_power_on(tmp_crtc)) {
+                               tmp_crtc->enabled) {
                        DPU_DEBUG("video interface connected crtc:%d\n",
                                tmp_crtc->base.id);
-                       intf_connected = true;
-                       goto end;
+                       return true;
                }
        }
 
-end:
-       return intf_connected;
+       return false;
 }
 
 static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
@@ -101,20 +88,20 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
        memset(perf, 0, sizeof(struct dpu_core_perf_params));
 
        if (!dpu_cstate->bw_control) {
-               for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+               for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                        perf->bw_ctl[i] = kms->catalog->perf.max_bw_high *
                                        1000ULL;
                        perf->max_per_pipe_ib[i] = perf->bw_ctl[i];
                }
                perf->core_clk_rate = kms->perf.max_core_clk_rate;
        } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) {
-               for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+               for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                        perf->bw_ctl[i] = 0;
                        perf->max_per_pipe_ib[i] = 0;
                }
                perf->core_clk_rate = 0;
        } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) {
-               for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+               for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                        perf->bw_ctl[i] = kms->perf.fix_core_ab_vote;
                        perf->max_per_pipe_ib[i] = kms->perf.fix_core_ib_vote;
                }
@@ -124,12 +111,12 @@ static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
        DPU_DEBUG(
                "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
                        crtc->base.id, perf->core_clk_rate,
-                       perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MNOC],
-                       perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MNOC],
-                       perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_LLCC],
-                       perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_LLCC],
-                       perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_EBI],
-                       perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_EBI]);
+                       perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
+                       perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
+                       perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
+                       perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
+                       perf->max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_EBI],
+                       perf->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_EBI]);
 }
 
 int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
@@ -164,13 +151,13 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
        /* obtain new values */
        _dpu_core_perf_calc_crtc(kms, crtc, state, &dpu_cstate->new_perf);
 
-       for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC;
-                       i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+       for (i = DPU_CORE_PERF_DATA_BUS_ID_MNOC;
+                       i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl[i];
                curr_client_type = dpu_crtc_get_client_type(crtc);
 
                drm_for_each_crtc(tmp_crtc, crtc->dev) {
-                       if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) &&
+                       if (tmp_crtc->enabled &&
                            (dpu_crtc_get_client_type(tmp_crtc) ==
                                            curr_client_type) &&
                            (tmp_crtc != crtc)) {
@@ -229,7 +216,7 @@ static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms,
        int ret = 0;
 
        drm_for_each_crtc(tmp_crtc, crtc->dev) {
-               if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) &&
+               if (tmp_crtc->enabled &&
                        curr_client_type ==
                                dpu_crtc_get_client_type(tmp_crtc)) {
                        dpu_cstate = to_dpu_crtc_state(tmp_crtc->state);
@@ -286,7 +273,7 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
         */
        if (dpu_crtc_get_intf_mode(crtc) == INTF_MODE_CMD)
                drm_for_each_crtc(tmp_crtc, crtc->dev) {
-                       if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) &&
+                       if (tmp_crtc->enabled &&
                                dpu_crtc_get_intf_mode(tmp_crtc) ==
                                                INTF_MODE_VIDEO)
                                return;
@@ -296,7 +283,7 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
        if (kms->perf.enable_bw_release) {
                trace_dpu_cmd_release_bw(crtc->base.id);
                DPU_DEBUG("Release BW crtc=%d\n", crtc->base.id);
-               for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+               for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                        dpu_crtc->cur_perf.bw_ctl[i] = 0;
                        _dpu_core_perf_crtc_update_bus(kms, crtc, i);
                }
@@ -321,7 +308,7 @@ static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms)
        struct dpu_crtc_state *dpu_cstate;
 
        drm_for_each_crtc(crtc, kms->dev) {
-               if (_dpu_core_perf_crtc_is_power_on(crtc)) {
+               if (crtc->enabled) {
                        dpu_cstate = to_dpu_crtc_state(crtc->state);
                        clk_rate = max(dpu_cstate->new_perf.core_clk_rate,
                                                        clk_rate);
@@ -372,8 +359,8 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
        old = &dpu_crtc->cur_perf;
        new = &dpu_cstate->new_perf;
 
-       if (_dpu_core_perf_crtc_is_power_on(crtc) && !stop_req) {
-               for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+       if (crtc->enabled && !stop_req) {
+               for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                        /*
                         * cases for bus bandwidth update.
                         * 1. new bandwidth vote - "ab or ib vote" is higher
@@ -415,13 +402,13 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
                update_clk = 1;
        }
        trace_dpu_perf_crtc_update(crtc->base.id,
-                               new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MNOC],
-                               new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_LLCC],
-                               new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_EBI],
+                               new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MNOC],
+                               new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_LLCC],
+                               new->bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_EBI],
                                new->core_clk_rate, stop_req,
                                update_bus, update_clk);
 
-       for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
+       for (i = 0; i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
                if (update_bus & BIT(i)) {
                        ret = _dpu_core_perf_crtc_update_bus(kms, crtc, i);
                        if (ret) {
@@ -462,24 +449,14 @@ static ssize_t _dpu_core_perf_mode_write(struct file *file,
        struct dpu_core_perf *perf = file->private_data;
        struct dpu_perf_cfg *cfg = &perf->catalog->perf;
        u32 perf_mode = 0;
-       char buf[10];
-
-       if (!perf)
-               return -ENODEV;
-
-       if (count >= sizeof(buf))
-               return -EFAULT;
-
-       if (copy_from_user(buf, user_buf, count))
-               return -EFAULT;
-
-       buf[count] = 0; /* end of string */
+       int ret;
 
-       if (kstrtouint(buf, 0, &perf_mode))
-               return -EFAULT;
+       ret = kstrtouint_from_user(user_buf, count, 0, &perf_mode);
+       if (ret)
+               return ret;
 
        if (perf_mode >= DPU_PERF_MODE_MAX)
-               return -EFAULT;
+               return -EINVAL;
 
        if (perf_mode == DPU_PERF_MODE_FIXED) {
                DRM_INFO("fix performance mode\n");
@@ -504,29 +481,16 @@ static ssize_t _dpu_core_perf_mode_read(struct file *file,
                        char __user *buff, size_t count, loff_t *ppos)
 {
        struct dpu_core_perf *perf = file->private_data;
-       int len = 0;
-       char buf[DPU_PERF_MODE_STRING_SIZE] = {'\0'};
-
-       if (!perf)
-               return -ENODEV;
+       int len;
+       char buf[128];
 
-       if (*ppos)
-               return 0;       /* the end */
-
-       len = snprintf(buf, sizeof(buf),
+       len = scnprintf(buf, sizeof(buf),
                        "mode %d min_mdp_clk %llu min_bus_vote %llu\n",
                        perf->perf_tune.mode,
                        perf->perf_tune.min_core_clk,
                        perf->perf_tune.min_bus_vote);
-       if (len < 0 || len >= sizeof(buf))
-               return 0;
-
-       if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
-               return -EFAULT;
-
-       *ppos += len;   /* increase offset */
 
-       return len;
+       return simple_read_from_buffer(buff, count, ppos, buf, len);
 }
 
 static const struct file_operations dpu_core_perf_mode_fops = {
@@ -535,70 +499,43 @@ static const struct file_operations dpu_core_perf_mode_fops = {
        .write = _dpu_core_perf_mode_write,
 };
 
-static void dpu_core_perf_debugfs_destroy(struct dpu_core_perf *perf)
-{
-       debugfs_remove_recursive(perf->debugfs_root);
-       perf->debugfs_root = NULL;
-}
-
-int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf,
-               struct dentry *parent)
+int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
 {
+       struct dpu_core_perf *perf = &dpu_kms->perf;
        struct dpu_mdss_cfg *catalog = perf->catalog;
-       struct msm_drm_private *priv;
-       struct dpu_kms *dpu_kms;
-
-       priv = perf->dev->dev_private;
-       if (!priv || !priv->kms) {
-               DPU_ERROR("invalid KMS reference\n");
-               return -EINVAL;
-       }
+       struct dentry *entry;
 
-       dpu_kms = to_dpu_kms(priv->kms);
-
-       perf->debugfs_root = debugfs_create_dir("core_perf", parent);
-       if (!perf->debugfs_root) {
-               DPU_ERROR("failed to create core perf debugfs\n");
+       entry = debugfs_create_dir("core_perf", parent);
+       if (IS_ERR_OR_NULL(entry))
                return -EINVAL;
-       }
 
-       debugfs_create_u64("max_core_clk_rate", 0600, perf->debugfs_root,
+       debugfs_create_u64("max_core_clk_rate", 0600, entry,
                        &perf->max_core_clk_rate);
-       debugfs_create_u64("core_clk_rate", 0600, perf->debugfs_root,
+       debugfs_create_u64("core_clk_rate", 0600, entry,
                        &perf->core_clk_rate);
-       debugfs_create_u32("enable_bw_release", 0600, perf->debugfs_root,
+       debugfs_create_u32("enable_bw_release", 0600, entry,
                        (u32 *)&perf->enable_bw_release);
-       debugfs_create_u32("threshold_low", 0600, perf->debugfs_root,
+       debugfs_create_u32("threshold_low", 0600, entry,
                        (u32 *)&catalog->perf.max_bw_low);
-       debugfs_create_u32("threshold_high", 0600, perf->debugfs_root,
+       debugfs_create_u32("threshold_high", 0600, entry,
                        (u32 *)&catalog->perf.max_bw_high);
-       debugfs_create_u32("min_core_ib", 0600, perf->debugfs_root,
+       debugfs_create_u32("min_core_ib", 0600, entry,
                        (u32 *)&catalog->perf.min_core_ib);
-       debugfs_create_u32("min_llcc_ib", 0600, perf->debugfs_root,
+       debugfs_create_u32("min_llcc_ib", 0600, entry,
                        (u32 *)&catalog->perf.min_llcc_ib);
-       debugfs_create_u32("min_dram_ib", 0600, perf->debugfs_root,
+       debugfs_create_u32("min_dram_ib", 0600, entry,
                        (u32 *)&catalog->perf.min_dram_ib);
-       debugfs_create_file("perf_mode", 0600, perf->debugfs_root,
+       debugfs_create_file("perf_mode", 0600, entry,
                        (u32 *)perf, &dpu_core_perf_mode_fops);
-       debugfs_create_u64("fix_core_clk_rate", 0600, perf->debugfs_root,
+       debugfs_create_u64("fix_core_clk_rate", 0600, entry,
                        &perf->fix_core_clk_rate);
-       debugfs_create_u64("fix_core_ib_vote", 0600, perf->debugfs_root,
+       debugfs_create_u64("fix_core_ib_vote", 0600, entry,
                        &perf->fix_core_ib_vote);
-       debugfs_create_u64("fix_core_ab_vote", 0600, perf->debugfs_root,
+       debugfs_create_u64("fix_core_ab_vote", 0600, entry,
                        &perf->fix_core_ab_vote);
 
        return 0;
 }
-#else
-static void dpu_core_perf_debugfs_destroy(struct dpu_core_perf *perf)
-{
-}
-
-int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf,
-               struct dentry *parent)
-{
-       return 0;
-}
 #endif
 
 void dpu_core_perf_destroy(struct dpu_core_perf *perf)
@@ -608,10 +545,8 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf)
                return;
        }
 
-       dpu_core_perf_debugfs_destroy(perf);
        perf->max_core_clk_rate = 0;
        perf->core_clk = NULL;
-       perf->phandle = NULL;
        perf->catalog = NULL;
        perf->dev = NULL;
 }
@@ -619,12 +554,10 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf)
 int dpu_core_perf_init(struct dpu_core_perf *perf,
                struct drm_device *dev,
                struct dpu_mdss_cfg *catalog,
-               struct dpu_power_handle *phandle,
                struct dss_clk *core_clk)
 {
        perf->dev = dev;
        perf->catalog = catalog;
-       perf->phandle = phandle;
        perf->core_clk = core_clk;
 
        perf->max_core_clk_rate = core_clk->max_rate;
index fbcbe0c7527af7c6a4eb7926da2131161c54f076..37f518815eb77a37ef1c08c49dfc9ba148bd0b75 100644 (file)
 #include <drm/drm_crtc.h>
 
 #include "dpu_hw_catalog.h"
-#include "dpu_power_handle.h"
 
 #define        DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE      412500000
 
+/**
+ * enum dpu_core_perf_data_bus_id - data bus identifier
+ * @DPU_CORE_PERF_DATA_BUS_ID_MNOC: DPU/MNOC data bus
+ * @DPU_CORE_PERF_DATA_BUS_ID_LLCC: MNOC/LLCC data bus
+ * @DPU_CORE_PERF_DATA_BUS_ID_EBI: LLCC/EBI data bus
+ */
+enum dpu_core_perf_data_bus_id {
+       DPU_CORE_PERF_DATA_BUS_ID_MNOC,
+       DPU_CORE_PERF_DATA_BUS_ID_LLCC,
+       DPU_CORE_PERF_DATA_BUS_ID_EBI,
+       DPU_CORE_PERF_DATA_BUS_ID_MAX,
+};
+
 /**
  * struct dpu_core_perf_params - definition of performance parameters
  * @max_per_pipe_ib: maximum instantaneous bandwidth request
@@ -30,8 +42,8 @@
  * @core_clk_rate: core clock rate request
  */
 struct dpu_core_perf_params {
-       u64 max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MAX];
-       u64 bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MAX];
+       u64 max_per_pipe_ib[DPU_CORE_PERF_DATA_BUS_ID_MAX];
+       u64 bw_ctl[DPU_CORE_PERF_DATA_BUS_ID_MAX];
        u64 core_clk_rate;
 };
 
@@ -52,7 +64,6 @@ struct dpu_core_perf_tune {
  * @dev: Pointer to drm device
  * @debugfs_root: top level debug folder
  * @catalog: Pointer to catalog configuration
- * @phandle: Pointer to power handler
  * @core_clk: Pointer to core clock structure
  * @core_clk_rate: current core clock rate
  * @max_core_clk_rate: maximum allowable core clock rate
@@ -66,7 +77,6 @@ struct dpu_core_perf {
        struct drm_device *dev;
        struct dentry *debugfs_root;
        struct dpu_mdss_cfg *catalog;
-       struct dpu_power_handle *phandle;
        struct dss_clk *core_clk;
        u64 core_clk_rate;
        u64 max_core_clk_rate;
@@ -113,21 +123,20 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf);
  * @perf: Pointer to core performance context
  * @dev: Pointer to drm device
  * @catalog: Pointer to catalog
- * @phandle: Pointer to power handle
  * @core_clk: pointer to core clock
  */
 int dpu_core_perf_init(struct dpu_core_perf *perf,
                struct drm_device *dev,
                struct dpu_mdss_cfg *catalog,
-               struct dpu_power_handle *phandle,
                struct dss_clk *core_clk);
 
+struct dpu_kms;
+
 /**
  * dpu_core_perf_debugfs_init - initialize debugfs for core performance context
- * @perf: Pointer to core performance context
+ * @dpu_kms: Pointer to the dpu_kms struct
  * @debugfs_parent: Pointer to parent debugfs
  */
-int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf,
-               struct dentry *parent);
+int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent);
 
 #endif /* _DPU_CORE_PERF_H_ */
index ca169f013a14efb4bbe5e26609c8152312ec7493..9be7c355debd0be51ed34f107038aa2739edb6dd 100644 (file)
@@ -33,7 +33,6 @@
 #include "dpu_plane.h"
 #include "dpu_encoder.h"
 #include "dpu_vbif.h"
-#include "dpu_power_handle.h"
 #include "dpu_core_perf.h"
 #include "dpu_trace.h"
 
 #define LEFT_MIXER 0
 #define RIGHT_MIXER 1
 
-static inline int _dpu_crtc_get_mixer_width(struct dpu_crtc_state *cstate,
-                                           struct drm_display_mode *mode)
-{
-       return mode->hdisplay / cstate->num_mixers;
-}
-
-static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
+static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
 {
        struct msm_drm_private *priv = crtc->dev->dev_private;
 
@@ -69,10 +62,7 @@ static void dpu_crtc_destroy(struct drm_crtc *crtc)
        if (!crtc)
                return;
 
-       dpu_crtc->phandle = NULL;
-
        drm_crtc_cleanup(crtc);
-       mutex_destroy(&dpu_crtc->crtc_lock);
        kfree(dpu_crtc);
 }
 
@@ -287,16 +277,17 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc)
                return INTF_MODE_NONE;
        }
 
-       drm_for_each_encoder(encoder, crtc->dev)
-               if (encoder->crtc == crtc)
-                       return dpu_encoder_get_intf_mode(encoder);
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       /* TODO: Returns the first INTF_MODE, could there be multiple values? */
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
+               return dpu_encoder_get_intf_mode(encoder);
 
        return INTF_MODE_NONE;
 }
 
-static void dpu_crtc_vblank_cb(void *data)
+void dpu_crtc_vblank_callback(struct drm_crtc *crtc)
 {
-       struct drm_crtc *crtc = (struct drm_crtc *)data;
        struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
 
        /* keep statistics on vblank callback - with auto reset via debugfs */
@@ -309,6 +300,19 @@ static void dpu_crtc_vblank_cb(void *data)
        trace_dpu_crtc_vblank_cb(DRMID(crtc));
 }
 
+static void dpu_crtc_release_bw_unlocked(struct drm_crtc *crtc)
+{
+       int ret = 0;
+       struct drm_modeset_acquire_ctx ctx;
+
+       DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret);
+       dpu_core_perf_crtc_release_bw(crtc);
+       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       if (ret)
+               DRM_ERROR("Failed to acquire modeset locks to release bw, %d\n",
+                         ret);
+}
+
 static void dpu_crtc_frame_event_work(struct kthread_work *work)
 {
        struct dpu_crtc_frame_event *fevent = container_of(work,
@@ -338,7 +342,7 @@ static void dpu_crtc_frame_event_work(struct kthread_work *work)
                        /* release bandwidth and other resources */
                        trace_dpu_crtc_frame_event_done(DRMID(crtc),
                                                        fevent->event);
-                       dpu_core_perf_crtc_release_bw(crtc);
+                       dpu_crtc_release_bw_unlocked(crtc);
                } else {
                        trace_dpu_crtc_frame_event_more_pending(DRMID(crtc),
                                                                fevent->event);
@@ -473,28 +477,21 @@ static void _dpu_crtc_setup_mixer_for_encoder(
 
 static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
 {
-       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
        struct drm_encoder *enc;
 
-       mutex_lock(&dpu_crtc->crtc_lock);
-       /* Check for mixers on all encoders attached to this crtc */
-       list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) {
-               if (enc->crtc != crtc)
-                       continue;
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
 
+       /* Check for mixers on all encoders attached to this crtc */
+       drm_for_each_encoder_mask(enc, crtc->dev, crtc->state->encoder_mask)
                _dpu_crtc_setup_mixer_for_encoder(crtc, enc);
-       }
-
-       mutex_unlock(&dpu_crtc->crtc_lock);
 }
 
 static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
                struct drm_crtc_state *state)
 {
-       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
        struct dpu_crtc_state *cstate = to_dpu_crtc_state(state);
        struct drm_display_mode *adj_mode = &state->adjusted_mode;
-       u32 crtc_split_width = _dpu_crtc_get_mixer_width(cstate, adj_mode);
+       u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers;
        int i;
 
        for (i = 0; i < cstate->num_mixers; i++) {
@@ -502,7 +499,7 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
                r->x1 = crtc_split_width * i;
                r->y1 = 0;
                r->x2 = r->x1 + crtc_split_width;
-               r->y2 = dpu_crtc_get_mixer_height(dpu_crtc, cstate, adj_mode);
+               r->y2 = adj_mode->vdisplay;
 
                trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r);
        }
@@ -552,13 +549,9 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               if (encoder->crtc != crtc)
-                       continue;
-
-               /* encoder will trigger pending mask now */
+       /* encoder will trigger pending mask now */
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
                dpu_encoder_trigger_kickoff_pending(encoder);
-       }
 
        /*
         * If no mixers have been allocated in dpu_crtc_atomic_check(),
@@ -702,10 +695,9 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc)
        return rc;
 }
 
-void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
+void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async)
 {
        struct drm_encoder *encoder;
-       struct drm_device *dev = crtc->dev;
        struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
        struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
        struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
@@ -721,127 +713,59 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
 
        DPU_ATRACE_BEGIN("crtc_commit");
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+       /*
+        * Encoder will flush/start now, unless it has a tx pending. If so, it
+        * may delay and flush at an irq event (e.g. ppdone)
+        */
+       drm_for_each_encoder_mask(encoder, crtc->dev,
+                                 crtc->state->encoder_mask) {
                struct dpu_encoder_kickoff_params params = { 0 };
-
-               if (encoder->crtc != crtc)
-                       continue;
-
-               /*
-                * Encoder will flush/start now, unless it has a tx pending.
-                * If so, it may delay and flush at an irq event (e.g. ppdone)
-                */
-               dpu_encoder_prepare_for_kickoff(encoder, &params);
+               dpu_encoder_prepare_for_kickoff(encoder, &params, async);
        }
 
-       /* wait for frame_event_done completion */
-       DPU_ATRACE_BEGIN("wait_for_frame_done_event");
-       ret = _dpu_crtc_wait_for_frame_done(crtc);
-       DPU_ATRACE_END("wait_for_frame_done_event");
-       if (ret) {
-               DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
-                               crtc->base.id,
-                               atomic_read(&dpu_crtc->frame_pending));
-               goto end;
-       }
 
-       if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) {
-               /* acquire bandwidth and other resources */
-               DPU_DEBUG("crtc%d first commit\n", crtc->base.id);
-       } else
-               DPU_DEBUG("crtc%d commit\n", crtc->base.id);
+       if (!async) {
+               /* wait for frame_event_done completion */
+               DPU_ATRACE_BEGIN("wait_for_frame_done_event");
+               ret = _dpu_crtc_wait_for_frame_done(crtc);
+               DPU_ATRACE_END("wait_for_frame_done_event");
+               if (ret) {
+                       DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
+                                       crtc->base.id,
+                                       atomic_read(&dpu_crtc->frame_pending));
+                       goto end;
+               }
+
+               if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) {
+                       /* acquire bandwidth and other resources */
+                       DPU_DEBUG("crtc%d first commit\n", crtc->base.id);
+               } else
+                       DPU_DEBUG("crtc%d commit\n", crtc->base.id);
 
-       dpu_crtc->play_count++;
+               dpu_crtc->play_count++;
+       }
 
        dpu_vbif_clear_errors(dpu_kms);
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               if (encoder->crtc != crtc)
-                       continue;
-
-               dpu_encoder_kickoff(encoder);
-       }
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
+               dpu_encoder_kickoff(encoder, async);
 
 end:
-       reinit_completion(&dpu_crtc->frame_done_comp);
+       if (!async)
+               reinit_completion(&dpu_crtc->frame_done_comp);
        DPU_ATRACE_END("crtc_commit");
 }
 
-/**
- * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank request
- * @dpu_crtc: Pointer to dpu crtc structure
- * @enable: Whether to enable/disable vblanks
- */
-static void _dpu_crtc_vblank_enable_no_lock(
-               struct dpu_crtc *dpu_crtc, bool enable)
-{
-       struct drm_crtc *crtc = &dpu_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct drm_encoder *enc;
-
-       if (enable) {
-               /* drop lock since power crtc cb may try to re-acquire lock */
-               mutex_unlock(&dpu_crtc->crtc_lock);
-               pm_runtime_get_sync(dev->dev);
-               mutex_lock(&dpu_crtc->crtc_lock);
-
-               list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
-                       if (enc->crtc != crtc)
-                               continue;
-
-                       trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base),
-                                                    DRMID(enc), enable,
-                                                    dpu_crtc);
-
-                       dpu_encoder_register_vblank_callback(enc,
-                                       dpu_crtc_vblank_cb, (void *)crtc);
-               }
-       } else {
-               list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
-                       if (enc->crtc != crtc)
-                               continue;
-
-                       trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base),
-                                                    DRMID(enc), enable,
-                                                    dpu_crtc);
-
-                       dpu_encoder_register_vblank_callback(enc, NULL, NULL);
-               }
-
-               /* drop lock since power crtc cb may try to re-acquire lock */
-               mutex_unlock(&dpu_crtc->crtc_lock);
-               pm_runtime_put_sync(dev->dev);
-               mutex_lock(&dpu_crtc->crtc_lock);
-       }
-}
-
-/**
- * _dpu_crtc_set_suspend - notify crtc of suspend enable/disable
- * @crtc: Pointer to drm crtc object
- * @enable: true to enable suspend, false to indicate resume
- */
-static void _dpu_crtc_set_suspend(struct drm_crtc *crtc, bool enable)
+static void dpu_crtc_reset(struct drm_crtc *crtc)
 {
-       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-
-       DRM_DEBUG_KMS("crtc%d suspend = %d\n", crtc->base.id, enable);
-
-       mutex_lock(&dpu_crtc->crtc_lock);
+       struct dpu_crtc_state *cstate;
 
-       /*
-        * If the vblank is enabled, release a power reference on suspend
-        * and take it back during resume (if it is still enabled).
-        */
-       trace_dpu_crtc_set_suspend(DRMID(&dpu_crtc->base), enable, dpu_crtc);
-       if (dpu_crtc->suspend == enable)
-               DPU_DEBUG("crtc%d suspend already set to %d, ignoring update\n",
-                               crtc->base.id, enable);
-       else if (dpu_crtc->enabled && dpu_crtc->vblank_requested) {
-               _dpu_crtc_vblank_enable_no_lock(dpu_crtc, !enable);
-       }
+       if (crtc->state)
+               dpu_crtc_destroy_state(crtc, crtc->state);
 
-       dpu_crtc->suspend = enable;
-       mutex_unlock(&dpu_crtc->crtc_lock);
+       crtc->state = kzalloc(sizeof(*cstate), GFP_KERNEL);
+       if (crtc->state)
+               crtc->state->crtc = crtc;
 }
 
 /**
@@ -873,65 +797,8 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc)
        return &cstate->base;
 }
 
-/**
- * dpu_crtc_reset - reset hook for CRTCs
- * Resets the atomic state for @crtc by freeing the state pointer (which might
- * be NULL, e.g. at driver load time) and allocating a new empty state object.
- * @crtc: Pointer to drm crtc structure
- */
-static void dpu_crtc_reset(struct drm_crtc *crtc)
-{
-       struct dpu_crtc *dpu_crtc;
-       struct dpu_crtc_state *cstate;
-
-       if (!crtc) {
-               DPU_ERROR("invalid crtc\n");
-               return;
-       }
-
-       /* revert suspend actions, if necessary */
-       if (dpu_kms_is_suspend_state(crtc->dev))
-               _dpu_crtc_set_suspend(crtc, false);
-
-       /* remove previous state, if present */
-       if (crtc->state) {
-               dpu_crtc_destroy_state(crtc, crtc->state);
-               crtc->state = 0;
-       }
-
-       dpu_crtc = to_dpu_crtc(crtc);
-       cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
-       if (!cstate) {
-               DPU_ERROR("failed to allocate state\n");
-               return;
-       }
-
-       cstate->base.crtc = crtc;
-       crtc->state = &cstate->base;
-}
-
-static void dpu_crtc_handle_power_event(u32 event_type, void *arg)
-{
-       struct drm_crtc *crtc = arg;
-       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-       struct drm_encoder *encoder;
-
-       mutex_lock(&dpu_crtc->crtc_lock);
-
-       trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type);
-
-       /* restore encoder; crtc will be programmed during commit */
-       drm_for_each_encoder(encoder, crtc->dev) {
-               if (encoder->crtc != crtc)
-                       continue;
-
-               dpu_encoder_virt_restore(encoder);
-       }
-
-       mutex_unlock(&dpu_crtc->crtc_lock);
-}
-
-static void dpu_crtc_disable(struct drm_crtc *crtc)
+static void dpu_crtc_disable(struct drm_crtc *crtc,
+                            struct drm_crtc_state *old_crtc_state)
 {
        struct dpu_crtc *dpu_crtc;
        struct dpu_crtc_state *cstate;
@@ -951,13 +818,12 @@ static void dpu_crtc_disable(struct drm_crtc *crtc)
 
        DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-       if (dpu_kms_is_suspend_state(crtc->dev))
-               _dpu_crtc_set_suspend(crtc, true);
-
        /* Disable/save vblank irq handling */
        drm_crtc_vblank_off(crtc);
 
-       mutex_lock(&dpu_crtc->crtc_lock);
+       drm_for_each_encoder_mask(encoder, crtc->dev,
+                                 old_crtc_state->encoder_mask)
+               dpu_encoder_assign_crtc(encoder, NULL);
 
        /* wait for frame_event_done completion */
        if (_dpu_crtc_wait_for_frame_done(crtc))
@@ -966,10 +832,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc)
                                atomic_read(&dpu_crtc->frame_pending));
 
        trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc);
-       if (dpu_crtc->enabled && !dpu_crtc->suspend &&
-                       dpu_crtc->vblank_requested) {
-               _dpu_crtc_vblank_enable_no_lock(dpu_crtc, false);
-       }
        dpu_crtc->enabled = false;
 
        if (atomic_read(&dpu_crtc->frame_pending)) {
@@ -981,15 +843,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc)
 
        dpu_core_perf_crtc_update(crtc, 0, true);
 
-       drm_for_each_encoder(encoder, crtc->dev) {
-               if (encoder->crtc != crtc)
-                       continue;
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
                dpu_encoder_register_frame_event_callback(encoder, NULL, NULL);
-       }
-
-       if (dpu_crtc->power_event)
-               dpu_power_handle_unregister_event(dpu_crtc->phandle,
-                               dpu_crtc->power_event);
 
        memset(cstate->mixers, 0, sizeof(cstate->mixers));
        cstate->num_mixers = 0;
@@ -998,14 +853,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc)
        cstate->bw_control = false;
        cstate->bw_split_vote = false;
 
-       mutex_unlock(&dpu_crtc->crtc_lock);
-
        if (crtc->state->event && !crtc->state->active) {
                spin_lock_irqsave(&crtc->dev->event_lock, flags);
                drm_crtc_send_vblank_event(crtc, crtc->state->event);
                crtc->state->event = NULL;
                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
        }
+
+       pm_runtime_put_sync(crtc->dev->dev);
 }
 
 static void dpu_crtc_enable(struct drm_crtc *crtc,
@@ -1021,33 +876,23 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
        }
        priv = crtc->dev->dev_private;
 
+       pm_runtime_get_sync(crtc->dev->dev);
+
        DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
        dpu_crtc = to_dpu_crtc(crtc);
 
-       drm_for_each_encoder(encoder, crtc->dev) {
-               if (encoder->crtc != crtc)
-                       continue;
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
                dpu_encoder_register_frame_event_callback(encoder,
                                dpu_crtc_frame_event_cb, (void *)crtc);
-       }
 
-       mutex_lock(&dpu_crtc->crtc_lock);
        trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
-       if (!dpu_crtc->enabled && !dpu_crtc->suspend &&
-                       dpu_crtc->vblank_requested) {
-               _dpu_crtc_vblank_enable_no_lock(dpu_crtc, true);
-       }
        dpu_crtc->enabled = true;
 
-       mutex_unlock(&dpu_crtc->crtc_lock);
+       drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
+               dpu_encoder_assign_crtc(encoder, crtc);
 
        /* Enable/restore vblank irq handling */
        drm_crtc_vblank_on(crtc);
-
-       dpu_crtc->power_event = dpu_power_handle_register_event(
-               dpu_crtc->phandle, DPU_POWER_EVENT_ENABLE,
-               dpu_crtc_handle_power_event, crtc, dpu_crtc->name);
-
 }
 
 struct plane_state {
@@ -1101,7 +946,7 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
 
        memset(pipe_staged, 0, sizeof(pipe_staged));
 
-       mixer_width = _dpu_crtc_get_mixer_width(cstate, mode);
+       mixer_width = mode->hdisplay / cstate->num_mixers;
 
        _dpu_crtc_setup_lm_bounds(crtc, state);
 
@@ -1289,21 +1134,32 @@ end:
 
 int dpu_crtc_vblank(struct drm_crtc *crtc, bool en)
 {
-       struct dpu_crtc *dpu_crtc;
-
-       if (!crtc) {
-               DPU_ERROR("invalid crtc\n");
-               return -EINVAL;
-       }
-       dpu_crtc = to_dpu_crtc(crtc);
+       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+       struct drm_encoder *enc;
 
-       mutex_lock(&dpu_crtc->crtc_lock);
        trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc);
-       if (dpu_crtc->enabled && !dpu_crtc->suspend) {
-               _dpu_crtc_vblank_enable_no_lock(dpu_crtc, en);
+
+       /*
+        * Normally we would iterate through encoder_mask in crtc state to find
+        * attached encoders. In this case, we might be disabling vblank _after_
+        * encoder_mask has been cleared.
+        *
+        * Instead, we "assign" a crtc to the encoder in enable and clear it in
+        * disable (which is also after encoder_mask is cleared). So instead of
+        * using encoder mask, we'll ask the encoder to toggle itself iff it's
+        * currently assigned to our crtc.
+        *
+        * Note also that this function cannot be called while crtc is disabled
+        * since we use drm_crtc_vblank_on/off. So we don't need to worry
+        * about the assigned crtcs being inconsistent with the current state
+        * (which means no need to worry about modeset locks).
+        */
+       list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) {
+               trace_dpu_crtc_vblank_enable(DRMID(crtc), DRMID(enc), en,
+                                            dpu_crtc);
+
+               dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en);
        }
-       dpu_crtc->vblank_requested = en;
-       mutex_unlock(&dpu_crtc->crtc_lock);
 
        return 0;
 }
@@ -1324,18 +1180,14 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
 
        int i, out_width;
 
-       if (!s || !s->private)
-               return -EINVAL;
-
        dpu_crtc = s->private;
        crtc = &dpu_crtc->base;
 
        drm_modeset_lock_all(crtc->dev);
        cstate = to_dpu_crtc_state(crtc->state);
 
-       mutex_lock(&dpu_crtc->crtc_lock);
        mode = &crtc->state->adjusted_mode;
-       out_width = _dpu_crtc_get_mixer_width(cstate, mode);
+       out_width = mode->hdisplay / cstate->num_mixers;
 
        seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id,
                                mode->hdisplay, mode->vdisplay);
@@ -1420,9 +1272,6 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
                dpu_crtc->vblank_cb_time = ktime_set(0, 0);
        }
 
-       seq_printf(s, "vblank_enable:%d\n", dpu_crtc->vblank_requested);
-
-       mutex_unlock(&dpu_crtc->crtc_lock);
        drm_modeset_unlock_all(crtc->dev);
 
        return 0;
@@ -1456,13 +1305,11 @@ static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v)
        seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc));
        seq_printf(s, "core_clk_rate: %llu\n",
                        dpu_crtc->cur_perf.core_clk_rate);
-       for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC;
-                       i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) {
-               seq_printf(s, "bw_ctl[%s]: %llu\n",
-                               dpu_power_handle_get_dbus_name(i),
+       for (i = DPU_CORE_PERF_DATA_BUS_ID_MNOC;
+                       i < DPU_CORE_PERF_DATA_BUS_ID_MAX; i++) {
+               seq_printf(s, "bw_ctl[%d]: %llu\n", i,
                                dpu_crtc->cur_perf.bw_ctl[i]);
-               seq_printf(s, "max_per_pipe_ib[%s]: %llu\n",
-                               dpu_power_handle_get_dbus_name(i),
+               seq_printf(s, "max_per_pipe_ib[%d]: %llu\n", i,
                                dpu_crtc->cur_perf.max_per_pipe_ib[i]);
        }
 
@@ -1472,8 +1319,7 @@ DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_crtc_debugfs_state);
 
 static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
 {
-       struct dpu_crtc *dpu_crtc;
-       struct dpu_kms *dpu_kms;
+       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
 
        static const struct file_operations debugfs_status_fops = {
                .open =         _dpu_debugfs_status_open,
@@ -1482,12 +1328,6 @@ static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
                .release =      single_release,
        };
 
-       if (!crtc)
-               return -EINVAL;
-       dpu_crtc = to_dpu_crtc(crtc);
-
-       dpu_kms = _dpu_crtc_get_kms(crtc);
-
        dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name,
                        crtc->dev->primary->debugfs_root);
        if (!dpu_crtc->debugfs_root)
@@ -1504,25 +1344,11 @@ static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
 
        return 0;
 }
-
-static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc)
-{
-       struct dpu_crtc *dpu_crtc;
-
-       if (!crtc)
-               return;
-       dpu_crtc = to_dpu_crtc(crtc);
-       debugfs_remove_recursive(dpu_crtc->debugfs_root);
-}
 #else
 static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
 {
        return 0;
 }
-
-static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc)
-{
-}
 #endif /* CONFIG_DEBUG_FS */
 
 static int dpu_crtc_late_register(struct drm_crtc *crtc)
@@ -1532,7 +1358,9 @@ static int dpu_crtc_late_register(struct drm_crtc *crtc)
 
 static void dpu_crtc_early_unregister(struct drm_crtc *crtc)
 {
-       _dpu_crtc_destroy_debugfs(crtc);
+       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+       debugfs_remove_recursive(dpu_crtc->debugfs_root);
 }
 
 static const struct drm_crtc_funcs dpu_crtc_funcs = {
@@ -1547,7 +1375,7 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = {
 };
 
 static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = {
-       .disable = dpu_crtc_disable,
+       .atomic_disable = dpu_crtc_disable,
        .atomic_enable = dpu_crtc_enable,
        .atomic_check = dpu_crtc_atomic_check,
        .atomic_begin = dpu_crtc_atomic_begin,
@@ -1574,7 +1402,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
        crtc = &dpu_crtc->base;
        crtc->dev = dev;
 
-       mutex_init(&dpu_crtc->crtc_lock);
        spin_lock_init(&dpu_crtc->spin_lock);
        atomic_set(&dpu_crtc->frame_pending, 0);
 
@@ -1601,8 +1428,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
        /* initialize event handling */
        spin_lock_init(&dpu_crtc->event_lock);
 
-       dpu_crtc->phandle = &kms->phandle;
-
        DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name);
        return crtc;
 }
index 3723b48303352c2d9ffbd8da0549b156cd05edcb..dbfb38a1986c8e8164e417add9aba1046160ee01 100644 (file)
@@ -132,8 +132,6 @@ struct dpu_crtc_frame_event {
  * @vblank_cb_count : count of vblank callback since last reset
  * @play_count    : frame count between crtc enable and disable
  * @vblank_cb_time  : ktime at vblank count reset
- * @vblank_requested : whether the user has requested vblank events
- * @suspend         : whether or not a suspend operation is in progress
  * @enabled       : whether the DPU CRTC is currently enabled. updated in the
  *                  commit-thread, not state-swap time which is earlier, so
  *                  safe to make decisions on during VBLANK on/off work
@@ -142,7 +140,6 @@ struct dpu_crtc_frame_event {
  * @dirty_list    : list of color processing features are dirty
  * @ad_dirty: list containing ad properties that are dirty
  * @ad_active: list containing ad properties that are active
- * @crtc_lock     : crtc lock around create, destroy and access.
  * @frame_pending : Whether or not an update is pending
  * @frame_events  : static allocation of in-flight frame events
  * @frame_event_list : available frame event list
@@ -152,7 +149,6 @@ struct dpu_crtc_frame_event {
  * @event_worker  : Event worker queue
  * @event_lock    : Spinlock around event handling code
  * @phandle: Pointer to power handler
- * @power_event   : registered power event handle
  * @cur_perf      : current performance committed to clock/bandwidth driver
  */
 struct dpu_crtc {
@@ -168,8 +164,6 @@ struct dpu_crtc {
        u32 vblank_cb_count;
        u64 play_count;
        ktime_t vblank_cb_time;
-       bool vblank_requested;
-       bool suspend;
        bool enabled;
 
        struct list_head feature_list;
@@ -178,8 +172,6 @@ struct dpu_crtc {
        struct list_head ad_dirty;
        struct list_head ad_active;
 
-       struct mutex crtc_lock;
-
        atomic_t frame_pending;
        struct dpu_crtc_frame_event frame_events[DPU_CRTC_FRAME_EVENT_SIZE];
        struct list_head frame_event_list;
@@ -189,9 +181,6 @@ struct dpu_crtc {
        /* for handling internal event thread */
        spinlock_t event_lock;
 
-       struct dpu_power_handle *phandle;
-       struct dpu_power_event *power_event;
-
        struct dpu_core_perf_params cur_perf;
 
        struct dpu_crtc_smmu_state_data smmu_state;
@@ -237,42 +226,13 @@ struct dpu_crtc_state {
 #define to_dpu_crtc_state(x) \
        container_of(x, struct dpu_crtc_state, base)
 
-/**
- * dpu_crtc_state_is_stereo - Is crtc virtualized with two mixers?
- * @cstate: Pointer to dpu crtc state
- * @Return: true - has two mixers, false - has one mixer
- */
-static inline bool dpu_crtc_state_is_stereo(struct dpu_crtc_state *cstate)
-{
-       return cstate->num_mixers == CRTC_DUAL_MIXERS;
-}
-
-/**
- * dpu_crtc_get_mixer_height - get the mixer height
- * Mixer height will be same as panel height
- */
-static inline int dpu_crtc_get_mixer_height(struct dpu_crtc *dpu_crtc,
-               struct dpu_crtc_state *cstate, struct drm_display_mode *mode)
-{
-       if (!dpu_crtc || !cstate || !mode)
-               return 0;
-
-       return mode->vdisplay;
-}
-
 /**
  * dpu_crtc_frame_pending - retun the number of pending frames
  * @crtc: Pointer to drm crtc object
  */
 static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc)
 {
-       struct dpu_crtc *dpu_crtc;
-
-       if (!crtc)
-               return -EINVAL;
-
-       dpu_crtc = to_dpu_crtc(crtc);
-       return atomic_read(&dpu_crtc->frame_pending);
+       return crtc ? atomic_read(&to_dpu_crtc(crtc)->frame_pending) : -EINVAL;
 }
 
 /**
@@ -282,11 +242,18 @@ static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc)
  */
 int dpu_crtc_vblank(struct drm_crtc *crtc, bool en);
 
+/**
+ * dpu_crtc_vblank_callback - called on vblank irq, issues completion events
+ * @crtc: Pointer to drm crtc object
+ */
+void dpu_crtc_vblank_callback(struct drm_crtc *crtc);
+
 /**
  * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc
  * @crtc: Pointer to drm crtc object
+ * @async: true if the commit is asynchronous, false otherwise
  */
-void dpu_crtc_commit_kickoff(struct drm_crtc *crtc);
+void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async);
 
 /**
  * dpu_crtc_complete_commit - callback signalling completion of current commit
@@ -329,22 +296,7 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc);
 static inline enum dpu_crtc_client_type dpu_crtc_get_client_type(
                                                struct drm_crtc *crtc)
 {
-       struct dpu_crtc_state *cstate =
-                       crtc ? to_dpu_crtc_state(crtc->state) : NULL;
-
-       if (!cstate)
-               return NRT_CLIENT;
-
-       return RT_CLIENT;
-}
-
-/**
- * dpu_crtc_is_enabled - check if dpu crtc is enabled or not
- * @crtc: Pointer to crtc
- */
-static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc)
-{
-       return crtc ? crtc->enabled : false;
+       return crtc && crtc->state ? RT_CLIENT : NRT_CLIENT;
 }
 
 #endif /* _DPU_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c
deleted file mode 100644 (file)
index ae2aee7..0000000
+++ /dev/null
@@ -1,2393 +0,0 @@
-/* Copyright (c) 2009-2018, 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.
- */
-
-#define pr_fmt(fmt)    "[drm:%s:%d] " fmt, __func__, __LINE__
-
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/ktime.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/dma-buf.h>
-#include <linux/slab.h>
-#include <linux/list_sort.h>
-#include <linux/pm_runtime.h>
-
-#include "dpu_dbg.h"
-#include "disp/dpu1/dpu_hw_catalog.h"
-
-
-#define DEFAULT_DBGBUS_DPU     DPU_DBG_DUMP_IN_MEM
-#define DEFAULT_DBGBUS_VBIFRT  DPU_DBG_DUMP_IN_MEM
-#define REG_BASE_NAME_LEN      80
-
-#define DBGBUS_FLAGS_DSPP      BIT(0)
-#define DBGBUS_DSPP_STATUS     0x34C
-
-#define DBGBUS_NAME_DPU                "dpu"
-#define DBGBUS_NAME_VBIF_RT    "vbif_rt"
-
-/* offsets from dpu top address for the debug buses */
-#define DBGBUS_SSPP0   0x188
-#define DBGBUS_AXI_INTF        0x194
-#define DBGBUS_SSPP1   0x298
-#define DBGBUS_DSPP    0x348
-#define DBGBUS_PERIPH  0x418
-
-#define TEST_MASK(id, tp)      ((id << 4) | (tp << 1) | BIT(0))
-
-/* following offsets are with respect to MDP VBIF base for DBG BUS access */
-#define MMSS_VBIF_CLKON                        0x4
-#define MMSS_VBIF_TEST_BUS_OUT_CTRL    0x210
-#define MMSS_VBIF_TEST_BUS_OUT         0x230
-
-/* Vbif error info */
-#define MMSS_VBIF_PND_ERR              0x190
-#define MMSS_VBIF_SRC_ERR              0x194
-#define MMSS_VBIF_XIN_HALT_CTRL1       0x204
-#define MMSS_VBIF_ERR_INFO             0X1a0
-#define MMSS_VBIF_ERR_INFO_1           0x1a4
-#define MMSS_VBIF_CLIENT_NUM           14
-
-/**
- * struct dpu_dbg_reg_base - register region base.
- *     may sub-ranges: sub-ranges are used for dumping
- *     or may not have sub-ranges: dumping is base -> max_offset
- * @reg_base_head: head of this node
- * @name: register base name
- * @base: base pointer
- * @off: cached offset of region for manual register dumping
- * @cnt: cached range of region for manual register dumping
- * @max_offset: length of region
- * @buf: buffer used for manual register dumping
- * @buf_len:  buffer length used for manual register dumping
- * @cb: callback for external dump function, null if not defined
- * @cb_ptr: private pointer to callback function
- */
-struct dpu_dbg_reg_base {
-       struct list_head reg_base_head;
-       char name[REG_BASE_NAME_LEN];
-       void __iomem *base;
-       size_t off;
-       size_t cnt;
-       size_t max_offset;
-       char *buf;
-       size_t buf_len;
-       void (*cb)(void *ptr);
-       void *cb_ptr;
-};
-
-struct dpu_debug_bus_entry {
-       u32 wr_addr;
-       u32 block_id;
-       u32 test_id;
-       void (*analyzer)(void __iomem *mem_base,
-                               struct dpu_debug_bus_entry *entry, u32 val);
-};
-
-struct vbif_debug_bus_entry {
-       u32 disable_bus_addr;
-       u32 block_bus_addr;
-       u32 bit_offset;
-       u32 block_cnt;
-       u32 test_pnt_start;
-       u32 test_pnt_cnt;
-};
-
-struct dpu_dbg_debug_bus_common {
-       char *name;
-       u32 enable_mask;
-       bool include_in_deferred_work;
-       u32 flags;
-       u32 entries_size;
-       u32 *dumped_content;
-};
-
-struct dpu_dbg_dpu_debug_bus {
-       struct dpu_dbg_debug_bus_common cmn;
-       struct dpu_debug_bus_entry *entries;
-       u32 top_blk_off;
-};
-
-struct dpu_dbg_vbif_debug_bus {
-       struct dpu_dbg_debug_bus_common cmn;
-       struct vbif_debug_bus_entry *entries;
-};
-
-/**
- * struct dpu_dbg_base - global dpu debug base structure
- * @reg_base_list: list of register dumping regions
- * @dev: device pointer
- * @dump_work: work struct for deferring register dump work to separate thread
- * @dbgbus_dpu: debug bus structure for the dpu
- * @dbgbus_vbif_rt: debug bus structure for the realtime vbif
- */
-static struct dpu_dbg_base {
-       struct list_head reg_base_list;
-       struct device *dev;
-
-       struct work_struct dump_work;
-
-       struct dpu_dbg_dpu_debug_bus dbgbus_dpu;
-       struct dpu_dbg_vbif_debug_bus dbgbus_vbif_rt;
-} dpu_dbg_base;
-
-static void _dpu_debug_bus_xbar_dump(void __iomem *mem_base,
-               struct dpu_debug_bus_entry *entry, u32 val)
-{
-       dev_err(dpu_dbg_base.dev, "xbar 0x%x %d %d 0x%x\n",
-                       entry->wr_addr, entry->block_id, entry->test_id, val);
-}
-
-static void _dpu_debug_bus_lm_dump(void __iomem *mem_base,
-               struct dpu_debug_bus_entry *entry, u32 val)
-{
-       if (!(val & 0xFFF000))
-               return;
-
-       dev_err(dpu_dbg_base.dev, "lm 0x%x %d %d 0x%x\n",
-                       entry->wr_addr, entry->block_id, entry->test_id, val);
-}
-
-static void _dpu_debug_bus_ppb0_dump(void __iomem *mem_base,
-               struct dpu_debug_bus_entry *entry, u32 val)
-{
-       if (!(val & BIT(15)))
-               return;
-
-       dev_err(dpu_dbg_base.dev, "ppb0 0x%x %d %d 0x%x\n",
-                       entry->wr_addr, entry->block_id, entry->test_id, val);
-}
-
-static void _dpu_debug_bus_ppb1_dump(void __iomem *mem_base,
-               struct dpu_debug_bus_entry *entry, u32 val)
-{
-       if (!(val & BIT(15)))
-               return;
-
-       dev_err(dpu_dbg_base.dev, "ppb1 0x%x %d %d 0x%x\n",
-                       entry->wr_addr, entry->block_id, entry->test_id, val);
-}
-
-static struct dpu_debug_bus_entry dbg_bus_dpu_8998[] = {
-
-       /* Unpack 0 sspp 0*/
-       { DBGBUS_SSPP0, 50, 2 },
-       { DBGBUS_SSPP0, 60, 2 },
-       { DBGBUS_SSPP0, 70, 2 },
-       { DBGBUS_SSPP0, 85, 2 },
-
-       /* Upack 0 sspp 1*/
-       { DBGBUS_SSPP1, 50, 2 },
-       { DBGBUS_SSPP1, 60, 2 },
-       { DBGBUS_SSPP1, 70, 2 },
-       { DBGBUS_SSPP1, 85, 2 },
-
-       /* scheduler */
-       { DBGBUS_DSPP, 130, 0 },
-       { DBGBUS_DSPP, 130, 1 },
-       { DBGBUS_DSPP, 130, 2 },
-       { DBGBUS_DSPP, 130, 3 },
-       { DBGBUS_DSPP, 130, 4 },
-       { DBGBUS_DSPP, 130, 5 },
-
-       /* qseed */
-       { DBGBUS_SSPP0, 6, 0},
-       { DBGBUS_SSPP0, 6, 1},
-       { DBGBUS_SSPP0, 26, 0},
-       { DBGBUS_SSPP0, 26, 1},
-       { DBGBUS_SSPP1, 6, 0},
-       { DBGBUS_SSPP1, 6, 1},
-       { DBGBUS_SSPP1, 26, 0},
-       { DBGBUS_SSPP1, 26, 1},
-
-       /* scale */
-       { DBGBUS_SSPP0, 16, 0},
-       { DBGBUS_SSPP0, 16, 1},
-       { DBGBUS_SSPP0, 36, 0},
-       { DBGBUS_SSPP0, 36, 1},
-       { DBGBUS_SSPP1, 16, 0},
-       { DBGBUS_SSPP1, 16, 1},
-       { DBGBUS_SSPP1, 36, 0},
-       { DBGBUS_SSPP1, 36, 1},
-
-       /* fetch sspp0 */
-
-       /* vig 0 */
-       { DBGBUS_SSPP0, 0, 0 },
-       { DBGBUS_SSPP0, 0, 1 },
-       { DBGBUS_SSPP0, 0, 2 },
-       { DBGBUS_SSPP0, 0, 3 },
-       { DBGBUS_SSPP0, 0, 4 },
-       { DBGBUS_SSPP0, 0, 5 },
-       { DBGBUS_SSPP0, 0, 6 },
-       { DBGBUS_SSPP0, 0, 7 },
-
-       { DBGBUS_SSPP0, 1, 0 },
-       { DBGBUS_SSPP0, 1, 1 },
-       { DBGBUS_SSPP0, 1, 2 },
-       { DBGBUS_SSPP0, 1, 3 },
-       { DBGBUS_SSPP0, 1, 4 },
-       { DBGBUS_SSPP0, 1, 5 },
-       { DBGBUS_SSPP0, 1, 6 },
-       { DBGBUS_SSPP0, 1, 7 },
-
-       { DBGBUS_SSPP0, 2, 0 },
-       { DBGBUS_SSPP0, 2, 1 },
-       { DBGBUS_SSPP0, 2, 2 },
-       { DBGBUS_SSPP0, 2, 3 },
-       { DBGBUS_SSPP0, 2, 4 },
-       { DBGBUS_SSPP0, 2, 5 },
-       { DBGBUS_SSPP0, 2, 6 },
-       { DBGBUS_SSPP0, 2, 7 },
-
-       { DBGBUS_SSPP0, 4, 0 },
-       { DBGBUS_SSPP0, 4, 1 },
-       { DBGBUS_SSPP0, 4, 2 },
-       { DBGBUS_SSPP0, 4, 3 },
-       { DBGBUS_SSPP0, 4, 4 },
-       { DBGBUS_SSPP0, 4, 5 },
-       { DBGBUS_SSPP0, 4, 6 },
-       { DBGBUS_SSPP0, 4, 7 },
-
-       { DBGBUS_SSPP0, 5, 0 },
-       { DBGBUS_SSPP0, 5, 1 },
-       { DBGBUS_SSPP0, 5, 2 },
-       { DBGBUS_SSPP0, 5, 3 },
-       { DBGBUS_SSPP0, 5, 4 },
-       { DBGBUS_SSPP0, 5, 5 },
-       { DBGBUS_SSPP0, 5, 6 },
-       { DBGBUS_SSPP0, 5, 7 },
-
-       /* vig 2 */
-       { DBGBUS_SSPP0, 20, 0 },
-       { DBGBUS_SSPP0, 20, 1 },
-       { DBGBUS_SSPP0, 20, 2 },
-       { DBGBUS_SSPP0, 20, 3 },
-       { DBGBUS_SSPP0, 20, 4 },
-       { DBGBUS_SSPP0, 20, 5 },
-       { DBGBUS_SSPP0, 20, 6 },
-       { DBGBUS_SSPP0, 20, 7 },
-
-       { DBGBUS_SSPP0, 21, 0 },
-       { DBGBUS_SSPP0, 21, 1 },
-       { DBGBUS_SSPP0, 21, 2 },
-       { DBGBUS_SSPP0, 21, 3 },
-       { DBGBUS_SSPP0, 21, 4 },
-       { DBGBUS_SSPP0, 21, 5 },
-       { DBGBUS_SSPP0, 21, 6 },
-       { DBGBUS_SSPP0, 21, 7 },
-
-       { DBGBUS_SSPP0, 22, 0 },
-       { DBGBUS_SSPP0, 22, 1 },
-       { DBGBUS_SSPP0, 22, 2 },
-       { DBGBUS_SSPP0, 22, 3 },
-       { DBGBUS_SSPP0, 22, 4 },
-       { DBGBUS_SSPP0, 22, 5 },
-       { DBGBUS_SSPP0, 22, 6 },
-       { DBGBUS_SSPP0, 22, 7 },
-
-       { DBGBUS_SSPP0, 24, 0 },
-       { DBGBUS_SSPP0, 24, 1 },
-       { DBGBUS_SSPP0, 24, 2 },
-       { DBGBUS_SSPP0, 24, 3 },
-       { DBGBUS_SSPP0, 24, 4 },
-       { DBGBUS_SSPP0, 24, 5 },
-       { DBGBUS_SSPP0, 24, 6 },
-       { DBGBUS_SSPP0, 24, 7 },
-
-       { DBGBUS_SSPP0, 25, 0 },
-       { DBGBUS_SSPP0, 25, 1 },
-       { DBGBUS_SSPP0, 25, 2 },
-       { DBGBUS_SSPP0, 25, 3 },
-       { DBGBUS_SSPP0, 25, 4 },
-       { DBGBUS_SSPP0, 25, 5 },
-       { DBGBUS_SSPP0, 25, 6 },
-       { DBGBUS_SSPP0, 25, 7 },
-
-       /* dma 2 */
-       { DBGBUS_SSPP0, 30, 0 },
-       { DBGBUS_SSPP0, 30, 1 },
-       { DBGBUS_SSPP0, 30, 2 },
-       { DBGBUS_SSPP0, 30, 3 },
-       { DBGBUS_SSPP0, 30, 4 },
-       { DBGBUS_SSPP0, 30, 5 },
-       { DBGBUS_SSPP0, 30, 6 },
-       { DBGBUS_SSPP0, 30, 7 },
-
-       { DBGBUS_SSPP0, 31, 0 },
-       { DBGBUS_SSPP0, 31, 1 },
-       { DBGBUS_SSPP0, 31, 2 },
-       { DBGBUS_SSPP0, 31, 3 },
-       { DBGBUS_SSPP0, 31, 4 },
-       { DBGBUS_SSPP0, 31, 5 },
-       { DBGBUS_SSPP0, 31, 6 },
-       { DBGBUS_SSPP0, 31, 7 },
-
-       { DBGBUS_SSPP0, 32, 0 },
-       { DBGBUS_SSPP0, 32, 1 },
-       { DBGBUS_SSPP0, 32, 2 },
-       { DBGBUS_SSPP0, 32, 3 },
-       { DBGBUS_SSPP0, 32, 4 },
-       { DBGBUS_SSPP0, 32, 5 },
-       { DBGBUS_SSPP0, 32, 6 },
-       { DBGBUS_SSPP0, 32, 7 },
-
-       { DBGBUS_SSPP0, 33, 0 },
-       { DBGBUS_SSPP0, 33, 1 },
-       { DBGBUS_SSPP0, 33, 2 },
-       { DBGBUS_SSPP0, 33, 3 },
-       { DBGBUS_SSPP0, 33, 4 },
-       { DBGBUS_SSPP0, 33, 5 },
-       { DBGBUS_SSPP0, 33, 6 },
-       { DBGBUS_SSPP0, 33, 7 },
-
-       { DBGBUS_SSPP0, 34, 0 },
-       { DBGBUS_SSPP0, 34, 1 },
-       { DBGBUS_SSPP0, 34, 2 },
-       { DBGBUS_SSPP0, 34, 3 },
-       { DBGBUS_SSPP0, 34, 4 },
-       { DBGBUS_SSPP0, 34, 5 },
-       { DBGBUS_SSPP0, 34, 6 },
-       { DBGBUS_SSPP0, 34, 7 },
-
-       { DBGBUS_SSPP0, 35, 0 },
-       { DBGBUS_SSPP0, 35, 1 },
-       { DBGBUS_SSPP0, 35, 2 },
-       { DBGBUS_SSPP0, 35, 3 },
-
-       /* dma 0 */
-       { DBGBUS_SSPP0, 40, 0 },
-       { DBGBUS_SSPP0, 40, 1 },
-       { DBGBUS_SSPP0, 40, 2 },
-       { DBGBUS_SSPP0, 40, 3 },
-       { DBGBUS_SSPP0, 40, 4 },
-       { DBGBUS_SSPP0, 40, 5 },
-       { DBGBUS_SSPP0, 40, 6 },
-       { DBGBUS_SSPP0, 40, 7 },
-
-       { DBGBUS_SSPP0, 41, 0 },
-       { DBGBUS_SSPP0, 41, 1 },
-       { DBGBUS_SSPP0, 41, 2 },
-       { DBGBUS_SSPP0, 41, 3 },
-       { DBGBUS_SSPP0, 41, 4 },
-       { DBGBUS_SSPP0, 41, 5 },
-       { DBGBUS_SSPP0, 41, 6 },
-       { DBGBUS_SSPP0, 41, 7 },
-
-       { DBGBUS_SSPP0, 42, 0 },
-       { DBGBUS_SSPP0, 42, 1 },
-       { DBGBUS_SSPP0, 42, 2 },
-       { DBGBUS_SSPP0, 42, 3 },
-       { DBGBUS_SSPP0, 42, 4 },
-       { DBGBUS_SSPP0, 42, 5 },
-       { DBGBUS_SSPP0, 42, 6 },
-       { DBGBUS_SSPP0, 42, 7 },
-
-       { DBGBUS_SSPP0, 44, 0 },
-       { DBGBUS_SSPP0, 44, 1 },
-       { DBGBUS_SSPP0, 44, 2 },
-       { DBGBUS_SSPP0, 44, 3 },
-       { DBGBUS_SSPP0, 44, 4 },
-       { DBGBUS_SSPP0, 44, 5 },
-       { DBGBUS_SSPP0, 44, 6 },
-       { DBGBUS_SSPP0, 44, 7 },
-
-       { DBGBUS_SSPP0, 45, 0 },
-       { DBGBUS_SSPP0, 45, 1 },
-       { DBGBUS_SSPP0, 45, 2 },
-       { DBGBUS_SSPP0, 45, 3 },
-       { DBGBUS_SSPP0, 45, 4 },
-       { DBGBUS_SSPP0, 45, 5 },
-       { DBGBUS_SSPP0, 45, 6 },
-       { DBGBUS_SSPP0, 45, 7 },
-
-       /* fetch sspp1 */
-       /* vig 1 */
-       { DBGBUS_SSPP1, 0, 0 },
-       { DBGBUS_SSPP1, 0, 1 },
-       { DBGBUS_SSPP1, 0, 2 },
-       { DBGBUS_SSPP1, 0, 3 },
-       { DBGBUS_SSPP1, 0, 4 },
-       { DBGBUS_SSPP1, 0, 5 },
-       { DBGBUS_SSPP1, 0, 6 },
-       { DBGBUS_SSPP1, 0, 7 },
-
-       { DBGBUS_SSPP1, 1, 0 },
-       { DBGBUS_SSPP1, 1, 1 },
-       { DBGBUS_SSPP1, 1, 2 },
-       { DBGBUS_SSPP1, 1, 3 },
-       { DBGBUS_SSPP1, 1, 4 },
-       { DBGBUS_SSPP1, 1, 5 },
-       { DBGBUS_SSPP1, 1, 6 },
-       { DBGBUS_SSPP1, 1, 7 },
-
-       { DBGBUS_SSPP1, 2, 0 },
-       { DBGBUS_SSPP1, 2, 1 },
-       { DBGBUS_SSPP1, 2, 2 },
-       { DBGBUS_SSPP1, 2, 3 },
-       { DBGBUS_SSPP1, 2, 4 },
-       { DBGBUS_SSPP1, 2, 5 },
-       { DBGBUS_SSPP1, 2, 6 },
-       { DBGBUS_SSPP1, 2, 7 },
-
-       { DBGBUS_SSPP1, 4, 0 },
-       { DBGBUS_SSPP1, 4, 1 },
-       { DBGBUS_SSPP1, 4, 2 },
-       { DBGBUS_SSPP1, 4, 3 },
-       { DBGBUS_SSPP1, 4, 4 },
-       { DBGBUS_SSPP1, 4, 5 },
-       { DBGBUS_SSPP1, 4, 6 },
-       { DBGBUS_SSPP1, 4, 7 },
-
-       { DBGBUS_SSPP1, 5, 0 },
-       { DBGBUS_SSPP1, 5, 1 },
-       { DBGBUS_SSPP1, 5, 2 },
-       { DBGBUS_SSPP1, 5, 3 },
-       { DBGBUS_SSPP1, 5, 4 },
-       { DBGBUS_SSPP1, 5, 5 },
-       { DBGBUS_SSPP1, 5, 6 },
-       { DBGBUS_SSPP1, 5, 7 },
-
-       /* vig 3 */
-       { DBGBUS_SSPP1, 20, 0 },
-       { DBGBUS_SSPP1, 20, 1 },
-       { DBGBUS_SSPP1, 20, 2 },
-       { DBGBUS_SSPP1, 20, 3 },
-       { DBGBUS_SSPP1, 20, 4 },
-       { DBGBUS_SSPP1, 20, 5 },
-       { DBGBUS_SSPP1, 20, 6 },
-       { DBGBUS_SSPP1, 20, 7 },
-
-       { DBGBUS_SSPP1, 21, 0 },
-       { DBGBUS_SSPP1, 21, 1 },
-       { DBGBUS_SSPP1, 21, 2 },
-       { DBGBUS_SSPP1, 21, 3 },
-       { DBGBUS_SSPP1, 21, 4 },
-       { DBGBUS_SSPP1, 21, 5 },
-       { DBGBUS_SSPP1, 21, 6 },
-       { DBGBUS_SSPP1, 21, 7 },
-
-       { DBGBUS_SSPP1, 22, 0 },
-       { DBGBUS_SSPP1, 22, 1 },
-       { DBGBUS_SSPP1, 22, 2 },
-       { DBGBUS_SSPP1, 22, 3 },
-       { DBGBUS_SSPP1, 22, 4 },
-       { DBGBUS_SSPP1, 22, 5 },
-       { DBGBUS_SSPP1, 22, 6 },
-       { DBGBUS_SSPP1, 22, 7 },
-
-       { DBGBUS_SSPP1, 24, 0 },
-       { DBGBUS_SSPP1, 24, 1 },
-       { DBGBUS_SSPP1, 24, 2 },
-       { DBGBUS_SSPP1, 24, 3 },
-       { DBGBUS_SSPP1, 24, 4 },
-       { DBGBUS_SSPP1, 24, 5 },
-       { DBGBUS_SSPP1, 24, 6 },
-       { DBGBUS_SSPP1, 24, 7 },
-
-       { DBGBUS_SSPP1, 25, 0 },
-       { DBGBUS_SSPP1, 25, 1 },
-       { DBGBUS_SSPP1, 25, 2 },
-       { DBGBUS_SSPP1, 25, 3 },
-       { DBGBUS_SSPP1, 25, 4 },
-       { DBGBUS_SSPP1, 25, 5 },
-       { DBGBUS_SSPP1, 25, 6 },
-       { DBGBUS_SSPP1, 25, 7 },
-
-       /* dma 3 */
-       { DBGBUS_SSPP1, 30, 0 },
-       { DBGBUS_SSPP1, 30, 1 },
-       { DBGBUS_SSPP1, 30, 2 },
-       { DBGBUS_SSPP1, 30, 3 },
-       { DBGBUS_SSPP1, 30, 4 },
-       { DBGBUS_SSPP1, 30, 5 },
-       { DBGBUS_SSPP1, 30, 6 },
-       { DBGBUS_SSPP1, 30, 7 },
-
-       { DBGBUS_SSPP1, 31, 0 },
-       { DBGBUS_SSPP1, 31, 1 },
-       { DBGBUS_SSPP1, 31, 2 },
-       { DBGBUS_SSPP1, 31, 3 },
-       { DBGBUS_SSPP1, 31, 4 },
-       { DBGBUS_SSPP1, 31, 5 },
-       { DBGBUS_SSPP1, 31, 6 },
-       { DBGBUS_SSPP1, 31, 7 },
-
-       { DBGBUS_SSPP1, 32, 0 },
-       { DBGBUS_SSPP1, 32, 1 },
-       { DBGBUS_SSPP1, 32, 2 },
-       { DBGBUS_SSPP1, 32, 3 },
-       { DBGBUS_SSPP1, 32, 4 },
-       { DBGBUS_SSPP1, 32, 5 },
-       { DBGBUS_SSPP1, 32, 6 },
-       { DBGBUS_SSPP1, 32, 7 },
-
-       { DBGBUS_SSPP1, 33, 0 },
-       { DBGBUS_SSPP1, 33, 1 },
-       { DBGBUS_SSPP1, 33, 2 },
-       { DBGBUS_SSPP1, 33, 3 },
-       { DBGBUS_SSPP1, 33, 4 },
-       { DBGBUS_SSPP1, 33, 5 },
-       { DBGBUS_SSPP1, 33, 6 },
-       { DBGBUS_SSPP1, 33, 7 },
-
-       { DBGBUS_SSPP1, 34, 0 },
-       { DBGBUS_SSPP1, 34, 1 },
-       { DBGBUS_SSPP1, 34, 2 },
-       { DBGBUS_SSPP1, 34, 3 },
-       { DBGBUS_SSPP1, 34, 4 },
-       { DBGBUS_SSPP1, 34, 5 },
-       { DBGBUS_SSPP1, 34, 6 },
-       { DBGBUS_SSPP1, 34, 7 },
-
-       { DBGBUS_SSPP1, 35, 0 },
-       { DBGBUS_SSPP1, 35, 1 },
-       { DBGBUS_SSPP1, 35, 2 },
-
-       /* dma 1 */
-       { DBGBUS_SSPP1, 40, 0 },
-       { DBGBUS_SSPP1, 40, 1 },
-       { DBGBUS_SSPP1, 40, 2 },
-       { DBGBUS_SSPP1, 40, 3 },
-       { DBGBUS_SSPP1, 40, 4 },
-       { DBGBUS_SSPP1, 40, 5 },
-       { DBGBUS_SSPP1, 40, 6 },
-       { DBGBUS_SSPP1, 40, 7 },
-
-       { DBGBUS_SSPP1, 41, 0 },
-       { DBGBUS_SSPP1, 41, 1 },
-       { DBGBUS_SSPP1, 41, 2 },
-       { DBGBUS_SSPP1, 41, 3 },
-       { DBGBUS_SSPP1, 41, 4 },
-       { DBGBUS_SSPP1, 41, 5 },
-       { DBGBUS_SSPP1, 41, 6 },
-       { DBGBUS_SSPP1, 41, 7 },
-
-       { DBGBUS_SSPP1, 42, 0 },
-       { DBGBUS_SSPP1, 42, 1 },
-       { DBGBUS_SSPP1, 42, 2 },
-       { DBGBUS_SSPP1, 42, 3 },
-       { DBGBUS_SSPP1, 42, 4 },
-       { DBGBUS_SSPP1, 42, 5 },
-       { DBGBUS_SSPP1, 42, 6 },
-       { DBGBUS_SSPP1, 42, 7 },
-
-       { DBGBUS_SSPP1, 44, 0 },
-       { DBGBUS_SSPP1, 44, 1 },
-       { DBGBUS_SSPP1, 44, 2 },
-       { DBGBUS_SSPP1, 44, 3 },
-       { DBGBUS_SSPP1, 44, 4 },
-       { DBGBUS_SSPP1, 44, 5 },
-       { DBGBUS_SSPP1, 44, 6 },
-       { DBGBUS_SSPP1, 44, 7 },
-
-       { DBGBUS_SSPP1, 45, 0 },
-       { DBGBUS_SSPP1, 45, 1 },
-       { DBGBUS_SSPP1, 45, 2 },
-       { DBGBUS_SSPP1, 45, 3 },
-       { DBGBUS_SSPP1, 45, 4 },
-       { DBGBUS_SSPP1, 45, 5 },
-       { DBGBUS_SSPP1, 45, 6 },
-       { DBGBUS_SSPP1, 45, 7 },
-
-       /* cursor 1 */
-       { DBGBUS_SSPP1, 80, 0 },
-       { DBGBUS_SSPP1, 80, 1 },
-       { DBGBUS_SSPP1, 80, 2 },
-       { DBGBUS_SSPP1, 80, 3 },
-       { DBGBUS_SSPP1, 80, 4 },
-       { DBGBUS_SSPP1, 80, 5 },
-       { DBGBUS_SSPP1, 80, 6 },
-       { DBGBUS_SSPP1, 80, 7 },
-
-       { DBGBUS_SSPP1, 81, 0 },
-       { DBGBUS_SSPP1, 81, 1 },
-       { DBGBUS_SSPP1, 81, 2 },
-       { DBGBUS_SSPP1, 81, 3 },
-       { DBGBUS_SSPP1, 81, 4 },
-       { DBGBUS_SSPP1, 81, 5 },
-       { DBGBUS_SSPP1, 81, 6 },
-       { DBGBUS_SSPP1, 81, 7 },
-
-       { DBGBUS_SSPP1, 82, 0 },
-       { DBGBUS_SSPP1, 82, 1 },
-       { DBGBUS_SSPP1, 82, 2 },
-       { DBGBUS_SSPP1, 82, 3 },
-       { DBGBUS_SSPP1, 82, 4 },
-       { DBGBUS_SSPP1, 82, 5 },
-       { DBGBUS_SSPP1, 82, 6 },
-       { DBGBUS_SSPP1, 82, 7 },
-
-       { DBGBUS_SSPP1, 83, 0 },
-       { DBGBUS_SSPP1, 83, 1 },
-       { DBGBUS_SSPP1, 83, 2 },
-       { DBGBUS_SSPP1, 83, 3 },
-       { DBGBUS_SSPP1, 83, 4 },
-       { DBGBUS_SSPP1, 83, 5 },
-       { DBGBUS_SSPP1, 83, 6 },
-       { DBGBUS_SSPP1, 83, 7 },
-
-       { DBGBUS_SSPP1, 84, 0 },
-       { DBGBUS_SSPP1, 84, 1 },
-       { DBGBUS_SSPP1, 84, 2 },
-       { DBGBUS_SSPP1, 84, 3 },
-       { DBGBUS_SSPP1, 84, 4 },
-       { DBGBUS_SSPP1, 84, 5 },
-       { DBGBUS_SSPP1, 84, 6 },
-       { DBGBUS_SSPP1, 84, 7 },
-
-       /* dspp */
-       { DBGBUS_DSPP, 13, 0 },
-       { DBGBUS_DSPP, 19, 0 },
-       { DBGBUS_DSPP, 14, 0 },
-       { DBGBUS_DSPP, 14, 1 },
-       { DBGBUS_DSPP, 14, 3 },
-       { DBGBUS_DSPP, 20, 0 },
-       { DBGBUS_DSPP, 20, 1 },
-       { DBGBUS_DSPP, 20, 3 },
-
-       /* ppb_0 */
-       { DBGBUS_DSPP, 31, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 33, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 35, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 42, 0, _dpu_debug_bus_ppb0_dump },
-
-       /* ppb_1 */
-       { DBGBUS_DSPP, 32, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 34, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 36, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 43, 0, _dpu_debug_bus_ppb1_dump },
-
-       /* lm_lut */
-       { DBGBUS_DSPP, 109, 0 },
-       { DBGBUS_DSPP, 105, 0 },
-       { DBGBUS_DSPP, 103, 0 },
-
-       /* tear-check */
-       { DBGBUS_PERIPH, 63, 0 },
-       { DBGBUS_PERIPH, 64, 0 },
-       { DBGBUS_PERIPH, 65, 0 },
-       { DBGBUS_PERIPH, 73, 0 },
-       { DBGBUS_PERIPH, 74, 0 },
-
-       /* crossbar */
-       { DBGBUS_DSPP, 0, 0, _dpu_debug_bus_xbar_dump },
-
-       /* rotator */
-       { DBGBUS_DSPP, 9, 0},
-
-       /* blend */
-       /* LM0 */
-       { DBGBUS_DSPP, 63, 0},
-       { DBGBUS_DSPP, 63, 1},
-       { DBGBUS_DSPP, 63, 2},
-       { DBGBUS_DSPP, 63, 3},
-       { DBGBUS_DSPP, 63, 4},
-       { DBGBUS_DSPP, 63, 5},
-       { DBGBUS_DSPP, 63, 6},
-       { DBGBUS_DSPP, 63, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 64, 0},
-       { DBGBUS_DSPP, 64, 1},
-       { DBGBUS_DSPP, 64, 2},
-       { DBGBUS_DSPP, 64, 3},
-       { DBGBUS_DSPP, 64, 4},
-       { DBGBUS_DSPP, 64, 5},
-       { DBGBUS_DSPP, 64, 6},
-       { DBGBUS_DSPP, 64, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 65, 0},
-       { DBGBUS_DSPP, 65, 1},
-       { DBGBUS_DSPP, 65, 2},
-       { DBGBUS_DSPP, 65, 3},
-       { DBGBUS_DSPP, 65, 4},
-       { DBGBUS_DSPP, 65, 5},
-       { DBGBUS_DSPP, 65, 6},
-       { DBGBUS_DSPP, 65, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 66, 0},
-       { DBGBUS_DSPP, 66, 1},
-       { DBGBUS_DSPP, 66, 2},
-       { DBGBUS_DSPP, 66, 3},
-       { DBGBUS_DSPP, 66, 4},
-       { DBGBUS_DSPP, 66, 5},
-       { DBGBUS_DSPP, 66, 6},
-       { DBGBUS_DSPP, 66, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 67, 0},
-       { DBGBUS_DSPP, 67, 1},
-       { DBGBUS_DSPP, 67, 2},
-       { DBGBUS_DSPP, 67, 3},
-       { DBGBUS_DSPP, 67, 4},
-       { DBGBUS_DSPP, 67, 5},
-       { DBGBUS_DSPP, 67, 6},
-       { DBGBUS_DSPP, 67, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 68, 0},
-       { DBGBUS_DSPP, 68, 1},
-       { DBGBUS_DSPP, 68, 2},
-       { DBGBUS_DSPP, 68, 3},
-       { DBGBUS_DSPP, 68, 4},
-       { DBGBUS_DSPP, 68, 5},
-       { DBGBUS_DSPP, 68, 6},
-       { DBGBUS_DSPP, 68, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 69, 0},
-       { DBGBUS_DSPP, 69, 1},
-       { DBGBUS_DSPP, 69, 2},
-       { DBGBUS_DSPP, 69, 3},
-       { DBGBUS_DSPP, 69, 4},
-       { DBGBUS_DSPP, 69, 5},
-       { DBGBUS_DSPP, 69, 6},
-       { DBGBUS_DSPP, 69, 7, _dpu_debug_bus_lm_dump },
-
-       /* LM1 */
-       { DBGBUS_DSPP, 70, 0},
-       { DBGBUS_DSPP, 70, 1},
-       { DBGBUS_DSPP, 70, 2},
-       { DBGBUS_DSPP, 70, 3},
-       { DBGBUS_DSPP, 70, 4},
-       { DBGBUS_DSPP, 70, 5},
-       { DBGBUS_DSPP, 70, 6},
-       { DBGBUS_DSPP, 70, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 71, 0},
-       { DBGBUS_DSPP, 71, 1},
-       { DBGBUS_DSPP, 71, 2},
-       { DBGBUS_DSPP, 71, 3},
-       { DBGBUS_DSPP, 71, 4},
-       { DBGBUS_DSPP, 71, 5},
-       { DBGBUS_DSPP, 71, 6},
-       { DBGBUS_DSPP, 71, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 72, 0},
-       { DBGBUS_DSPP, 72, 1},
-       { DBGBUS_DSPP, 72, 2},
-       { DBGBUS_DSPP, 72, 3},
-       { DBGBUS_DSPP, 72, 4},
-       { DBGBUS_DSPP, 72, 5},
-       { DBGBUS_DSPP, 72, 6},
-       { DBGBUS_DSPP, 72, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 73, 0},
-       { DBGBUS_DSPP, 73, 1},
-       { DBGBUS_DSPP, 73, 2},
-       { DBGBUS_DSPP, 73, 3},
-       { DBGBUS_DSPP, 73, 4},
-       { DBGBUS_DSPP, 73, 5},
-       { DBGBUS_DSPP, 73, 6},
-       { DBGBUS_DSPP, 73, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 74, 0},
-       { DBGBUS_DSPP, 74, 1},
-       { DBGBUS_DSPP, 74, 2},
-       { DBGBUS_DSPP, 74, 3},
-       { DBGBUS_DSPP, 74, 4},
-       { DBGBUS_DSPP, 74, 5},
-       { DBGBUS_DSPP, 74, 6},
-       { DBGBUS_DSPP, 74, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 75, 0},
-       { DBGBUS_DSPP, 75, 1},
-       { DBGBUS_DSPP, 75, 2},
-       { DBGBUS_DSPP, 75, 3},
-       { DBGBUS_DSPP, 75, 4},
-       { DBGBUS_DSPP, 75, 5},
-       { DBGBUS_DSPP, 75, 6},
-       { DBGBUS_DSPP, 75, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 76, 0},
-       { DBGBUS_DSPP, 76, 1},
-       { DBGBUS_DSPP, 76, 2},
-       { DBGBUS_DSPP, 76, 3},
-       { DBGBUS_DSPP, 76, 4},
-       { DBGBUS_DSPP, 76, 5},
-       { DBGBUS_DSPP, 76, 6},
-       { DBGBUS_DSPP, 76, 7, _dpu_debug_bus_lm_dump },
-
-       /* LM2 */
-       { DBGBUS_DSPP, 77, 0},
-       { DBGBUS_DSPP, 77, 1},
-       { DBGBUS_DSPP, 77, 2},
-       { DBGBUS_DSPP, 77, 3},
-       { DBGBUS_DSPP, 77, 4},
-       { DBGBUS_DSPP, 77, 5},
-       { DBGBUS_DSPP, 77, 6},
-       { DBGBUS_DSPP, 77, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 78, 0},
-       { DBGBUS_DSPP, 78, 1},
-       { DBGBUS_DSPP, 78, 2},
-       { DBGBUS_DSPP, 78, 3},
-       { DBGBUS_DSPP, 78, 4},
-       { DBGBUS_DSPP, 78, 5},
-       { DBGBUS_DSPP, 78, 6},
-       { DBGBUS_DSPP, 78, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 79, 0},
-       { DBGBUS_DSPP, 79, 1},
-       { DBGBUS_DSPP, 79, 2},
-       { DBGBUS_DSPP, 79, 3},
-       { DBGBUS_DSPP, 79, 4},
-       { DBGBUS_DSPP, 79, 5},
-       { DBGBUS_DSPP, 79, 6},
-       { DBGBUS_DSPP, 79, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 80, 0},
-       { DBGBUS_DSPP, 80, 1},
-       { DBGBUS_DSPP, 80, 2},
-       { DBGBUS_DSPP, 80, 3},
-       { DBGBUS_DSPP, 80, 4},
-       { DBGBUS_DSPP, 80, 5},
-       { DBGBUS_DSPP, 80, 6},
-       { DBGBUS_DSPP, 80, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 81, 0},
-       { DBGBUS_DSPP, 81, 1},
-       { DBGBUS_DSPP, 81, 2},
-       { DBGBUS_DSPP, 81, 3},
-       { DBGBUS_DSPP, 81, 4},
-       { DBGBUS_DSPP, 81, 5},
-       { DBGBUS_DSPP, 81, 6},
-       { DBGBUS_DSPP, 81, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 82, 0},
-       { DBGBUS_DSPP, 82, 1},
-       { DBGBUS_DSPP, 82, 2},
-       { DBGBUS_DSPP, 82, 3},
-       { DBGBUS_DSPP, 82, 4},
-       { DBGBUS_DSPP, 82, 5},
-       { DBGBUS_DSPP, 82, 6},
-       { DBGBUS_DSPP, 82, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 83, 0},
-       { DBGBUS_DSPP, 83, 1},
-       { DBGBUS_DSPP, 83, 2},
-       { DBGBUS_DSPP, 83, 3},
-       { DBGBUS_DSPP, 83, 4},
-       { DBGBUS_DSPP, 83, 5},
-       { DBGBUS_DSPP, 83, 6},
-       { DBGBUS_DSPP, 83, 7, _dpu_debug_bus_lm_dump },
-
-       /* csc */
-       { DBGBUS_SSPP0, 7, 0},
-       { DBGBUS_SSPP0, 7, 1},
-       { DBGBUS_SSPP0, 27, 0},
-       { DBGBUS_SSPP0, 27, 1},
-       { DBGBUS_SSPP1, 7, 0},
-       { DBGBUS_SSPP1, 7, 1},
-       { DBGBUS_SSPP1, 27, 0},
-       { DBGBUS_SSPP1, 27, 1},
-
-       /* pcc */
-       { DBGBUS_SSPP0, 3,  3},
-       { DBGBUS_SSPP0, 23, 3},
-       { DBGBUS_SSPP0, 33, 3},
-       { DBGBUS_SSPP0, 43, 3},
-       { DBGBUS_SSPP1, 3,  3},
-       { DBGBUS_SSPP1, 23, 3},
-       { DBGBUS_SSPP1, 33, 3},
-       { DBGBUS_SSPP1, 43, 3},
-
-       /* spa */
-       { DBGBUS_SSPP0, 8,  0},
-       { DBGBUS_SSPP0, 28, 0},
-       { DBGBUS_SSPP1, 8,  0},
-       { DBGBUS_SSPP1, 28, 0},
-       { DBGBUS_DSPP, 13, 0},
-       { DBGBUS_DSPP, 19, 0},
-
-       /* igc */
-       { DBGBUS_SSPP0, 9,  0},
-       { DBGBUS_SSPP0, 9,  1},
-       { DBGBUS_SSPP0, 9,  3},
-       { DBGBUS_SSPP0, 29, 0},
-       { DBGBUS_SSPP0, 29, 1},
-       { DBGBUS_SSPP0, 29, 3},
-       { DBGBUS_SSPP0, 17, 0},
-       { DBGBUS_SSPP0, 17, 1},
-       { DBGBUS_SSPP0, 17, 3},
-       { DBGBUS_SSPP0, 37, 0},
-       { DBGBUS_SSPP0, 37, 1},
-       { DBGBUS_SSPP0, 37, 3},
-       { DBGBUS_SSPP0, 46, 0},
-       { DBGBUS_SSPP0, 46, 1},
-       { DBGBUS_SSPP0, 46, 3},
-
-       { DBGBUS_SSPP1, 9,  0},
-       { DBGBUS_SSPP1, 9,  1},
-       { DBGBUS_SSPP1, 9,  3},
-       { DBGBUS_SSPP1, 29, 0},
-       { DBGBUS_SSPP1, 29, 1},
-       { DBGBUS_SSPP1, 29, 3},
-       { DBGBUS_SSPP1, 17, 0},
-       { DBGBUS_SSPP1, 17, 1},
-       { DBGBUS_SSPP1, 17, 3},
-       { DBGBUS_SSPP1, 37, 0},
-       { DBGBUS_SSPP1, 37, 1},
-       { DBGBUS_SSPP1, 37, 3},
-       { DBGBUS_SSPP1, 46, 0},
-       { DBGBUS_SSPP1, 46, 1},
-       { DBGBUS_SSPP1, 46, 3},
-
-       { DBGBUS_DSPP, 14, 0},
-       { DBGBUS_DSPP, 14, 1},
-       { DBGBUS_DSPP, 14, 3},
-       { DBGBUS_DSPP, 20, 0},
-       { DBGBUS_DSPP, 20, 1},
-       { DBGBUS_DSPP, 20, 3},
-
-       { DBGBUS_PERIPH, 60, 0},
-};
-
-static struct dpu_debug_bus_entry dbg_bus_dpu_sdm845[] = {
-
-       /* Unpack 0 sspp 0*/
-       { DBGBUS_SSPP0, 50, 2 },
-       { DBGBUS_SSPP0, 60, 2 },
-       { DBGBUS_SSPP0, 70, 2 },
-
-       /* Upack 0 sspp 1*/
-       { DBGBUS_SSPP1, 50, 2 },
-       { DBGBUS_SSPP1, 60, 2 },
-       { DBGBUS_SSPP1, 70, 2 },
-
-       /* scheduler */
-       { DBGBUS_DSPP, 130, 0 },
-       { DBGBUS_DSPP, 130, 1 },
-       { DBGBUS_DSPP, 130, 2 },
-       { DBGBUS_DSPP, 130, 3 },
-       { DBGBUS_DSPP, 130, 4 },
-       { DBGBUS_DSPP, 130, 5 },
-
-       /* qseed */
-       { DBGBUS_SSPP0, 6, 0},
-       { DBGBUS_SSPP0, 6, 1},
-       { DBGBUS_SSPP0, 26, 0},
-       { DBGBUS_SSPP0, 26, 1},
-       { DBGBUS_SSPP1, 6, 0},
-       { DBGBUS_SSPP1, 6, 1},
-       { DBGBUS_SSPP1, 26, 0},
-       { DBGBUS_SSPP1, 26, 1},
-
-       /* scale */
-       { DBGBUS_SSPP0, 16, 0},
-       { DBGBUS_SSPP0, 16, 1},
-       { DBGBUS_SSPP0, 36, 0},
-       { DBGBUS_SSPP0, 36, 1},
-       { DBGBUS_SSPP1, 16, 0},
-       { DBGBUS_SSPP1, 16, 1},
-       { DBGBUS_SSPP1, 36, 0},
-       { DBGBUS_SSPP1, 36, 1},
-
-       /* fetch sspp0 */
-
-       /* vig 0 */
-       { DBGBUS_SSPP0, 0, 0 },
-       { DBGBUS_SSPP0, 0, 1 },
-       { DBGBUS_SSPP0, 0, 2 },
-       { DBGBUS_SSPP0, 0, 3 },
-       { DBGBUS_SSPP0, 0, 4 },
-       { DBGBUS_SSPP0, 0, 5 },
-       { DBGBUS_SSPP0, 0, 6 },
-       { DBGBUS_SSPP0, 0, 7 },
-
-       { DBGBUS_SSPP0, 1, 0 },
-       { DBGBUS_SSPP0, 1, 1 },
-       { DBGBUS_SSPP0, 1, 2 },
-       { DBGBUS_SSPP0, 1, 3 },
-       { DBGBUS_SSPP0, 1, 4 },
-       { DBGBUS_SSPP0, 1, 5 },
-       { DBGBUS_SSPP0, 1, 6 },
-       { DBGBUS_SSPP0, 1, 7 },
-
-       { DBGBUS_SSPP0, 2, 0 },
-       { DBGBUS_SSPP0, 2, 1 },
-       { DBGBUS_SSPP0, 2, 2 },
-       { DBGBUS_SSPP0, 2, 3 },
-       { DBGBUS_SSPP0, 2, 4 },
-       { DBGBUS_SSPP0, 2, 5 },
-       { DBGBUS_SSPP0, 2, 6 },
-       { DBGBUS_SSPP0, 2, 7 },
-
-       { DBGBUS_SSPP0, 4, 0 },
-       { DBGBUS_SSPP0, 4, 1 },
-       { DBGBUS_SSPP0, 4, 2 },
-       { DBGBUS_SSPP0, 4, 3 },
-       { DBGBUS_SSPP0, 4, 4 },
-       { DBGBUS_SSPP0, 4, 5 },
-       { DBGBUS_SSPP0, 4, 6 },
-       { DBGBUS_SSPP0, 4, 7 },
-
-       { DBGBUS_SSPP0, 5, 0 },
-       { DBGBUS_SSPP0, 5, 1 },
-       { DBGBUS_SSPP0, 5, 2 },
-       { DBGBUS_SSPP0, 5, 3 },
-       { DBGBUS_SSPP0, 5, 4 },
-       { DBGBUS_SSPP0, 5, 5 },
-       { DBGBUS_SSPP0, 5, 6 },
-       { DBGBUS_SSPP0, 5, 7 },
-
-       /* vig 2 */
-       { DBGBUS_SSPP0, 20, 0 },
-       { DBGBUS_SSPP0, 20, 1 },
-       { DBGBUS_SSPP0, 20, 2 },
-       { DBGBUS_SSPP0, 20, 3 },
-       { DBGBUS_SSPP0, 20, 4 },
-       { DBGBUS_SSPP0, 20, 5 },
-       { DBGBUS_SSPP0, 20, 6 },
-       { DBGBUS_SSPP0, 20, 7 },
-
-       { DBGBUS_SSPP0, 21, 0 },
-       { DBGBUS_SSPP0, 21, 1 },
-       { DBGBUS_SSPP0, 21, 2 },
-       { DBGBUS_SSPP0, 21, 3 },
-       { DBGBUS_SSPP0, 21, 4 },
-       { DBGBUS_SSPP0, 21, 5 },
-       { DBGBUS_SSPP0, 21, 6 },
-       { DBGBUS_SSPP0, 21, 7 },
-
-       { DBGBUS_SSPP0, 22, 0 },
-       { DBGBUS_SSPP0, 22, 1 },
-       { DBGBUS_SSPP0, 22, 2 },
-       { DBGBUS_SSPP0, 22, 3 },
-       { DBGBUS_SSPP0, 22, 4 },
-       { DBGBUS_SSPP0, 22, 5 },
-       { DBGBUS_SSPP0, 22, 6 },
-       { DBGBUS_SSPP0, 22, 7 },
-
-       { DBGBUS_SSPP0, 24, 0 },
-       { DBGBUS_SSPP0, 24, 1 },
-       { DBGBUS_SSPP0, 24, 2 },
-       { DBGBUS_SSPP0, 24, 3 },
-       { DBGBUS_SSPP0, 24, 4 },
-       { DBGBUS_SSPP0, 24, 5 },
-       { DBGBUS_SSPP0, 24, 6 },
-       { DBGBUS_SSPP0, 24, 7 },
-
-       { DBGBUS_SSPP0, 25, 0 },
-       { DBGBUS_SSPP0, 25, 1 },
-       { DBGBUS_SSPP0, 25, 2 },
-       { DBGBUS_SSPP0, 25, 3 },
-       { DBGBUS_SSPP0, 25, 4 },
-       { DBGBUS_SSPP0, 25, 5 },
-       { DBGBUS_SSPP0, 25, 6 },
-       { DBGBUS_SSPP0, 25, 7 },
-
-       /* dma 2 */
-       { DBGBUS_SSPP0, 30, 0 },
-       { DBGBUS_SSPP0, 30, 1 },
-       { DBGBUS_SSPP0, 30, 2 },
-       { DBGBUS_SSPP0, 30, 3 },
-       { DBGBUS_SSPP0, 30, 4 },
-       { DBGBUS_SSPP0, 30, 5 },
-       { DBGBUS_SSPP0, 30, 6 },
-       { DBGBUS_SSPP0, 30, 7 },
-
-       { DBGBUS_SSPP0, 31, 0 },
-       { DBGBUS_SSPP0, 31, 1 },
-       { DBGBUS_SSPP0, 31, 2 },
-       { DBGBUS_SSPP0, 31, 3 },
-       { DBGBUS_SSPP0, 31, 4 },
-       { DBGBUS_SSPP0, 31, 5 },
-       { DBGBUS_SSPP0, 31, 6 },
-       { DBGBUS_SSPP0, 31, 7 },
-
-       { DBGBUS_SSPP0, 32, 0 },
-       { DBGBUS_SSPP0, 32, 1 },
-       { DBGBUS_SSPP0, 32, 2 },
-       { DBGBUS_SSPP0, 32, 3 },
-       { DBGBUS_SSPP0, 32, 4 },
-       { DBGBUS_SSPP0, 32, 5 },
-       { DBGBUS_SSPP0, 32, 6 },
-       { DBGBUS_SSPP0, 32, 7 },
-
-       { DBGBUS_SSPP0, 33, 0 },
-       { DBGBUS_SSPP0, 33, 1 },
-       { DBGBUS_SSPP0, 33, 2 },
-       { DBGBUS_SSPP0, 33, 3 },
-       { DBGBUS_SSPP0, 33, 4 },
-       { DBGBUS_SSPP0, 33, 5 },
-       { DBGBUS_SSPP0, 33, 6 },
-       { DBGBUS_SSPP0, 33, 7 },
-
-       { DBGBUS_SSPP0, 34, 0 },
-       { DBGBUS_SSPP0, 34, 1 },
-       { DBGBUS_SSPP0, 34, 2 },
-       { DBGBUS_SSPP0, 34, 3 },
-       { DBGBUS_SSPP0, 34, 4 },
-       { DBGBUS_SSPP0, 34, 5 },
-       { DBGBUS_SSPP0, 34, 6 },
-       { DBGBUS_SSPP0, 34, 7 },
-
-       { DBGBUS_SSPP0, 35, 0 },
-       { DBGBUS_SSPP0, 35, 1 },
-       { DBGBUS_SSPP0, 35, 2 },
-       { DBGBUS_SSPP0, 35, 3 },
-
-       /* dma 0 */
-       { DBGBUS_SSPP0, 40, 0 },
-       { DBGBUS_SSPP0, 40, 1 },
-       { DBGBUS_SSPP0, 40, 2 },
-       { DBGBUS_SSPP0, 40, 3 },
-       { DBGBUS_SSPP0, 40, 4 },
-       { DBGBUS_SSPP0, 40, 5 },
-       { DBGBUS_SSPP0, 40, 6 },
-       { DBGBUS_SSPP0, 40, 7 },
-
-       { DBGBUS_SSPP0, 41, 0 },
-       { DBGBUS_SSPP0, 41, 1 },
-       { DBGBUS_SSPP0, 41, 2 },
-       { DBGBUS_SSPP0, 41, 3 },
-       { DBGBUS_SSPP0, 41, 4 },
-       { DBGBUS_SSPP0, 41, 5 },
-       { DBGBUS_SSPP0, 41, 6 },
-       { DBGBUS_SSPP0, 41, 7 },
-
-       { DBGBUS_SSPP0, 42, 0 },
-       { DBGBUS_SSPP0, 42, 1 },
-       { DBGBUS_SSPP0, 42, 2 },
-       { DBGBUS_SSPP0, 42, 3 },
-       { DBGBUS_SSPP0, 42, 4 },
-       { DBGBUS_SSPP0, 42, 5 },
-       { DBGBUS_SSPP0, 42, 6 },
-       { DBGBUS_SSPP0, 42, 7 },
-
-       { DBGBUS_SSPP0, 44, 0 },
-       { DBGBUS_SSPP0, 44, 1 },
-       { DBGBUS_SSPP0, 44, 2 },
-       { DBGBUS_SSPP0, 44, 3 },
-       { DBGBUS_SSPP0, 44, 4 },
-       { DBGBUS_SSPP0, 44, 5 },
-       { DBGBUS_SSPP0, 44, 6 },
-       { DBGBUS_SSPP0, 44, 7 },
-
-       { DBGBUS_SSPP0, 45, 0 },
-       { DBGBUS_SSPP0, 45, 1 },
-       { DBGBUS_SSPP0, 45, 2 },
-       { DBGBUS_SSPP0, 45, 3 },
-       { DBGBUS_SSPP0, 45, 4 },
-       { DBGBUS_SSPP0, 45, 5 },
-       { DBGBUS_SSPP0, 45, 6 },
-       { DBGBUS_SSPP0, 45, 7 },
-
-       /* fetch sspp1 */
-       /* vig 1 */
-       { DBGBUS_SSPP1, 0, 0 },
-       { DBGBUS_SSPP1, 0, 1 },
-       { DBGBUS_SSPP1, 0, 2 },
-       { DBGBUS_SSPP1, 0, 3 },
-       { DBGBUS_SSPP1, 0, 4 },
-       { DBGBUS_SSPP1, 0, 5 },
-       { DBGBUS_SSPP1, 0, 6 },
-       { DBGBUS_SSPP1, 0, 7 },
-
-       { DBGBUS_SSPP1, 1, 0 },
-       { DBGBUS_SSPP1, 1, 1 },
-       { DBGBUS_SSPP1, 1, 2 },
-       { DBGBUS_SSPP1, 1, 3 },
-       { DBGBUS_SSPP1, 1, 4 },
-       { DBGBUS_SSPP1, 1, 5 },
-       { DBGBUS_SSPP1, 1, 6 },
-       { DBGBUS_SSPP1, 1, 7 },
-
-       { DBGBUS_SSPP1, 2, 0 },
-       { DBGBUS_SSPP1, 2, 1 },
-       { DBGBUS_SSPP1, 2, 2 },
-       { DBGBUS_SSPP1, 2, 3 },
-       { DBGBUS_SSPP1, 2, 4 },
-       { DBGBUS_SSPP1, 2, 5 },
-       { DBGBUS_SSPP1, 2, 6 },
-       { DBGBUS_SSPP1, 2, 7 },
-
-       { DBGBUS_SSPP1, 4, 0 },
-       { DBGBUS_SSPP1, 4, 1 },
-       { DBGBUS_SSPP1, 4, 2 },
-       { DBGBUS_SSPP1, 4, 3 },
-       { DBGBUS_SSPP1, 4, 4 },
-       { DBGBUS_SSPP1, 4, 5 },
-       { DBGBUS_SSPP1, 4, 6 },
-       { DBGBUS_SSPP1, 4, 7 },
-
-       { DBGBUS_SSPP1, 5, 0 },
-       { DBGBUS_SSPP1, 5, 1 },
-       { DBGBUS_SSPP1, 5, 2 },
-       { DBGBUS_SSPP1, 5, 3 },
-       { DBGBUS_SSPP1, 5, 4 },
-       { DBGBUS_SSPP1, 5, 5 },
-       { DBGBUS_SSPP1, 5, 6 },
-       { DBGBUS_SSPP1, 5, 7 },
-
-       /* vig 3 */
-       { DBGBUS_SSPP1, 20, 0 },
-       { DBGBUS_SSPP1, 20, 1 },
-       { DBGBUS_SSPP1, 20, 2 },
-       { DBGBUS_SSPP1, 20, 3 },
-       { DBGBUS_SSPP1, 20, 4 },
-       { DBGBUS_SSPP1, 20, 5 },
-       { DBGBUS_SSPP1, 20, 6 },
-       { DBGBUS_SSPP1, 20, 7 },
-
-       { DBGBUS_SSPP1, 21, 0 },
-       { DBGBUS_SSPP1, 21, 1 },
-       { DBGBUS_SSPP1, 21, 2 },
-       { DBGBUS_SSPP1, 21, 3 },
-       { DBGBUS_SSPP1, 21, 4 },
-       { DBGBUS_SSPP1, 21, 5 },
-       { DBGBUS_SSPP1, 21, 6 },
-       { DBGBUS_SSPP1, 21, 7 },
-
-       { DBGBUS_SSPP1, 22, 0 },
-       { DBGBUS_SSPP1, 22, 1 },
-       { DBGBUS_SSPP1, 22, 2 },
-       { DBGBUS_SSPP1, 22, 3 },
-       { DBGBUS_SSPP1, 22, 4 },
-       { DBGBUS_SSPP1, 22, 5 },
-       { DBGBUS_SSPP1, 22, 6 },
-       { DBGBUS_SSPP1, 22, 7 },
-
-       { DBGBUS_SSPP1, 24, 0 },
-       { DBGBUS_SSPP1, 24, 1 },
-       { DBGBUS_SSPP1, 24, 2 },
-       { DBGBUS_SSPP1, 24, 3 },
-       { DBGBUS_SSPP1, 24, 4 },
-       { DBGBUS_SSPP1, 24, 5 },
-       { DBGBUS_SSPP1, 24, 6 },
-       { DBGBUS_SSPP1, 24, 7 },
-
-       { DBGBUS_SSPP1, 25, 0 },
-       { DBGBUS_SSPP1, 25, 1 },
-       { DBGBUS_SSPP1, 25, 2 },
-       { DBGBUS_SSPP1, 25, 3 },
-       { DBGBUS_SSPP1, 25, 4 },
-       { DBGBUS_SSPP1, 25, 5 },
-       { DBGBUS_SSPP1, 25, 6 },
-       { DBGBUS_SSPP1, 25, 7 },
-
-       /* dma 3 */
-       { DBGBUS_SSPP1, 30, 0 },
-       { DBGBUS_SSPP1, 30, 1 },
-       { DBGBUS_SSPP1, 30, 2 },
-       { DBGBUS_SSPP1, 30, 3 },
-       { DBGBUS_SSPP1, 30, 4 },
-       { DBGBUS_SSPP1, 30, 5 },
-       { DBGBUS_SSPP1, 30, 6 },
-       { DBGBUS_SSPP1, 30, 7 },
-
-       { DBGBUS_SSPP1, 31, 0 },
-       { DBGBUS_SSPP1, 31, 1 },
-       { DBGBUS_SSPP1, 31, 2 },
-       { DBGBUS_SSPP1, 31, 3 },
-       { DBGBUS_SSPP1, 31, 4 },
-       { DBGBUS_SSPP1, 31, 5 },
-       { DBGBUS_SSPP1, 31, 6 },
-       { DBGBUS_SSPP1, 31, 7 },
-
-       { DBGBUS_SSPP1, 32, 0 },
-       { DBGBUS_SSPP1, 32, 1 },
-       { DBGBUS_SSPP1, 32, 2 },
-       { DBGBUS_SSPP1, 32, 3 },
-       { DBGBUS_SSPP1, 32, 4 },
-       { DBGBUS_SSPP1, 32, 5 },
-       { DBGBUS_SSPP1, 32, 6 },
-       { DBGBUS_SSPP1, 32, 7 },
-
-       { DBGBUS_SSPP1, 33, 0 },
-       { DBGBUS_SSPP1, 33, 1 },
-       { DBGBUS_SSPP1, 33, 2 },
-       { DBGBUS_SSPP1, 33, 3 },
-       { DBGBUS_SSPP1, 33, 4 },
-       { DBGBUS_SSPP1, 33, 5 },
-       { DBGBUS_SSPP1, 33, 6 },
-       { DBGBUS_SSPP1, 33, 7 },
-
-       { DBGBUS_SSPP1, 34, 0 },
-       { DBGBUS_SSPP1, 34, 1 },
-       { DBGBUS_SSPP1, 34, 2 },
-       { DBGBUS_SSPP1, 34, 3 },
-       { DBGBUS_SSPP1, 34, 4 },
-       { DBGBUS_SSPP1, 34, 5 },
-       { DBGBUS_SSPP1, 34, 6 },
-       { DBGBUS_SSPP1, 34, 7 },
-
-       { DBGBUS_SSPP1, 35, 0 },
-       { DBGBUS_SSPP1, 35, 1 },
-       { DBGBUS_SSPP1, 35, 2 },
-
-       /* dma 1 */
-       { DBGBUS_SSPP1, 40, 0 },
-       { DBGBUS_SSPP1, 40, 1 },
-       { DBGBUS_SSPP1, 40, 2 },
-       { DBGBUS_SSPP1, 40, 3 },
-       { DBGBUS_SSPP1, 40, 4 },
-       { DBGBUS_SSPP1, 40, 5 },
-       { DBGBUS_SSPP1, 40, 6 },
-       { DBGBUS_SSPP1, 40, 7 },
-
-       { DBGBUS_SSPP1, 41, 0 },
-       { DBGBUS_SSPP1, 41, 1 },
-       { DBGBUS_SSPP1, 41, 2 },
-       { DBGBUS_SSPP1, 41, 3 },
-       { DBGBUS_SSPP1, 41, 4 },
-       { DBGBUS_SSPP1, 41, 5 },
-       { DBGBUS_SSPP1, 41, 6 },
-       { DBGBUS_SSPP1, 41, 7 },
-
-       { DBGBUS_SSPP1, 42, 0 },
-       { DBGBUS_SSPP1, 42, 1 },
-       { DBGBUS_SSPP1, 42, 2 },
-       { DBGBUS_SSPP1, 42, 3 },
-       { DBGBUS_SSPP1, 42, 4 },
-       { DBGBUS_SSPP1, 42, 5 },
-       { DBGBUS_SSPP1, 42, 6 },
-       { DBGBUS_SSPP1, 42, 7 },
-
-       { DBGBUS_SSPP1, 44, 0 },
-       { DBGBUS_SSPP1, 44, 1 },
-       { DBGBUS_SSPP1, 44, 2 },
-       { DBGBUS_SSPP1, 44, 3 },
-       { DBGBUS_SSPP1, 44, 4 },
-       { DBGBUS_SSPP1, 44, 5 },
-       { DBGBUS_SSPP1, 44, 6 },
-       { DBGBUS_SSPP1, 44, 7 },
-
-       { DBGBUS_SSPP1, 45, 0 },
-       { DBGBUS_SSPP1, 45, 1 },
-       { DBGBUS_SSPP1, 45, 2 },
-       { DBGBUS_SSPP1, 45, 3 },
-       { DBGBUS_SSPP1, 45, 4 },
-       { DBGBUS_SSPP1, 45, 5 },
-       { DBGBUS_SSPP1, 45, 6 },
-       { DBGBUS_SSPP1, 45, 7 },
-
-       /* dspp */
-       { DBGBUS_DSPP, 13, 0 },
-       { DBGBUS_DSPP, 19, 0 },
-       { DBGBUS_DSPP, 14, 0 },
-       { DBGBUS_DSPP, 14, 1 },
-       { DBGBUS_DSPP, 14, 3 },
-       { DBGBUS_DSPP, 20, 0 },
-       { DBGBUS_DSPP, 20, 1 },
-       { DBGBUS_DSPP, 20, 3 },
-
-       /* ppb_0 */
-       { DBGBUS_DSPP, 31, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 33, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 35, 0, _dpu_debug_bus_ppb0_dump },
-       { DBGBUS_DSPP, 42, 0, _dpu_debug_bus_ppb0_dump },
-
-       /* ppb_1 */
-       { DBGBUS_DSPP, 32, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 34, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 36, 0, _dpu_debug_bus_ppb1_dump },
-       { DBGBUS_DSPP, 43, 0, _dpu_debug_bus_ppb1_dump },
-
-       /* lm_lut */
-       { DBGBUS_DSPP, 109, 0 },
-       { DBGBUS_DSPP, 105, 0 },
-       { DBGBUS_DSPP, 103, 0 },
-
-       /* crossbar */
-       { DBGBUS_DSPP, 0, 0, _dpu_debug_bus_xbar_dump },
-
-       /* rotator */
-       { DBGBUS_DSPP, 9, 0},
-
-       /* blend */
-       /* LM0 */
-       { DBGBUS_DSPP, 63, 1},
-       { DBGBUS_DSPP, 63, 2},
-       { DBGBUS_DSPP, 63, 3},
-       { DBGBUS_DSPP, 63, 4},
-       { DBGBUS_DSPP, 63, 5},
-       { DBGBUS_DSPP, 63, 6},
-       { DBGBUS_DSPP, 63, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 64, 1},
-       { DBGBUS_DSPP, 64, 2},
-       { DBGBUS_DSPP, 64, 3},
-       { DBGBUS_DSPP, 64, 4},
-       { DBGBUS_DSPP, 64, 5},
-       { DBGBUS_DSPP, 64, 6},
-       { DBGBUS_DSPP, 64, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 65, 1},
-       { DBGBUS_DSPP, 65, 2},
-       { DBGBUS_DSPP, 65, 3},
-       { DBGBUS_DSPP, 65, 4},
-       { DBGBUS_DSPP, 65, 5},
-       { DBGBUS_DSPP, 65, 6},
-       { DBGBUS_DSPP, 65, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 66, 1},
-       { DBGBUS_DSPP, 66, 2},
-       { DBGBUS_DSPP, 66, 3},
-       { DBGBUS_DSPP, 66, 4},
-       { DBGBUS_DSPP, 66, 5},
-       { DBGBUS_DSPP, 66, 6},
-       { DBGBUS_DSPP, 66, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 67, 1},
-       { DBGBUS_DSPP, 67, 2},
-       { DBGBUS_DSPP, 67, 3},
-       { DBGBUS_DSPP, 67, 4},
-       { DBGBUS_DSPP, 67, 5},
-       { DBGBUS_DSPP, 67, 6},
-       { DBGBUS_DSPP, 67, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 68, 1},
-       { DBGBUS_DSPP, 68, 2},
-       { DBGBUS_DSPP, 68, 3},
-       { DBGBUS_DSPP, 68, 4},
-       { DBGBUS_DSPP, 68, 5},
-       { DBGBUS_DSPP, 68, 6},
-       { DBGBUS_DSPP, 68, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 69, 1},
-       { DBGBUS_DSPP, 69, 2},
-       { DBGBUS_DSPP, 69, 3},
-       { DBGBUS_DSPP, 69, 4},
-       { DBGBUS_DSPP, 69, 5},
-       { DBGBUS_DSPP, 69, 6},
-       { DBGBUS_DSPP, 69, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 84, 1},
-       { DBGBUS_DSPP, 84, 2},
-       { DBGBUS_DSPP, 84, 3},
-       { DBGBUS_DSPP, 84, 4},
-       { DBGBUS_DSPP, 84, 5},
-       { DBGBUS_DSPP, 84, 6},
-       { DBGBUS_DSPP, 84, 7, _dpu_debug_bus_lm_dump },
-
-
-       { DBGBUS_DSPP, 85, 1},
-       { DBGBUS_DSPP, 85, 2},
-       { DBGBUS_DSPP, 85, 3},
-       { DBGBUS_DSPP, 85, 4},
-       { DBGBUS_DSPP, 85, 5},
-       { DBGBUS_DSPP, 85, 6},
-       { DBGBUS_DSPP, 85, 7, _dpu_debug_bus_lm_dump },
-
-
-       { DBGBUS_DSPP, 86, 1},
-       { DBGBUS_DSPP, 86, 2},
-       { DBGBUS_DSPP, 86, 3},
-       { DBGBUS_DSPP, 86, 4},
-       { DBGBUS_DSPP, 86, 5},
-       { DBGBUS_DSPP, 86, 6},
-       { DBGBUS_DSPP, 86, 7, _dpu_debug_bus_lm_dump },
-
-
-       { DBGBUS_DSPP, 87, 1},
-       { DBGBUS_DSPP, 87, 2},
-       { DBGBUS_DSPP, 87, 3},
-       { DBGBUS_DSPP, 87, 4},
-       { DBGBUS_DSPP, 87, 5},
-       { DBGBUS_DSPP, 87, 6},
-       { DBGBUS_DSPP, 87, 7, _dpu_debug_bus_lm_dump },
-
-       /* LM1 */
-       { DBGBUS_DSPP, 70, 1},
-       { DBGBUS_DSPP, 70, 2},
-       { DBGBUS_DSPP, 70, 3},
-       { DBGBUS_DSPP, 70, 4},
-       { DBGBUS_DSPP, 70, 5},
-       { DBGBUS_DSPP, 70, 6},
-       { DBGBUS_DSPP, 70, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 71, 1},
-       { DBGBUS_DSPP, 71, 2},
-       { DBGBUS_DSPP, 71, 3},
-       { DBGBUS_DSPP, 71, 4},
-       { DBGBUS_DSPP, 71, 5},
-       { DBGBUS_DSPP, 71, 6},
-       { DBGBUS_DSPP, 71, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 72, 1},
-       { DBGBUS_DSPP, 72, 2},
-       { DBGBUS_DSPP, 72, 3},
-       { DBGBUS_DSPP, 72, 4},
-       { DBGBUS_DSPP, 72, 5},
-       { DBGBUS_DSPP, 72, 6},
-       { DBGBUS_DSPP, 72, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 73, 1},
-       { DBGBUS_DSPP, 73, 2},
-       { DBGBUS_DSPP, 73, 3},
-       { DBGBUS_DSPP, 73, 4},
-       { DBGBUS_DSPP, 73, 5},
-       { DBGBUS_DSPP, 73, 6},
-       { DBGBUS_DSPP, 73, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 74, 1},
-       { DBGBUS_DSPP, 74, 2},
-       { DBGBUS_DSPP, 74, 3},
-       { DBGBUS_DSPP, 74, 4},
-       { DBGBUS_DSPP, 74, 5},
-       { DBGBUS_DSPP, 74, 6},
-       { DBGBUS_DSPP, 74, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 75, 1},
-       { DBGBUS_DSPP, 75, 2},
-       { DBGBUS_DSPP, 75, 3},
-       { DBGBUS_DSPP, 75, 4},
-       { DBGBUS_DSPP, 75, 5},
-       { DBGBUS_DSPP, 75, 6},
-       { DBGBUS_DSPP, 75, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 76, 1},
-       { DBGBUS_DSPP, 76, 2},
-       { DBGBUS_DSPP, 76, 3},
-       { DBGBUS_DSPP, 76, 4},
-       { DBGBUS_DSPP, 76, 5},
-       { DBGBUS_DSPP, 76, 6},
-       { DBGBUS_DSPP, 76, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 88, 1},
-       { DBGBUS_DSPP, 88, 2},
-       { DBGBUS_DSPP, 88, 3},
-       { DBGBUS_DSPP, 88, 4},
-       { DBGBUS_DSPP, 88, 5},
-       { DBGBUS_DSPP, 88, 6},
-       { DBGBUS_DSPP, 88, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 89, 1},
-       { DBGBUS_DSPP, 89, 2},
-       { DBGBUS_DSPP, 89, 3},
-       { DBGBUS_DSPP, 89, 4},
-       { DBGBUS_DSPP, 89, 5},
-       { DBGBUS_DSPP, 89, 6},
-       { DBGBUS_DSPP, 89, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 90, 1},
-       { DBGBUS_DSPP, 90, 2},
-       { DBGBUS_DSPP, 90, 3},
-       { DBGBUS_DSPP, 90, 4},
-       { DBGBUS_DSPP, 90, 5},
-       { DBGBUS_DSPP, 90, 6},
-       { DBGBUS_DSPP, 90, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 91, 1},
-       { DBGBUS_DSPP, 91, 2},
-       { DBGBUS_DSPP, 91, 3},
-       { DBGBUS_DSPP, 91, 4},
-       { DBGBUS_DSPP, 91, 5},
-       { DBGBUS_DSPP, 91, 6},
-       { DBGBUS_DSPP, 91, 7, _dpu_debug_bus_lm_dump },
-
-       /* LM2 */
-       { DBGBUS_DSPP, 77, 0},
-       { DBGBUS_DSPP, 77, 1},
-       { DBGBUS_DSPP, 77, 2},
-       { DBGBUS_DSPP, 77, 3},
-       { DBGBUS_DSPP, 77, 4},
-       { DBGBUS_DSPP, 77, 5},
-       { DBGBUS_DSPP, 77, 6},
-       { DBGBUS_DSPP, 77, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 78, 0},
-       { DBGBUS_DSPP, 78, 1},
-       { DBGBUS_DSPP, 78, 2},
-       { DBGBUS_DSPP, 78, 3},
-       { DBGBUS_DSPP, 78, 4},
-       { DBGBUS_DSPP, 78, 5},
-       { DBGBUS_DSPP, 78, 6},
-       { DBGBUS_DSPP, 78, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 79, 0},
-       { DBGBUS_DSPP, 79, 1},
-       { DBGBUS_DSPP, 79, 2},
-       { DBGBUS_DSPP, 79, 3},
-       { DBGBUS_DSPP, 79, 4},
-       { DBGBUS_DSPP, 79, 5},
-       { DBGBUS_DSPP, 79, 6},
-       { DBGBUS_DSPP, 79, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 80, 0},
-       { DBGBUS_DSPP, 80, 1},
-       { DBGBUS_DSPP, 80, 2},
-       { DBGBUS_DSPP, 80, 3},
-       { DBGBUS_DSPP, 80, 4},
-       { DBGBUS_DSPP, 80, 5},
-       { DBGBUS_DSPP, 80, 6},
-       { DBGBUS_DSPP, 80, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 81, 0},
-       { DBGBUS_DSPP, 81, 1},
-       { DBGBUS_DSPP, 81, 2},
-       { DBGBUS_DSPP, 81, 3},
-       { DBGBUS_DSPP, 81, 4},
-       { DBGBUS_DSPP, 81, 5},
-       { DBGBUS_DSPP, 81, 6},
-       { DBGBUS_DSPP, 81, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 82, 0},
-       { DBGBUS_DSPP, 82, 1},
-       { DBGBUS_DSPP, 82, 2},
-       { DBGBUS_DSPP, 82, 3},
-       { DBGBUS_DSPP, 82, 4},
-       { DBGBUS_DSPP, 82, 5},
-       { DBGBUS_DSPP, 82, 6},
-       { DBGBUS_DSPP, 82, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 83, 0},
-       { DBGBUS_DSPP, 83, 1},
-       { DBGBUS_DSPP, 83, 2},
-       { DBGBUS_DSPP, 83, 3},
-       { DBGBUS_DSPP, 83, 4},
-       { DBGBUS_DSPP, 83, 5},
-       { DBGBUS_DSPP, 83, 6},
-       { DBGBUS_DSPP, 83, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 92, 1},
-       { DBGBUS_DSPP, 92, 2},
-       { DBGBUS_DSPP, 92, 3},
-       { DBGBUS_DSPP, 92, 4},
-       { DBGBUS_DSPP, 92, 5},
-       { DBGBUS_DSPP, 92, 6},
-       { DBGBUS_DSPP, 92, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 93, 1},
-       { DBGBUS_DSPP, 93, 2},
-       { DBGBUS_DSPP, 93, 3},
-       { DBGBUS_DSPP, 93, 4},
-       { DBGBUS_DSPP, 93, 5},
-       { DBGBUS_DSPP, 93, 6},
-       { DBGBUS_DSPP, 93, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 94, 1},
-       { DBGBUS_DSPP, 94, 2},
-       { DBGBUS_DSPP, 94, 3},
-       { DBGBUS_DSPP, 94, 4},
-       { DBGBUS_DSPP, 94, 5},
-       { DBGBUS_DSPP, 94, 6},
-       { DBGBUS_DSPP, 94, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 95, 1},
-       { DBGBUS_DSPP, 95, 2},
-       { DBGBUS_DSPP, 95, 3},
-       { DBGBUS_DSPP, 95, 4},
-       { DBGBUS_DSPP, 95, 5},
-       { DBGBUS_DSPP, 95, 6},
-       { DBGBUS_DSPP, 95, 7, _dpu_debug_bus_lm_dump },
-
-       /* LM5 */
-       { DBGBUS_DSPP, 110, 1},
-       { DBGBUS_DSPP, 110, 2},
-       { DBGBUS_DSPP, 110, 3},
-       { DBGBUS_DSPP, 110, 4},
-       { DBGBUS_DSPP, 110, 5},
-       { DBGBUS_DSPP, 110, 6},
-       { DBGBUS_DSPP, 110, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 111, 1},
-       { DBGBUS_DSPP, 111, 2},
-       { DBGBUS_DSPP, 111, 3},
-       { DBGBUS_DSPP, 111, 4},
-       { DBGBUS_DSPP, 111, 5},
-       { DBGBUS_DSPP, 111, 6},
-       { DBGBUS_DSPP, 111, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 112, 1},
-       { DBGBUS_DSPP, 112, 2},
-       { DBGBUS_DSPP, 112, 3},
-       { DBGBUS_DSPP, 112, 4},
-       { DBGBUS_DSPP, 112, 5},
-       { DBGBUS_DSPP, 112, 6},
-       { DBGBUS_DSPP, 112, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 113, 1},
-       { DBGBUS_DSPP, 113, 2},
-       { DBGBUS_DSPP, 113, 3},
-       { DBGBUS_DSPP, 113, 4},
-       { DBGBUS_DSPP, 113, 5},
-       { DBGBUS_DSPP, 113, 6},
-       { DBGBUS_DSPP, 113, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 114, 1},
-       { DBGBUS_DSPP, 114, 2},
-       { DBGBUS_DSPP, 114, 3},
-       { DBGBUS_DSPP, 114, 4},
-       { DBGBUS_DSPP, 114, 5},
-       { DBGBUS_DSPP, 114, 6},
-       { DBGBUS_DSPP, 114, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 115, 1},
-       { DBGBUS_DSPP, 115, 2},
-       { DBGBUS_DSPP, 115, 3},
-       { DBGBUS_DSPP, 115, 4},
-       { DBGBUS_DSPP, 115, 5},
-       { DBGBUS_DSPP, 115, 6},
-       { DBGBUS_DSPP, 115, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 116, 1},
-       { DBGBUS_DSPP, 116, 2},
-       { DBGBUS_DSPP, 116, 3},
-       { DBGBUS_DSPP, 116, 4},
-       { DBGBUS_DSPP, 116, 5},
-       { DBGBUS_DSPP, 116, 6},
-       { DBGBUS_DSPP, 116, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 117, 1},
-       { DBGBUS_DSPP, 117, 2},
-       { DBGBUS_DSPP, 117, 3},
-       { DBGBUS_DSPP, 117, 4},
-       { DBGBUS_DSPP, 117, 5},
-       { DBGBUS_DSPP, 117, 6},
-       { DBGBUS_DSPP, 117, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 118, 1},
-       { DBGBUS_DSPP, 118, 2},
-       { DBGBUS_DSPP, 118, 3},
-       { DBGBUS_DSPP, 118, 4},
-       { DBGBUS_DSPP, 118, 5},
-       { DBGBUS_DSPP, 118, 6},
-       { DBGBUS_DSPP, 118, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 119, 1},
-       { DBGBUS_DSPP, 119, 2},
-       { DBGBUS_DSPP, 119, 3},
-       { DBGBUS_DSPP, 119, 4},
-       { DBGBUS_DSPP, 119, 5},
-       { DBGBUS_DSPP, 119, 6},
-       { DBGBUS_DSPP, 119, 7, _dpu_debug_bus_lm_dump },
-
-       { DBGBUS_DSPP, 120, 1},
-       { DBGBUS_DSPP, 120, 2},
-       { DBGBUS_DSPP, 120, 3},
-       { DBGBUS_DSPP, 120, 4},
-       { DBGBUS_DSPP, 120, 5},
-       { DBGBUS_DSPP, 120, 6},
-       { DBGBUS_DSPP, 120, 7, _dpu_debug_bus_lm_dump },
-
-       /* csc */
-       { DBGBUS_SSPP0, 7, 0},
-       { DBGBUS_SSPP0, 7, 1},
-       { DBGBUS_SSPP0, 27, 0},
-       { DBGBUS_SSPP0, 27, 1},
-       { DBGBUS_SSPP1, 7, 0},
-       { DBGBUS_SSPP1, 7, 1},
-       { DBGBUS_SSPP1, 27, 0},
-       { DBGBUS_SSPP1, 27, 1},
-
-       /* pcc */
-       { DBGBUS_SSPP0, 3,  3},
-       { DBGBUS_SSPP0, 23, 3},
-       { DBGBUS_SSPP0, 33, 3},
-       { DBGBUS_SSPP0, 43, 3},
-       { DBGBUS_SSPP1, 3,  3},
-       { DBGBUS_SSPP1, 23, 3},
-       { DBGBUS_SSPP1, 33, 3},
-       { DBGBUS_SSPP1, 43, 3},
-
-       /* spa */
-       { DBGBUS_SSPP0, 8,  0},
-       { DBGBUS_SSPP0, 28, 0},
-       { DBGBUS_SSPP1, 8,  0},
-       { DBGBUS_SSPP1, 28, 0},
-       { DBGBUS_DSPP, 13, 0},
-       { DBGBUS_DSPP, 19, 0},
-
-       /* igc */
-       { DBGBUS_SSPP0, 17, 0},
-       { DBGBUS_SSPP0, 17, 1},
-       { DBGBUS_SSPP0, 17, 3},
-       { DBGBUS_SSPP0, 37, 0},
-       { DBGBUS_SSPP0, 37, 1},
-       { DBGBUS_SSPP0, 37, 3},
-       { DBGBUS_SSPP0, 46, 0},
-       { DBGBUS_SSPP0, 46, 1},
-       { DBGBUS_SSPP0, 46, 3},
-
-       { DBGBUS_SSPP1, 17, 0},
-       { DBGBUS_SSPP1, 17, 1},
-       { DBGBUS_SSPP1, 17, 3},
-       { DBGBUS_SSPP1, 37, 0},
-       { DBGBUS_SSPP1, 37, 1},
-       { DBGBUS_SSPP1, 37, 3},
-       { DBGBUS_SSPP1, 46, 0},
-       { DBGBUS_SSPP1, 46, 1},
-       { DBGBUS_SSPP1, 46, 3},
-
-       { DBGBUS_DSPP, 14, 0},
-       { DBGBUS_DSPP, 14, 1},
-       { DBGBUS_DSPP, 14, 3},
-       { DBGBUS_DSPP, 20, 0},
-       { DBGBUS_DSPP, 20, 1},
-       { DBGBUS_DSPP, 20, 3},
-
-       /* intf0-3 */
-       { DBGBUS_PERIPH, 0, 0},
-       { DBGBUS_PERIPH, 1, 0},
-       { DBGBUS_PERIPH, 2, 0},
-       { DBGBUS_PERIPH, 3, 0},
-
-       /* te counter wrapper */
-       { DBGBUS_PERIPH, 60, 0},
-
-       /* dsc0 */
-       { DBGBUS_PERIPH, 47, 0},
-       { DBGBUS_PERIPH, 47, 1},
-       { DBGBUS_PERIPH, 47, 2},
-       { DBGBUS_PERIPH, 47, 3},
-       { DBGBUS_PERIPH, 47, 4},
-       { DBGBUS_PERIPH, 47, 5},
-       { DBGBUS_PERIPH, 47, 6},
-       { DBGBUS_PERIPH, 47, 7},
-
-       /* dsc1 */
-       { DBGBUS_PERIPH, 48, 0},
-       { DBGBUS_PERIPH, 48, 1},
-       { DBGBUS_PERIPH, 48, 2},
-       { DBGBUS_PERIPH, 48, 3},
-       { DBGBUS_PERIPH, 48, 4},
-       { DBGBUS_PERIPH, 48, 5},
-       { DBGBUS_PERIPH, 48, 6},
-       { DBGBUS_PERIPH, 48, 7},
-
-       /* dsc2 */
-       { DBGBUS_PERIPH, 51, 0},
-       { DBGBUS_PERIPH, 51, 1},
-       { DBGBUS_PERIPH, 51, 2},
-       { DBGBUS_PERIPH, 51, 3},
-       { DBGBUS_PERIPH, 51, 4},
-       { DBGBUS_PERIPH, 51, 5},
-       { DBGBUS_PERIPH, 51, 6},
-       { DBGBUS_PERIPH, 51, 7},
-
-       /* dsc3 */
-       { DBGBUS_PERIPH, 52, 0},
-       { DBGBUS_PERIPH, 52, 1},
-       { DBGBUS_PERIPH, 52, 2},
-       { DBGBUS_PERIPH, 52, 3},
-       { DBGBUS_PERIPH, 52, 4},
-       { DBGBUS_PERIPH, 52, 5},
-       { DBGBUS_PERIPH, 52, 6},
-       { DBGBUS_PERIPH, 52, 7},
-
-       /* tear-check */
-       { DBGBUS_PERIPH, 63, 0 },
-       { DBGBUS_PERIPH, 64, 0 },
-       { DBGBUS_PERIPH, 65, 0 },
-       { DBGBUS_PERIPH, 73, 0 },
-       { DBGBUS_PERIPH, 74, 0 },
-
-       /* cdwn */
-       { DBGBUS_PERIPH, 80, 0},
-       { DBGBUS_PERIPH, 80, 1},
-       { DBGBUS_PERIPH, 80, 2},
-
-       { DBGBUS_PERIPH, 81, 0},
-       { DBGBUS_PERIPH, 81, 1},
-       { DBGBUS_PERIPH, 81, 2},
-
-       { DBGBUS_PERIPH, 82, 0},
-       { DBGBUS_PERIPH, 82, 1},
-       { DBGBUS_PERIPH, 82, 2},
-       { DBGBUS_PERIPH, 82, 3},
-       { DBGBUS_PERIPH, 82, 4},
-       { DBGBUS_PERIPH, 82, 5},
-       { DBGBUS_PERIPH, 82, 6},
-       { DBGBUS_PERIPH, 82, 7},
-
-       /* hdmi */
-       { DBGBUS_PERIPH, 68, 0},
-       { DBGBUS_PERIPH, 68, 1},
-       { DBGBUS_PERIPH, 68, 2},
-       { DBGBUS_PERIPH, 68, 3},
-       { DBGBUS_PERIPH, 68, 4},
-       { DBGBUS_PERIPH, 68, 5},
-
-       /* edp */
-       { DBGBUS_PERIPH, 69, 0},
-       { DBGBUS_PERIPH, 69, 1},
-       { DBGBUS_PERIPH, 69, 2},
-       { DBGBUS_PERIPH, 69, 3},
-       { DBGBUS_PERIPH, 69, 4},
-       { DBGBUS_PERIPH, 69, 5},
-
-       /* dsi0 */
-       { DBGBUS_PERIPH, 70, 0},
-       { DBGBUS_PERIPH, 70, 1},
-       { DBGBUS_PERIPH, 70, 2},
-       { DBGBUS_PERIPH, 70, 3},
-       { DBGBUS_PERIPH, 70, 4},
-       { DBGBUS_PERIPH, 70, 5},
-
-       /* dsi1 */
-       { DBGBUS_PERIPH, 71, 0},
-       { DBGBUS_PERIPH, 71, 1},
-       { DBGBUS_PERIPH, 71, 2},
-       { DBGBUS_PERIPH, 71, 3},
-       { DBGBUS_PERIPH, 71, 4},
-       { DBGBUS_PERIPH, 71, 5},
-};
-
-static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = {
-       {0x214, 0x21c, 16, 2, 0x0, 0xd},     /* arb clients */
-       {0x214, 0x21c, 16, 2, 0x80, 0xc0},   /* arb clients */
-       {0x214, 0x21c, 16, 2, 0x100, 0x140}, /* arb clients */
-       {0x214, 0x21c, 0, 16, 0x0, 0xf},     /* xin blocks - axi side */
-       {0x214, 0x21c, 0, 16, 0x80, 0xa4},   /* xin blocks - axi side */
-       {0x214, 0x21c, 0, 15, 0x100, 0x124}, /* xin blocks - axi side */
-       {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */
-};
-
-/**
- * _dpu_dbg_enable_power - use callback to turn power on for hw register access
- * @enable: whether to turn power on or off
- */
-static inline void _dpu_dbg_enable_power(int enable)
-{
-       if (enable)
-               pm_runtime_get_sync(dpu_dbg_base.dev);
-       else
-               pm_runtime_put_sync(dpu_dbg_base.dev);
-}
-
-static void _dpu_dbg_dump_dpu_dbg_bus(struct dpu_dbg_dpu_debug_bus *bus)
-{
-       bool in_log, in_mem;
-       u32 **dump_mem = NULL;
-       u32 *dump_addr = NULL;
-       u32 status = 0;
-       struct dpu_debug_bus_entry *head;
-       phys_addr_t phys = 0;
-       int list_size;
-       int i;
-       u32 offset;
-       void __iomem *mem_base = NULL;
-       struct dpu_dbg_reg_base *reg_base;
-
-       if (!bus || !bus->cmn.entries_size)
-               return;
-
-       list_for_each_entry(reg_base, &dpu_dbg_base.reg_base_list,
-                       reg_base_head)
-               if (strlen(reg_base->name) &&
-                       !strcmp(reg_base->name, bus->cmn.name))
-                       mem_base = reg_base->base + bus->top_blk_off;
-
-       if (!mem_base) {
-               pr_err("unable to find mem_base for %s\n", bus->cmn.name);
-               return;
-       }
-
-       dump_mem = &bus->cmn.dumped_content;
-
-       /* will keep in memory 4 entries of 4 bytes each */
-       list_size = (bus->cmn.entries_size * 4 * 4);
-
-       in_log = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_LOG);
-       in_mem = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_MEM);
-
-       if (!in_log && !in_mem)
-               return;
-
-       dev_info(dpu_dbg_base.dev, "======== start %s dump =========\n",
-                       bus->cmn.name);
-
-       if (in_mem) {
-               if (!(*dump_mem))
-                       *dump_mem = dma_alloc_coherent(dpu_dbg_base.dev,
-                               list_size, &phys, GFP_KERNEL);
-
-               if (*dump_mem) {
-                       dump_addr = *dump_mem;
-                       dev_info(dpu_dbg_base.dev,
-                               "%s: start_addr:0x%pK len:0x%x\n",
-                               __func__, dump_addr, list_size);
-               } else {
-                       in_mem = false;
-                       pr_err("dump_mem: allocation fails\n");
-               }
-       }
-
-       _dpu_dbg_enable_power(true);
-       for (i = 0; i < bus->cmn.entries_size; i++) {
-               head = bus->entries + i;
-               writel_relaxed(TEST_MASK(head->block_id, head->test_id),
-                               mem_base + head->wr_addr);
-               wmb(); /* make sure test bits were written */
-
-               if (bus->cmn.flags & DBGBUS_FLAGS_DSPP) {
-                       offset = DBGBUS_DSPP_STATUS;
-                       /* keep DSPP test point enabled */
-                       if (head->wr_addr != DBGBUS_DSPP)
-                               writel_relaxed(0xF, mem_base + DBGBUS_DSPP);
-               } else {
-                       offset = head->wr_addr + 0x4;
-               }
-
-               status = readl_relaxed(mem_base + offset);
-
-               if (in_log)
-                       dev_info(dpu_dbg_base.dev,
-                                       "waddr=0x%x blk=%d tst=%d val=0x%x\n",
-                                       head->wr_addr, head->block_id,
-                                       head->test_id, status);
-
-               if (dump_addr && in_mem) {
-                       dump_addr[i*4]     = head->wr_addr;
-                       dump_addr[i*4 + 1] = head->block_id;
-                       dump_addr[i*4 + 2] = head->test_id;
-                       dump_addr[i*4 + 3] = status;
-               }
-
-               if (head->analyzer)
-                       head->analyzer(mem_base, head, status);
-
-               /* Disable debug bus once we are done */
-               writel_relaxed(0, mem_base + head->wr_addr);
-               if (bus->cmn.flags & DBGBUS_FLAGS_DSPP &&
-                                               head->wr_addr != DBGBUS_DSPP)
-                       writel_relaxed(0x0, mem_base + DBGBUS_DSPP);
-       }
-       _dpu_dbg_enable_power(false);
-
-       dev_info(dpu_dbg_base.dev, "======== end %s dump =========\n",
-                       bus->cmn.name);
-}
-
-static void _dpu_dbg_dump_vbif_debug_bus_entry(
-               struct vbif_debug_bus_entry *head, void __iomem *mem_base,
-               u32 *dump_addr, bool in_log)
-{
-       int i, j;
-       u32 val;
-
-       if (!dump_addr && !in_log)
-               return;
-
-       for (i = 0; i < head->block_cnt; i++) {
-               writel_relaxed(1 << (i + head->bit_offset),
-                               mem_base + head->block_bus_addr);
-               /* make sure that current bus blcok enable */
-               wmb();
-               for (j = head->test_pnt_start; j < head->test_pnt_cnt; j++) {
-                       writel_relaxed(j, mem_base + head->block_bus_addr + 4);
-                       /* make sure that test point is enabled */
-                       wmb();
-                       val = readl_relaxed(mem_base + MMSS_VBIF_TEST_BUS_OUT);
-                       if (dump_addr) {
-                               *dump_addr++ = head->block_bus_addr;
-                               *dump_addr++ = i;
-                               *dump_addr++ = j;
-                               *dump_addr++ = val;
-                       }
-                       if (in_log)
-                               dev_info(dpu_dbg_base.dev,
-                                       "testpoint:%x arb/xin id=%d index=%d val=0x%x\n",
-                                       head->block_bus_addr, i, j, val);
-               }
-       }
-}
-
-static void _dpu_dbg_dump_vbif_dbg_bus(struct dpu_dbg_vbif_debug_bus *bus)
-{
-       bool in_log, in_mem;
-       u32 **dump_mem = NULL;
-       u32 *dump_addr = NULL;
-       u32 value, d0, d1;
-       unsigned long reg, reg1, reg2;
-       struct vbif_debug_bus_entry *head;
-       phys_addr_t phys = 0;
-       int i, list_size = 0;
-       void __iomem *mem_base = NULL;
-       struct vbif_debug_bus_entry *dbg_bus;
-       u32 bus_size;
-       struct dpu_dbg_reg_base *reg_base;
-
-       if (!bus || !bus->cmn.entries_size)
-               return;
-
-       list_for_each_entry(reg_base, &dpu_dbg_base.reg_base_list,
-                       reg_base_head)
-               if (strlen(reg_base->name) &&
-                       !strcmp(reg_base->name, bus->cmn.name))
-                       mem_base = reg_base->base;
-
-       if (!mem_base) {
-               pr_err("unable to find mem_base for %s\n", bus->cmn.name);
-               return;
-       }
-
-       dbg_bus = bus->entries;
-       bus_size = bus->cmn.entries_size;
-       list_size = bus->cmn.entries_size;
-       dump_mem = &bus->cmn.dumped_content;
-
-       dev_info(dpu_dbg_base.dev, "======== start %s dump =========\n",
-                       bus->cmn.name);
-
-       if (!dump_mem || !dbg_bus || !bus_size || !list_size)
-               return;
-
-       /* allocate memory for each test point */
-       for (i = 0; i < bus_size; i++) {
-               head = dbg_bus + i;
-               list_size += (head->block_cnt * head->test_pnt_cnt);
-       }
-
-       /* 4 bytes * 4 entries for each test point*/
-       list_size *= 16;
-
-       in_log = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_LOG);
-       in_mem = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_MEM);
-
-       if (!in_log && !in_mem)
-               return;
-
-       if (in_mem) {
-               if (!(*dump_mem))
-                       *dump_mem = dma_alloc_coherent(dpu_dbg_base.dev,
-                               list_size, &phys, GFP_KERNEL);
-
-               if (*dump_mem) {
-                       dump_addr = *dump_mem;
-                       dev_info(dpu_dbg_base.dev,
-                               "%s: start_addr:0x%pK len:0x%x\n",
-                               __func__, dump_addr, list_size);
-               } else {
-                       in_mem = false;
-                       pr_err("dump_mem: allocation fails\n");
-               }
-       }
-
-       _dpu_dbg_enable_power(true);
-
-       value = readl_relaxed(mem_base + MMSS_VBIF_CLKON);
-       writel_relaxed(value | BIT(1), mem_base + MMSS_VBIF_CLKON);
-
-       /* make sure that vbif core is on */
-       wmb();
-
-       /**
-        * Extract VBIF error info based on XIN halt and error status.
-        * If the XIN client is not in HALT state, or an error is detected,
-        * then retrieve the VBIF error info for it.
-        */
-       reg = readl_relaxed(mem_base + MMSS_VBIF_XIN_HALT_CTRL1);
-       reg1 = readl_relaxed(mem_base + MMSS_VBIF_PND_ERR);
-       reg2 = readl_relaxed(mem_base + MMSS_VBIF_SRC_ERR);
-       dev_err(dpu_dbg_base.dev,
-                       "XIN HALT:0x%lX, PND ERR:0x%lX, SRC ERR:0x%lX\n",
-                       reg, reg1, reg2);
-       reg >>= 16;
-       reg &= ~(reg1 | reg2);
-       for (i = 0; i < MMSS_VBIF_CLIENT_NUM; i++) {
-               if (!test_bit(0, &reg)) {
-                       writel_relaxed(i, mem_base + MMSS_VBIF_ERR_INFO);
-                       /* make sure reg write goes through */
-                       wmb();
-
-                       d0 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO);
-                       d1 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO_1);
-
-                       dev_err(dpu_dbg_base.dev,
-                                       "Client:%d, errinfo=0x%X, errinfo1=0x%X\n",
-                                       i, d0, d1);
-               }
-               reg >>= 1;
-       }
-
-       for (i = 0; i < bus_size; i++) {
-               head = dbg_bus + i;
-
-               writel_relaxed(0, mem_base + head->disable_bus_addr);
-               writel_relaxed(BIT(0), mem_base + MMSS_VBIF_TEST_BUS_OUT_CTRL);
-               /* make sure that other bus is off */
-               wmb();
-
-               _dpu_dbg_dump_vbif_debug_bus_entry(head, mem_base, dump_addr,
-                               in_log);
-               if (dump_addr)
-                       dump_addr += (head->block_cnt * head->test_pnt_cnt * 4);
-       }
-
-       _dpu_dbg_enable_power(false);
-
-       dev_info(dpu_dbg_base.dev, "======== end %s dump =========\n",
-                       bus->cmn.name);
-}
-
-/**
- * _dpu_dump_array - dump array of register bases
- * @name: string indicating origin of dump
- * @dump_dbgbus_dpu: whether to dump the dpu debug bus
- * @dump_dbgbus_vbif_rt: whether to dump the vbif rt debug bus
- */
-static void _dpu_dump_array(const char *name, bool dump_dbgbus_dpu,
-                           bool dump_dbgbus_vbif_rt)
-{
-       if (dump_dbgbus_dpu)
-               _dpu_dbg_dump_dpu_dbg_bus(&dpu_dbg_base.dbgbus_dpu);
-
-       if (dump_dbgbus_vbif_rt)
-               _dpu_dbg_dump_vbif_dbg_bus(&dpu_dbg_base.dbgbus_vbif_rt);
-}
-
-/**
- * _dpu_dump_work - deferred dump work function
- * @work: work structure
- */
-static void _dpu_dump_work(struct work_struct *work)
-{
-       _dpu_dump_array("dpudump_workitem",
-               dpu_dbg_base.dbgbus_dpu.cmn.include_in_deferred_work,
-               dpu_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work);
-}
-
-void dpu_dbg_dump(bool queue_work, const char *name, bool dump_dbgbus_dpu,
-                 bool dump_dbgbus_vbif_rt)
-{
-       if (queue_work && work_pending(&dpu_dbg_base.dump_work))
-               return;
-
-       if (!queue_work) {
-               _dpu_dump_array(name, dump_dbgbus_dpu, dump_dbgbus_vbif_rt);
-               return;
-       }
-
-       /* schedule work to dump later */
-       dpu_dbg_base.dbgbus_dpu.cmn.include_in_deferred_work = dump_dbgbus_dpu;
-       dpu_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work =
-                       dump_dbgbus_vbif_rt;
-       schedule_work(&dpu_dbg_base.dump_work);
-}
-
-/*
- * dpu_dbg_debugfs_open - debugfs open handler for debug dump
- * @inode: debugfs inode
- * @file: file handle
- */
-static int dpu_dbg_debugfs_open(struct inode *inode, struct file *file)
-{
-       /* non-seekable */
-       file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-/**
- * dpu_dbg_dump_write - debugfs write handler for debug dump
- * @file: file handler
- * @user_buf: user buffer content from debugfs
- * @count: size of user buffer
- * @ppos: position offset of user buffer
- */
-static ssize_t dpu_dbg_dump_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       _dpu_dump_array("dump_debugfs", true, true);
-       return count;
-}
-
-static const struct file_operations dpu_dbg_dump_fops = {
-       .open = dpu_dbg_debugfs_open,
-       .write = dpu_dbg_dump_write,
-};
-
-int dpu_dbg_debugfs_register(struct dentry *debugfs_root)
-{
-       static struct dpu_dbg_base *dbg = &dpu_dbg_base;
-       char debug_name[80] = "";
-
-       if (!debugfs_root)
-               return -EINVAL;
-
-       debugfs_create_file("dump", 0600, debugfs_root, NULL,
-                       &dpu_dbg_dump_fops);
-
-       if (dbg->dbgbus_dpu.entries) {
-               dbg->dbgbus_dpu.cmn.name = DBGBUS_NAME_DPU;
-               snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
-                               dbg->dbgbus_dpu.cmn.name);
-               dbg->dbgbus_dpu.cmn.enable_mask = DEFAULT_DBGBUS_DPU;
-               debugfs_create_u32(debug_name, 0600, debugfs_root,
-                               &dbg->dbgbus_dpu.cmn.enable_mask);
-       }
-
-       if (dbg->dbgbus_vbif_rt.entries) {
-               dbg->dbgbus_vbif_rt.cmn.name = DBGBUS_NAME_VBIF_RT;
-               snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
-                               dbg->dbgbus_vbif_rt.cmn.name);
-               dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT;
-               debugfs_create_u32(debug_name, 0600, debugfs_root,
-                               &dbg->dbgbus_vbif_rt.cmn.enable_mask);
-       }
-
-       return 0;
-}
-
-static void _dpu_dbg_debugfs_destroy(void)
-{
-}
-
-void dpu_dbg_init_dbg_buses(u32 hwversion)
-{
-       static struct dpu_dbg_base *dbg = &dpu_dbg_base;
-
-       memset(&dbg->dbgbus_dpu, 0, sizeof(dbg->dbgbus_dpu));
-       memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt));
-
-       if (IS_MSM8998_TARGET(hwversion)) {
-               dbg->dbgbus_dpu.entries = dbg_bus_dpu_8998;
-               dbg->dbgbus_dpu.cmn.entries_size = ARRAY_SIZE(dbg_bus_dpu_8998);
-               dbg->dbgbus_dpu.cmn.flags = DBGBUS_FLAGS_DSPP;
-
-               dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
-               dbg->dbgbus_vbif_rt.cmn.entries_size =
-                               ARRAY_SIZE(vbif_dbg_bus_msm8998);
-       } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) {
-               dbg->dbgbus_dpu.entries = dbg_bus_dpu_sdm845;
-               dbg->dbgbus_dpu.cmn.entries_size =
-                               ARRAY_SIZE(dbg_bus_dpu_sdm845);
-               dbg->dbgbus_dpu.cmn.flags = DBGBUS_FLAGS_DSPP;
-
-               /* vbif is unchanged vs 8998 */
-               dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
-               dbg->dbgbus_vbif_rt.cmn.entries_size =
-                               ARRAY_SIZE(vbif_dbg_bus_msm8998);
-       } else {
-               pr_err("unsupported chipset id %X\n", hwversion);
-       }
-}
-
-int dpu_dbg_init(struct device *dev)
-{
-       if (!dev) {
-               pr_err("invalid params\n");
-               return -EINVAL;
-       }
-
-       INIT_LIST_HEAD(&dpu_dbg_base.reg_base_list);
-       dpu_dbg_base.dev = dev;
-
-       INIT_WORK(&dpu_dbg_base.dump_work, _dpu_dump_work);
-
-       return 0;
-}
-
-/**
- * dpu_dbg_destroy - destroy dpu debug facilities
- */
-void dpu_dbg_destroy(void)
-{
-       _dpu_dbg_debugfs_destroy();
-}
-
-void dpu_dbg_set_dpu_top_offset(u32 blk_off)
-{
-       dpu_dbg_base.dbgbus_dpu.top_blk_off = blk_off;
-}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h
deleted file mode 100644 (file)
index 1e6fa94..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Copyright (c) 2016-2018, 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 DPU_DBG_H_
-#define DPU_DBG_H_
-
-#include <stdarg.h>
-#include <linux/debugfs.h>
-#include <linux/list.h>
-
-enum dpu_dbg_dump_flag {
-       DPU_DBG_DUMP_IN_LOG = BIT(0),
-       DPU_DBG_DUMP_IN_MEM = BIT(1),
-};
-
-#if defined(CONFIG_DEBUG_FS)
-
-/**
- * dpu_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset
- * @hwversion:         Chipset revision
- */
-void dpu_dbg_init_dbg_buses(u32 hwversion);
-
-/**
- * dpu_dbg_init - initialize global dpu debug facilities: regdump
- * @dev:               device handle
- * Returns:            0 or -ERROR
- */
-int dpu_dbg_init(struct device *dev);
-
-/**
- * dpu_dbg_debugfs_register - register entries at the given debugfs dir
- * @debugfs_root:      debugfs root in which to create dpu debug entries
- * Returns:    0 or -ERROR
- */
-int dpu_dbg_debugfs_register(struct dentry *debugfs_root);
-
-/**
- * dpu_dbg_destroy - destroy the global dpu debug facilities
- * Returns:    none
- */
-void dpu_dbg_destroy(void);
-
-/**
- * dpu_dbg_dump - trigger dumping of all dpu_dbg facilities
- * @queue_work:          whether to queue the dumping work to the work_struct
- * @name:        string indicating origin of dump
- * @dump_dbgbus:  dump the dpu debug bus
- * @dump_vbif_rt: dump the vbif rt bus
- * Returns:    none
- */
-void dpu_dbg_dump(bool queue_work, const char *name, bool dump_dbgbus_dpu,
-                 bool dump_dbgbus_vbif_rt);
-
-/**
- * dpu_dbg_set_dpu_top_offset - set the target specific offset from mdss base
- *     address of the top registers. Used for accessing debug bus controls.
- * @blk_off: offset from mdss base of the top block
- */
-void dpu_dbg_set_dpu_top_offset(u32 blk_off);
-
-#else
-
-static inline void dpu_dbg_init_dbg_buses(u32 hwversion)
-{
-}
-
-static inline int dpu_dbg_init(struct device *dev)
-{
-       return 0;
-}
-
-static inline int dpu_dbg_debugfs_register(struct dentry *debugfs_root)
-{
-       return 0;
-}
-
-static inline void dpu_dbg_destroy(void)
-{
-}
-
-static inline void dpu_dbg_dump(bool queue_work, const char *name,
-                               bool dump_dbgbus_dpu, bool dump_dbgbus_vbif_rt)
-{
-}
-
-static inline void dpu_dbg_set_dpu_top_offset(u32 blk_off)
-{
-}
-
-#endif /* defined(CONFIG_DEBUG_FS) */
-
-
-#endif /* DPU_DBG_H_ */
index d31d8281424efb371cf04cfe82220ef3959828fa..36158b7d99cdb14a063b0c63be57a93314008c61 100644 (file)
@@ -130,8 +130,9 @@ enum dpu_enc_rc_states {
  *     Virtual encoder defers as much as possible to the physical encoders.
  *     Virtual encoder registers itself with the DRM Framework as the encoder.
  * @base:              drm_encoder base class for registration with DRM
- * @enc_spin_lock:     Virtual-Encoder-Wide Spin Lock for IRQ purposes
+ * @enc_spinlock:      Virtual-Encoder-Wide Spin Lock for IRQ purposes
  * @bus_scaling_client:        Client handle to the bus scaling interface
+ * @enabled:           True if the encoder is active, protected by enc_lock
  * @num_phys_encs:     Actual number of physical encoders contained.
  * @phys_encs:         Container of physical encoders managed.
  * @cur_master:                Pointer to the current master in this mode. Optimization
@@ -141,15 +142,17 @@ enum dpu_enc_rc_states {
  * @intfs_swapped      Whether or not the phys_enc interfaces have been swapped
  *                     for partial update right-only cases, such as pingpong
  *                     split where virtual pingpong does not generate IRQs
- * @crtc_vblank_cb:    Callback into the upper layer / CRTC for
- *                     notification of the VBLANK
- * @crtc_vblank_cb_data:       Data from upper layer for VBLANK notification
+ * @crtc:              Pointer to the currently assigned crtc. Normally you
+ *                     would use crtc->state->encoder_mask to determine the
+ *                     link between encoder/crtc. However in this case we need
+ *                     to track crtc in the disable() hook which is called
+ *                     _after_ encoder_mask is cleared.
  * @crtc_kickoff_cb:           Callback into CRTC that will flush & start
  *                             all CTL paths
  * @crtc_kickoff_cb_data:      Opaque user data given to crtc_kickoff_cb
  * @debugfs_root:              Debug file system root file node
- * @enc_lock:                  Lock around physical encoder create/destroy and
-                               access.
+ * @enc_lock:                  Lock around physical encoder
+ *                             create/destroy/enable/disable
  * @frame_busy_mask:           Bitmask tracking which phys_enc we are still
  *                             busy processing current command.
  *                             Bit0 = phys_encs[0] etc.
@@ -175,6 +178,8 @@ struct dpu_encoder_virt {
        spinlock_t enc_spinlock;
        uint32_t bus_scaling_client;
 
+       bool enabled;
+
        unsigned int num_phys_encs;
        struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
        struct dpu_encoder_phys *cur_master;
@@ -183,8 +188,7 @@ struct dpu_encoder_virt {
 
        bool intfs_swapped;
 
-       void (*crtc_vblank_cb)(void *);
-       void *crtc_vblank_cb_data;
+       struct drm_crtc *crtc;
 
        struct dentry *debugfs_root;
        struct mutex enc_lock;
@@ -210,39 +214,6 @@ struct dpu_encoder_virt {
 };
 
 #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base)
-static inline int _dpu_encoder_power_enable(struct dpu_encoder_virt *dpu_enc,
-                                                               bool enable)
-{
-       struct drm_encoder *drm_enc;
-       struct msm_drm_private *priv;
-       struct dpu_kms *dpu_kms;
-
-       if (!dpu_enc) {
-               DPU_ERROR("invalid dpu enc\n");
-               return -EINVAL;
-       }
-
-       drm_enc = &dpu_enc->base;
-       if (!drm_enc->dev || !drm_enc->dev->dev_private) {
-               DPU_ERROR("drm device invalid\n");
-               return -EINVAL;
-       }
-
-       priv = drm_enc->dev->dev_private;
-       if (!priv->kms) {
-               DPU_ERROR("invalid kms\n");
-               return -EINVAL;
-       }
-
-       dpu_kms = to_dpu_kms(priv->kms);
-
-       if (enable)
-               pm_runtime_get_sync(&dpu_kms->pdev->dev);
-       else
-               pm_runtime_put_sync(&dpu_kms->pdev->dev);
-
-       return 0;
-}
 
 void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc,
                enum dpu_intr_idx intr_idx)
@@ -1117,28 +1088,24 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
        _dpu_encoder_update_vsync_source(dpu_enc, &dpu_enc->disp_info);
 }
 
-void dpu_encoder_virt_restore(struct drm_encoder *drm_enc)
+void dpu_encoder_virt_runtime_resume(struct drm_encoder *drm_enc)
 {
-       struct dpu_encoder_virt *dpu_enc = NULL;
-       int i;
-
-       if (!drm_enc) {
-               DPU_ERROR("invalid encoder\n");
-               return;
-       }
-       dpu_enc = to_dpu_encoder_virt(drm_enc);
+       struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
 
-       for (i = 0; i < dpu_enc->num_phys_encs; i++) {
-               struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+       mutex_lock(&dpu_enc->enc_lock);
 
-               if (phys && (phys != dpu_enc->cur_master) && phys->ops.restore)
-                       phys->ops.restore(phys);
-       }
+       if (!dpu_enc->enabled)
+               goto out;
 
+       if (dpu_enc->cur_slave && dpu_enc->cur_slave->ops.restore)
+               dpu_enc->cur_slave->ops.restore(dpu_enc->cur_slave);
        if (dpu_enc->cur_master && dpu_enc->cur_master->ops.restore)
                dpu_enc->cur_master->ops.restore(dpu_enc->cur_master);
 
        _dpu_encoder_virt_enable_helper(drm_enc);
+
+out:
+       mutex_unlock(&dpu_enc->enc_lock);
 }
 
 static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
@@ -1152,6 +1119,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
                return;
        }
        dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+       mutex_lock(&dpu_enc->enc_lock);
        cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
 
        trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
@@ -1168,10 +1137,15 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
        if (ret) {
                DPU_ERROR_ENC(dpu_enc, "dpu resource control failed: %d\n",
                                ret);
-               return;
+               goto out;
        }
 
        _dpu_encoder_virt_enable_helper(drm_enc);
+
+       dpu_enc->enabled = true;
+
+out:
+       mutex_unlock(&dpu_enc->enc_lock);
 }
 
 static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
@@ -1193,11 +1167,14 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
                return;
        }
 
-       mode = &drm_enc->crtc->state->adjusted_mode;
-
        dpu_enc = to_dpu_encoder_virt(drm_enc);
        DPU_DEBUG_ENC(dpu_enc, "\n");
 
+       mutex_lock(&dpu_enc->enc_lock);
+       dpu_enc->enabled = false;
+
+       mode = &drm_enc->crtc->state->adjusted_mode;
+
        priv = drm_enc->dev->dev_private;
        dpu_kms = to_dpu_kms(priv->kms);
 
@@ -1231,6 +1208,8 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
        DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n");
 
        dpu_rm_release(&dpu_kms->rm, drm_enc);
+
+       mutex_unlock(&dpu_enc->enc_lock);
 }
 
 static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
@@ -1261,8 +1240,8 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
        dpu_enc = to_dpu_encoder_virt(drm_enc);
 
        spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags);
-       if (dpu_enc->crtc_vblank_cb)
-               dpu_enc->crtc_vblank_cb(dpu_enc->crtc_vblank_cb_data);
+       if (dpu_enc->crtc)
+               dpu_crtc_vblank_callback(dpu_enc->crtc);
        spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
 
        atomic_inc(&phy_enc->vsync_cnt);
@@ -1282,25 +1261,32 @@ static void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
        DPU_ATRACE_END("encoder_underrun_callback");
 }
 
-void dpu_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
-               void (*vbl_cb)(void *), void *vbl_data)
+void dpu_encoder_assign_crtc(struct drm_encoder *drm_enc, struct drm_crtc *crtc)
 {
        struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
        unsigned long lock_flags;
-       bool enable;
-       int i;
 
-       enable = vbl_cb ? true : false;
+       spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags);
+       /* crtc should always be cleared before re-assigning */
+       WARN_ON(crtc && dpu_enc->crtc);
+       dpu_enc->crtc = crtc;
+       spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
+}
+
+void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *drm_enc,
+                                       struct drm_crtc *crtc, bool enable)
+{
+       struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+       unsigned long lock_flags;
+       int i;
 
-       if (!drm_enc) {
-               DPU_ERROR("invalid encoder\n");
-               return;
-       }
        trace_dpu_enc_vblank_cb(DRMID(drm_enc), enable);
 
        spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags);
-       dpu_enc->crtc_vblank_cb = vbl_cb;
-       dpu_enc->crtc_vblank_cb_data = vbl_data;
+       if (dpu_enc->crtc != crtc) {
+               spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
+               return;
+       }
        spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
 
        for (i = 0; i < dpu_enc->num_phys_encs; i++) {
@@ -1405,8 +1391,9 @@ static void dpu_encoder_off_work(struct kthread_work *work)
  * phys: Pointer to physical encoder structure
  * extra_flush_bits: Additional bit mask to include in flush trigger
  */
-static inline void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
-               struct dpu_encoder_phys *phys, uint32_t extra_flush_bits)
+static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
+               struct dpu_encoder_phys *phys, uint32_t extra_flush_bits,
+               bool async)
 {
        struct dpu_hw_ctl *ctl;
        int pending_kickoff_cnt;
@@ -1429,7 +1416,10 @@ static inline void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
                return;
        }
 
-       pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys);
+       if (!async)
+               pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys);
+       else
+               pending_kickoff_cnt = atomic_read(&phys->pending_kickoff_cnt);
 
        if (extra_flush_bits && ctl->ops.update_pending_flush)
                ctl->ops.update_pending_flush(ctl, extra_flush_bits);
@@ -1448,7 +1438,7 @@ static inline void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
  * _dpu_encoder_trigger_start - trigger start for a physical encoder
  * phys: Pointer to physical encoder structure
  */
-static inline void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys)
+static void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys)
 {
        if (!phys) {
                DPU_ERROR("invalid argument(s)\n");
@@ -1505,7 +1495,7 @@ static int dpu_encoder_helper_wait_event_timeout(
        return rc;
 }
 
-void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc)
+static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc)
 {
        struct dpu_encoder_virt *dpu_enc;
        struct dpu_hw_ctl *ctl;
@@ -1525,10 +1515,8 @@ void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc)
                      ctl->idx);
 
        rc = ctl->ops.reset(ctl);
-       if (rc) {
+       if (rc)
                DPU_ERROR_ENC(dpu_enc, "ctl %d reset failure\n",  ctl->idx);
-               dpu_dbg_dump(false, __func__, true, true);
-       }
 
        phys_enc->enable_state = DPU_ENC_ENABLED;
 }
@@ -1542,7 +1530,8 @@ void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc)
  *     a time.
  * dpu_enc: Pointer to virtual encoder structure
  */
-static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc)
+static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc,
+                                     bool async)
 {
        struct dpu_hw_ctl *ctl;
        uint32_t i, pending_flush;
@@ -1573,7 +1562,8 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc)
                        set_bit(i, dpu_enc->frame_busy_mask);
                if (!phys->ops.needs_single_flush ||
                                !phys->ops.needs_single_flush(phys))
-                       _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0);
+                       _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0,
+                                                  async);
                else if (ctl->ops.get_pending_flush)
                        pending_flush |= ctl->ops.get_pending_flush(ctl);
        }
@@ -1583,7 +1573,7 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc)
                _dpu_encoder_trigger_flush(
                                &dpu_enc->base,
                                dpu_enc->cur_master,
-                               pending_flush);
+                               pending_flush, async);
        }
 
        _dpu_encoder_trigger_start(dpu_enc->cur_master);
@@ -1767,7 +1757,7 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
 }
 
 void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
-               struct dpu_encoder_kickoff_params *params)
+               struct dpu_encoder_kickoff_params *params, bool async)
 {
        struct dpu_encoder_virt *dpu_enc;
        struct dpu_encoder_phys *phys;
@@ -1801,14 +1791,12 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
        if (needs_hw_reset) {
                trace_dpu_enc_prepare_kickoff_reset(DRMID(drm_enc));
                for (i = 0; i < dpu_enc->num_phys_encs; i++) {
-                       phys = dpu_enc->phys_encs[i];
-                       if (phys && phys->ops.hw_reset)
-                               phys->ops.hw_reset(phys);
+                       dpu_encoder_helper_hw_reset(dpu_enc->phys_encs[i]);
                }
        }
 }
 
-void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
+void dpu_encoder_kickoff(struct drm_encoder *drm_enc, bool async)
 {
        struct dpu_encoder_virt *dpu_enc;
        struct dpu_encoder_phys *phys;
@@ -1831,7 +1819,7 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
                ((atomic_read(&dpu_enc->frame_done_timeout) * HZ) / 1000));
 
        /* All phys encs are ready to go, trigger the kickoff */
-       _dpu_encoder_kickoff_phys(dpu_enc);
+       _dpu_encoder_kickoff_phys(dpu_enc, async);
 
        /* allow phys encs to handle any post-kickoff business */
        for (i = 0; i < dpu_enc->num_phys_encs; i++) {
@@ -1873,14 +1861,9 @@ void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc)
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 {
-       struct dpu_encoder_virt *dpu_enc;
+       struct dpu_encoder_virt *dpu_enc = s->private;
        int i;
 
-       if (!s || !s->private)
-               return -EINVAL;
-
-       dpu_enc = s->private;
-
        mutex_lock(&dpu_enc->enc_lock);
        for (i = 0; i < dpu_enc->num_phys_encs; i++) {
                struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
@@ -1918,7 +1901,7 @@ static int _dpu_encoder_debugfs_status_open(struct inode *inode,
 
 static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
 {
-       struct dpu_encoder_virt *dpu_enc;
+       struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
        struct msm_drm_private *priv;
        struct dpu_kms *dpu_kms;
        int i;
@@ -1932,12 +1915,11 @@ static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
 
        char name[DPU_NAME_SIZE];
 
-       if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+       if (!drm_enc->dev || !drm_enc->dev->dev_private) {
                DPU_ERROR("invalid encoder or kms\n");
                return -EINVAL;
        }
 
-       dpu_enc = to_dpu_encoder_virt(drm_enc);
        priv = drm_enc->dev->dev_private;
        dpu_kms = to_dpu_kms(priv->kms);
 
@@ -1962,26 +1944,11 @@ static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
 
        return 0;
 }
-
-static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc)
-{
-       struct dpu_encoder_virt *dpu_enc;
-
-       if (!drm_enc)
-               return;
-
-       dpu_enc = to_dpu_encoder_virt(drm_enc);
-       debugfs_remove_recursive(dpu_enc->debugfs_root);
-}
 #else
 static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc)
 {
        return 0;
 }
-
-static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc)
-{
-}
 #endif
 
 static int dpu_encoder_late_register(struct drm_encoder *encoder)
@@ -1991,7 +1958,9 @@ static int dpu_encoder_late_register(struct drm_encoder *encoder)
 
 static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
 {
-       _dpu_encoder_destroy_debugfs(encoder);
+       struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(encoder);
+
+       debugfs_remove_recursive(dpu_enc->debugfs_root);
 }
 
 static int dpu_encoder_virt_add_phys_encs(
@@ -2266,6 +2235,8 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
 
        drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs);
 
+       dpu_enc->enabled = false;
+
        return &dpu_enc->base;
 }
 
index 9dbf38f446d936ce39bdf01e8c66fd521443fbe4..3f5dafe00580e268d0bd79327d0c9d3f65c5956e 100644 (file)
@@ -55,14 +55,22 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *encoder,
                                  struct dpu_encoder_hw_resources *hw_res);
 
 /**
- * dpu_encoder_register_vblank_callback - provide callback to encoder that
- *     will be called on the next vblank.
+ * dpu_encoder_assign_crtc - Link the encoder to the crtc it's assigned to
  * @encoder:   encoder pointer
- * @cb:                callback pointer, provide NULL to deregister and disable IRQs
- * @data:      user data provided to callback
+ * @crtc:      crtc pointer
+ */
+void dpu_encoder_assign_crtc(struct drm_encoder *encoder,
+                            struct drm_crtc *crtc);
+
+/**
+ * dpu_encoder_toggle_vblank_for_crtc - Toggles vblank interrupts on or off if
+ *     the encoder is assigned to the given crtc
+ * @encoder:   encoder pointer
+ * @crtc:      crtc pointer
+ * @enable:    true if vblank should be enabled
  */
-void dpu_encoder_register_vblank_callback(struct drm_encoder *encoder,
-               void (*cb)(void *), void *data);
+void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *encoder,
+                                       struct drm_crtc *crtc, bool enable);
 
 /**
  * dpu_encoder_register_frame_event_callback - provide callback to encoder that
@@ -81,9 +89,10 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder,
  *     Delayed: Block until next trigger can be issued.
  * @encoder:   encoder pointer
  * @params:    kickoff time parameters
+ * @async:     true if this is an asynchronous commit
  */
 void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder,
-               struct dpu_encoder_kickoff_params *params);
+               struct dpu_encoder_kickoff_params *params, bool async);
 
 /**
  * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous
@@ -96,8 +105,9 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder);
  * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path
  *     (i.e. ctl flush and start) immediately.
  * @encoder:   encoder pointer
+ * @async:     true if this is an asynchronous commit
  */
-void dpu_encoder_kickoff(struct drm_encoder *encoder);
+void dpu_encoder_kickoff(struct drm_encoder *encoder, bool async);
 
 /**
  * dpu_encoder_wait_for_event - Waits for encoder events
@@ -126,10 +136,10 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder,
 enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder);
 
 /**
- * dpu_encoder_virt_restore - restore the encoder configs
+ * dpu_encoder_virt_runtime_resume - pm runtime resume the encoder configs
  * @encoder:   encoder pointer
  */
-void dpu_encoder_virt_restore(struct drm_encoder *encoder);
+void dpu_encoder_virt_runtime_resume(struct drm_encoder *encoder);
 
 /**
  * dpu_encoder_init - initialize virtual encoder object
index 964efcc757a4dcb53b9cae05e688ae9745f9089d..44e6f8b68e70d9fa5ab71075ec7a803356cc44f7 100644 (file)
@@ -114,8 +114,6 @@ struct dpu_encoder_virt_ops {
  * @handle_post_kickoff:       Do any work necessary post-kickoff work
  * @trigger_start:             Process start event on physical encoder
  * @needs_single_flush:                Whether encoder slaves need to be flushed
- * @hw_reset:                  Issue HW recovery such as CTL reset and clear
- *                             DPU_ENC_ERR_NEEDS_HW_RESET state
  * @irq_control:               Handler to enable/disable all the encoder IRQs
  * @prepare_idle_pc:           phys encoder can update the vsync_enable status
  *                              on idle power collapse prepare
@@ -151,7 +149,6 @@ struct dpu_encoder_phys_ops {
        void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
        void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
        bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
-       void (*hw_reset)(struct dpu_encoder_phys *phys_enc);
        void (*irq_control)(struct dpu_encoder_phys *phys, bool enable);
        void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc);
        void (*restore)(struct dpu_encoder_phys *phys);
@@ -342,15 +339,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
  */
 void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc);
 
-/**
- * dpu_encoder_helper_hw_reset - issue ctl hw reset
- *     This helper function may be optionally specified by physical
- *     encoders if they require ctl hw reset. If state is currently
- *     DPU_ENC_ERR_NEEDS_HW_RESET, it is set back to DPU_ENC_ENABLED.
- * @phys_enc: Pointer to physical encoder structure
- */
-void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc);
-
 static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
                struct dpu_encoder_phys *phys_enc)
 {
@@ -362,7 +350,7 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
        dpu_cstate = to_dpu_crtc_state(phys_enc->parent->crtc->state);
 
        if (phys_enc->split_role == ENC_ROLE_SOLO &&
-           dpu_crtc_state_is_stereo(dpu_cstate))
+           dpu_cstate->num_mixers == CRTC_DUAL_MIXERS)
                return BLEND_3D_H_ROW_INT;
 
        return BLEND_3D_NONE;
index b2d7f0ded24c051247869eeebb71f36615524083..99ab5ca9bed3b721f26e2471705a6fe1d616b3a5 100644 (file)
 
 #define DPU_ENC_WR_PTR_START_TIMEOUT_US 20000
 
-static inline int _dpu_encoder_phys_cmd_get_idle_timeout(
-               struct dpu_encoder_phys_cmd *cmd_enc)
-{
-       return KICKOFF_TIMEOUT_MS;
-}
-
-static inline bool dpu_encoder_phys_cmd_is_master(
-               struct dpu_encoder_phys *phys_enc)
+static bool dpu_encoder_phys_cmd_is_master(struct dpu_encoder_phys *phys_enc)
 {
        return (phys_enc->split_role != ENC_ROLE_SLAVE) ? true : false;
 }
@@ -243,7 +236,6 @@ static int _dpu_encoder_phys_cmd_handle_ppdone_timeout(
                          atomic_read(&phys_enc->pending_kickoff_cnt));
 
                dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR);
-               dpu_dbg_dump(false, __func__, true, true);
        }
 
        atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
@@ -496,14 +488,11 @@ static void dpu_encoder_phys_cmd_enable_helper(
        _dpu_encoder_phys_cmd_pingpong_config(phys_enc);
 
        if (!dpu_encoder_phys_cmd_is_master(phys_enc))
-               goto skip_flush;
+               return;
 
        ctl = phys_enc->hw_ctl;
        ctl->ops.get_bitmask_intf(ctl, &flush_mask, phys_enc->intf_idx);
        ctl->ops.update_pending_flush(ctl, flush_mask);
-
-skip_flush:
-       return;
 }
 
 static void dpu_encoder_phys_cmd_enable(struct dpu_encoder_phys *phys_enc)
@@ -727,7 +716,7 @@ static int dpu_encoder_phys_cmd_wait_for_vblank(
 
        wait_info.wq = &cmd_enc->pending_vblank_wq;
        wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt;
-       wait_info.timeout_ms = _dpu_encoder_phys_cmd_get_idle_timeout(cmd_enc);
+       wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
 
        atomic_inc(&cmd_enc->pending_vblank_cnt);
 
@@ -776,7 +765,6 @@ static void dpu_encoder_phys_cmd_init_ops(
        ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank;
        ops->trigger_start = dpu_encoder_phys_cmd_trigger_start;
        ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush;
-       ops->hw_reset = dpu_encoder_helper_hw_reset;
        ops->irq_control = dpu_encoder_phys_cmd_irq_control;
        ops->restore = dpu_encoder_phys_cmd_enable_helper;
        ops->prepare_idle_pc = dpu_encoder_phys_cmd_prepare_idle_pc;
@@ -798,7 +786,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
        if (!cmd_enc) {
                ret = -ENOMEM;
                DPU_ERROR("failed to allocate\n");
-               goto fail;
+               return ERR_PTR(ret);
        }
        phys_enc = &cmd_enc->base;
        phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
@@ -856,6 +844,5 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
 
        return phys_enc;
 
-fail:
        return ERR_PTR(ret);
 }
index 84de385a9f6223881433bec56a38674598fb9d42..acdab5b0db18b5c776ffb8ee2e52df524b0c55d9 100644 (file)
@@ -110,7 +110,7 @@ static void drm_mode_to_intf_timing_params(
         */
 }
 
-static inline u32 get_horizontal_total(const struct intf_timing_params *timing)
+static u32 get_horizontal_total(const struct intf_timing_params *timing)
 {
        u32 active = timing->xres;
        u32 inactive =
@@ -119,7 +119,7 @@ static inline u32 get_horizontal_total(const struct intf_timing_params *timing)
        return active + inactive;
 }
 
-static inline u32 get_vertical_total(const struct intf_timing_params *timing)
+static u32 get_vertical_total(const struct intf_timing_params *timing)
 {
        u32 active = timing->yres;
        u32 inactive =
@@ -331,7 +331,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
        if (hw_ctl && hw_ctl->ops.get_flush_register)
                flush_register = hw_ctl->ops.get_flush_register(hw_ctl);
 
-       if (flush_register == 0)
+       if (!(flush_register & hw_ctl->ops.get_pending_flush(hw_ctl)))
                new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt,
                                -1, 0);
        spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
@@ -613,7 +613,6 @@ static void dpu_encoder_phys_vid_prepare_for_kickoff(
                DPU_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n",
                                ctl->idx, rc);
                dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_VSYNC);
-               dpu_dbg_dump(false, __func__, true, true);
        }
 }
 
@@ -766,7 +765,6 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops)
        ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff;
        ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff;
        ops->needs_single_flush = dpu_encoder_phys_vid_needs_single_flush;
-       ops->hw_reset = dpu_encoder_helper_hw_reset;
        ops->get_line_count = dpu_encoder_phys_vid_get_line_count;
 }
 
index d743e7ca6a3c8b2e83e5ccc619e0f3d6070ff4da..0874f0a53bf9b88bc581f4ea6772739977f26354 100644 (file)
@@ -921,7 +921,7 @@ static int _dpu_format_populate_addrs_ubwc(
                        + layout->plane_size[2] + layout->plane_size[3];
 
                if (!meta)
-                       goto done;
+                       return 0;
 
                /* configure Y metadata plane */
                layout->plane_addr[2] = base_addr;
@@ -952,12 +952,11 @@ static int _dpu_format_populate_addrs_ubwc(
                layout->plane_addr[1] = 0;
 
                if (!meta)
-                       goto done;
+                       return 0;
 
                layout->plane_addr[2] = base_addr;
                layout->plane_addr[3] = 0;
        }
-done:
        return 0;
 }
 
index 58d29e43faefde4f8608b0464c43b5ce47ab1fa6..92f1c4241b9aace6ad51a3de18030c7b7e2684d9 100644 (file)
@@ -30,16 +30,10 @@ static LIST_HEAD(dpu_hw_blk_list);
  * @type: hw block type - enum dpu_hw_blk_type
  * @id: instance id of the hw block
  * @ops: Pointer to block operations
- * return: 0 if success; error code otherwise
  */
-int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
+void dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
                struct dpu_hw_blk_ops *ops)
 {
-       if (!hw_blk) {
-               pr_err("invalid parameters\n");
-               return -EINVAL;
-       }
-
        INIT_LIST_HEAD(&hw_blk->list);
        hw_blk->type = type;
        hw_blk->id = id;
@@ -51,8 +45,6 @@ int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
        mutex_lock(&dpu_hw_blk_lock);
        list_add(&hw_blk->list, &dpu_hw_blk_list);
        mutex_unlock(&dpu_hw_blk_lock);
-
-       return 0;
 }
 
 /**
index 0f4ca8af1ec5a5738f78651c6230a84ead11d725..1934c2f7e8fa684ca7ad0bf5740823c5b7e381c1 100644 (file)
@@ -44,7 +44,7 @@ struct dpu_hw_blk {
        struct dpu_hw_blk_ops ops;
 };
 
-int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
+void dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id,
                struct dpu_hw_blk_ops *ops);
 void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk);
 
index dc060e7358e44df3e223631d44565c53d9355e9d..144358a3d0fb6a9f9a2242644dfccafd65067c70 100644 (file)
@@ -736,13 +736,4 @@ struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev);
  */
 void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg);
 
-/**
- * dpu_hw_sspp_multirect_enabled - check multirect enabled for the sspp
- * @cfg:          pointer to sspp cfg
- */
-static inline bool dpu_hw_sspp_multirect_enabled(const struct dpu_sspp_cfg *cfg)
-{
-       return test_bit(DPU_SSPP_SMART_DMA_V1, &cfg->features) ||
-                        test_bit(DPU_SSPP_SMART_DMA_V2, &cfg->features);
-}
 #endif /* _DPU_HW_CATALOG_H */
index eec1051f2afc4593d20ffecec59af8beb13bb020..1068b4b7940f02c59ea7884a604f6ebbde6ae9cb 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/delay.h>
 #include "dpu_hwio.h"
 #include "dpu_hw_ctl.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
+#include "dpu_trace.h"
 
 #define   CTL_LAYER(lm)                 \
        (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
@@ -72,24 +72,39 @@ static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count,
        return stages;
 }
 
+static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx)
+{
+       struct dpu_hw_blk_reg_map *c = &ctx->hw;
+
+       return DPU_REG_READ(c, CTL_FLUSH);
+}
+
 static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx)
 {
+       trace_dpu_hw_ctl_trigger_start(ctx->pending_flush_mask,
+                                      dpu_hw_ctl_get_flush_register(ctx));
        DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
 }
 
 static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx)
 {
+       trace_dpu_hw_ctl_trigger_prepare(ctx->pending_flush_mask,
+                                        dpu_hw_ctl_get_flush_register(ctx));
        DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1);
 }
 
 static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx)
 {
+       trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask,
+                                    dpu_hw_ctl_get_flush_register(ctx));
        ctx->pending_flush_mask = 0x0;
 }
 
 static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
                u32 flushbits)
 {
+       trace_dpu_hw_ctl_update_pending_flush(flushbits,
+                                             ctx->pending_flush_mask);
        ctx->pending_flush_mask |= flushbits;
 }
 
@@ -103,18 +118,12 @@ static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
 
 static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx)
 {
-
+       trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask,
+                                    dpu_hw_ctl_get_flush_register(ctx));
        DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
 
-static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx)
-{
-       struct dpu_hw_blk_reg_map *c = &ctx->hw;
-
-       return DPU_REG_READ(c, CTL_FLUSH);
-}
-
-static inline uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx,
+static uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx,
        enum dpu_sspp sspp)
 {
        uint32_t flushbits = 0;
@@ -169,7 +178,7 @@ static inline uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx,
        return flushbits;
 }
 
-static inline uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx,
+static uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx,
        enum dpu_lm lm)
 {
        uint32_t flushbits = 0;
@@ -202,7 +211,7 @@ static inline uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx,
        return flushbits;
 }
 
-static inline int dpu_hw_ctl_get_bitmask_intf(struct dpu_hw_ctl *ctx,
+static int dpu_hw_ctl_get_bitmask_intf(struct dpu_hw_ctl *ctx,
                u32 *flushbits, enum dpu_intf intf)
 {
        switch (intf) {
@@ -474,10 +483,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
        ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf;
 };
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
                void __iomem *addr,
@@ -485,7 +491,6 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
 {
        struct dpu_hw_ctl *c;
        struct dpu_ctl_cfg *cfg;
-       int rc;
 
        c = kzalloc(sizeof(*c), GFP_KERNEL);
        if (!c)
@@ -504,18 +509,9 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
        c->mixer_count = m->mixer_count;
        c->mixer_hw_caps = m->mixer;
 
-       rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_CTL, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
+       dpu_hw_blk_init(&c->base, DPU_HW_BLK_CTL, idx, &dpu_hw_ops);
 
        return c;
-
-blk_init_error:
-       kzfree(c);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx)
index 9c6bba0ac7c30f18557d67e479047f3a936b2bb6..f6a83daa385b2123df7c7f6acaf71c3d7430ade0 100644 (file)
@@ -13,7 +13,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_intf.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
 
 #define INTF_TIMING_ENGINE_EN           0x000
@@ -265,10 +264,7 @@ static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
        ops->get_line_count = dpu_hw_intf_get_line_count;
 }
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
                void __iomem *addr,
@@ -276,7 +272,6 @@ struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
 {
        struct dpu_hw_intf *c;
        struct dpu_intf_cfg *cfg;
-       int rc;
 
        c = kzalloc(sizeof(*c), GFP_KERNEL);
        if (!c)
@@ -297,18 +292,9 @@ struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
        c->mdss = m;
        _setup_intf_ops(&c->ops, c->cap->features);
 
-       rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_INTF, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
+       dpu_hw_blk_init(&c->base, DPU_HW_BLK_INTF, idx, &dpu_hw_ops);
 
        return c;
-
-blk_init_error:
-       kzfree(c);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_intf_destroy(struct dpu_hw_intf *intf)
index 3b77df460deaf2924279114ce4c2713187acf1b7..a2b0dbc23058b6092300fe2960cf552b2b40ed0f 100644 (file)
@@ -91,16 +91,6 @@ struct dpu_hw_intf {
        struct dpu_hw_intf_ops ops;
 };
 
-/**
- * to_dpu_hw_intf - convert base object dpu_hw_base to container
- * @hw: Pointer to base hardware block
- * return: Pointer to hardware block container
- */
-static inline struct dpu_hw_intf *to_dpu_hw_intf(struct dpu_hw_blk *hw)
-{
-       return container_of(hw, struct dpu_hw_intf, base);
-}
-
 /**
  * dpu_hw_intf_init(): Initializes the intf driver for the passed
  * interface idx.
index acb8dc8acaa59687d075f01e00480dae80992d9a..018df2c3b7ed61a016a7194883e306cff1f52ab4 100644 (file)
@@ -15,7 +15,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_lm.h"
 #include "dpu_hw_mdss.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
 
 #define LM_OP_MODE                        0x00
@@ -64,16 +63,10 @@ static struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer,
 static inline int _stage_offset(struct dpu_hw_mixer *ctx, enum dpu_stage stage)
 {
        const struct dpu_lm_sub_blks *sblk = ctx->cap->sblk;
-       int rc;
+       if (stage != DPU_STAGE_BASE && stage <= sblk->maxblendstages)
+               return sblk->blendstage_base[stage - DPU_STAGE_0];
 
-       if (stage == DPU_STAGE_BASE)
-               rc = -EINVAL;
-       else if (stage <= sblk->maxblendstages)
-               rc = sblk->blendstage_base[stage - DPU_STAGE_0];
-       else
-               rc = -EINVAL;
-
-       return rc;
+       return -EINVAL;
 }
 
 static void dpu_hw_lm_setup_out(struct dpu_hw_mixer *ctx,
@@ -163,11 +156,6 @@ static void dpu_hw_lm_setup_color3(struct dpu_hw_mixer *ctx,
        DPU_REG_WRITE(c, LM_OP_MODE, op_mode);
 }
 
-static void dpu_hw_lm_gc(struct dpu_hw_mixer *mixer,
-                       void *cfg)
-{
-}
-
 static void _setup_mixer_ops(struct dpu_mdss_cfg *m,
                struct dpu_hw_lm_ops *ops,
                unsigned long features)
@@ -179,13 +167,9 @@ static void _setup_mixer_ops(struct dpu_mdss_cfg *m,
                ops->setup_blend_config = dpu_hw_lm_setup_blend_config;
        ops->setup_alpha_out = dpu_hw_lm_setup_color3;
        ops->setup_border_color = dpu_hw_lm_setup_border_color;
-       ops->setup_gc = dpu_hw_lm_gc;
 };
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx,
                void __iomem *addr,
@@ -193,7 +177,6 @@ struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx,
 {
        struct dpu_hw_mixer *c;
        struct dpu_lm_cfg *cfg;
-       int rc;
 
        c = kzalloc(sizeof(*c), GFP_KERNEL);
        if (!c)
@@ -210,18 +193,9 @@ struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx,
        c->cap = cfg;
        _setup_mixer_ops(m, &c->ops, c->cap->features);
 
-       rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_LM, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
+       dpu_hw_blk_init(&c->base, DPU_HW_BLK_LM, idx, &dpu_hw_ops);
 
        return c;
-
-blk_init_error:
-       kzfree(c);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm)
index 5b036aca83408f11ee112cf7a7d172b1b9a67725..6aee839a6a234636eff0eec0d5f0044ab1678ed6 100644 (file)
@@ -61,11 +61,6 @@ struct dpu_hw_lm_ops {
        void (*setup_border_color)(struct dpu_hw_mixer *ctx,
                struct dpu_mdss_color *color,
                u8 border_en);
-       /**
-        * setup_gc : enable/disable gamma correction feature
-        */
-       void (*setup_gc)(struct dpu_hw_mixer *mixer,
-                       void *cfg);
 };
 
 struct dpu_hw_mixer {
index cc3a623903f4f90de1fc8d69f9ec7704139010a2..3bdf47ed1845166811e9885eaaaa9a116456699b 100644 (file)
@@ -16,7 +16,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_pingpong.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
 #include "dpu_trace.h"
 
@@ -177,7 +176,7 @@ static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp)
        height = DPU_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF;
 
        if (height < init)
-               goto line_count_exit;
+               return line;
 
        line = DPU_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF;
 
@@ -186,7 +185,6 @@ static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp)
        else
                line -= init;
 
-line_count_exit:
        return line;
 }
 
@@ -201,10 +199,7 @@ static void _setup_pingpong_ops(struct dpu_hw_pingpong_ops *ops,
        ops->get_line_count = dpu_hw_pp_get_line_count;
 };
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
                void __iomem *addr,
@@ -212,7 +207,6 @@ struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
 {
        struct dpu_hw_pingpong *c;
        struct dpu_pingpong_cfg *cfg;
-       int rc;
 
        c = kzalloc(sizeof(*c), GFP_KERNEL);
        if (!c)
@@ -228,18 +222,9 @@ struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
        c->caps = cfg;
        _setup_pingpong_ops(&c->ops, c->caps);
 
-       rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
+       dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
 
        return c;
-
-blk_init_error:
-       kzfree(c);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp)
index 3caccd7d6a3e1fa36436ddd83c62cedb1894ae81..0e02e43cee148749135b71bf8458730ffdb91b0d 100644 (file)
@@ -104,16 +104,6 @@ struct dpu_hw_pingpong {
        struct dpu_hw_pingpong_ops ops;
 };
 
-/**
- * dpu_hw_pingpong - convert base object dpu_hw_base to container
- * @hw: Pointer to base hardware block
- * return: Pointer to hardware block container
- */
-static inline struct dpu_hw_pingpong *to_dpu_hw_pingpong(struct dpu_hw_blk *hw)
-{
-       return container_of(hw, struct dpu_hw_pingpong, base);
-}
-
 /**
  * dpu_hw_pingpong_init - initializes the pingpong driver for the passed
  *     pingpong idx.
index c25b52a6b21989828cd8e76428342fd0734e1469..e9132bf5166be8ae8b044d3a514f056564547eef 100644 (file)
@@ -14,7 +14,6 @@
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_lm.h"
 #include "dpu_hw_sspp.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
 
 #define DPU_FETCH_CONFIG_RESET_VALUE   0x00000087
 /* traffic shaper clock in Hz */
 #define TS_CLK                 19200000
 
-static inline int _sspp_subblk_offset(struct dpu_hw_pipe *ctx,
+static int _sspp_subblk_offset(struct dpu_hw_pipe *ctx,
                int s_id,
                u32 *idx)
 {
@@ -662,7 +661,8 @@ static void _setup_layer_ops(struct dpu_hw_pipe *c,
                test_bit(DPU_SSPP_CSC_10BIT, &features))
                c->ops.setup_csc = dpu_hw_sspp_setup_csc;
 
-       if (dpu_hw_sspp_multirect_enabled(c->cap))
+       if (test_bit(DPU_SSPP_SMART_DMA_V1, &c->cap->features) ||
+               test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features))
                c->ops.setup_multirect = dpu_hw_sspp_setup_multirect;
 
        if (test_bit(DPU_SSPP_SCALER_QSEED3, &features)) {
@@ -697,10 +697,7 @@ static struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp,
        return ERR_PTR(-ENOMEM);
 }
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
                void __iomem *addr, struct dpu_mdss_cfg *catalog,
@@ -708,7 +705,6 @@ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
 {
        struct dpu_hw_pipe *hw_pipe;
        struct dpu_sspp_cfg *cfg;
-       int rc;
 
        if (!addr || !catalog)
                return ERR_PTR(-EINVAL);
@@ -730,18 +726,9 @@ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
        hw_pipe->cap = cfg;
        _setup_layer_ops(hw_pipe, hw_pipe->cap->features);
 
-       rc = dpu_hw_blk_init(&hw_pipe->base, DPU_HW_BLK_SSPP, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
+       dpu_hw_blk_init(&hw_pipe->base, DPU_HW_BLK_SSPP, idx, &dpu_hw_ops);
 
        return hw_pipe;
-
-blk_init_error:
-       kzfree(hw_pipe);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_sspp_destroy(struct dpu_hw_pipe *ctx)
index 4d81e5f5ce1b45974cb88c4b1fb490f4abbd5b25..119b4e1c16be752dc3e78381f694d46c36a65c4b 100644 (file)
@@ -391,16 +391,6 @@ struct dpu_hw_pipe {
        struct dpu_hw_sspp_ops ops;
 };
 
-/**
- * dpu_hw_pipe - convert base object dpu_hw_base to container
- * @hw: Pointer to base hardware block
- * return: Pointer to hardware block container
- */
-static inline struct dpu_hw_pipe *to_dpu_hw_pipe(struct dpu_hw_blk *hw)
-{
-       return container_of(hw, struct dpu_hw_pipe, base);
-}
-
 /**
  * dpu_hw_sspp_init - initializes the sspp hw driver object.
  * Should be called once before accessing every pipe.
index b8781256e21b1028c00005864a3f2c974c29e8f6..a041597bb849f79bb9577dda684a3a6db6e78918 100644 (file)
@@ -13,7 +13,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_top.h"
-#include "dpu_dbg.h"
 #include "dpu_kms.h"
 
 #define SSPP_SPARE                        0x28
@@ -322,10 +321,7 @@ static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp,
        return ERR_PTR(-EINVAL);
 }
 
-static struct dpu_hw_blk_ops dpu_hw_ops = {
-       .start = NULL,
-       .stop = NULL,
-};
+static struct dpu_hw_blk_ops dpu_hw_ops;
 
 struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx,
                void __iomem *addr,
@@ -333,7 +329,6 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx,
 {
        struct dpu_hw_mdp *mdp;
        const struct dpu_mdp_cfg *cfg;
-       int rc;
 
        if (!addr || !m)
                return ERR_PTR(-EINVAL);
@@ -355,20 +350,9 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx,
        mdp->caps = cfg;
        _setup_mdp_ops(&mdp->ops, mdp->caps->features);
 
-       rc = dpu_hw_blk_init(&mdp->base, DPU_HW_BLK_TOP, idx, &dpu_hw_ops);
-       if (rc) {
-               DPU_ERROR("failed to init hw blk %d\n", rc);
-               goto blk_init_error;
-       }
-
-       dpu_dbg_set_dpu_top_offset(mdp->hw.blk_off);
+       dpu_hw_blk_init(&mdp->base, DPU_HW_BLK_TOP, idx, &dpu_hw_ops);
 
        return mdp;
-
-blk_init_error:
-       kzfree(mdp);
-
-       return ERR_PTR(rc);
 }
 
 void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp)
index 192e338f20bbf1c8c8d9b9298d0e602ecfd980d7..aa21fd834398f065cdf76f1b37db50f98de74a90 100644 (file)
@@ -160,16 +160,6 @@ struct dpu_hw_mdp {
        struct dpu_hw_mdp_ops ops;
 };
 
-/**
- * to_dpu_hw_mdp - convert base object dpu_hw_base to container
- * @hw: Pointer to base hardware block
- * return: Pointer to hardware block container
- */
-static inline struct dpu_hw_mdp *to_dpu_hw_mdp(struct dpu_hw_blk *hw)
-{
-       return container_of(hw, struct dpu_hw_mdp, base);
-}
-
 /**
  * dpu_hw_mdptop_init - initializes the top driver for the passed idx
  * @idx:  Interface index for which driver object is required
index d43905525f92660179fdd2963023db33a817034e..38bfd222ed72a39c61cf3d4465dff18605755d12 100644 (file)
@@ -13,7 +13,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_vbif.h"
-#include "dpu_dbg.h"
 
 #define VBIF_VERSION                   0x0000
 #define VBIF_CLK_FORCE_CTRL0           0x0008
index b557687b1964e49b8fb5eec078d200a5d6ac739e..78833c2c27f850682ce45e743388fd2d744726b7 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 
+#include <drm/drm_print.h>
+
 #include "dpu_io_util.h"
 
 void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
@@ -164,7 +166,7 @@ int msm_dss_parse_clock(struct platform_device *pdev,
                                                   "clock-names", i,
                                                   &clock_name);
                if (rc) {
-                       dev_err(&pdev->dev, "Failed to get clock name for %d\n",
+                       DRM_DEV_ERROR(&pdev->dev, "Failed to get clock name for %d\n",
                                i);
                        break;
                }
@@ -176,13 +178,13 @@ int msm_dss_parse_clock(struct platform_device *pdev,
 
        rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, num_clk);
        if (rc) {
-               dev_err(&pdev->dev, "Failed to get clock refs %d\n", rc);
+               DRM_DEV_ERROR(&pdev->dev, "Failed to get clock refs %d\n", rc);
                goto err;
        }
 
        rc = of_clk_set_defaults(pdev->dev.of_node, false);
        if (rc) {
-               dev_err(&pdev->dev, "Failed to set clock defaults %d\n", rc);
+               DRM_DEV_ERROR(&pdev->dev, "Failed to set clock defaults %d\n", rc);
                goto err;
        }
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c
deleted file mode 100644 (file)
index d5e6ce0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copyright (c) 2015-2018, 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.
- */
-
-#define pr_fmt(fmt)    "[drm:%s:%d] " fmt, __func__, __LINE__
-
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-#include <linux/kthread.h>
-
-#include "dpu_irq.h"
-#include "dpu_core_irq.h"
-
-irqreturn_t dpu_irq(struct msm_kms *kms)
-{
-       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-
-       return dpu_core_irq(dpu_kms);
-}
-
-void dpu_irq_preinstall(struct msm_kms *kms)
-{
-       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-
-       if (!dpu_kms->dev || !dpu_kms->dev->dev) {
-               pr_err("invalid device handles\n");
-               return;
-       }
-
-       dpu_core_irq_preinstall(dpu_kms);
-}
-
-int dpu_irq_postinstall(struct msm_kms *kms)
-{
-       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-       int rc;
-
-       if (!kms) {
-               DPU_ERROR("invalid parameters\n");
-               return -EINVAL;
-       }
-
-       rc = dpu_core_irq_postinstall(dpu_kms);
-
-       return rc;
-}
-
-void dpu_irq_uninstall(struct msm_kms *kms)
-{
-       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-
-       if (!kms) {
-               DPU_ERROR("invalid parameters\n");
-               return;
-       }
-
-       dpu_core_irq_uninstall(dpu_kms);
-}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h
deleted file mode 100644 (file)
index 3e147f7..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Copyright (c) 2015-2018, 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 __DPU_IRQ_H__
-#define __DPU_IRQ_H__
-
-#include <linux/kernel.h>
-#include <linux/irqdomain.h>
-
-#include "msm_kms.h"
-
-/**
- * dpu_irq_controller - define MDSS level interrupt controller context
- * @enabled_mask:      enable status of MDSS level interrupt
- * @domain:            interrupt domain of this controller
- */
-struct dpu_irq_controller {
-       unsigned long enabled_mask;
-       struct irq_domain *domain;
-};
-
-/**
- * dpu_irq_preinstall - perform pre-installation of MDSS IRQ handler
- * @kms:               pointer to kms context
- * @return:            none
- */
-void dpu_irq_preinstall(struct msm_kms *kms);
-
-/**
- * dpu_irq_postinstall - perform post-installation of MDSS IRQ handler
- * @kms:               pointer to kms context
- * @return:            0 if success; error code otherwise
- */
-int dpu_irq_postinstall(struct msm_kms *kms);
-
-/**
- * dpu_irq_uninstall - uninstall MDSS IRQ handler
- * @drm_dev:           pointer to kms context
- * @return:            none
- */
-void dpu_irq_uninstall(struct msm_kms *kms);
-
-/**
- * dpu_irq - MDSS level IRQ handler
- * @kms:               pointer to kms context
- * @return:            interrupt handling status
- */
-irqreturn_t dpu_irq(struct msm_kms *kms);
-
-#endif /* __DPU_IRQ_H__ */
index 0a683e65a9f31ccb09286a85dbc9ffc51e4e808b..4d67b3c96702f93c12c1afcfc8d9615a7b5b47d2 100644 (file)
@@ -81,7 +81,7 @@ static int _dpu_danger_signal_status(struct seq_file *s,
        struct dpu_danger_safe_status status;
        int i;
 
-       if (!kms || !kms->dev || !kms->dev->dev_private || !kms->hw_mdp) {
+       if (!kms->dev || !kms->dev->dev_private || !kms->hw_mdp) {
                DPU_ERROR("invalid arg(s)\n");
                return 0;
        }
@@ -138,46 +138,29 @@ static int dpu_debugfs_safe_stats_show(struct seq_file *s, void *v)
 }
 DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_safe_stats);
 
-static void dpu_debugfs_danger_destroy(struct dpu_kms *dpu_kms)
-{
-       debugfs_remove_recursive(dpu_kms->debugfs_danger);
-       dpu_kms->debugfs_danger = NULL;
-}
-
-static int dpu_debugfs_danger_init(struct dpu_kms *dpu_kms,
+static void dpu_debugfs_danger_init(struct dpu_kms *dpu_kms,
                struct dentry *parent)
 {
-       dpu_kms->debugfs_danger = debugfs_create_dir("danger",
-                       parent);
-       if (!dpu_kms->debugfs_danger) {
-               DPU_ERROR("failed to create danger debugfs\n");
-               return -EINVAL;
-       }
+       struct dentry *entry = debugfs_create_dir("danger", parent);
+       if (IS_ERR_OR_NULL(entry))
+               return;
 
-       debugfs_create_file("danger_status", 0600, dpu_kms->debugfs_danger,
+       debugfs_create_file("danger_status", 0600, entry,
                        dpu_kms, &dpu_debugfs_danger_stats_fops);
-       debugfs_create_file("safe_status", 0600, dpu_kms->debugfs_danger,
+       debugfs_create_file("safe_status", 0600, entry,
                        dpu_kms, &dpu_debugfs_safe_stats_fops);
-
-       return 0;
 }
 
 static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data)
 {
-       struct dpu_debugfs_regset32 *regset;
-       struct dpu_kms *dpu_kms;
+       struct dpu_debugfs_regset32 *regset = s->private;
+       struct dpu_kms *dpu_kms = regset->dpu_kms;
        struct drm_device *dev;
        struct msm_drm_private *priv;
        void __iomem *base;
        uint32_t i, addr;
 
-       if (!s || !s->private)
-               return 0;
-
-       regset = s->private;
-
-       dpu_kms = regset->dpu_kms;
-       if (!dpu_kms || !dpu_kms->mmio)
+       if (!dpu_kms->mmio)
                return 0;
 
        dev = dpu_kms->dev;
@@ -250,57 +233,24 @@ void *dpu_debugfs_create_regset32(const char *name, umode_t mode,
 
 static int _dpu_debugfs_init(struct dpu_kms *dpu_kms)
 {
-       void *p;
-       int rc;
-
-       p = dpu_hw_util_get_log_mask_ptr();
+       void *p = dpu_hw_util_get_log_mask_ptr();
+       struct dentry *entry;
 
-       if (!dpu_kms || !p)
+       if (!p)
                return -EINVAL;
 
-       dpu_kms->debugfs_root = debugfs_create_dir("debug",
-                                          dpu_kms->dev->primary->debugfs_root);
-       if (IS_ERR_OR_NULL(dpu_kms->debugfs_root)) {
-               DRM_ERROR("debugfs create_dir failed %ld\n",
-                         PTR_ERR(dpu_kms->debugfs_root));
-               return PTR_ERR(dpu_kms->debugfs_root);
-       }
-
-       rc = dpu_dbg_debugfs_register(dpu_kms->debugfs_root);
-       if (rc) {
-               DRM_ERROR("failed to reg dpu dbg debugfs: %d\n", rc);
-               return rc;
-       }
+       entry = debugfs_create_dir("debug", dpu_kms->dev->primary->debugfs_root);
+       if (IS_ERR_OR_NULL(entry))
+               return -ENODEV;
 
        /* allow root to be NULL */
-       debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, dpu_kms->debugfs_root, p);
-
-       (void) dpu_debugfs_danger_init(dpu_kms, dpu_kms->debugfs_root);
-       (void) dpu_debugfs_vbif_init(dpu_kms, dpu_kms->debugfs_root);
-       (void) dpu_debugfs_core_irq_init(dpu_kms, dpu_kms->debugfs_root);
-
-       rc = dpu_core_perf_debugfs_init(&dpu_kms->perf, dpu_kms->debugfs_root);
-       if (rc) {
-               DPU_ERROR("failed to init perf %d\n", rc);
-               return rc;
-       }
+       debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p);
 
-       return 0;
-}
+       dpu_debugfs_danger_init(dpu_kms, entry);
+       dpu_debugfs_vbif_init(dpu_kms, entry);
+       dpu_debugfs_core_irq_init(dpu_kms, entry);
 
-static void _dpu_debugfs_destroy(struct dpu_kms *dpu_kms)
-{
-       /* don't need to NULL check debugfs_root */
-       if (dpu_kms) {
-               dpu_debugfs_vbif_destroy(dpu_kms);
-               dpu_debugfs_danger_destroy(dpu_kms);
-               dpu_debugfs_core_irq_destroy(dpu_kms);
-               debugfs_remove_recursive(dpu_kms->debugfs_root);
-       }
-}
-#else
-static void _dpu_debugfs_destroy(struct dpu_kms *dpu_kms)
-{
+       return dpu_core_perf_debugfs_init(dpu_kms, entry);
 }
 #endif
 
@@ -320,7 +270,10 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms,
        struct dpu_kms *dpu_kms;
        struct msm_drm_private *priv;
        struct drm_device *dev;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
        struct drm_encoder *encoder;
+       int i;
 
        if (!kms)
                return;
@@ -332,9 +285,13 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms,
        priv = dev->dev_private;
        pm_runtime_get_sync(&dpu_kms->pdev->dev);
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
-               if (encoder->crtc != NULL)
+       /* Call prepare_commit for all affected encoders */
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               drm_for_each_encoder_mask(encoder, crtc->dev,
+                                         crtc_state->encoder_mask) {
                        dpu_encoder_prepare_commit(encoder);
+               }
+       }
 }
 
 /*
@@ -344,15 +301,20 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms,
 void dpu_kms_encoder_enable(struct drm_encoder *encoder)
 {
        const struct drm_encoder_helper_funcs *funcs = encoder->helper_private;
-       struct drm_crtc *crtc = encoder->crtc;
+       struct drm_device *dev = encoder->dev;
+       struct drm_crtc *crtc;
 
        /* Forward this enable call to the commit hook */
        if (funcs && funcs->commit)
                funcs->commit(encoder);
 
-       if (crtc && crtc->state->active) {
+       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+       drm_for_each_crtc(crtc, dev) {
+               if (!(crtc->state->encoder_mask & drm_encoder_mask(encoder)))
+                       continue;
+
                trace_dpu_kms_enc_enable(DRMID(crtc));
-               dpu_crtc_commit_kickoff(crtc);
+               dpu_crtc_commit_kickoff(crtc, false);
        }
 }
 
@@ -369,7 +331,8 @@ static void dpu_kms_commit(struct msm_kms *kms, struct drm_atomic_state *state)
 
                if (crtc->state->active) {
                        trace_dpu_kms_commit(DRMID(crtc));
-                       dpu_crtc_commit_kickoff(crtc);
+                       dpu_crtc_commit_kickoff(crtc,
+                                               state->legacy_cursor_update);
                }
        }
 }
@@ -613,22 +576,7 @@ fail:
 #ifdef CONFIG_DEBUG_FS
 static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
 {
-       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
-       struct drm_device *dev;
-       int rc;
-
-       if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev) {
-               DPU_ERROR("invalid dpu_kms\n");
-               return -EINVAL;
-       }
-
-       dev = dpu_kms->dev;
-
-       rc = _dpu_debugfs_init(dpu_kms);
-       if (rc)
-               DPU_ERROR("dpu_debugfs init failed: %d\n", rc);
-
-       return rc;
+       return _dpu_debugfs_init(to_dpu_kms(kms));
 }
 #endif
 
@@ -651,12 +599,7 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)
                dpu_hw_intr_destroy(dpu_kms->hw_intr);
        dpu_kms->hw_intr = NULL;
 
-       if (dpu_kms->power_event)
-               dpu_power_handle_unregister_event(
-                               &dpu_kms->phandle, dpu_kms->power_event);
-
        /* safe to call these more than once during shutdown */
-       _dpu_debugfs_destroy(dpu_kms);
        _dpu_kms_mmu_destroy(dpu_kms);
 
        if (dpu_kms->catalog) {
@@ -676,11 +619,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)
                dpu_hw_catalog_deinit(dpu_kms->catalog);
        dpu_kms->catalog = NULL;
 
-       if (dpu_kms->core_client)
-               dpu_power_client_destroy(&dpu_kms->phandle,
-                       dpu_kms->core_client);
-       dpu_kms->core_client = NULL;
-
        if (dpu_kms->vbif[VBIF_NRT])
                devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_NRT]);
        dpu_kms->vbif[VBIF_NRT] = NULL;
@@ -705,131 +643,9 @@ static void dpu_kms_destroy(struct msm_kms *kms)
 
        dpu_kms = to_dpu_kms(kms);
 
-       dpu_dbg_destroy();
        _dpu_kms_hw_destroy(dpu_kms);
 }
 
-static int dpu_kms_pm_suspend(struct device *dev)
-{
-       struct drm_device *ddev;
-       struct drm_modeset_acquire_ctx ctx;
-       struct drm_atomic_state *state;
-       struct dpu_kms *dpu_kms;
-       int ret = 0, num_crtcs = 0;
-
-       if (!dev)
-               return -EINVAL;
-
-       ddev = dev_get_drvdata(dev);
-       if (!ddev || !ddev_to_msm_kms(ddev))
-               return -EINVAL;
-
-       dpu_kms = to_dpu_kms(ddev_to_msm_kms(ddev));
-
-       /* disable hot-plug polling */
-       drm_kms_helper_poll_disable(ddev);
-
-       /* acquire modeset lock(s) */
-       drm_modeset_acquire_init(&ctx, 0);
-
-retry:
-       DPU_ATRACE_BEGIN("kms_pm_suspend");
-
-       ret = drm_modeset_lock_all_ctx(ddev, &ctx);
-       if (ret)
-               goto unlock;
-
-       /* save current state for resume */
-       if (dpu_kms->suspend_state)
-               drm_atomic_state_put(dpu_kms->suspend_state);
-       dpu_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
-       if (IS_ERR_OR_NULL(dpu_kms->suspend_state)) {
-               DRM_ERROR("failed to back up suspend state\n");
-               dpu_kms->suspend_state = NULL;
-               goto unlock;
-       }
-
-       /* create atomic state to disable all CRTCs */
-       state = drm_atomic_state_alloc(ddev);
-       if (IS_ERR_OR_NULL(state)) {
-               DRM_ERROR("failed to allocate crtc disable state\n");
-               goto unlock;
-       }
-
-       state->acquire_ctx = &ctx;
-
-       /* check for nothing to do */
-       if (num_crtcs == 0) {
-               DRM_DEBUG("all crtcs are already in the off state\n");
-               drm_atomic_state_put(state);
-               goto suspended;
-       }
-
-       /* commit the "disable all" state */
-       ret = drm_atomic_commit(state);
-       if (ret < 0) {
-               DRM_ERROR("failed to disable crtcs, %d\n", ret);
-               drm_atomic_state_put(state);
-               goto unlock;
-       }
-
-suspended:
-       dpu_kms->suspend_block = true;
-
-unlock:
-       if (ret == -EDEADLK) {
-               drm_modeset_backoff(&ctx);
-               goto retry;
-       }
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-
-       DPU_ATRACE_END("kms_pm_suspend");
-       return 0;
-}
-
-static int dpu_kms_pm_resume(struct device *dev)
-{
-       struct drm_device *ddev;
-       struct dpu_kms *dpu_kms;
-       int ret;
-
-       if (!dev)
-               return -EINVAL;
-
-       ddev = dev_get_drvdata(dev);
-       if (!ddev || !ddev_to_msm_kms(ddev))
-               return -EINVAL;
-
-       dpu_kms = to_dpu_kms(ddev_to_msm_kms(ddev));
-
-       DPU_ATRACE_BEGIN("kms_pm_resume");
-
-       drm_mode_config_reset(ddev);
-
-       drm_modeset_lock_all(ddev);
-
-       dpu_kms->suspend_block = false;
-
-       if (dpu_kms->suspend_state) {
-               dpu_kms->suspend_state->acquire_ctx =
-                       ddev->mode_config.acquire_ctx;
-               ret = drm_atomic_commit(dpu_kms->suspend_state);
-               if (ret < 0) {
-                       DRM_ERROR("failed to restore state, %d\n", ret);
-                       drm_atomic_state_put(dpu_kms->suspend_state);
-               }
-               dpu_kms->suspend_state = NULL;
-       }
-       drm_modeset_unlock_all(ddev);
-
-       /* enable hot-plug polling */
-       drm_kms_helper_poll_enable(ddev);
-
-       DPU_ATRACE_END("kms_pm_resume");
-       return 0;
-}
-
 static void _dpu_kms_set_encoder_mode(struct msm_kms *kms,
                                 struct drm_encoder *encoder,
                                 bool cmd_mode)
@@ -858,10 +674,30 @@ static void _dpu_kms_set_encoder_mode(struct msm_kms *kms,
                        encoder->base.id, rc);
 }
 
+static irqreturn_t dpu_irq(struct msm_kms *kms)
+{
+       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
+
+       return dpu_core_irq(dpu_kms);
+}
+
+static void dpu_irq_preinstall(struct msm_kms *kms)
+{
+       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
+
+       dpu_core_irq_preinstall(dpu_kms);
+}
+
+static void dpu_irq_uninstall(struct msm_kms *kms)
+{
+       struct dpu_kms *dpu_kms = to_dpu_kms(kms);
+
+       dpu_core_irq_uninstall(dpu_kms);
+}
+
 static const struct msm_kms_funcs kms_funcs = {
        .hw_init         = dpu_kms_hw_init,
        .irq_preinstall  = dpu_irq_preinstall,
-       .irq_postinstall = dpu_irq_postinstall,
        .irq_uninstall   = dpu_irq_uninstall,
        .irq             = dpu_irq,
        .prepare_commit  = dpu_kms_prepare_commit,
@@ -873,8 +709,6 @@ static const struct msm_kms_funcs kms_funcs = {
        .check_modified_format = dpu_format_check_modified_format,
        .get_format      = dpu_get_msm_format,
        .round_pixclk    = dpu_kms_round_pixclk,
-       .pm_suspend      = dpu_kms_pm_suspend,
-       .pm_resume       = dpu_kms_pm_resume,
        .destroy         = dpu_kms_destroy,
        .set_encoder_mode = _dpu_kms_set_encoder_mode,
 #ifdef CONFIG_DEBUG_FS
@@ -882,12 +716,6 @@ static const struct msm_kms_funcs kms_funcs = {
 #endif
 };
 
-/* the caller api needs to turn on clock before calling it */
-static inline void _dpu_kms_core_hw_rev_init(struct dpu_kms *dpu_kms)
-{
-       dpu_kms->core_rev = readl_relaxed(dpu_kms->mmio + 0x0);
-}
-
 static int _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms)
 {
        struct msm_mmu *mmu;
@@ -911,6 +739,9 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
        if (!domain)
                return 0;
 
+       domain->geometry.aperture_start = 0x1000;
+       domain->geometry.aperture_end = 0xffffffff;
+
        aspace = msm_gem_address_space_create(dpu_kms->dev->dev,
                        domain, "dpu1");
        if (IS_ERR(aspace)) {
@@ -960,16 +791,6 @@ u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name)
        return clk_get_rate(clk->clk);
 }
 
-static void dpu_kms_handle_power_event(u32 event_type, void *usr)
-{
-       struct dpu_kms *dpu_kms = usr;
-
-       if (!dpu_kms)
-               return;
-
-       dpu_vbif_init_memtypes(dpu_kms);
-}
-
 static int dpu_kms_hw_init(struct msm_kms *kms)
 {
        struct dpu_kms *dpu_kms;
@@ -979,26 +800,20 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
 
        if (!kms) {
                DPU_ERROR("invalid kms\n");
-               goto end;
+               return rc;
        }
 
        dpu_kms = to_dpu_kms(kms);
        dev = dpu_kms->dev;
        if (!dev) {
                DPU_ERROR("invalid device\n");
-               goto end;
-       }
-
-       rc = dpu_dbg_init(&dpu_kms->pdev->dev);
-       if (rc) {
-               DRM_ERROR("failed to init dpu dbg: %d\n", rc);
-               goto end;
+               return rc;
        }
 
        priv = dev->dev_private;
        if (!priv) {
                DPU_ERROR("invalid private data\n");
-               goto dbg_destroy;
+               return rc;
        }
 
        dpu_kms->mmio = msm_ioremap(dpu_kms->pdev, "mdp", "mdp");
@@ -1036,20 +851,9 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
                dpu_kms->reg_dma_len = dpu_iomap_size(dpu_kms->pdev, "regdma");
        }
 
-       dpu_kms->core_client = dpu_power_client_create(&dpu_kms->phandle,
-                                       "core");
-       if (IS_ERR_OR_NULL(dpu_kms->core_client)) {
-               rc = PTR_ERR(dpu_kms->core_client);
-               if (!dpu_kms->core_client)
-                       rc = -EINVAL;
-               DPU_ERROR("dpu power client create failed: %d\n", rc);
-               dpu_kms->core_client = NULL;
-               goto error;
-       }
-
        pm_runtime_get_sync(&dpu_kms->pdev->dev);
 
-       _dpu_kms_core_hw_rev_init(dpu_kms);
+       dpu_kms->core_rev = readl_relaxed(dpu_kms->mmio + 0x0);
 
        pr_info("dpu hardware revision:0x%x\n", dpu_kms->core_rev);
 
@@ -1063,8 +867,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
                goto power_error;
        }
 
-       dpu_dbg_init_dbg_buses(dpu_kms->core_rev);
-
        /*
         * Now we need to read the HW catalog and initialize resources such as
         * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc
@@ -1110,7 +912,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
        }
 
        rc = dpu_core_perf_init(&dpu_kms->perf, dev, dpu_kms->catalog,
-                       &dpu_kms->phandle,
                        _dpu_kms_get_clk(dpu_kms, "core"));
        if (rc) {
                DPU_ERROR("failed to init perf %d\n", rc);
@@ -1151,13 +952,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
         */
        dev->mode_config.allow_fb_modifiers = true;
 
-       /*
-        * Handle (re)initializations during power enable
-        */
-       dpu_kms_handle_power_event(DPU_POWER_EVENT_ENABLE, dpu_kms);
-       dpu_kms->power_event = dpu_power_handle_register_event(
-                       &dpu_kms->phandle, DPU_POWER_EVENT_ENABLE,
-                       dpu_kms_handle_power_event, dpu_kms, "kms");
+       dpu_vbif_init_memtypes(dpu_kms);
 
        pm_runtime_put_sync(&dpu_kms->pdev->dev);
 
@@ -1171,9 +966,7 @@ power_error:
        pm_runtime_put_sync(&dpu_kms->pdev->dev);
 error:
        _dpu_kms_hw_destroy(dpu_kms);
-dbg_destroy:
-       dpu_dbg_destroy();
-end:
+
        return rc;
 }
 
@@ -1221,8 +1014,6 @@ static int dpu_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       dpu_power_resource_init(pdev, &dpu_kms->phandle);
-
        platform_set_drvdata(pdev, dpu_kms);
 
        msm_kms_init(&dpu_kms->base, &kms_funcs);
@@ -1242,7 +1033,6 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data)
        struct dpu_kms *dpu_kms = platform_get_drvdata(pdev);
        struct dss_module_power *mp = &dpu_kms->mp;
 
-       dpu_power_resource_deinit(pdev, &dpu_kms->phandle);
        msm_dss_put_clk(mp->clk_config, mp->num_clk);
        devm_kfree(&pdev->dev, mp->clk_config);
        mp->num_clk = 0;
@@ -1278,19 +1068,13 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev)
        ddev = dpu_kms->dev;
        if (!ddev) {
                DPU_ERROR("invalid drm_device\n");
-               goto exit;
+               return rc;
        }
 
-       rc = dpu_power_resource_enable(&dpu_kms->phandle,
-                       dpu_kms->core_client, false);
-       if (rc)
-               DPU_ERROR("resource disable failed: %d\n", rc);
-
        rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false);
        if (rc)
                DPU_ERROR("clock disable failed rc:%d\n", rc);
 
-exit:
        return rc;
 }
 
@@ -1299,27 +1083,27 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev)
        int rc = -1;
        struct platform_device *pdev = to_platform_device(dev);
        struct dpu_kms *dpu_kms = platform_get_drvdata(pdev);
+       struct drm_encoder *encoder;
        struct drm_device *ddev;
        struct dss_module_power *mp = &dpu_kms->mp;
 
        ddev = dpu_kms->dev;
        if (!ddev) {
                DPU_ERROR("invalid drm_device\n");
-               goto exit;
+               return rc;
        }
 
        rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true);
        if (rc) {
                DPU_ERROR("clock enable failed rc:%d\n", rc);
-               goto exit;
+               return rc;
        }
 
-       rc = dpu_power_resource_enable(&dpu_kms->phandle,
-                       dpu_kms->core_client, true);
-       if (rc)
-               DPU_ERROR("resource enable failed: %d\n", rc);
+       dpu_vbif_init_memtypes(dpu_kms);
+
+       drm_for_each_encoder(encoder, ddev)
+               dpu_encoder_virt_runtime_resume(encoder);
 
-exit:
        return rc;
 }
 
index 66d466628e2b90de86ba6d331678efcdedba5c77..ac75cfc267f40fe071db92554de0db7885b4b0c5 100644 (file)
 #include "msm_kms.h"
 #include "msm_mmu.h"
 #include "msm_gem.h"
-#include "dpu_dbg.h"
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_lm.h"
 #include "dpu_hw_interrupts.h"
 #include "dpu_hw_top.h"
+#include "dpu_io_util.h"
 #include "dpu_rm.h"
-#include "dpu_power_handle.h"
-#include "dpu_irq.h"
 #include "dpu_core_perf.h"
 
 #define DRMID(x) ((x) ? (x)->base.id : -1)
@@ -104,7 +102,6 @@ struct dpu_irq {
        atomic_t *enable_counts;
        atomic_t *irq_counts;
        spinlock_t cb_lock;
-       struct dentry *debugfs_file;
 };
 
 struct dpu_kms {
@@ -113,15 +110,6 @@ struct dpu_kms {
        int core_rev;
        struct dpu_mdss_cfg *catalog;
 
-       struct dpu_power_handle phandle;
-       struct dpu_power_client *core_client;
-       struct dpu_power_event *power_event;
-
-       /* directory entry for debugfs */
-       struct dentry *debugfs_root;
-       struct dentry *debugfs_danger;
-       struct dentry *debugfs_vbif;
-
        /* io/register spaces: */
        void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma;
        unsigned long mmio_len, vbif_len[VBIF_MAX], reg_dma_len;
@@ -135,10 +123,6 @@ struct dpu_kms {
 
        struct dpu_core_perf perf;
 
-       /* saved atomic state during system suspend */
-       struct drm_atomic_state *suspend_state;
-       bool suspend_block;
-
        struct dpu_rm rm;
        bool rm_init;
 
@@ -163,33 +147,6 @@ struct vsync_info {
 #define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \
                ((struct msm_drm_private *)((D)->dev_private))->kms : NULL)
 
-/**
- * dpu_kms_is_suspend_state - whether or not the system is pm suspended
- * @dev: Pointer to drm device
- * Return: Suspend status
- */
-static inline bool dpu_kms_is_suspend_state(struct drm_device *dev)
-{
-       if (!ddev_to_msm_kms(dev))
-               return false;
-
-       return to_dpu_kms(ddev_to_msm_kms(dev))->suspend_state != NULL;
-}
-
-/**
- * dpu_kms_is_suspend_blocked - whether or not commits are blocked due to pm
- *                             suspend status
- * @dev: Pointer to drm device
- * Return: True if commits should be rejected due to pm suspend
- */
-static inline bool dpu_kms_is_suspend_blocked(struct drm_device *dev)
-{
-       if (!dpu_kms_is_suspend_state(dev))
-               return false;
-
-       return to_dpu_kms(ddev_to_msm_kms(dev))->suspend_block;
-}
-
 /**
  * Debugfs functions - extra helper functions for debugfs support
  *
index 2235ef8129f4b02e85e0779ef52429fbf3f29836..cb307a2abf06c6136976f861e28525a244a34882 100644 (file)
@@ -9,6 +9,11 @@
 
 #define HW_INTR_STATUS                 0x0010
 
+struct dpu_irq_controller {
+       unsigned long enabled_mask;
+       struct irq_domain *domain;
+};
+
 struct dpu_mdss {
        struct msm_mdss base;
        void __iomem *mmio;
@@ -115,13 +120,12 @@ static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss)
        return 0;
 }
 
-static int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss)
+static void _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss)
 {
        if (dpu_mdss->irq_controller.domain) {
                irq_domain_remove(dpu_mdss->irq_controller.domain);
                dpu_mdss->irq_controller.domain = NULL;
        }
-       return 0;
 }
 static int dpu_mdss_enable(struct msm_mdss *mdss)
 {
@@ -156,18 +160,16 @@ static void dpu_mdss_destroy(struct drm_device *dev)
        struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss);
        struct dss_module_power *mp = &dpu_mdss->mp;
 
+       pm_runtime_suspend(dev->dev);
+       pm_runtime_disable(dev->dev);
        _dpu_mdss_irq_domain_fini(dpu_mdss);
-
        free_irq(platform_get_irq(pdev, 0), dpu_mdss);
-
        msm_dss_put_clk(mp->clk_config, mp->num_clk);
        devm_kfree(&pdev->dev, mp->clk_config);
 
        if (dpu_mdss->mmio)
                devm_iounmap(&pdev->dev, dpu_mdss->mmio);
        dpu_mdss->mmio = NULL;
-
-       pm_runtime_disable(dev->dev);
        priv->mdss = NULL;
 }
 
index f549daf30fe6d39b2c2f3e78f145f14d50db9a40..fd75870eb17f7c7d5e8f8446f526b19715042b03 100644 (file)
@@ -137,7 +137,7 @@ static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane)
  * @src_wdith:         width of source buffer
  * Return: fill level corresponding to the source buffer/format or 0 if error
  */
-static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane,
+static int _dpu_plane_calc_fill_level(struct drm_plane *plane,
                const struct dpu_format *fmt, u32 src_width)
 {
        struct dpu_plane *pdpu, *tmp;
@@ -430,24 +430,14 @@ static void _dpu_plane_set_qos_remap(struct drm_plane *plane)
        dpu_vbif_set_qos_remap(dpu_kms, &qos_params);
 }
 
-/**
- * _dpu_plane_get_aspace: gets the address space
- */
-static inline struct msm_gem_address_space *_dpu_plane_get_aspace(
-               struct dpu_plane *pdpu)
-{
-       struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
-
-       return kms->base.aspace;
-}
-
-static inline void _dpu_plane_set_scanout(struct drm_plane *plane,
+static void _dpu_plane_set_scanout(struct drm_plane *plane,
                struct dpu_plane_state *pstate,
                struct dpu_hw_pipe_cfg *pipe_cfg,
                struct drm_framebuffer *fb)
 {
        struct dpu_plane *pdpu = to_dpu_plane(plane);
-       struct msm_gem_address_space *aspace = _dpu_plane_get_aspace(pdpu);
+       struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
+       struct msm_gem_address_space *aspace = kms->base.aspace;
        int ret;
 
        ret = dpu_format_populate_layout(aspace, fb, &pipe_cfg->layout);
@@ -525,7 +515,7 @@ static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu,
        scale_cfg->enable = 1;
 }
 
-static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
+static void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
 {
        static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = {
                {
@@ -801,7 +791,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane,
        struct drm_gem_object *obj;
        struct msm_gem_object *msm_obj;
        struct dma_fence *fence;
-       struct msm_gem_address_space *aspace = _dpu_plane_get_aspace(pdpu);
+       struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
        int ret;
 
        if (!new_state->fb)
@@ -810,7 +800,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane,
        DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id);
 
        /* cache aspace */
-       pstate->aspace = aspace;
+       pstate->aspace = kms->base.aspace;
 
        /*
         * TODO: Need to sort out the msm_framebuffer_prepare() call below so
@@ -1179,8 +1169,6 @@ static void dpu_plane_destroy(struct drm_plane *plane)
 
                mutex_destroy(&pdpu->lock);
 
-               drm_plane_helper_disable(plane, NULL);
-
                /* this will destroy the states as well */
                drm_plane_cleanup(plane);
 
@@ -1193,19 +1181,8 @@ static void dpu_plane_destroy(struct drm_plane *plane)
 static void dpu_plane_destroy_state(struct drm_plane *plane,
                struct drm_plane_state *state)
 {
-       struct dpu_plane_state *pstate;
-
-       if (!plane || !state) {
-               DPU_ERROR("invalid arg(s), plane %d state %d\n",
-                               plane != 0, state != 0);
-               return;
-       }
-
-       pstate = to_dpu_plane_state(state);
-
        __drm_atomic_helper_plane_destroy_state(state);
-
-       kfree(pstate);
+       kfree(to_dpu_plane_state(state));
 }
 
 static struct drm_plane_state *
@@ -1275,26 +1252,12 @@ static ssize_t _dpu_plane_danger_read(struct file *file,
                        char __user *buff, size_t count, loff_t *ppos)
 {
        struct dpu_kms *kms = file->private_data;
-       struct dpu_mdss_cfg *cfg = kms->catalog;
-       int len = 0;
-       char buf[40] = {'\0'};
-
-       if (!cfg)
-               return -ENODEV;
-
-       if (*ppos)
-               return 0; /* the end */
+       int len;
+       char buf[40];
 
-       len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
-       if (len < 0 || len >= sizeof(buf))
-               return 0;
-
-       if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
-               return -EFAULT;
+       len = scnprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
 
-       *ppos += len;   /* increase offset */
-
-       return len;
+       return simple_read_from_buffer(buff, count, ppos, buf, len);
 }
 
 static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable)
@@ -1324,23 +1287,12 @@ static ssize_t _dpu_plane_danger_write(struct file *file,
                    const char __user *user_buf, size_t count, loff_t *ppos)
 {
        struct dpu_kms *kms = file->private_data;
-       struct dpu_mdss_cfg *cfg = kms->catalog;
        int disable_panic;
-       char buf[10];
-
-       if (!cfg)
-               return -EFAULT;
-
-       if (count >= sizeof(buf))
-               return -EFAULT;
-
-       if (copy_from_user(buf, user_buf, count))
-               return -EFAULT;
-
-       buf[count] = 0; /* end of string */
+       int ret;
 
-       if (kstrtoint(buf, 0, &disable_panic))
-               return -EFAULT;
+       ret = kstrtouint_from_user(user_buf, count, 0, &disable_panic);
+       if (ret)
+               return ret;
 
        if (disable_panic) {
                /* Disable panic signal for all active pipes */
@@ -1365,33 +1317,10 @@ static const struct file_operations dpu_plane_danger_enable = {
 
 static int _dpu_plane_init_debugfs(struct drm_plane *plane)
 {
-       struct dpu_plane *pdpu;
-       struct dpu_kms *kms;
-       struct msm_drm_private *priv;
-       const struct dpu_sspp_sub_blks *sblk = 0;
-       const struct dpu_sspp_cfg *cfg = 0;
-
-       if (!plane || !plane->dev) {
-               DPU_ERROR("invalid arguments\n");
-               return -EINVAL;
-       }
-
-       priv = plane->dev->dev_private;
-       if (!priv || !priv->kms) {
-               DPU_ERROR("invalid KMS reference\n");
-               return -EINVAL;
-       }
-
-       kms = to_dpu_kms(priv->kms);
-       pdpu = to_dpu_plane(plane);
-
-       if (pdpu && pdpu->pipe_hw)
-               cfg = pdpu->pipe_hw->cap;
-       if (cfg)
-               sblk = cfg->sblk;
-
-       if (!sblk)
-               return 0;
+       struct dpu_plane *pdpu = to_dpu_plane(plane);
+       struct dpu_kms *kms = _dpu_plane_get_kms(plane);
+       const struct dpu_sspp_cfg *cfg = pdpu->pipe_hw->cap;
+       const struct dpu_sspp_sub_blks *sblk = cfg->sblk;
 
        /* create overall sub-directory for the pipe */
        pdpu->debugfs_root =
@@ -1462,25 +1391,11 @@ static int _dpu_plane_init_debugfs(struct drm_plane *plane)
 
        return 0;
 }
-
-static void _dpu_plane_destroy_debugfs(struct drm_plane *plane)
-{
-       struct dpu_plane *pdpu;
-
-       if (!plane)
-               return;
-       pdpu = to_dpu_plane(plane);
-
-       debugfs_remove_recursive(pdpu->debugfs_root);
-}
 #else
 static int _dpu_plane_init_debugfs(struct drm_plane *plane)
 {
        return 0;
 }
-static void _dpu_plane_destroy_debugfs(struct drm_plane *plane)
-{
-}
 #endif
 
 static int dpu_plane_late_register(struct drm_plane *plane)
@@ -1490,7 +1405,9 @@ static int dpu_plane_late_register(struct drm_plane *plane)
 
 static void dpu_plane_early_unregister(struct drm_plane *plane)
 {
-       _dpu_plane_destroy_debugfs(plane);
+       struct dpu_plane *pdpu = to_dpu_plane(plane);
+
+       debugfs_remove_recursive(pdpu->debugfs_root);
 }
 
 static const struct drm_plane_funcs dpu_plane_funcs = {
@@ -1539,7 +1456,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
        if (!pdpu) {
                DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe);
                ret = -ENOMEM;
-               goto exit;
+               return ERR_PTR(ret);
        }
 
        /* cache local stuff for later */
@@ -1625,6 +1542,5 @@ clean_sspp:
                dpu_hw_sspp_destroy(pdpu->pipe_hw);
 clean_plane:
        kfree(pdpu);
-exit:
        return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c
deleted file mode 100644 (file)
index fc14116..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/* Copyright (c) 2014-2018, 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.
- *
- */
-
-#define pr_fmt(fmt)    "[drm:%s:%d]: " fmt, __func__, __LINE__
-
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/string.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/of_platform.h>
-
-#include "dpu_power_handle.h"
-#include "dpu_trace.h"
-
-static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = {
-       [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus",
-       [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus",
-       [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus",
-};
-
-const char *dpu_power_handle_get_dbus_name(u32 bus_id)
-{
-       if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX)
-               return data_bus_name[bus_id];
-
-       return NULL;
-}
-
-static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle,
-               u32 event_type)
-{
-       struct dpu_power_event *event;
-
-       list_for_each_entry(event, &phandle->event_list, list) {
-               if (event->event_type & event_type)
-                       event->cb_fnc(event_type, event->usr);
-       }
-}
-
-struct dpu_power_client *dpu_power_client_create(
-       struct dpu_power_handle *phandle, char *client_name)
-{
-       struct dpu_power_client *client;
-       static u32 id;
-
-       if (!client_name || !phandle) {
-               pr_err("client name is null or invalid power data\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL);
-       if (!client)
-               return ERR_PTR(-ENOMEM);
-
-       mutex_lock(&phandle->phandle_lock);
-       strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
-       client->usecase_ndx = VOTE_INDEX_DISABLE;
-       client->id = id;
-       client->active = true;
-       pr_debug("client %s created:%pK id :%d\n", client_name,
-               client, id);
-       id++;
-       list_add(&client->list, &phandle->power_client_clist);
-       mutex_unlock(&phandle->phandle_lock);
-
-       return client;
-}
-
-void dpu_power_client_destroy(struct dpu_power_handle *phandle,
-       struct dpu_power_client *client)
-{
-       if (!client  || !phandle) {
-               pr_err("reg bus vote: invalid client handle\n");
-       } else if (!client->active) {
-               pr_err("dpu power deinit already done\n");
-               kfree(client);
-       } else {
-               pr_debug("bus vote client %s destroyed:%pK id:%u\n",
-                       client->name, client, client->id);
-               mutex_lock(&phandle->phandle_lock);
-               list_del_init(&client->list);
-               mutex_unlock(&phandle->phandle_lock);
-               kfree(client);
-       }
-}
-
-void dpu_power_resource_init(struct platform_device *pdev,
-       struct dpu_power_handle *phandle)
-{
-       phandle->dev = &pdev->dev;
-
-       INIT_LIST_HEAD(&phandle->power_client_clist);
-       INIT_LIST_HEAD(&phandle->event_list);
-
-       mutex_init(&phandle->phandle_lock);
-}
-
-void dpu_power_resource_deinit(struct platform_device *pdev,
-       struct dpu_power_handle *phandle)
-{
-       struct dpu_power_client *curr_client, *next_client;
-       struct dpu_power_event *curr_event, *next_event;
-
-       if (!phandle || !pdev) {
-               pr_err("invalid input param\n");
-               return;
-       }
-
-       mutex_lock(&phandle->phandle_lock);
-       list_for_each_entry_safe(curr_client, next_client,
-                       &phandle->power_client_clist, list) {
-               pr_err("client:%s-%d still registered with refcount:%d\n",
-                               curr_client->name, curr_client->id,
-                               curr_client->refcount);
-               curr_client->active = false;
-               list_del(&curr_client->list);
-       }
-
-       list_for_each_entry_safe(curr_event, next_event,
-                       &phandle->event_list, list) {
-               pr_err("event:%d, client:%s still registered\n",
-                               curr_event->event_type,
-                               curr_event->client_name);
-               curr_event->active = false;
-               list_del(&curr_event->list);
-       }
-       mutex_unlock(&phandle->phandle_lock);
-}
-
-int dpu_power_resource_enable(struct dpu_power_handle *phandle,
-       struct dpu_power_client *pclient, bool enable)
-{
-       bool changed = false;
-       u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx;
-       struct dpu_power_client *client;
-       u32 event_type;
-
-       if (!phandle || !pclient) {
-               pr_err("invalid input argument\n");
-               return -EINVAL;
-       }
-
-       mutex_lock(&phandle->phandle_lock);
-       if (enable)
-               pclient->refcount++;
-       else if (pclient->refcount)
-               pclient->refcount--;
-
-       if (pclient->refcount)
-               pclient->usecase_ndx = VOTE_INDEX_LOW;
-       else
-               pclient->usecase_ndx = VOTE_INDEX_DISABLE;
-
-       list_for_each_entry(client, &phandle->power_client_clist, list) {
-               if (client->usecase_ndx < VOTE_INDEX_MAX &&
-                   client->usecase_ndx > max_usecase_ndx)
-                       max_usecase_ndx = client->usecase_ndx;
-       }
-
-       if (phandle->current_usecase_ndx != max_usecase_ndx) {
-               changed = true;
-               prev_usecase_ndx = phandle->current_usecase_ndx;
-               phandle->current_usecase_ndx = max_usecase_ndx;
-       }
-
-       pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n",
-               __builtin_return_address(0), changed, max_usecase_ndx,
-               pclient->name, pclient->id, enable, pclient->refcount);
-
-       if (!changed)
-               goto end;
-
-       event_type = enable ? DPU_POWER_EVENT_ENABLE : DPU_POWER_EVENT_DISABLE;
-
-       dpu_power_event_trigger_locked(phandle, event_type);
-end:
-       mutex_unlock(&phandle->phandle_lock);
-       return 0;
-}
-
-struct dpu_power_event *dpu_power_handle_register_event(
-               struct dpu_power_handle *phandle,
-               u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
-               void *usr, char *client_name)
-{
-       struct dpu_power_event *event;
-
-       if (!phandle) {
-               pr_err("invalid power handle\n");
-               return ERR_PTR(-EINVAL);
-       } else if (!cb_fnc || !event_type) {
-               pr_err("no callback fnc or event type\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL);
-       if (!event)
-               return ERR_PTR(-ENOMEM);
-
-       event->event_type = event_type;
-       event->cb_fnc = cb_fnc;
-       event->usr = usr;
-       strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
-       event->active = true;
-
-       mutex_lock(&phandle->phandle_lock);
-       list_add(&event->list, &phandle->event_list);
-       mutex_unlock(&phandle->phandle_lock);
-
-       return event;
-}
-
-void dpu_power_handle_unregister_event(
-               struct dpu_power_handle *phandle,
-               struct dpu_power_event *event)
-{
-       if (!phandle || !event) {
-               pr_err("invalid phandle or event\n");
-       } else if (!event->active) {
-               pr_err("power handle deinit already done\n");
-               kfree(event);
-       } else {
-               mutex_lock(&phandle->phandle_lock);
-               list_del_init(&event->list);
-               mutex_unlock(&phandle->phandle_lock);
-               kfree(event);
-       }
-}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h
deleted file mode 100644 (file)
index a65b7a2..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/* Copyright (c) 2016-2018, 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 _DPU_POWER_HANDLE_H_
-#define _DPU_POWER_HANDLE_H_
-
-#define MAX_CLIENT_NAME_LEN 128
-
-#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA   0
-#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA  0
-#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA   1600000000
-#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA  0
-
-#include "dpu_io_util.h"
-
-/* events will be triggered on power handler enable/disable */
-#define DPU_POWER_EVENT_DISABLE        BIT(0)
-#define DPU_POWER_EVENT_ENABLE BIT(1)
-
-/**
- * mdss_bus_vote_type: register bus vote type
- * VOTE_INDEX_DISABLE: removes the client vote
- * VOTE_INDEX_LOW: keeps the lowest vote for register bus
- * VOTE_INDEX_MAX: invalid
- */
-enum mdss_bus_vote_type {
-       VOTE_INDEX_DISABLE,
-       VOTE_INDEX_LOW,
-       VOTE_INDEX_MAX,
-};
-
-/**
- * enum dpu_power_handle_data_bus_client - type of axi bus clients
- * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client
- * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client
- * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type
- */
-enum dpu_power_handle_data_bus_client {
-       DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT,
-       DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT,
-       DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX
-};
-
-/**
- * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier
- * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus
- * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus
- * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus
- */
-enum DPU_POWER_HANDLE_DBUS_ID {
-       DPU_POWER_HANDLE_DBUS_ID_MNOC,
-       DPU_POWER_HANDLE_DBUS_ID_LLCC,
-       DPU_POWER_HANDLE_DBUS_ID_EBI,
-       DPU_POWER_HANDLE_DBUS_ID_MAX,
-};
-
-/**
- * struct dpu_power_client: stores the power client for dpu driver
- * @name:      name of the client
- * @usecase_ndx: current regs bus vote type
- * @refcount:  current refcount if multiple modules are using same
- *              same client for enable/disable. Power module will
- *              aggregate the refcount and vote accordingly for this
- *              client.
- * @id:                assigned during create. helps for debugging.
- * @list:      list to attach power handle master list
- * @ab:         arbitrated bandwidth for each bus client
- * @ib:         instantaneous bandwidth for each bus client
- * @active:    inidcates the state of dpu power handle
- */
-struct dpu_power_client {
-       char name[MAX_CLIENT_NAME_LEN];
-       short usecase_ndx;
-       short refcount;
-       u32 id;
-       struct list_head list;
-       u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
-       u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
-       bool active;
-};
-
-/*
- * struct dpu_power_event - local event registration structure
- * @client_name: name of the client registering
- * @cb_fnc: pointer to desired callback function
- * @usr: user pointer to pass to callback event trigger
- * @event: refer to DPU_POWER_HANDLE_EVENT_*
- * @list: list to attach event master list
- * @active: indicates the state of dpu power handle
- */
-struct dpu_power_event {
-       char client_name[MAX_CLIENT_NAME_LEN];
-       void (*cb_fnc)(u32 event_type, void *usr);
-       void *usr;
-       u32 event_type;
-       struct list_head list;
-       bool active;
-};
-
-/**
- * struct dpu_power_handle: power handle main struct
- * @client_clist: master list to store all clients
- * @phandle_lock: lock to synchronize the enable/disable
- * @dev: pointer to device structure
- * @usecase_ndx: current usecase index
- * @event_list: current power handle event list
- */
-struct dpu_power_handle {
-       struct list_head power_client_clist;
-       struct mutex phandle_lock;
-       struct device *dev;
-       u32 current_usecase_ndx;
-       struct list_head event_list;
-};
-
-/**
- * dpu_power_resource_init() - initializes the dpu power handle
- * @pdev:   platform device to search the power resources
- * @pdata:  power handle to store the power resources
- */
-void dpu_power_resource_init(struct platform_device *pdev,
-       struct dpu_power_handle *pdata);
-
-/**
- * dpu_power_resource_deinit() - release the dpu power handle
- * @pdev:   platform device for power resources
- * @pdata:  power handle containing the resources
- *
- * Return: error code.
- */
-void dpu_power_resource_deinit(struct platform_device *pdev,
-       struct dpu_power_handle *pdata);
-
-/**
- * dpu_power_client_create() - create the client on power handle
- * @pdata:  power handle containing the resources
- * @client_name: new client name for registration
- *
- * Return: error code.
- */
-struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata,
-       char *client_name);
-
-/**
- * dpu_power_client_destroy() - destroy the client on power handle
- * @pdata:  power handle containing the resources
- * @client_name: new client name for registration
- *
- * Return: none
- */
-void dpu_power_client_destroy(struct dpu_power_handle *phandle,
-       struct dpu_power_client *client);
-
-/**
- * dpu_power_resource_enable() - enable/disable the power resources
- * @pdata:  power handle containing the resources
- * @client: client information to enable/disable its vote
- * @enable: boolean request for enable/disable
- *
- * Return: error code.
- */
-int dpu_power_resource_enable(struct dpu_power_handle *pdata,
-       struct dpu_power_client *pclient, bool enable);
-
-/**
- * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable
- * @phandle:  power handle containing the resources
- * @client: client information to bandwidth control
- * @enable: true to enable bandwidth for data base
- *
- * Return: none
- */
-void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle,
-               struct dpu_power_client *pclient, int enable);
-
-/**
- * dpu_power_handle_register_event - register a callback function for an event.
- *     Clients can register for multiple events with a single register.
- *     Any block with access to phandle can register for the event
- *     notification.
- * @phandle:   power handle containing the resources
- * @event_type:        event type to register; refer DPU_POWER_HANDLE_EVENT_*
- * @cb_fnc:    pointer to desired callback function
- * @usr:       user pointer to pass to callback on event trigger
- *
- * Return:     event pointer if success, or error code otherwise
- */
-struct dpu_power_event *dpu_power_handle_register_event(
-               struct dpu_power_handle *phandle,
-               u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
-               void *usr, char *client_name);
-/**
- * dpu_power_handle_unregister_event - unregister callback for event(s)
- * @phandle:   power handle containing the resources
- * @event:     event pointer returned after power handle register
- */
-void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle,
-               struct dpu_power_event *event);
-
-/**
- * dpu_power_handle_get_dbus_name - get name of given data bus identifier
- * @bus_id:    data bus identifier
- * Return:     Pointer to name string if success; NULL otherwise
- */
-const char *dpu_power_handle_get_dbus_name(u32 bus_id);
-
-#endif /* _DPU_POWER_HANDLE_H_ */
index e12c4cefb7427047b582b7d0e87b8a1ab6c11aa4..c78b521ceda1bd06f7e06635ff86e3eaab483186 100644 (file)
@@ -99,27 +99,6 @@ TRACE_EVENT(dpu_perf_set_ot,
                        __entry->vbif_idx)
 )
 
-TRACE_EVENT(dpu_perf_update_bus,
-       TP_PROTO(int client, unsigned long long ab_quota,
-       unsigned long long ib_quota),
-       TP_ARGS(client, ab_quota, ib_quota),
-       TP_STRUCT__entry(
-                       __field(int, client)
-                       __field(u64, ab_quota)
-                       __field(u64, ib_quota)
-       ),
-       TP_fast_assign(
-                       __entry->client = client;
-                       __entry->ab_quota = ab_quota;
-                       __entry->ib_quota = ib_quota;
-       ),
-       TP_printk("Request client:%d ab=%llu ib=%llu",
-                       __entry->client,
-                       __entry->ab_quota,
-                       __entry->ib_quota)
-)
-
-
 TRACE_EVENT(dpu_cmd_release_bw,
        TP_PROTO(u32 crtc_id),
        TP_ARGS(crtc_id),
@@ -319,6 +298,10 @@ DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_wait_for_commit_done,
        TP_PROTO(uint32_t drm_id),
        TP_ARGS(drm_id)
 );
+DEFINE_EVENT(dpu_drm_obj_template, dpu_crtc_runtime_resume,
+       TP_PROTO(uint32_t drm_id),
+       TP_ARGS(drm_id)
+);
 
 TRACE_EVENT(dpu_enc_enable,
        TP_PROTO(uint32_t drm_id, int hdisplay, int vdisplay),
@@ -539,10 +522,6 @@ DEFINE_EVENT(dpu_id_event_template, dpu_crtc_frame_event_cb,
        TP_PROTO(uint32_t drm_id, u32 event),
        TP_ARGS(drm_id, event)
 );
-DEFINE_EVENT(dpu_id_event_template, dpu_crtc_handle_power_event,
-       TP_PROTO(uint32_t drm_id, u32 event),
-       TP_ARGS(drm_id, event)
-);
 DEFINE_EVENT(dpu_id_event_template, dpu_crtc_frame_event_done,
        TP_PROTO(uint32_t drm_id, u32 event),
        TP_ARGS(drm_id, event)
@@ -749,24 +728,17 @@ TRACE_EVENT(dpu_crtc_vblank_enable,
                __field(        uint32_t,               enc_id  )
                __field(        bool,                   enable  )
                __field(        bool,                   enabled )
-               __field(        bool,                   suspend )
-               __field(        bool,                   vblank_requested )
        ),
        TP_fast_assign(
                __entry->drm_id = drm_id;
                __entry->enc_id = enc_id;
                __entry->enable = enable;
                __entry->enabled = crtc->enabled;
-               __entry->suspend = crtc->suspend;
-               __entry->vblank_requested = crtc->vblank_requested;
        ),
-       TP_printk("id:%u encoder:%u enable:%s state{enabled:%s suspend:%s "
-                 "vblank_req:%s}",
+       TP_printk("id:%u encoder:%u enable:%s state{enabled:%s}",
                  __entry->drm_id, __entry->enc_id,
                  __entry->enable ? "true" : "false",
-                 __entry->enabled ? "true" : "false",
-                 __entry->suspend ? "true" : "false",
-                 __entry->vblank_requested ? "true" : "false")
+                 __entry->enabled ? "true" : "false")
 );
 
 DECLARE_EVENT_CLASS(dpu_crtc_enable_template,
@@ -776,25 +748,15 @@ DECLARE_EVENT_CLASS(dpu_crtc_enable_template,
                __field(        uint32_t,               drm_id  )
                __field(        bool,                   enable  )
                __field(        bool,                   enabled )
-               __field(        bool,                   suspend )
-               __field(        bool,                   vblank_requested )
        ),
        TP_fast_assign(
                __entry->drm_id = drm_id;
                __entry->enable = enable;
                __entry->enabled = crtc->enabled;
-               __entry->suspend = crtc->suspend;
-               __entry->vblank_requested = crtc->vblank_requested;
        ),
-       TP_printk("id:%u enable:%s state{enabled:%s suspend:%s vblank_req:%s}",
+       TP_printk("id:%u enable:%s state{enabled:%s}",
                  __entry->drm_id, __entry->enable ? "true" : "false",
-                 __entry->enabled ? "true" : "false",
-                 __entry->suspend ? "true" : "false",
-                 __entry->vblank_requested ? "true" : "false")
-);
-DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_set_suspend,
-       TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc),
-       TP_ARGS(drm_id, enable, crtc)
+                 __entry->enabled ? "true" : "false")
 );
 DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_enable,
        TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc),
@@ -1004,6 +966,53 @@ TRACE_EVENT(dpu_core_perf_update_clk,
                  __entry->stop_req ? "true" : "false", __entry->clk_rate)
 );
 
+TRACE_EVENT(dpu_hw_ctl_update_pending_flush,
+       TP_PROTO(u32 new_bits, u32 pending_mask),
+       TP_ARGS(new_bits, pending_mask),
+       TP_STRUCT__entry(
+               __field(        u32,                    new_bits        )
+               __field(        u32,                    pending_mask    )
+       ),
+       TP_fast_assign(
+               __entry->new_bits = new_bits;
+               __entry->pending_mask = pending_mask;
+       ),
+       TP_printk("new=%x existing=%x", __entry->new_bits,
+                 __entry->pending_mask)
+);
+
+DECLARE_EVENT_CLASS(dpu_hw_ctl_pending_flush_template,
+       TP_PROTO(u32 pending_mask, u32 ctl_flush),
+       TP_ARGS(pending_mask, ctl_flush),
+       TP_STRUCT__entry(
+               __field(        u32,                    pending_mask    )
+               __field(        u32,                    ctl_flush       )
+       ),
+       TP_fast_assign(
+               __entry->pending_mask = pending_mask;
+               __entry->ctl_flush = ctl_flush;
+       ),
+       TP_printk("pending_mask=%x CTL_FLUSH=%x", __entry->pending_mask,
+                 __entry->ctl_flush)
+);
+DEFINE_EVENT(dpu_hw_ctl_pending_flush_template, dpu_hw_ctl_clear_pending_flush,
+       TP_PROTO(u32 pending_mask, u32 ctl_flush),
+       TP_ARGS(pending_mask, ctl_flush)
+);
+DEFINE_EVENT(dpu_hw_ctl_pending_flush_template,
+            dpu_hw_ctl_trigger_pending_flush,
+       TP_PROTO(u32 pending_mask, u32 ctl_flush),
+       TP_ARGS(pending_mask, ctl_flush)
+);
+DEFINE_EVENT(dpu_hw_ctl_pending_flush_template, dpu_hw_ctl_trigger_prepare,
+       TP_PROTO(u32 pending_mask, u32 ctl_flush),
+       TP_ARGS(pending_mask, ctl_flush)
+);
+DEFINE_EVENT(dpu_hw_ctl_pending_flush_template, dpu_hw_ctl_trigger_start,
+       TP_PROTO(u32 pending_mask, u32 ctl_flush),
+       TP_ARGS(pending_mask, ctl_flush)
+);
+
 #define DPU_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
 #define DPU_ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
 #define DPU_ATRACE_FUNC() DPU_ATRACE_BEGIN(__func__)
index 2955282922964deb660171efc381ed932983a8d9..ef753ea9c4999a0341b35391aeb46a37f4858dff 100644 (file)
@@ -191,7 +191,7 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms,
        ot_lim = _dpu_vbif_get_ot_limit(vbif, params) & 0xFF;
 
        if (ot_lim == 0)
-               goto exit;
+               return;
 
        trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim,
                params->vbif_idx);
@@ -210,8 +210,6 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms,
 
        if (forced_on)
                mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
-exit:
-       return;
 }
 
 void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms,
@@ -312,31 +310,25 @@ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms)
 }
 
 #ifdef CONFIG_DEBUG_FS
-void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms)
-{
-       debugfs_remove_recursive(dpu_kms->debugfs_vbif);
-       dpu_kms->debugfs_vbif = NULL;
-}
 
-int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
+void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
 {
        char vbif_name[32];
-       struct dentry *debugfs_vbif;
+       struct dentry *entry, *debugfs_vbif;
        int i, j;
 
-       dpu_kms->debugfs_vbif = debugfs_create_dir("vbif", debugfs_root);
-       if (!dpu_kms->debugfs_vbif) {
-               DPU_ERROR("failed to create vbif debugfs\n");
-               return -EINVAL;
-       }
+       entry = debugfs_create_dir("vbif", debugfs_root);
+       if (IS_ERR_OR_NULL(entry))
+               return;
 
        for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {
                struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i];
 
                snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id);
 
-               debugfs_vbif = debugfs_create_dir(vbif_name,
-                               dpu_kms->debugfs_vbif);
+               debugfs_vbif = debugfs_create_dir(vbif_name, entry);
+               if (IS_ERR_OR_NULL(debugfs_vbif))
+                       continue;
 
                debugfs_create_u32("features", 0600, debugfs_vbif,
                        (u32 *)&vbif->features);
@@ -378,7 +370,5 @@ int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
                                        (u32 *)&cfg->ot_limit);
                }
        }
-
-       return 0;
 }
 #endif
index f17af52dbbd58e14b1a87c94eec6132e1fc7d277..6356876d7a66d8833ea66b36a7a5340f8eaa4baf 100644 (file)
@@ -78,17 +78,6 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms);
  */
 void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms);
 
-#ifdef CONFIG_DEBUG_FS
-int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root);
-void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms);
-#else
-static inline int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms,
-               struct dentry *debugfs_root)
-{
-       return 0;
-}
-static inline void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms)
-{
-}
-#endif
+void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root);
+
 #endif /* __DPU_VBIF_H__ */
index 4f12e5c534c8c4d7cfc389b6174133449d613183..9fc9dbde8a27c1d7078c3d6b260c8635f27a514f 100644 (file)
@@ -813,18 +813,6 @@ enum color_fmts {
 #define COLOR_FMT_P010_UBWC            COLOR_FMT_P010_UBWC
 #define COLOR_FMT_P010         COLOR_FMT_P010
 
-static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
-{
-       (void)height;
-       (void)width;
-
-       /*
-        * In the future, calculate the size based on the w/h but just
-        * hardcode it for now since 16K satisfies all current usecases.
-        */
-       return 16 * 1024;
-}
-
 /*
  * Function arguments:
  * @color_fmt
@@ -832,38 +820,32 @@ static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
  * Progressive: width
  * Interlaced: width
  */
-static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
 {
-       unsigned int alignment, stride = 0;
+       unsigned int stride = 0;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV21:
        case COLOR_FMT_NV12:
        case COLOR_FMT_NV12_MVTB:
        case COLOR_FMT_NV12_UBWC:
-               alignment = 128;
-               stride = MSM_MEDIA_ALIGN(width, alignment);
+               stride = MSM_MEDIA_ALIGN(width, 128);
                break;
        case COLOR_FMT_NV12_BPP10_UBWC:
-               alignment = 256;
                stride = MSM_MEDIA_ALIGN(width, 192);
-               stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment);
+               stride = MSM_MEDIA_ALIGN(stride * 4 / 3, 256);
                break;
        case COLOR_FMT_P010_UBWC:
-               alignment = 256;
-               stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+               stride = MSM_MEDIA_ALIGN(width * 2, 256);
                break;
        case COLOR_FMT_P010:
-               alignment = 128;
-               stride = MSM_MEDIA_ALIGN(width*2, alignment);
-               break;
-       default:
+               stride = MSM_MEDIA_ALIGN(width * 2, 128);
                break;
        }
-invalid_input:
+
        return stride;
 }
 
@@ -874,38 +856,32 @@ invalid_input:
  * Progressive: width
  * Interlaced: width
  */
-static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_UV_STRIDE(int color_fmt, int width)
 {
-       unsigned int alignment, stride = 0;
+       unsigned int stride = 0;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV21:
        case COLOR_FMT_NV12:
        case COLOR_FMT_NV12_MVTB:
        case COLOR_FMT_NV12_UBWC:
-               alignment = 128;
-               stride = MSM_MEDIA_ALIGN(width, alignment);
+               stride = MSM_MEDIA_ALIGN(width, 128);
                break;
        case COLOR_FMT_NV12_BPP10_UBWC:
-               alignment = 256;
                stride = MSM_MEDIA_ALIGN(width, 192);
-               stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment);
+               stride = MSM_MEDIA_ALIGN(stride * 4 / 3, 256);
                break;
        case COLOR_FMT_P010_UBWC:
-               alignment = 256;
-               stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+               stride = MSM_MEDIA_ALIGN(width * 2, 256);
                break;
        case COLOR_FMT_P010:
-               alignment = 128;
-               stride = MSM_MEDIA_ALIGN(width*2, alignment);
-               break;
-       default:
+               stride = MSM_MEDIA_ALIGN(width * 2, 128);
                break;
        }
-invalid_input:
+
        return stride;
 }
 
@@ -916,12 +892,12 @@ invalid_input:
  * Progressive: height
  * Interlaced: (height+1)>>1
  */
-static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
 {
-       unsigned int alignment, sclines = 0;
+       unsigned int sclines = 0;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV21:
@@ -929,17 +905,14 @@ static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
        case COLOR_FMT_NV12_MVTB:
        case COLOR_FMT_NV12_UBWC:
        case COLOR_FMT_P010:
-               alignment = 32;
+               sclines = MSM_MEDIA_ALIGN(height, 32);
                break;
        case COLOR_FMT_NV12_BPP10_UBWC:
        case COLOR_FMT_P010_UBWC:
-               alignment = 16;
+               sclines = MSM_MEDIA_ALIGN(height, 16);
                break;
-       default:
-               return 0;
        }
-       sclines = MSM_MEDIA_ALIGN(height, alignment);
-invalid_input:
+
        return sclines;
 }
 
@@ -950,12 +923,12 @@ invalid_input:
  * Progressive: height
  * Interlaced: (height+1)>>1
  */
-static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
 {
-       unsigned int alignment, sclines = 0;
+       unsigned int sclines = 0;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV21:
@@ -964,18 +937,13 @@ static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
        case COLOR_FMT_NV12_BPP10_UBWC:
        case COLOR_FMT_P010_UBWC:
        case COLOR_FMT_P010:
-               alignment = 16;
+               sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, 16);
                break;
        case COLOR_FMT_NV12_UBWC:
-               alignment = 32;
+               sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, 32);
                break;
-       default:
-               goto invalid_input;
        }
 
-       sclines = MSM_MEDIA_ALIGN((height+1)>>1, alignment);
-
-invalid_input:
        return sclines;
 }
 
@@ -986,12 +954,12 @@ invalid_input:
  * Progressive: width
  * Interlaced: width
  */
-static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width)
 {
-       int y_tile_width = 0, y_meta_stride = 0;
+       int y_tile_width = 0, y_meta_stride;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV12_UBWC:
@@ -1002,14 +970,11 @@ static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width)
                y_tile_width = 48;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
        y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width);
-       y_meta_stride = MSM_MEDIA_ALIGN(y_meta_stride, 64);
-
-invalid_input:
-       return y_meta_stride;
+       return MSM_MEDIA_ALIGN(y_meta_stride, 64);
 }
 
 /*
@@ -1019,12 +984,12 @@ invalid_input:
  * Progressive: height
  * Interlaced: (height+1)>>1
  */
-static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height)
 {
-       int y_tile_height = 0, y_meta_scanlines = 0;
+       int y_tile_height = 0, y_meta_scanlines;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV12_UBWC:
@@ -1035,14 +1000,11 @@ static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height)
                y_tile_height = 4;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
        y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height);
-       y_meta_scanlines = MSM_MEDIA_ALIGN(y_meta_scanlines, 16);
-
-invalid_input:
-       return y_meta_scanlines;
+       return MSM_MEDIA_ALIGN(y_meta_scanlines, 16);
 }
 
 /*
@@ -1052,12 +1014,12 @@ invalid_input:
  * Progressive: width
  * Interlaced: width
  */
-static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width)
 {
-       int uv_tile_width = 0, uv_meta_stride = 0;
+       int uv_tile_width = 0, uv_meta_stride;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV12_UBWC:
@@ -1068,14 +1030,11 @@ static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width)
                uv_tile_width = 24;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
        uv_meta_stride = MSM_MEDIA_ROUNDUP((width+1)>>1, uv_tile_width);
-       uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64);
-
-invalid_input:
-       return uv_meta_stride;
+       return MSM_MEDIA_ALIGN(uv_meta_stride, 64);
 }
 
 /*
@@ -1085,12 +1044,12 @@ invalid_input:
  * Progressive: height
  * Interlaced: (height+1)>>1
  */
-static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height)
 {
-       int uv_tile_height = 0, uv_meta_scanlines = 0;
+       int uv_tile_height = 0, uv_meta_scanlines;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_NV12_UBWC:
@@ -1101,22 +1060,19 @@ static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height)
                uv_tile_height = 4;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
        uv_meta_scanlines = MSM_MEDIA_ROUNDUP((height+1)>>1, uv_tile_height);
-       uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16);
-
-invalid_input:
-       return uv_meta_scanlines;
+       return MSM_MEDIA_ALIGN(uv_meta_scanlines, 16);
 }
 
-static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_RGB_STRIDE(int color_fmt, int width)
 {
-       unsigned int alignment = 0, stride = 0, bpp = 4;
+       unsigned int alignment = 0, bpp = 4;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_RGBA8888:
@@ -1131,21 +1087,18 @@ static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width)
                alignment = 256;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
-       stride = MSM_MEDIA_ALIGN(width * bpp, alignment);
-
-invalid_input:
-       return stride;
+       return MSM_MEDIA_ALIGN(width * bpp, alignment);
 }
 
-static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height)
 {
-       unsigned int alignment = 0, scanlines = 0;
+       unsigned int alignment = 0;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_RGBA8888:
@@ -1157,220 +1110,46 @@ static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height)
                alignment = 16;
                break;
        default:
-               goto invalid_input;
+               return 0;
        }
 
-       scanlines = MSM_MEDIA_ALIGN(height, alignment);
-
-invalid_input:
-       return scanlines;
+       return MSM_MEDIA_ALIGN(height, alignment);
 }
 
-static inline unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width)
+static unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width)
 {
-       int rgb_tile_width = 0, rgb_meta_stride = 0;
+       int rgb_meta_stride;
 
        if (!width)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_RGBA8888_UBWC:
        case COLOR_FMT_RGBA1010102_UBWC:
        case COLOR_FMT_RGB565_UBWC:
-               rgb_tile_width = 16;
-               break;
-       default:
-               goto invalid_input;
+               rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, 16);
+               return MSM_MEDIA_ALIGN(rgb_meta_stride, 64);
        }
 
-       rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, rgb_tile_width);
-       rgb_meta_stride = MSM_MEDIA_ALIGN(rgb_meta_stride, 64);
-
-invalid_input:
-       return rgb_meta_stride;
+       return 0;
 }
 
-static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height)
+static unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height)
 {
-       int rgb_tile_height = 0, rgb_meta_scanlines = 0;
+       int rgb_meta_scanlines;
 
        if (!height)
-               goto invalid_input;
+               return 0;
 
        switch (color_fmt) {
        case COLOR_FMT_RGBA8888_UBWC:
        case COLOR_FMT_RGBA1010102_UBWC:
        case COLOR_FMT_RGB565_UBWC:
-               rgb_tile_height = 4;
-               break;
-       default:
-               goto invalid_input;
+               rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, 4);
+               return MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16);
        }
 
-       rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, rgb_tile_height);
-       rgb_meta_scanlines = MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16);
-
-invalid_input:
-       return rgb_meta_scanlines;
-}
-
-/*
- * Function arguments:
- * @color_fmt
- * @width
- * Progressive: width
- * Interlaced: width
- * @height
- * Progressive: height
- * Interlaced: height
- */
-static inline unsigned int VENUS_BUFFER_SIZE(
-       int color_fmt, int width, int height)
-{
-       const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height);
-       unsigned int uv_alignment = 0, size = 0;
-       unsigned int y_plane, uv_plane, y_stride,
-               uv_stride, y_sclines, uv_sclines;
-       unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0;
-       unsigned int y_meta_stride = 0, y_meta_scanlines = 0;
-       unsigned int uv_meta_stride = 0, uv_meta_scanlines = 0;
-       unsigned int y_meta_plane = 0, uv_meta_plane = 0;
-       unsigned int rgb_stride = 0, rgb_scanlines = 0;
-       unsigned int rgb_plane = 0, rgb_ubwc_plane = 0, rgb_meta_plane = 0;
-       unsigned int rgb_meta_stride = 0, rgb_meta_scanlines = 0;
-
-       if (!width || !height)
-               goto invalid_input;
-
-       y_stride = VENUS_Y_STRIDE(color_fmt, width);
-       uv_stride = VENUS_UV_STRIDE(color_fmt, width);
-       y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
-       uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
-       rgb_stride = VENUS_RGB_STRIDE(color_fmt, width);
-       rgb_scanlines = VENUS_RGB_SCANLINES(color_fmt, height);
-
-       switch (color_fmt) {
-       case COLOR_FMT_NV21:
-       case COLOR_FMT_NV12:
-       case COLOR_FMT_P010:
-               uv_alignment = 4096;
-               y_plane = y_stride * y_sclines;
-               uv_plane = uv_stride * uv_sclines + uv_alignment;
-               size = y_plane + uv_plane +
-                               MSM_MEDIA_MAX(extra_size, 8 * y_stride);
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_NV12_MVTB:
-               uv_alignment = 4096;
-               y_plane = y_stride * y_sclines;
-               uv_plane = uv_stride * uv_sclines + uv_alignment;
-               size = y_plane + uv_plane;
-               size = 2 * size + extra_size;
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_NV12_UBWC:
-               y_sclines = VENUS_Y_SCANLINES(color_fmt, (height+1)>>1);
-               y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
-               uv_sclines = VENUS_UV_SCANLINES(color_fmt, (height+1)>>1);
-               uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
-               y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
-               y_meta_scanlines =
-                       VENUS_Y_META_SCANLINES(color_fmt, (height+1)>>1);
-               y_meta_plane = MSM_MEDIA_ALIGN(
-                       y_meta_stride * y_meta_scanlines, 4096);
-               uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
-               uv_meta_scanlines =
-                       VENUS_UV_META_SCANLINES(color_fmt, (height+1)>>1);
-               uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride *
-                       uv_meta_scanlines, 4096);
-
-               size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
-                       uv_meta_plane)*2 +
-                       MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride);
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_NV12_BPP10_UBWC:
-               y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
-               uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
-               y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
-               y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height);
-               y_meta_plane = MSM_MEDIA_ALIGN(
-                               y_meta_stride * y_meta_scanlines, 4096);
-               uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
-               uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height);
-               uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride *
-                                       uv_meta_scanlines, 4096);
-
-               size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
-                       uv_meta_plane +
-                       MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride);
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_P010_UBWC:
-               y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
-               uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
-               y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
-               y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height);
-               y_meta_plane = MSM_MEDIA_ALIGN(
-                               y_meta_stride * y_meta_scanlines, 4096);
-               uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
-               uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height);
-               uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride *
-                                       uv_meta_scanlines, 4096);
-
-               size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
-                       uv_meta_plane;
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_RGBA8888:
-               rgb_plane = MSM_MEDIA_ALIGN(rgb_stride  * rgb_scanlines, 4096);
-               size = rgb_plane;
-               size =  MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       case COLOR_FMT_RGBA8888_UBWC:
-       case COLOR_FMT_RGBA1010102_UBWC:
-       case COLOR_FMT_RGB565_UBWC:
-               rgb_ubwc_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines,
-                                                       4096);
-               rgb_meta_stride = VENUS_RGB_META_STRIDE(color_fmt, width);
-               rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color_fmt,
-                                       height);
-               rgb_meta_plane = MSM_MEDIA_ALIGN(rgb_meta_stride *
-                                       rgb_meta_scanlines, 4096);
-               size = rgb_ubwc_plane + rgb_meta_plane;
-               size = MSM_MEDIA_ALIGN(size, 4096);
-               break;
-       default:
-               break;
-       }
-invalid_input:
-       return size;
-}
-
-static inline unsigned int VENUS_VIEW2_OFFSET(
-       int color_fmt, int width, int height)
-{
-       unsigned int offset = 0;
-       unsigned int y_plane, uv_plane, y_stride,
-               uv_stride, y_sclines, uv_sclines;
-       if (!width || !height)
-               goto invalid_input;
-
-       y_stride = VENUS_Y_STRIDE(color_fmt, width);
-       uv_stride = VENUS_UV_STRIDE(color_fmt, width);
-       y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
-       uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
-       switch (color_fmt) {
-       case COLOR_FMT_NV12_MVTB:
-               y_plane = y_stride * y_sclines;
-               uv_plane = uv_stride * uv_sclines;
-               offset = y_plane + uv_plane;
-               break;
-       default:
-               break;
-       }
-invalid_input:
-       return offset;
+       return 0;
 }
 
 #endif
index 457c29dba4a1a096012fad1fd7b21e3b47cdb22e..8f2359dc87b4ea5b34aabe77bb288a365f5f3233 100644 (file)
@@ -128,7 +128,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val)
        struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base);
        struct msm_kms *kms = &mdp4_kms->base.base;
 
-       msm_gem_put_iova(val, kms->aspace);
+       msm_gem_unpin_iova(val, kms->aspace);
        drm_gem_object_put_unlocked(val);
 }
 
@@ -384,7 +384,7 @@ static void update_cursor(struct drm_crtc *crtc)
                if (next_bo) {
                        /* take a obj ref + iova ref when we start scanning out: */
                        drm_gem_object_get(next_bo);
-                       msm_gem_get_iova(next_bo, kms->aspace, &iova);
+                       msm_gem_get_and_pin_iova(next_bo, kms->aspace, &iova);
 
                        /* enable cursor: */
                        mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma),
@@ -429,7 +429,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
        int ret;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
-               dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+               DRM_DEV_ERROR(dev->dev, "bad cursor size: %dx%d\n", width, height);
                return -EINVAL;
        }
 
@@ -442,7 +442,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
        }
 
        if (cursor_bo) {
-               ret = msm_gem_get_iova(cursor_bo, kms->aspace, &iova);
+               ret = msm_gem_get_and_pin_iova(cursor_bo, kms->aspace, &iova);
                if (ret)
                        goto fail;
        } else {
index ba8e587f734b3d6632af0d7796ab9929a17808b5..a8fd14d4846b37d95160b6b00ea84c32a270c2bc 100644 (file)
@@ -45,7 +45,7 @@ static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder)
        struct lcdc_platform_data *dtv_pdata = mdp4_find_pdata("dtv.0");
 
        if (!dtv_pdata) {
-               dev_err(dev->dev, "could not find dtv pdata\n");
+               DRM_DEV_ERROR(dev->dev, "could not find dtv pdata\n");
                return;
        }
 
@@ -209,16 +209,16 @@ static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder)
 
        ret = clk_set_rate(mdp4_dtv_encoder->mdp_clk, pc);
        if (ret)
-               dev_err(dev->dev, "failed to set mdp_clk to %lu: %d\n",
+               DRM_DEV_ERROR(dev->dev, "failed to set mdp_clk to %lu: %d\n",
                        pc, ret);
 
        ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
        if (ret)
-               dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
 
        ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
        if (ret)
-               dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
 
        mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
 
@@ -258,14 +258,14 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev)
 
        mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk");
        if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) {
-               dev_err(dev->dev, "failed to get hdmi_clk\n");
+               DRM_DEV_ERROR(dev->dev, "failed to get hdmi_clk\n");
                ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk);
                goto fail;
        }
 
        mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk");
        if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) {
-               dev_err(dev->dev, "failed to get tv_clk\n");
+               DRM_DEV_ERROR(dev->dev, "failed to get tv_clk\n");
                ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk);
                goto fail;
        }
index 44d1cda56974d7f6c106329ae0fac034fe4d38c6..e437aa806f7beaa57ec87fc2808cd0c7949c560a 100644 (file)
@@ -43,7 +43,7 @@ static int mdp4_hw_init(struct msm_kms *kms)
        DBG("found MDP4 version v%d.%d", major, minor);
 
        if (major != 4) {
-               dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
+               DRM_DEV_ERROR(dev->dev, "unexpected MDP version: v%d.%d\n",
                                major, minor);
                ret = -ENXIO;
                goto out;
@@ -165,7 +165,7 @@ static void mdp4_destroy(struct msm_kms *kms)
        struct msm_gem_address_space *aspace = kms->aspace;
 
        if (mdp4_kms->blank_cursor_iova)
-               msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace);
+               msm_gem_unpin_iova(mdp4_kms->blank_cursor_bo, kms->aspace);
        drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo);
 
        if (aspace) {
@@ -206,7 +206,8 @@ int mdp4_disable(struct mdp4_kms *mdp4_kms)
        clk_disable_unprepare(mdp4_kms->clk);
        if (mdp4_kms->pclk)
                clk_disable_unprepare(mdp4_kms->pclk);
-       clk_disable_unprepare(mdp4_kms->lut_clk);
+       if (mdp4_kms->lut_clk)
+               clk_disable_unprepare(mdp4_kms->lut_clk);
        if (mdp4_kms->axi_clk)
                clk_disable_unprepare(mdp4_kms->axi_clk);
 
@@ -220,7 +221,8 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
        clk_prepare_enable(mdp4_kms->clk);
        if (mdp4_kms->pclk)
                clk_prepare_enable(mdp4_kms->pclk);
-       clk_prepare_enable(mdp4_kms->lut_clk);
+       if (mdp4_kms->lut_clk)
+               clk_prepare_enable(mdp4_kms->lut_clk);
        if (mdp4_kms->axi_clk)
                clk_prepare_enable(mdp4_kms->axi_clk);
 
@@ -251,7 +253,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
 
                encoder = mdp4_lcdc_encoder_init(dev, panel_node);
                if (IS_ERR(encoder)) {
-                       dev_err(dev->dev, "failed to construct LCDC encoder\n");
+                       DRM_DEV_ERROR(dev->dev, "failed to construct LCDC encoder\n");
                        return PTR_ERR(encoder);
                }
 
@@ -260,7 +262,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
 
                connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
                if (IS_ERR(connector)) {
-                       dev_err(dev->dev, "failed to initialize LVDS connector\n");
+                       DRM_DEV_ERROR(dev->dev, "failed to initialize LVDS connector\n");
                        return PTR_ERR(connector);
                }
 
@@ -271,7 +273,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
        case DRM_MODE_ENCODER_TMDS:
                encoder = mdp4_dtv_encoder_init(dev);
                if (IS_ERR(encoder)) {
-                       dev_err(dev->dev, "failed to construct DTV encoder\n");
+                       DRM_DEV_ERROR(dev->dev, "failed to construct DTV encoder\n");
                        return PTR_ERR(encoder);
                }
 
@@ -282,7 +284,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
                        /* Construct bridge/connector for HDMI: */
                        ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
                        if (ret) {
-                               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+                               DRM_DEV_ERROR(dev->dev, "failed to initialize HDMI: %d\n", ret);
                                return ret;
                        }
                }
@@ -300,7 +302,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
                encoder = mdp4_dsi_encoder_init(dev);
                if (IS_ERR(encoder)) {
                        ret = PTR_ERR(encoder);
-                       dev_err(dev->dev,
+                       DRM_DEV_ERROR(dev->dev,
                                "failed to construct DSI encoder: %d\n", ret);
                        return ret;
                }
@@ -311,14 +313,14 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
 
                ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
                if (ret) {
-                       dev_err(dev->dev, "failed to initialize DSI: %d\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to initialize DSI: %d\n",
                                ret);
                        return ret;
                }
 
                break;
        default:
-               dev_err(dev->dev, "Invalid or unsupported interface\n");
+               DRM_DEV_ERROR(dev->dev, "Invalid or unsupported interface\n");
                return -EINVAL;
        }
 
@@ -354,7 +356,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        for (i = 0; i < ARRAY_SIZE(vg_planes); i++) {
                plane = mdp4_plane_init(dev, vg_planes[i], false);
                if (IS_ERR(plane)) {
-                       dev_err(dev->dev,
+                       DRM_DEV_ERROR(dev->dev,
                                "failed to construct plane for VG%d\n", i + 1);
                        ret = PTR_ERR(plane);
                        goto fail;
@@ -365,7 +367,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        for (i = 0; i < ARRAY_SIZE(mdp4_crtcs); i++) {
                plane = mdp4_plane_init(dev, rgb_planes[i], true);
                if (IS_ERR(plane)) {
-                       dev_err(dev->dev,
+                       DRM_DEV_ERROR(dev->dev,
                                "failed to construct plane for RGB%d\n", i + 1);
                        ret = PTR_ERR(plane);
                        goto fail;
@@ -374,7 +376,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
                crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, i,
                                mdp4_crtcs[i]);
                if (IS_ERR(crtc)) {
-                       dev_err(dev->dev, "failed to construct crtc for %s\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to construct crtc for %s\n",
                                mdp4_crtc_names[i]);
                        ret = PTR_ERR(crtc);
                        goto fail;
@@ -396,7 +398,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        for (i = 0; i < ARRAY_SIZE(mdp4_intfs); i++) {
                ret = mdp4_modeset_init_intf(mdp4_kms, mdp4_intfs[i]);
                if (ret) {
-                       dev_err(dev->dev, "failed to initialize intf: %d, %d\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to initialize intf: %d, %d\n",
                                i, ret);
                        goto fail;
                }
@@ -419,7 +421,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 
        mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
        if (!mdp4_kms) {
-               dev_err(dev->dev, "failed to allocate kms\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate kms\n");
                ret = -ENOMEM;
                goto fail;
        }
@@ -439,7 +441,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = irq;
-               dev_err(dev->dev, "failed to get irq: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret);
                goto fail;
        }
 
@@ -456,14 +458,14 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        if (mdp4_kms->vdd) {
                ret = regulator_enable(mdp4_kms->vdd);
                if (ret) {
-                       dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", ret);
                        goto fail;
                }
        }
 
        mdp4_kms->clk = devm_clk_get(&pdev->dev, "core_clk");
        if (IS_ERR(mdp4_kms->clk)) {
-               dev_err(dev->dev, "failed to get core_clk\n");
+               DRM_DEV_ERROR(dev->dev, "failed to get core_clk\n");
                ret = PTR_ERR(mdp4_kms->clk);
                goto fail;
        }
@@ -472,23 +474,25 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        if (IS_ERR(mdp4_kms->pclk))
                mdp4_kms->pclk = NULL;
 
-       // XXX if (rev >= MDP_REV_42) { ???
-       mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
-       if (IS_ERR(mdp4_kms->lut_clk)) {
-               dev_err(dev->dev, "failed to get lut_clk\n");
-               ret = PTR_ERR(mdp4_kms->lut_clk);
-               goto fail;
+       if (mdp4_kms->rev >= 2) {
+               mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
+               if (IS_ERR(mdp4_kms->lut_clk)) {
+                       DRM_DEV_ERROR(dev->dev, "failed to get lut_clk\n");
+                       ret = PTR_ERR(mdp4_kms->lut_clk);
+                       goto fail;
+               }
        }
 
        mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
        if (IS_ERR(mdp4_kms->axi_clk)) {
-               dev_err(dev->dev, "failed to get axi_clk\n");
+               DRM_DEV_ERROR(dev->dev, "failed to get axi_clk\n");
                ret = PTR_ERR(mdp4_kms->axi_clk);
                goto fail;
        }
 
        clk_set_rate(mdp4_kms->clk, config->max_clk);
-       clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
+       if (mdp4_kms->lut_clk)
+               clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
 
        pm_runtime_enable(dev->dev);
        mdp4_kms->rpm_enabled = true;
@@ -519,29 +523,29 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
                if (ret)
                        goto fail;
        } else {
-               dev_info(dev->dev, "no iommu, fallback to phys "
+               DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys "
                                "contig buffers for scanout\n");
                aspace = NULL;
        }
 
        ret = modeset_init(mdp4_kms);
        if (ret) {
-               dev_err(dev->dev, "modeset_init failed: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret);
                goto fail;
        }
 
-       mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
+       mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT);
        if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
                ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
-               dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
                mdp4_kms->blank_cursor_bo = NULL;
                goto fail;
        }
 
-       ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, kms->aspace,
+       ret = msm_gem_get_and_pin_iova(mdp4_kms->blank_cursor_bo, kms->aspace,
                        &mdp4_kms->blank_cursor_iova);
        if (ret) {
-               dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
                goto fail;
        }
 
index 2bfb39082f54dd7f9e9c51e038a46e2955ed03c8..c9e34501a89e8c485743b8a27632783bde4355bb 100644 (file)
@@ -47,7 +47,7 @@ static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
        struct lcdc_platform_data *lcdc_pdata = mdp4_find_pdata("lvds.0");
 
        if (!lcdc_pdata) {
-               dev_err(dev->dev, "could not find lvds pdata\n");
+               DRM_DEV_ERROR(dev->dev, "could not find lvds pdata\n");
                return;
        }
 
@@ -224,7 +224,7 @@ static void setup_phy(struct drm_encoder *encoder)
                break;
 
        default:
-               dev_err(dev->dev, "unknown bpp: %d\n", bpp);
+               DRM_DEV_ERROR(dev->dev, "unknown bpp: %d\n", bpp);
                return;
        }
 
@@ -241,7 +241,7 @@ static void setup_phy(struct drm_encoder *encoder)
                                MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
                break;
        default:
-               dev_err(dev->dev, "unknown # of channels: %d\n", nchan);
+               DRM_DEV_ERROR(dev->dev, "unknown # of channels: %d\n", nchan);
                return;
        }
 
@@ -361,7 +361,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
        for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
                ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
                if (ret)
-                       dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to disable regulator: %d\n", ret);
        }
 
        bs_set(mdp4_lcdc_encoder, 0);
@@ -377,20 +377,25 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
        unsigned long pc = mdp4_lcdc_encoder->pixclock;
        struct mdp4_kms *mdp4_kms = get_kms(encoder);
        struct drm_panel *panel;
+       uint32_t config;
        int i, ret;
 
        if (WARN_ON(mdp4_lcdc_encoder->enabled))
                return;
 
        /* TODO: hard-coded for 18bpp: */
-       mdp4_crtc_set_config(encoder->crtc,
-                       MDP4_DMA_CONFIG_R_BPC(BPC6) |
-                       MDP4_DMA_CONFIG_G_BPC(BPC6) |
-                       MDP4_DMA_CONFIG_B_BPC(BPC6) |
-                       MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
-                       MDP4_DMA_CONFIG_PACK(0x21) |
-                       MDP4_DMA_CONFIG_DEFLKR_EN |
-                       MDP4_DMA_CONFIG_DITHER_EN);
+       config =
+               MDP4_DMA_CONFIG_R_BPC(BPC6) |
+               MDP4_DMA_CONFIG_G_BPC(BPC6) |
+               MDP4_DMA_CONFIG_B_BPC(BPC6) |
+               MDP4_DMA_CONFIG_PACK(0x21) |
+               MDP4_DMA_CONFIG_DEFLKR_EN |
+               MDP4_DMA_CONFIG_DITHER_EN;
+
+       if (!of_property_read_bool(dev->dev->of_node, "qcom,lcdc-align-lsb"))
+               config |= MDP4_DMA_CONFIG_PACK_ALIGN_MSB;
+
+       mdp4_crtc_set_config(encoder->crtc, config);
        mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
 
        bs_set(mdp4_lcdc_encoder, 1);
@@ -398,16 +403,16 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
        for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
                ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
                if (ret)
-                       dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to enable regulator: %d\n", ret);
        }
 
        DBG("setting lcdc_clk=%lu", pc);
        ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
        if (ret)
-               dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
        ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
        if (ret)
-               dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
 
        panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
        if (!IS_ERR(panel)) {
@@ -461,7 +466,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
        /* TODO: do we need different pll in other cases? */
        mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
        if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
-               dev_err(dev->dev, "failed to get lvds_clk\n");
+               DRM_DEV_ERROR(dev->dev, "failed to get lvds_clk\n");
                ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
                goto fail;
        }
@@ -470,7 +475,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
        reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
        if (IS_ERR(reg)) {
                ret = PTR_ERR(reg);
-               dev_err(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
                goto fail;
        }
        mdp4_lcdc_encoder->regs[0] = reg;
@@ -478,7 +483,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
        reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
        if (IS_ERR(reg)) {
                ret = PTR_ERR(reg);
-               dev_err(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
                goto fail;
        }
        mdp4_lcdc_encoder->regs[1] = reg;
@@ -486,7 +491,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
        reg = devm_regulator_get(dev->dev, "lvds-vdda");
        if (IS_ERR(reg)) {
                ret = PTR_ERR(reg);
-               dev_err(dev->dev, "failed to get lvds-vdda: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get lvds-vdda: %d\n", ret);
                goto fail;
        }
        mdp4_lcdc_encoder->regs[2] = reg;
index 79ff653d8081e63d4aff0c57aa04037c24b7f58b..005066f7154d3cacc7aec43c884dd8991b35dc92 100644 (file)
@@ -68,7 +68,6 @@ static void mdp4_plane_destroy(struct drm_plane *plane)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
 
-       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 
        kfree(mdp4_plane);
@@ -235,22 +234,22 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
        format = to_mdp_format(msm_framebuffer_format(fb));
 
        if (src_w > (crtc_w * DOWN_SCALE_MAX)) {
-               dev_err(dev->dev, "Width down scaling exceeds limits!\n");
+               DRM_DEV_ERROR(dev->dev, "Width down scaling exceeds limits!\n");
                return -ERANGE;
        }
 
        if (src_h > (crtc_h * DOWN_SCALE_MAX)) {
-               dev_err(dev->dev, "Height down scaling exceeds limits!\n");
+               DRM_DEV_ERROR(dev->dev, "Height down scaling exceeds limits!\n");
                return -ERANGE;
        }
 
        if (crtc_w > (src_w * UP_SCALE_MAX)) {
-               dev_err(dev->dev, "Width up scaling exceeds limits!\n");
+               DRM_DEV_ERROR(dev->dev, "Width up scaling exceeds limits!\n");
                return -ERANGE;
        }
 
        if (crtc_h > (src_h * UP_SCALE_MAX)) {
-               dev_err(dev->dev, "Height up scaling exceeds limits!\n");
+               DRM_DEV_ERROR(dev->dev, "Height up scaling exceeds limits!\n");
                return -ERANGE;
        }
 
index 824067d2d4277d36699b1f15c6d58f74a97fe23f..ea8f7d7daf7f4dd76e20d5b075b328f3b02a152e 100644 (file)
@@ -553,6 +553,91 @@ const struct mdp5_cfg_hw msm8x96_config = {
        .max_clk = 412500000,
 };
 
+const struct mdp5_cfg_hw msm8917_config = {
+       .name = "msm8917",
+       .mdp = {
+               .count = 1,
+               .caps = MDP_CAP_CDM,
+       },
+       .ctl = {
+               .count = 3,
+               .base = { 0x01000, 0x01200, 0x01400 },
+               .flush_hw_mask = 0xffffffff,
+       },
+       .pipe_vig = {
+               .count = 1,
+               .base = { 0x04000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SCALE      |
+                       MDP_PIPE_CAP_CSC        |
+                       MDP_PIPE_CAP_DECIMATION |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_rgb = {
+               .count = 2,
+               .base = { 0x14000, 0x16000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_DECIMATION |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_dma = {
+               .count = 1,
+               .base = { 0x24000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_cursor = {
+               .count = 1,
+               .base = { 0x34000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       MDP_PIPE_CAP_CURSOR     |
+                       0,
+       },
+
+       .lm = {
+               .count = 2,
+               .base = { 0x44000, 0x45000 },
+               .instances = {
+                               { .id = 0, .pp = 0, .dspp = 0,
+                                 .caps = MDP_LM_CAP_DISPLAY, },
+                               { .id = 1, .pp = -1, .dspp = -1,
+                                 .caps = MDP_LM_CAP_WB },
+                            },
+               .nb_stages = 8,
+               .max_width = 2048,
+               .max_height = 0xFFFF,
+       },
+       .dspp = {
+               .count = 1,
+               .base = { 0x54000 },
+
+       },
+       .pp = {
+               .count = 1,
+               .base = { 0x70000 },
+       },
+       .cdm = {
+               .count = 1,
+               .base = { 0x79200 },
+       },
+       .intf = {
+               .base = { 0x6a000, 0x6a800 },
+               .connect = {
+                       [0] = INTF_DISABLED,
+                       [1] = INTF_DSI,
+               },
+       },
+       .max_clk = 320000000,
+};
+
 static const struct mdp5_cfg_handler cfg_handlers[] = {
        { .revision = 0, .config = { .hw = &msm8x74v1_config } },
        { .revision = 2, .config = { .hw = &msm8x74v2_config } },
@@ -560,6 +645,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = {
        { .revision = 6, .config = { .hw = &msm8x16_config } },
        { .revision = 9, .config = { .hw = &msm8x94_config } },
        { .revision = 7, .config = { .hw = &msm8x96_config } },
+       { .revision = 15, .config = { .hw = &msm8917_config } },
 };
 
 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
@@ -600,7 +686,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
        }
 
        if (major != 1) {
-               dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
+               DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n",
                                major, minor);
                ret = -ENXIO;
                goto fail;
@@ -615,7 +701,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
                break;
        }
        if (unlikely(!mdp5_cfg)) {
-               dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
+               DRM_DEV_ERROR(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
                                major, minor);
                ret = -ENXIO;
                goto fail;
index d6f79dc755b46d9b53e491422c53c604dbe73f4f..c1962f29ec7d688e98ec57f40c9375210fc47af0 100644 (file)
@@ -55,20 +55,20 @@ static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
        int pp_id = mixer->pp;
 
        if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
-               dev_err(dev, "vsync_clk is not initialized\n");
+               DRM_DEV_ERROR(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",
+               DRM_DEV_ERROR(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",
+               DRM_DEV_ERROR(dev, "vsync_clk round rate failed %ld\n",
                                                        vsync_clk_speed);
                return -EINVAL;
        }
@@ -102,13 +102,13 @@ static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
        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,
+               DRM_DEV_ERROR(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,
+               DRM_DEV_ERROR(encoder->dev->dev,
                        "vsync_clk clk_prepare_enable failed, %d\n", ret);
                return ret;
        }
index b1da9ce54379099f3fc33e4f48a49cd007b74fa1..c5fde1a4191aaa03d7a002e52b803a2689519667 100644 (file)
@@ -173,7 +173,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val)
        struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);
        struct msm_kms *kms = &mdp5_kms->base.base;
 
-       msm_gem_put_iova(val, kms->aspace);
+       msm_gem_unpin_iova(val, kms->aspace);
        drm_gem_object_put_unlocked(val);
 }
 
@@ -662,7 +662,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 
        ret = mdp5_crtc_setup_pipeline(crtc, state, need_right_mixer);
        if (ret) {
-               dev_err(dev->dev, "couldn't assign mixers %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "couldn't assign mixers %d\n", ret);
                return ret;
        }
 
@@ -679,7 +679,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
         * and that we don't have conflicting mixer stages:
         */
        if ((cnt + start - 1) >= hw_cfg->lm.nb_stages) {
-               dev_err(dev->dev, "too many planes! cnt=%d, start stage=%d\n",
+               DRM_DEV_ERROR(dev->dev, "too many planes! cnt=%d, start stage=%d\n",
                        cnt, start);
                return -EINVAL;
        }
@@ -879,7 +879,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        }
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
-               dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+               DRM_DEV_ERROR(dev->dev, "bad cursor size: %dx%d\n", width, height);
                return -EINVAL;
        }
 
@@ -903,7 +903,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        if (!cursor_bo)
                return -ENOENT;
 
-       ret = msm_gem_get_iova(cursor_bo, kms->aspace,
+       ret = msm_gem_get_and_pin_iova(cursor_bo, kms->aspace,
                        &mdp5_crtc->cursor.iova);
        if (ret)
                return -EINVAL;
@@ -924,7 +924,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
 set_cursor:
        ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
        if (ret) {
-               dev_err(dev->dev, "failed to %sable cursor: %d\n",
+               DRM_DEV_ERROR(dev->dev, "failed to %sable cursor: %d\n",
                                cursor_enable ? "en" : "dis", ret);
                goto end;
        }
index f93d5681267c7c56102bd82d47978a9eb9826792..65a871f9f0d9c1cb6f130e811de1605e57815b17 100644 (file)
@@ -262,13 +262,13 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
 
        if (unlikely(WARN_ON(!mixer))) {
-               dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM",
+               DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTL %d cannot find LM",
                        ctl->id);
                return -EINVAL;
        }
 
        if (pipeline->r_mixer) {
-               dev_err(ctl_mgr->dev->dev, "unsupported configuration");
+               DRM_DEV_ERROR(ctl_mgr->dev->dev, "unsupported configuration");
                return -EINVAL;
        }
 
@@ -604,10 +604,10 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable)
                mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, 0);
                return 0;
        } else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) {
-               dev_err(ctl_mgr->dev->dev, "CTLs already paired\n");
+               DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTLs already paired\n");
                return -EINVAL;
        } else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) {
-               dev_err(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
+               DRM_DEV_ERROR(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
                return -EINVAL;
        }
 
@@ -652,7 +652,7 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
                if ((ctl_mgr->ctls[c].status & checkm) == match)
                        goto found;
 
-       dev_err(ctl_mgr->dev->dev, "No more CTL available!");
+       DRM_DEV_ERROR(ctl_mgr->dev->dev, "No more CTL available!");
        goto unlock;
 
 found:
@@ -698,13 +698,13 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
 
        ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL);
        if (!ctl_mgr) {
-               dev_err(dev->dev, "failed to allocate CTL manager\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate CTL manager\n");
                ret = -ENOMEM;
                goto fail;
        }
 
        if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) {
-               dev_err(dev->dev, "Increase static pool size to at least %d\n",
+               DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n",
                                ctl_cfg->count);
                ret = -ENOSPC;
                goto fail;
@@ -723,7 +723,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
 
                if (WARN_ON(!ctl_cfg->base[c])) {
-                       dev_err(dev->dev, "CTL_%d: base is null!\n", c);
+                       DRM_DEV_ERROR(dev->dev, "CTL_%d: base is null!\n", c);
                        ret = -EINVAL;
                        spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
                        goto fail;
index bddd625ab91bd44a56824c3e30a8ea2edefe46ff..d27e35a217bd77f3ffbfe88f452bf1f7c8c7f51e 100644 (file)
@@ -264,7 +264,7 @@ static int mdp5_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
                        minor->debugfs_root, minor);
 
        if (ret) {
-               dev_err(dev->dev, "could not install mdp5_debugfs_list\n");
+               DRM_DEV_ERROR(dev->dev, "could not install mdp5_debugfs_list\n");
                return ret;
        }
 
@@ -337,7 +337,7 @@ static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
 
        encoder = mdp5_encoder_init(dev, intf, ctl);
        if (IS_ERR(encoder)) {
-               dev_err(dev->dev, "failed to construct encoder\n");
+               DRM_DEV_ERROR(dev->dev, "failed to construct encoder\n");
                return encoder;
        }
 
@@ -418,7 +418,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
                int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);
 
                if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
-                       dev_err(dev->dev, "failed to find dsi from intf %d\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to find dsi from intf %d\n",
                                intf->num);
                        ret = -EINVAL;
                        break;
@@ -443,7 +443,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
                break;
        }
        default:
-               dev_err(dev->dev, "unknown intf: %d\n", intf->type);
+               DRM_DEV_ERROR(dev->dev, "unknown intf: %d\n", intf->type);
                ret = -EINVAL;
                break;
        }
@@ -500,7 +500,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                plane = mdp5_plane_init(dev, type);
                if (IS_ERR(plane)) {
                        ret = PTR_ERR(plane);
-                       dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
                        goto fail;
                }
                priv->planes[priv->num_planes++] = plane;
@@ -517,7 +517,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                crtc  = mdp5_crtc_init(dev, primary[i], cursor[i], i);
                if (IS_ERR(crtc)) {
                        ret = PTR_ERR(crtc);
-                       dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
                        goto fail;
                }
                priv->crtcs[priv->num_crtcs++] = crtc;
@@ -552,7 +552,7 @@ static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
        *major = FIELD(version, MDP5_HW_VERSION_MAJOR);
        *minor = FIELD(version, MDP5_HW_VERSION_MINOR);
 
-       dev_info(dev, "MDP5 version v%d.%d", *major, *minor);
+       DRM_DEV_INFO(dev, "MDP5 version v%d.%d", *major, *minor);
 }
 
 static int get_clk(struct platform_device *pdev, struct clk **clkp,
@@ -561,7 +561,7 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
        struct device *dev = &pdev->dev;
        struct clk *clk = msm_clk_get(pdev, name);
        if (IS_ERR(clk) && mandatory) {
-               dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
+               DRM_DEV_ERROR(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
                return PTR_ERR(clk);
        }
        if (IS_ERR(clk))
@@ -688,7 +688,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
        irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        if (irq < 0) {
                ret = irq;
-               dev_err(&pdev->dev, "failed to get irq: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to get irq: %d\n", ret);
                goto fail;
        }
 
@@ -724,12 +724,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
                                ARRAY_SIZE(iommu_ports));
                if (ret) {
-                       dev_err(&pdev->dev, "failed to attach iommu: %d\n",
+                       DRM_DEV_ERROR(&pdev->dev, "failed to attach iommu: %d\n",
                                ret);
                        goto fail;
                }
        } else {
-               dev_info(&pdev->dev,
+               DRM_DEV_INFO(&pdev->dev,
                         "no iommu, fallback to phys contig buffers for scanout\n");
                aspace = NULL;
        }
@@ -738,7 +738,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
        ret = modeset_init(mdp5_kms);
        if (ret) {
-               dev_err(&pdev->dev, "modeset_init failed: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
                goto fail;
        }
 
@@ -795,7 +795,7 @@ static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,
                hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps);
                if (IS_ERR(hwpipe)) {
                        ret = PTR_ERR(hwpipe);
-                       dev_err(dev->dev, "failed to construct pipe for %s (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to construct pipe for %s (%d)\n",
                                        pipe2name(pipes[i]), ret);
                        return ret;
                }
@@ -867,7 +867,7 @@ static int hwmixer_init(struct mdp5_kms *mdp5_kms)
                mixer = mdp5_mixer_init(&hw_cfg->lm.instances[i]);
                if (IS_ERR(mixer)) {
                        ret = PTR_ERR(mixer);
-                       dev_err(dev->dev, "failed to construct LM%d (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to construct LM%d (%d)\n",
                                i, ret);
                        return ret;
                }
@@ -897,7 +897,7 @@ static int interface_init(struct mdp5_kms *mdp5_kms)
 
                intf = kzalloc(sizeof(*intf), GFP_KERNEL);
                if (!intf) {
-                       dev_err(dev->dev, "failed to construct INTF%d\n", i);
+                       DRM_DEV_ERROR(dev->dev, "failed to construct INTF%d\n", i);
                        return -ENOMEM;
                }
 
index 1cc4e57f0226f89c40c5b78baa3045138c89470d..889c2940692c8e4221c6fd1d54c27b1a6ffd8a34 100644 (file)
@@ -132,7 +132,7 @@ static int mdss_irq_domain_init(struct mdp5_mdss *mdp5_mdss)
        d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops,
                                  mdp5_mdss);
        if (!d) {
-               dev_err(dev, "mdss irq domain add failed\n");
+               DRM_DEV_ERROR(dev, "mdss irq domain add failed\n");
                return -ENXIO;
        }
 
@@ -246,7 +246,7 @@ int mdp5_mdss_init(struct drm_device *dev)
 
        ret = msm_mdss_get_clocks(mdp5_mdss);
        if (ret) {
-               dev_err(dev->dev, "failed to get clocks: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get clocks: %d\n", ret);
                goto fail;
        }
 
@@ -259,7 +259,7 @@ int mdp5_mdss_init(struct drm_device *dev)
 
        ret = regulator_enable(mdp5_mdss->vdd);
        if (ret) {
-               dev_err(dev->dev, "failed to enable regulator vdd: %d\n",
+               DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n",
                        ret);
                goto fail;
        }
@@ -267,13 +267,13 @@ int mdp5_mdss_init(struct drm_device *dev)
        ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0),
                               mdss_irq, 0, "mdss_isr", mdp5_mdss);
        if (ret) {
-               dev_err(dev->dev, "failed to init irq: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to init irq: %d\n", ret);
                goto fail_irq;
        }
 
        ret = mdss_irq_domain_init(mdp5_mdss);
        if (ret) {
-               dev_err(dev->dev, "failed to init sub-block irqs: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to init sub-block irqs: %d\n", ret);
                goto fail_irq;
        }
 
index 7f42c3e68a536b4d8512f5d5272c5c142f1ee3bd..be13140967b4e8a294263ed2632673aee73368b0 100644 (file)
@@ -46,7 +46,6 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 
-       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 
        kfree(mdp5_plane);
@@ -126,7 +125,7 @@ static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
 
        SET_PROPERTY(zpos, ZPOS, uint8_t);
 
-       dev_err(dev->dev, "Invalid property\n");
+       DRM_DEV_ERROR(dev->dev, "Invalid property\n");
        ret = -EINVAL;
 done:
        return ret;
@@ -154,7 +153,7 @@ static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
 
        GET_PROPERTY(zpos, ZPOS, uint8_t);
 
-       dev_err(dev->dev, "Invalid property\n");
+       DRM_DEV_ERROR(dev->dev, "Invalid property\n");
        ret = -EINVAL;
 done:
        return ret;
@@ -659,7 +658,7 @@ static int calc_scalex_steps(struct drm_plane *plane,
 
        ret = calc_phase_step(src, dest, &phasex_step);
        if (ret) {
-               dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
+               DRM_DEV_ERROR(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
                return ret;
        }
 
@@ -684,7 +683,7 @@ static int calc_scaley_steps(struct drm_plane *plane,
 
        ret = calc_phase_step(src, dest, &phasey_step);
        if (ret) {
-               dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
+               DRM_DEV_ERROR(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
                return ret;
        }
 
index 96c2b828dba4a7cf2934c95a16fa092a6d1c0152..7cebcb2b3a379246e55faef1dcce6657d2ec3a3a 100644 (file)
@@ -88,7 +88,7 @@ static int smp_request_block(struct mdp5_smp *smp,
 
        avail = cnt - bitmap_weight(state->state, cnt);
        if (nblks > avail) {
-               dev_err(smp->dev->dev, "out of blks (req=%d > avail=%d)\n",
+               DRM_DEV_ERROR(smp->dev->dev, "out of blks (req=%d > avail=%d)\n",
                                nblks, avail);
                return -ENOSPC;
        }
@@ -188,7 +188,7 @@ int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
                DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
                ret = smp_request_block(smp, state, cid, n);
                if (ret) {
-                       dev_err(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
+                       DRM_DEV_ERROR(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
                                        n, ret);
                        return ret;
                }
index a9768f823290bd1037c90a49ccb97273cb46a9a5..7b2a1e6a881079ec39c6d838da7d743a30758642 100644 (file)
@@ -29,7 +29,7 @@ static int dsi_get_phy(struct msm_dsi *msm_dsi)
 
        phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0);
        if (!phy_node) {
-               dev_err(&pdev->dev, "cannot find phy device\n");
+               DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n");
                return -ENXIO;
        }
 
@@ -40,7 +40,7 @@ static int dsi_get_phy(struct msm_dsi *msm_dsi)
        of_node_put(phy_node);
 
        if (!phy_pdev || !msm_dsi->phy) {
-               dev_err(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+               DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
                return -EPROBE_DEFER;
        }
 
@@ -210,7 +210,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *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);
+               DRM_DEV_ERROR(dev->dev, "failed to modeset init host: %d\n", ret);
                goto fail;
        }
 
@@ -222,7 +222,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
        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);
+               DRM_DEV_ERROR(dev->dev, "failed to create dsi bridge: %d\n", ret);
                msm_dsi->bridge = NULL;
                goto fail;
        }
@@ -244,7 +244,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 
        if (IS_ERR(msm_dsi->connector)) {
                ret = PTR_ERR(msm_dsi->connector);
-               dev_err(dev->dev,
+               DRM_DEV_ERROR(dev->dev,
                        "failed to create dsi connector: %d\n", ret);
                msm_dsi->connector = NULL;
                goto fail;
index 9c6c523eacdcb7abe62c3501b5ff6f143be9db12..38e481d2d606f9f8d3a0600c8e5f5495db00a848 100644 (file)
@@ -1050,7 +1050,7 @@ static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
                        msecs_to_jiffies(70));
 
        if (ret <= 0)
-               dev_err(dev, "wait for video done timed out\n");
+               DRM_DEV_ERROR(dev, "wait for video done timed out\n");
 
        dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0);
 }
@@ -1083,6 +1083,8 @@ int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size)
                return PTR_ERR(data);
        }
 
+       msm_gem_object_set_name(msm_host->tx_gem_obj, "tx_gem");
+
        msm_host->tx_size = msm_host->tx_gem_obj->size;
 
        return 0;
@@ -1118,7 +1120,7 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
 
        priv = dev->dev_private;
        if (msm_host->tx_gem_obj) {
-               msm_gem_put_iova(msm_host->tx_gem_obj, priv->kms->aspace);
+               msm_gem_unpin_iova(msm_host->tx_gem_obj, priv->kms->aspace);
                drm_gem_object_put_unlocked(msm_host->tx_gem_obj);
                msm_host->tx_gem_obj = NULL;
        }
@@ -1248,7 +1250,7 @@ int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *dma_base)
        if (!dma_base)
                return -EINVAL;
 
-       return msm_gem_get_iova(msm_host->tx_gem_obj,
+       return msm_gem_get_and_pin_iova(msm_host->tx_gem_obj,
                                priv->kms->aspace, dma_base);
 }
 
@@ -1673,7 +1675,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
 
        prop = of_find_property(ep, "data-lanes", &len);
        if (!prop) {
-               dev_dbg(dev,
+               DRM_DEV_DEBUG(dev,
                        "failed to find data lane mapping, using default\n");
                return 0;
        }
@@ -1681,7 +1683,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
        num_lanes = len / sizeof(u32);
 
        if (num_lanes < 1 || num_lanes > 4) {
-               dev_err(dev, "bad number of data lanes\n");
+               DRM_DEV_ERROR(dev, "bad number of data lanes\n");
                return -EINVAL;
        }
 
@@ -1690,7 +1692,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
        ret = of_property_read_u32_array(ep, "data-lanes", lane_map,
                                         num_lanes);
        if (ret) {
-               dev_err(dev, "failed to read lane data\n");
+               DRM_DEV_ERROR(dev, "failed to read lane data\n");
                return ret;
        }
 
@@ -1711,7 +1713,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
                 */
                for (j = 0; j < num_lanes; j++) {
                        if (lane_map[j] < 0 || lane_map[j] > 3)
-                               dev_err(dev, "bad physical lane entry %u\n",
+                               DRM_DEV_ERROR(dev, "bad physical lane entry %u\n",
                                        lane_map[j]);
 
                        if (swap[lane_map[j]] != j)
@@ -1742,13 +1744,13 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
         */
        endpoint = of_graph_get_endpoint_by_regs(np, 1, -1);
        if (!endpoint) {
-               dev_dbg(dev, "%s: no endpoint\n", __func__);
+               DRM_DEV_DEBUG(dev, "%s: no endpoint\n", __func__);
                return 0;
        }
 
        ret = dsi_host_parse_lane_data(msm_host, endpoint);
        if (ret) {
-               dev_err(dev, "%s: invalid lane configuration %d\n",
+               DRM_DEV_ERROR(dev, "%s: invalid lane configuration %d\n",
                        __func__, ret);
                ret = -EINVAL;
                goto err;
@@ -1757,7 +1759,7 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
        /* Get panel node from the output port's endpoint data */
        device_node = of_graph_get_remote_node(np, 1, 0);
        if (!device_node) {
-               dev_dbg(dev, "%s: no valid device\n", __func__);
+               DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
                ret = -ENODEV;
                goto err;
        }
@@ -1768,7 +1770,7 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
                msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
                                        "syscon-sfpb");
                if (IS_ERR(msm_host->sfpb)) {
-                       dev_err(dev, "%s: failed to get sfpb regmap\n",
+                       DRM_DEV_ERROR(dev, "%s: failed to get sfpb regmap\n",
                                __func__);
                        ret = PTR_ERR(msm_host->sfpb);
                }
@@ -1918,7 +1920,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
        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);
+               DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret);
                return ret;
        }
 
@@ -1926,7 +1928,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
                        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",
+               DRM_DEV_ERROR(&pdev->dev, "failed to request IRQ%u: %d\n",
                                msm_host->irq, ret);
                return ret;
        }
index 9a9fa0c75a131083f32c57f5cd89a0e02c7b87d1..1760483b247e60a17f6b20e6933b83ecab392237 100644 (file)
@@ -404,7 +404,7 @@ static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
 
        ret = devm_regulator_bulk_get(dev, num, s);
        if (ret < 0) {
-               dev_err(dev, "%s: failed to init regulator, ret=%d\n",
+               DRM_DEV_ERROR(dev, "%s: failed to init regulator, ret=%d\n",
                                                __func__, ret);
                return ret;
        }
@@ -441,7 +441,7 @@ static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
                        ret = regulator_set_load(s[i].consumer,
                                                        regs[i].enable_load);
                        if (ret < 0) {
-                               dev_err(dev,
+                               DRM_DEV_ERROR(dev,
                                        "regulator %d set op mode failed, %d\n",
                                        i, ret);
                                goto fail;
@@ -451,7 +451,7 @@ static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
 
        ret = regulator_bulk_enable(num, s);
        if (ret < 0) {
-               dev_err(dev, "regulator enable failed, %d\n", ret);
+               DRM_DEV_ERROR(dev, "regulator enable failed, %d\n", ret);
                goto fail;
        }
 
@@ -472,7 +472,7 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
 
        ret = clk_prepare_enable(phy->ahb_clk);
        if (ret) {
-               dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
+               DRM_DEV_ERROR(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
                pm_runtime_put_sync(dev);
        }
 
@@ -543,7 +543,7 @@ int msm_dsi_phy_init_common(struct msm_dsi_phy *phy)
        phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
                                "DSI_PHY_REG");
        if (IS_ERR(phy->reg_base)) {
-               dev_err(&pdev->dev, "%s: failed to map phy regulator base\n",
+               DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy regulator base\n",
                        __func__);
                ret = -ENOMEM;
                goto fail;
@@ -574,7 +574,7 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
        phy->id = dsi_phy_get_id(phy);
        if (phy->id < 0) {
                ret = phy->id;
-               dev_err(dev, "%s: couldn't identify PHY index, %d\n",
+               DRM_DEV_ERROR(dev, "%s: couldn't identify PHY index, %d\n",
                        __func__, ret);
                goto fail;
        }
@@ -584,20 +584,20 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
 
        phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
        if (IS_ERR(phy->base)) {
-               dev_err(dev, "%s: failed to map phy base\n", __func__);
+               DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
                ret = -ENOMEM;
                goto fail;
        }
 
        ret = dsi_phy_regulator_init(phy);
        if (ret) {
-               dev_err(dev, "%s: failed to init regulator\n", __func__);
+               DRM_DEV_ERROR(dev, "%s: failed to init regulator\n", __func__);
                goto fail;
        }
 
        phy->ahb_clk = msm_clk_get(pdev, "iface");
        if (IS_ERR(phy->ahb_clk)) {
-               dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
+               DRM_DEV_ERROR(dev, "%s: Unable to get ahb clk\n", __func__);
                ret = PTR_ERR(phy->ahb_clk);
                goto fail;
        }
@@ -617,7 +617,7 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
 
        phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
        if (IS_ERR_OR_NULL(phy->pll))
-               dev_info(dev,
+               DRM_DEV_INFO(dev,
                        "%s: pll init failed: %ld, need separate pll clk driver\n",
                        __func__, PTR_ERR(phy->pll));
 
@@ -675,21 +675,21 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
 
        ret = dsi_phy_enable_resource(phy);
        if (ret) {
-               dev_err(dev, "%s: resource enable failed, %d\n",
+               DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n",
                        __func__, ret);
                goto res_en_fail;
        }
 
        ret = dsi_phy_regulator_enable(phy);
        if (ret) {
-               dev_err(dev, "%s: regulator enable failed, %d\n",
+               DRM_DEV_ERROR(dev, "%s: regulator enable failed, %d\n",
                        __func__, ret);
                goto reg_en_fail;
        }
 
        ret = phy->cfg->ops.enable(phy, src_pll_id, clk_req);
        if (ret) {
-               dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
+               DRM_DEV_ERROR(dev, "%s: phy enable failed, %d\n", __func__, ret);
                goto phy_en_fail;
        }
 
@@ -702,7 +702,7 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        if (phy->usecase != MSM_DSI_PHY_SLAVE) {
                ret = msm_dsi_pll_restore_state(phy->pll);
                if (ret) {
-                       dev_err(dev, "%s: failed to restore pll state, %d\n",
+                       DRM_DEV_ERROR(dev, "%s: failed to restore pll state, %d\n",
                                __func__, ret);
                        goto pll_restor_fail;
                }
index b3fffc8dbb2ab572aa688aabe8ef4546728e3fb8..44959e79ce28250c4da3c9f24cd8d83f778cb2d7 100644 (file)
@@ -93,7 +93,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        DBG("");
 
        if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) {
-               dev_err(&phy->pdev->dev,
+               DRM_DEV_ERROR(&phy->pdev->dev,
                        "%s: D-PHY timing calculation failed\n", __func__);
                return -EINVAL;
        }
@@ -172,7 +172,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
 
        ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
        if (ret) {
-               dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
+               DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
                        __func__, ret);
                return ret;
        }
@@ -196,7 +196,7 @@ static int dsi_10nm_phy_init(struct msm_dsi_phy *phy)
        phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
                                     "DSI_PHY_LANE");
        if (IS_ERR(phy->lane_base)) {
-               dev_err(&pdev->dev, "%s: failed to map phy lane base\n",
+               DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n",
                        __func__);
                return -ENOMEM;
        }
index 513f4234adc198c9507289fc058ce08f4e084bbf..a172c667e8bcffad675842077906ca0c28a42714 100644 (file)
@@ -64,7 +64,7 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        void __iomem *lane_base = phy->lane_base;
 
        if (msm_dsi_dphy_timing_calc_v2(timing, clk_req)) {
-               dev_err(&phy->pdev->dev,
+               DRM_DEV_ERROR(&phy->pdev->dev,
                        "%s: D-PHY timing calculation failed\n", __func__);
                return -EINVAL;
        }
@@ -115,7 +115,7 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
 
        ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
        if (ret) {
-               dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
+               DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
                        __func__, ret);
                return ret;
        }
@@ -142,7 +142,7 @@ static int dsi_14nm_phy_init(struct msm_dsi_phy *phy)
        phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
                                "DSI_PHY_LANE");
        if (IS_ERR(phy->lane_base)) {
-               dev_err(&pdev->dev, "%s: failed to map phy lane base\n",
+               DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n",
                        __func__);
                return -ENOMEM;
        }
index 1ca6c69516f57c5740055c6b66d2b4b26c18ff63..9ea9478d370785f4f8e0f897135a5268deabf8fa 100644 (file)
@@ -82,7 +82,7 @@ static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        DBG("");
 
        if (msm_dsi_dphy_timing_calc(timing, clk_req)) {
-               dev_err(&phy->pdev->dev,
+               DRM_DEV_ERROR(&phy->pdev->dev,
                        "%s: D-PHY timing calculation failed\n", __func__);
                return -EINVAL;
        }
index 4972b52cbe447c2cb0083485aa51f6afe95ddec2..c79505d97fe83d83c0b1f2d54c717e609e331fb9 100644 (file)
@@ -76,7 +76,7 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        DBG("");
 
        if (msm_dsi_dphy_timing_calc(timing, clk_req)) {
-               dev_err(&phy->pdev->dev,
+               DRM_DEV_ERROR(&phy->pdev->dev,
                        "%s: D-PHY timing calculation failed\n", __func__);
                return -EINVAL;
        }
index 39800446349848dce6bbfc9d2808d2d615f4152c..98790b44da48b2de94e1fa765430ba2c482ec70b 100644 (file)
@@ -132,7 +132,7 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
        DBG("");
 
        if (msm_dsi_dphy_timing_calc(timing, clk_req)) {
-               dev_err(&phy->pdev->dev,
+               DRM_DEV_ERROR(&phy->pdev->dev,
                        "%s: D-PHY timing calculation failed\n", __func__);
                return -EINVAL;
        }
index 613e206fa4fc2ce8295fa8df3aa029e8811e9423..7a1fb4da2ad346be4c4ac48fdd7848b332593ac3 100644 (file)
@@ -175,7 +175,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
        }
 
        if (IS_ERR(pll)) {
-               dev_err(dev, "%s: failed to init DSI PLL\n", __func__);
+               DRM_DEV_ERROR(dev, "%s: failed to init DSI PLL\n", __func__);
                return pll;
        }
 
index 41bec570c51848f24f378d0982cb987860fd0047..aabab6311043afbc4304de9c2c8db0bf08edc796 100644 (file)
@@ -17,7 +17,7 @@
  *                              |                |
  *                              |                |
  *                 +---------+  |  +----------+  |  +----+
- *  dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0pllbyte
+ *  dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk
  *                 +---------+  |  +----------+  |  +----+
  *                              |                |
  *                              |                |         dsi0_pll_by_2_bit_clk
@@ -25,7 +25,7 @@
  *                              |                |  +----+  |  |\  dsi0_pclk_mux
  *                              |                |--| /2 |--o--| \   |
  *                              |                |  +----+     |  \  |  +---------+
- *                              |                --------------|  |--o--| div_7_4 |-- dsi0pll
+ *                              |                --------------|  |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk
  *                              |------------------------------|  /     +---------+
  *                              |          +-----+             | /
  *                              -----------| /4? |--o----------|/
@@ -690,7 +690,7 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
 
        hws[num++] = hw;
 
-       snprintf(clk_name, 32, "dsi%dpllbyte", pll_10nm->id);
+       snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id);
        snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
 
        /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
@@ -739,7 +739,7 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
 
        hws[num++] = hw;
 
-       snprintf(clk_name, 32, "dsi%dpll", pll_10nm->id);
+       snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id);
        snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id);
 
        /* PIX CLK DIV : DIV_CTRL_7_4*/
@@ -762,7 +762,7 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
        ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                                     pll_10nm->hw_data);
        if (ret) {
-               dev_err(dev, "failed to register clk provider: %d\n", ret);
+               DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
                return ret;
        }
 
@@ -790,13 +790,13 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
 
        pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
        if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) {
-               dev_err(&pdev->dev, "failed to map CMN PHY base\n");
+               DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n");
                return ERR_PTR(-ENOMEM);
        }
 
        pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
        if (IS_ERR_OR_NULL(pll_10nm->mmio)) {
-               dev_err(&pdev->dev, "failed to map PLL base\n");
+               DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -815,7 +815,7 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
 
        ret = pll_10nm_register(pll_10nm);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
                return ERR_PTR(ret);
        }
 
index 71fe60e5f01f1e05e99b45d35db3e47e3dba0bf6..0e18cddd6f22e0eb4bba70ff4ac52af312c9b9d4 100644 (file)
@@ -783,7 +783,7 @@ static int dsi_pll_14nm_enable_seq(struct msm_dsi_pll *pll)
                                         POLL_TIMEOUT_US);
 
        if (unlikely(!locked))
-               dev_err(&pll_14nm->pdev->dev, "DSI PLL lock failed\n");
+               DRM_DEV_ERROR(&pll_14nm->pdev->dev, "DSI PLL lock failed\n");
        else
                DBG("DSI PLL lock success");
 
@@ -829,7 +829,7 @@ static int dsi_pll_14nm_restore_state(struct msm_dsi_pll *pll)
        ret = dsi_pll_14nm_vco_set_rate(&pll->clk_hw,
                                        cached_state->vco_rate, 0);
        if (ret) {
-               dev_err(&pll_14nm->pdev->dev,
+               DRM_DEV_ERROR(&pll_14nm->pdev->dev,
                        "restore vco rate failed. ret=%d\n", ret);
                return ret;
        }
@@ -1039,7 +1039,7 @@ static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm)
        ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                                     pll_14nm->hw_data);
        if (ret) {
-               dev_err(dev, "failed to register clk provider: %d\n", ret);
+               DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
                return ret;
        }
 
@@ -1067,13 +1067,13 @@ struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device *pdev, int id)
 
        pll_14nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
        if (IS_ERR_OR_NULL(pll_14nm->phy_cmn_mmio)) {
-               dev_err(&pdev->dev, "failed to map CMN PHY base\n");
+               DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n");
                return ERR_PTR(-ENOMEM);
        }
 
        pll_14nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
        if (IS_ERR_OR_NULL(pll_14nm->mmio)) {
-               dev_err(&pdev->dev, "failed to map PLL base\n");
+               DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1096,7 +1096,7 @@ struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device *pdev, int id)
 
        ret = pll_14nm_register(pll_14nm);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
                return ERR_PTR(ret);
        }
 
index 26e3a01a99c2b71dde9fed5bd548ee17b61e2df4..dcbbaeb1b1fbb72a5ff66e04c2e4e984ece55f64 100644 (file)
@@ -156,7 +156,7 @@ static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
                if (rate <= lpfr_lut[i].vco_rate)
                        break;
        if (i == LPFR_LUT_SIZE) {
-               dev_err(dev, "unable to get loop filter resistance. vco=%lu\n",
+               DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n",
                                rate);
                return -EINVAL;
        }
@@ -386,7 +386,7 @@ static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll)
        }
 
        if (unlikely(!locked))
-               dev_err(dev, "DSI PLL lock failed\n");
+               DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
        else
                DBG("DSI PLL Lock success");
 
@@ -429,7 +429,7 @@ static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll)
        locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
 
        if (unlikely(!locked))
-               dev_err(dev, "DSI PLL lock failed\n");
+               DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
        else
                DBG("DSI PLL lock success");
 
@@ -468,7 +468,7 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
        ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
                                        cached_state->vco_rate, 0);
        if (ret) {
-               dev_err(&pll_28nm->pdev->dev,
+               DRM_DEV_ERROR(&pll_28nm->pdev->dev,
                        "restore vco rate failed. ret=%d\n", ret);
                return ret;
        }
@@ -581,7 +581,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
        ret = of_clk_add_provider(dev->of_node,
                        of_clk_src_onecell_get, &pll_28nm->clk_data);
        if (ret) {
-               dev_err(dev, "failed to register clk provider: %d\n", ret);
+               DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
                return ret;
        }
 
@@ -607,7 +607,7 @@ struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
 
        pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
        if (IS_ERR_OR_NULL(pll_28nm->mmio)) {
-               dev_err(&pdev->dev, "%s: failed to map pll base\n", __func__);
+               DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -633,13 +633,13 @@ struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
                pll->en_seq_cnt = 1;
                pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp;
        } else {
-               dev_err(&pdev->dev, "phy type (%d) is not 28nm\n", type);
+               DRM_DEV_ERROR(&pdev->dev, "phy type (%d) is not 28nm\n", type);
                return ERR_PTR(-EINVAL);
        }
 
        ret = pll_28nm_register(pll_28nm);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
                return ERR_PTR(ret);
        }
 
index 49008451085b86ccb84ee3760c406554db51fd49..d6897464755f605e9ffe46187c91b56f18638e3b 100644 (file)
@@ -327,7 +327,7 @@ static int dsi_pll_28nm_enable_seq(struct msm_dsi_pll *pll)
        locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
 
        if (unlikely(!locked))
-               dev_err(dev, "DSI PLL lock failed\n");
+               DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
        else
                DBG("DSI PLL lock success");
 
@@ -368,7 +368,7 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
        ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
                                        cached_state->vco_rate, 0);
        if (ret) {
-               dev_err(&pll_28nm->pdev->dev,
+               DRM_DEV_ERROR(&pll_28nm->pdev->dev,
                        "restore vco rate failed. ret=%d\n", ret);
                return ret;
        }
@@ -482,7 +482,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
        ret = of_clk_add_provider(dev->of_node,
                        of_clk_src_onecell_get, &pll_28nm->clk_data);
        if (ret) {
-               dev_err(dev, "failed to register clk provider: %d\n", ret);
+               DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
                return ret;
        }
 
@@ -508,7 +508,7 @@ struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
 
        pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
        if (IS_ERR_OR_NULL(pll_28nm->mmio)) {
-               dev_err(&pdev->dev, "%s: failed to map pll base\n", __func__);
+               DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -526,7 +526,7 @@ struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
 
        ret = pll_28nm_register(pll_28nm);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
                return ERR_PTR(ret);
        }
 
index 0940e84b2821b6df619b901f4c25f2fbf9297828..6a63aba98a3073b3143cf34d37fc36f385cd5c89 100644 (file)
@@ -157,7 +157,7 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
        edp->bridge = msm_edp_bridge_init(edp);
        if (IS_ERR(edp->bridge)) {
                ret = PTR_ERR(edp->bridge);
-               dev_err(dev->dev, "failed to create eDP bridge: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to create eDP bridge: %d\n", ret);
                edp->bridge = NULL;
                goto fail;
        }
@@ -165,7 +165,7 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
        edp->connector = msm_edp_connector_init(edp);
        if (IS_ERR(edp->connector)) {
                ret = PTR_ERR(edp->connector);
-               dev_err(dev->dev, "failed to create eDP connector: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to create eDP connector: %d\n", ret);
                edp->connector = NULL;
                goto fail;
        }
@@ -173,7 +173,7 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
        edp->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        if (edp->irq < 0) {
                ret = edp->irq;
-               dev_err(dev->dev, "failed to get IRQ: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get IRQ: %d\n", ret);
                goto fail;
        }
 
@@ -181,7 +181,7 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
                        edp_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
                        "edp_isr", edp);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+               DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n",
                                edp->irq, ret);
                goto fail;
        }
index adbdce3aeda0039f7779059687774924c7d6561f..e247d6942a49e12ff66789887fa3a49017079ac6 100644 (file)
@@ -98,7 +98,7 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
 
        phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0);
        if (!phy_node) {
-               dev_err(&pdev->dev, "cannot find phy device\n");
+               DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n");
                return -ENXIO;
        }
 
@@ -109,7 +109,7 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
        of_node_put(phy_node);
 
        if (!phy_pdev || !hdmi->phy) {
-               dev_err(&pdev->dev, "phy driver is not ready\n");
+               DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
                return -EPROBE_DEFER;
        }
 
@@ -153,7 +153,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
        hdmi->qfprom_mmio = msm_ioremap(pdev,
                config->qfprom_mmio_name, "HDMI_QFPROM");
        if (IS_ERR(hdmi->qfprom_mmio)) {
-               dev_info(&pdev->dev, "can't find qfprom resource\n");
+               DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n");
                hdmi->qfprom_mmio = NULL;
        }
 
@@ -172,7 +172,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
                                config->hpd_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(&pdev->dev, "failed to get hpd regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %s (%d)\n",
                                        config->hpd_reg_names[i], ret);
                        goto fail;
                }
@@ -195,7 +195,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
                                config->pwr_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(&pdev->dev, "failed to get pwr regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %s (%d)\n",
                                        config->pwr_reg_names[i], ret);
                        goto fail;
                }
@@ -217,7 +217,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
                clk = msm_clk_get(pdev, config->hpd_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
+                       DRM_DEV_ERROR(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
                                        config->hpd_clk_names[i], ret);
                        goto fail;
                }
@@ -239,7 +239,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
                clk = msm_clk_get(pdev, config->pwr_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
+                       DRM_DEV_ERROR(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
                                        config->pwr_clk_names[i], ret);
                        goto fail;
                }
@@ -254,14 +254,14 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev)
        hdmi->i2c = msm_hdmi_i2c_init(hdmi);
        if (IS_ERR(hdmi->i2c)) {
                ret = PTR_ERR(hdmi->i2c);
-               dev_err(&pdev->dev, "failed to get i2c: %d\n", ret);
+               DRM_DEV_ERROR(&pdev->dev, "failed to get i2c: %d\n", ret);
                hdmi->i2c = NULL;
                goto fail;
        }
 
        ret = msm_hdmi_get_phy(hdmi);
        if (ret) {
-               dev_err(&pdev->dev, "failed to get phy\n");
+               DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n");
                goto fail;
        }
 
@@ -303,7 +303,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
        hdmi->bridge = msm_hdmi_bridge_init(hdmi);
        if (IS_ERR(hdmi->bridge)) {
                ret = PTR_ERR(hdmi->bridge);
-               dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
                hdmi->bridge = NULL;
                goto fail;
        }
@@ -311,7 +311,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
        hdmi->connector = msm_hdmi_connector_init(hdmi);
        if (IS_ERR(hdmi->connector)) {
                ret = PTR_ERR(hdmi->connector);
-               dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to create HDMI connector: %d\n", ret);
                hdmi->connector = NULL;
                goto fail;
        }
@@ -319,7 +319,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
        hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        if (hdmi->irq < 0) {
                ret = hdmi->irq;
-               dev_err(dev->dev, "failed to get irq: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret);
                goto fail;
        }
 
@@ -327,7 +327,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
                        msm_hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
                        "hdmi_isr", hdmi);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+               DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n",
                                hdmi->irq, ret);
                goto fail;
        }
@@ -482,7 +482,7 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
        unsigned int level_shift  = 0; /* 0dB */
        bool down_mix = false;
 
-       dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
+       DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
                 params->sample_width, params->cea.channels);
 
        switch (params->cea.channels) {
@@ -533,7 +533,7 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
                rate = HDMI_SAMPLE_RATE_192KHZ;
                break;
        default:
-               dev_err(dev, "rate[%d] not supported!\n",
+               DRM_DEV_ERROR(dev, "rate[%d] not supported!\n",
                        params->sample_rate);
                return -EINVAL;
        }
@@ -585,7 +585,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
        hdmi_cfg = (struct hdmi_platform_config *)
                        of_device_get_match_data(dev);
        if (!hdmi_cfg) {
-               dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name);
+               DRM_DEV_ERROR(dev, "unknown hdmi_cfg: %pOFn\n", of_node);
                return -ENXIO;
        }
 
index 7e357077ed2634dadb2436c6c5abfb0d6625583b..98d61c690260f49a09228c75ee325738ed484aa5 100644 (file)
@@ -40,7 +40,7 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
        for (i = 0; i < config->pwr_reg_cnt; i++) {
                ret = regulator_enable(hdmi->pwr_regs[i]);
                if (ret) {
-                       dev_err(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
                                        config->pwr_reg_names[i], ret);
                }
        }
@@ -49,7 +49,7 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
                DBG("pixclock: %lu", hdmi->pixclock);
                ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
                if (ret) {
-                       dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to set pixel clk: %s (%d)\n",
                                        config->pwr_clk_names[0], ret);
                }
        }
@@ -57,7 +57,7 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
        for (i = 0; i < config->pwr_clk_cnt; i++) {
                ret = clk_prepare_enable(hdmi->pwr_clks[i]);
                if (ret) {
-                       dev_err(dev->dev, "failed to enable pwr clk: %s (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to enable pwr clk: %s (%d)\n",
                                        config->pwr_clk_names[i], ret);
                }
        }
@@ -82,7 +82,7 @@ static void power_off(struct drm_bridge *bridge)
        for (i = 0; i < config->pwr_reg_cnt; i++) {
                ret = regulator_disable(hdmi->pwr_regs[i]);
                if (ret) {
-                       dev_err(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
                                        config->pwr_reg_names[i], ret);
                }
        }
@@ -105,7 +105,7 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
 
        len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
        if (len < 0) {
-               dev_err(&hdmi->pdev->dev,
+               DRM_DEV_ERROR(&hdmi->pdev->dev,
                        "failed to configure avi infoframe\n");
                return;
        }
index 30e908dfded7ed888267d2c7a4a8211764fc6a22..a6eeab2c4dc313d9776d006f2118597264661fad 100644 (file)
@@ -90,7 +90,7 @@ static int gpio_config(struct hdmi *hdmi, bool on)
                        if (gpio.num != -1) {
                                ret = gpio_request(gpio.num, gpio.label);
                                if (ret) {
-                                       dev_err(dev,
+                                       DRM_DEV_ERROR(dev,
                                                "'%s'(%d) gpio_request failed: %d\n",
                                                gpio.label, gpio.num, ret);
                                        goto err;
@@ -156,7 +156,7 @@ static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
 
                        ret = clk_prepare_enable(hdmi->hpd_clks[i]);
                        if (ret) {
-                               dev_err(dev,
+                               DRM_DEV_ERROR(dev,
                                        "failed to enable hpd clk: %s (%d)\n",
                                        config->hpd_clk_names[i], ret);
                        }
@@ -180,7 +180,7 @@ int msm_hdmi_hpd_enable(struct drm_connector *connector)
        for (i = 0; i < config->hpd_reg_cnt; i++) {
                ret = regulator_enable(hdmi->hpd_regs[i]);
                if (ret) {
-                       dev_err(dev, "failed to enable hpd regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(dev, "failed to enable hpd regulator: %s (%d)\n",
                                        config->hpd_reg_names[i], ret);
                        goto fail;
                }
@@ -188,13 +188,13 @@ int msm_hdmi_hpd_enable(struct drm_connector *connector)
 
        ret = pinctrl_pm_select_default_state(dev);
        if (ret) {
-               dev_err(dev, "pinctrl state chg failed: %d\n", ret);
+               DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret);
                goto fail;
        }
 
        ret = gpio_config(hdmi, true);
        if (ret) {
-               dev_err(dev, "failed to configure GPIOs: %d\n", ret);
+               DRM_DEV_ERROR(dev, "failed to configure GPIOs: %d\n", ret);
                goto fail;
        }
 
index 73e20219d431a78c4ec9d3f335c430efbf2c49af..25d2fe2c60e8ad701fa06e31156f1f4b93e66334 100644 (file)
@@ -66,7 +66,7 @@ static int ddc_clear_irq(struct hdmi_i2c_adapter *hdmi_i2c)
        } while ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT) && retry);
 
        if (!retry) {
-               dev_err(dev->dev, "timeout waiting for DDC\n");
+               DRM_DEV_ERROR(dev->dev, "timeout waiting for DDC\n");
                return -ETIMEDOUT;
        }
 
index 4157722d6b4dc897bd46cda2ce27436b2caa368b..1f4331ed69bd6a4938bce6229e0ca18df394b095 100644 (file)
@@ -37,7 +37,7 @@ static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
                reg = devm_regulator_get(dev, cfg->reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(dev, "failed to get phy regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(dev, "failed to get phy regulator: %s (%d)\n",
                                cfg->reg_names[i], ret);
                        return ret;
                }
@@ -51,7 +51,7 @@ static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
                clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(dev, "failed to get phy clock: %s (%d)\n",
+                       DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",
                                cfg->clk_names[i], ret);
                        return ret;
                }
@@ -73,14 +73,14 @@ int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)
        for (i = 0; i < cfg->num_regs; i++) {
                ret = regulator_enable(phy->regs[i]);
                if (ret)
-                       dev_err(dev, "failed to enable regulator: %s (%d)\n",
+                       DRM_DEV_ERROR(dev, "failed to enable regulator: %s (%d)\n",
                                cfg->reg_names[i], ret);
        }
 
        for (i = 0; i < cfg->num_clks; i++) {
                ret = clk_prepare_enable(phy->clks[i]);
                if (ret)
-                       dev_err(dev, "failed to enable clock: %s (%d)\n",
+                       DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",
                                cfg->clk_names[i], ret);
        }
 
@@ -159,7 +159,7 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
 
        phy->mmio = msm_ioremap(pdev, "hdmi_phy", "HDMI_PHY");
        if (IS_ERR(phy->mmio)) {
-               dev_err(dev, "%s: failed to map phy base\n", __func__);
+               DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
                return -ENOMEM;
        }
 
@@ -177,7 +177,7 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
 
        ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
        if (ret) {
-               dev_err(dev, "couldn't init PLL\n");
+               DRM_DEV_ERROR(dev, "couldn't init PLL\n");
                msm_hdmi_phy_resource_disable(phy);
                return ret;
        }
index 0df504c61833c5e614a85698cab31a0c8027fe70..318708f26731e3b1540b3f0fef2039f2e54a96bf 100644 (file)
@@ -725,7 +725,7 @@ int msm_hdmi_pll_8996_init(struct platform_device *pdev)
 
        pll->mmio_qserdes_com = msm_ioremap(pdev, "hdmi_pll", "HDMI_PLL");
        if (IS_ERR(pll->mmio_qserdes_com)) {
-               dev_err(dev, "failed to map pll base\n");
+               DRM_DEV_ERROR(dev, "failed to map pll base\n");
                return -ENOMEM;
        }
 
@@ -737,7 +737,7 @@ int msm_hdmi_pll_8996_init(struct platform_device *pdev)
 
                pll->mmio_qserdes_tx[i] = msm_ioremap(pdev, name, label);
                if (IS_ERR(pll->mmio_qserdes_tx[i])) {
-                       dev_err(dev, "failed to map pll base\n");
+                       DRM_DEV_ERROR(dev, "failed to map pll base\n");
                        return -ENOMEM;
                }
        }
@@ -745,7 +745,7 @@ int msm_hdmi_pll_8996_init(struct platform_device *pdev)
 
        clk = devm_clk_register(dev, &pll->clk_hw);
        if (IS_ERR(clk)) {
-               dev_err(dev, "failed to register pll clock\n");
+               DRM_DEV_ERROR(dev, "failed to register pll clock\n");
                return -EINVAL;
        }
 
index 99590758c68b7cf8e296928db1bab5ce5b2df4c4..c6dae6e437f97460232df84d9ae0a499d343f30c 100644 (file)
@@ -445,7 +445,7 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev)
 
        pll->mmio = msm_ioremap(pdev, "hdmi_pll", "HDMI_PLL");
        if (IS_ERR(pll->mmio)) {
-               dev_err(dev, "failed to map pll base\n");
+               DRM_DEV_ERROR(dev, "failed to map pll base\n");
                return -ENOMEM;
        }
 
@@ -454,7 +454,7 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev)
 
        clk = devm_clk_register(dev, &pll->clk_hw);
        if (IS_ERR(clk)) {
-               dev_err(dev, "failed to register pll clock\n");
+               DRM_DEV_ERROR(dev, "failed to register pll clock\n");
                return -EINVAL;
        }
 
index 2088a20eb27024f8e868d17b1eb04343a3ad37bb..f5b1256e32b645fa9c7bac934dbd2aa587f039cf 100644 (file)
@@ -83,7 +83,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
                kms->funcs->commit(kms, state);
        }
 
-       msm_atomic_wait_for_commit_done(dev, state);
+       if (!state->legacy_cursor_update)
+               msm_atomic_wait_for_commit_done(dev, state);
 
        kms->funcs->complete_commit(kms, state);
 
index d756436c1fcd3293f40db2d9efda018603c496e4..fb423d309e91b9c0bd356b4c91740ba101adfc01 100644 (file)
@@ -201,13 +201,13 @@ static int late_init_minor(struct drm_minor *minor)
 
        ret = msm_rd_debugfs_init(minor);
        if (ret) {
-               dev_err(minor->dev->dev, "could not install rd debugfs\n");
+               DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n");
                return ret;
        }
 
        ret = msm_perf_debugfs_init(minor);
        if (ret) {
-               dev_err(minor->dev->dev, "could not install perf debugfs\n");
+               DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n");
                return ret;
        }
 
@@ -235,14 +235,14 @@ int msm_debugfs_init(struct drm_minor *minor)
                        minor->debugfs_root, minor);
 
        if (ret) {
-               dev_err(dev->dev, "could not install msm_debugfs_list\n");
+               DRM_DEV_ERROR(dev->dev, "could not install msm_debugfs_list\n");
                return ret;
        }
 
        debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root,
                dev, &msm_gpu_fops);
 
-       if (priv->kms->funcs->debugfs_init) {
+       if (priv->kms && priv->kms->funcs->debugfs_init) {
                ret = priv->kms->funcs->debugfs_init(priv->kms, minor);
                if (ret)
                        return ret;
index dcff812c63d0739ee3dd867e63a503f1bee5e1f1..d2cdc7b553feb4dd8b3864dfa69c3bad3502c273 100644 (file)
 #include "msm_drv.h"
 #include "msm_debugfs.h"
 #include "msm_fence.h"
+#include "msm_gem.h"
 #include "msm_gpu.h"
 #include "msm_kms.h"
+#include "adreno/adreno_gpu.h"
 
 
 /*
  * - 1.3.0 - adds GMEM_BASE + NR_RINGS params, SUBMITQUEUE_NEW +
  *           SUBMITQUEUE_CLOSE ioctls, and MSM_INFO_IOVA flag for
  *           MSM_GEM_INFO ioctl.
+ * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get
+ *           GEM object's debug name
  */
 #define MSM_VERSION_MAJOR      1
-#define MSM_VERSION_MINOR      3
+#define MSM_VERSION_MINOR      4
 #define MSM_VERSION_PATCHLEVEL 0
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -170,7 +174,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        if (!res) {
-               dev_err(&pdev->dev, "failed to get memory resource: %s\n", name);
+               DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name);
                return ERR_PTR(-EINVAL);
        }
 
@@ -178,7 +182,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
 
        ptr = devm_ioremap_nocache(&pdev->dev, res->start, size);
        if (!ptr) {
-               dev_err(&pdev->dev, "failed to ioremap: %s\n", name);
+               DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -312,6 +316,7 @@ static int msm_drm_uninit(struct device *dev)
        if (fbdev && priv->fbdev)
                msm_fbdev_free(ddev);
 #endif
+       drm_atomic_helper_shutdown(ddev);
        drm_mode_config_cleanup(ddev);
 
        pm_runtime_get_sync(dev);
@@ -357,6 +362,14 @@ static int get_mdp_ver(struct platform_device *pdev)
 
 #include <linux/of_address.h>
 
+bool msm_use_mmu(struct drm_device *dev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+
+       /* a2xx comes with its own MMU */
+       return priv->is_a2xx || iommu_present(&platform_bus_type);
+}
+
 static int msm_init_vram(struct drm_device *dev)
 {
        struct msm_drm_private *priv = dev->dev_private;
@@ -395,7 +408,7 @@ static int msm_init_vram(struct drm_device *dev)
                 * Grab the entire CMA chunk carved out in early startup in
                 * mach-msm:
                 */
-       } else if (!iommu_present(&platform_bus_type)) {
+       } else if (!msm_use_mmu(dev)) {
                DRM_INFO("using %s VRAM carveout\n", vram);
                size = memparse(vram, NULL);
        }
@@ -418,12 +431,12 @@ static int msm_init_vram(struct drm_device *dev)
                p = dma_alloc_attrs(dev->dev, size,
                                &priv->vram.paddr, GFP_KERNEL, attrs);
                if (!p) {
-                       dev_err(dev->dev, "failed to allocate VRAM\n");
+                       DRM_DEV_ERROR(dev->dev, "failed to allocate VRAM\n");
                        priv->vram.paddr = 0;
                        return -ENOMEM;
                }
 
-               dev_info(dev->dev, "VRAM: %08x->%08x\n",
+               DRM_DEV_INFO(dev->dev, "VRAM: %08x->%08x\n",
                                (uint32_t)priv->vram.paddr,
                                (uint32_t)(priv->vram.paddr + size));
        }
@@ -443,7 +456,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 
        ddev = drm_dev_alloc(drv, dev);
        if (IS_ERR(ddev)) {
-               dev_err(dev, "failed to allocate drm_device\n");
+               DRM_DEV_ERROR(dev, "failed to allocate drm_device\n");
                return PTR_ERR(ddev);
        }
 
@@ -507,19 +520,16 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
                priv->kms = kms;
                break;
        default:
-               kms = ERR_PTR(-ENODEV);
+               /* valid only for the dummy headless case, where of_node=NULL */
+               WARN_ON(dev->of_node);
+               kms = NULL;
                break;
        }
 
        if (IS_ERR(kms)) {
-               /*
-                * NOTE: once we have GPU support, having no kms should not
-                * be considered fatal.. ideally we would still support gpu
-                * and (for example) use dmabuf/prime to share buffers with
-                * imx drm driver on iMX5
-                */
-               dev_err(dev, "failed to load kms\n");
+               DRM_DEV_ERROR(dev, "failed to load kms\n");
                ret = PTR_ERR(kms);
+               priv->kms = NULL;
                goto err_msm_uninit;
        }
 
@@ -529,7 +539,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
        if (kms) {
                ret = kms->funcs->hw_init(kms);
                if (ret) {
-                       dev_err(dev, "kms hw init failed: %d\n", ret);
+                       DRM_DEV_ERROR(dev, "kms hw init failed: %d\n", ret);
                        goto err_msm_uninit;
                }
        }
@@ -554,7 +564,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
                                &priv->disp_thread[i].worker,
                                "crtc_commit:%d", priv->disp_thread[i].crtc_id);
                if (IS_ERR(priv->disp_thread[i].thread)) {
-                       dev_err(dev, "failed to create crtc_commit kthread\n");
+                       DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n");
                        priv->disp_thread[i].thread = NULL;
                        goto err_msm_uninit;
                }
@@ -574,7 +584,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
                                &priv->event_thread[i].worker,
                                "crtc_event:%d", priv->event_thread[i].crtc_id);
                if (IS_ERR(priv->event_thread[i].thread)) {
-                       dev_err(dev, "failed to create crtc_event kthread\n");
+                       DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n");
                        priv->event_thread[i].thread = NULL;
                        goto err_msm_uninit;
                }
@@ -595,7 +605,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 
        ret = drm_vblank_init(ddev, priv->num_crtcs);
        if (ret < 0) {
-               dev_err(dev, "failed to initialize vblank\n");
+               DRM_DEV_ERROR(dev, "failed to initialize vblank\n");
                goto err_msm_uninit;
        }
 
@@ -604,7 +614,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
                ret = drm_irq_install(ddev, kms->irq);
                pm_runtime_put_sync(dev);
                if (ret < 0) {
-                       dev_err(dev, "failed to install IRQ handler\n");
+                       DRM_DEV_ERROR(dev, "failed to install IRQ handler\n");
                        goto err_msm_uninit;
                }
        }
@@ -616,7 +626,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
        drm_mode_config_reset(ddev);
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
-       if (fbdev)
+       if (kms && fbdev)
                priv->fbdev = msm_fbdev_init(ddev);
 #endif
 
@@ -724,7 +734,11 @@ static int msm_irq_postinstall(struct drm_device *dev)
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_kms *kms = priv->kms;
        BUG_ON(!kms);
-       return kms->funcs->irq_postinstall(kms);
+
+       if (kms->funcs->irq_postinstall)
+               return kms->funcs->irq_postinstall(kms);
+
+       return 0;
 }
 
 static void msm_irq_uninstall(struct drm_device *dev)
@@ -791,7 +805,7 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
        }
 
        return msm_gem_new_handle(dev, file, args->size,
-                       args->flags, &args->handle);
+                       args->flags, &args->handle, NULL);
 }
 
 static inline ktime_t to_ktime(struct drm_msm_timespec timeout)
@@ -849,6 +863,10 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
        if (!priv->gpu)
                return -EINVAL;
 
+       /*
+        * Don't pin the memory here - just get an address so that userspace can
+        * be productive
+        */
        return msm_gem_get_iova(obj, priv->gpu->aspace, iova);
 }
 
@@ -857,23 +875,66 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
 {
        struct drm_msm_gem_info *args = data;
        struct drm_gem_object *obj;
-       int ret = 0;
+       struct msm_gem_object *msm_obj;
+       int i, ret = 0;
 
-       if (args->flags & ~MSM_INFO_FLAGS)
+       if (args->pad)
+               return -EINVAL;
+
+       switch (args->info) {
+       case MSM_INFO_GET_OFFSET:
+       case MSM_INFO_GET_IOVA:
+               /* value returned as immediate, not pointer, so len==0: */
+               if (args->len)
+                       return -EINVAL;
+               break;
+       case MSM_INFO_SET_NAME:
+       case MSM_INFO_GET_NAME:
+               break;
+       default:
                return -EINVAL;
+       }
 
        obj = drm_gem_object_lookup(file, args->handle);
        if (!obj)
                return -ENOENT;
 
-       if (args->flags & MSM_INFO_IOVA) {
-               uint64_t iova;
+       msm_obj = to_msm_bo(obj);
 
-               ret = msm_ioctl_gem_info_iova(dev, obj, &iova);
-               if (!ret)
-                       args->offset = iova;
-       } else {
-               args->offset = msm_gem_mmap_offset(obj);
+       switch (args->info) {
+       case MSM_INFO_GET_OFFSET:
+               args->value = msm_gem_mmap_offset(obj);
+               break;
+       case MSM_INFO_GET_IOVA:
+               ret = msm_ioctl_gem_info_iova(dev, obj, &args->value);
+               break;
+       case MSM_INFO_SET_NAME:
+               /* length check should leave room for terminating null: */
+               if (args->len >= sizeof(msm_obj->name)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = copy_from_user(msm_obj->name,
+                       u64_to_user_ptr(args->value), args->len);
+               msm_obj->name[args->len] = '\0';
+               for (i = 0; i < args->len; i++) {
+                       if (!isprint(msm_obj->name[i])) {
+                               msm_obj->name[i] = '\0';
+                               break;
+                       }
+               }
+               break;
+       case MSM_INFO_GET_NAME:
+               if (args->value && (args->len < strlen(msm_obj->name))) {
+                       ret = -EINVAL;
+                       break;
+               }
+               args->len = strlen(msm_obj->name);
+               if (args->value) {
+                       ret = copy_to_user(u64_to_user_ptr(args->value),
+                                       msm_obj->name, args->len);
+               }
+               break;
        }
 
        drm_gem_object_put_unlocked(obj);
@@ -1052,18 +1113,15 @@ static int msm_pm_suspend(struct device *dev)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct msm_drm_private *priv = ddev->dev_private;
-       struct msm_kms *kms = priv->kms;
-
-       /* TODO: Use atomic helper suspend/resume */
-       if (kms && kms->funcs && kms->funcs->pm_suspend)
-               return kms->funcs->pm_suspend(dev);
 
-       drm_kms_helper_poll_disable(ddev);
+       if (WARN_ON(priv->pm_state))
+               drm_atomic_state_put(priv->pm_state);
 
        priv->pm_state = drm_atomic_helper_suspend(ddev);
        if (IS_ERR(priv->pm_state)) {
-               drm_kms_helper_poll_enable(ddev);
-               return PTR_ERR(priv->pm_state);
+               int ret = PTR_ERR(priv->pm_state);
+               DRM_ERROR("Failed to suspend dpu, %d\n", ret);
+               return ret;
        }
 
        return 0;
@@ -1073,16 +1131,16 @@ static int msm_pm_resume(struct device *dev)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct msm_drm_private *priv = ddev->dev_private;
-       struct msm_kms *kms = priv->kms;
+       int ret;
 
-       /* TODO: Use atomic helper suspend/resume */
-       if (kms && kms->funcs && kms->funcs->pm_resume)
-               return kms->funcs->pm_resume(dev);
+       if (WARN_ON(!priv->pm_state))
+               return -ENOENT;
 
-       drm_atomic_helper_resume(ddev, priv->pm_state);
-       drm_kms_helper_poll_enable(ddev);
+       ret = drm_atomic_helper_resume(ddev, priv->pm_state);
+       if (!ret)
+               priv->pm_state = NULL;
 
-       return 0;
+       return ret;
 }
 #endif
 
@@ -1167,7 +1225,7 @@ static int add_components_mdp(struct device *mdp_dev,
 
                ret = of_graph_parse_endpoint(ep_node, &ep);
                if (ret) {
-                       dev_err(mdp_dev, "unable to parse port endpoint\n");
+                       DRM_DEV_ERROR(mdp_dev, "unable to parse port endpoint\n");
                        of_node_put(ep_node);
                        return ret;
                }
@@ -1189,8 +1247,10 @@ static int add_components_mdp(struct device *mdp_dev,
                if (!intf)
                        continue;
 
-               drm_of_component_match_add(master_dev, matchptr, compare_of,
-                                          intf);
+               if (of_device_is_available(intf))
+                       drm_of_component_match_add(master_dev, matchptr,
+                                                  compare_of, intf);
+
                of_node_put(intf);
        }
 
@@ -1218,13 +1278,13 @@ static int add_display_components(struct device *dev,
            of_device_is_compatible(dev->of_node, "qcom,sdm845-mdss")) {
                ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
                if (ret) {
-                       dev_err(dev, "failed to populate children devices\n");
+                       DRM_DEV_ERROR(dev, "failed to populate children devices\n");
                        return ret;
                }
 
                mdp_dev = device_find_child(dev, NULL, compare_name_mdp);
                if (!mdp_dev) {
-                       dev_err(dev, "failed to find MDSS MDP node\n");
+                       DRM_DEV_ERROR(dev, "failed to find MDSS MDP node\n");
                        of_platform_depopulate(dev);
                        return -ENODEV;
                }
@@ -1254,6 +1314,7 @@ static int add_display_components(struct device *dev,
 static const struct of_device_id msm_gpu_match[] = {
        { .compatible = "qcom,adreno" },
        { .compatible = "qcom,adreno-3xx" },
+       { .compatible = "amd,imageon" },
        { .compatible = "qcom,kgsl-3d0" },
        { },
 };
@@ -1298,9 +1359,11 @@ static int msm_pdev_probe(struct platform_device *pdev)
        struct component_match *match = NULL;
        int ret;
 
-       ret = add_display_components(&pdev->dev, &match);
-       if (ret)
-               return ret;
+       if (get_mdp_ver(pdev)) {
+               ret = add_display_components(&pdev->dev, &match);
+               if (ret)
+                       return ret;
+       }
 
        ret = add_gpu_components(&pdev->dev, &match);
        if (ret)
index 9d11f321f5a9286c5b046c8fc46f04622ed22d2c..9cd6a96c6bf2a522d413681f20d918753921f554 100644 (file)
@@ -179,6 +179,8 @@ struct msm_drm_private {
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
        struct msm_file_private *lastctx;
+       /* gpu is only set on open(), but we need this info earlier */
+       bool is_a2xx;
 
        struct drm_fb_helper *fbdev;
 
@@ -241,10 +243,16 @@ struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev);
 void msm_atomic_state_clear(struct drm_atomic_state *state);
 void msm_atomic_state_free(struct drm_atomic_state *state);
 
+int msm_gem_init_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, int npages);
+void msm_gem_purge_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma);
 void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt);
+               struct msm_gem_vma *vma);
 int msm_gem_map_vma(struct msm_gem_address_space *aspace,
                struct msm_gem_vma *vma, struct sg_table *sgt, int npages);
+void msm_gem_close_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma);
 
 void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
 
@@ -252,9 +260,15 @@ struct msm_gem_address_space *
 msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
                const char *name);
 
+struct msm_gem_address_space *
+msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
+               const char *name, uint64_t va_start, uint64_t va_end);
+
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
+bool msm_use_mmu(struct drm_device *dev);
+
 void msm_gem_submit_free(struct msm_gem_submit *submit);
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                struct drm_file *file);
@@ -269,12 +283,14 @@ vm_fault_t msm_gem_fault(struct vm_fault *vmf);
 uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
 int msm_gem_get_iova(struct drm_gem_object *obj,
                struct msm_gem_address_space *aspace, uint64_t *iova);
+int msm_gem_get_and_pin_iova(struct drm_gem_object *obj,
+               struct msm_gem_address_space *aspace, uint64_t *iova);
 uint64_t msm_gem_iova(struct drm_gem_object *obj,
                struct msm_gem_address_space *aspace);
+void msm_gem_unpin_iova(struct drm_gem_object *obj,
+               struct msm_gem_address_space *aspace);
 struct page **msm_gem_get_pages(struct drm_gem_object *obj);
 void msm_gem_put_pages(struct drm_gem_object *obj);
-void msm_gem_put_iova(struct drm_gem_object *obj,
-               struct msm_gem_address_space *aspace);
 int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
                struct drm_mode_create_dumb *args);
 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
@@ -301,7 +317,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout);
 int msm_gem_cpu_fini(struct drm_gem_object *obj);
 void msm_gem_free_object(struct drm_gem_object *obj);
 int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
-               uint32_t size, uint32_t flags, uint32_t *handle);
+               uint32_t size, uint32_t flags, uint32_t *handle, char *name);
 struct drm_gem_object *msm_gem_new(struct drm_device *dev,
                uint32_t size, uint32_t flags);
 struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev,
@@ -312,9 +328,13 @@ void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
 void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size,
                uint32_t flags, struct msm_gem_address_space *aspace,
                struct drm_gem_object **bo, uint64_t *iova);
+void msm_gem_kernel_put(struct drm_gem_object *bo,
+               struct msm_gem_address_space *aspace, bool locked);
 struct drm_gem_object *msm_gem_import(struct drm_device *dev,
                struct dma_buf *dmabuf, struct sg_table *sgt);
 
+void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);
+
 int msm_framebuffer_prepare(struct drm_framebuffer *fb,
                struct msm_gem_address_space *aspace);
 void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
index 2a7348aeb38d1a785c79b874a4d6fef9bb080017..67dfd8d3dc12caaaf9c17c7e5c3d6dbc344bb696 100644 (file)
@@ -66,7 +66,7 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb,
        uint64_t iova;
 
        for (i = 0; i < n; i++) {
-               ret = msm_gem_get_iova(fb->obj[i], aspace, &iova);
+               ret = msm_gem_get_and_pin_iova(fb->obj[i], aspace, &iova);
                DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret);
                if (ret)
                        return ret;
@@ -81,7 +81,7 @@ void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
        int i, n = fb->format->num_planes;
 
        for (i = 0; i < n; i++)
-               msm_gem_put_iova(fb->obj[i], aspace);
+               msm_gem_unpin_iova(fb->obj[i], aspace);
 }
 
 uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
@@ -154,7 +154,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
        format = kms->funcs->get_format(kms, mode_cmd->pixel_format,
                        mode_cmd->modifier[0]);
        if (!format) {
-               dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
+               DRM_DEV_ERROR(dev->dev, "unsupported pixel format: %4.4s\n",
                                (char *)&mode_cmd->pixel_format);
                ret = -EINVAL;
                goto fail;
@@ -196,7 +196,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
 
        ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs);
        if (ret) {
-               dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "framebuffer init failed: %d\n", ret);
                goto fail;
        }
 
@@ -233,13 +233,15 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format
                bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
        }
        if (IS_ERR(bo)) {
-               dev_err(dev->dev, "failed to allocate buffer object\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate buffer object\n");
                return ERR_CAST(bo);
        }
 
+       msm_gem_object_set_name(bo, "stolenfb");
+
        fb = msm_framebuffer_init(dev, &mode_cmd, &bo);
        if (IS_ERR(fb)) {
-               dev_err(dev->dev, "failed to allocate fb\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
                /* note: if fb creation failed, we can't rely on fb destroy
                 * to unref the bo:
                 */
index 456622b4633558b7d0d98a1d57729aac9d33c57f..c03e860ba737f8d56d0759c239b416086c66fb55 100644 (file)
@@ -91,7 +91,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
                        sizes->surface_height, pitch, format);
 
        if (IS_ERR(fb)) {
-               dev_err(dev->dev, "failed to allocate fb\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
                return PTR_ERR(fb);
        }
 
@@ -104,15 +104,15 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
         * in panic (ie. lock-safe, etc) we could avoid pinning the
         * buffer now:
         */
-       ret = msm_gem_get_iova(bo, priv->kms->aspace, &paddr);
+       ret = msm_gem_get_and_pin_iova(bo, priv->kms->aspace, &paddr);
        if (ret) {
-               dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "failed to get buffer obj iova: %d\n", ret);
                goto fail_unlock;
        }
 
        fbi = drm_fb_helper_alloc_fbi(helper);
        if (IS_ERR(fbi)) {
-               dev_err(dev->dev, "failed to allocate fb info\n");
+               DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n");
                ret = PTR_ERR(fbi);
                goto fail_unlock;
        }
@@ -176,7 +176,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
 
        ret = drm_fb_helper_init(dev, helper, priv->num_connectors);
        if (ret) {
-               dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret);
+               DRM_DEV_ERROR(dev->dev, "could not init fbdev: ret=%d\n", ret);
                goto fail;
        }
 
index f59ca27a4a357492f96d0b7e37c76536037b40d6..51a95da694d8d498dee29bd91ddb880b3478c356 100644 (file)
@@ -88,7 +88,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
                        p = get_pages_vram(obj, npages);
 
                if (IS_ERR(p)) {
-                       dev_err(dev->dev, "could not get pages: %ld\n",
+                       DRM_DEV_ERROR(dev->dev, "could not get pages: %ld\n",
                                        PTR_ERR(p));
                        return p;
                }
@@ -99,7 +99,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
                if (IS_ERR(msm_obj->sgt)) {
                        void *ptr = ERR_CAST(msm_obj->sgt);
 
-                       dev_err(dev->dev, "failed to allocate sgt\n");
+                       DRM_DEV_ERROR(dev->dev, "failed to allocate sgt\n");
                        msm_obj->sgt = NULL;
                        return ptr;
                }
@@ -280,7 +280,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)
        ret = drm_gem_create_mmap_offset(obj);
 
        if (ret) {
-               dev_err(dev->dev, "could not allocate mmap offset\n");
+               DRM_DEV_ERROR(dev->dev, "could not allocate mmap offset\n");
                return 0;
        }
 
@@ -352,63 +352,104 @@ put_iova(struct drm_gem_object *obj)
        WARN_ON(!mutex_is_locked(&msm_obj->lock));
 
        list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) {
-               msm_gem_unmap_vma(vma->aspace, vma, msm_obj->sgt);
+               msm_gem_purge_vma(vma->aspace, vma);
+               msm_gem_close_vma(vma->aspace, vma);
                del_vma(vma);
        }
 }
 
-/* get iova, taking a reference.  Should have a matching put */
-int msm_gem_get_iova(struct drm_gem_object *obj,
+static int msm_gem_get_iova_locked(struct drm_gem_object *obj,
                struct msm_gem_address_space *aspace, uint64_t *iova)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        struct msm_gem_vma *vma;
        int ret = 0;
 
-       mutex_lock(&msm_obj->lock);
-
-       if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) {
-               mutex_unlock(&msm_obj->lock);
-               return -EBUSY;
-       }
+       WARN_ON(!mutex_is_locked(&msm_obj->lock));
 
        vma = lookup_vma(obj, aspace);
 
        if (!vma) {
-               struct page **pages;
-
                vma = add_vma(obj, aspace);
-               if (IS_ERR(vma)) {
-                       ret = PTR_ERR(vma);
-                       goto unlock;
-               }
+               if (IS_ERR(vma))
+                       return PTR_ERR(vma);
 
-               pages = get_pages(obj);
-               if (IS_ERR(pages)) {
-                       ret = PTR_ERR(pages);
-                       goto fail;
+               ret = msm_gem_init_vma(aspace, vma, obj->size >> PAGE_SHIFT);
+               if (ret) {
+                       del_vma(vma);
+                       return ret;
                }
-
-               ret = msm_gem_map_vma(aspace, vma, msm_obj->sgt,
-                               obj->size >> PAGE_SHIFT);
-               if (ret)
-                       goto fail;
        }
 
        *iova = vma->iova;
+       return 0;
+}
+
+static int msm_gem_pin_iova(struct drm_gem_object *obj,
+               struct msm_gem_address_space *aspace)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       struct msm_gem_vma *vma;
+       struct page **pages;
+
+       WARN_ON(!mutex_is_locked(&msm_obj->lock));
+
+       if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED))
+               return -EBUSY;
+
+       vma = lookup_vma(obj, aspace);
+       if (WARN_ON(!vma))
+               return -EINVAL;
+
+       pages = get_pages(obj);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       return msm_gem_map_vma(aspace, vma, msm_obj->sgt,
+                       obj->size >> PAGE_SHIFT);
+}
+
+/* get iova and pin it. Should have a matching put */
+int msm_gem_get_and_pin_iova(struct drm_gem_object *obj,
+               struct msm_gem_address_space *aspace, uint64_t *iova)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       u64 local;
+       int ret;
+
+       mutex_lock(&msm_obj->lock);
+
+       ret = msm_gem_get_iova_locked(obj, aspace, &local);
+
+       if (!ret)
+               ret = msm_gem_pin_iova(obj, aspace);
+
+       if (!ret)
+               *iova = local;
 
        mutex_unlock(&msm_obj->lock);
-       return 0;
+       return ret;
+}
 
-fail:
-       del_vma(vma);
-unlock:
+/*
+ * Get an iova but don't pin it. Doesn't need a put because iovas are currently
+ * valid for the life of the object
+ */
+int msm_gem_get_iova(struct drm_gem_object *obj,
+               struct msm_gem_address_space *aspace, uint64_t *iova)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       int ret;
+
+       mutex_lock(&msm_obj->lock);
+       ret = msm_gem_get_iova_locked(obj, aspace, iova);
        mutex_unlock(&msm_obj->lock);
+
        return ret;
 }
 
 /* get iova without taking a reference, used in places where you have
- * already done a 'msm_gem_get_iova()'.
+ * already done a 'msm_gem_get_and_pin_iova' or 'msm_gem_get_iova'
  */
 uint64_t msm_gem_iova(struct drm_gem_object *obj,
                struct msm_gem_address_space *aspace)
@@ -424,15 +465,24 @@ uint64_t msm_gem_iova(struct drm_gem_object *obj,
        return vma ? vma->iova : 0;
 }
 
-void msm_gem_put_iova(struct drm_gem_object *obj,
+/*
+ * Unpin a iova by updating the reference counts. The memory isn't actually
+ * purged until something else (shrinker, mm_notifier, destroy, etc) decides
+ * to get rid of it
+ */
+void msm_gem_unpin_iova(struct drm_gem_object *obj,
                struct msm_gem_address_space *aspace)
 {
-       // XXX TODO ..
-       // NOTE: probably don't need a _locked() version.. we wouldn't
-       // normally unmap here, but instead just mark that it could be
-       // unmapped (if the iova refcnt drops to zero), but then later
-       // if another _get_iova_locked() fails we can start unmapping
-       // things that are no longer needed..
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       struct msm_gem_vma *vma;
+
+       mutex_lock(&msm_obj->lock);
+       vma = lookup_vma(obj, aspace);
+
+       if (!WARN_ON(!vma))
+               msm_gem_unmap_vma(aspace, vma);
+
+       mutex_unlock(&msm_obj->lock);
 }
 
 int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
@@ -441,7 +491,7 @@ int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
        args->pitch = align_pitch(args->width, args->bpp);
        args->size  = PAGE_ALIGN(args->pitch * args->height);
        return msm_gem_new_handle(dev, file, args->size,
-                       MSM_BO_SCANOUT | MSM_BO_WC, &args->handle);
+                       MSM_BO_SCANOUT | MSM_BO_WC, &args->handle, "dumb");
 }
 
 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
@@ -473,7 +523,7 @@ static void *get_vaddr(struct drm_gem_object *obj, unsigned madv)
        mutex_lock(&msm_obj->lock);
 
        if (WARN_ON(msm_obj->madv > madv)) {
-               dev_err(obj->dev->dev, "Invalid madv state: %u vs %u\n",
+               DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n",
                        msm_obj->madv, madv);
                mutex_unlock(&msm_obj->lock);
                return ERR_PTR(-EBUSY);
@@ -739,16 +789,24 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
                break;
        }
 
-       seq_printf(m, "%08x: %c %2d (%2d) %08llx %p\t",
+       seq_printf(m, "%08x: %c %2d (%2d) %08llx %p",
                        msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
                        obj->name, kref_read(&obj->refcount),
                        off, msm_obj->vaddr);
 
-       /* FIXME: we need to print the address space here too */
-       list_for_each_entry(vma, &msm_obj->vmas, list)
-               seq_printf(m, " %08llx", vma->iova);
+       seq_printf(m, " %08zu %9s %-32s\n", obj->size, madv, msm_obj->name);
+
+       if (!list_empty(&msm_obj->vmas)) {
+
+               seq_puts(m, "      vmas:");
 
-       seq_printf(m, " %zu%s\n", obj->size, madv);
+               list_for_each_entry(vma, &msm_obj->vmas, list)
+                       seq_printf(m, " [%s: %08llx,%s,inuse=%d]", vma->aspace->name,
+                               vma->iova, vma->mapped ? "mapped" : "unmapped",
+                               vma->inuse);
+
+               seq_puts(m, "\n");
+       }
 
        rcu_read_lock();
        fobj = rcu_dereference(robj->fence);
@@ -775,9 +833,10 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
        int count = 0;
        size_t size = 0;
 
+       seq_puts(m, "   flags       id ref  offset   kaddr            size     madv      name\n");
        list_for_each_entry(msm_obj, list, mm_list) {
                struct drm_gem_object *obj = &msm_obj->base;
-               seq_printf(m, "   ");
+               seq_puts(m, "   ");
                msm_gem_describe(obj, m);
                count++;
                size += obj->size;
@@ -831,7 +890,8 @@ void msm_gem_free_object(struct drm_gem_object *obj)
 
 /* convenience method to construct a GEM buffer object, and userspace handle */
 int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
-               uint32_t size, uint32_t flags, uint32_t *handle)
+               uint32_t size, uint32_t flags, uint32_t *handle,
+               char *name)
 {
        struct drm_gem_object *obj;
        int ret;
@@ -841,6 +901,9 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
        if (IS_ERR(obj))
                return PTR_ERR(obj);
 
+       if (name)
+               msm_gem_object_set_name(obj, "%s", name);
+
        ret = drm_gem_handle_create(file, obj, handle);
 
        /* drop reference from allocate - handle holds it now */
@@ -864,7 +927,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
        case MSM_BO_WC:
                break;
        default:
-               dev_err(dev->dev, "invalid cache flag: %x\n",
+               DRM_DEV_ERROR(dev->dev, "invalid cache flag: %x\n",
                                (flags & MSM_BO_CACHE_MASK));
                return -EINVAL;
        }
@@ -912,9 +975,9 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
 
        size = PAGE_ALIGN(size);
 
-       if (!iommu_present(&platform_bus_type))
+       if (!msm_use_mmu(dev))
                use_vram = true;
-       else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
+       else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size)
                use_vram = true;
 
        if (WARN_ON(use_vram && !priv->vram.size))
@@ -989,8 +1052,8 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
        int ret, npages;
 
        /* if we don't have IOMMU, don't bother pretending we can import: */
-       if (!iommu_present(&platform_bus_type)) {
-               dev_err(dev->dev, "cannot import without IOMMU\n");
+       if (!msm_use_mmu(dev)) {
+               DRM_DEV_ERROR(dev->dev, "cannot import without IOMMU\n");
                return ERR_PTR(-EINVAL);
        }
 
@@ -1040,24 +1103,30 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
                return ERR_CAST(obj);
 
        if (iova) {
-               ret = msm_gem_get_iova(obj, aspace, iova);
-               if (ret) {
-                       drm_gem_object_put(obj);
-                       return ERR_PTR(ret);
-               }
+               ret = msm_gem_get_and_pin_iova(obj, aspace, iova);
+               if (ret)
+                       goto err;
        }
 
        vaddr = msm_gem_get_vaddr(obj);
        if (IS_ERR(vaddr)) {
-               msm_gem_put_iova(obj, aspace);
-               drm_gem_object_put(obj);
-               return ERR_CAST(vaddr);
+               msm_gem_unpin_iova(obj, aspace);
+               ret = PTR_ERR(vaddr);
+               goto err;
        }
 
        if (bo)
                *bo = obj;
 
        return vaddr;
+err:
+       if (locked)
+               drm_gem_object_put(obj);
+       else
+               drm_gem_object_put_unlocked(obj);
+
+       return ERR_PTR(ret);
+
 }
 
 void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
@@ -1073,3 +1142,31 @@ void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size,
 {
        return _msm_gem_kernel_new(dev, size, flags, aspace, bo, iova, true);
 }
+
+void msm_gem_kernel_put(struct drm_gem_object *bo,
+               struct msm_gem_address_space *aspace, bool locked)
+{
+       if (IS_ERR_OR_NULL(bo))
+               return;
+
+       msm_gem_put_vaddr(bo);
+       msm_gem_unpin_iova(bo, aspace);
+
+       if (locked)
+               drm_gem_object_put(bo);
+       else
+               drm_gem_object_put_unlocked(bo);
+}
+
+void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(bo);
+       va_list ap;
+
+       if (!fmt)
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(msm_obj->name, sizeof(msm_obj->name), fmt, ap);
+       va_end(ap);
+}
index c5d9bd3e47a8d20100f4c29da961aba368fb8752..2064fac871b8c8040a6ff129996952471f7ec0d4 100644 (file)
@@ -41,6 +41,8 @@ struct msm_gem_vma {
        uint64_t iova;
        struct msm_gem_address_space *aspace;
        struct list_head list;    /* node in msm_gem_object::vmas */
+       bool mapped;
+       int inuse;
 };
 
 struct msm_gem_object {
@@ -91,6 +93,8 @@ struct msm_gem_object {
         */
        struct drm_mm_node *vram_node;
        struct mutex lock; /* Protects resources associated with bo */
+
+       char name[32]; /* Identifier to print for the debugfs files */
 };
 #define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
 
@@ -150,6 +154,7 @@ struct msm_gem_submit {
        struct msm_ringbuffer *ring;
        unsigned int nr_cmds;
        unsigned int nr_bos;
+       u32 ident;         /* A "identifier" for the submit for logging */
        struct {
                uint32_t type;
                uint32_t size;  /* in dwords */
index 6942604ad9a8b832b8425f90012ba688da3983aa..a28465d9052908787d569a970f431ac564ba2f22 100644 (file)
@@ -20,6 +20,7 @@
 #include "msm_drv.h"
 #include "msm_gpu.h"
 #include "msm_gem.h"
+#include "msm_gpu_trace.h"
 
 /*
  * Cmdstream submission:
@@ -48,7 +49,6 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
        submit->dev = dev;
        submit->gpu = gpu;
        submit->fence = NULL;
-       submit->pid = get_pid(task_pid(current));
        submit->cmd = (void *)&submit->bos[nr_bos];
        submit->queue = queue;
        submit->ring = gpu->rb[queue->prio];
@@ -114,8 +114,11 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                        pagefault_disable();
                }
 
+/* at least one of READ and/or WRITE flags should be set: */
+#define MANDATORY_FLAGS (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
+
                if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
-                       !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
+                       !(submit_bo.flags & MANDATORY_FLAGS)) {
                        DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
                        ret = -EINVAL;
                        goto out_unlock;
@@ -167,7 +170,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit,
        struct msm_gem_object *msm_obj = submit->bos[i].obj;
 
        if (submit->bos[i].flags & BO_PINNED)
-               msm_gem_put_iova(&msm_obj->base, submit->gpu->aspace);
+               msm_gem_unpin_iova(&msm_obj->base, submit->gpu->aspace);
 
        if (submit->bos[i].flags & BO_LOCKED)
                ww_mutex_unlock(&msm_obj->resv->lock);
@@ -241,7 +244,8 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
                         * strange place to call it.  OTOH this is a
                         * convenient can-fail point to hook it in.
                         */
-                       ret = reservation_object_reserve_shared(msm_obj->resv);
+                       ret = reservation_object_reserve_shared(msm_obj->resv,
+                                                               1);
                        if (ret)
                                return ret;
                }
@@ -269,7 +273,7 @@ static int submit_pin_objects(struct msm_gem_submit *submit)
                uint64_t iova;
 
                /* if locking succeeded, pin bo: */
-               ret = msm_gem_get_iova(&msm_obj->base,
+               ret = msm_gem_get_and_pin_iova(&msm_obj->base,
                                submit->gpu->aspace, &iova);
 
                if (ret)
@@ -408,6 +412,7 @@ static void submit_cleanup(struct msm_gem_submit *submit)
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                struct drm_file *file)
 {
+       static atomic_t ident = ATOMIC_INIT(0);
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_msm_gem_submit *args = data;
        struct msm_file_private *ctx = file->driver_priv;
@@ -417,9 +422,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        struct msm_gpu_submitqueue *queue;
        struct msm_ringbuffer *ring;
        int out_fence_fd = -1;
+       struct pid *pid = get_pid(task_pid(current));
        unsigned i;
-       int ret;
-
+       int ret, submitid;
        if (!gpu)
                return -ENXIO;
 
@@ -442,7 +447,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        if (!queue)
                return -ENOENT;
 
+       /* Get a unique identifier for the submission for logging purposes */
+       submitid = atomic_inc_return(&ident) - 1;
+
        ring = gpu->rb[queue->prio];
+       trace_msm_gpu_submit(pid_nr(pid), ring->id, submitid,
+               args->nr_bos, args->nr_cmds);
 
        if (args->flags & MSM_SUBMIT_FENCE_FD_IN) {
                struct dma_fence *in_fence;
@@ -483,6 +493,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                goto out_unlock;
        }
 
+       submit->pid = pid;
+       submit->ident = submitid;
+
        if (args->flags & MSM_SUBMIT_SUDO)
                submit->in_rb = true;
 
index ffbec224551b52f927eebb92b4319134b3399e2c..557360788084eb3db21e0c964722a0ce1923f92b 100644 (file)
@@ -38,20 +38,72 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace)
                kref_put(&aspace->kref, msm_gem_address_space_destroy);
 }
 
-void
-msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt)
+/* Actually unmap memory for the vma */
+void msm_gem_purge_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma)
 {
-       if (!aspace || !vma->iova)
+       unsigned size = vma->node.size << PAGE_SHIFT;
+
+       /* Print a message if we try to purge a vma in use */
+       if (WARN_ON(vma->inuse > 0))
+               return;
+
+       /* Don't do anything if the memory isn't mapped */
+       if (!vma->mapped)
                return;
 
-       if (aspace->mmu) {
-               unsigned size = vma->node.size << PAGE_SHIFT;
-               aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, size);
-       }
+       if (aspace->mmu)
+               aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, size);
+
+       vma->mapped = false;
+}
+
+/* Remove reference counts for the mapping */
+void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma)
+{
+       if (!WARN_ON(!vma->iova))
+               vma->inuse--;
+}
+
+int
+msm_gem_map_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, struct sg_table *sgt, int npages)
+{
+       unsigned size = npages << PAGE_SHIFT;
+       int ret = 0;
+
+       if (WARN_ON(!vma->iova))
+               return -EINVAL;
+
+       /* Increase the usage counter */
+       vma->inuse++;
+
+       if (vma->mapped)
+               return 0;
+
+       vma->mapped = true;
+
+       if (aspace->mmu)
+               ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
+                               size, IOMMU_READ | IOMMU_WRITE);
+
+       if (ret)
+               vma->mapped = false;
+
+       return ret;
+}
+
+/* Close an iova.  Warn if it is still in use */
+void msm_gem_close_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma)
+{
+       if (WARN_ON(vma->inuse > 0 || vma->mapped))
+               return;
 
        spin_lock(&aspace->lock);
-       drm_mm_remove_node(&vma->node);
+       if (vma->iova)
+               drm_mm_remove_node(&vma->node);
        spin_unlock(&aspace->lock);
 
        vma->iova = 0;
@@ -59,18 +111,16 @@ msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
        msm_gem_address_space_put(aspace);
 }
 
-int
-msm_gem_map_vma(struct msm_gem_address_space *aspace,
-               struct msm_gem_vma *vma, struct sg_table *sgt, int npages)
+/* Initialize a new vma and allocate an iova for it */
+int msm_gem_init_vma(struct msm_gem_address_space *aspace,
+               struct msm_gem_vma *vma, int npages)
 {
        int ret;
 
-       spin_lock(&aspace->lock);
-       if (WARN_ON(drm_mm_node_allocated(&vma->node))) {
-               spin_unlock(&aspace->lock);
-               return 0;
-       }
+       if (WARN_ON(vma->iova))
+               return -EBUSY;
 
+       spin_lock(&aspace->lock);
        ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages);
        spin_unlock(&aspace->lock);
 
@@ -78,19 +128,14 @@ msm_gem_map_vma(struct msm_gem_address_space *aspace,
                return ret;
 
        vma->iova = vma->node.start << PAGE_SHIFT;
+       vma->mapped = false;
 
-       if (aspace->mmu) {
-               unsigned size = npages << PAGE_SHIFT;
-               ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
-                               size, IOMMU_READ | IOMMU_WRITE);
-       }
-
-       /* Get a reference to the aspace to keep it around */
        kref_get(&aspace->kref);
 
-       return ret;
+       return 0;
 }
 
+
 struct msm_gem_address_space *
 msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
                const char *name)
@@ -114,3 +159,26 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
 
        return aspace;
 }
+
+struct msm_gem_address_space *
+msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu,
+               const char *name, uint64_t va_start, uint64_t va_end)
+{
+       struct msm_gem_address_space *aspace;
+       u64 size = va_end - va_start;
+
+       aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
+       if (!aspace)
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock_init(&aspace->lock);
+       aspace->name = name;
+       aspace->mmu = msm_gpummu_new(dev, gpu);
+
+       drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT),
+               size >> PAGE_SHIFT);
+
+       kref_init(&aspace->kref);
+
+       return aspace;
+}
index 2b7c8946adba97983a79a6f78dae85ffc269102c..5f3eff3043554491eca50a559599b0e5293e1357 100644 (file)
@@ -19,6 +19,8 @@
 #include "msm_gem.h"
 #include "msm_mmu.h"
 #include "msm_fence.h"
+#include "msm_gpu_trace.h"
+#include "adreno/adreno_gpu.h"
 
 #include <generated/utsrelease.h>
 #include <linux/string_helpers.h>
@@ -107,7 +109,7 @@ static void msm_devfreq_init(struct msm_gpu *gpu)
                        &msm_devfreq_profile, "simple_ondemand", NULL);
 
        if (IS_ERR(gpu->devfreq.devfreq)) {
-               dev_err(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
+               DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
                gpu->devfreq.devfreq = NULL;
        }
 
@@ -122,7 +124,7 @@ static int enable_pwrrail(struct msm_gpu *gpu)
        if (gpu->gpu_reg) {
                ret = regulator_enable(gpu->gpu_reg);
                if (ret) {
-                       dev_err(dev->dev, "failed to enable 'gpu_reg': %d\n", ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to enable 'gpu_reg': %d\n", ret);
                        return ret;
                }
        }
@@ -130,7 +132,7 @@ static int enable_pwrrail(struct msm_gpu *gpu)
        if (gpu->gpu_cx) {
                ret = regulator_enable(gpu->gpu_cx);
                if (ret) {
-                       dev_err(dev->dev, "failed to enable 'gpu_cx': %d\n", ret);
+                       DRM_DEV_ERROR(dev->dev, "failed to enable 'gpu_cx': %d\n", ret);
                        return ret;
                }
        }
@@ -315,28 +317,28 @@ static void msm_gpu_crashstate_get_bo(struct msm_gpu_state *state,
        struct msm_gpu_state_bo *state_bo = &state->bos[state->nr_bos];
 
        /* Don't record write only objects */
-
        state_bo->size = obj->base.size;
        state_bo->iova = iova;
 
-       /* Only store the data for buffer objects marked for read */
-       if ((flags & MSM_SUBMIT_BO_READ)) {
+       /* Only store data for non imported buffer objects marked for read */
+       if ((flags & MSM_SUBMIT_BO_READ) && !obj->base.import_attach) {
                void *ptr;
 
                state_bo->data = kvmalloc(obj->base.size, GFP_KERNEL);
                if (!state_bo->data)
-                       return;
+                       goto out;
 
                ptr = msm_gem_get_vaddr_active(&obj->base);
                if (IS_ERR(ptr)) {
                        kvfree(state_bo->data);
-                       return;
+                       state_bo->data = NULL;
+                       goto out;
                }
 
                memcpy(state_bo->data, ptr, obj->base.size);
                msm_gem_put_vaddr(&obj->base);
        }
-
+out:
        state->nr_bos++;
 }
 
@@ -364,12 +366,15 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu,
        if (submit) {
                int i;
 
-               state->bos = kcalloc(submit->nr_bos,
+               state->bos = kcalloc(submit->nr_cmds,
                        sizeof(struct msm_gpu_state_bo), GFP_KERNEL);
 
-               for (i = 0; state->bos && i < submit->nr_bos; i++)
-                       msm_gpu_crashstate_get_bo(state, submit->bos[i].obj,
-                               submit->bos[i].iova, submit->bos[i].flags);
+               for (i = 0; state->bos && i < submit->nr_cmds; i++) {
+                       int idx = submit->cmd[i].idx;
+
+                       msm_gpu_crashstate_get_bo(state, submit->bos[idx].obj,
+                               submit->bos[idx].iova, submit->bos[idx].flags);
+               }
        }
 
        /* Set the active crash state to be dumped on failure */
@@ -432,7 +437,7 @@ static void recover_worker(struct work_struct *work)
 
        mutex_lock(&dev->struct_mutex);
 
-       dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name);
+       DRM_DEV_ERROR(dev->dev, "%s: hangcheck recover!\n", gpu->name);
 
        submit = find_submit(cur_ring, cur_ring->memptrs->fence + 1);
        if (submit) {
@@ -459,7 +464,7 @@ static void recover_worker(struct work_struct *work)
                }
 
                if (comm && cmd) {
-                       dev_err(dev->dev, "%s: offending task: %s (%s)\n",
+                       DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n",
                                gpu->name, comm, cmd);
 
                        msm_rd_dump_submit(priv->hangrd, submit,
@@ -542,11 +547,11 @@ static void hangcheck_handler(struct timer_list *t)
        } else if (fence < ring->seqno) {
                /* no progress and not done.. hung! */
                ring->hangcheck_fence = fence;
-               dev_err(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n",
+               DRM_DEV_ERROR(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n",
                                gpu->name, ring->id);
-               dev_err(dev->dev, "%s:     completed fence: %u\n",
+               DRM_DEV_ERROR(dev->dev, "%s:     completed fence: %u\n",
                                gpu->name, fence);
-               dev_err(dev->dev, "%s:     submitted fence: %u\n",
+               DRM_DEV_ERROR(dev->dev, "%s:     submitted fence: %u\n",
                                gpu->name, ring->seqno);
 
                queue_work(priv->wq, &gpu->recover_work);
@@ -662,15 +667,33 @@ out:
  * Cmdstream submission/retirement:
  */
 
-static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
+static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
+               struct msm_gem_submit *submit)
 {
+       int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
+       volatile struct msm_gpu_submit_stats *stats;
+       u64 elapsed, clock = 0;
        int i;
 
+       stats = &ring->memptrs->stats[index];
+       /* Convert 19.2Mhz alwayson ticks to nanoseconds for elapsed time */
+       elapsed = (stats->alwayson_end - stats->alwayson_start) * 10000;
+       do_div(elapsed, 192);
+
+       /* Calculate the clock frequency from the number of CP cycles */
+       if (elapsed) {
+               clock = (stats->cpcycles_end - stats->cpcycles_start) * 1000;
+               do_div(clock, elapsed);
+       }
+
+       trace_msm_gpu_submit_retired(submit, elapsed, clock,
+               stats->alwayson_start, stats->alwayson_end);
+
        for (i = 0; i < submit->nr_bos; i++) {
                struct msm_gem_object *msm_obj = submit->bos[i].obj;
                /* move to inactive: */
                msm_gem_move_to_inactive(&msm_obj->base);
-               msm_gem_put_iova(&msm_obj->base, gpu->aspace);
+               msm_gem_unpin_iova(&msm_obj->base, gpu->aspace);
                drm_gem_object_put(&msm_obj->base);
        }
 
@@ -693,7 +716,7 @@ static void retire_submits(struct msm_gpu *gpu)
 
                list_for_each_entry_safe(submit, tmp, &ring->submits, node) {
                        if (dma_fence_is_signaled(submit->fence))
-                               retire_submit(gpu, submit);
+                               retire_submit(gpu, ring, submit);
                }
        }
 }
@@ -754,7 +777,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 
                /* submit takes a reference to the bo and iova until retired: */
                drm_gem_object_get(&msm_obj->base);
-               msm_gem_get_iova(&msm_obj->base,
+               msm_gem_get_and_pin_iova(&msm_obj->base,
                                submit->gpu->aspace, &iova);
 
                if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
@@ -803,7 +826,6 @@ static struct msm_gem_address_space *
 msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
                uint64_t va_start, uint64_t va_end)
 {
-       struct iommu_domain *iommu;
        struct msm_gem_address_space *aspace;
        int ret;
 
@@ -812,20 +834,27 @@ msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev,
         * and have separate page tables per context.  For now, to keep things
         * simple and to get something working, just use a single address space:
         */
-       iommu = iommu_domain_alloc(&platform_bus_type);
-       if (!iommu)
-               return NULL;
-
-       iommu->geometry.aperture_start = va_start;
-       iommu->geometry.aperture_end = va_end;
-
-       dev_info(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
+       if (!adreno_is_a2xx(to_adreno_gpu(gpu))) {
+               struct iommu_domain *iommu = iommu_domain_alloc(&platform_bus_type);
+               if (!iommu)
+                       return NULL;
+
+               iommu->geometry.aperture_start = va_start;
+               iommu->geometry.aperture_end = va_end;
+
+               DRM_DEV_INFO(gpu->dev->dev, "%s: using IOMMU\n", gpu->name);
+
+               aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
+               if (IS_ERR(aspace))
+                       iommu_domain_free(iommu);
+       } else {
+               aspace = msm_gem_address_space_create_a2xx(&pdev->dev, gpu, "gpu",
+                       va_start, va_end);
+       }
 
-       aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu");
        if (IS_ERR(aspace)) {
-               dev_err(gpu->dev->dev, "failed to init iommu: %ld\n",
+               DRM_DEV_ERROR(gpu->dev->dev, "failed to init mmu: %ld\n",
                        PTR_ERR(aspace));
-               iommu_domain_free(iommu);
                return ERR_CAST(aspace);
        }
 
@@ -874,14 +903,14 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        gpu->irq = platform_get_irq_byname(pdev, config->irqname);
        if (gpu->irq < 0) {
                ret = gpu->irq;
-               dev_err(drm->dev, "failed to get irq: %d\n", ret);
+               DRM_DEV_ERROR(drm->dev, "failed to get irq: %d\n", ret);
                goto fail;
        }
 
        ret = devm_request_irq(&pdev->dev, gpu->irq, irq_handler,
                        IRQF_TRIGGER_HIGH, gpu->name, gpu);
        if (ret) {
-               dev_err(drm->dev, "failed to request IRQ%u: %d\n", gpu->irq, ret);
+               DRM_DEV_ERROR(drm->dev, "failed to request IRQ%u: %d\n", gpu->irq, ret);
                goto fail;
        }
 
@@ -914,22 +943,25 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                config->va_start, config->va_end);
 
        if (gpu->aspace == NULL)
-               dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name);
+               DRM_DEV_INFO(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name);
        else if (IS_ERR(gpu->aspace)) {
                ret = PTR_ERR(gpu->aspace);
                goto fail;
        }
 
-       memptrs = msm_gem_kernel_new(drm, sizeof(*gpu->memptrs_bo),
+       memptrs = msm_gem_kernel_new(drm,
+               sizeof(struct msm_rbmemptrs) * nr_rings,
                MSM_BO_UNCACHED, gpu->aspace, &gpu->memptrs_bo,
                &memptrs_iova);
 
        if (IS_ERR(memptrs)) {
                ret = PTR_ERR(memptrs);
-               dev_err(drm->dev, "could not allocate memptrs: %d\n", ret);
+               DRM_DEV_ERROR(drm->dev, "could not allocate memptrs: %d\n", ret);
                goto fail;
        }
 
+       msm_gem_object_set_name(gpu->memptrs_bo, "memptrs");
+
        if (nr_rings > ARRAY_SIZE(gpu->rb)) {
                DRM_DEV_INFO_ONCE(drm->dev, "Only creating %zu ringbuffers\n",
                        ARRAY_SIZE(gpu->rb));
@@ -942,7 +974,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
                if (IS_ERR(gpu->rb[i])) {
                        ret = PTR_ERR(gpu->rb[i]);
-                       dev_err(drm->dev,
+                       DRM_DEV_ERROR(drm->dev,
                                "could not create ringbuffer %d: %d\n", i, ret);
                        goto fail;
                }
@@ -961,11 +993,7 @@ fail:
                gpu->rb[i] = NULL;
        }
 
-       if (gpu->memptrs_bo) {
-               msm_gem_put_vaddr(gpu->memptrs_bo);
-               msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace);
-               drm_gem_object_put_unlocked(gpu->memptrs_bo);
-       }
+       msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace, false);
 
        platform_set_drvdata(pdev, NULL);
        return ret;
@@ -984,11 +1012,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
                gpu->rb[i] = NULL;
        }
 
-       if (gpu->memptrs_bo) {
-               msm_gem_put_vaddr(gpu->memptrs_bo);
-               msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace);
-               drm_gem_object_put_unlocked(gpu->memptrs_bo);
-       }
+       msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace, false);
 
        if (!IS_ERR_OR_NULL(gpu->aspace)) {
                gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu,
index f82bac0866664bc3e00e1903abb6d428ab5eee9b..efb49bb64191732a0a8ee683e1f9790389295fa9 100644 (file)
@@ -187,6 +187,7 @@ struct msm_gpu_state_bo {
        u64 iova;
        size_t size;
        void *data;
+       bool encoded;
 };
 
 struct msm_gpu_state {
@@ -201,6 +202,7 @@ struct msm_gpu_state {
                u32 wptr;
                void *data;
                int data_size;
+               bool encoded;
        } ring[MSM_GPU_MAX_RINGS];
 
        int nr_registers;
diff --git a/drivers/gpu/drm/msm/msm_gpu_trace.h b/drivers/gpu/drm/msm/msm_gpu_trace.h
new file mode 100644 (file)
index 0000000..1155118
--- /dev/null
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_MSM_GPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MSM_GPU_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM drm_msm
+#define TRACE_INCLUDE_FILE msm_gpu_trace
+
+TRACE_EVENT(msm_gpu_submit,
+           TP_PROTO(pid_t pid, u32 ringid, u32 id, u32 nr_bos, u32 nr_cmds),
+           TP_ARGS(pid, ringid, id, nr_bos, nr_cmds),
+           TP_STRUCT__entry(
+                   __field(pid_t, pid)
+                   __field(u32, id)
+                   __field(u32, ringid)
+                   __field(u32, nr_cmds)
+                   __field(u32, nr_bos)
+                   ),
+           TP_fast_assign(
+                   __entry->pid = pid;
+                   __entry->id = id;
+                   __entry->ringid = ringid;
+                   __entry->nr_bos = nr_bos;
+                   __entry->nr_cmds = nr_cmds
+                   ),
+           TP_printk("id=%d pid=%d ring=%d bos=%d cmds=%d",
+                   __entry->id, __entry->pid, __entry->ringid,
+                   __entry->nr_bos, __entry->nr_cmds)
+);
+
+TRACE_EVENT(msm_gpu_submit_flush,
+           TP_PROTO(struct msm_gem_submit *submit, u64 ticks),
+           TP_ARGS(submit, ticks),
+           TP_STRUCT__entry(
+                   __field(pid_t, pid)
+                   __field(u32, id)
+                   __field(u32, ringid)
+                   __field(u32, seqno)
+                   __field(u64, ticks)
+                   ),
+           TP_fast_assign(
+                   __entry->pid = pid_nr(submit->pid);
+                   __entry->id = submit->ident;
+                   __entry->ringid = submit->ring->id;
+                   __entry->seqno = submit->seqno;
+                   __entry->ticks = ticks;
+                   ),
+           TP_printk("id=%d pid=%d ring=%d:%d ticks=%lld",
+                   __entry->id, __entry->pid, __entry->ringid, __entry->seqno,
+                   __entry->ticks)
+);
+
+
+TRACE_EVENT(msm_gpu_submit_retired,
+           TP_PROTO(struct msm_gem_submit *submit, u64 elapsed, u64 clock,
+                   u64 start, u64 end),
+           TP_ARGS(submit, elapsed, clock, start, end),
+           TP_STRUCT__entry(
+                   __field(pid_t, pid)
+                   __field(u32, id)
+                   __field(u32, ringid)
+                   __field(u32, seqno)
+                   __field(u64, elapsed)
+                   __field(u64, clock)
+                   __field(u64, start_ticks)
+                   __field(u64, end_ticks)
+                   ),
+           TP_fast_assign(
+                   __entry->pid = pid_nr(submit->pid);
+                   __entry->id = submit->ident;
+                   __entry->ringid = submit->ring->id;
+                   __entry->seqno = submit->seqno;
+                   __entry->elapsed = elapsed;
+                   __entry->clock = clock;
+                   __entry->start_ticks = start;
+                   __entry->end_ticks = end;
+                   ),
+           TP_printk("id=%d pid=%d ring=%d:%d elapsed=%lld ns mhz=%lld start=%lld end=%lld",
+                   __entry->id, __entry->pid, __entry->ringid, __entry->seqno,
+                   __entry->elapsed, __entry->clock,
+                   __entry->start_ticks, __entry->end_ticks)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/msm
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/msm/msm_gpu_tracepoints.c b/drivers/gpu/drm/msm/msm_gpu_tracepoints.c
new file mode 100644 (file)
index 0000000..72c074f
--- /dev/null
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "msm_gem.h"
+#include "msm_ringbuffer.h"
+
+#define CREATE_TRACE_POINTS
+#include "msm_gpu_trace.h"
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
new file mode 100644 (file)
index 0000000..27312b5
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
+
+#include "msm_drv.h"
+#include "msm_mmu.h"
+#include "adreno/adreno_gpu.h"
+#include "adreno/a2xx.xml.h"
+
+struct msm_gpummu {
+       struct msm_mmu base;
+       struct msm_gpu *gpu;
+       dma_addr_t pt_base;
+       uint32_t *table;
+};
+#define to_msm_gpummu(x) container_of(x, struct msm_gpummu, base)
+
+#define GPUMMU_VA_START SZ_16M
+#define GPUMMU_VA_RANGE (0xfff * SZ_64K)
+#define GPUMMU_PAGE_SIZE SZ_4K
+#define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE)
+
+static int msm_gpummu_attach(struct msm_mmu *mmu, const char * const *names,
+               int cnt)
+{
+       return 0;
+}
+
+static void msm_gpummu_detach(struct msm_mmu *mmu, const char * const *names,
+               int cnt)
+{
+}
+
+static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova,
+               struct sg_table *sgt, unsigned len, int prot)
+{
+       struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
+       unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE;
+       struct scatterlist *sg;
+       unsigned prot_bits = 0;
+       unsigned i, j;
+
+       if (prot & IOMMU_WRITE)
+               prot_bits |= 1;
+       if (prot & IOMMU_READ)
+               prot_bits |= 2;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               dma_addr_t addr = sg->dma_address;
+               for (j = 0; j < sg->length / GPUMMU_PAGE_SIZE; j++, idx++) {
+                       gpummu->table[idx] = addr | prot_bits;
+                       addr += GPUMMU_PAGE_SIZE;
+               }
+       }
+
+       /* we can improve by deferring flush for multiple map() */
+       gpu_write(gpummu->gpu, REG_A2XX_MH_MMU_INVALIDATE,
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
+       return 0;
+}
+
+static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len)
+{
+       struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
+       unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE;
+       unsigned i;
+
+       for (i = 0; i < len / GPUMMU_PAGE_SIZE; i++, idx++)
+                gpummu->table[idx] = 0;
+
+       gpu_write(gpummu->gpu, REG_A2XX_MH_MMU_INVALIDATE,
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
+               A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
+       return 0;
+}
+
+static void msm_gpummu_destroy(struct msm_mmu *mmu)
+{
+       struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
+
+       dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base,
+               DMA_ATTR_FORCE_CONTIGUOUS);
+
+       kfree(gpummu);
+}
+
+static const struct msm_mmu_funcs funcs = {
+               .attach = msm_gpummu_attach,
+               .detach = msm_gpummu_detach,
+               .map = msm_gpummu_map,
+               .unmap = msm_gpummu_unmap,
+               .destroy = msm_gpummu_destroy,
+};
+
+struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
+{
+       struct msm_gpummu *gpummu;
+
+       gpummu = kzalloc(sizeof(*gpummu), GFP_KERNEL);
+       if (!gpummu)
+               return ERR_PTR(-ENOMEM);
+
+       gpummu->table = dma_alloc_attrs(dev, TABLE_SIZE + 32, &gpummu->pt_base,
+               GFP_KERNEL | __GFP_ZERO, DMA_ATTR_FORCE_CONTIGUOUS);
+       if (!gpummu->table) {
+               kfree(gpummu);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       gpummu->gpu = gpu;
+       msm_mmu_init(&gpummu->base, dev, &funcs);
+
+       return &gpummu->base;
+}
+
+void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
+               dma_addr_t *tran_error)
+{
+       dma_addr_t base = to_msm_gpummu(mmu)->pt_base;
+
+       *pt_base = base;
+       *tran_error = base + TABLE_SIZE; /* 32-byte aligned */
+}
index 2a90aa4caec081b2349ce115d77f4225d22ab3a4..4d62790cd4257545dce8bf8c57d596eb9aa80947 100644 (file)
@@ -71,8 +71,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
        return (ret == len) ? 0 : -EINVAL;
 }
 
-static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova,
-               struct sg_table *sgt, unsigned len)
+static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len)
 {
        struct msm_iommu *iommu = to_msm_iommu(mmu);
 
index fd88cebb6adb339f489137178bd49e8ec0b0eafc..2b81b43a4bab2ddf9ceee9dfcfe96e446b8530e5 100644 (file)
@@ -67,9 +67,6 @@ struct msm_kms_funcs {
        void (*set_encoder_mode)(struct msm_kms *kms,
                                 struct drm_encoder *encoder,
                                 bool cmd_mode);
-       /* pm suspend/resume hooks */
-       int (*pm_suspend)(struct device *dev);
-       int (*pm_resume)(struct device *dev);
        /* cleanup: */
        void (*destroy)(struct msm_kms *kms);
 #ifdef CONFIG_DEBUG_FS
index aa2c5d4580c820b2e54c16317c121994bd7f37a9..d21b26604d0b8243f711618d96a5dc8de1ad676e 100644 (file)
@@ -25,8 +25,7 @@ struct msm_mmu_funcs {
        void (*detach)(struct msm_mmu *mmu, const char * const *names, int cnt);
        int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
                        unsigned len, int prot);
-       int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
-                       unsigned len);
+       int (*unmap)(struct msm_mmu *mmu, uint64_t iova, unsigned len);
        void (*destroy)(struct msm_mmu *mmu);
 };
 
@@ -54,4 +53,7 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
        mmu->handler = handler;
 }
 
+void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
+               dma_addr_t *tran_error);
+
 #endif /* __MSM_MMU_H__ */
index 0c2c8d2c631f309791a91b388d7d370c969e2f20..90e9d0a48dc0409feca3c8feab838fa83aeed946 100644 (file)
@@ -348,6 +348,12 @@ static void snapshot_buf(struct msm_rd_state *rd,
        msm_gem_put_vaddr(&obj->base);
 }
 
+static bool
+should_dump(struct msm_gem_submit *submit, int idx)
+{
+       return rd_full || (submit->bos[idx].flags & MSM_SUBMIT_BO_DUMP);
+}
+
 /* called under struct_mutex */
 void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
                const char *fmt, ...)
@@ -389,15 +395,16 @@ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
 
        rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4));
 
-       for (i = 0; rd_full && i < submit->nr_bos; i++)
-               snapshot_buf(rd, submit, i, 0, 0);
+       for (i = 0; i < submit->nr_bos; i++)
+               if (should_dump(submit, i))
+                       snapshot_buf(rd, submit, i, 0, 0);
 
        for (i = 0; i < submit->nr_cmds; i++) {
                uint64_t iova = submit->cmd[i].iova;
                uint32_t szd  = submit->cmd[i].size; /* in dwords */
 
                /* snapshot cmdstream bo's (if we haven't already): */
-               if (!rd_full) {
+               if (!should_dump(submit, i)) {
                        snapshot_buf(rd, submit, submit->cmd[i].idx,
                                        submit->cmd[i].iova, szd * 4);
                }
index 6f5295b3f2f69b0afc47bdae9552cd3356246be5..20a96fe69dcd89b4ed4e5cf3332df81deb709d33 100644 (file)
@@ -36,15 +36,18 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
 
        ring->gpu = gpu;
        ring->id = id;
-       /* Pass NULL for the iova pointer - we will map it later */
+
        ring->start = msm_gem_kernel_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ,
-               MSM_BO_WC, gpu->aspace, &ring->bo, NULL);
+               MSM_BO_WC, gpu->aspace, &ring->bo, &ring->iova);
 
        if (IS_ERR(ring->start)) {
                ret = PTR_ERR(ring->start);
                ring->start = 0;
                goto fail;
        }
+
+       msm_gem_object_set_name(ring->bo, "ring%d", id);
+
        ring->end   = ring->start + (MSM_GPU_RINGBUFFER_SZ >> 2);
        ring->next  = ring->start;
        ring->cur   = ring->start;
@@ -73,10 +76,7 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
 
        msm_fence_context_free(ring->fctx);
 
-       if (ring->bo) {
-               msm_gem_put_iova(ring->bo, ring->gpu->aspace);
-               msm_gem_put_vaddr(ring->bo);
-               drm_gem_object_put_unlocked(ring->bo);
-       }
+       msm_gem_kernel_put(ring->bo, ring->gpu->aspace, false);
+
        kfree(ring);
 }
index cffce094aecb47d0788740220778022d64e5bb27..6434ebb1313657aa25678cd8861b1329d60be4db 100644 (file)
 #define rbmemptr(ring, member)  \
        ((ring)->memptrs_iova + offsetof(struct msm_rbmemptrs, member))
 
+#define rbmemptr_stats(ring, index, member) \
+       (rbmemptr((ring), stats) + \
+        ((index) * sizeof(struct msm_gpu_submit_stats)) + \
+        offsetof(struct msm_gpu_submit_stats, member))
+
+struct msm_gpu_submit_stats {
+       u64 cpcycles_start;
+       u64 cpcycles_end;
+       u64 alwayson_start;
+       u64 alwayson_end;
+};
+
+#define MSM_GPU_SUBMIT_STATS_COUNT 64
+
 struct msm_rbmemptrs {
        volatile uint32_t rptr;
        volatile uint32_t fence;
+
+       volatile struct msm_gpu_submit_stats stats[MSM_GPU_SUBMIT_STATS_COUNT];
 };
 
 struct msm_ringbuffer {
index 2393e6d16ffd4d4118335a018747e218755cb8e9..88ba003979e6b841cce82bd390282335ebb13028 100644 (file)
@@ -417,7 +417,7 @@ static int mxsfb_probe(struct platform_device *pdev)
 err_unload:
        mxsfb_unload(drm);
 err_free:
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return ret;
 }
@@ -428,7 +428,7 @@ static int mxsfb_remove(struct platform_device *pdev)
 
        drm_dev_unregister(drm);
        mxsfb_unload(drm);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return 0;
 }
index 70dce544984e848b54409a390a41c2a3f9c24d4f..1727d399833cc2fd17b0fcb477b70a573aac30a9 100644 (file)
@@ -67,7 +67,7 @@ nv04_display_create(struct drm_device *dev)
        for (i = 0; i < dcb->entries; i++) {
                struct dcb_output *dcbent = &dcb->entry[i];
 
-               connector = nouveau_connector_create(dev, dcbent->connector);
+               connector = nouveau_connector_create(dev, dcbent);
                if (IS_ERR(connector))
                        continue;
 
index 849b0f45afb866dbb2004dea301e0090aaafd8db..3d074aa311732e777ba183d2afa57bbe3c54d7be 100644 (file)
@@ -7,6 +7,7 @@ nouveau-y += dispnv50/core827d.o
 nouveau-y += dispnv50/core907d.o
 nouveau-y += dispnv50/core917d.o
 nouveau-y += dispnv50/corec37d.o
+nouveau-y += dispnv50/corec57d.o
 
 nouveau-y += dispnv50/dac507d.o
 nouveau-y += dispnv50/dac907d.o
@@ -23,12 +24,14 @@ nouveau-y += dispnv50/head827d.o
 nouveau-y += dispnv50/head907d.o
 nouveau-y += dispnv50/head917d.o
 nouveau-y += dispnv50/headc37d.o
+nouveau-y += dispnv50/headc57d.o
 
 nouveau-y += dispnv50/wimm.o
 nouveau-y += dispnv50/wimmc37b.o
 
 nouveau-y += dispnv50/wndw.o
 nouveau-y += dispnv50/wndwc37e.o
+nouveau-y += dispnv50/wndwc57e.o
 
 nouveau-y += dispnv50/base.o
 nouveau-y += dispnv50/base507c.o
index 908feb1fc60f7cadb855e7fa71dc61bd42b63567..a194990d2b0da2c5e576e9672de55b6ff91c7a60 100644 (file)
@@ -54,9 +54,10 @@ struct nv50_head_atom {
                u64 offset:40;
                u8 buffer:1;
                u8 mode:4;
-               u8 size:2;
+               u16 size:11;
                u8 range:2;
                u8 output_mode:2;
+               void (*load)(struct drm_color_lut *, int size, void __iomem *);
        } olut;
 
        struct {
@@ -169,9 +170,11 @@ struct nv50_wndw_atom {
                        u8  buffer:1;
                        u8  enable:2;
                        u8  mode:4;
-                       u8  size:2;
+                       u16 size:11;
                        u8  range:2;
                        u8  output_mode:2;
+                       void (*load)(struct drm_color_lut *, int size,
+                                    void __iomem *);
                } i;
        } xlut;
 
index a562fc94ce5990700b1664af2c295586b7dca1b8..049ce6da321c3fa3e102b1b1773122ea02b9566d 100644 (file)
@@ -80,6 +80,7 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
        asyw->xlut.i.mode = 7;
        asyw->xlut.i.enable = 2;
+       asyw->xlut.i.load = head907d_olut_load;
 }
 
 const struct nv50_wndw_func
index f3c49adb1bdb9ab656303739d108f7b13e90ec26..c25e0ebe3c92e92a724068fec1a818b171322abf 100644 (file)
@@ -42,6 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore)
                int version;
                int (*new)(struct nouveau_drm *, s32, struct nv50_core **);
        } cores[] = {
+               { TU104_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
                { GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new },
                { GP102_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
                { GP100_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
index 8470df9dd13de463bebe69cc762173b0f8586dd1..df8336b593f7c4adc02878a171f8abf8d927e721 100644 (file)
@@ -46,5 +46,9 @@ extern const struct nv50_outp_func sor907d;
 int core917d_new(struct nouveau_drm *, s32, struct nv50_core **);
 
 int corec37d_new(struct nouveau_drm *, s32, struct nv50_core **);
+int corec37d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *);
+void corec37d_update(struct nv50_core *, u32 *, bool);
 extern const struct nv50_outp_func sorc37d;
+
+int corec57d_new(struct nouveau_drm *, s32, struct nv50_core **);
 #endif
index b5c17c94891874d9b9841aab7bc584c826bcddf1..7860774b65bc0322aab7e0d69450738ff7c720c4 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <nouveau_bo.h>
 
-static void
+void
 corec37d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
 {
        u32 *push;
@@ -71,7 +71,7 @@ corec37d_ntfy_init(struct nouveau_bo *bo, u32 offset)
        nouveau_bo_wr32(bo, offset / 4 + 3, 0x00000000);
 }
 
-void
+static void
 corec37d_init(struct nv50_core *core)
 {
        const u32 windows = 8; /*XXX*/
diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c
new file mode 100644 (file)
index 0000000..b606d68
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "core.h"
+#include "head.h"
+
+static void
+corec57d_init(struct nv50_core *core)
+{
+       const u32 windows = 8; /*XXX*/
+       u32 *push, i;
+       if ((push = evo_wait(&core->chan, 2 + 6 * windows + 2))) {
+               evo_mthd(push, 0x0208, 1);
+               evo_data(push, core->chan.sync.handle);
+               for (i = 0; i < windows; i++) {
+                       evo_mthd(push, 0x1000 + (i * 0x080), 3);
+                       evo_data(push, i >> 1);
+                       evo_data(push, 0x0000000f);
+                       evo_data(push, 0x00000000);
+                       evo_mthd(push, 0x1010 + (i * 0x080), 1);
+                       evo_data(push, 0x00117fff);
+               }
+               evo_mthd(push, 0x0200, 1);
+               evo_data(push, 0x00000001);
+               evo_kick(push, &core->chan);
+       }
+}
+
+static const struct nv50_core_func
+corec57d = {
+       .init = corec57d_init,
+       .ntfy_init = corec37d_ntfy_init,
+       .ntfy_wait_done = corec37d_ntfy_wait_done,
+       .update = corec37d_update,
+       .head = &headc57d,
+       .sor = &sorc37d,
+};
+
+int
+corec57d_new(struct nouveau_drm *drm, s32 oclass, struct nv50_core **pcore)
+{
+       return core507d_new_(&corec57d, drm, oclass, pcore);
+}
index f592087338c465267548dee6f9309d33bd052ec4..cb6e4d2b1b4508fcf9e74048285a2149fe700f63 100644 (file)
@@ -31,6 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
                int version;
                int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
        } curses[] = {
+               { TU104_DISP_CURSOR, 0, cursc37a_new },
                { GV100_DISP_CURSOR, 0, cursc37a_new },
                { GK104_DISP_CURSOR, 0, curs907a_new },
                { GF110_DISP_CURSOR, 0, curs907a_new },
index db1bf7f88c1f5aa8b2c57e44971cc1e33201443a..134701a837c8f9a43768c269222fda98324536a7 100644 (file)
@@ -1262,8 +1262,16 @@ nv50_mstm_fini(struct nv50_mstm *mstm)
 static void
 nv50_mstm_init(struct nv50_mstm *mstm)
 {
-       if (mstm && mstm->mgr.mst_state)
-               drm_dp_mst_topology_mgr_resume(&mstm->mgr);
+       int ret;
+
+       if (!mstm || !mstm->mgr.mst_state)
+               return;
+
+       ret = drm_dp_mst_topology_mgr_resume(&mstm->mgr);
+       if (ret == -1) {
+               drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false);
+               drm_kms_helper_hotplug_event(mstm->mgr.dev);
+       }
 }
 
 static void
@@ -2301,7 +2309,7 @@ nv50_display_create(struct drm_device *dev)
 
        /* create encoder/connector objects based on VBIOS DCB table */
        for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
-               connector = nouveau_connector_create(dev, dcbe->connector);
+               connector = nouveau_connector_create(dev, dcbe);
                if (IS_ERR(connector))
                        continue;
 
index e48c5eb35b49883d015d3688a58888d9fa0b80c5..2216c58620c2de8253b57c17446a24909eca9d3e 100644 (file)
@@ -45,6 +45,8 @@ struct nv50_disp_interlock {
 
 void corec37d_ntfy_init(struct nouveau_bo *, u32);
 
+void head907d_olut_load(struct drm_color_lut *, int size, void __iomem *);
+
 struct nv50_chan {
        struct nvif_object user;
        struct nvif_device *device;
index 4f57e53797968e845175bb6b0689aa73e9d2bc29..ac97ebce5b35139d15cfddf08583f3b0719800ef 100644 (file)
@@ -50,9 +50,9 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        if (asyh->set.core   ) head->func->core_set(head, asyh);
        if (asyh->set.olut   ) {
                asyh->olut.offset = nv50_lut_load(&head->olut,
-                                                 asyh->olut.mode <= 1,
                                                  asyh->olut.buffer,
-                                                 asyh->state.gamma_lut);
+                                                 asyh->state.gamma_lut,
+                                                 asyh->olut.load);
                head->func->olut_set(head, asyh);
        }
        if (asyh->set.curs   ) head->func->curs_set(head, asyh);
@@ -210,7 +210,7 @@ nv50_head_atomic_check_lut(struct nv50_head *head,
                }
        }
 
-       if (!olut) {
+       if (!olut && !head->func->olut_identity) {
                asyh->olut.handle = 0;
                return 0;
        }
index 37b3248c6dae4d5a9b736553518eef30534865cf..d1c002f534d4edaffb48bff227a0b1b81d90d986 100644 (file)
@@ -21,6 +21,7 @@ struct nv50_head_func {
        void (*view)(struct nv50_head *, struct nv50_head_atom *);
        void (*mode)(struct nv50_head *, struct nv50_head_atom *);
        void (*olut)(struct nv50_head *, struct nv50_head_atom *);
+       bool olut_identity;
        void (*olut_set)(struct nv50_head *, struct nv50_head_atom *);
        void (*olut_clr)(struct nv50_head *);
        void (*core_calc)(struct nv50_head *, struct nv50_head_atom *);
@@ -75,4 +76,14 @@ int head917d_curs_layout(struct nv50_head *, struct nv50_wndw_atom *,
                         struct nv50_head_atom *);
 
 extern const struct nv50_head_func headc37d;
+void headc37d_view(struct nv50_head *, struct nv50_head_atom *);
+void headc37d_core_set(struct nv50_head *, struct nv50_head_atom *);
+void headc37d_core_clr(struct nv50_head *);
+int headc37d_curs_format(struct nv50_head *, struct nv50_wndw_atom *,
+                        struct nv50_head_atom *);
+void headc37d_curs_set(struct nv50_head *, struct nv50_head_atom *);
+void headc37d_curs_clr(struct nv50_head *);
+void headc37d_dither(struct nv50_head *, struct nv50_head_atom *);
+
+extern const struct nv50_head_func headc57d;
 #endif
index 51bc5996fd37a1a85e4e2189995f8d8bdb10f33e..7561be5ca707c5d2447ecb027349e60a004fc6fd 100644 (file)
@@ -254,6 +254,23 @@ head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
+static void
+head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       for (; size--; in++, mem += 8) {
+               writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
+               writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
+               writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
 void
 head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
@@ -261,6 +278,8 @@ head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
                asyh->olut.mode = 0;
        else
                asyh->olut.mode = 1;
+
+       asyh->olut.load = head507d_olut_load;
 }
 
 void
index 633907163eb1f1289b08da747c144649eb17b6f8..c2d09dd97b1ff1a01c91a6593f7b8f4d18d12ea8 100644 (file)
@@ -213,10 +213,28 @@ head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
+void
+head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       for (; size--; in++, mem += 8) {
+               writew(drm_color_lut_extract(in->  red, 14) + 0x6000, mem + 0);
+               writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2);
+               writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
 void
 head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
        asyh->olut.mode = 7;
+       asyh->olut.load = head907d_olut_load;
 }
 
 void
index 989c14083066ddd4fbed6069f3e9673fab8de535..ef6a99d95a9cd009cfe9ad637dc0646e9ddbadad 100644 (file)
@@ -65,7 +65,7 @@ headc37d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
-static void
+void
 headc37d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
@@ -79,7 +79,7 @@ headc37d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
-static void
+void
 headc37d_curs_clr(struct nv50_head *head)
 {
        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
@@ -93,7 +93,7 @@ headc37d_curs_clr(struct nv50_head *head)
        }
 }
 
-static void
+void
 headc37d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
@@ -112,7 +112,7 @@ headc37d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
-static int
+int
 headc37d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
                     struct nv50_head_atom *asyh)
 {
@@ -155,6 +155,7 @@ headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
        asyh->olut.size = 0;
        asyh->olut.range = 0;
        asyh->olut.output_mode = 1;
+       asyh->olut.load = head907d_olut_load;
 }
 
 static void
@@ -181,7 +182,7 @@ headc37d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
-static void
+void
 headc37d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
new file mode 100644 (file)
index 0000000..32a7f9e
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "head.h"
+#include "atom.h"
+#include "core.h"
+
+static void
+headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
+       u32 *push;
+       if ((push = evo_wait(core, 2))) {
+               /*XXX: This is a dirty hack until OR depth handling is
+                *     improved later for deep colour etc.
+                */
+               switch (asyh->or.depth) {
+               case 6: asyh->or.depth = 5; break;
+               case 5: asyh->or.depth = 4; break;
+               case 2: asyh->or.depth = 1; break;
+               case 0: asyh->or.depth = 4; break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+
+               evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1);
+               evo_data(push, 0xfc000001 |
+                              asyh->or.depth << 4 |
+                              asyh->or.nvsync << 3 |
+                              asyh->or.nhsync << 2);
+               evo_kick(push, core);
+       }
+}
+
+static void
+headc57d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
+       u32 *push;
+       if ((push = evo_wait(core, 2))) {
+               evo_mthd(push, 0x2000 + (head->base.index * 0x400), 1);
+#if 0
+               evo_data(push, 0x80000000 |
+                              asyh->procamp.sat.sin << 16 |
+                              asyh->procamp.sat.cos << 4);
+#else
+               evo_data(push, 0);
+#endif
+               evo_kick(push, core);
+       }
+}
+
+void
+headc57d_olut_clr(struct nv50_head *head)
+{
+       struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
+       u32 *push;
+       if ((push = evo_wait(core, 2))) {
+               evo_mthd(push, 0x2288 + (head->base.index * 0x400), 1);
+               evo_data(push, 0x00000000);
+               evo_kick(push, core);
+       }
+}
+
+void
+headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
+       u32 *push;
+       if ((push = evo_wait(core, 4))) {
+               evo_mthd(push, 0x2280 + (head->base.index * 0x400), 4);
+               evo_data(push, asyh->olut.size << 8 |
+                              asyh->olut.mode << 2 |
+                              asyh->olut.output_mode);
+               evo_data(push, 0xffffffff); /* FP_NORM_SCALE. */
+               evo_data(push, asyh->olut.handle);
+               evo_data(push, asyh->olut.offset >> 8);
+               evo_kick(push, core);
+       }
+}
+
+static void
+headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       memset_io(mem, 0x00, 0x20); /* VSS header. */
+       mem += 0x20;
+
+       while (size--) {
+               u16 r = drm_color_lut_extract(in->  red + 0, 16);
+               u16 g = drm_color_lut_extract(in->green + 0, 16);
+               u16 b = drm_color_lut_extract(in-> blue + 0, 16);
+               u16 ri = 0, gi = 0, bi = 0, i;
+
+               if (in++, size) {
+                       ri = (drm_color_lut_extract(in->  red, 16) - r) / 4;
+                       gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
+                       bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
+               }
+
+               for (i = 0; i < 4; i++, mem += 8) {
+                       writew(r + ri * i, mem + 0);
+                       writew(g + gi * i, mem + 2);
+                       writew(b + bi * i, mem + 4);
+               }
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
+static void
+headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       memset_io(mem, 0x00, 0x20); /* VSS header. */
+       mem += 0x20;
+
+       for (; size--; in++, mem += 0x08) {
+               writew(drm_color_lut_extract(in->  red, 16), mem + 0);
+               writew(drm_color_lut_extract(in->green, 16), mem + 2);
+               writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
+void
+headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       asyh->olut.mode = 2; /* DIRECT10 */
+       asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
+       asyh->olut.output_mode = 1; /* INTERPOLATE_ENABLE. */
+       if (asyh->state.gamma_lut &&
+           asyh->state.gamma_lut->length / sizeof(struct drm_color_lut) == 256)
+               asyh->olut.load = headc57d_olut_load_8;
+       else
+               asyh->olut.load = headc57d_olut_load;
+}
+
+static void
+headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+       struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
+       struct nv50_head_mode *m = &asyh->mode;
+       u32 *push;
+       if ((push = evo_wait(core, 12))) {
+               evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
+               evo_data(push, (m->v.active  << 16) | m->h.active );
+               evo_data(push, (m->v.synce   << 16) | m->h.synce  );
+               evo_data(push, (m->v.blanke  << 16) | m->h.blanke );
+               evo_data(push, (m->v.blanks  << 16) | m->h.blanks );
+               evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
+               evo_mthd(push, 0x200c + (head->base.index * 0x400), 1);
+               evo_data(push, m->clock * 1000);
+               evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
+               evo_data(push, m->clock * 1000);
+               /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
+               evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
+               evo_data(push, 0x00001014);
+               evo_kick(push, core);
+       }
+}
+
+const struct nv50_head_func
+headc57d = {
+       .view = headc37d_view,
+       .mode = headc57d_mode,
+       .olut = headc57d_olut,
+       .olut_identity = true,
+       .olut_set = headc57d_olut_set,
+       .olut_clr = headc57d_olut_clr,
+       .curs_layout = head917d_curs_layout,
+       .curs_format = headc37d_curs_format,
+       .curs_set = headc37d_curs_set,
+       .curs_clr = headc37d_curs_clr,
+       .dither = headc37d_dither,
+       .procamp = headc57d_procamp,
+       .or = headc57d_or,
+};
index a6b96ae2a22f8f9bf01ee647738f44093671ca0b..994def4fd51a8da9deb2f99374ecfe3a88bc08fc 100644 (file)
 #include <nvif/class.h>
 
 u32
-nv50_lut_load(struct nv50_lut *lut, bool legacy, int buffer,
-             struct drm_property_blob *blob)
+nv50_lut_load(struct nv50_lut *lut, int buffer, struct drm_property_blob *blob,
+             void (*load)(struct drm_color_lut *, int, void __iomem *))
 {
-       struct drm_color_lut *in = (struct drm_color_lut *)blob->data;
+       struct drm_color_lut *in = blob ? blob->data : NULL;
        void __iomem *mem = lut->mem[buffer].object.map.ptr;
-       const int size = blob->length / sizeof(*in);
-       int bits, shift, i;
-       u16 zero, r, g, b;
-       u32 addr = lut->mem[buffer].addr;
-
-       /* This can't happen.. But it shuts the compiler up. */
-       if (WARN_ON(size != 256))
-               return 0;
+       const u32 addr = lut->mem[buffer].addr;
+       int i;
 
-       if (legacy) {
-               bits = 11;
-               shift = 3;
-               zero = 0x0000;
+       if (!in) {
+               in = kvmalloc_array(1024, sizeof(*in), GFP_KERNEL);
+               if (!WARN_ON(!in)) {
+                       for (i = 0; i < 1024; i++) {
+                               in[i].red   =
+                               in[i].green =
+                               in[i].blue  = (i << 16) >> 10;
+                       }
+                       load(in, 1024, mem);
+                       kvfree(in);
+               }
        } else {
-               bits = 14;
-               shift = 0;
-               zero = 0x6000;
-       }
-
-       for (i = 0; i < size; i++) {
-               r = (drm_color_lut_extract(in[i].  red, bits) + zero) << shift;
-               g = (drm_color_lut_extract(in[i].green, bits) + zero) << shift;
-               b = (drm_color_lut_extract(in[i]. blue, bits) + zero) << shift;
-               writew(r, mem + (i * 0x08) + 0);
-               writew(g, mem + (i * 0x08) + 2);
-               writew(b, mem + (i * 0x08) + 4);
+               load(in, blob->length / sizeof(*in), mem);
        }
 
-       /* INTERPOLATE modes require a "next" entry to interpolate with,
-        * so we replicate the last entry to deal with this for now.
-        */
-       writew(r, mem + (i * 0x08) + 0);
-       writew(g, mem + (i * 0x08) + 2);
-       writew(b, mem + (i * 0x08) + 4);
        return addr;
 }
 
index 6d7b8352e4cb245b073860f798a3d93b02d0f72e..b3b9040cfe9a9c9f1c4701ebfab2a5ead95c7b6a 100644 (file)
@@ -2,6 +2,7 @@
 #define __NV50_KMS_LUT_H__
 #include <nvif/mem.h>
 struct drm_property_blob;
+struct drm_color_lut;
 struct nv50_disp;
 
 struct nv50_lut {
@@ -10,6 +11,6 @@ struct nv50_lut {
 
 int nv50_lut_init(struct nv50_disp *, struct nvif_mmu *, struct nv50_lut *);
 void nv50_lut_fini(struct nv50_lut *);
-u32 nv50_lut_load(struct nv50_lut *, bool legacy, int buffer,
-                 struct drm_property_blob *);
+u32 nv50_lut_load(struct nv50_lut *, int buffer, struct drm_property_blob *,
+                 void (*)(struct drm_color_lut *, int size, void __iomem *));
 #endif
index fc36e06964077c000bbcb0db683e70456c274665..bc9eeaf212ae0b9ca63c478ff3cc303a4ef7f616 100644 (file)
@@ -31,6 +31,7 @@ nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw)
                int version;
                int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *);
        } wimms[] = {
+               { TU104_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
                { GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
                {}
        };
index 2187922e8dc28d4d11df28bc33aec3f91281791c..ba9eea2ff16bb2dbfac5606c3f1a566777d7abbc 100644 (file)
@@ -139,10 +139,8 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
        if (asyw->set.xlut ) {
                if (asyw->ilut) {
                        asyw->xlut.i.offset =
-                               nv50_lut_load(&wndw->ilut,
-                                             asyw->xlut.i.mode <= 1,
-                                             asyw->xlut.i.buffer,
-                                             asyw->ilut);
+                               nv50_lut_load(&wndw->ilut, asyw->xlut.i.buffer,
+                                             asyw->ilut, asyw->xlut.i.load);
                }
                wndw->func->xlut_set(wndw, asyw);
        }
@@ -322,6 +320,11 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
                asyh->wndw.olut &= ~BIT(wndw->id);
        }
 
+       if (!ilut && wndw->func->ilut_identity) {
+               static struct drm_property_blob dummy = {};
+               ilut = &dummy;
+       }
+
        /* Recalculate LUT state. */
        memset(&asyw->xlut, 0x00, sizeof(asyw->xlut));
        if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) {
@@ -623,6 +626,7 @@ nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
                int (*new)(struct nouveau_drm *, enum drm_plane_type,
                           int, s32, struct nv50_wndw **);
        } wndws[] = {
+               { TU104_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new },
                { GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new },
                {}
        };
index b0b6428034b07f32659f254c32b410b192dc77de..03f3d8dc235a70cb5d15670c687b427c5c665319 100644 (file)
@@ -65,6 +65,7 @@ struct nv50_wndw_func {
        int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset,
                               struct nvif_device *);
        void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *);
+       bool ilut_identity;
        bool olut_core;
        void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
        void (*xlut_clr)(struct nv50_wndw *);
@@ -90,6 +91,23 @@ extern const struct nv50_wimm_func curs507a;
 
 int wndwc37e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
                 struct nv50_wndw **);
+int wndwc37e_new_(const struct nv50_wndw_func *, struct nouveau_drm *,
+                 enum drm_plane_type type, int index, s32 oclass, u32 heads,
+                 struct nv50_wndw **);
+int wndwc37e_acquire(struct nv50_wndw *, struct nv50_wndw_atom *,
+                    struct nv50_head_atom *);
+void wndwc37e_release(struct nv50_wndw *, struct nv50_wndw_atom *,
+                     struct nv50_head_atom *);
+void wndwc37e_sema_set(struct nv50_wndw *, struct nv50_wndw_atom *);
+void wndwc37e_sema_clr(struct nv50_wndw *);
+void wndwc37e_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
+void wndwc37e_ntfy_clr(struct nv50_wndw *);
+void wndwc37e_image_set(struct nv50_wndw *, struct nv50_wndw_atom *);
+void wndwc37e_image_clr(struct nv50_wndw *);
+void wndwc37e_update(struct nv50_wndw *, u32 *);
+
+int wndwc57e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
+                struct nv50_wndw **);
 
 int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
                  struct nv50_wndw **);
index 44afb0f069a55e362b969604161da7508b55c07a..e52a85c83f7a81358981536b419db9e5a475d82e 100644 (file)
@@ -61,9 +61,10 @@ wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
        asyw->xlut.i.size = 0;
        asyw->xlut.i.range = 0;
        asyw->xlut.i.output_mode = 1;
+       asyw->xlut.i.load = head907d_olut_load;
 }
 
-static void
+void
 wndwc37e_image_clr(struct nv50_wndw *wndw)
 {
        u32 *push;
@@ -76,7 +77,7 @@ wndwc37e_image_clr(struct nv50_wndw *wndw)
        }
 }
 
-static void
+void
 wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
        u32 *push;
@@ -117,7 +118,7 @@ wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
        evo_kick(push, &wndw->wndw);
 }
 
-static void
+void
 wndwc37e_ntfy_clr(struct nv50_wndw *wndw)
 {
        u32 *push;
@@ -128,7 +129,7 @@ wndwc37e_ntfy_clr(struct nv50_wndw *wndw)
        }
 }
 
-static void
+void
 wndwc37e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
        u32 *push;
@@ -140,7 +141,7 @@ wndwc37e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
        }
 }
 
-static void
+void
 wndwc37e_sema_clr(struct nv50_wndw *wndw)
 {
        u32 *push;
@@ -151,7 +152,7 @@ wndwc37e_sema_clr(struct nv50_wndw *wndw)
        }
 }
 
-static void
+void
 wndwc37e_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
        u32 *push;
@@ -165,7 +166,7 @@ wndwc37e_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
        }
 }
 
-static void
+void
 wndwc37e_update(struct nv50_wndw *wndw, u32 *interlock)
 {
        u32 *push;
@@ -183,13 +184,13 @@ wndwc37e_update(struct nv50_wndw *wndw, u32 *interlock)
        }
 }
 
-static void
+void
 wndwc37e_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
                 struct nv50_head_atom *asyh)
 {
 }
 
-static int
+int
 wndwc37e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
                 struct nv50_head_atom *asyh)
 {
@@ -236,7 +237,7 @@ wndwc37e = {
        .update = wndwc37e_update,
 };
 
-static int
+int
 wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm,
              enum drm_plane_type type, int index, s32 oclass, u32 heads,
              struct nv50_wndw **pwndw)
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
new file mode 100644 (file)
index 0000000..ba89f1a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "wndw.h"
+#include "atom.h"
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <nouveau_bo.h>
+
+#include <nvif/clc37e.h>
+
+static void
+wndwc57e_ilut_clr(struct nv50_wndw *wndw)
+{
+       u32 *push;
+       if ((push = evo_wait(&wndw->wndw, 2))) {
+               evo_mthd(push, 0x0444, 1);
+               evo_data(push, 0x00000000);
+               evo_kick(push, &wndw->wndw);
+       }
+}
+
+static void
+wndwc57e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+       u32 *push;
+       if ((push = evo_wait(&wndw->wndw, 4))) {
+               evo_mthd(push, 0x0440, 3);
+               evo_data(push, asyw->xlut.i.size << 8 |
+                              asyw->xlut.i.mode << 2 |
+                              asyw->xlut.i.output_mode);
+               evo_data(push, asyw->xlut.handle);
+               evo_data(push, asyw->xlut.i.offset >> 8);
+               evo_kick(push, &wndw->wndw);
+       }
+}
+
+static u16
+fixedU0_16_FP16(u16 fixed)
+{
+        int sign = 0, exp = 0, man = 0;
+        if (fixed) {
+                while (--exp && !(fixed & 0x8000))
+                        fixed <<= 1;
+                man = ((fixed << 1) & 0xffc0) >> 6;
+                exp += 15;
+        }
+        return (sign << 15) | (exp << 10) | man;
+}
+
+static void
+wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       memset_io(mem, 0x00, 0x20); /* VSS header. */
+       mem += 0x20;
+
+       for (; size--; in++, mem += 0x08) {
+               u16 r = fixedU0_16_FP16(drm_color_lut_extract(in->  red, 16));
+               u16 g = fixedU0_16_FP16(drm_color_lut_extract(in->green, 16));
+               u16 b = fixedU0_16_FP16(drm_color_lut_extract(in-> blue, 16));
+               writew(r, mem + 0);
+               writew(g, mem + 2);
+               writew(b, mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
+static void
+wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+       u16 size = asyw->ilut->length / sizeof(struct drm_color_lut);
+       if (size == 256) {
+               asyw->xlut.i.mode = 1; /* DIRECT8. */
+       } else {
+               asyw->xlut.i.mode = 2; /* DIRECT10. */
+               size = 1024;
+       }
+       asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */;
+       asyw->xlut.i.output_mode = 0; /* INTERPOLATE_DISABLE. */
+       asyw->xlut.i.load = wndwc57e_ilut_load;
+}
+
+static const struct nv50_wndw_func
+wndwc57e = {
+       .acquire = wndwc37e_acquire,
+       .release = wndwc37e_release,
+       .sema_set = wndwc37e_sema_set,
+       .sema_clr = wndwc37e_sema_clr,
+       .ntfy_set = wndwc37e_ntfy_set,
+       .ntfy_clr = wndwc37e_ntfy_clr,
+       .ntfy_reset = corec37d_ntfy_init,
+       .ntfy_wait_begun = base507c_ntfy_wait_begun,
+       .ilut = wndwc57e_ilut,
+       .ilut_identity = true,
+       .xlut_set = wndwc57e_ilut_set,
+       .xlut_clr = wndwc57e_ilut_clr,
+       .image_set = wndwc37e_image_set,
+       .image_clr = wndwc37e_image_clr,
+       .update = wndwc37e_update,
+};
+
+int
+wndwc57e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
+            s32 oclass, struct nv50_wndw **pwndw)
+{
+       return wndwc37e_new_(&wndwc57e, drm, type, index, oclass,
+                            BIT(index >> 1), pwndw);
+}
index 4f5233107f5f83d4ea2abbf8a639278f6588e577..4cbed03293676742c5e5b2b72f50537df63a0e1e 100644 (file)
@@ -32,6 +32,7 @@ struct nv_device_info_v0 {
 #define NV_DEVICE_INFO_V0_MAXWELL                                          0x09
 #define NV_DEVICE_INFO_V0_PASCAL                                           0x0a
 #define NV_DEVICE_INFO_V0_VOLTA                                            0x0b
+#define NV_DEVICE_INFO_V0_TURING                                           0x0c
        __u8  family;
        __u8  pad06[2];
        __u64 ram_size;
index fbfcffc5feb2b4440572a317ed2ae41aff4bd2fe..81401eb970ea68798356a667e7249cfea9d34fda 100644 (file)
@@ -4,12 +4,13 @@
 
 struct kepler_channel_gpfifo_a_v0 {
        __u8  version;
-       __u8  pad01[1];
+       __u8  priv;
        __u16 chid;
        __u32 ilength;
        __u64 ioffset;
        __u64 runlist;
        __u64 vmm;
+       __u64 inst;
 };
 
 #define NVA06F_V0_NTFY_NON_STALL_INTERRUPT                                 0x00
index 6db56bd7d67eb1b6d745ff26d09e57dfe2a81ebc..1d82cbf70cf448784e388e3e2909f5e33d568daa 100644 (file)
@@ -68,7 +68,8 @@
 #define KEPLER_CHANNEL_GPFIFO_B                       /* cla06f.h */ 0x0000a16f
 #define MAXWELL_CHANNEL_GPFIFO_A                      /* cla06f.h */ 0x0000b06f
 #define PASCAL_CHANNEL_GPFIFO_A                       /* cla06f.h */ 0x0000c06f
-#define VOLTA_CHANNEL_GPFIFO_A                        /* cla06f.h */ 0x0000c36f
+#define VOLTA_CHANNEL_GPFIFO_A                        /* clc36f.h */ 0x0000c36f
+#define TURING_CHANNEL_GPFIFO_A                       /* clc36f.h */ 0x0000c46f
 
 #define NV50_DISP                                     /* cl5070.h */ 0x00005070
 #define G82_DISP                                      /* cl5070.h */ 0x00008270
@@ -83,6 +84,7 @@
 #define GP100_DISP                                    /* cl5070.h */ 0x00009770
 #define GP102_DISP                                    /* cl5070.h */ 0x00009870
 #define GV100_DISP                                    /* cl5070.h */ 0x0000c370
+#define TU104_DISP                                    /* cl5070.h */ 0x0000c570
 
 #define NV31_MPEG                                                    0x00003174
 #define G82_MPEG                                                     0x00008274
@@ -95,6 +97,7 @@
 #define GF110_DISP_CURSOR                             /* cl507a.h */ 0x0000907a
 #define GK104_DISP_CURSOR                             /* cl507a.h */ 0x0000917a
 #define GV100_DISP_CURSOR                             /* cl507a.h */ 0x0000c37a
+#define TU104_DISP_CURSOR                             /* cl507a.h */ 0x0000c57a
 
 #define NV50_DISP_OVERLAY                             /* cl507b.h */ 0x0000507b
 #define G82_DISP_OVERLAY                              /* cl507b.h */ 0x0000827b
 #define GK104_DISP_OVERLAY                            /* cl507b.h */ 0x0000917b
 
 #define GV100_DISP_WINDOW_IMM_CHANNEL_DMA             /* clc37b.h */ 0x0000c37b
+#define TU104_DISP_WINDOW_IMM_CHANNEL_DMA             /* clc37b.h */ 0x0000c57b
 
 #define NV50_DISP_BASE_CHANNEL_DMA                    /* cl507c.h */ 0x0000507c
 #define G82_DISP_BASE_CHANNEL_DMA                     /* cl507c.h */ 0x0000827c
 #define GP100_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000977d
 #define GP102_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000987d
 #define GV100_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000c37d
+#define TU104_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000c57d
 
 #define NV50_DISP_OVERLAY_CHANNEL_DMA                 /* cl507e.h */ 0x0000507e
 #define G82_DISP_OVERLAY_CHANNEL_DMA                  /* cl507e.h */ 0x0000827e
 #define GK104_DISP_OVERLAY_CONTROL_DMA                /* cl507e.h */ 0x0000917e
 
 #define GV100_DISP_WINDOW_CHANNEL_DMA                 /* clc37e.h */ 0x0000c37e
+#define TU104_DISP_WINDOW_CHANNEL_DMA                 /* clc37e.h */ 0x0000c57e
 
 #define NV50_TESLA                                                   0x00005097
 #define G82_TESLA                                                    0x00008297
 #define PASCAL_DMA_COPY_A                                            0x0000c0b5
 #define PASCAL_DMA_COPY_B                                            0x0000c1b5
 #define VOLTA_DMA_COPY_A                                             0x0000c3b5
+#define TURING_DMA_COPY_A                                            0x0000c5b5
 
 #define FERMI_DECOMPRESS                                             0x000090b8
 
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clc36f.h b/drivers/gpu/drm/nouveau/include/nvif/clc36f.h
new file mode 100644 (file)
index 0000000..6b14d7e
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NVIF_CLC36F_H__
+#define __NVIF_CLC36F_H__
+
+struct volta_channel_gpfifo_a_v0 {
+       __u8  version;
+       __u8  priv;
+       __u16 chid;
+       __u32 ilength;
+       __u64 ioffset;
+       __u64 runlist;
+       __u64 vmm;
+       __u64 inst;
+       __u32 token;
+};
+
+#define NVC36F_V0_NTFY_NON_STALL_INTERRUPT                                 0x00
+#define NVC36F_V0_NTFY_KILLED                                              0x01
+#endif
index d83d834b745217940a9125c8ce99930aad6ac79a..72e4dc1f02360ff6856a671048328f325718f994 100644 (file)
@@ -61,7 +61,11 @@ enum nvkm_devidx {
        NVKM_ENGINE_NVENC2,
        NVKM_ENGINE_NVENC_LAST = NVKM_ENGINE_NVENC2,
 
-       NVKM_ENGINE_NVDEC,
+       NVKM_ENGINE_NVDEC0,
+       NVKM_ENGINE_NVDEC1,
+       NVKM_ENGINE_NVDEC2,
+       NVKM_ENGINE_NVDEC_LAST = NVKM_ENGINE_NVDEC2,
+
        NVKM_ENGINE_PM,
        NVKM_ENGINE_SEC,
        NVKM_ENGINE_SEC2,
@@ -114,6 +118,7 @@ struct nvkm_device {
                GM100    = 0x110,
                GP100    = 0x130,
                GV100    = 0x140,
+               TU100    = 0x160,
        } card_type;
        u32 chipset;
        u8  chiprev;
@@ -163,7 +168,7 @@ struct nvkm_device {
        struct nvkm_engine *msppp;
        struct nvkm_engine *msvld;
        struct nvkm_engine *nvenc[3];
-       struct nvkm_nvdec *nvdec;
+       struct nvkm_nvdec *nvdec[3];
        struct nvkm_pm *pm;
        struct nvkm_engine *sec;
        struct nvkm_sec2 *sec2;
@@ -235,7 +240,7 @@ struct nvkm_device_chip {
        int (*msppp   )(struct nvkm_device *, int idx, struct nvkm_engine **);
        int (*msvld   )(struct nvkm_device *, int idx, struct nvkm_engine **);
        int (*nvenc[3])(struct nvkm_device *, int idx, struct nvkm_engine **);
-       int (*nvdec   )(struct nvkm_device *, int idx, struct nvkm_nvdec **);
+       int (*nvdec[3])(struct nvkm_device *, int idx, struct nvkm_nvdec **);
        int (*pm      )(struct nvkm_device *, int idx, struct nvkm_pm **);
        int (*sec     )(struct nvkm_device *, int idx, struct nvkm_engine **);
        int (*sec2    )(struct nvkm_device *, int idx, struct nvkm_sec2 **);
index 05f505de0075f5256b39814292789ae56b8d044f..f34c80310861ed9446342e304ec385ed775a610d 100644 (file)
@@ -29,6 +29,7 @@ struct nvkm_memory_func {
        void *(*dtor)(struct nvkm_memory *);
        enum nvkm_memory_target (*target)(struct nvkm_memory *);
        u8 (*page)(struct nvkm_memory *);
+       u64 (*bar2)(struct nvkm_memory *);
        u64 (*addr)(struct nvkm_memory *);
        u64 (*size)(struct nvkm_memory *);
        void (*boot)(struct nvkm_memory *, struct nvkm_vmm *);
@@ -56,6 +57,7 @@ void nvkm_memory_tags_put(struct nvkm_memory *, struct nvkm_device *,
 
 #define nvkm_memory_target(p) (p)->func->target(p)
 #define nvkm_memory_page(p) (p)->func->page(p)
+#define nvkm_memory_bar2(p) (p)->func->bar2(p)
 #define nvkm_memory_addr(p) (p)->func->addr(p)
 #define nvkm_memory_size(p) (p)->func->size(p)
 #define nvkm_memory_boot(p,v) (p)->func->boot((p),(v))
index fc295e1faa198282118739759eb47c33d4866542..86abe76023c230cdb212c41efd246b0993052fc5 100644 (file)
@@ -11,4 +11,5 @@ int gm200_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
 int gp100_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
 int gp102_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
 int gv100_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
+int tu104_ce_new(struct nvkm_device *, int, struct nvkm_engine **);
 #endif
index ef7dc0844d26e4b6f6268cae18224026d1237318..5ca86e178bb98f5eb857d4cd2624efa533a2457c 100644 (file)
@@ -36,4 +36,5 @@ int gm200_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
 int gp100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
 int gp102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
 int gv100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
+int tu104_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
 #endif
index 7e39fbed2519cb104658c1e8195f26a47788b453..3b2b685778eb15d57310fabd0a690b6a27cd0610 100644 (file)
@@ -74,4 +74,5 @@ int gm20b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
 int gp100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
 int gp10b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
 int gv100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
+int tu104_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **);
 #endif
index f6bd94c7e0f75fa71586a41270a1865c6c702a11..fd9d713b611cf4a133985c6311ac53e75fcce86b 100644 (file)
@@ -16,8 +16,10 @@ struct nvkm_bar {
 };
 
 struct nvkm_vmm *nvkm_bar_bar1_vmm(struct nvkm_device *);
+void nvkm_bar_bar1_reset(struct nvkm_device *);
 void nvkm_bar_bar2_init(struct nvkm_device *);
 void nvkm_bar_bar2_fini(struct nvkm_device *);
+void nvkm_bar_bar2_reset(struct nvkm_device *);
 struct nvkm_vmm *nvkm_bar_bar2_vmm(struct nvkm_device *);
 void nvkm_bar_flush(struct nvkm_bar *);
 
@@ -27,4 +29,5 @@ int gf100_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
 int gk20a_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
 int gm107_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
 int gm20b_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
+int tu104_bar_new(struct nvkm_device *, int, struct nvkm_bar **);
 #endif
index 703a5b524b96c7bd445f35a79bf402f60e7f6d4b..425ccc47e3b778740b2cf8101a6b8c71402fa4ec 100644 (file)
@@ -12,11 +12,14 @@ u32 nvbios_M0203Tp(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
                   struct nvbios_M0203T *);
 
 struct nvbios_M0203E {
-#define M0203E_TYPE_DDR2  0x0
-#define M0203E_TYPE_DDR3  0x1
-#define M0203E_TYPE_GDDR3 0x2
-#define M0203E_TYPE_GDDR5 0x3
-#define M0203E_TYPE_SKIP  0xf
+#define M0203E_TYPE_DDR2   0x0
+#define M0203E_TYPE_DDR3   0x1
+#define M0203E_TYPE_GDDR3  0x2
+#define M0203E_TYPE_GDDR5  0x3
+#define M0203E_TYPE_HBM2   0x6
+#define M0203E_TYPE_GDDR5X 0x8
+#define M0203E_TYPE_GDDR6  0x9
+#define M0203E_TYPE_SKIP   0xf
        u8 type;
        u8 strap;
        u8 group;
index ed9e0a6a001190fed601b6af8255eed621f0307a..8463b421d34542796c605c4b77beccfaf7094bd3 100644 (file)
@@ -20,6 +20,7 @@ enum dcb_connector_type {
        DCB_CONNECTOR_DMS59_DP0 = 0x64,
        DCB_CONNECTOR_DMS59_DP1 = 0x65,
        DCB_CONNECTOR_WFD       = 0x70,
+       DCB_CONNECTOR_USB_C = 0x71,
        DCB_CONNECTOR_NONE = 0xff
 };
 
index 486e7635c29d7aa12b7ddd6f3de0b443c03f8c64..1b71812a790bcd1ec8068e3233a014024a265fba 100644 (file)
@@ -31,4 +31,5 @@ int gf100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
 int gm107_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
 int gm200_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
 int gv100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
+int tu104_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
 #endif
index 5a77498fe6a09a304c1d63cf297cc3977c9bf5ac..127f48066026eaa55dea0c3d7cb666b9767ed17a 100644 (file)
@@ -30,4 +30,5 @@ struct nvkm_fault_data {
 
 int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
 int gv100_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
+int tu104_fault_new(struct nvkm_device *, int, struct nvkm_fault **);
 #endif
index 96ccc624ee8144ded1208bf276b7477598976470..27298f8b7ead09c050a9761a8bfd0637b80a8587 100644 (file)
@@ -105,7 +105,10 @@ enum nvkm_ram_type {
        NVKM_RAM_TYPE_GDDR2,
        NVKM_RAM_TYPE_GDDR3,
        NVKM_RAM_TYPE_GDDR4,
-       NVKM_RAM_TYPE_GDDR5
+       NVKM_RAM_TYPE_GDDR5,
+       NVKM_RAM_TYPE_GDDR5X,
+       NVKM_RAM_TYPE_GDDR6,
+       NVKM_RAM_TYPE_HBM2,
 };
 
 struct nvkm_ram {
index 61c93c86e2e2473113ea1ed7f0b49b4c8b1a23f7..b66dedd8abb6aae949058a2ccc57c86ea5ea4f65 100644 (file)
@@ -31,4 +31,5 @@ int gk104_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
 int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
 int gp100_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
 int gp10b_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
+int tu104_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
 #endif
index 688595545e21ed7b2700953f9a698a06f40b81de..0a0e064f22e5962b06405a05ea42e9d6f47de18a 100644 (file)
@@ -130,4 +130,5 @@ int gm20b_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
 int gp100_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
 int gp10b_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
 int gv100_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
+int tu104_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **);
 #endif
index e9b0746826ca66f9ac1765bbf8e757e1ee57a208..3693ebf371b647d0e7ba1044861f5417da6e332f 100644 (file)
@@ -28,6 +28,18 @@ struct nvkm_timer {
 u64 nvkm_timer_read(struct nvkm_timer *);
 void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
 
+struct nvkm_timer_wait {
+       struct nvkm_timer *tmr;
+       u64 limit;
+       u64 time0;
+       u64 time1;
+       int reads;
+};
+
+void nvkm_timer_wait_init(struct nvkm_device *, u64 nsec,
+                         struct nvkm_timer_wait *);
+s64 nvkm_timer_wait_test(struct nvkm_timer_wait *);
+
 /* Delay based on GPU time (ie. PTIMER).
  *
  * Will return -ETIMEDOUT unless the loop was terminated with 'break',
@@ -38,21 +50,17 @@ void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
  */
 #define NVKM_DELAY _warn = false;
 #define nvkm_nsec(d,n,cond...) ({                                              \
-       struct nvkm_device *_device = (d);                                     \
-       struct nvkm_timer *_tmr = _device->timer;                              \
-       u64 _nsecs = (n), _time0 = nvkm_timer_read(_tmr);                      \
-       s64 _taken = 0;                                                        \
+       struct nvkm_timer_wait _wait;                                          \
        bool _warn = true;                                                     \
+       s64 _taken = 0;                                                        \
                                                                                \
+       nvkm_timer_wait_init((d), (n), &_wait);                                \
        do {                                                                   \
                cond                                                           \
-       } while (_taken = nvkm_timer_read(_tmr) - _time0, _taken < _nsecs);    \
+       } while ((_taken = nvkm_timer_wait_test(&_wait)) >= 0);                \
                                                                                \
-       if (_taken >= _nsecs) {                                                \
-               if (_warn)                                                     \
-                       dev_WARN(_device->dev, "timeout\n");                   \
-               _taken = -ETIMEDOUT;                                           \
-       }                                                                      \
+       if (_warn && _taken < 0)                                               \
+               dev_WARN(_wait.tmr->subdev.device->dev, "timeout\n");          \
        _taken;                                                                \
 })
 #define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond)
index e67a471331b514b75321c4bf8a0fff1be7057113..b06cdac8f3a2bf0e0041a865cf3103379f1e11ce 100644 (file)
@@ -306,7 +306,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
 
        /* create channel object and initialise dma and fence management */
        ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
-                                 init->tt_ctxdma_handle, &chan->chan);
+                                 init->tt_ctxdma_handle, false, &chan->chan);
        if (ret)
                goto done;
 
index 7214022dfb91187ae519e51905a5512b542abe70..73eff52036d2a9785d65cbfd4f8ab8a4d6824878 100644 (file)
@@ -1141,6 +1141,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, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
+               {  "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },
                {  "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init },
                {  "GRCE", 0, 0xc3b5, nve0_bo_move_copy, nvc0_bo_move_init },
                {  "COPY", 4, 0xc1b5, nve0_bo_move_copy, nve0_bo_move_init },
index 92d3115f96b5090889281c62edf219bbdb64dd66..668afbc29c3e362b055c9b9bc0f944ff4ebf8e2d 100644 (file)
@@ -29,6 +29,7 @@
 #include <nvif/cl506f.h>
 #include <nvif/cl906f.h>
 #include <nvif/cla06f.h>
+#include <nvif/clc36f.h>
 #include <nvif/ioctl.h>
 
 /*XXX*/
@@ -217,10 +218,11 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
 
 static int
 nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
-                   u64 runlist, struct nouveau_channel **pchan)
+                   u64 runlist, bool priv, struct nouveau_channel **pchan)
 {
        struct nouveau_cli *cli = (void *)device->object.client;
-       static const u16 oclasses[] = { VOLTA_CHANNEL_GPFIFO_A,
+       static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A,
+                                       VOLTA_CHANNEL_GPFIFO_A,
                                        PASCAL_CHANNEL_GPFIFO_A,
                                        MAXWELL_CHANNEL_GPFIFO_A,
                                        KEPLER_CHANNEL_GPFIFO_B,
@@ -234,6 +236,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
                struct nv50_channel_gpfifo_v0 nv50;
                struct fermi_channel_gpfifo_v0 fermi;
                struct kepler_channel_gpfifo_a_v0 kepler;
+               struct volta_channel_gpfifo_a_v0 volta;
        } args;
        struct nouveau_channel *chan;
        u32 size;
@@ -247,12 +250,22 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
 
        /* create channel object */
        do {
+               if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) {
+                       args.volta.version = 0;
+                       args.volta.ilength = 0x02000;
+                       args.volta.ioffset = 0x10000 + chan->push.addr;
+                       args.volta.runlist = runlist;
+                       args.volta.vmm = nvif_handle(&cli->vmm.vmm.object);
+                       args.volta.priv = priv;
+                       size = sizeof(args.volta);
+               } else
                if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
                        args.kepler.version = 0;
                        args.kepler.ilength = 0x02000;
                        args.kepler.ioffset = 0x10000 + chan->push.addr;
                        args.kepler.runlist = runlist;
                        args.kepler.vmm = nvif_handle(&cli->vmm.vmm.object);
+                       args.kepler.priv = priv;
                        size = sizeof(args.kepler);
                } else
                if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
@@ -273,13 +286,20 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
                ret = nvif_object_init(&device->object, 0, *oclass++,
                                       &args, size, &chan->user);
                if (ret == 0) {
-                       if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A)
+                       if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) {
+                               chan->chid = args.volta.chid;
+                               chan->inst = args.volta.inst;
+                               chan->token = args.volta.token;
+                       } else
+                       if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) {
                                chan->chid = args.kepler.chid;
-                       else
-                       if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO)
+                               chan->inst = args.kepler.inst;
+                       } else
+                       if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
                                chan->chid = args.fermi.chid;
-                       else
+                       } else {
                                chan->chid = args.nv50.chid;
+                       }
                        return ret;
                }
        } while (*oclass);
@@ -448,7 +468,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
 
 int
 nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
-                   u32 arg0, u32 arg1, struct nouveau_channel **pchan)
+                   u32 arg0, u32 arg1, bool priv,
+                   struct nouveau_channel **pchan)
 {
        struct nouveau_cli *cli = (void *)device->object.client;
        bool super;
@@ -458,7 +479,7 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
        super = cli->base.super;
        cli->base.super = true;
 
-       ret = nouveau_channel_ind(drm, device, arg0, pchan);
+       ret = nouveau_channel_ind(drm, device, arg0, priv, pchan);
        if (ret) {
                NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
                ret = nouveau_channel_dma(drm, device, pchan);
index 64454c2ebd908ce82a1b6886ee376dd37d71d489..28418f4e574884376522d6a3d65274231d6eaca5 100644 (file)
@@ -10,6 +10,8 @@ struct nouveau_channel {
        struct nouveau_drm *drm;
 
        int chid;
+       u64 inst;
+       u32 token;
 
        struct nvif_object vram;
        struct nvif_object gart;
@@ -48,7 +50,8 @@ struct nouveau_channel {
 int nouveau_channels_init(struct nouveau_drm *);
 
 int  nouveau_channel_new(struct nouveau_drm *, struct nvif_device *,
-                        u32 arg0, u32 arg1, struct nouveau_channel **);
+                        u32 arg0, u32 arg1, bool priv,
+                        struct nouveau_channel **);
 void nouveau_channel_del(struct nouveau_channel **);
 int  nouveau_channel_idle(struct nouveau_channel *);
 
index fd80661dff92691f94c9b91c3799712d04cb9c17..3f463c91314ab6ae6b896a759b1a56b9494807d3 100644 (file)
@@ -403,6 +403,7 @@ nouveau_connector_destroy(struct drm_connector *connector)
        if (nv_connector->aux.transfer) {
                drm_dp_cec_unregister_connector(&nv_connector->aux);
                drm_dp_aux_unregister(&nv_connector->aux);
+               kfree(nv_connector->aux.name);
        }
        kfree(connector);
 }
@@ -1218,7 +1219,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
        case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
        case DCB_CONNECTOR_DMS59_DP0:
        case DCB_CONNECTOR_DMS59_DP1:
-       case DCB_CONNECTOR_DP       : return DRM_MODE_CONNECTOR_DisplayPort;
+       case DCB_CONNECTOR_DP       :
+       case DCB_CONNECTOR_USB_C    : return DRM_MODE_CONNECTOR_DisplayPort;
        case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
        case DCB_CONNECTOR_HDMI_0   :
        case DCB_CONNECTOR_HDMI_1   :
@@ -1232,7 +1234,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
 }
 
 struct drm_connector *
-nouveau_connector_create(struct drm_device *dev, int index)
+nouveau_connector_create(struct drm_device *dev,
+                        const struct dcb_output *dcbe)
 {
        const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
        struct nouveau_drm *drm = nouveau_drm(dev);
@@ -1240,6 +1243,8 @@ nouveau_connector_create(struct drm_device *dev, int index)
        struct nouveau_connector *nv_connector = NULL;
        struct drm_connector *connector;
        struct drm_connector_list_iter conn_iter;
+       char aux_name[48] = {0};
+       int index = dcbe->connector;
        int type, ret = 0;
        bool dummy;
 
@@ -1342,6 +1347,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
        case DRM_MODE_CONNECTOR_eDP:
                nv_connector->aux.dev = dev->dev;
                nv_connector->aux.transfer = nouveau_connector_aux_xfer;
+               snprintf(aux_name, sizeof(aux_name), "sor-%04x-%04x",
+                        dcbe->hasht, dcbe->hashm);
+               nv_connector->aux.name = kstrdup(aux_name, GFP_KERNEL);
                ret = drm_dp_aux_register(&nv_connector->aux);
                if (ret) {
                        NV_ERROR(drm, "failed to register aux channel\n");
index f57ef35b1e5e6b6b5ce222bfc1f16fa9c757fa31..f43a8d63aef86e07c7078501ff4bad0e33ba937b 100644 (file)
@@ -38,6 +38,7 @@
 #include "nouveau_encoder.h"
 
 struct nvkm_i2c_port;
+struct dcb_output;
 
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
 struct nouveau_backlight;
@@ -113,7 +114,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
 }
 
 struct drm_connector *
-nouveau_connector_create(struct drm_device *, int index);
+nouveau_connector_create(struct drm_device *, const struct dcb_output *);
 
 extern int nouveau_tv_disable;
 extern int nouveau_ignorelid;
index 9109b69cd052958bbc126b4bad4f490720e11f4a..88a52f6b39fe333df24c33dce9aef2535d6a1b09 100644 (file)
@@ -46,6 +46,26 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
        return 0;
 }
 
+static int
+nouveau_debugfs_strap_peek(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = m->private;
+       struct nouveau_drm *drm = nouveau_drm(node->minor->dev);
+       int ret;
+
+       ret = pm_runtime_get_sync(drm->dev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       seq_printf(m, "0x%08x\n",
+                  nvif_rd32(&drm->client.device.object, 0x101000));
+
+       pm_runtime_mark_last_busy(drm->dev->dev);
+       pm_runtime_put_autosuspend(drm->dev->dev);
+
+       return 0;
+}
+
 static int
 nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
 {
@@ -185,7 +205,8 @@ static const struct file_operations nouveau_pstate_fops = {
 };
 
 static struct drm_info_list nouveau_debugfs_list[] = {
-       { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
+       { "vbios.rom",  nouveau_debugfs_vbios_image, 0, NULL },
+       { "strap_peek", nouveau_debugfs_strap_peek, 0, NULL },
 };
 #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
 
@@ -199,8 +220,9 @@ static const struct nouveau_debugfs_files {
 int
 nouveau_drm_debugfs_init(struct drm_minor *minor)
 {
+       struct nouveau_drm *drm = nouveau_drm(minor->dev);
        struct dentry *dentry;
-       int i;
+       int i, ret;
 
        for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
                dentry = debugfs_create_file(nouveau_debugfs_files[i].name,
@@ -211,9 +233,23 @@ nouveau_drm_debugfs_init(struct drm_minor *minor)
                        return -ENOMEM;
        }
 
-       return drm_debugfs_create_files(nouveau_debugfs_list,
-                                       NOUVEAU_DEBUGFS_ENTRIES,
-                                       minor->debugfs_root, minor);
+       ret = drm_debugfs_create_files(nouveau_debugfs_list,
+                                      NOUVEAU_DEBUGFS_ENTRIES,
+                                      minor->debugfs_root, minor);
+       if (ret)
+               return ret;
+
+       /* Set the size of the vbios since we know it, and it's confusing to
+        * userspace if it wants to seek() but the file has a length of 0
+        */
+       dentry = debugfs_lookup("vbios.rom", minor->debugfs_root);
+       if (!dentry)
+               return 0;
+
+       d_inode(dentry)->i_size = drm->vbios.length;
+       dput(dentry);
+
+       return 0;
 }
 
 int
index 945afd34138edc06efe504d1be6583c8cb76c050..078f65d849ce4403839a9d857021612c7ce6e7c8 100644 (file)
@@ -101,7 +101,7 @@ nv50_dma_push(struct nouveau_channel *chan, u64 offset, int length)
 
        nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put);
        if (user->func && user->func->doorbell)
-               user->func->doorbell(user, chan->chid);
+               user->func->doorbell(user, chan->token);
        chan->dma.ib_free--;
 }
 
index d2928d43f29a43d772729ef68036b426f861047d..f900e94592f8c1ab1f7c54bd8810f241363933c9 100644 (file)
@@ -353,6 +353,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
                case MAXWELL_CHANNEL_GPFIFO_A:
                case PASCAL_CHANNEL_GPFIFO_A:
                case VOLTA_CHANNEL_GPFIFO_A:
+               case TURING_CHANNEL_GPFIFO_A:
                        ret = nvc0_fence_create(drm);
                        break;
                default:
@@ -370,7 +371,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
        if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
                ret = nouveau_channel_new(drm, &drm->client.device,
                                          nvif_fifo_runlist_ce(device), 0,
-                                         &drm->cechan);
+                                         true, &drm->cechan);
                if (ret)
                        NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
 
@@ -381,7 +382,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
            device->info.chipset != 0xaa &&
            device->info.chipset != 0xac) {
                ret = nouveau_channel_new(drm, &drm->client.device,
-                                         NvDmaFB, NvDmaTT, &drm->cechan);
+                                         NvDmaFB, NvDmaTT, false,
+                                         &drm->cechan);
                if (ret)
                        NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
 
@@ -393,7 +395,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
        }
 
        ret = nouveau_channel_new(drm, &drm->client.device,
-                                 arg0, arg1, &drm->channel);
+                                 arg0, arg1, false, &drm->channel);
        if (ret) {
                NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
                nouveau_accel_fini(drm);
index 0b2191fa96f7bc288e28e2cb6df141422882ef1a..d20b9ba4b1c1a60d6ab942708479f2fdb15ccaa5 100644 (file)
@@ -146,8 +146,6 @@ struct nouveau_drm {
 
        /* TTM interface support */
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
                atomic_t validate_sequence;
                int (*move)(struct nouveau_channel *,
index 99be61ddeb75843621c7ed2b36c1c7974d805769..d4964f3397a134aab44b05b7f3852c7157978a8c 100644 (file)
@@ -341,7 +341,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
        int ret = 0, i;
 
        if (!exclusive) {
-               ret = reservation_object_reserve_shared(resv);
+               ret = reservation_object_reserve_shared(resv, 1);
 
                if (ret)
                        return ret;
index 8edb9f2a426945be9bf88ff167cc9ccebfa2171b..1543c2f8d3d3312f267e17c03168fab29370aa77 100644 (file)
@@ -174,66 +174,6 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
        return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
 
-static int
-nouveau_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void
-nouveau_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-int
-nouveau_ttm_global_init(struct nouveau_drm *drm)
-{
-       struct drm_global_reference *global_ref;
-       int ret;
-
-       global_ref = &drm->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &nouveau_ttm_mem_global_init;
-       global_ref->release = &nouveau_ttm_mem_global_release;
-
-       ret = drm_global_item_ref(global_ref);
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed setting up TTM memory accounting\n");
-               drm->ttm.mem_global_ref.release = NULL;
-               return ret;
-       }
-
-       drm->ttm.bo_global_ref.mem_glob = global_ref->object;
-       global_ref = &drm->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-
-       ret = drm_global_item_ref(global_ref);
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed setting up TTM BO subsystem\n");
-               drm_global_item_unref(&drm->ttm.mem_global_ref);
-               drm->ttm.mem_global_ref.release = NULL;
-               return ret;
-       }
-
-       return 0;
-}
-
-void
-nouveau_ttm_global_release(struct nouveau_drm *drm)
-{
-       if (drm->ttm.mem_global_ref.release == NULL)
-               return;
-
-       drm_global_item_unref(&drm->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&drm->ttm.mem_global_ref);
-       drm->ttm.mem_global_ref.release = NULL;
-}
-
 static int
 nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)
 {
@@ -296,12 +236,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
                drm->agp.cma = pci->agp.cma;
        }
 
-       ret = nouveau_ttm_global_init(drm);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&drm->ttm.bdev,
-                                 drm->ttm.bo_global_ref.ref.object,
                                  &nouveau_bo_driver,
                                  dev->anon_inode->i_mapping,
                                  DRM_FILE_PAGE_OFFSET,
@@ -356,8 +291,6 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
 
        ttm_bo_device_release(&drm->ttm.bdev);
 
-       nouveau_ttm_global_release(drm);
-
        arch_phys_wc_del(drm->ttm.mtrr);
        drm->ttm.mtrr = 0;
        arch_io_free_memtype_wc(device->func->resource_addr(device, 1),
index 7e3b118cf7c4da6016874aac0c2f2d653db72398..ede872f6f66803873f11dc459c1ff7cea285e9ee 100644 (file)
@@ -25,7 +25,6 @@ void nouveau_vma_unmap(struct nouveau_vma *);
 struct nouveau_vmm {
        struct nouveau_cli *cli;
        struct nvif_vmm vmm;
-       struct nvkm_vm *vm;
 };
 
 int nouveau_vmm_init(struct nouveau_cli *, s32 oclass, struct nouveau_vmm *);
index 18c7d064f75c84397e20eba815ec9f97bc7010d9..ef97dd223a32f1e33091a01cc6793d6a6359a018 100644 (file)
@@ -34,6 +34,7 @@ int
 nvif_disp_ctor(struct nvif_device *device, s32 oclass, struct nvif_disp *disp)
 {
        static const struct nvif_mclass disps[] = {
+               { TU104_DISP, -1 },
                { GV100_DISP, -1 },
                { GP102_DISP, -1 },
                { GP100_DISP, -1 },
index 03f676c18aad5240e654739d6092a62ca5f74e4f..c61b467cf45e1c738dfc66670128d396f01fd4e3 100644 (file)
@@ -79,7 +79,9 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = {
        [NVKM_ENGINE_NVENC0  ] = "nvenc0",
        [NVKM_ENGINE_NVENC1  ] = "nvenc1",
        [NVKM_ENGINE_NVENC2  ] = "nvenc2",
-       [NVKM_ENGINE_NVDEC   ] = "nvdec",
+       [NVKM_ENGINE_NVDEC0  ] = "nvdec0",
+       [NVKM_ENGINE_NVDEC1  ] = "nvdec1",
+       [NVKM_ENGINE_NVDEC2  ] = "nvdec2",
        [NVKM_ENGINE_PM      ] = "pm",
        [NVKM_ENGINE_SEC     ] = "sec",
        [NVKM_ENGINE_SEC2    ] = "sec2",
index 80d7844419044da450528a442dc2a58eb8511c7b..177a23301d6ab46d99866db5f1241886e01c6fa5 100644 (file)
@@ -6,3 +6,4 @@ nvkm-y += nvkm/engine/ce/gm200.o
 nvkm-y += nvkm/engine/ce/gp100.o
 nvkm-y += nvkm/engine/ce/gp102.o
 nvkm-y += nvkm/engine/ce/gv100.o
+nvkm-y += nvkm/engine/ce/tu104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/tu104.c
new file mode 100644 (file)
index 0000000..3c25043
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+#include <nvif/class.h>
+
+static const struct nvkm_engine_func
+tu104_ce = {
+       .intr = gp100_ce_intr,
+       .sclass = {
+               { -1, -1, TURING_DMA_COPY_A },
+               {}
+       }
+};
+
+int
+tu104_ce_new(struct nvkm_device *device, int index,
+            struct nvkm_engine **pengine)
+{
+       return nvkm_engine_new_(&tu104_ce, device, index, true, pengine);
+}
index e294013426ced84844d6950facd1737f63f3205c..bfbc9341e0c21f361746ec81363a687119f97a92 100644 (file)
@@ -2221,7 +2221,7 @@ nv132_chipset = {
        .dma = gf119_dma_new,
        .fifo = gp100_fifo_new,
        .gr = gp102_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
        .sw = gf100_sw_new,
 };
@@ -2257,7 +2257,7 @@ nv134_chipset = {
        .dma = gf119_dma_new,
        .fifo = gp100_fifo_new,
        .gr = gp104_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
        .sw = gf100_sw_new,
 };
@@ -2293,7 +2293,7 @@ nv136_chipset = {
        .dma = gf119_dma_new,
        .fifo = gp100_fifo_new,
        .gr = gp104_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
        .sw = gf100_sw_new,
 };
@@ -2329,7 +2329,7 @@ nv137_chipset = {
        .dma = gf119_dma_new,
        .fifo = gp100_fifo_new,
        .gr = gp107_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
        .sw = gf100_sw_new,
 };
@@ -2365,7 +2365,7 @@ nv138_chipset = {
        .dma = gf119_dma_new,
        .fifo = gp100_fifo_new,
        .gr = gp107_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
        .sw = gf100_sw_new,
 };
@@ -2430,10 +2430,74 @@ nv140_chipset = {
        .dma = gv100_dma_new,
        .fifo = gv100_fifo_new,
        .gr = gv100_gr_new,
-       .nvdec = gp102_nvdec_new,
+       .nvdec[0] = gp102_nvdec_new,
        .sec2 = gp102_sec2_new,
 };
 
+static const struct nvkm_device_chip
+nv164_chipset = {
+       .name = "TU104",
+       .bar = tu104_bar_new,
+       .bios = nvkm_bios_new,
+       .bus = gf100_bus_new,
+       .devinit = tu104_devinit_new,
+       .fault = tu104_fault_new,
+       .fb = gv100_fb_new,
+       .fuse = gm107_fuse_new,
+       .gpio = gk104_gpio_new,
+       .i2c = gm200_i2c_new,
+       .ibus = gm200_ibus_new,
+       .imem = nv50_instmem_new,
+       .ltc = gp102_ltc_new,
+       .mc = tu104_mc_new,
+       .mmu = tu104_mmu_new,
+       .pci = gp100_pci_new,
+       .pmu = gp102_pmu_new,
+       .therm = gp100_therm_new,
+       .timer = gk20a_timer_new,
+       .top = gk104_top_new,
+       .ce[0] = tu104_ce_new,
+       .ce[1] = tu104_ce_new,
+       .ce[2] = tu104_ce_new,
+       .ce[3] = tu104_ce_new,
+       .ce[4] = tu104_ce_new,
+       .disp = tu104_disp_new,
+       .dma = gv100_dma_new,
+       .fifo = tu104_fifo_new,
+};
+
+static const struct nvkm_device_chip
+nv166_chipset = {
+       .name = "TU106",
+       .bar = tu104_bar_new,
+       .bios = nvkm_bios_new,
+       .bus = gf100_bus_new,
+       .devinit = tu104_devinit_new,
+       .fault = tu104_fault_new,
+       .fb = gv100_fb_new,
+       .fuse = gm107_fuse_new,
+       .gpio = gk104_gpio_new,
+       .i2c = gm200_i2c_new,
+       .ibus = gm200_ibus_new,
+       .imem = nv50_instmem_new,
+       .ltc = gp102_ltc_new,
+       .mc = tu104_mc_new,
+       .mmu = tu104_mmu_new,
+       .pci = gp100_pci_new,
+       .pmu = gp102_pmu_new,
+       .therm = gp100_therm_new,
+       .timer = gk20a_timer_new,
+       .top = gk104_top_new,
+       .ce[0] = tu104_ce_new,
+       .ce[1] = tu104_ce_new,
+       .ce[2] = tu104_ce_new,
+       .ce[3] = tu104_ce_new,
+       .ce[4] = tu104_ce_new,
+       .disp = tu104_disp_new,
+       .dma = gv100_dma_new,
+       .fifo = tu104_fifo_new,
+};
+
 static int
 nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
                       struct nvkm_notify *notify)
@@ -2529,7 +2593,9 @@ nvkm_device_engine(struct nvkm_device *device, int index)
        _(NVENC0 , device->nvenc[0],  device->nvenc[0]);
        _(NVENC1 , device->nvenc[1],  device->nvenc[1]);
        _(NVENC2 , device->nvenc[2],  device->nvenc[2]);
-       _(NVDEC  , device->nvdec   , &device->nvdec->engine);
+       _(NVDEC0 , device->nvdec[0], &device->nvdec[0]->engine);
+       _(NVDEC1 , device->nvdec[1], &device->nvdec[1]->engine);
+       _(NVDEC2 , device->nvdec[2], &device->nvdec[2]->engine);
        _(PM     , device->pm      , &device->pm->engine);
        _(SEC    , device->sec     ,  device->sec);
        _(SEC2   , device->sec2    , &device->sec2->engine);
@@ -2791,6 +2857,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                        case 0x120: device->card_type = GM100; break;
                        case 0x130: device->card_type = GP100; break;
                        case 0x140: device->card_type = GV100; break;
+                       case 0x160: device->card_type = TU100; break;
                        default:
                                break;
                        }
@@ -2883,6 +2950,8 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x138: device->chip = &nv138_chipset; break;
                case 0x13b: device->chip = &nv13b_chipset; break;
                case 0x140: device->chip = &nv140_chipset; break;
+               case 0x164: device->chip = &nv164_chipset; break;
+               case 0x166: device->chip = &nv166_chipset; break;
                default:
                        nvdev_error(device, "unknown chipset (%08x)\n", boot0);
                        goto done;
@@ -2988,7 +3057,9 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                _(NVKM_ENGINE_NVENC0  , nvenc[0]);
                _(NVKM_ENGINE_NVENC1  , nvenc[1]);
                _(NVKM_ENGINE_NVENC2  , nvenc[2]);
-               _(NVKM_ENGINE_NVDEC   ,    nvdec);
+               _(NVKM_ENGINE_NVDEC0  , nvdec[0]);
+               _(NVKM_ENGINE_NVDEC1  , nvdec[1]);
+               _(NVKM_ENGINE_NVDEC2  , nvdec[2]);
                _(NVKM_ENGINE_PM      ,       pm);
                _(NVKM_ENGINE_SEC     ,      sec);
                _(NVKM_ENGINE_SEC2    ,     sec2);
index dde6bbafa709f781e776434c374664dff037c9a6..092ddc4ffefac09c51b1ec705ff36f746434040d 100644 (file)
@@ -91,7 +91,7 @@ nvkm_udevice_info_v1(struct nvkm_device *device,
        case ENGINE_A(MSENC ); break;
        case ENGINE_A(VIC   ); break;
        case ENGINE_A(SEC2  ); break;
-       case ENGINE_A(NVDEC ); break;
+       case ENGINE_B(NVDEC ); break;
        case ENGINE_B(NVENC ); break;
        default:
                args->mthd = NV_DEVICE_INFO_INVALID;
@@ -175,6 +175,7 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
        case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
        case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break;
        case GV100: args->v0.family = NV_DEVICE_INFO_V0_VOLTA; break;
+       case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
        default:
                args->v0.family = 0;
                break;
index 8089ac9a12e2673b252b6377eef4f30afc934dce..c6a257ba43476dec8f43d3d431f765a792ed6abc 100644 (file)
@@ -15,6 +15,7 @@ nvkm-y += nvkm/engine/disp/gm200.o
 nvkm-y += nvkm/engine/disp/gp100.o
 nvkm-y += nvkm/engine/disp/gp102.o
 nvkm-y += nvkm/engine/disp/gv100.o
+nvkm-y += nvkm/engine/disp/tu104.o
 nvkm-y += nvkm/engine/disp/vga.o
 
 nvkm-y += nvkm/engine/disp/head.o
@@ -38,6 +39,7 @@ nvkm-y += nvkm/engine/disp/sorgk104.o
 nvkm-y += nvkm/engine/disp/sorgm107.o
 nvkm-y += nvkm/engine/disp/sorgm200.o
 nvkm-y += nvkm/engine/disp/sorgv100.o
+nvkm-y += nvkm/engine/disp/sortu104.o
 
 nvkm-y += nvkm/engine/disp/outp.o
 nvkm-y += nvkm/engine/disp/dp.o
@@ -69,6 +71,7 @@ nvkm-y += nvkm/engine/disp/rootgm200.o
 nvkm-y += nvkm/engine/disp/rootgp100.o
 nvkm-y += nvkm/engine/disp/rootgp102.o
 nvkm-y += nvkm/engine/disp/rootgv100.o
+nvkm-y += nvkm/engine/disp/roottu104.o
 
 nvkm-y += nvkm/engine/disp/channv50.o
 nvkm-y += nvkm/engine/disp/changf119.o
index d0a7e3456da1661029b48600f90562be1dac6faf..47be0ba4aebe2df17f6412160c10cdad417e1447 100644 (file)
@@ -28,7 +28,7 @@
 #include <core/gpuobj.h>
 #include <subdev/timer.h>
 
-static int
+int
 gv100_disp_wndw_cnt(struct nvkm_disp *disp, unsigned long *pmask)
 {
        struct nvkm_device *device = disp->engine.subdev.device;
@@ -36,7 +36,7 @@ gv100_disp_wndw_cnt(struct nvkm_disp *disp, unsigned long *pmask)
        return (nvkm_rd32(device, 0x610074) & 0x03f00000) >> 20;
 }
 
-static void
+void
 gv100_disp_super(struct work_struct *work)
 {
        struct nv50_disp *disp =
@@ -257,7 +257,7 @@ gv100_disp_intr_head_timing(struct nv50_disp *disp, int head)
        }
 }
 
-static void
+void
 gv100_disp_intr(struct nv50_disp *disp)
 {
        struct nvkm_subdev *subdev = &disp->base.engine.subdev;
@@ -297,7 +297,7 @@ gv100_disp_intr(struct nv50_disp *disp)
                nvkm_warn(subdev, "intr %08x\n", stat);
 }
 
-static void
+void
 gv100_disp_fini(struct nv50_disp *disp)
 {
        struct nvkm_device *device = disp->base.engine.subdev.device;
index 0f0c86c32ec3affd8472948a7232cc17647dd028..790e42f460fdc78a2e83cc249cf373b84ee72bd3 100644 (file)
@@ -144,6 +144,11 @@ void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *);
 int gm200_sor_route_get(struct nvkm_outp *, int *);
 void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);
 
+void gv100_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
+void gv100_sor_dp_audio(struct nvkm_ior *, int, bool);
+void gv100_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
+void gv100_sor_dp_watermark(struct nvkm_ior *, int, u8);
+
 void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
 void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
 void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
@@ -195,4 +200,6 @@ int gm200_sor_new(struct nvkm_disp *, int);
 
 int gv100_sor_cnt(struct nvkm_disp *, unsigned long *);
 int gv100_sor_new(struct nvkm_disp *, int);
+
+int tu104_sor_new(struct nvkm_disp *, int);
 #endif
index 8580382ab248949ebf8e21dd28cada7b34055a17..c36a8a7cafa16184585330ddfb7b89c490b4f4dc 100644 (file)
@@ -78,6 +78,11 @@ void gf119_disp_intr(struct nv50_disp *);
 void gf119_disp_super(struct work_struct *);
 void gf119_disp_intr_error(struct nv50_disp *, int);
 
+void gv100_disp_fini(struct nv50_disp *);
+void gv100_disp_intr(struct nv50_disp *);
+void gv100_disp_super(struct work_struct *);
+int gv100_disp_wndw_cnt(struct nvkm_disp *, unsigned long *);
+
 void nv50_disp_dptmds_war_2(struct nv50_disp *, struct dcb_output *);
 void nv50_disp_dptmds_war_3(struct nv50_disp *, struct dcb_output *);
 void nv50_disp_update_sppll1(struct nv50_disp *);
index 6ca4f9184b51528b15875b8f8f05fa59435aef59..97de928cbde131b4a4a7176361f24fd964006f8c 100644 (file)
@@ -37,4 +37,5 @@ extern const struct nvkm_disp_oclass gm200_disp_root_oclass;
 extern const struct nvkm_disp_oclass gp100_disp_root_oclass;
 extern const struct nvkm_disp_oclass gp102_disp_root_oclass;
 extern const struct nvkm_disp_oclass gv100_disp_root_oclass;
+extern const struct nvkm_disp_oclass tu104_disp_root_oclass;
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/roottu104.c
new file mode 100644 (file)
index 0000000..ad438c6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "rootnv50.h"
+#include "channv50.h"
+
+#include <nvif/class.h>
+
+static const struct nv50_disp_root_func
+tu104_disp_root = {
+       .user = {
+               {{0,0,TU104_DISP_CURSOR                }, gv100_disp_curs_new },
+               {{0,0,TU104_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
+               {{0,0,TU104_DISP_CORE_CHANNEL_DMA      }, gv100_disp_core_new },
+               {{0,0,TU104_DISP_WINDOW_CHANNEL_DMA    }, gv100_disp_wndw_new },
+               {}
+       },
+};
+
+static int
+tu104_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
+                   void *data, u32 size, struct nvkm_object **pobject)
+{
+       return nv50_disp_root_new_(&tu104_disp_root, disp, oclass,
+                                  data, size, pobject);
+}
+
+const struct nvkm_disp_oclass
+tu104_disp_root_oclass = {
+       .base.oclass = TU104_DISP,
+       .base.minver = -1,
+       .base.maxver = -1,
+       .ctor = tu104_disp_root_new,
+};
index 8ba881a729eecd6c89dda224313615bab3f17e1f..b0597ff9a7149fb256fa259caf50a78d2c5f89cd 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <subdev/timer.h>
 
-static void
+void
 gv100_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
 {
        struct nvkm_device *device = sor->disp->engine.subdev.device;
@@ -31,7 +31,7 @@ gv100_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
        nvkm_mask(device, 0x616550 + hoff, 0x0c00003f, 0x08000000 | watermark);
 }
 
-static void
+void
 gv100_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
 {
        struct nvkm_device *device = sor->disp->engine.subdev.device;
@@ -40,7 +40,7 @@ gv100_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
        nvkm_mask(device, 0x61656c + hoff, 0x00ffffff, v);
 }
 
-static void
+void
 gv100_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
 {
        struct nvkm_device *device = sor->disp->engine.subdev.device;
@@ -54,7 +54,7 @@ gv100_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
        );
 }
 
-static void
+void
 gv100_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
 {
        struct nvkm_device *device = sor->disp->engine.subdev.device;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sortu104.c
new file mode 100644 (file)
index 0000000..df026a5
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ior.h"
+
+#include <subdev/timer.h>
+
+static void
+tu104_sor_dp_vcpi(struct nvkm_ior *sor, int head,
+                 u8 slot, u8 slot_nr, u16 pbn, u16 aligned)
+{
+       struct nvkm_device *device = sor->disp->engine.subdev.device;
+       const u32 hoff = head * 0x800;
+
+       nvkm_mask(device, 0x61657c + hoff, 0xffffffff, (aligned << 16) | pbn);
+       nvkm_mask(device, 0x616578 + hoff, 0x00003f3f, (slot_nr << 8) | slot);
+}
+
+static int
+tu104_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
+{
+       struct nvkm_device *device = sor->disp->engine.subdev.device;
+       const u32 soff = nv50_ior_base(sor);
+       const u32 loff = nv50_sor_link(sor);
+       u32 dpctrl = 0x00000000;
+       u32 clksor = 0x00000000;
+
+       clksor |= sor->dp.bw << 18;
+       dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
+       if (sor->dp.mst)
+               dpctrl |= 0x40000000;
+       if (sor->dp.ef)
+               dpctrl |= 0x00004000;
+
+       nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
+
+       /*XXX*/
+       nvkm_msec(device, 40, NVKM_DELAY);
+       nvkm_mask(device, 0x612300 + soff, 0x00030000, 0x00010000);
+       nvkm_mask(device, 0x61c10c + loff, 0x00000003, 0x00000001);
+
+       nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl);
+       return 0;
+}
+
+static const struct nvkm_ior_func
+tu104_sor = {
+       .route = {
+               .get = gm200_sor_route_get,
+               .set = gm200_sor_route_set,
+       },
+       .state = gv100_sor_state,
+       .power = nv50_sor_power,
+       .clock = gf119_sor_clock,
+       .hdmi = {
+               .ctrl = gv100_hdmi_ctrl,
+       },
+       .dp = {
+               .lanes = { 0, 1, 2, 3 },
+               .links = tu104_sor_dp_links,
+               .power = g94_sor_dp_power,
+               .pattern = gm107_sor_dp_pattern,
+               .drive = gm200_sor_dp_drive,
+               .vcpi = tu104_sor_dp_vcpi,
+               .audio = gv100_sor_dp_audio,
+               .audio_sym = gv100_sor_dp_audio_sym,
+               .watermark = gv100_sor_dp_watermark,
+       },
+       .hda = {
+               .hpd = gf119_hda_hpd,
+               .eld = gf119_hda_eld,
+       },
+};
+
+int
+tu104_sor_new(struct nvkm_disp *disp, int id)
+{
+       return nvkm_ior_new_(&tu104_sor, disp, SOR, id);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu104.c
new file mode 100644 (file)
index 0000000..13fa214
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nv50.h"
+#include "head.h"
+#include "ior.h"
+#include "channv50.h"
+#include "rootnv50.h"
+
+#include <core/gpuobj.h>
+#include <subdev/timer.h>
+
+static int
+tu104_disp_init(struct nv50_disp *disp)
+{
+       struct nvkm_device *device = disp->base.engine.subdev.device;
+       struct nvkm_head *head;
+       int i, j;
+       u32 tmp;
+
+       /* Claim ownership of display. */
+       if (nvkm_rd32(device, 0x6254e8) & 0x00000002) {
+               nvkm_mask(device, 0x6254e8, 0x00000001, 0x00000000);
+               if (nvkm_msec(device, 2000,
+                       if (!(nvkm_rd32(device, 0x6254e8) & 0x00000002))
+                               break;
+               ) < 0)
+                       return -EBUSY;
+       }
+
+       /* Lock pin capabilities. */
+       tmp = 0x00000021; /*XXX*/
+       nvkm_wr32(device, 0x640008, tmp);
+
+       /* SOR capabilities. */
+       for (i = 0; i < disp->sor.nr; i++) {
+               tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
+               nvkm_mask(device, 0x640000, 0x00000100 << i, 0x00000100 << i);
+               nvkm_wr32(device, 0x640144 + (i * 0x08), tmp);
+       }
+
+       /* Head capabilities. */
+       list_for_each_entry(head, &disp->base.head, head) {
+               const int id = head->id;
+
+               /* RG. */
+               tmp = nvkm_rd32(device, 0x616300 + (id * 0x800));
+               nvkm_wr32(device, 0x640048 + (id * 0x020), tmp);
+
+               /* POSTCOMP. */
+               for (j = 0; j < 5 * 4; j += 4) {
+                       tmp = nvkm_rd32(device, 0x616140 + (id * 0x800) + j);
+                       nvkm_wr32(device, 0x640680 + (id * 0x20) + j, tmp);
+               }
+       }
+
+       /* Window capabilities. */
+       for (i = 0; i < disp->wndw.nr; i++) {
+               nvkm_mask(device, 0x640004, 1 << i, 1 << i);
+               for (j = 0; j < 6 * 4; j += 4) {
+                       tmp = nvkm_rd32(device, 0x630100 + (i * 0x800) + j);
+                       nvkm_mask(device, 0x640780 + (i * 0x20) + j, 0xffffffff, tmp);
+               }
+               nvkm_mask(device, 0x64000c, 0x00000100, 0x00000100);
+       }
+
+       /* IHUB capabilities. */
+       for (i = 0; i < 3; i++) {
+               tmp = nvkm_rd32(device, 0x62e000 + (i * 0x04));
+               nvkm_wr32(device, 0x640010 + (i * 0x04), tmp);
+       }
+
+       nvkm_mask(device, 0x610078, 0x00000001, 0x00000001);
+
+       /* Setup instance memory. */
+       switch (nvkm_memory_target(disp->inst->memory)) {
+       case NVKM_MEM_TARGET_VRAM: tmp = 0x00000001; break;
+       case NVKM_MEM_TARGET_NCOH: tmp = 0x00000002; break;
+       case NVKM_MEM_TARGET_HOST: tmp = 0x00000003; break;
+       default:
+               break;
+       }
+       nvkm_wr32(device, 0x610010, 0x00000008 | tmp);
+       nvkm_wr32(device, 0x610014, disp->inst->addr >> 16);
+
+       /* CTRL_DISP: AWAKEN, ERROR, SUPERVISOR[1-3]. */
+       nvkm_wr32(device, 0x611cf0, 0x00000187); /* MSK. */
+       nvkm_wr32(device, 0x611db0, 0x00000187); /* EN. */
+
+       /* EXC_OTHER: CURSn, CORE. */
+       nvkm_wr32(device, 0x611cec, disp->head.mask << 16 |
+                                   0x00000001); /* MSK. */
+       nvkm_wr32(device, 0x611dac, 0x00000000); /* EN. */
+
+       /* EXC_WINIM. */
+       nvkm_wr32(device, 0x611ce8, disp->wndw.mask); /* MSK. */
+       nvkm_wr32(device, 0x611da8, 0x00000000); /* EN. */
+
+       /* EXC_WIN. */
+       nvkm_wr32(device, 0x611ce4, disp->wndw.mask); /* MSK. */
+       nvkm_wr32(device, 0x611da4, 0x00000000); /* EN. */
+
+       /* HEAD_TIMING(n): VBLANK. */
+       list_for_each_entry(head, &disp->base.head, head) {
+               const u32 hoff = head->id * 4;
+               nvkm_wr32(device, 0x611cc0 + hoff, 0x00000004); /* MSK. */
+               nvkm_wr32(device, 0x611d80 + hoff, 0x00000000); /* EN. */
+       }
+
+       /* OR. */
+       nvkm_wr32(device, 0x611cf4, 0x00000000); /* MSK. */
+       nvkm_wr32(device, 0x611db4, 0x00000000); /* EN. */
+       return 0;
+}
+
+static const struct nv50_disp_func
+tu104_disp = {
+       .init = tu104_disp_init,
+       .fini = gv100_disp_fini,
+       .intr = gv100_disp_intr,
+       .uevent = &gv100_disp_chan_uevent,
+       .super = gv100_disp_super,
+       .root = &tu104_disp_root_oclass,
+       .wndw = { .cnt = gv100_disp_wndw_cnt },
+       .head = { .cnt = gv100_head_cnt, .new = gv100_head_new },
+       .sor = { .cnt = gv100_sor_cnt, .new = tu104_sor_new },
+       .ramht_size = 0x2000,
+};
+
+int
+tu104_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
+{
+       return nv50_disp_new_(&tu104_disp, device, index, pdisp);
+}
index 98911805aabf6375852f9bd00df89433fce2387f..5d3b641dbb141decd8f187f038ad99d0737e8413 100644 (file)
@@ -118,7 +118,7 @@ gv100_disp_wndw_mthd_base = {
 
 const struct nv50_disp_chan_mthd
 gv100_disp_wndw_mthd = {
-       .name = "Base",
+       .name = "Window",
        .addr = 0x001000,
        .prev = 0x000800,
        .data = {
index f00408577a6afaac015bb13b2a3c16d6241680f1..87d8e054e40ae4d8ff3ab30d870363b0e28afbeb 100644 (file)
@@ -16,6 +16,7 @@ nvkm-y += nvkm/engine/fifo/gm20b.o
 nvkm-y += nvkm/engine/fifo/gp100.o
 nvkm-y += nvkm/engine/fifo/gp10b.o
 nvkm-y += nvkm/engine/fifo/gv100.o
+nvkm-y += nvkm/engine/fifo/tu104.o
 
 nvkm-y += nvkm/engine/fifo/chan.o
 nvkm-y += nvkm/engine/fifo/channv50.o
@@ -33,5 +34,7 @@ nvkm-y += nvkm/engine/fifo/gpfifog84.o
 nvkm-y += nvkm/engine/fifo/gpfifogf100.o
 nvkm-y += nvkm/engine/fifo/gpfifogk104.o
 nvkm-y += nvkm/engine/fifo/gpfifogv100.o
+nvkm-y += nvkm/engine/fifo/gpfifotu104.o
 
 nvkm-y += nvkm/engine/fifo/usergv100.o
+nvkm-y += nvkm/engine/fifo/usertu104.o
index 3ffef236189e6e1781af17a34cae7692ec2f4a1d..2c7c5afc1ea5675ab4dcf44d73400393e71a3f29 100644 (file)
@@ -17,6 +17,7 @@ struct nvkm_fifo_chan_func {
                            bool suspend);
        int  (*object_ctor)(struct nvkm_fifo_chan *, struct nvkm_object *);
        void (*object_dtor)(struct nvkm_fifo_chan *, int);
+       u32 (*submit_token)(struct nvkm_fifo_chan *);
 };
 
 int nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *, struct nvkm_fifo *,
index 8e28ba6b23074bdfb6cf790b9c18d7adf31996b3..a14545d871d8efc2c3d352d567ef618d3c3ff8b5 100644 (file)
@@ -14,6 +14,8 @@ struct gk104_fifo_chan {
        struct list_head head;
        bool killed;
 
+       struct nvkm_memory *mthd;
+
        struct {
                struct nvkm_gpuobj *inst;
                struct nvkm_vma *vma;
@@ -36,4 +38,15 @@ int gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *);
 
 int gv100_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
                          void *data, u32 size, struct nvkm_object **);
+int gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *,
+                          struct gk104_fifo *, u64 *, u16 *, u64, u64, u64,
+                          u64 *, bool, u32 *, const struct nvkm_oclass *,
+                          struct nvkm_object **);
+int gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *,
+                                 struct nvkm_engine *);
+int gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *,
+                                 struct nvkm_engine *, bool);
+
+int tu104_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
+                         void *data, u32 size, struct nvkm_object **);
 #endif
index f6957686816433adbddee81f7e8c37fa694ee374..10a2e7039a7522a51b1d05326e8fe93db61bb1e5 100644 (file)
@@ -346,10 +346,10 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit)
        if (eu && eu->data2) {
                switch (eu->data2) {
                case NVKM_SUBDEV_BAR:
-                       nvkm_mask(device, 0x001704, 0x00000000, 0x00000000);
+                       nvkm_bar_bar1_reset(device);
                        break;
                case NVKM_SUBDEV_INSTMEM:
-                       nvkm_mask(device, 0x001714, 0x00000000, 0x00000000);
+                       nvkm_bar_bar2_reset(device);
                        break;
                case NVKM_ENGINE_IFB:
                        nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
index afccf9721cf0af3c7759cba6d406ac37c6c96d33..1053fe7964661ce809b4ab78e87ec04049d9180f 100644 (file)
@@ -149,16 +149,41 @@ gk104_fifo_uevent_init(struct nvkm_fifo *fifo)
 }
 
 void
-gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl)
+gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
+                         struct nvkm_memory *mem, int nr)
+{
+       struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+       int target;
+
+       switch (nvkm_memory_target(mem)) {
+       case NVKM_MEM_TARGET_VRAM: target = 0; break;
+       case NVKM_MEM_TARGET_NCOH: target = 3; break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+
+       nvkm_wr32(device, 0x002270, (nvkm_memory_addr(mem) >> 12) |
+                                   (target << 28));
+       nvkm_wr32(device, 0x002274, (runl << 20) | nr);
+
+       if (nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000))
+                       break;
+       ) < 0)
+               nvkm_error(subdev, "runlist %d update timeout\n", runl);
+}
+
+void
+gk104_fifo_runlist_update(struct gk104_fifo *fifo, int runl)
 {
        const struct gk104_fifo_runlist_func *func = fifo->func->runlist;
        struct gk104_fifo_chan *chan;
        struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
-       struct nvkm_device *device = subdev->device;
        struct nvkm_memory *mem;
        struct nvkm_fifo_cgrp *cgrp;
        int nr = 0;
-       int target;
 
        mutex_lock(&subdev->mutex);
        mem = fifo->runlist[runl].mem[fifo->runlist[runl].next];
@@ -177,24 +202,7 @@ gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl)
        }
        nvkm_done(mem);
 
-       switch (nvkm_memory_target(mem)) {
-       case NVKM_MEM_TARGET_VRAM: target = 0; break;
-       case NVKM_MEM_TARGET_NCOH: target = 3; break;
-       default:
-               WARN_ON(1);
-               goto unlock;
-       }
-
-       nvkm_wr32(device, 0x002270, (nvkm_memory_addr(mem) >> 12) |
-                                   (target << 28));
-       nvkm_wr32(device, 0x002274, (runl << 20) | nr);
-
-       if (nvkm_msec(device, 2000,
-               if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000))
-                       break;
-       ) < 0)
-               nvkm_error(subdev, "runlist %d update timeout\n", runl);
-unlock:
+       func->commit(fifo, runl, mem, nr);
        mutex_unlock(&subdev->mutex);
 }
 
@@ -238,6 +246,29 @@ const struct gk104_fifo_runlist_func
 gk104_fifo_runlist = {
        .size = 8,
        .chan = gk104_fifo_runlist_chan,
+       .commit = gk104_fifo_runlist_commit,
+};
+
+void
+gk104_fifo_pbdma_init(struct gk104_fifo *fifo)
+{
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
+       nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1);
+}
+
+int
+gk104_fifo_pbdma_nr(struct gk104_fifo *fifo)
+{
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
+       /* Determine number of PBDMAs by checking valid enable bits. */
+       nvkm_wr32(device, 0x000204, 0xffffffff);
+       return hweight32(nvkm_rd32(device, 0x000204));
+}
+
+const struct gk104_fifo_pbdma_func
+gk104_fifo_pbdma = {
+       .nr = gk104_fifo_pbdma_nr,
+       .init = gk104_fifo_pbdma_init,
 };
 
 static void
@@ -267,7 +298,7 @@ gk104_fifo_recover_work(struct work_struct *w)
        }
 
        for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl))
-               gk104_fifo_runlist_commit(fifo, runl);
+               gk104_fifo_runlist_update(fifo, runl);
 
        nvkm_wr32(device, 0x00262c, runm);
        nvkm_mask(device, 0x002630, runm, 0x00000000);
@@ -456,10 +487,10 @@ gk104_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
        if (ee && ee->data2) {
                switch (ee->data2) {
                case NVKM_SUBDEV_BAR:
-                       nvkm_mask(device, 0x001704, 0x00000000, 0x00000000);
+                       nvkm_bar_bar1_reset(device);
                        break;
                case NVKM_SUBDEV_INSTMEM:
-                       nvkm_mask(device, 0x001714, 0x00000000, 0x00000000);
+                       nvkm_bar_bar2_reset(device);
                        break;
                case NVKM_ENGINE_IFB:
                        nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
@@ -904,9 +935,7 @@ gk104_fifo_oneinit(struct nvkm_fifo *base)
        enum nvkm_devidx engidx;
        u32 *map;
 
-       /* Determine number of PBDMAs by checking valid enable bits. */
-       nvkm_wr32(device, 0x000204, 0xffffffff);
-       fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x000204));
+       fifo->pbdma_nr = fifo->func->pbdma->nr(fifo);
        nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr);
 
        /* Read PBDMA->runlist(s) mapping from HW. */
@@ -978,7 +1007,7 @@ gk104_fifo_init(struct nvkm_fifo *base)
        int i;
 
        /* Enable PBDMAs. */
-       nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1);
+       fifo->func->pbdma->init(fifo);
 
        /* PBDMA[n] */
        for (i = 0; i < fifo->pbdma_nr; i++) {
@@ -995,8 +1024,8 @@ gk104_fifo_init(struct nvkm_fifo *base)
 
        nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar->addr >> 12);
 
-       if (fifo->func->init_pbdma_timeout)
-               fifo->func->init_pbdma_timeout(fifo);
+       if (fifo->func->pbdma->init_timeout)
+               fifo->func->pbdma->init_timeout(fifo);
 
        nvkm_wr32(device, 0x002100, 0xffffffff);
        nvkm_wr32(device, 0x002140, 0x7fffffff);
@@ -1175,6 +1204,7 @@ gk104_fifo_fault_gpcclient[] = {
 
 static const struct gk104_fifo_func
 gk104_fifo = {
+       .pbdma = &gk104_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gk104_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index d295b81e18d6c398ed115fd286ee253fd25ca634..d4e565658f46af8ae2bd502b6347e0ba8358cd45 100644 (file)
@@ -45,7 +45,11 @@ struct gk104_fifo {
 };
 
 struct gk104_fifo_func {
-       void (*init_pbdma_timeout)(struct gk104_fifo *);
+       const struct gk104_fifo_pbdma_func {
+               int (*nr)(struct gk104_fifo *);
+               void (*init)(struct gk104_fifo *);
+               void (*init_timeout)(struct gk104_fifo *);
+       } *pbdma;
 
        struct {
                const struct nvkm_enum *access;
@@ -61,6 +65,8 @@ struct gk104_fifo_func {
                             struct nvkm_memory *, u32 offset);
                void (*chan)(struct gk104_fifo_chan *,
                             struct nvkm_memory *, u32 offset);
+               void (*commit)(struct gk104_fifo *, int runl,
+                              struct nvkm_memory *, int entries);
        } *runlist;
 
        struct gk104_fifo_user_user {
@@ -81,8 +87,11 @@ int gk104_fifo_new_(const struct gk104_fifo_func *, struct nvkm_device *,
                    int index, int nr, struct nvkm_fifo **);
 void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *);
 void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *);
-void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl);
+void gk104_fifo_runlist_update(struct gk104_fifo *, int runl);
 
+extern const struct gk104_fifo_pbdma_func gk104_fifo_pbdma;
+int gk104_fifo_pbdma_nr(struct gk104_fifo *);
+void gk104_fifo_pbdma_init(struct gk104_fifo *);
 extern const struct nvkm_enum gk104_fifo_fault_access[];
 extern const struct nvkm_enum gk104_fifo_fault_engine[];
 extern const struct nvkm_enum gk104_fifo_fault_reason[];
@@ -91,15 +100,30 @@ extern const struct nvkm_enum gk104_fifo_fault_gpcclient[];
 extern const struct gk104_fifo_runlist_func gk104_fifo_runlist;
 void gk104_fifo_runlist_chan(struct gk104_fifo_chan *,
                             struct nvkm_memory *, u32);
+void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl,
+                              struct nvkm_memory *, int);
 
 extern const struct gk104_fifo_runlist_func gk110_fifo_runlist;
 void gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
                             struct nvkm_memory *, u32);
 
-void gk208_fifo_init_pbdma_timeout(struct gk104_fifo *);
+extern const struct gk104_fifo_pbdma_func gk208_fifo_pbdma;
+void gk208_fifo_pbdma_init_timeout(struct gk104_fifo *);
 
 extern const struct nvkm_enum gm107_fifo_fault_engine[];
 extern const struct gk104_fifo_runlist_func gm107_fifo_runlist;
 
+extern const struct gk104_fifo_pbdma_func gm200_fifo_pbdma;
+int gm200_fifo_pbdma_nr(struct gk104_fifo *);
+
 extern const struct nvkm_enum gp100_fifo_fault_engine[];
+
+extern const struct nvkm_enum gv100_fifo_fault_access[];
+extern const struct nvkm_enum gv100_fifo_fault_reason[];
+extern const struct nvkm_enum gv100_fifo_fault_hubclient[];
+extern const struct nvkm_enum gv100_fifo_fault_gpcclient[];
+void gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
+                            struct nvkm_memory *, u32);
+void gv100_fifo_runlist_chan(struct gk104_fifo_chan *,
+                            struct nvkm_memory *, u32);
 #endif
index ac7655a130fbdf0c78857c54593fb969db166068..8adfa6b182cbab9b703bee09a9bdb89014fa7656 100644 (file)
@@ -43,10 +43,12 @@ gk110_fifo_runlist = {
        .size = 8,
        .cgrp = gk110_fifo_runlist_cgrp,
        .chan = gk104_fifo_runlist_chan,
+       .commit = gk104_fifo_runlist_commit,
 };
 
 static const struct gk104_fifo_func
 gk110_fifo = {
+       .pbdma = &gk104_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gk104_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 5ea7e452cc660d4f2120be5194ad2d9be2848891..9553fb4af601f033e37b6bdc8878bf9fa6e9f727 100644 (file)
@@ -27,7 +27,7 @@
 #include <nvif/class.h>
 
 void
-gk208_fifo_init_pbdma_timeout(struct gk104_fifo *fifo)
+gk208_fifo_pbdma_init_timeout(struct gk104_fifo *fifo)
 {
        struct nvkm_device *device = fifo->base.engine.subdev.device;
        int i;
@@ -36,9 +36,16 @@ gk208_fifo_init_pbdma_timeout(struct gk104_fifo *fifo)
                nvkm_wr32(device, 0x04012c + (i * 0x2000), 0x0000ffff);
 }
 
+const struct gk104_fifo_pbdma_func
+gk208_fifo_pbdma = {
+       .nr = gk104_fifo_pbdma_nr,
+       .init = gk104_fifo_pbdma_init,
+       .init_timeout = gk208_fifo_pbdma_init_timeout,
+};
+
 static const struct gk104_fifo_func
 gk208_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gk208_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gk104_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 535a0eb67a5fc83eda731e5fc60ca0853ba41206..a4c6ac3cd6c70a1e8d5cef24e01ea33f5c30b871 100644 (file)
@@ -26,7 +26,7 @@
 
 static const struct gk104_fifo_func
 gk20a_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gk208_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gk104_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 79ae19b1db673c6b0f95b1f6115166597c549e84..acf230764cb0bb966e915d6826e8ddeb4561f2e0 100644 (file)
@@ -41,6 +41,7 @@ gm107_fifo_runlist = {
        .size = 8,
        .cgrp = gk110_fifo_runlist_cgrp,
        .chan = gm107_fifo_runlist_chan,
+       .commit = gk104_fifo_runlist_commit,
 };
 
 const struct nvkm_enum
@@ -68,7 +69,7 @@ gm107_fifo_fault_engine[] = {
 
 static const struct gk104_fifo_func
 gm107_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gk208_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gm107_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 49565faa854d06c72aff1259d182e1c7105004c1..b96c1c5d6577f0a12a1494077fef43d76ba23cfe 100644 (file)
 
 #include <nvif/class.h>
 
+int
+gm200_fifo_pbdma_nr(struct gk104_fifo *fifo)
+{
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
+       return nvkm_rd32(device, 0x002004) & 0x000000ff;
+}
+
+const struct gk104_fifo_pbdma_func
+gm200_fifo_pbdma = {
+       .nr = gm200_fifo_pbdma_nr,
+       .init = gk104_fifo_pbdma_init,
+       .init_timeout = gk208_fifo_pbdma_init_timeout,
+};
+
 static const struct gk104_fifo_func
 gm200_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gm200_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gm107_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 46736513bd11a5bbd228f41efd8ee93e9ce86f2f..a49539b9e4ec328f24d7d3b1e4aa798b19ae92c2 100644 (file)
@@ -26,7 +26,7 @@
 
 static const struct gk104_fifo_func
 gm20b_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gm200_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gm107_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index e2f8f9087d7c8dd03501c4202b3f3a5eb674a046..54377e0f6a88fb1957beca80c28e062dab08009c 100644 (file)
@@ -52,7 +52,7 @@ gp100_fifo_fault_engine[] = {
 
 static const struct gk104_fifo_func
 gp100_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gm200_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gp100_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 7733bf7c6545cf03027dce6a4fd18ed9d43550d7..778ba7e46fb36f1d10ea48d9c651df2a2bd7520a 100644 (file)
@@ -26,7 +26,7 @@
 
 static const struct gk104_fifo_func
 gp10b_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gm200_fifo_pbdma,
        .fault.access = gk104_fifo_fault_access,
        .fault.engine = gp100_fifo_fault_engine,
        .fault.reason = gk104_fifo_fault_reason,
index 118b37aea318f94b4f4af80bb476a10136b1d495..728a1edbf98c8cce3f7cb81ea8912b8097d293b5 100644 (file)
@@ -85,7 +85,7 @@ gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
        case NVKM_ENGINE_MSVLD : return 0x0270;
        case NVKM_ENGINE_VIC   : return 0x0280;
        case NVKM_ENGINE_MSENC : return 0x0290;
-       case NVKM_ENGINE_NVDEC : return 0x02100270;
+       case NVKM_ENGINE_NVDEC0: return 0x02100270;
        case NVKM_ENGINE_NVENC0: return 0x02100290;
        case NVKM_ENGINE_NVENC1: return 0x0210;
        default:
@@ -192,7 +192,7 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
                gk104_fifo_runlist_remove(fifo, chan);
                nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800);
                gk104_fifo_gpfifo_kick(chan);
-               gk104_fifo_runlist_commit(fifo, chan->runl);
+               gk104_fifo_runlist_update(fifo, chan->runl);
        }
 
        nvkm_wr32(device, 0x800000 + coff, 0x00000000);
@@ -213,7 +213,7 @@ gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
        if (list_empty(&chan->head) && !chan->killed) {
                gk104_fifo_runlist_insert(fifo, chan);
                nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
-               gk104_fifo_runlist_commit(fifo, chan->runl);
+               gk104_fifo_runlist_update(fifo, chan->runl);
                nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
        }
 }
@@ -222,6 +222,7 @@ void *
 gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base)
 {
        struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
+       nvkm_memory_unref(&chan->mthd);
        kfree(chan->cgrp);
        return chan;
 }
@@ -240,7 +241,7 @@ gk104_fifo_gpfifo_func = {
 
 static int
 gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
-                      u64 vmm, u64 ioffset, u64 ilength,
+                      u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv,
                       const struct nvkm_oclass *oclass,
                       struct nvkm_object **pobject)
 {
@@ -279,6 +280,7 @@ gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
                return ret;
 
        *chid = chan->base.chid;
+       *inst = chan->base.inst->addr;
 
        /* Hack to support GPUs where even individual channels should be
         * part of a channel group.
@@ -315,6 +317,7 @@ gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
        nvkm_wo32(chan->base.inst, 0x94, 0x30000001);
        nvkm_wo32(chan->base.inst, 0x9c, 0x00000100);
        nvkm_wo32(chan->base.inst, 0xac, 0x0000001f);
+       nvkm_wo32(chan->base.inst, 0xe4, priv ? 0x00000020 : 0x00000000);
        nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid);
        nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000);
        nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */
@@ -337,15 +340,19 @@ gk104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
                nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
                                   "ioffset %016llx ilength %08x "
-                                  "runlist %016llx\n",
+                                  "runlist %016llx priv %d\n",
                           args->v0.version, args->v0.vmm, args->v0.ioffset,
-                          args->v0.ilength, args->v0.runlist);
+                          args->v0.ilength, args->v0.runlist, args->v0.priv);
+               if (args->v0.priv && !oclass->client->super)
+                       return -EINVAL;
                return gk104_fifo_gpfifo_new_(fifo,
                                              &args->v0.runlist,
                                              &args->v0.chid,
                                               args->v0.vmm,
                                               args->v0.ioffset,
                                               args->v0.ilength,
+                                             &args->v0.inst,
+                                              args->v0.priv,
                                              oclass, pobject);
        }
 
index 9598853ced56244285591c732bcd0cd4e44e0c4a..a7462cf59d65cb1c6afc5388d5f3f9e211db64d4 100644 (file)
 #include <core/client.h>
 #include <core/gpuobj.h>
 
-#include <nvif/cla06f.h>
+#include <nvif/clc36f.h>
 #include <nvif/unpack.h>
 
+static u32
+gv100_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *chan)
+{
+       return chan->chid;
+}
+
 static int
 gv100_fifo_gpfifo_engine_valid(struct gk104_fifo_chan *chan, bool ce, bool valid)
 {
@@ -56,7 +62,7 @@ gv100_fifo_gpfifo_engine_valid(struct gk104_fifo_chan *chan, bool ce, bool valid
        return ret;
 }
 
-static int
+int
 gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
                              struct nvkm_engine *engine, bool suspend)
 {
@@ -79,7 +85,7 @@ gv100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
        return ret;
 }
 
-static int
+int
 gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
                              struct nvkm_engine *engine)
 {
@@ -100,8 +106,8 @@ gv100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
        return gv100_fifo_gpfifo_engine_valid(chan, false, true);
 }
 
-const struct nvkm_fifo_chan_func
-gv100_fifo_gpfifo_func = {
+static const struct nvkm_fifo_chan_func
+gv100_fifo_gpfifo = {
        .dtor = gk104_fifo_gpfifo_dtor,
        .init = gk104_fifo_gpfifo_init,
        .fini = gk104_fifo_gpfifo_fini,
@@ -110,19 +116,23 @@ gv100_fifo_gpfifo_func = {
        .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
        .engine_init = gv100_fifo_gpfifo_engine_init,
        .engine_fini = gv100_fifo_gpfifo_engine_fini,
+       .submit_token = gv100_fifo_gpfifo_submit_token,
 };
 
-static int
-gv100_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
-                      u64 vmm, u64 ioffset, u64 ilength,
-                      const struct nvkm_oclass *oclass,
+int
+gv100_fifo_gpfifo_new_(const struct nvkm_fifo_chan_func *func,
+                      struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
+                      u64 vmm, u64 ioffset, u64 ilength, u64 *inst, bool priv,
+                      u32 *token, const struct nvkm_oclass *oclass,
                       struct nvkm_object **pobject)
 {
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
        struct gk104_fifo_chan *chan;
        int runlist = ffs(*runlists) -1, ret, i;
        unsigned long engm;
        u64 subdevs = 0;
-       u64 usermem;
+       u64 usermem, mthd;
+       u32 size;
 
        if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr)
                return -EINVAL;
@@ -142,14 +152,15 @@ gv100_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
        chan->runl = runlist;
        INIT_LIST_HEAD(&chan->head);
 
-       ret = nvkm_fifo_chan_ctor(&gv100_fifo_gpfifo_func, &fifo->base,
-                                 0x1000, 0x1000, true, vmm, 0, subdevs,
-                                 1, fifo->user.bar->addr, 0x200,
+       ret = nvkm_fifo_chan_ctor(func, &fifo->base, 0x1000, 0x1000, true, vmm,
+                                 0, subdevs, 1, fifo->user.bar->addr, 0x200,
                                  oclass, &chan->base);
        if (ret)
                return ret;
 
        *chid = chan->base.chid;
+       *inst = chan->base.inst->addr;
+       *token = chan->base.func->submit_token(&chan->base);
 
        /* Hack to support GPUs where even individual channels should be
         * part of a channel group.
@@ -173,6 +184,20 @@ gv100_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
        nvkm_done(fifo->user.mem);
        usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
 
+       /* Allocate fault method buffer (magics come from nvgpu). */
+       size = nvkm_rd32(device, 0x104028); /* NV_PCE_PCE_MAP */
+       size = 27 * 5 * (((9 + 1 + 3) * hweight32(size)) + 2);
+       size = roundup(size, PAGE_SIZE);
+
+       ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, true,
+                             &chan->mthd);
+       if (ret)
+               return ret;
+
+       mthd = nvkm_memory_bar2(chan->mthd);
+       if (mthd == ~0ULL)
+               return -EFAULT;
+
        /* RAMFC */
        nvkm_kmap(chan->base.inst);
        nvkm_wo32(chan->base.inst, 0x008, lower_32_bits(usermem));
@@ -184,13 +209,13 @@ gv100_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
                                          (ilength << 16));
        nvkm_wo32(chan->base.inst, 0x084, 0x20400000);
        nvkm_wo32(chan->base.inst, 0x094, 0x30000001);
-       nvkm_wo32(chan->base.inst, 0x0e4, 0x00000020);
+       nvkm_wo32(chan->base.inst, 0x0e4, priv ? 0x00000020 : 0x00000000);
        nvkm_wo32(chan->base.inst, 0x0e8, chan->base.chid);
-       nvkm_wo32(chan->base.inst, 0x0f4, 0x00001100);
+       nvkm_wo32(chan->base.inst, 0x0f4, 0x00001000);
        nvkm_wo32(chan->base.inst, 0x0f8, 0x10003080);
        nvkm_mo32(chan->base.inst, 0x218, 0x00000000, 0x00000000);
-       nvkm_wo32(chan->base.inst, 0x220, 0x020a1000);
-       nvkm_wo32(chan->base.inst, 0x224, 0x00000000);
+       nvkm_wo32(chan->base.inst, 0x220, lower_32_bits(mthd));
+       nvkm_wo32(chan->base.inst, 0x224, upper_32_bits(mthd));
        nvkm_done(chan->base.inst);
        return gv100_fifo_gpfifo_engine_valid(chan, true, true);
 }
@@ -201,7 +226,7 @@ gv100_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
 {
        struct nvkm_object *parent = oclass->parent;
        union {
-               struct kepler_channel_gpfifo_a_v0 v0;
+               struct volta_channel_gpfifo_a_v0 v0;
        } *args = data;
        int ret = -ENOSYS;
 
@@ -209,15 +234,20 @@ gv100_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
                nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
                                   "ioffset %016llx ilength %08x "
-                                  "runlist %016llx\n",
+                                  "runlist %016llx priv %d\n",
                           args->v0.version, args->v0.vmm, args->v0.ioffset,
-                          args->v0.ilength, args->v0.runlist);
-               return gv100_fifo_gpfifo_new_(fifo,
+                          args->v0.ilength, args->v0.runlist, args->v0.priv);
+               if (args->v0.priv && !oclass->client->super)
+                       return -EINVAL;
+               return gv100_fifo_gpfifo_new_(&gv100_fifo_gpfifo, fifo,
                                              &args->v0.runlist,
                                              &args->v0.chid,
                                               args->v0.vmm,
                                               args->v0.ioffset,
                                               args->v0.ilength,
+                                             &args->v0.inst,
+                                              args->v0.priv,
+                                             &args->v0.token,
                                              oclass, pobject);
        }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu104.c
new file mode 100644 (file)
index 0000000..ff70484
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "changk104.h"
+#include "cgrp.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+
+#include <nvif/clc36f.h>
+#include <nvif/unpack.h>
+
+static u32
+tu104_fifo_gpfifo_submit_token(struct nvkm_fifo_chan *base)
+{
+       struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
+       return (chan->runl << 16) | chan->base.chid;
+}
+
+static const struct nvkm_fifo_chan_func
+tu104_fifo_gpfifo = {
+       .dtor = gk104_fifo_gpfifo_dtor,
+       .init = gk104_fifo_gpfifo_init,
+       .fini = gk104_fifo_gpfifo_fini,
+       .ntfy = gf100_fifo_chan_ntfy,
+       .engine_ctor = gk104_fifo_gpfifo_engine_ctor,
+       .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
+       .engine_init = gv100_fifo_gpfifo_engine_init,
+       .engine_fini = gv100_fifo_gpfifo_engine_fini,
+       .submit_token = tu104_fifo_gpfifo_submit_token,
+};
+
+int
+tu104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass,
+                     void *data, u32 size, struct nvkm_object **pobject)
+{
+       struct nvkm_object *parent = oclass->parent;
+       union {
+               struct volta_channel_gpfifo_a_v0 v0;
+       } *args = data;
+       int ret = -ENOSYS;
+
+       nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
+       if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
+               nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
+                                  "ioffset %016llx ilength %08x "
+                                  "runlist %016llx priv %d\n",
+                          args->v0.version, args->v0.vmm, args->v0.ioffset,
+                          args->v0.ilength, args->v0.runlist, args->v0.priv);
+               if (args->v0.priv && !oclass->client->super)
+                       return -EINVAL;
+               return gv100_fifo_gpfifo_new_(&tu104_fifo_gpfifo, fifo,
+                                             &args->v0.runlist,
+                                             &args->v0.chid,
+                                              args->v0.vmm,
+                                              args->v0.ioffset,
+                                              args->v0.ilength,
+                                             &args->v0.inst,
+                                              args->v0.priv,
+                                             &args->v0.token,
+                                             oclass, pobject);
+       }
+
+       return ret;
+}
index 4e1d159c0ae7b1981bdffc099b9ecae6b5a4bf03..6ee1bb32a071c0bd9c51e0cf3063049d206e06f2 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <nvif/class.h>
 
-static void
+void
 gv100_fifo_runlist_chan(struct gk104_fifo_chan *chan,
                        struct nvkm_memory *memory, u32 offset)
 {
@@ -42,7 +42,7 @@ gv100_fifo_runlist_chan(struct gk104_fifo_chan *chan,
        nvkm_wo32(memory, offset + 0xc, upper_32_bits(inst));
 }
 
-static void
+void
 gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp,
                        struct nvkm_memory *memory, u32 offset)
 {
@@ -57,9 +57,10 @@ gv100_fifo_runlist = {
        .size = 16,
        .cgrp = gv100_fifo_runlist_cgrp,
        .chan = gv100_fifo_runlist_chan,
+       .commit = gk104_fifo_runlist_commit,
 };
 
-static const struct nvkm_enum
+const struct nvkm_enum
 gv100_fifo_fault_gpcclient[] = {
        { 0x00, "T1_0" },
        { 0x01, "T1_1" },
@@ -161,7 +162,7 @@ gv100_fifo_fault_gpcclient[] = {
        {}
 };
 
-static const struct nvkm_enum
+const struct nvkm_enum
 gv100_fifo_fault_hubclient[] = {
        { 0x00, "VIP" },
        { 0x01, "CE0" },
@@ -223,7 +224,7 @@ gv100_fifo_fault_hubclient[] = {
        {}
 };
 
-static const struct nvkm_enum
+const struct nvkm_enum
 gv100_fifo_fault_reason[] = {
        { 0x00, "PDE" },
        { 0x01, "PDE_SIZE" },
@@ -271,7 +272,7 @@ gv100_fifo_fault_engine[] = {
        {}
 };
 
-static const struct nvkm_enum
+const struct nvkm_enum
 gv100_fifo_fault_access[] = {
        { 0x0, "VIRT_READ" },
        { 0x1, "VIRT_WRITE" },
@@ -287,7 +288,7 @@ gv100_fifo_fault_access[] = {
 
 static const struct gk104_fifo_func
 gv100_fifo = {
-       .init_pbdma_timeout = gk208_fifo_init_pbdma_timeout,
+       .pbdma = &gm200_fifo_pbdma,
        .fault.access = gv100_fifo_fault_access,
        .fault.engine = gv100_fifo_fault_engine,
        .fault.reason = gv100_fifo_fault_reason,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu104.c
new file mode 100644 (file)
index 0000000..98c8070
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "gk104.h"
+#include "cgrp.h"
+#include "changk104.h"
+#include "user.h"
+
+#include <core/gpuobj.h>
+
+#include <nvif/class.h>
+
+static void
+tu104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl,
+                         struct nvkm_memory *mem, int nr)
+{
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
+       u64 addr = nvkm_memory_addr(mem);
+       /*XXX: target? */
+
+       nvkm_wr32(device, 0x002b00 + (runl * 0x10), lower_32_bits(addr));
+       nvkm_wr32(device, 0x002b04 + (runl * 0x10), upper_32_bits(addr));
+       nvkm_wr32(device, 0x002b08 + (runl * 0x10), nr);
+
+       /*XXX: how to wait? can you even wait? */
+}
+
+const struct gk104_fifo_runlist_func
+tu104_fifo_runlist = {
+       .size = 16,
+       .cgrp = gv100_fifo_runlist_cgrp,
+       .chan = gv100_fifo_runlist_chan,
+       .commit = tu104_fifo_runlist_commit,
+};
+
+static const struct nvkm_enum
+tu104_fifo_fault_engine[] = {
+       { 0x01, "DISPLAY" },
+       { 0x03, "PTP" },
+       { 0x06, "PWR_PMU" },
+       { 0x08, "IFB", NULL, NVKM_ENGINE_IFB },
+       { 0x09, "PERF" },
+       { 0x1f, "PHYSICAL" },
+       { 0x20, "HOST0" },
+       { 0x21, "HOST1" },
+       { 0x22, "HOST2" },
+       { 0x23, "HOST3" },
+       { 0x24, "HOST4" },
+       { 0x25, "HOST5" },
+       { 0x26, "HOST6" },
+       { 0x27, "HOST7" },
+       { 0x28, "HOST8" },
+       { 0x29, "HOST9" },
+       { 0x2a, "HOST10" },
+       { 0x2b, "HOST11" },
+       { 0x2c, "HOST12" },
+       { 0x2d, "HOST13" },
+       { 0x2e, "HOST14" },
+       { 0x80, "BAR1", NULL, NVKM_SUBDEV_BAR },
+       { 0xc0, "BAR2", NULL, NVKM_SUBDEV_INSTMEM },
+       {}
+};
+
+static void
+tu104_fifo_pbdma_init(struct gk104_fifo *fifo)
+{
+       struct nvkm_device *device = fifo->base.engine.subdev.device;
+       const u32 mask = (1 << fifo->pbdma_nr) - 1;
+       /*XXX: this is a bit of a guess at this point in time. */
+       nvkm_mask(device, 0xb65000, 0x80000fff, 0x80000000 | mask);
+}
+
+static const struct gk104_fifo_pbdma_func
+tu104_fifo_pbdma = {
+       .nr = gm200_fifo_pbdma_nr,
+       .init = tu104_fifo_pbdma_init,
+       .init_timeout = gk208_fifo_pbdma_init_timeout,
+};
+
+static const struct gk104_fifo_func
+tu104_fifo = {
+       .pbdma = &tu104_fifo_pbdma,
+       .fault.access = gv100_fifo_fault_access,
+       .fault.engine = tu104_fifo_fault_engine,
+       .fault.reason = gv100_fifo_fault_reason,
+       .fault.hubclient = gv100_fifo_fault_hubclient,
+       .fault.gpcclient = gv100_fifo_fault_gpcclient,
+       .runlist = &tu104_fifo_runlist,
+       .user = {{-1,-1,VOLTA_USERMODE_A       }, tu104_fifo_user_new   },
+       .chan = {{ 0, 0,TURING_CHANNEL_GPFIFO_A}, tu104_fifo_gpfifo_new },
+       .cgrp_force = true,
+};
+
+int
+tu104_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo)
+{
+       return gk104_fifo_new_(&tu104_fifo, device, index, 4096, pfifo);
+}
index ed840921ebe8cf5e7a90dc86903102b78c2ea973..14b0c6bde8ebbdfcef22fdca8a3ae4fc8fcffe21 100644 (file)
@@ -3,4 +3,6 @@
 #include "priv.h"
 int gv100_fifo_user_new(const struct nvkm_oclass *, void *, u32,
                        struct nvkm_object **);
+int tu104_fifo_user_new(const struct nvkm_oclass *, void *, u32,
+                       struct nvkm_object **);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/usertu104.c
new file mode 100644 (file)
index 0000000..8f98548
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "user.h"
+
+static int
+tu104_fifo_user_map(struct nvkm_object *object, void *argv, u32 argc,
+                   enum nvkm_object_map *type, u64 *addr, u64 *size)
+{
+       struct nvkm_device *device = object->engine->subdev.device;
+       *addr = 0xbb0000 + device->func->resource_addr(device, 0);
+       *size = 0x010000;
+       *type = NVKM_OBJECT_MAP_IO;
+       return 0;
+}
+
+static const struct nvkm_object_func
+tu104_fifo_user = {
+       .map = tu104_fifo_user_map,
+};
+
+int
+tu104_fifo_user_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+                   struct nvkm_object **pobject)
+{
+       return nvkm_object_new_(&tu104_fifo_user, oclass, argv, argc, pobject);
+}
index 14be41f24155a737a1eff869f5778380fae803c4..427340153640111c8c1b418000df37ff31a85785 100644 (file)
@@ -197,7 +197,7 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func,
        case NVKM_SUBDEV_PMU:
                debug_reg = 0xc08;
                break;
-       case NVKM_ENGINE_NVDEC:
+       case NVKM_ENGINE_NVDEC0:
                debug_reg = 0xd00;
                break;
        case NVKM_ENGINE_SEC2:
index e5830453813d43014daa13c16b85c5f211e4156d..ab0282dc07369e801071b2cae4a5c45b844975e5 100644 (file)
@@ -5,3 +5,4 @@ nvkm-y += nvkm/subdev/bar/gf100.o
 nvkm-y += nvkm/subdev/bar/gk20a.o
 nvkm-y += nvkm/subdev/bar/gm107.o
 nvkm-y += nvkm/subdev/bar/gm20b.o
+nvkm-y += nvkm/subdev/bar/tu104.o
index 243f0a5c8a62530007c7815d226d46b3fb7f0fbd..209a6a40834a0f21d6a341f008337a2730f848bc 100644 (file)
@@ -36,6 +36,16 @@ nvkm_bar_bar1_vmm(struct nvkm_device *device)
        return device->bar->func->bar1.vmm(device->bar);
 }
 
+void
+nvkm_bar_bar1_reset(struct nvkm_device *device)
+{
+       struct nvkm_bar *bar = device->bar;
+       if (bar) {
+               bar->func->bar1.init(bar);
+               bar->func->bar1.wait(bar);
+       }
+}
+
 struct nvkm_vmm *
 nvkm_bar_bar2_vmm(struct nvkm_device *device)
 {
@@ -48,6 +58,16 @@ nvkm_bar_bar2_vmm(struct nvkm_device *device)
        return NULL;
 }
 
+void
+nvkm_bar_bar2_reset(struct nvkm_device *device)
+{
+       struct nvkm_bar *bar = device->bar;
+       if (bar && bar->bar2) {
+               bar->func->bar2.init(bar);
+               bar->func->bar2.wait(bar);
+       }
+}
+
 void
 nvkm_bar_bar2_fini(struct nvkm_device *device)
 {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu104.c
new file mode 100644 (file)
index 0000000..ecaead1
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "gf100.h"
+
+#include <core/memory.h>
+#include <subdev/timer.h>
+
+static void
+tu104_bar_bar2_wait(struct nvkm_bar *bar)
+{
+       struct nvkm_device *device = bar->subdev.device;
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0xb80f50) & 0x0000000c))
+                       break;
+       );
+}
+
+static void
+tu104_bar_bar2_fini(struct nvkm_bar *bar)
+{
+       nvkm_mask(bar->subdev.device, 0xb80f48, 0x80000000, 0x00000000);
+}
+
+static void
+tu104_bar_bar2_init(struct nvkm_bar *base)
+{
+       struct nvkm_device *device = base->subdev.device;
+       struct gf100_bar *bar = gf100_bar(base);
+       u32 addr = nvkm_memory_addr(bar->bar[0].inst) >> 12;
+       if (bar->bar2_halve)
+               addr |= 0x40000000;
+       nvkm_wr32(device, 0xb80f48, 0x80000000 | addr);
+}
+
+static void
+tu104_bar_bar1_wait(struct nvkm_bar *bar)
+{
+       struct nvkm_device *device = bar->subdev.device;
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0xb80f50) & 0x00000003))
+                       break;
+       );
+}
+
+static void
+tu104_bar_bar1_fini(struct nvkm_bar *bar)
+{
+       nvkm_mask(bar->subdev.device, 0xb80f40, 0x80000000, 0x00000000);
+}
+
+static void
+tu104_bar_bar1_init(struct nvkm_bar *base)
+{
+       struct nvkm_device *device = base->subdev.device;
+       struct gf100_bar *bar = gf100_bar(base);
+       const u32 addr = nvkm_memory_addr(bar->bar[1].inst) >> 12;
+       nvkm_wr32(device, 0xb80f40, 0x80000000 | addr);
+}
+
+static const struct nvkm_bar_func
+tu104_bar = {
+       .dtor = gf100_bar_dtor,
+       .oneinit = gf100_bar_oneinit,
+       .bar1.init = tu104_bar_bar1_init,
+       .bar1.fini = tu104_bar_bar1_fini,
+       .bar1.wait = tu104_bar_bar1_wait,
+       .bar1.vmm = gf100_bar_bar1_vmm,
+       .bar2.init = tu104_bar_bar2_init,
+       .bar2.fini = tu104_bar_bar2_fini,
+       .bar2.wait = tu104_bar_bar2_wait,
+       .bar2.vmm = gf100_bar_bar2_vmm,
+       .flush = g84_bar_flush,
+};
+
+int
+tu104_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar)
+{
+       return gf100_bar_new_(&tu104_bar, device, index, pbar);
+}
index 50a4369264841d57cd268dec05352360184e157f..3ef505a5c01b20a99a695ca7d00bdd05d512fb1f 100644 (file)
@@ -13,3 +13,4 @@ nvkm-y += nvkm/subdev/devinit/gf100.o
 nvkm-y += nvkm/subdev/devinit/gm107.o
 nvkm-y += nvkm/subdev/devinit/gm200.o
 nvkm-y += nvkm/subdev/devinit/gv100.o
+nvkm-y += nvkm/subdev/devinit/tu104.o
index 17235e940ca9e354226836b4bb9e8582a48e1f90..59940dacc2ba028939d3822c0e736248a5af9359 100644 (file)
@@ -105,6 +105,15 @@ pmu_load(struct nv50_devinit *init, u8 type, bool post,
        return pmu_exec(init, pmu.init_addr_pmu), 0;
 }
 
+void
+gm200_devinit_preos(struct nv50_devinit *init, bool post)
+{
+       /* Optional: Execute PRE_OS application on PMU, which should at
+        * least take care of fans until a full PMU has been loaded.
+        */
+       pmu_load(init, 0x01, post, NULL, NULL);
+}
+
 int
 gm200_devinit_post(struct nvkm_devinit *base, bool post)
 {
@@ -156,10 +165,7 @@ gm200_devinit_post(struct nvkm_devinit *base, bool post)
                        return -ETIMEDOUT;
        }
 
-       /* Optional: Execute PRE_OS application on PMU, which should at
-        * least take care of fans until a full PMU has been loaded.
-        */
-       pmu_load(init, 0x01, post, NULL, NULL);
+       gm200_devinit_preos(init, post);
        return 0;
 }
 
index 9b9f0dc1e19288b80200f3f4f4a54f5da849bf4e..72d130bb7f7cd2c4a9a00b1573cf2fbffbdf8d34 100644 (file)
@@ -26,4 +26,5 @@ void gf100_devinit_preinit(struct nvkm_devinit *);
 u64  gm107_devinit_disable(struct nvkm_devinit *);
 
 int gm200_devinit_post(struct nvkm_devinit *, bool);
+void gm200_devinit_preos(struct nv50_devinit *, bool);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu104.c
new file mode 100644 (file)
index 0000000..aae87b3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+
+static int
+tu104_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
+{
+       struct nvkm_subdev *subdev = &init->subdev;
+       struct nvkm_device *device = subdev->device;
+       struct nvbios_pll info;
+       int head = type - PLL_VPLL0;
+       int N, fN, M, P;
+       int ret;
+
+       ret = nvbios_pll_parse(device->bios, type, &info);
+       if (ret)
+               return ret;
+
+       ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P);
+       if (ret < 0)
+               return ret;
+
+       switch (info.type) {
+       case PLL_VPLL0:
+       case PLL_VPLL1:
+       case PLL_VPLL2:
+       case PLL_VPLL3:
+               nvkm_wr32(device, 0x00ef10 + (head * 0x40), fN << 16);
+               nvkm_wr32(device, 0x00ef04 + (head * 0x40), (P << 16) |
+                                                           (N <<  8) |
+                                                           (M <<  0));
+               /*XXX*/
+               nvkm_wr32(device, 0x00ef0c + (head * 0x40), 0x00000900);
+               nvkm_wr32(device, 0x00ef00 + (head * 0x40), 0x02000014);
+               break;
+       default:
+               nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int
+tu104_devinit_post(struct nvkm_devinit *base, bool post)
+{
+       struct nv50_devinit *init = nv50_devinit(base);
+       gm200_devinit_preos(init, post);
+       return 0;
+}
+
+static const struct nvkm_devinit_func
+tu104_devinit = {
+       .init = nv50_devinit_init,
+       .post = tu104_devinit_post,
+       .pll_set = tu104_devinit_pll_set,
+       .disable = gm107_devinit_disable,
+};
+
+int
+tu104_devinit_new(struct nvkm_device *device, int index,
+               struct nvkm_devinit **pinit)
+{
+       return nv50_devinit_new_(&tu104_devinit, device, index, pinit);
+}
index 45bb46fb0929a4638cb354eca51038817f7797ab..794eb1745b2fcc808aaaf035b0c8f0715936eb5e 100644 (file)
@@ -1,3 +1,4 @@
 nvkm-y += nvkm/subdev/fault/base.o
 nvkm-y += nvkm/subdev/fault/gp100.o
 nvkm-y += nvkm/subdev/fault/gv100.o
+nvkm-y += nvkm/subdev/fault/tu104.o
index 16ad91c91a7beca11a8febfbb91a54f3b34ac008..4ba1e21e8fdac6a557489c7bcadcf1ceee780527 100644 (file)
 
 #include <core/memory.h>
 #include <core/notify.h>
-#include <subdev/bar.h>
-#include <subdev/mmu.h>
 
 static void
 nvkm_fault_ntfy_fini(struct nvkm_event *event, int type, int index)
 {
        struct nvkm_fault *fault = container_of(event, typeof(*fault), event);
-       fault->func->buffer.fini(fault->buffer[index]);
+       fault->func->buffer.intr(fault->buffer[index], false);
 }
 
 static void
 nvkm_fault_ntfy_init(struct nvkm_event *event, int type, int index)
 {
        struct nvkm_fault *fault = container_of(event, typeof(*fault), event);
-       fault->func->buffer.init(fault->buffer[index]);
+       fault->func->buffer.intr(fault->buffer[index], true);
 }
 
 static int
@@ -91,7 +89,6 @@ nvkm_fault_oneinit_buffer(struct nvkm_fault *fault, int id)
 {
        struct nvkm_subdev *subdev = &fault->subdev;
        struct nvkm_device *device = subdev->device;
-       struct nvkm_vmm *bar2 = nvkm_bar_bar2_vmm(device);
        struct nvkm_fault_buffer *buffer;
        int ret;
 
@@ -99,7 +96,7 @@ nvkm_fault_oneinit_buffer(struct nvkm_fault *fault, int id)
                return -ENOMEM;
        buffer->fault = fault;
        buffer->id = id;
-       buffer->entries = fault->func->buffer.entries(buffer);
+       fault->func->buffer.info(buffer);
        fault->buffer[id] = buffer;
 
        nvkm_debug(subdev, "buffer %d: %d entries\n", id, buffer->entries);
@@ -110,12 +107,12 @@ nvkm_fault_oneinit_buffer(struct nvkm_fault *fault, int id)
        if (ret)
                return ret;
 
-       ret = nvkm_vmm_get(bar2, 12, nvkm_memory_size(buffer->mem),
-                          &buffer->vma);
-       if (ret)
-               return ret;
+       /* Pin fault buffer in BAR2. */
+       buffer->addr = nvkm_memory_bar2(buffer->mem);
+       if (buffer->addr == ~0ULL)
+               return -EFAULT;
 
-       return nvkm_memory_map(buffer->mem, 0, bar2, buffer->vma, NULL, 0);
+       return 0;
 }
 
 static int
@@ -146,7 +143,6 @@ nvkm_fault_oneinit(struct nvkm_subdev *subdev)
 static void *
 nvkm_fault_dtor(struct nvkm_subdev *subdev)
 {
-       struct nvkm_vmm *bar2 = nvkm_bar_bar2_vmm(subdev->device);
        struct nvkm_fault *fault = nvkm_fault(subdev);
        int i;
 
@@ -154,7 +150,6 @@ nvkm_fault_dtor(struct nvkm_subdev *subdev)
 
        for (i = 0; i < fault->buffer_nr; i++) {
                if (fault->buffer[i]) {
-                       nvkm_vmm_put(bar2, &fault->buffer[i]->vma);
                        nvkm_memory_unref(&fault->buffer[i]->mem);
                        kfree(fault->buffer[i]);
                }
index 5e71db2e8d750378a6746438949d23c4ae4f6676..8fb96fe614f9dead4075bc233fdd5c9bd9750491 100644 (file)
  */
 #include "priv.h"
 
-#include <subdev/mmu.h>
+#include <subdev/mc.h>
+
+static void
+gp100_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
+{
+       struct nvkm_device *device = buffer->fault->subdev.device;
+       nvkm_mc_intr_mask(device, NVKM_SUBDEV_FAULT, enable);
+}
 
 static void
 gp100_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
@@ -34,15 +41,17 @@ static void
 gp100_fault_buffer_init(struct nvkm_fault_buffer *buffer)
 {
        struct nvkm_device *device = buffer->fault->subdev.device;
-       nvkm_wr32(device, 0x002a74, upper_32_bits(buffer->vma->addr));
-       nvkm_wr32(device, 0x002a70, lower_32_bits(buffer->vma->addr));
+       nvkm_wr32(device, 0x002a74, upper_32_bits(buffer->addr));
+       nvkm_wr32(device, 0x002a70, lower_32_bits(buffer->addr));
        nvkm_mask(device, 0x002a70, 0x00000001, 0x00000001);
 }
 
-static u32
-gp100_fault_buffer_entries(struct nvkm_fault_buffer *buffer)
+static void
+gp100_fault_buffer_info(struct nvkm_fault_buffer *buffer)
 {
-       return nvkm_rd32(buffer->fault->subdev.device, 0x002a78);
+       buffer->entries = nvkm_rd32(buffer->fault->subdev.device, 0x002a78);
+       buffer->get = 0x002a7c;
+       buffer->put = 0x002a80;
 }
 
 static void
@@ -56,9 +65,10 @@ gp100_fault = {
        .intr = gp100_fault_intr,
        .buffer.nr = 1,
        .buffer.entry_size = 32,
-       .buffer.entries = gp100_fault_buffer_entries,
+       .buffer.info = gp100_fault_buffer_info,
        .buffer.init = gp100_fault_buffer_init,
        .buffer.fini = gp100_fault_buffer_fini,
+       .buffer.intr = gp100_fault_buffer_intr,
 };
 
 int
index 3cd610d7deb5268f1e73fcebbd4e49aa50519cfc..6fc54e17c9354d17f0dba41f2915b0bd72f70728 100644 (file)
@@ -30,9 +30,8 @@ gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer)
 {
        struct nvkm_device *device = buffer->fault->subdev.device;
        struct nvkm_memory *mem = buffer->mem;
-       const u32 foff = buffer->id * 0x14;
-       u32 get = nvkm_rd32(device, 0x100e2c + foff);
-       u32 put = nvkm_rd32(device, 0x100e30 + foff);
+       u32 get = nvkm_rd32(device, buffer->get);
+       u32 put = nvkm_rd32(device, buffer->put);
        if (put == get)
                return;
 
@@ -51,7 +50,7 @@ gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer)
 
                if (++get == buffer->entries)
                        get = 0;
-               nvkm_wr32(device, 0x100e2c + foff, get);
+               nvkm_wr32(device, buffer->get, get);
 
                info.addr   = ((u64)addrhi << 32) | addrlo;
                info.inst   = ((u64)insthi << 32) | instlo;
@@ -70,13 +69,21 @@ gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer)
 }
 
 static void
-gv100_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
+gv100_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
 {
        struct nvkm_device *device = buffer->fault->subdev.device;
        const u32 intr = buffer->id ? 0x08000000 : 0x20000000;
-       const u32 foff = buffer->id * 0x14;
+       if (enable)
+               nvkm_mask(device, 0x100a2c, intr, intr);
+       else
+               nvkm_mask(device, 0x100a34, intr, intr);
+}
 
-       nvkm_mask(device, 0x100a34, intr, intr);
+static void
+gv100_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
+{
+       struct nvkm_device *device = buffer->fault->subdev.device;
+       const u32 foff = buffer->id * 0x14;
        nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x00000000);
 }
 
@@ -84,23 +91,25 @@ static void
 gv100_fault_buffer_init(struct nvkm_fault_buffer *buffer)
 {
        struct nvkm_device *device = buffer->fault->subdev.device;
-       const u32 intr = buffer->id ? 0x08000000 : 0x20000000;
        const u32 foff = buffer->id * 0x14;
 
        nvkm_mask(device, 0x100e34 + foff, 0xc0000000, 0x40000000);
-       nvkm_wr32(device, 0x100e28 + foff, upper_32_bits(buffer->vma->addr));
-       nvkm_wr32(device, 0x100e24 + foff, lower_32_bits(buffer->vma->addr));
+       nvkm_wr32(device, 0x100e28 + foff, upper_32_bits(buffer->addr));
+       nvkm_wr32(device, 0x100e24 + foff, lower_32_bits(buffer->addr));
        nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x80000000);
-       nvkm_mask(device, 0x100a2c, intr, intr);
 }
 
-static u32
-gv100_fault_buffer_entries(struct nvkm_fault_buffer *buffer)
+static void
+gv100_fault_buffer_info(struct nvkm_fault_buffer *buffer)
 {
        struct nvkm_device *device = buffer->fault->subdev.device;
        const u32 foff = buffer->id * 0x14;
+
        nvkm_mask(device, 0x100e34 + foff, 0x40000000, 0x40000000);
-       return nvkm_rd32(device, 0x100e34 + foff) & 0x000fffff;
+
+       buffer->entries = nvkm_rd32(device, 0x100e34 + foff) & 0x000fffff;
+       buffer->get = 0x100e2c + foff;
+       buffer->put = 0x100e30 + foff;
 }
 
 static int
@@ -166,6 +175,8 @@ static void
 gv100_fault_fini(struct nvkm_fault *fault)
 {
        nvkm_notify_put(&fault->nrpfb);
+       if (fault->buffer[0])
+               fault->func->buffer.fini(fault->buffer[0]);
        nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000);
 }
 
@@ -173,14 +184,15 @@ static void
 gv100_fault_init(struct nvkm_fault *fault)
 {
        nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000);
+       fault->func->buffer.init(fault->buffer[0]);
        nvkm_notify_get(&fault->nrpfb);
 }
 
-static int
+int
 gv100_fault_oneinit(struct nvkm_fault *fault)
 {
        return nvkm_notify_init(&fault->buffer[0]->object, &fault->event,
-                               gv100_fault_ntfy_nrpfb, false, NULL, 0, 0,
+                               gv100_fault_ntfy_nrpfb, true, NULL, 0, 0,
                                &fault->nrpfb);
 }
 
@@ -192,9 +204,10 @@ gv100_fault = {
        .intr = gv100_fault_intr,
        .buffer.nr = 2,
        .buffer.entry_size = 32,
-       .buffer.entries = gv100_fault_buffer_entries,
+       .buffer.info = gv100_fault_buffer_info,
        .buffer.init = gv100_fault_buffer_init,
        .buffer.fini = gv100_fault_buffer_fini,
+       .buffer.intr = gv100_fault_buffer_intr,
 };
 
 int
index e4d2f5234fd19be82125e7266bf89e3db1e4f563..8ca8b2876dadf30b1b6eb16c2b1acdff8b091624 100644 (file)
@@ -12,8 +12,10 @@ struct nvkm_fault_buffer {
        struct nvkm_fault *fault;
        int id;
        int entries;
+       u32 get;
+       u32 put;
        struct nvkm_memory *mem;
-       struct nvkm_vma *vma;
+       u64 addr;
 };
 
 int nvkm_fault_new_(const struct nvkm_fault_func *, struct nvkm_device *,
@@ -27,9 +29,12 @@ struct nvkm_fault_func {
        struct {
                int nr;
                u32 entry_size;
-               u32 (*entries)(struct nvkm_fault_buffer *);
+               void (*info)(struct nvkm_fault_buffer *);
                void (*init)(struct nvkm_fault_buffer *);
                void (*fini)(struct nvkm_fault_buffer *);
+               void (*intr)(struct nvkm_fault_buffer *, bool enable);
        } buffer;
 };
+
+int gv100_fault_oneinit(struct nvkm_fault *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu104.c
new file mode 100644 (file)
index 0000000..9c8a3ad
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+#include <core/memory.h>
+#include <subdev/mmu.h>
+#include <engine/fifo.h>
+
+#include <nvif/class.h>
+
+static void
+tu104_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
+{
+       /*XXX: Earlier versions of RM touched the old regs on Turing,
+        *     which don't appear to actually work anymore, but newer
+        *     versions of RM don't appear to touch anything at all..
+        */
+}
+
+static void
+tu104_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
+{
+       struct nvkm_device *device = buffer->fault->subdev.device;
+       const u32 foff = buffer->id * 0x20;
+       nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x00000000);
+}
+
+static void
+tu104_fault_buffer_init(struct nvkm_fault_buffer *buffer)
+{
+       struct nvkm_device *device = buffer->fault->subdev.device;
+       const u32 foff = buffer->id * 0x20;
+
+       nvkm_mask(device, 0xb83010 + foff, 0xc0000000, 0x40000000);
+       nvkm_wr32(device, 0xb83004 + foff, upper_32_bits(buffer->addr));
+       nvkm_wr32(device, 0xb83000 + foff, lower_32_bits(buffer->addr));
+       nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x80000000);
+}
+
+static void
+tu104_fault_buffer_info(struct nvkm_fault_buffer *buffer)
+{
+       struct nvkm_device *device = buffer->fault->subdev.device;
+       const u32 foff = buffer->id * 0x20;
+
+       nvkm_mask(device, 0xb83010 + foff, 0x40000000, 0x40000000);
+
+       buffer->entries = nvkm_rd32(device, 0xb83010 + foff) & 0x000fffff;
+       buffer->get = 0xb83008 + foff;
+       buffer->put = 0xb8300c + foff;
+}
+
+static void
+tu104_fault_intr_fault(struct nvkm_fault *fault)
+{
+       struct nvkm_subdev *subdev = &fault->subdev;
+       struct nvkm_device *device = subdev->device;
+       struct nvkm_fault_data info;
+       const u32 addrlo = nvkm_rd32(device, 0xb83080);
+       const u32 addrhi = nvkm_rd32(device, 0xb83084);
+       const u32  info0 = nvkm_rd32(device, 0xb83088);
+       const u32 insthi = nvkm_rd32(device, 0xb8308c);
+       const u32  info1 = nvkm_rd32(device, 0xb83090);
+
+       info.addr = ((u64)addrhi << 32) | addrlo;
+       info.inst = ((u64)insthi << 32) | (info0 & 0xfffff000);
+       info.time = 0;
+       info.engine = (info0 & 0x000000ff);
+       info.valid  = (info1 & 0x80000000) >> 31;
+       info.gpc    = (info1 & 0x1f000000) >> 24;
+       info.hub    = (info1 & 0x00100000) >> 20;
+       info.access = (info1 & 0x000f0000) >> 16;
+       info.client = (info1 & 0x00007f00) >> 8;
+       info.reason = (info1 & 0x0000001f);
+
+       nvkm_fifo_fault(device->fifo, &info);
+}
+
+static void
+tu104_fault_intr(struct nvkm_fault *fault)
+{
+       struct nvkm_subdev *subdev = &fault->subdev;
+       struct nvkm_device *device = subdev->device;
+       u32 stat = nvkm_rd32(device, 0xb83094);
+
+       if (stat & 0x80000000) {
+               tu104_fault_intr_fault(fault);
+               nvkm_wr32(device, 0xb83094, 0x80000000);
+               stat &= ~0x80000000;
+       }
+
+       if (stat & 0x00000200) {
+               if (fault->buffer[0]) {
+                       nvkm_event_send(&fault->event, 1, 0, NULL, 0);
+                       stat &= ~0x00000200;
+               }
+       }
+
+       /*XXX: guess, can't confirm until we get fw... */
+       if (stat & 0x00000100) {
+               if (fault->buffer[1]) {
+                       nvkm_event_send(&fault->event, 1, 1, NULL, 0);
+                       stat &= ~0x00000100;
+               }
+       }
+
+       if (stat) {
+               nvkm_debug(subdev, "intr %08x\n", stat);
+       }
+}
+
+static void
+tu104_fault_fini(struct nvkm_fault *fault)
+{
+       nvkm_notify_put(&fault->nrpfb);
+       if (fault->buffer[0])
+               fault->func->buffer.fini(fault->buffer[0]);
+       /*XXX: disable priv faults */
+}
+
+static void
+tu104_fault_init(struct nvkm_fault *fault)
+{
+       /*XXX: enable priv faults */
+       fault->func->buffer.init(fault->buffer[0]);
+       nvkm_notify_get(&fault->nrpfb);
+}
+
+static const struct nvkm_fault_func
+tu104_fault = {
+       .oneinit = gv100_fault_oneinit,
+       .init = tu104_fault_init,
+       .fini = tu104_fault_fini,
+       .intr = tu104_fault_intr,
+       .buffer.nr = 2,
+       .buffer.entry_size = 32,
+       .buffer.info = tu104_fault_buffer_info,
+       .buffer.init = tu104_fault_buffer_init,
+       .buffer.fini = tu104_fault_buffer_fini,
+       .buffer.intr = tu104_fault_buffer_intr,
+};
+
+int
+tu104_fault_new(struct nvkm_device *device, int index,
+               struct nvkm_fault **pfault)
+{
+       return nvkm_fault_new_(&tu104_fault, device, index, pfault);
+}
index 434d2fc5bb1ce90c92c16299208ba5a290cbbe06..b2bb5a3ccb02b34a7158eee49d7fec2aa5559626 100644 (file)
@@ -68,10 +68,13 @@ nvkm_fb_bios_memtype(struct nvkm_bios *bios)
 
        if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
                switch (M0203E.type) {
-               case M0203E_TYPE_DDR2 : return NVKM_RAM_TYPE_DDR2;
-               case M0203E_TYPE_DDR3 : return NVKM_RAM_TYPE_DDR3;
-               case M0203E_TYPE_GDDR3: return NVKM_RAM_TYPE_GDDR3;
-               case M0203E_TYPE_GDDR5: return NVKM_RAM_TYPE_GDDR5;
+               case M0203E_TYPE_DDR2  : return NVKM_RAM_TYPE_DDR2;
+               case M0203E_TYPE_DDR3  : return NVKM_RAM_TYPE_DDR3;
+               case M0203E_TYPE_GDDR3 : return NVKM_RAM_TYPE_GDDR3;
+               case M0203E_TYPE_GDDR5 : return NVKM_RAM_TYPE_GDDR5;
+               case M0203E_TYPE_GDDR5X: return NVKM_RAM_TYPE_GDDR5X;
+               case M0203E_TYPE_GDDR6 : return NVKM_RAM_TYPE_GDDR6;
+               case M0203E_TYPE_HBM2  : return NVKM_RAM_TYPE_HBM2;
                default:
                        nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type);
                        return NVKM_RAM_TYPE_UNKNOWN;
index 24c7bd50573169054047634ffc98f546fa2f2a2a..b11867f682cb933fe60996092e29357e4aab8154 100644 (file)
@@ -184,6 +184,9 @@ nvkm_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
                [NVKM_RAM_TYPE_GDDR3  ] = "GDDR3",
                [NVKM_RAM_TYPE_GDDR4  ] = "GDDR4",
                [NVKM_RAM_TYPE_GDDR5  ] = "GDDR5",
+               [NVKM_RAM_TYPE_GDDR5X ] = "GDDR5X",
+               [NVKM_RAM_TYPE_GDDR6  ] = "GDDR6",
+               [NVKM_RAM_TYPE_HBM2   ] = "HBM2",
        };
        struct nvkm_subdev *subdev = &fb->subdev;
        int ret;
index db48a1daca0c7a3d786332ce25435839fcc10760..02c4eb28cef44db11ef989f34cab124b74d4f84b 100644 (file)
@@ -288,6 +288,19 @@ nv50_instobj_addr(struct nvkm_memory *memory)
        return nvkm_memory_addr(nv50_instobj(memory)->ram);
 }
 
+static u64
+nv50_instobj_bar2(struct nvkm_memory *memory)
+{
+       struct nv50_instobj *iobj = nv50_instobj(memory);
+       u64 addr = ~0ULL;
+       if (nv50_instobj_acquire(&iobj->base.memory)) {
+               iobj->lru.next = NULL; /* Exclude from eviction. */
+               addr = iobj->bar->addr;
+       }
+       nv50_instobj_release(&iobj->base.memory);
+       return addr;
+}
+
 static enum nvkm_memory_target
 nv50_instobj_target(struct nvkm_memory *memory)
 {
@@ -325,8 +338,9 @@ static const struct nvkm_memory_func
 nv50_instobj_func = {
        .dtor = nv50_instobj_dtor,
        .target = nv50_instobj_target,
-       .size = nv50_instobj_size,
+       .bar2 = nv50_instobj_bar2,
        .addr = nv50_instobj_addr,
+       .size = nv50_instobj_size,
        .boot = nv50_instobj_boot,
        .acquire = nv50_instobj_acquire,
        .release = nv50_instobj_release,
index 2befbe36dc28dcf02757dd5f0de718f392046167..f3b06329c338bf43223d6f05ef278e25ce7ef01f 100644 (file)
@@ -12,3 +12,4 @@ nvkm-y += nvkm/subdev/mc/gk104.o
 nvkm-y += nvkm/subdev/mc/gk20a.o
 nvkm-y += nvkm/subdev/mc/gp100.o
 nvkm-y += nvkm/subdev/mc/gp10b.o
+nvkm-y += nvkm/subdev/mc/tu104.o
index 09f669ac663090ecc7615cf3dbb504915fcc3323..0e57ab2a709f4376eb0a96c324ea25f2ba2ae1c4 100644 (file)
@@ -108,6 +108,9 @@ nvkm_mc_intr(struct nvkm_device *device, bool *handled)
        if (stat)
                nvkm_error(&mc->subdev, "intr %08x\n", stat);
        *handled = intr != 0;
+
+       if (mc->func->intr_hack)
+               mc->func->intr_hack(mc, handled);
 }
 
 static u32
index d9e3691d45b7976bf4b5ef9782aea8f7e685487c..eb91a4cf452bd7d6a342bd93a44e17f08a9f7ff6 100644 (file)
@@ -26,6 +26,7 @@ struct nvkm_mc_func {
        void (*intr_mask)(struct nvkm_mc *, u32 mask, u32 stat);
        /* retrieve pending interrupt mask (NV_PMC_INTR) */
        u32 (*intr_stat)(struct nvkm_mc *);
+       void (*intr_hack)(struct nvkm_mc *, bool *handled);
        const struct nvkm_mc_map *reset;
        void (*unk260)(struct nvkm_mc *, u32);
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/tu104.c
new file mode 100644 (file)
index 0000000..b7165bd
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "priv.h"
+
+static void
+tu104_mc_intr_hack(struct nvkm_mc *mc, bool *handled)
+{
+       struct nvkm_device *device = mc->subdev.device;
+       u32 stat = nvkm_rd32(device, 0xb81010);
+       if (stat & 0x00000050) {
+               struct nvkm_subdev *subdev =
+                       nvkm_device_subdev(device, NVKM_SUBDEV_FAULT);
+               nvkm_wr32(device, 0xb81010, stat & 0x00000050);
+               if (subdev)
+                       nvkm_subdev_intr(subdev);
+               *handled = true;
+       }
+}
+
+static const struct nvkm_mc_func
+tu104_mc = {
+       .init = nv50_mc_init,
+       .intr = gp100_mc_intr,
+       .intr_unarm = gp100_mc_intr_unarm,
+       .intr_rearm = gp100_mc_intr_rearm,
+       .intr_mask = gp100_mc_intr_mask,
+       .intr_stat = gf100_mc_intr_stat,
+       .intr_hack = tu104_mc_intr_hack,
+       .reset = gk104_mc_reset,
+};
+
+int
+tu104_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
+{
+       return gp100_mc_new_(&tu104_mc, device, index, pmc);
+}
index 58a24e3a05985d0ef01e6c72fc4fed79e86d4b3e..8966180b36ccd62f0170a3750a153506026242b5 100644 (file)
@@ -13,6 +13,7 @@ nvkm-y += nvkm/subdev/mmu/gm20b.o
 nvkm-y += nvkm/subdev/mmu/gp100.o
 nvkm-y += nvkm/subdev/mmu/gp10b.o
 nvkm-y += nvkm/subdev/mmu/gv100.o
+nvkm-y += nvkm/subdev/mmu/tu104.o
 
 nvkm-y += nvkm/subdev/mmu/mem.o
 nvkm-y += nvkm/subdev/mmu/memnv04.o
@@ -33,6 +34,7 @@ nvkm-y += nvkm/subdev/mmu/vmmgm20b.o
 nvkm-y += nvkm/subdev/mmu/vmmgp100.o
 nvkm-y += nvkm/subdev/mmu/vmmgp10b.o
 nvkm-y += nvkm/subdev/mmu/vmmgv100.o
+nvkm-y += nvkm/subdev/mmu/vmmtu104.o
 
 nvkm-y += nvkm/subdev/mmu/umem.o
 nvkm-y += nvkm/subdev/mmu/ummu.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu104.c
new file mode 100644 (file)
index 0000000..8e6f409
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "mem.h"
+#include "vmm.h"
+
+#include <core/option.h>
+
+#include <nvif/class.h>
+
+static const struct nvkm_mmu_func
+tu104_mmu = {
+       .dma_bits = 47,
+       .mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
+       .mem = {{ -1,  0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
+       .vmm = {{ -1,  0, NVIF_CLASS_VMM_GP100}, tu104_vmm_new },
+       .kind = gm200_mmu_kind,
+       .kind_sys = true,
+};
+
+int
+tu104_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
+{
+       return nvkm_mmu_new_(&tu104_mmu, device, index, pmmu);
+}
index 37b201b95f15bcab36374fdc4b7478e5a324e118..6889076097ecaf3f97686a7a570bd1d170d09042 100644 (file)
@@ -134,23 +134,10 @@ nvkm_uvmm_mthd_map(struct nvkm_uvmm *uvmm, void *argv, u32 argc)
                        goto fail;
                }
 
-               if (vma->addr != addr) {
-                       const u64 tail = vma->size + vma->addr - addr;
-                       if (ret = -ENOMEM, !(vma = nvkm_vma_tail(vma, tail)))
-                               goto fail;
-                       vma->part = true;
-                       nvkm_vmm_node_insert(vmm, vma);
-               }
-
-               if (vma->size != size) {
-                       const u64 tail = vma->size - size;
-                       struct nvkm_vma *tmp;
-                       if (ret = -ENOMEM, !(tmp = nvkm_vma_tail(vma, tail))) {
-                               nvkm_vmm_unmap_region(vmm, vma);
-                               goto fail;
-                       }
-                       tmp->part = true;
-                       nvkm_vmm_node_insert(vmm, tmp);
+               vma = nvkm_vmm_node_split(vmm, vma, addr, size);
+               if (!vma) {
+                       ret = -ENOMEM;
+                       goto fail;
                }
        }
        vma->busy = true;
index 7459def78d504f006a2f7f0b625ba3372238b7ec..6b87fff014b3c5b672308f7467d02fb0ace418c5 100644 (file)
@@ -767,6 +767,20 @@ nvkm_vma_tail(struct nvkm_vma *vma, u64 tail)
        return new;
 }
 
+static inline void
+nvkm_vmm_free_remove(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
+{
+       rb_erase(&vma->tree, &vmm->free);
+}
+
+static inline void
+nvkm_vmm_free_delete(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
+{
+       nvkm_vmm_free_remove(vmm, vma);
+       list_del(&vma->head);
+       kfree(vma);
+}
+
 static void
 nvkm_vmm_free_insert(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
 {
@@ -795,7 +809,21 @@ nvkm_vmm_free_insert(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
        rb_insert_color(&vma->tree, &vmm->free);
 }
 
-void
+static inline void
+nvkm_vmm_node_remove(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
+{
+       rb_erase(&vma->tree, &vmm->root);
+}
+
+static inline void
+nvkm_vmm_node_delete(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
+{
+       nvkm_vmm_node_remove(vmm, vma);
+       list_del(&vma->head);
+       kfree(vma);
+}
+
+static void
 nvkm_vmm_node_insert(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
 {
        struct rb_node **ptr = &vmm->root.rb_node;
@@ -834,6 +862,78 @@ nvkm_vmm_node_search(struct nvkm_vmm *vmm, u64 addr)
        return NULL;
 }
 
+#define node(root, dir) (((root)->head.dir == &vmm->list) ? NULL :             \
+       list_entry((root)->head.dir, struct nvkm_vma, head))
+
+static struct nvkm_vma *
+nvkm_vmm_node_merge(struct nvkm_vmm *vmm, struct nvkm_vma *prev,
+                   struct nvkm_vma *vma, struct nvkm_vma *next, u64 size)
+{
+       if (next) {
+               if (vma->size == size) {
+                       vma->size += next->size;
+                       nvkm_vmm_node_delete(vmm, next);
+                       if (prev) {
+                               prev->size += vma->size;
+                               nvkm_vmm_node_delete(vmm, vma);
+                               return prev;
+                       }
+                       return vma;
+               }
+               BUG_ON(prev);
+
+               nvkm_vmm_node_remove(vmm, next);
+               vma->size -= size;
+               next->addr -= size;
+               next->size += size;
+               nvkm_vmm_node_insert(vmm, next);
+               return next;
+       }
+
+       if (prev) {
+               if (vma->size != size) {
+                       nvkm_vmm_node_remove(vmm, vma);
+                       prev->size += size;
+                       vma->addr += size;
+                       vma->size -= size;
+                       nvkm_vmm_node_insert(vmm, vma);
+               } else {
+                       prev->size += vma->size;
+                       nvkm_vmm_node_delete(vmm, vma);
+               }
+               return prev;
+       }
+
+       return vma;
+}
+
+struct nvkm_vma *
+nvkm_vmm_node_split(struct nvkm_vmm *vmm,
+                   struct nvkm_vma *vma, u64 addr, u64 size)
+{
+       struct nvkm_vma *prev = NULL;
+
+       if (vma->addr != addr) {
+               prev = vma;
+               if (!(vma = nvkm_vma_tail(vma, vma->size + vma->addr - addr)))
+                       return NULL;
+               vma->part = true;
+               nvkm_vmm_node_insert(vmm, vma);
+       }
+
+       if (vma->size != size) {
+               struct nvkm_vma *tmp;
+               if (!(tmp = nvkm_vma_tail(vma, vma->size - size))) {
+                       nvkm_vmm_node_merge(vmm, prev, vma, NULL, vma->size);
+                       return NULL;
+               }
+               tmp->part = true;
+               nvkm_vmm_node_insert(vmm, tmp);
+       }
+
+       return vma;
+}
+
 static void
 nvkm_vmm_dtor(struct nvkm_vmm *vmm)
 {
@@ -954,37 +1054,20 @@ nvkm_vmm_new_(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
        return nvkm_vmm_ctor(func, mmu, hdr, addr, size, key, name, *pvmm);
 }
 
-#define node(root, dir) ((root)->head.dir == &vmm->list) ? NULL :              \
-       list_entry((root)->head.dir, struct nvkm_vma, head)
-
 void
 nvkm_vmm_unmap_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
 {
-       struct nvkm_vma *next;
+       struct nvkm_vma *next = node(vma, next);
+       struct nvkm_vma *prev = NULL;
 
        nvkm_memory_tags_put(vma->memory, vmm->mmu->subdev.device, &vma->tags);
        nvkm_memory_unref(&vma->memory);
 
-       if (vma->part) {
-               struct nvkm_vma *prev = node(vma, prev);
-               if (!prev->memory) {
-                       prev->size += vma->size;
-                       rb_erase(&vma->tree, &vmm->root);
-                       list_del(&vma->head);
-                       kfree(vma);
-                       vma = prev;
-               }
-       }
-
-       next = node(vma, next);
-       if (next && next->part) {
-               if (!next->memory) {
-                       vma->size += next->size;
-                       rb_erase(&next->tree, &vmm->root);
-                       list_del(&next->head);
-                       kfree(next);
-               }
-       }
+       if (!vma->part || ((prev = node(vma, prev)), prev->memory))
+               prev = NULL;
+       if (!next->part || next->memory)
+               next = NULL;
+       nvkm_vmm_node_merge(vmm, prev, vma, next, vma->size);
 }
 
 void
@@ -1163,18 +1246,14 @@ nvkm_vmm_put_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
        struct nvkm_vma *prev, *next;
 
        if ((prev = node(vma, prev)) && !prev->used) {
-               rb_erase(&prev->tree, &vmm->free);
-               list_del(&prev->head);
                vma->addr  = prev->addr;
                vma->size += prev->size;
-               kfree(prev);
+               nvkm_vmm_free_delete(vmm, prev);
        }
 
        if ((next = node(vma, next)) && !next->used) {
-               rb_erase(&next->tree, &vmm->free);
-               list_del(&next->head);
                vma->size += next->size;
-               kfree(next);
+               nvkm_vmm_free_delete(vmm, next);
        }
 
        nvkm_vmm_free_insert(vmm, vma);
@@ -1250,7 +1329,7 @@ nvkm_vmm_put_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma)
        }
 
        /* Remove VMA from the list of allocated nodes. */
-       rb_erase(&vma->tree, &vmm->root);
+       nvkm_vmm_node_remove(vmm, vma);
 
        /* Merge VMA back into the free list. */
        vma->page = NVKM_VMA_PAGE_NONE;
@@ -1357,7 +1436,7 @@ nvkm_vmm_get_locked(struct nvkm_vmm *vmm, bool getref, bool mapref, bool sparse,
                        tail = ALIGN_DOWN(tail, vmm->func->page_block);
 
                if (addr <= tail && tail - addr >= size) {
-                       rb_erase(&this->tree, &vmm->free);
+                       nvkm_vmm_free_remove(vmm, this);
                        vma = this;
                        break;
                }
index 1a3b0a3724ca76ec697f8ab9948bb854847f2b2d..42ad326521a3391a6bd6442eb4a2630842002fd1 100644 (file)
@@ -157,6 +157,8 @@ int nvkm_vmm_ctor(const struct nvkm_vmm_func *, struct nvkm_mmu *,
                  u32 pd_header, u64 addr, u64 size, struct lock_class_key *,
                  const char *name, struct nvkm_vmm *);
 struct nvkm_vma *nvkm_vmm_node_search(struct nvkm_vmm *, u64 addr);
+struct nvkm_vma *nvkm_vmm_node_split(struct nvkm_vmm *, struct nvkm_vma *,
+                                    u64 addr, u64 size);
 int nvkm_vmm_get_locked(struct nvkm_vmm *, bool getref, bool mapref,
                        bool sparse, u8 page, u8 align, u64 size,
                        struct nvkm_vma **pvma);
@@ -165,7 +167,6 @@ void nvkm_vmm_unmap_locked(struct nvkm_vmm *, struct nvkm_vma *);
 void nvkm_vmm_unmap_region(struct nvkm_vmm *vmm, struct nvkm_vma *vma);
 
 struct nvkm_vma *nvkm_vma_tail(struct nvkm_vma *, u64 tail);
-void nvkm_vmm_node_insert(struct nvkm_vmm *, struct nvkm_vma *);
 
 int nv04_vmm_new_(const struct nvkm_vmm_func *, struct nvkm_mmu *, u32,
                  u64, u64, void *, u32, struct lock_class_key *,
@@ -200,6 +201,8 @@ int gp100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
 int gp100_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
 void gp100_vmm_flush(struct nvkm_vmm *, int);
 
+int gv100_vmm_join(struct nvkm_vmm *, struct nvkm_memory *);
+
 int nv04_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
                 struct lock_class_key *, const char *, struct nvkm_vmm **);
 int nv41_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
@@ -239,6 +242,9 @@ int gp10b_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
 int gv100_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
                  struct lock_class_key *, const char *,
                  struct nvkm_vmm **);
+int tu104_vmm_new(struct nvkm_mmu *, u64, u64, void *, u32,
+                 struct lock_class_key *, const char *,
+                 struct nvkm_vmm **);
 
 #define VMM_PRINT(l,v,p,f,a...) do {                                           \
        struct nvkm_vmm *_vmm = (v);                                           \
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu104.c
new file mode 100644 (file)
index 0000000..adaadd9
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "vmm.h"
+
+#include <subdev/timer.h>
+
+static void
+tu104_vmm_flush(struct nvkm_vmm *vmm, int depth)
+{
+       struct nvkm_subdev *subdev = &vmm->mmu->subdev;
+       struct nvkm_device *device = subdev->device;
+       u32 type = depth << 24; /*XXX: not confirmed */
+
+       type = 0x00000001; /* PAGE_ALL */
+       if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
+               type |= 0x00000004; /* HUB_ONLY */
+
+       mutex_lock(&subdev->mutex);
+
+       nvkm_wr32(device, 0xb830a0, vmm->pd->pt[0]->addr >> 8);
+       nvkm_wr32(device, 0xb830a4, 0x00000000);
+       nvkm_wr32(device, 0x100e68, 0x00000000);
+       nvkm_wr32(device, 0xb830b0, 0x80000000 | type);
+
+       nvkm_msec(device, 2000,
+               if (!(nvkm_rd32(device, 0xb830b0) & 0x80000000))
+                       break;
+       );
+
+       mutex_unlock(&subdev->mutex);
+}
+
+static const struct nvkm_vmm_func
+tu104_vmm = {
+       .join = gv100_vmm_join,
+       .part = gf100_vmm_part,
+       .aper = gf100_vmm_aper,
+       .valid = gp100_vmm_valid,
+       .flush = tu104_vmm_flush,
+       .page = {
+               { 47, &gp100_vmm_desc_16[4], NVKM_VMM_PAGE_Sxxx },
+               { 38, &gp100_vmm_desc_16[3], NVKM_VMM_PAGE_Sxxx },
+               { 29, &gp100_vmm_desc_16[2], NVKM_VMM_PAGE_Sxxx },
+               { 21, &gp100_vmm_desc_16[1], NVKM_VMM_PAGE_SVxC },
+               { 16, &gp100_vmm_desc_16[0], NVKM_VMM_PAGE_SVxC },
+               { 12, &gp100_vmm_desc_12[0], NVKM_VMM_PAGE_SVHx },
+               {}
+       }
+};
+
+int
+tu104_vmm_new(struct nvkm_mmu *mmu, u64 addr, u64 size,
+             void *argv, u32 argc, struct lock_class_key *key,
+             const char *name, struct nvkm_vmm **pvmm)
+{
+       return nv04_vmm_new_(&tu104_vmm, mmu, 0, addr, size,
+                            argv, argc, key, name, pvmm);
+}
index 1f7a3c1a7f5061b74e89febd1213b493bacab9b6..84a2f243ed9bd16a59bf752f1f01602c72519c03 100644 (file)
@@ -59,10 +59,10 @@ gp102_run_secure_scrub(struct nvkm_secboot *sb)
 
        nvkm_debug(subdev, "running VPR scrubber binary on NVDEC...\n");
 
-       engine = nvkm_engine_ref(&device->nvdec->engine);
+       engine = nvkm_engine_ref(&device->nvdec[0]->engine);
        if (IS_ERR(engine))
                return PTR_ERR(engine);
-       falcon = device->nvdec->falcon;
+       falcon = device->nvdec[0]->falcon;
 
        nvkm_falcon_get(falcon, &sb->subdev);
 
index 36de23d12ae460e336d1f4917434881afe26a5a5..dd922033628c236cfec38f3e91d49aa9ba886e78 100644 (file)
  */
 #include "priv.h"
 
+s64
+nvkm_timer_wait_test(struct nvkm_timer_wait *wait)
+{
+       struct nvkm_subdev *subdev = &wait->tmr->subdev;
+       u64 time = nvkm_timer_read(wait->tmr);
+
+       if (wait->reads == 0) {
+               wait->time0 = time;
+               wait->time1 = time;
+       }
+
+       if (wait->time1 == time) {
+               if (wait->reads++ == 16) {
+                       nvkm_fatal(subdev, "stalled at %016llx\n", time);
+                       return -ETIMEDOUT;
+               }
+       } else {
+               wait->time1 = time;
+               wait->reads = 1;
+       }
+
+       if (wait->time1 - wait->time0 > wait->limit)
+               return -ETIMEDOUT;
+
+       return wait->time1 - wait->time0;
+}
+
+void
+nvkm_timer_wait_init(struct nvkm_device *device, u64 nsec,
+                    struct nvkm_timer_wait *wait)
+{
+       wait->tmr = device->timer;
+       wait->limit = nsec;
+       wait->reads = 0;
+}
+
 u64
 nvkm_timer_read(struct nvkm_timer *tmr)
 {
index 4f1f3e890650601a4514e2aaa84805d346bb8d1b..39081eadfd84cd29422c612ae715593bb8940b0c 100644 (file)
@@ -86,7 +86,7 @@ gk104_top_oneinit(struct nvkm_top *top)
                case 0x0000000d: A_(SEC2  ); break;
                case 0x0000000e: B_(NVENC ); break;
                case 0x0000000f: A_(NVENC1); break;
-               case 0x00000010: A_(NVDEC ); break;
+               case 0x00000010: B_(NVDEC ); break;
                case 0x00000013: B_(CE    ); break;
                        break;
                default:
index 6020c30a33b39ab696d7f820f14d951c4c483f19..3f3537719beb2eddaa6c132236da3a8f2ff0bdc7 100644 (file)
@@ -90,6 +90,18 @@ config DRM_PANEL_LG_LG4573
          Say Y here if you want to enable support for LG4573 RGB panel.
          To compile this driver as a module, choose M here.
 
+config DRM_PANEL_OLIMEX_LCD_OLINUXINO
+       tristate "Olimex LCD-OLinuXino panel"
+       depends on OF
+       depends on I2C
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         The panel is used with different sizes LCDs, from 480x272 to
+         1280x800, and 24 bit per pixel.
+
+         Say Y here if you want to enable support for Olimex Ltd.
+         LCD-OLinuXino panel.
+
 config DRM_PANEL_ORISETECH_OTM8009A
        tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
        depends on OF
@@ -126,6 +138,12 @@ config DRM_PANEL_RAYDIUM_RM68200
          Say Y here if you want to enable support for Raydium RM68200
          720x1280 DSI video mode panel.
 
+config DRM_PANEL_SAMSUNG_S6D16D0
+       tristate "Samsung S6D16D0 DSI video mode panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       select VIDEOMODE_HELPERS
+
 config DRM_PANEL_SAMSUNG_S6E3HA2
        tristate "Samsung S6E3HA2 DSI video mode panel"
        depends on OF
@@ -186,4 +204,11 @@ config DRM_PANEL_SITRONIX_ST7789V
          Say Y here if you want to enable support for the Sitronix
          ST7789V controller for 240x320 LCD panels
 
+config DRM_PANEL_TRULY_NT35597_WQXGA
+       tristate "Truly WQXGA"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       help
+         Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
+         Video Mode panel
 endmenu
index 5ccaaa9d13af50c0f61865e2bd20b2ca38dda5c6..4396658a7996466c62ae24b8391757044eb0e712 100644 (file)
@@ -7,11 +7,13 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
 obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
 obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
 obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
@@ -19,3 +21,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
+obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
index 72edb334d9976840b0649debe31ea2819b5d6c74..ca4ae45dd307c6cb29b16efb99caa1c1965736a5 100644 (file)
@@ -506,8 +506,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,
 
 static void innolux_panel_del(struct innolux_panel *innolux)
 {
-       if (innolux->base.dev)
-               drm_panel_remove(&innolux->base);
+       drm_panel_remove(&innolux->base);
 }
 
 static int innolux_panel_probe(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
new file mode 100644 (file)
index 0000000..5e8d452
--- /dev/null
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LCD-OLinuXino support for panel driver
+ *
+ * Copyright (C) 2018 Olimex Ltd.
+ *   Author: Stefan Mavrodiev <stefan@olimex.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/crc32.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+#include <video/display_timing.h>
+
+#define LCD_OLINUXINO_HEADER_MAGIC     0x4F4CB727
+#define LCD_OLINUXINO_DATA_LEN         256
+
+struct lcd_olinuxino_mode {
+       u32 pixelclock;
+       u32 hactive;
+       u32 hfp;
+       u32 hbp;
+       u32 hpw;
+       u32 vactive;
+       u32 vfp;
+       u32 vbp;
+       u32 vpw;
+       u32 refresh;
+       u32 flags;
+};
+
+struct lcd_olinuxino_info {
+       char name[32];
+       u32 width_mm;
+       u32 height_mm;
+       u32 bpc;
+       u32 bus_format;
+       u32 bus_flag;
+} __attribute__((__packed__));
+
+struct lcd_olinuxino_eeprom {
+       u32 header;
+       u32 id;
+       char revision[4];
+       u32 serial;
+       struct lcd_olinuxino_info info;
+       u32 num_modes;
+       u8 reserved[180];
+       u32 checksum;
+} __attribute__((__packed__));
+
+struct lcd_olinuxino {
+       struct drm_panel panel;
+       struct device *dev;
+       struct i2c_client *client;
+       struct mutex mutex;
+
+       bool prepared;
+       bool enabled;
+
+       struct backlight_device *backlight;
+       struct regulator *supply;
+       struct gpio_desc *enable_gpio;
+
+       struct lcd_olinuxino_eeprom eeprom;
+};
+
+static inline struct lcd_olinuxino *to_lcd_olinuxino(struct drm_panel *panel)
+{
+       return container_of(panel, struct lcd_olinuxino, panel);
+}
+
+static int lcd_olinuxino_disable(struct drm_panel *panel)
+{
+       struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+       if (!lcd->enabled)
+               return 0;
+
+       backlight_disable(lcd->backlight);
+
+       lcd->enabled = false;
+
+       return 0;
+}
+
+static int lcd_olinuxino_unprepare(struct drm_panel *panel)
+{
+       struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+       if (!lcd->prepared)
+               return 0;
+
+       gpiod_set_value_cansleep(lcd->enable_gpio, 0);
+       regulator_disable(lcd->supply);
+
+       lcd->prepared = false;
+
+       return 0;
+}
+
+static int lcd_olinuxino_prepare(struct drm_panel *panel)
+{
+       struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+       int ret;
+
+       if (lcd->prepared)
+               return 0;
+
+       ret = regulator_enable(lcd->supply);
+       if (ret < 0)
+               return ret;
+
+       gpiod_set_value_cansleep(lcd->enable_gpio, 1);
+       lcd->prepared = true;
+
+       return 0;
+}
+
+static int lcd_olinuxino_enable(struct drm_panel *panel)
+{
+       struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+       if (lcd->enabled)
+               return 0;
+
+       backlight_enable(lcd->backlight);
+
+       lcd->enabled = true;
+
+       return 0;
+}
+
+static int lcd_olinuxino_get_modes(struct drm_panel *panel)
+{
+       struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+       struct drm_connector *connector = lcd->panel.connector;
+       struct lcd_olinuxino_info *lcd_info = &lcd->eeprom.info;
+       struct drm_device *drm = lcd->panel.drm;
+       struct lcd_olinuxino_mode *lcd_mode;
+       struct drm_display_mode *mode;
+       u32 i, num = 0;
+
+       for (i = 0; i < lcd->eeprom.num_modes; i++) {
+               lcd_mode = (struct lcd_olinuxino_mode *)
+                          &lcd->eeprom.reserved[i * sizeof(*lcd_mode)];
+
+               mode = drm_mode_create(drm);
+               if (!mode) {
+                       dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
+                               lcd_mode->hactive,
+                               lcd_mode->vactive,
+                               lcd_mode->refresh);
+                               continue;
+               }
+
+               mode->clock = lcd_mode->pixelclock;
+               mode->hdisplay = lcd_mode->hactive;
+               mode->hsync_start = lcd_mode->hactive + lcd_mode->hfp;
+               mode->hsync_end = lcd_mode->hactive + lcd_mode->hfp +
+                                 lcd_mode->hpw;
+               mode->htotal = lcd_mode->hactive + lcd_mode->hfp +
+                              lcd_mode->hpw + lcd_mode->hbp;
+               mode->vdisplay = lcd_mode->vactive;
+               mode->vsync_start = lcd_mode->vactive + lcd_mode->vfp;
+               mode->vsync_end = lcd_mode->vactive + lcd_mode->vfp +
+                                 lcd_mode->vpw;
+               mode->vtotal = lcd_mode->vactive + lcd_mode->vfp +
+                              lcd_mode->vpw + lcd_mode->vbp;
+               mode->vrefresh = lcd_mode->refresh;
+
+               /* Always make the first mode preferred */
+               if (i == 0)
+                       mode->type |= DRM_MODE_TYPE_PREFERRED;
+               mode->type |= DRM_MODE_TYPE_DRIVER;
+
+               drm_mode_set_name(mode);
+               drm_mode_probed_add(connector, mode);
+
+               num++;
+       }
+
+       memcpy(connector->display_info.name, lcd_info->name, 32);
+       connector->display_info.width_mm = lcd_info->width_mm;
+       connector->display_info.height_mm = lcd_info->height_mm;
+       connector->display_info.bpc = lcd_info->bpc;
+
+       if (lcd_info->bus_format)
+               drm_display_info_set_bus_formats(&connector->display_info,
+                                                &lcd_info->bus_format, 1);
+       connector->display_info.bus_flags = lcd_info->bus_flag;
+
+       return num;
+}
+
+static const struct drm_panel_funcs lcd_olinuxino_funcs = {
+       .disable = lcd_olinuxino_disable,
+       .unprepare = lcd_olinuxino_unprepare,
+       .prepare = lcd_olinuxino_prepare,
+       .enable = lcd_olinuxino_enable,
+       .get_modes = lcd_olinuxino_get_modes,
+};
+
+static int lcd_olinuxino_probe(struct i2c_client *client,
+                              const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct lcd_olinuxino *lcd;
+       u32 checksum, i;
+       int ret = 0;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+                                    I2C_FUNC_SMBUS_READ_I2C_BLOCK))
+               return -ENODEV;
+
+       lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
+       if (!lcd)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, lcd);
+       lcd->dev = dev;
+       lcd->client = client;
+
+       mutex_init(&lcd->mutex);
+
+       /* Copy data into buffer */
+       for (i = 0; i < LCD_OLINUXINO_DATA_LEN; i += I2C_SMBUS_BLOCK_MAX) {
+               mutex_lock(&lcd->mutex);
+               ret = i2c_smbus_read_i2c_block_data(client,
+                                                   i,
+                                                   I2C_SMBUS_BLOCK_MAX,
+                                                   (u8 *)&lcd->eeprom + i);
+               mutex_unlock(&lcd->mutex);
+               if (ret < 0) {
+                       dev_err(dev, "error reading from device at %02x\n", i);
+                       return ret;
+               }
+       }
+
+       /* Check configuration checksum */
+       checksum = ~crc32(~0, (u8 *)&lcd->eeprom, 252);
+       if (checksum != lcd->eeprom.checksum) {
+               dev_err(dev, "configuration checksum does not match!\n");
+               return -EINVAL;
+       }
+
+       /* Check magic header */
+       if (lcd->eeprom.header != LCD_OLINUXINO_HEADER_MAGIC) {
+               dev_err(dev, "magic header does not match\n");
+               return -EINVAL;
+       }
+
+       dev_info(dev, "Detected %s, Rev. %s, Serial: %08x\n",
+                lcd->eeprom.info.name,
+                lcd->eeprom.revision,
+                lcd->eeprom.serial);
+
+       /*
+        * The eeprom can hold up to 4 modes.
+        * If the stored value is bigger, overwrite it.
+        */
+       if (lcd->eeprom.num_modes > 4) {
+               dev_warn(dev, "invalid number of modes, falling back to 4\n");
+               lcd->eeprom.num_modes = 4;
+       }
+
+       lcd->enabled = false;
+       lcd->prepared = false;
+
+       lcd->supply = devm_regulator_get(dev, "power");
+       if (IS_ERR(lcd->supply))
+               return PTR_ERR(lcd->supply);
+
+       lcd->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(lcd->enable_gpio))
+               return PTR_ERR(lcd->enable_gpio);
+
+       lcd->backlight = devm_of_find_backlight(dev);
+       if (IS_ERR(lcd->backlight))
+               return PTR_ERR(lcd->backlight);
+
+       drm_panel_init(&lcd->panel);
+       lcd->panel.dev = dev;
+       lcd->panel.funcs = &lcd_olinuxino_funcs;
+
+       return drm_panel_add(&lcd->panel);
+}
+
+static int lcd_olinuxino_remove(struct i2c_client *client)
+{
+       struct lcd_olinuxino *panel = i2c_get_clientdata(client);
+
+       drm_panel_remove(&panel->panel);
+
+       lcd_olinuxino_disable(&panel->panel);
+       lcd_olinuxino_unprepare(&panel->panel);
+
+       return 0;
+}
+
+static const struct of_device_id lcd_olinuxino_of_ids[] = {
+       { .compatible = "olimex,lcd-olinuxino" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lcd_olinuxino_of_ids);
+
+static struct i2c_driver lcd_olinuxino_driver = {
+       .driver = {
+               .name = "lcd_olinuxino",
+               .of_match_table = lcd_olinuxino_of_ids,
+       },
+       .probe = lcd_olinuxino_probe,
+       .remove = lcd_olinuxino_remove,
+};
+
+module_i2c_driver(lcd_olinuxino_driver);
+
+MODULE_AUTHOR("Stefan Mavrodiev <stefan@olimex.com>");
+MODULE_DESCRIPTION("LCD-OLinuXino driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
new file mode 100644 (file)
index 0000000..33c22ee
--- /dev/null
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MIPI-DSI Samsung s6d16d0 panel driver. This is a 864x480
+ * AMOLED panel with a command-only DSI interface.
+ */
+
+#include <drm/drm_modes.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+
+struct s6d16d0 {
+       struct device *dev;
+       struct drm_panel panel;
+       struct regulator *supply;
+       struct gpio_desc *reset_gpio;
+};
+
+/*
+ * The timings are not very helpful as the display is used in
+ * command mode.
+ */
+static const struct drm_display_mode samsung_s6d16d0_mode = {
+       /* HS clock, (htotal*vtotal*vrefresh)/1000 */
+       .clock = 420160,
+       .hdisplay = 864,
+       .hsync_start = 864 + 154,
+       .hsync_end = 864 + 154 + 16,
+       .htotal = 864 + 154 + 16 + 32,
+       .vdisplay = 480,
+       .vsync_start = 480 + 1,
+       .vsync_end = 480 + 1 + 1,
+       .vtotal = 480 + 1 + 1 + 1,
+       /*
+        * This depends on the clocking HS vs LP rate, this value
+        * is calculated as:
+        * vrefresh = (clock * 1000) / (htotal*vtotal)
+        */
+       .vrefresh = 816,
+       .width_mm = 84,
+       .height_mm = 48,
+};
+
+static inline struct s6d16d0 *panel_to_s6d16d0(struct drm_panel *panel)
+{
+       return container_of(panel, struct s6d16d0, panel);
+}
+
+static int s6d16d0_unprepare(struct drm_panel *panel)
+{
+       struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+       int ret;
+
+       /* Enter sleep mode */
+       ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n",
+                             ret);
+               return ret;
+       }
+
+       /* Assert RESET */
+       gpiod_set_value_cansleep(s6->reset_gpio, 1);
+       regulator_disable(s6->supply);
+
+       return 0;
+}
+
+static int s6d16d0_prepare(struct drm_panel *panel)
+{
+       struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+       int ret;
+
+       ret = regulator_enable(s6->supply);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret);
+               return ret;
+       }
+
+       /* Assert RESET */
+       gpiod_set_value_cansleep(s6->reset_gpio, 1);
+       udelay(10);
+       /* De-assert RESET */
+       gpiod_set_value_cansleep(s6->reset_gpio, 0);
+       msleep(120);
+
+       /* Enabe tearing mode: send TE (tearing effect) at VBLANK */
+       ret = mipi_dsi_dcs_set_tear_on(dsi,
+                                      MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n",
+                             ret);
+               return ret;
+       }
+       /* Exit sleep mode and power on */
+       ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n",
+                             ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6d16d0_enable(struct drm_panel *panel)
+{
+       struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+       int ret;
+
+       ret = mipi_dsi_dcs_set_display_on(dsi);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n",
+                             ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6d16d0_disable(struct drm_panel *panel)
+{
+       struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+       int ret;
+
+       ret = mipi_dsi_dcs_set_display_off(dsi);
+       if (ret) {
+               DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n",
+                             ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6d16d0_get_modes(struct drm_panel *panel)
+{
+       struct drm_connector *connector = panel->connector;
+       struct drm_display_mode *mode;
+
+       strncpy(connector->display_info.name, "Samsung S6D16D0\0",
+               DRM_DISPLAY_INFO_LEN);
+
+       mode = drm_mode_duplicate(panel->drm, &samsung_s6d16d0_mode);
+       if (!mode) {
+               DRM_ERROR("bad mode or failed to add mode\n");
+               return -EINVAL;
+       }
+       drm_mode_set_name(mode);
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+
+       drm_mode_probed_add(connector, mode);
+
+       return 1; /* Number of modes */
+}
+
+static const struct drm_panel_funcs s6d16d0_drm_funcs = {
+       .disable = s6d16d0_disable,
+       .unprepare = s6d16d0_unprepare,
+       .prepare = s6d16d0_prepare,
+       .enable = s6d16d0_enable,
+       .get_modes = s6d16d0_get_modes,
+};
+
+static int s6d16d0_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct s6d16d0 *s6;
+       int ret;
+
+       s6 = devm_kzalloc(dev, sizeof(struct s6d16d0), GFP_KERNEL);
+       if (!s6)
+               return -ENOMEM;
+
+       mipi_dsi_set_drvdata(dsi, s6);
+       s6->dev = dev;
+
+       dsi->lanes = 2;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->hs_rate = 420160000;
+       dsi->lp_rate = 19200000;
+       /*
+        * This display uses command mode so no MIPI_DSI_MODE_VIDEO
+        * or MIPI_DSI_MODE_VIDEO_SYNC_PULSE
+        *
+        * As we only send commands we do not need to be continuously
+        * clocked.
+        */
+       dsi->mode_flags =
+               MIPI_DSI_CLOCK_NON_CONTINUOUS |
+               MIPI_DSI_MODE_EOT_PACKET;
+
+       s6->supply = devm_regulator_get(dev, "vdd1");
+       if (IS_ERR(s6->supply))
+               return PTR_ERR(s6->supply);
+
+       /* This asserts RESET by default */
+       s6->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                GPIOD_OUT_HIGH);
+       if (IS_ERR(s6->reset_gpio)) {
+               ret = PTR_ERR(s6->reset_gpio);
+               if (ret != -EPROBE_DEFER)
+                       DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
+                                     ret);
+               return ret;
+       }
+
+       drm_panel_init(&s6->panel);
+       s6->panel.dev = dev;
+       s6->panel.funcs = &s6d16d0_drm_funcs;
+
+       ret = drm_panel_add(&s6->panel);
+       if (ret < 0)
+               return ret;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0)
+               drm_panel_remove(&s6->panel);
+
+       return ret;
+}
+
+static int s6d16d0_remove(struct mipi_dsi_device *dsi)
+{
+       struct s6d16d0 *s6 = mipi_dsi_get_drvdata(dsi);
+
+       mipi_dsi_detach(dsi);
+       drm_panel_remove(&s6->panel);
+
+       return 0;
+}
+
+static const struct of_device_id s6d16d0_of_match[] = {
+       { .compatible = "samsung,s6d16d0" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, s6d16d0_of_match);
+
+static struct mipi_dsi_driver s6d16d0_driver = {
+       .probe = s6d16d0_probe,
+       .remove = s6d16d0_remove,
+       .driver = {
+               .name = "panel-samsung-s6d16d0",
+               .of_match_table = s6d16d0_of_match,
+       },
+};
+module_mipi_dsi_driver(s6d16d0_driver);
+
+MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("MIPI-DSI s6d16d0 Panel Driver");
+MODULE_LICENSE("GPL v2");
index 75f92539055104c14aba1fa9e42f39b71c1f3467..2d99e28ff117f078bd767dbb27e2c8baf13f0f0a 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2017 NXP Semiconductors.
  * Author: Marco Franchi <marco.franchi@nxp.com>
  *
  * Based on Panel Simple driver by Thierry Reding <treding@nvidia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
  */
 
 #include <linux/backlight.h>
@@ -366,6 +363,6 @@ static struct platform_driver seiko_panel_platform_driver = {
 };
 module_platform_driver(seiko_panel_platform_driver);
 
-MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com");
+MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com>");
 MODULE_DESCRIPTION("Seiko 43WVF1G panel driver");
 MODULE_LICENSE("GPL v2");
index a04ffb3b21742a834c44c4770e2760f8139053dd..9c69e739a524dd59d84f5758cc210686e4f797b4 100644 (file)
@@ -618,6 +618,30 @@ static const struct panel_desc auo_g070vvn01 = {
        },
 };
 
+static const struct drm_display_mode auo_g101evn010_mode = {
+       .clock = 68930,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 82,
+       .hsync_end = 1280 + 82 + 2,
+       .htotal = 1280 + 82 + 2 + 84,
+       .vdisplay = 800,
+       .vsync_start = 800 + 8,
+       .vsync_end = 800 + 8 + 2,
+       .vtotal = 800 + 8 + 2 + 6,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_g101evn010 = {
+       .modes = &auo_g101evn010_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 216,
+               .height = 135,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode auo_g104sn02_mode = {
        .clock = 40000,
        .hdisplay = 800,
@@ -782,16 +806,38 @@ static const struct panel_desc avic_tm070ddh03 = {
        },
 };
 
+static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
+       .clock = 30000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 40,
+       .hsync_end = 800 + 40 + 48,
+       .htotal = 800 + 40 + 48 + 40,
+       .vdisplay = 480,
+       .vsync_start = 480 + 13,
+       .vsync_end = 480 + 13 + 3,
+       .vtotal = 480 + 13 + 3 + 29,
+};
+
+static const struct panel_desc bananapi_s070wv20_ct16 = {
+       .modes = &bananapi_s070wv20_ct16_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 154,
+               .height = 86,
+       },
+};
+
 static const struct drm_display_mode boe_hv070wsa_mode = {
-       .clock = 40800,
+       .clock = 42105,
        .hdisplay = 1024,
-       .hsync_start = 1024 + 90,
-       .hsync_end = 1024 + 90 + 90,
-       .htotal = 1024 + 90 + 90 + 90,
+       .hsync_start = 1024 + 30,
+       .hsync_end = 1024 + 30 + 30,
+       .htotal = 1024 + 30 + 30 + 30,
        .vdisplay = 600,
-       .vsync_start = 600 + 3,
-       .vsync_end = 600 + 3 + 4,
-       .vtotal = 600 + 3 + 4 + 3,
+       .vsync_start = 600 + 10,
+       .vsync_end = 600 + 10 + 10,
+       .vtotal = 600 + 10 + 10 + 10,
        .vrefresh = 60,
 };
 
@@ -846,6 +892,55 @@ static const struct panel_desc boe_nv101wxmn51 = {
        },
 };
 
+static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = {
+       .clock = 9000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 5,
+       .hsync_end = 480 + 5 + 5,
+       .htotal = 480 + 5 + 5 + 40,
+       .vdisplay = 272,
+       .vsync_start = 272 + 8,
+       .vsync_end = 272 + 8 + 8,
+       .vtotal = 272 + 8 + 8 + 8,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc cdtech_s043wq26h_ct7 = {
+       .modes = &cdtech_s043wq26h_ct7_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 95,
+               .height = 54,
+       },
+       .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
+};
+
+static const struct drm_display_mode cdtech_s070wv95_ct16_mode = {
+       .clock = 35000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 40,
+       .hsync_end = 800 + 40 + 40,
+       .htotal = 800 + 40 + 40 + 48,
+       .vdisplay = 480,
+       .vsync_start = 480 + 29,
+       .vsync_end = 480 + 29 + 13,
+       .vtotal = 480 + 29 + 13 + 3,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc cdtech_s070wv95_ct16 = {
+       .modes = &cdtech_s070wv95_ct16_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 154,
+               .height = 85,
+       },
+};
+
 static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
        .clock = 66770,
        .hdisplay = 800,
@@ -971,6 +1066,36 @@ static const struct panel_desc dlc_dlc0700yzg_1 = {
        .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
 };
 
+static const struct display_timing dlc_dlc1010gig_timing = {
+       .pixelclock = { 68900000, 71100000, 73400000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 43, 53, 63 },
+       .hback_porch = { 43, 53, 63 },
+       .hsync_len = { 44, 54, 64 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 5, 8, 11 },
+       .vback_porch = { 5, 8, 11 },
+       .vsync_len = { 5, 7, 11 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc dlc_dlc1010gig = {
+       .timings = &dlc_dlc1010gig_timing,
+       .num_timings = 1,
+       .bpc = 8,
+       .size = {
+               .width = 216,
+               .height = 135,
+       },
+       .delay = {
+               .prepare = 60,
+               .enable = 150,
+               .disable = 100,
+               .unprepare = 60,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+};
+
 static const struct drm_display_mode edt_et057090dhu_mode = {
        .clock = 25175,
        .hdisplay = 640,
@@ -2334,6 +2459,33 @@ static const struct panel_desc winstar_wf35ltiacd = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
+static const struct drm_display_mode arm_rtsm_mode[] = {
+       {
+               .clock = 65000,
+               .hdisplay = 1024,
+               .hsync_start = 1024 + 24,
+               .hsync_end = 1024 + 24 + 136,
+               .htotal = 1024 + 24 + 136 + 160,
+               .vdisplay = 768,
+               .vsync_start = 768 + 3,
+               .vsync_end = 768 + 3 + 6,
+               .vtotal = 768 + 3 + 6 + 29,
+               .vrefresh = 60,
+               .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+       },
+};
+
+static const struct panel_desc arm_rtsm = {
+       .modes = arm_rtsm_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 400,
+               .height = 300,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
 static const struct of_device_id platform_of_match[] = {
        {
                .compatible = "ampire,am-480272h3tmqw-t01h",
@@ -2341,6 +2493,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "ampire,am800480r3tmqwa1h",
                .data = &ampire_am800480r3tmqwa1h,
+       }, {
+               .compatible = "arm,rtsm-display",
+               .data = &arm_rtsm,
        }, {
                .compatible = "auo,b101aw03",
                .data = &auo_b101aw03,
@@ -2362,6 +2517,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,g070vvn01",
                .data = &auo_g070vvn01,
+       }, {
+               .compatible = "auo,g101evn010",
+               .data = &auo_g101evn010,
        }, {
                .compatible = "auo,g104sn02",
                .data = &auo_g104sn02,
@@ -2380,12 +2538,21 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "avic,tm070ddh03",
                .data = &avic_tm070ddh03,
+       }, {
+               .compatible = "bananapi,s070wv20-ct16",
+               .data = &bananapi_s070wv20_ct16,
        }, {
                .compatible = "boe,hv070wsa-100",
                .data = &boe_hv070wsa
        }, {
                .compatible = "boe,nv101wxmn51",
                .data = &boe_nv101wxmn51,
+       }, {
+               .compatible = "cdtech,s043wq26h-ct7",
+               .data = &cdtech_s043wq26h_ct7,
+       }, {
+               .compatible = "cdtech,s070wv95-ct16",
+               .data = &cdtech_s070wv95_ct16,
        }, {
                .compatible = "chunghwa,claa070wp03xg",
                .data = &chunghwa_claa070wp03xg,
@@ -2401,6 +2568,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "dlc,dlc0700yzg-1",
                .data = &dlc_dlc0700yzg_1,
+       }, {
+               .compatible = "dlc,dlc1010gig",
+               .data = &dlc_dlc1010gig,
        }, {
                .compatible = "edt,et057090dhu",
                .data = &edt_et057090dhu,
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c
new file mode 100644 (file)
index 0000000..fc2a66c
--- /dev/null
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_mipi_dsi.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+static const char * const regulator_names[] = {
+       "vdda",
+       "vdispp",
+       "vdispn",
+};
+
+static unsigned long const regulator_enable_loads[] = {
+       62000,
+       100000,
+       100000,
+};
+
+static unsigned long const regulator_disable_loads[] = {
+       80,
+       100,
+       100,
+};
+
+struct cmd_set {
+       u8 commands[4];
+       u8 size;
+};
+
+struct nt35597_config {
+       u32 width_mm;
+       u32 height_mm;
+       const char *panel_name;
+       const struct cmd_set *panel_on_cmds;
+       u32 num_on_cmds;
+       const struct drm_display_mode *dm;
+};
+
+struct truly_nt35597 {
+       struct device *dev;
+       struct drm_panel panel;
+
+       struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
+
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *mode_gpio;
+
+       struct backlight_device *backlight;
+
+       struct mipi_dsi_device *dsi[2];
+
+       const struct nt35597_config *config;
+       bool prepared;
+       bool enabled;
+};
+
+static inline struct truly_nt35597 *panel_to_ctx(struct drm_panel *panel)
+{
+       return container_of(panel, struct truly_nt35597, panel);
+}
+
+static const struct cmd_set qcom_2k_panel_magic_cmds[] = {
+       /* CMD2_P0 */
+       { { 0xff, 0x20 }, 2 },
+       { { 0xfb, 0x01 }, 2 },
+       { { 0x00, 0x01 }, 2 },
+       { { 0x01, 0x55 }, 2 },
+       { { 0x02, 0x45 }, 2 },
+       { { 0x05, 0x40 }, 2 },
+       { { 0x06, 0x19 }, 2 },
+       { { 0x07, 0x1e }, 2 },
+       { { 0x0b, 0x73 }, 2 },
+       { { 0x0c, 0x73 }, 2 },
+       { { 0x0e, 0xb0 }, 2 },
+       { { 0x0f, 0xae }, 2 },
+       { { 0x11, 0xb8 }, 2 },
+       { { 0x13, 0x00 }, 2 },
+       { { 0x58, 0x80 }, 2 },
+       { { 0x59, 0x01 }, 2 },
+       { { 0x5a, 0x00 }, 2 },
+       { { 0x5b, 0x01 }, 2 },
+       { { 0x5c, 0x80 }, 2 },
+       { { 0x5d, 0x81 }, 2 },
+       { { 0x5e, 0x00 }, 2 },
+       { { 0x5f, 0x01 }, 2 },
+       { { 0x72, 0x11 }, 2 },
+       { { 0x68, 0x03 }, 2 },
+       /* CMD2_P4 */
+       { { 0xFF, 0x24 }, 2 },
+       { { 0xFB, 0x01 }, 2 },
+       { { 0x00, 0x1C }, 2 },
+       { { 0x01, 0x0B }, 2 },
+       { { 0x02, 0x0C }, 2 },
+       { { 0x03, 0x01 }, 2 },
+       { { 0x04, 0x0F }, 2 },
+       { { 0x05, 0x10 }, 2 },
+       { { 0x06, 0x10 }, 2 },
+       { { 0x07, 0x10 }, 2 },
+       { { 0x08, 0x89 }, 2 },
+       { { 0x09, 0x8A }, 2 },
+       { { 0x0A, 0x13 }, 2 },
+       { { 0x0B, 0x13 }, 2 },
+       { { 0x0C, 0x15 }, 2 },
+       { { 0x0D, 0x15 }, 2 },
+       { { 0x0E, 0x17 }, 2 },
+       { { 0x0F, 0x17 }, 2 },
+       { { 0x10, 0x1C }, 2 },
+       { { 0x11, 0x0B }, 2 },
+       { { 0x12, 0x0C }, 2 },
+       { { 0x13, 0x01 }, 2 },
+       { { 0x14, 0x0F }, 2 },
+       { { 0x15, 0x10 }, 2 },
+       { { 0x16, 0x10 }, 2 },
+       { { 0x17, 0x10 }, 2 },
+       { { 0x18, 0x89 }, 2 },
+       { { 0x19, 0x8A }, 2 },
+       { { 0x1A, 0x13 }, 2 },
+       { { 0x1B, 0x13 }, 2 },
+       { { 0x1C, 0x15 }, 2 },
+       { { 0x1D, 0x15 }, 2 },
+       { { 0x1E, 0x17 }, 2 },
+       { { 0x1F, 0x17 }, 2 },
+       /* STV */
+       { { 0x20, 0x40 }, 2 },
+       { { 0x21, 0x01 }, 2 },
+       { { 0x22, 0x00 }, 2 },
+       { { 0x23, 0x40 }, 2 },
+       { { 0x24, 0x40 }, 2 },
+       { { 0x25, 0x6D }, 2 },
+       { { 0x26, 0x40 }, 2 },
+       { { 0x27, 0x40 }, 2 },
+       /* Vend */
+       { { 0xE0, 0x00 }, 2 },
+       { { 0xDC, 0x21 }, 2 },
+       { { 0xDD, 0x22 }, 2 },
+       { { 0xDE, 0x07 }, 2 },
+       { { 0xDF, 0x07 }, 2 },
+       { { 0xE3, 0x6D }, 2 },
+       { { 0xE1, 0x07 }, 2 },
+       { { 0xE2, 0x07 }, 2 },
+       /* UD */
+       { { 0x29, 0xD8 }, 2 },
+       { { 0x2A, 0x2A }, 2 },
+       /* CLK */
+       { { 0x4B, 0x03 }, 2 },
+       { { 0x4C, 0x11 }, 2 },
+       { { 0x4D, 0x10 }, 2 },
+       { { 0x4E, 0x01 }, 2 },
+       { { 0x4F, 0x01 }, 2 },
+       { { 0x50, 0x10 }, 2 },
+       { { 0x51, 0x00 }, 2 },
+       { { 0x52, 0x80 }, 2 },
+       { { 0x53, 0x00 }, 2 },
+       { { 0x56, 0x00 }, 2 },
+       { { 0x54, 0x07 }, 2 },
+       { { 0x58, 0x07 }, 2 },
+       { { 0x55, 0x25 }, 2 },
+       /* Reset XDONB */
+       { { 0x5B, 0x43 }, 2 },
+       { { 0x5C, 0x00 }, 2 },
+       { { 0x5F, 0x73 }, 2 },
+       { { 0x60, 0x73 }, 2 },
+       { { 0x63, 0x22 }, 2 },
+       { { 0x64, 0x00 }, 2 },
+       { { 0x67, 0x08 }, 2 },
+       { { 0x68, 0x04 }, 2 },
+       /* Resolution:1440x2560 */
+       { { 0x72, 0x02 }, 2 },
+       /* mux */
+       { { 0x7A, 0x80 }, 2 },
+       { { 0x7B, 0x91 }, 2 },
+       { { 0x7C, 0xD8 }, 2 },
+       { { 0x7D, 0x60 }, 2 },
+       { { 0x7F, 0x15 }, 2 },
+       { { 0x75, 0x15 }, 2 },
+       /* ABOFF */
+       { { 0xB3, 0xC0 }, 2 },
+       { { 0xB4, 0x00 }, 2 },
+       { { 0xB5, 0x00 }, 2 },
+       /* Source EQ */
+       { { 0x78, 0x00 }, 2 },
+       { { 0x79, 0x00 }, 2 },
+       { { 0x80, 0x00 }, 2 },
+       { { 0x83, 0x00 }, 2 },
+       /* FP BP */
+       { { 0x93, 0x0A }, 2 },
+       { { 0x94, 0x0A }, 2 },
+       /* Inversion Type */
+       { { 0x8A, 0x00 }, 2 },
+       { { 0x9B, 0xFF }, 2 },
+       /* IMGSWAP =1 @PortSwap=1 */
+       { { 0x9D, 0xB0 }, 2 },
+       { { 0x9F, 0x63 }, 2 },
+       { { 0x98, 0x10 }, 2 },
+       /* FRM */
+       { { 0xEC, 0x00 }, 2 },
+       /* CMD1 */
+       { { 0xFF, 0x10 }, 2 },
+       /* VBP+VSA=,VFP = 10H */
+       { { 0x3B, 0x03, 0x0A, 0x0A }, 4 },
+       /* FTE on */
+       { { 0x35, 0x00 }, 2 },
+       /* EN_BK =1(auto black) */
+       { { 0xE5, 0x01 }, 2 },
+       /* CMD mode(10) VDO mode(03) */
+       { { 0xBB, 0x03 }, 2 },
+       /* Non Reload MTP */
+       { { 0xFB, 0x01 }, 2 },
+};
+
+static int truly_dcs_write(struct drm_panel *panel, u32 command)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+               ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(ctx->dev,
+                               "cmd 0x%x failed for dsi = %d\n",
+                               command, i);
+               }
+       }
+
+       return ret;
+}
+
+static int truly_dcs_write_buf(struct drm_panel *panel,
+       u32 size, const u8 *buf)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+               ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(ctx->dev,
+                               "failed to tx cmd [%d], err: %d\n", i, ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int truly_35597_power_on(struct truly_nt35597 *ctx)
+{
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
+               ret = regulator_set_load(ctx->supplies[i].consumer,
+                                       regulator_enable_loads[i]);
+               if (ret)
+                       return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Reset sequence of truly panel requires the panel to be
+        * out of reset for 10ms, followed by being held in reset
+        * for 10ms and then out again
+        */
+       gpiod_set_value(ctx->reset_gpio, 0);
+       usleep_range(10000, 20000);
+       gpiod_set_value(ctx->reset_gpio, 1);
+       usleep_range(10000, 20000);
+       gpiod_set_value(ctx->reset_gpio, 0);
+
+       return 0;
+}
+
+static int truly_nt35597_power_off(struct truly_nt35597 *ctx)
+{
+       int ret = 0;
+       int i;
+
+       gpiod_set_value(ctx->reset_gpio, 1);
+
+       for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
+               ret = regulator_set_load(ctx->supplies[i].consumer,
+                               regulator_disable_loads[i]);
+               if (ret) {
+                       DRM_DEV_ERROR(ctx->dev,
+                               "regulator_set_load failed %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "regulator_bulk_disable failed %d\n", ret);
+       }
+       return ret;
+}
+
+static int truly_nt35597_disable(struct drm_panel *panel)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int ret;
+
+       if (!ctx->enabled)
+               return 0;
+
+       if (ctx->backlight) {
+               ret = backlight_disable(ctx->backlight);
+               if (ret < 0)
+                       DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n",
+                               ret);
+       }
+
+       ctx->enabled = false;
+       return 0;
+}
+
+static int truly_nt35597_unprepare(struct drm_panel *panel)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int ret = 0;
+
+       if (!ctx->prepared)
+               return 0;
+
+       ctx->dsi[0]->mode_flags = 0;
+       ctx->dsi[1]->mode_flags = 0;
+
+       ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF);
+       if (ret < 0) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "set_display_off cmd failed ret = %d\n",
+                       ret);
+       }
+
+       /* 120ms delay required here as per DCS spec */
+       msleep(120);
+
+       ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE);
+       if (ret < 0) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "enter_sleep cmd failed ret = %d\n", ret);
+       }
+
+       ret = truly_nt35597_power_off(ctx);
+       if (ret < 0)
+               DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret);
+
+       ctx->prepared = false;
+       return ret;
+}
+
+static int truly_nt35597_prepare(struct drm_panel *panel)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int ret;
+       int i;
+       const struct cmd_set *panel_on_cmds;
+       const struct nt35597_config *config;
+       u32 num_cmds;
+
+       if (ctx->prepared)
+               return 0;
+
+       ret = truly_35597_power_on(ctx);
+       if (ret < 0)
+               return ret;
+
+       ctx->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
+       ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       config = ctx->config;
+       panel_on_cmds = config->panel_on_cmds;
+       num_cmds = config->num_on_cmds;
+
+       for (i = 0; i < num_cmds; i++) {
+               ret = truly_dcs_write_buf(panel,
+                               panel_on_cmds[i].size,
+                                       panel_on_cmds[i].commands);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(ctx->dev,
+                               "cmd set tx failed i = %d ret = %d\n",
+                                       i, ret);
+                       goto power_off;
+               }
+       }
+
+       ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE);
+       if (ret < 0) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "exit_sleep_mode cmd failed ret = %d\n",
+                       ret);
+               goto power_off;
+       }
+
+       /* Per DSI spec wait 120ms after sending exit sleep DCS command */
+       msleep(120);
+
+       ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON);
+       if (ret < 0) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "set_display_on cmd failed ret = %d\n", ret);
+               goto power_off;
+       }
+
+       /* Per DSI spec wait 120ms after sending set_display_on DCS command */
+       msleep(120);
+
+       ctx->prepared = true;
+
+       return 0;
+
+power_off:
+       if (truly_nt35597_power_off(ctx))
+               DRM_DEV_ERROR(ctx->dev, "power_off failed\n");
+       return ret;
+}
+
+static int truly_nt35597_enable(struct drm_panel *panel)
+{
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       int ret;
+
+       if (ctx->enabled)
+               return 0;
+
+       if (ctx->backlight) {
+               ret = backlight_enable(ctx->backlight);
+               if (ret < 0)
+                       DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n",
+                                                 ret);
+       }
+
+       ctx->enabled = true;
+
+       return 0;
+}
+
+static int truly_nt35597_get_modes(struct drm_panel *panel)
+{
+       struct drm_connector *connector = panel->connector;
+       struct truly_nt35597 *ctx = panel_to_ctx(panel);
+       struct drm_display_mode *mode;
+       const struct nt35597_config *config;
+
+       config = ctx->config;
+       mode = drm_mode_create(connector->dev);
+       if (!mode) {
+               DRM_DEV_ERROR(ctx->dev,
+                       "failed to create a new display mode\n");
+               return 0;
+       }
+
+       connector->display_info.width_mm = config->width_mm;
+       connector->display_info.height_mm = config->height_mm;
+       drm_mode_copy(mode, config->dm);
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static const struct drm_panel_funcs truly_nt35597_drm_funcs = {
+       .disable = truly_nt35597_disable,
+       .unprepare = truly_nt35597_unprepare,
+       .prepare = truly_nt35597_prepare,
+       .enable = truly_nt35597_enable,
+       .get_modes = truly_nt35597_get_modes,
+};
+
+static int truly_nt35597_panel_add(struct truly_nt35597 *ctx)
+{
+       struct device *dev = ctx->dev;
+       int ret, i;
+       const struct nt35597_config *config;
+
+       config = ctx->config;
+       for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
+               ctx->supplies[i].supply = regulator_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+                                     ctx->supplies);
+       if (ret < 0)
+               return ret;
+
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->reset_gpio)) {
+               DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
+                       PTR_ERR(ctx->reset_gpio));
+               return PTR_ERR(ctx->reset_gpio);
+       }
+
+       ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->mode_gpio)) {
+               DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n",
+                       PTR_ERR(ctx->mode_gpio));
+               return PTR_ERR(ctx->mode_gpio);
+       }
+
+       /* dual port */
+       gpiod_set_value(ctx->mode_gpio, 0);
+
+       drm_panel_init(&ctx->panel);
+       ctx->panel.dev = dev;
+       ctx->panel.funcs = &truly_nt35597_drm_funcs;
+       drm_panel_add(&ctx->panel);
+
+       return 0;
+}
+
+static const struct drm_display_mode qcom_sdm845_mtp_2k_mode = {
+       .name = "1440x2560",
+       .clock = 268316,
+       .hdisplay = 1440,
+       .hsync_start = 1440 + 200,
+       .hsync_end = 1440 + 200 + 32,
+       .htotal = 1440 + 200 + 32 + 64,
+       .vdisplay = 2560,
+       .vsync_start = 2560 + 8,
+       .vsync_end = 2560 + 8 + 1,
+       .vtotal = 2560 + 8 + 1 + 7,
+       .vrefresh = 60,
+       .flags = 0,
+};
+
+static const struct nt35597_config nt35597_dir = {
+       .width_mm = 74,
+       .height_mm = 131,
+       .panel_name = "qcom_sdm845_mtp_2k_panel",
+       .dm = &qcom_sdm845_mtp_2k_mode,
+       .panel_on_cmds = qcom_2k_panel_magic_cmds,
+       .num_on_cmds = ARRAY_SIZE(qcom_2k_panel_magic_cmds),
+};
+
+static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct truly_nt35597 *ctx;
+       struct mipi_dsi_device *dsi1_device;
+       struct device_node *dsi1;
+       struct mipi_dsi_host *dsi1_host;
+       struct mipi_dsi_device *dsi_dev;
+       int ret = 0;
+       int i;
+
+       const struct mipi_dsi_device_info info = {
+               .type = "trulynt35597",
+               .channel = 0,
+               .node = NULL,
+       };
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+
+       if (!ctx)
+               return -ENOMEM;
+
+       /*
+        * This device represents itself as one with two input ports which are
+        * fed by the output ports of the two DSI controllers . The DSI0 is
+        * the master controller and has most of the panel related info in its
+        * child node.
+        */
+
+       ctx->config = of_device_get_match_data(dev);
+
+       if (!ctx->config) {
+               dev_err(dev, "missing device configuration\n");
+               return -ENODEV;
+       }
+
+       dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
+       if (!dsi1) {
+               DRM_DEV_ERROR(dev,
+                       "failed to get remote node for dsi1_device\n");
+               return -ENODEV;
+       }
+
+       dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
+       of_node_put(dsi1);
+       if (!dsi1_host) {
+               DRM_DEV_ERROR(dev, "failed to find dsi host\n");
+               return -EPROBE_DEFER;
+       }
+
+       /* register the second DSI device */
+       dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info);
+       if (IS_ERR(dsi1_device)) {
+               DRM_DEV_ERROR(dev, "failed to create dsi device\n");
+               return PTR_ERR(dsi1_device);
+       }
+
+       mipi_dsi_set_drvdata(dsi, ctx);
+
+       ctx->dev = dev;
+       ctx->dsi[0] = dsi;
+       ctx->dsi[1] = dsi1_device;
+
+       ret = truly_nt35597_panel_add(ctx);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "failed to add panel\n");
+               goto err_panel_add;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+               dsi_dev = ctx->dsi[i];
+               dsi_dev->lanes = 4;
+               dsi_dev->format = MIPI_DSI_FMT_RGB888;
+               dsi_dev->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
+                       MIPI_DSI_CLOCK_NON_CONTINUOUS;
+               ret = mipi_dsi_attach(dsi_dev);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(dev,
+                               "dsi attach failed i = %d\n", i);
+                       goto err_dsi_attach;
+               }
+       }
+
+       return 0;
+
+err_dsi_attach:
+       drm_panel_remove(&ctx->panel);
+err_panel_add:
+       mipi_dsi_device_unregister(dsi1_device);
+       return ret;
+}
+
+static int truly_nt35597_remove(struct mipi_dsi_device *dsi)
+{
+       struct truly_nt35597 *ctx = mipi_dsi_get_drvdata(dsi);
+
+       if (ctx->dsi[0])
+               mipi_dsi_detach(ctx->dsi[0]);
+       if (ctx->dsi[1]) {
+               mipi_dsi_detach(ctx->dsi[1]);
+               mipi_dsi_device_unregister(ctx->dsi[1]);
+       }
+
+       drm_panel_remove(&ctx->panel);
+       return 0;
+}
+
+static const struct of_device_id truly_nt35597_of_match[] = {
+       {
+               .compatible = "truly,nt35597-2K-display",
+               .data = &nt35597_dir,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, truly_nt35597_of_match);
+
+static struct mipi_dsi_driver truly_nt35597_driver = {
+       .driver = {
+               .name = "panel-truly-nt35597",
+               .of_match_table = truly_nt35597_of_match,
+       },
+       .probe = truly_nt35597_probe,
+       .remove = truly_nt35597_remove,
+};
+module_mipi_dsi_driver(truly_nt35597_driver);
+
+MODULE_DESCRIPTION("Truly NT35597 DSI Panel Driver");
+MODULE_LICENSE("GPL v2");
index 5fa0441bb6df8fea7fd54433a7f7b68cfa28d3be..38c938c9addaf72f86853feb307d2cd62938dd1d 100644 (file)
@@ -55,6 +55,8 @@ int pl111_vexpress_clcd_init(struct device *dev,
                }
        }
 
+       of_node_put(root);
+
        /*
         * If there is a coretile HDLCD and it has a driver,
         * do not mux the CLCD on the motherboard to the DVI.
index 208af9f379144d09fa4dba4ee9f98f3745106cc9..dffc5093ff16b96cbd8f6f4ee0b99670f8032303 100644 (file)
@@ -84,6 +84,7 @@ static int qxl_check_header(struct qxl_ring *ring)
        int ret;
        struct qxl_ring_header *header = &(ring->ring->header);
        unsigned long flags;
+
        spin_lock_irqsave(&ring->lock, flags);
        ret = header->prod - header->cons < header->num_items;
        if (ret == 0)
@@ -97,6 +98,7 @@ int qxl_check_idle(struct qxl_ring *ring)
        int ret;
        struct qxl_ring_header *header = &(ring->ring->header);
        unsigned long flags;
+
        spin_lock_irqsave(&ring->lock, flags);
        ret = header->prod == header->cons;
        spin_unlock_irqrestore(&ring->lock, flags);
@@ -110,6 +112,7 @@ int qxl_ring_push(struct qxl_ring *ring,
        uint8_t *elt;
        int idx, ret;
        unsigned long flags;
+
        spin_lock_irqsave(&ring->lock, flags);
        if (header->prod - header->cons == header->num_items) {
                header->notify_on_cons = header->cons + 1;
@@ -156,6 +159,7 @@ static bool qxl_ring_pop(struct qxl_ring *ring,
        volatile uint8_t *ring_elt;
        int idx;
        unsigned long flags;
+
        spin_lock_irqsave(&ring->lock, flags);
        if (header->cons == header->prod) {
                header->notify_on_prod = header->cons + 1;
@@ -365,7 +369,6 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev)
        wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC);
 }
 
-
 void qxl_io_destroy_primary(struct qxl_device *qdev)
 {
        wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
@@ -373,7 +376,7 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
 }
 
 void qxl_io_create_primary(struct qxl_device *qdev,
-                          unsigned offset, struct qxl_bo *bo)
+                          unsigned int offset, struct qxl_bo *bo)
 {
        struct qxl_surface_create *create;
 
index 15c84068d3fb560c0cb79c3abab9b5363be4dd67..1184225498284daf2add397c54398a95860c9807 100644 (file)
@@ -34,7 +34,6 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
-
 #if defined(CONFIG_DEBUG_FS)
 static int
 qxl_debugfs_irq_received(struct seq_file *m, void *data)
@@ -102,9 +101,9 @@ qxl_debugfs_init(struct drm_minor *minor)
 
 int qxl_debugfs_add_files(struct qxl_device *qdev,
                          struct drm_info_list *files,
-                         unsigned nfiles)
+                         unsigned int nfiles)
 {
-       unsigned i;
+       unsigned int i;
 
        for (i = 0; i < qdev->debugfs_count; i++) {
                if (qdev->debugfs[i].files == files) {
index 94c5aec7192094f57e0fc1e6e635f2c48ce0efe5..a0ee41632d7ef7dc3c4092448029e77408c366cc 100644 (file)
@@ -28,7 +28,6 @@
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-
 #ifndef H_QXL_DEV
 #define H_QXL_DEV
 
index 87d16a0ce01e3a54a73d06e4ff7ddc53c7b0f3b7..ce0b9c40fc212fb88ebc37391a1cf0be2a0a763a 100644 (file)
@@ -253,12 +253,13 @@ static struct mode_size {
 };
 
 static int qxl_add_common_modes(struct drm_connector *connector,
-                                unsigned pwidth,
-                                unsigned pheight)
+                                unsigned int pwidth,
+                                unsigned int pheight)
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode = NULL;
        int i;
+
        for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
                mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,
                                    60, false, false, false);
@@ -315,6 +316,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
        oldcount = qdev->monitors_config->count;
        if (crtc->state->active) {
                struct drm_display_mode *mode = &crtc->mode;
+
                head.width = mode->hdisplay;
                head.height = mode->vdisplay;
                head.x = crtc->x;
@@ -391,9 +393,9 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
 
 static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
                                         struct drm_file *file_priv,
-                                        unsigned flags, unsigned color,
+                                        unsigned int flags, unsigned int color,
                                         struct drm_clip_rect *clips,
-                                        unsigned num_clips)
+                                        unsigned int num_clips)
 {
        /* TODO: vmwgfx where this was cribbed from had locking. Why? */
        struct qxl_device *qdev = fb->dev->dev_private;
@@ -620,10 +622,14 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
                if (ret)
                        goto out_kunmap;
 
-               ret = qxl_release_reserve_list(release, true);
+               ret = qxl_bo_pin(cursor_bo);
                if (ret)
                        goto out_free_bo;
 
+               ret = qxl_release_reserve_list(release, true);
+               if (ret)
+                       goto out_unpin;
+
                ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
                if (ret)
                        goto out_backoff;
@@ -668,15 +674,17 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
        qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
        qxl_release_fence_buffer_objects(release);
 
-       if (old_cursor_bo)
-               qxl_bo_unref(&old_cursor_bo);
-
+       if (old_cursor_bo != NULL)
+               qxl_bo_unpin(old_cursor_bo);
+       qxl_bo_unref(&old_cursor_bo);
        qxl_bo_unref(&cursor_bo);
 
        return;
 
 out_backoff:
        qxl_release_backoff_reserve_list(release);
+out_unpin:
+       qxl_bo_unpin(cursor_bo);
 out_free_bo:
        qxl_bo_unref(&cursor_bo);
 out_kunmap:
@@ -755,7 +763,7 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane,
                }
        }
 
-       ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL);
+       ret = qxl_bo_pin(user_bo);
        if (ret)
                return ret;
 
@@ -917,8 +925,8 @@ free_mem:
 
 static int qxl_conn_get_modes(struct drm_connector *connector)
 {
-       unsigned pwidth = 1024;
-       unsigned pheight = 768;
+       unsigned int pwidth = 1024;
+       unsigned int pheight = 768;
        int ret = 0;
 
        ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
@@ -938,8 +946,8 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
        /* TODO: is this called for user defined modes? (xrandr --add-mode)
         * TODO: check that the mode fits in the framebuffer */
 
-       if(qdev->monitors_config_width == mode->hdisplay &&
-          qdev->monitors_config_height == mode->vdisplay)
+       if (qdev->monitors_config_width == mode->hdisplay &&
+           qdev->monitors_config_height == mode->vdisplay)
                return MODE_OK;
 
        for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
@@ -958,7 +966,6 @@ static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
        return &qxl_output->enc;
 }
 
-
 static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = {
 };
 
@@ -1103,7 +1110,7 @@ int qxl_create_monitors_object(struct qxl_device *qdev)
        }
        qdev->monitors_config_bo = gem_to_qxl_bo(gobj);
 
-       ret = qxl_bo_pin(qdev->monitors_config_bo, QXL_GEM_DOMAIN_VRAM, NULL);
+       ret = qxl_bo_pin(qdev->monitors_config_bo);
        if (ret)
                return ret;
 
index cc5b32e749cefdc28cb6597a63f8edff67e926ad..c408bb83c7a92809532698b19398fd64e7a51ccc 100644 (file)
@@ -25,7 +25,7 @@
 
 static int alloc_clips(struct qxl_device *qdev,
                       struct qxl_release *release,
-                      unsigned num_clips,
+                      unsigned int num_clips,
                       struct qxl_bo **clips_bo)
 {
        int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
@@ -37,7 +37,7 @@ static int alloc_clips(struct qxl_device *qdev,
  * the qxl_clip_rects. This is *not* the same as the memory allocated
  * on the device, it is offset to qxl_clip_rects.chunk.data */
 static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
-                                             unsigned num_clips,
+                                             unsigned int num_clips,
                                              struct qxl_bo *clips_bo)
 {
        struct qxl_clip_rects *dev_clips;
@@ -168,6 +168,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
        int ret;
        struct qxl_drm_image *dimage;
        struct qxl_bo *palette_bo = NULL;
+
        if (stride == 0)
                stride = depth * width / 8;
 
@@ -214,6 +215,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
 
        if (depth == 1) {
                void *ptr;
+
                ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
 
                ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
@@ -245,8 +247,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
        qxl_release_fence_buffer_objects(release);
 
 out_free_palette:
-       if (palette_bo)
-               qxl_bo_unref(&palette_bo);
+       qxl_bo_unref(&palette_bo);
 out_free_image:
        qxl_image_free_objects(qdev, dimage);
 out_free_drawable:
@@ -264,9 +265,9 @@ out_free_drawable:
 void qxl_draw_dirty_fb(struct qxl_device *qdev,
                       struct drm_framebuffer *fb,
                       struct qxl_bo *bo,
-                      unsigned flags, unsigned color,
+                      unsigned int flags, unsigned int color,
                       struct drm_clip_rect *clips,
-                      unsigned num_clips, int inc)
+                      unsigned int num_clips, int inc)
 {
        /*
         * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
@@ -340,7 +341,6 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
        if (ret)
                goto out_release_backoff;
 
-
        ret = qxl_image_init(qdev, release, dimage, surface_base,
                             left, top, width, height, depth, stride);
        qxl_bo_kunmap(bo);
index 8ff70a7281a73580f2d8e475d6d8d5489392a82c..13a0254b59a1a55fd09663dd32170b478b9513a3 100644 (file)
@@ -23,7 +23,6 @@
  *          Alon Levy
  */
 
-
 #ifndef QXL_DRV_H
 #define QXL_DRV_H
 
@@ -83,16 +82,16 @@ struct qxl_bo {
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
-       unsigned                        pin_count;
+       unsigned int pin_count;
        void                            *kptr;
        int                             type;
 
        /* Constant after initialization */
        struct drm_gem_object           gem_base;
-       bool is_primary; /* is this now a primary surface */
-       bool is_dumb;
+       unsigned int is_primary:1; /* is this now a primary surface */
+       unsigned int is_dumb:1;
        struct qxl_bo *shadow;
-       bool hw_surf_alloc;
+       unsigned int hw_surf_alloc:1;
        struct qxl_surface surf;
        uint32_t surface_id;
        struct qxl_release *surf_create;
@@ -127,13 +126,9 @@ struct qxl_output {
 #define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
 
 struct qxl_mman {
-       struct ttm_bo_global_ref        bo_global_ref;
-       struct drm_global_reference     mem_global_ref;
-       bool                            mem_global_referenced;
        struct ttm_bo_device            bdev;
 };
 
-
 struct qxl_memslot {
        uint8_t         generation;
        uint64_t        start_phys_addr;
@@ -191,12 +186,12 @@ struct qxl_draw_fill {
  */
 struct qxl_debugfs {
        struct drm_info_list    *files;
-       unsigned                num_files;
+       unsigned int num_files;
 };
 
 int qxl_debugfs_add_files(struct qxl_device *rdev,
                             struct drm_info_list *files,
-                            unsigned nfiles);
+                            unsigned int nfiles);
 int qxl_debugfs_fence_init(struct qxl_device *rdev);
 
 struct qxl_device;
@@ -231,7 +226,7 @@ struct qxl_device {
 
        struct qxl_ram_header *ram_header;
 
-       bool primary_created;
+       unsigned int primary_created:1;
 
        struct qxl_memslot      *mem_slots;
        uint8_t         n_mem_slots;
@@ -254,7 +249,7 @@ struct qxl_device {
        atomic_t irq_received_display;
        atomic_t irq_received_cursor;
        atomic_t irq_received_io_cmd;
-       unsigned irq_received_error;
+       unsigned int irq_received_error;
        wait_queue_head_t display_event;
        wait_queue_head_t cursor_event;
        wait_queue_head_t io_cmd_event;
@@ -262,7 +257,7 @@ struct qxl_device {
 
        /* debugfs */
        struct qxl_debugfs      debugfs[QXL_DEBUGFS_MAX_COMPONENTS];
-       unsigned                debugfs_count;
+       unsigned int debugfs_count;
 
        struct mutex            update_area_mutex;
 
@@ -372,7 +367,6 @@ int qxl_mode_dumb_mmap(struct drm_file *filp,
                       struct drm_device *dev,
                       uint32_t handle, uint64_t *offset_p);
 
-
 /* qxl ttm */
 int qxl_ttm_init(struct qxl_device *qdev);
 void qxl_ttm_fini(struct qxl_device *qdev);
@@ -398,7 +392,7 @@ void qxl_update_screen(struct qxl_device *qxl);
 /* qxl io operations (qxl_cmd.c) */
 
 void qxl_io_create_primary(struct qxl_device *qdev,
-                          unsigned offset,
+                          unsigned int offset,
                           struct qxl_bo *bo);
 void qxl_io_destroy_primary(struct qxl_device *qdev);
 void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -449,9 +443,9 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
 void qxl_draw_dirty_fb(struct qxl_device *qdev,
                       struct drm_framebuffer *fb,
                       struct qxl_bo *bo,
-                      unsigned flags, unsigned color,
+                      unsigned int flags, unsigned int color,
                       struct drm_clip_rect *clips,
-                      unsigned num_clips, int inc);
+                      unsigned int num_clips, int inc);
 
 void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec);
 
@@ -496,7 +490,7 @@ bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
 
 int qxl_debugfs_add_files(struct qxl_device *qdev,
                          struct drm_info_list *files,
-                         unsigned nfiles);
+                         unsigned int nfiles);
 
 int qxl_surface_id_alloc(struct qxl_device *qdev,
                         struct qxl_bo *surf);
index c666b89eed5d12d77c3be77ac3c23290895a9424..e3765739c396b0e6f734b7c36c52c5bf40dcc5c0 100644 (file)
@@ -38,6 +38,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
        int r;
        struct qxl_surface surf;
        uint32_t pitch, format;
+
        pitch = args->width * ((args->bpp + 1) / 8);
        args->size = pitch * args->height;
        args->size = ALIGN(args->size, PAGE_SIZE);
@@ -52,7 +53,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
        default:
                return -EINVAL;
        }
-         
+
        surf.width = args->width;
        surf.height = args->height;
        surf.stride = pitch;
index 2294b7f14fdf7a0ca8fe1f20fef5790e7fe3ca24..a819d24225d2a6f26768e9c0f2ec67d9221e2f66 100644 (file)
@@ -111,7 +111,7 @@ static int qxlfb_create_pinned_object(struct qxl_device *qdev,
        qbo->surf.stride = mode_cmd->pitches[0];
        qbo->surf.format = SPICE_SURFACE_FMT_32_xRGB;
 
-       ret = qxl_bo_pin(qbo, QXL_GEM_DOMAIN_SURFACE, NULL);
+       ret = qxl_bo_pin(qbo);
        if (ret) {
                goto out_unref;
        }
@@ -134,9 +134,9 @@ out_unref:
  */
 static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
                                   struct drm_file *file_priv,
-                                  unsigned flags, unsigned color,
+                                  unsigned int flags, unsigned int color,
                                   struct drm_clip_rect *clips,
-                                  unsigned num_clips)
+                                  unsigned int num_clips)
 {
        struct qxl_device *qdev = fb->dev->dev_private;
        struct fb_info *info = qdev->fb_helper.fbdev;
index 7fbcc35e8ad35bfa8cce9f3323a4f4e5d574f21e..43688ecdd8a04d9d4bc3286ae03259c9892626e8 100644 (file)
@@ -136,6 +136,7 @@ qxl_image_init_helper(struct qxl_device *qdev,
                int remain;
                int page;
                int size;
+
                if (stride == linesize && chunk_stride == stride) {
                        remain = linesize * height;
                        page = 0;
@@ -162,7 +163,8 @@ qxl_image_init_helper(struct qxl_device *qdev,
                                page++;
                        }
                } else {
-                       unsigned page_base, page_offset, out_offset;
+                       unsigned int page_base, page_offset, out_offset;
+
                        for (i = 0 ; i < height ; ++i) {
                                i_data = (void *)data + i * stride;
                                remain = linesize;
index 6cc9f3367fa05581a90280b7cc111259cc2692fa..6e828158bcb02d3e5dbc09225c7c353ea3766eb2 100644 (file)
@@ -85,6 +85,7 @@ static void
 apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
 {
        void *reloc_page;
+
        reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
        *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
                                                                                              info->src_bo,
@@ -189,6 +190,7 @@ static int qxl_process_single_command(struct qxl_device *qdev,
 
        {
                struct qxl_drawable *draw = fb_cmd;
+
                draw->mm_time = qdev->rom->mm_clock;
        }
 
index e25c589d5f50f33809c00c7c90d9c5aa9446de86..15238a413f9d7809cd4f937a943b8ac131472564 100644 (file)
@@ -92,6 +92,7 @@ void qxl_reinit_memslots(struct qxl_device *qdev)
 static void qxl_gc_work(struct work_struct *work)
 {
        struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
+
        qxl_garbage_collect(qdev);
 }
 
@@ -284,7 +285,6 @@ int qxl_device_init(struct qxl_device *qdev,
                 (unsigned long)qdev->surfaceram_base,
                 (unsigned long)qdev->surfaceram_size);
 
-
        INIT_WORK(&qdev->gc_work, qxl_gc_work);
 
        return 0;
@@ -313,10 +313,8 @@ error:
 
 void qxl_device_fini(struct qxl_device *qdev)
 {
-       if (qdev->current_release_bo[0])
-               qxl_bo_unref(&qdev->current_release_bo[0]);
-       if (qdev->current_release_bo[1])
-               qxl_bo_unref(&qdev->current_release_bo[1]);
+       qxl_bo_unref(&qdev->current_release_bo[0]);
+       qxl_bo_unref(&qdev->current_release_bo[1]);
        flush_work(&qdev->gc_work);
        qxl_ring_free(qdev->command_ring);
        qxl_ring_free(qdev->cursor_ring);
index 6a30196e9d6c1a371c0b74071b4369b5c237cc4f..91f3bbc73ecc01fa9d41ba3270b403963d024ac0 100644 (file)
@@ -54,7 +54,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
 {
        u32 c = 0;
        u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
-       unsigned i;
+       unsigned int i;
 
        qbo->placement.placement = qbo->placements;
        qbo->placement.busy_placement = qbo->placements;
@@ -74,7 +74,6 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
        }
 }
 
-
 int qxl_bo_create(struct qxl_device *qdev,
                  unsigned long size, bool kernel, bool pinned, u32 domain,
                  struct qxl_surface *surf,
@@ -187,13 +186,9 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,
                               struct qxl_bo *bo, void *pmap)
 {
        struct ttm_mem_type_manager *man = &bo->tbo.bdev->man[bo->tbo.mem.mem_type];
-       struct io_mapping *map;
 
-       if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
-               map = qdev->vram_mapping;
-       else if (bo->tbo.mem.mem_type == TTM_PL_PRIV)
-               map = qdev->surface_mapping;
-       else
+       if ((bo->tbo.mem.mem_type != TTM_PL_VRAM) &&
+           (bo->tbo.mem.mem_type != TTM_PL_PRIV))
                goto fallback;
 
        io_mapping_unmap_atomic(pmap);
@@ -201,7 +196,7 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,
        (void) ttm_mem_io_lock(man, false);
        ttm_mem_io_free(bo->tbo.bdev, &bo->tbo.mem);
        ttm_mem_io_unlock(man);
-       return ;
+       return;
  fallback:
        qxl_bo_kunmap(bo);
 }
@@ -221,7 +216,7 @@ struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
        return bo;
 }
 
-static int __qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
+static int __qxl_bo_pin(struct qxl_bo *bo)
 {
        struct ttm_operation_ctx ctx = { false, false };
        struct drm_device *ddev = bo->gem_base.dev;
@@ -229,16 +224,12 @@ static int __qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
 
        if (bo->pin_count) {
                bo->pin_count++;
-               if (gpu_addr)
-                       *gpu_addr = qxl_bo_gpu_offset(bo);
                return 0;
        }
-       qxl_ttm_placement_from_domain(bo, domain, true);
+       qxl_ttm_placement_from_domain(bo, bo->type, true);
        r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
        if (likely(r == 0)) {
                bo->pin_count = 1;
-               if (gpu_addr != NULL)
-                       *gpu_addr = qxl_bo_gpu_offset(bo);
        }
        if (unlikely(r != 0))
                dev_err(ddev->dev, "%p pin failed\n", bo);
@@ -266,13 +257,12 @@ static int __qxl_bo_unpin(struct qxl_bo *bo)
        return r;
 }
 
-
 /*
  * Reserve the BO before pinning the object.  If the BO was reserved
  * beforehand, use the internal version directly __qxl_bo_pin.
  *
  */
-int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
+int qxl_bo_pin(struct qxl_bo *bo)
 {
        int r;
 
@@ -280,7 +270,7 @@ int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
        if (r)
                return r;
 
-       r = __qxl_bo_pin(bo, bo->type, NULL);
+       r = __qxl_bo_pin(bo);
        qxl_bo_unreserve(bo);
        return r;
 }
@@ -335,6 +325,7 @@ void qxl_bo_fini(struct qxl_device *qdev)
 int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
 {
        int ret;
+
        if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) {
                /* allocate a surface id for this surface now */
                ret = qxl_surface_id_alloc(qdev, bo);
index 0374fd93f4d662525946c8618054d137712b25aa..255b914e2a7b50ea560b94596ba64e7a778fa4cb 100644 (file)
@@ -35,6 +35,7 @@ static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait)
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS) {
                        struct drm_device *ddev = bo->gem_base.dev;
+
                        dev_err(ddev->dev, "%p reserve failed\n", bo);
                }
                return r;
@@ -71,6 +72,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS) {
                        struct drm_device *ddev = bo->gem_base.dev;
+
                        dev_err(ddev->dev, "%p reserve failed for wait\n",
                                bo);
                }
@@ -95,7 +97,7 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, int pa
 void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *map);
 extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo);
 extern void qxl_bo_unref(struct qxl_bo **bo);
-extern int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr);
+extern int qxl_bo_pin(struct qxl_bo *bo);
 extern int qxl_bo_unpin(struct qxl_bo *bo);
 extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned);
 extern bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo);
index 9f029dda1f071431a9d90894096ab4a3f89bbe0a..a55dece118b292a5b6958a64b5a5c47d12d82033 100644 (file)
@@ -38,7 +38,6 @@ void qxl_gem_prime_unpin(struct drm_gem_object *obj)
        WARN_ONCE(1, "not implemented");
 }
 
-
 struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
        WARN_ONCE(1, "not implemented");
index e37f0097f7441323281b8e06f76a04e1104ab260..30f85f0130cbb172ef9292097acb3c56c0adcbb7 100644 (file)
@@ -217,7 +217,7 @@ int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo)
 
        qxl_bo_ref(bo);
        entry->tv.bo = &bo->tbo;
-       entry->tv.shared = false;
+       entry->tv.num_shared = 0;
        list_add_tail(&entry->tv.head, &release->bos);
        return 0;
 }
@@ -234,7 +234,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
                        return ret;
        }
 
-       ret = reservation_object_reserve_shared(bo->tbo.resv);
+       ret = reservation_object_reserve_shared(bo->tbo.resv, 1);
        if (ret)
                return ret;
 
@@ -282,7 +282,6 @@ void qxl_release_backoff_reserve_list(struct qxl_release *release)
        ttm_eu_backoff_reservation(&release->ticket, &release->bos);
 }
 
-
 int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
                                       enum qxl_surface_cmd_type surface_cmd_type,
                                       struct qxl_release *create_rel,
@@ -428,8 +427,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release)
        struct ttm_buffer_object *bo;
        struct ttm_bo_global *glob;
        struct ttm_bo_device *bdev;
-       struct ttm_bo_driver *driver;
-       struct qxl_bo *qbo;
        struct ttm_validate_buffer *entry;
        struct qxl_device *qdev;
 
@@ -450,14 +447,12 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release)
                       release->id | 0xf0000000, release->base.seqno);
        trace_dma_fence_emit(&release->base);
 
-       driver = bdev->driver;
        glob = bdev->glob;
 
        spin_lock(&glob->lru_lock);
 
        list_for_each_entry(entry, &release->bos, head) {
                bo = entry->bo;
-               qbo = to_qxl_bo(bo);
 
                reservation_object_add_shared_fence(bo->resv, &release->base);
                ttm_bo_add_to_lru(bo);
index 86a1fb32f6db80b0a5c930c35b9c65960310c9b6..886f61e94f24470c37feaf224974fb28d43d2e5b 100644 (file)
@@ -46,62 +46,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
        return qdev;
 }
 
-static int qxl_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void qxl_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int qxl_ttm_global_init(struct qxl_device *qdev)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       qdev->mman.mem_global_referenced = false;
-       global_ref = &qdev->mman.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &qxl_ttm_mem_global_init;
-       global_ref->release = &qxl_ttm_mem_global_release;
-
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       qdev->mman.bo_global_ref.mem_glob =
-               qdev->mman.mem_global_ref.object;
-       global_ref = &qdev->mman.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&qdev->mman.mem_global_ref);
-               return r;
-       }
-
-       qdev->mman.mem_global_referenced = true;
-       return 0;
-}
-
-static void qxl_ttm_global_fini(struct qxl_device *qdev)
-{
-       if (qdev->mman.mem_global_referenced) {
-               drm_global_item_unref(&qdev->mman.bo_global_ref.ref);
-               drm_global_item_unref(&qdev->mman.mem_global_ref);
-               qdev->mman.mem_global_referenced = false;
-       }
-}
-
 static struct vm_operations_struct qxl_ttm_vm_ops;
 static const struct vm_operations_struct *ttm_vm_ops;
 
@@ -174,7 +118,7 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        default:
-               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
                return -EINVAL;
        }
        return 0;
@@ -331,7 +275,6 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
        if (ret)
                return ret;
 
-
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
                qxl_move_null(bo, new_mem);
                return 0;
@@ -373,12 +316,8 @@ int qxl_ttm_init(struct qxl_device *qdev)
        int r;
        int num_io_pages; /* != rom->num_io_pages, we include surface0 */
 
-       r = qxl_ttm_global_init(qdev);
-       if (r)
-               return r;
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&qdev->mman.bdev,
-                              qdev->mman.bo_global_ref.ref.object,
                               &qxl_bo_driver,
                               qdev->ddev.anon_inode->i_mapping,
                               DRM_FILE_PAGE_OFFSET, 0);
@@ -401,11 +340,11 @@ int qxl_ttm_init(struct qxl_device *qdev)
                return r;
        }
        DRM_INFO("qxl: %uM of VRAM memory size\n",
-                (unsigned)qdev->vram_size / (1024 * 1024));
+                (unsigned int)qdev->vram_size / (1024 * 1024));
        DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n",
-                ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
+                ((unsigned int)num_io_pages * PAGE_SIZE) / (1024 * 1024));
        DRM_INFO("qxl: %uM of Surface memory size\n",
-                (unsigned)qdev->surfaceram_size / (1024 * 1024));
+                (unsigned int)qdev->surfaceram_size / (1024 * 1024));
        return 0;
 }
 
@@ -414,11 +353,9 @@ void qxl_ttm_fini(struct qxl_device *qdev)
        ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV);
        ttm_bo_device_release(&qdev->mman.bdev);
-       qxl_ttm_global_fini(qdev);
        DRM_INFO("qxl: ttm finalized\n");
 }
 
-
 #define QXL_DEBUGFS_MEM_TYPES 2
 
 #if defined(CONFIG_DEBUG_FS)
@@ -443,7 +380,7 @@ int qxl_ttm_debugfs_init(struct qxl_device *qdev)
 #if defined(CONFIG_DEBUG_FS)
        static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
        static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32];
-       unsigned i;
+       unsigned int i;
 
        for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) {
                if (i == 0)
index 21161aa8acbf202d196a0ed7949a4659f4cf8269..652126fd6dd4f4ea5c0899f43a5047b0758db555 100644 (file)
@@ -814,7 +814,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                          ((idx_value >> 21) & 0xF));
                                return -EINVAL;
                        }
-                       /* Pass through. */
+                       /* Fall through. */
                case 6:
                        track->cb[i].cpp = 4;
                        break;
@@ -965,7 +965,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                return -EINVAL;
                        }
                        /* The same rules apply as for DXT3/5. */
-                       /* Pass through. */
+                       /* Fall through. */
                case R300_TX_FORMAT_DXT3:
                case R300_TX_FORMAT_DXT5:
                        track->textures[i].cpp = 1;
index 45e1d4e60759f55bbe4bb03faf629a442d7417f8..2318d9e3ed96ddc3c00395149bce5fe5c73af19c 100644 (file)
@@ -109,6 +109,7 @@ void r420_pipes_init(struct radeon_device *rdev)
        default:
                /* force to 1 pipe */
                num_pipes = 1;
+               /* fall through */
        case 1:
                tmp = (0 << 1);
                break;
index 1a6f6edb3515188ea55e3ce8e2b9d2e951d0c8c7..32808e50be12f815c85178083cc49bf24d16cf89 100644 (file)
@@ -448,10 +448,7 @@ struct radeon_surface_reg {
  * TTM.
  */
 struct radeon_mman {
-       struct ttm_bo_global_ref        bo_global_ref;
-       struct drm_global_reference     mem_global_ref;
        struct ttm_bo_device            bdev;
-       bool                            mem_global_referenced;
        bool                            initialized;
 
 #if defined(CONFIG_DEBUG_FS)
index 1ae31dbc61c64a2fbf30ede3a84fa0ea315fe8b5..f43305329939856bbfad5837cca510e3c8c5450b 100644 (file)
@@ -178,7 +178,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                }
 
                p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
-               p->relocs[i].tv.shared = !r->write_domain;
+               p->relocs[i].tv.num_shared = !r->write_domain;
 
                radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head,
                                      priority);
@@ -253,7 +253,7 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
 
                resv = reloc->robj->tbo.resv;
                r = radeon_sync_resv(p->rdev, &p->ib.sync, resv,
-                                    reloc->tv.shared);
+                                    reloc->tv.num_shared);
                if (r)
                        return r;
        }
index 27d8e7dd2d0676c4f369041be3bcb5b95774a1b3..44617dec8183373c5bd278502d54337f93b4ad77 100644 (file)
@@ -552,7 +552,7 @@ static void radeon_gem_va_update_vm(struct radeon_device *rdev,
        INIT_LIST_HEAD(&list);
 
        tv.bo = &bo_va->bo->tbo;
-       tv.shared = true;
+       tv.num_shared = 1;
        list_add(&tv.head, &list);
 
        vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list);
index 4278272e3191d3508aa88eede6751b75daefe388..3dae2c4dec711417d1537d603b3b1dd4d95cb03f 100644 (file)
@@ -421,24 +421,14 @@ static void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encode
 
 static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
-       struct radeon_crtc *radeon_crtc;
        int restart;
        unsigned int h_total, v_total, f_total;
        int v_offset, h_offset;
        u16 p1, p2, h_inc;
        bool h_changed;
        const struct radeon_tv_mode_constants *const_ptr;
-       struct radeon_pll *pll;
-
-       radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
-       if (radeon_crtc->crtc_id == 1)
-               pll = &rdev->clock.p2pll;
-       else
-               pll = &rdev->clock.p1pll;
 
        const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
        if (!const_ptr)
index 92f6d4002eea4274a2d87c75f0322372864ba5cf..833e909706a9c2ef6845abd7358d495acc728603 100644 (file)
@@ -314,11 +314,9 @@ struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo)
 void radeon_bo_unref(struct radeon_bo **bo)
 {
        struct ttm_buffer_object *tbo;
-       struct radeon_device *rdev;
 
        if ((*bo) == NULL)
                return;
-       rdev = (*bo)->rdev;
        tbo = &((*bo)->tbo);
        ttm_bo_put(tbo);
        *bo = NULL;
index cbb67e9ffb3a52f413564f82db87dd0ece44c37e..9920a6fc11bf3446f1e1858414d8c25fc9cc2f07 100644 (file)
@@ -60,65 +60,6 @@ static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
        return rdev;
 }
 
-
-/*
- * Global memory.
- */
-static int radeon_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void radeon_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int radeon_ttm_global_init(struct radeon_device *rdev)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       rdev->mman.mem_global_referenced = false;
-       global_ref = &rdev->mman.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &radeon_ttm_mem_global_init;
-       global_ref->release = &radeon_ttm_mem_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       rdev->mman.bo_global_ref.mem_glob =
-               rdev->mman.mem_global_ref.object;
-       global_ref = &rdev->mman.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&rdev->mman.mem_global_ref);
-               return r;
-       }
-
-       rdev->mman.mem_global_referenced = true;
-       return 0;
-}
-
-static void radeon_ttm_global_fini(struct radeon_device *rdev)
-{
-       if (rdev->mman.mem_global_referenced) {
-               drm_global_item_unref(&rdev->mman.bo_global_ref.ref);
-               drm_global_item_unref(&rdev->mman.mem_global_ref);
-               rdev->mman.mem_global_referenced = false;
-       }
-}
-
 static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
 {
        return 0;
@@ -847,13 +788,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
 {
        int r;
 
-       r = radeon_ttm_global_init(rdev);
-       if (r) {
-               return r;
-       }
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&rdev->mman.bdev,
-                              rdev->mman.bo_global_ref.ref.object,
                               &radeon_bo_driver,
                               rdev->ddev->anon_inode->i_mapping,
                               DRM_FILE_PAGE_OFFSET,
@@ -925,7 +861,6 @@ void radeon_ttm_fini(struct radeon_device *rdev)
        ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT);
        ttm_bo_device_release(&rdev->mman.bdev);
        radeon_gart_fini(rdev);
-       radeon_ttm_global_fini(rdev);
        rdev->mman.initialized = false;
        DRM_INFO("radeon: ttm finalized\n");
 }
index 7f1a9c787bd1325ec5b2a50b982f8aa69fec2438..0d374211661c23107baee8cf6c0e643acd22a823 100644 (file)
@@ -142,7 +142,7 @@ struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
        list[0].preferred_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].tv.bo = &vm->page_directory->tbo;
-       list[0].tv.shared = true;
+       list[0].tv.num_shared = 1;
        list[0].tiling_flags = 0;
        list_add(&list[0].tv.head, head);
 
@@ -154,7 +154,7 @@ struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
                list[idx].preferred_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].tv.bo = &list[idx].robj->tbo;
-               list[idx].tv.shared = true;
+               list[idx].tv.num_shared = 1;
                list[idx].tiling_flags = 0;
                list_add(&list[idx++].tv.head, head);
        }
@@ -831,7 +831,7 @@ static int radeon_vm_update_ptes(struct radeon_device *rdev,
                int r;
 
                radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true);
-               r = reservation_object_reserve_shared(pt->tbo.resv);
+               r = reservation_object_reserve_shared(pt->tbo.resv, 1);
                if (r)
                        return r;
 
@@ -946,7 +946,7 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
                bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
 
        if (mem) {
-               addr = mem->start << PAGE_SHIFT;
+               addr = (u64)mem->start << PAGE_SHIFT;
                if (mem->mem_type != TTM_PL_SYSTEM) {
                        bo_va->flags |= RADEON_VM_PAGE_VALID;
                }
index 17741843cf519be7769047c24db32732551f7d24..90dacab67be5a8629525ed30665d58b93eeb2878 100644 (file)
@@ -226,9 +226,6 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
                 * system clock, and have no internal clock divider.
                 */
 
-               if (WARN_ON(!rcrtc->extclock))
-                       return;
-
                /*
                 * The H3 ES1.x exhibits dot clock duty cycle stability issues.
                 * We can work around them by configuring the DPLL to twice the
@@ -701,7 +698,7 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
         * CRTC will be put later in .atomic_disable().
         *
         * If a mode set is not in progress the CRTC is enabled, and the
-        * following get call will be a no-op. There is thus no need to belance
+        * following get call will be a no-op. There is thus no need to balance
         * it in .atomic_flush() either.
         */
        rcar_du_crtc_get(rcrtc);
@@ -738,10 +735,22 @@ enum drm_mode_status rcar_du_crtc_mode_valid(struct drm_crtc *crtc,
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
        struct rcar_du_device *rcdu = rcrtc->group->dev;
        bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
+       unsigned int vbp;
 
        if (interlaced && !rcar_du_has(rcdu, RCAR_DU_FEATURE_INTERLACED))
                return MODE_NO_INTERLACE;
 
+       /*
+        * The hardware requires a minimum combined horizontal sync and back
+        * porch of 20 pixels and a minimum vertical back porch of 3 lines.
+        */
+       if (mode->htotal - mode->hsync_start < 20)
+               return MODE_HBLANK_NARROW;
+
+       vbp = (mode->vtotal - mode->vsync_end) / (interlaced ? 2 : 1);
+       if (vbp < 3)
+               return MODE_VBLANK_NARROW;
+
        return MODE_OK;
 }
 
@@ -1002,7 +1011,7 @@ unlock:
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
 
-       return 0;
+       return ret;
 }
 
 static const struct drm_crtc_funcs crtc_funcs_gen2 = {
@@ -1113,9 +1122,16 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
        clk = devm_clk_get(rcdu->dev, clk_name);
        if (!IS_ERR(clk)) {
                rcrtc->extclock = clk;
-       } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
-               dev_info(rcdu->dev, "can't get external clock %u\n", hwindex);
+       } else if (PTR_ERR(clk) == -EPROBE_DEFER) {
                return -EPROBE_DEFER;
+       } else if (rcdu->info->dpll_mask & BIT(hwindex)) {
+               /*
+                * DU channels that have a display PLL can't use the internal
+                * system clock and thus require an external clock.
+                */
+               ret = PTR_ERR(clk);
+               dev_err(rcdu->dev, "can't get dclkin.%u: %d\n", hwindex, ret);
+               return ret;
        }
 
        init_waitqueue_head(&rcrtc->flip_wait);
index 084f58df4a8cf3baa8d3ab63091c23be708aa1b1..f50a3b1864bbe199c97d9df4a6ac018b12da7e67 100644 (file)
@@ -21,6 +21,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
 #include "rcar_du_drv.h"
@@ -41,7 +42,7 @@ static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
        .channels_mask = BIT(1) | BIT(0),
        .routes = {
                /*
-                * R8A7743 has one RGB output and one LVDS output
+                * R8A774[34] has one RGB output and one LVDS output
                 */
                [RCAR_DU_OUTPUT_DPAD0] = {
                        .possible_crtcs = BIT(1) | BIT(0),
@@ -77,6 +78,33 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
        },
 };
 
+static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
+       .gen = 2,
+       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+                 | RCAR_DU_FEATURE_EXT_CTRL_REGS
+                 | RCAR_DU_FEATURE_INTERLACED
+                 | RCAR_DU_FEATURE_TVM_SYNC,
+       .channels_mask = BIT(1) | BIT(0),
+       .routes = {
+               /*
+                * R8A77470 has two RGB outputs, one LVDS output, and
+                * one (currently unsupported) analog video output
+                */
+               [RCAR_DU_OUTPUT_DPAD0] = {
+                       .possible_crtcs = BIT(0),
+                       .port = 0,
+               },
+               [RCAR_DU_OUTPUT_DPAD1] = {
+                       .possible_crtcs = BIT(1),
+                       .port = 1,
+               },
+               [RCAR_DU_OUTPUT_LVDS0] = {
+                       .possible_crtcs = BIT(0) | BIT(1),
+                       .port = 2,
+               },
+       },
+};
+
 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
        .gen = 2,
        .features = RCAR_DU_FEATURE_INTERLACED
@@ -341,7 +369,9 @@ static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
 
 static const struct of_device_id rcar_du_of_table[] = {
        { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
+       { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
        { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
+       { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
        { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
        { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
        { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
@@ -363,19 +393,11 @@ MODULE_DEVICE_TABLE(of, rcar_du_of_table);
  * DRM operations
  */
 
-static void rcar_du_lastclose(struct drm_device *dev)
-{
-       struct rcar_du_device *rcdu = dev->dev_private;
-
-       drm_fbdev_cma_restore_mode(rcdu->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
 
 static struct drm_driver rcar_du_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
                                | DRIVER_ATOMIC,
-       .lastclose              = rcar_du_lastclose,
        .gem_free_object_unlocked = drm_gem_cma_free_object,
        .gem_vm_ops             = &drm_gem_cma_vm_ops,
        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
@@ -404,32 +426,15 @@ static struct drm_driver rcar_du_driver = {
 static int rcar_du_pm_suspend(struct device *dev)
 {
        struct rcar_du_device *rcdu = dev_get_drvdata(dev);
-       struct drm_atomic_state *state;
 
-       drm_kms_helper_poll_disable(rcdu->ddev);
-       drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
-
-       state = drm_atomic_helper_suspend(rcdu->ddev);
-       if (IS_ERR(state)) {
-               drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
-               drm_kms_helper_poll_enable(rcdu->ddev);
-               return PTR_ERR(state);
-       }
-
-       rcdu->suspend_state = state;
-
-       return 0;
+       return drm_mode_config_helper_suspend(rcdu->ddev);
 }
 
 static int rcar_du_pm_resume(struct device *dev)
 {
        struct rcar_du_device *rcdu = dev_get_drvdata(dev);
 
-       drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
-       drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
-       drm_kms_helper_poll_enable(rcdu->ddev);
-
-       return 0;
+       return drm_mode_config_helper_resume(rcdu->ddev);
 }
 #endif
 
@@ -448,13 +453,10 @@ static int rcar_du_remove(struct platform_device *pdev)
 
        drm_dev_unregister(ddev);
 
-       if (rcdu->fbdev)
-               drm_fbdev_cma_fini(rcdu->fbdev);
-
        drm_kms_helper_poll_fini(ddev);
        drm_mode_config_cleanup(ddev);
 
-       drm_dev_unref(ddev);
+       drm_dev_put(ddev);
 
        return 0;
 }
@@ -510,6 +512,8 @@ static int rcar_du_probe(struct platform_device *pdev)
 
        DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
 
+       drm_fbdev_generic_setup(ddev, 32);
+
        return 0;
 
 error:
index 143c037e2c0f715ba8e109b62582df2fe0b8991c..a68da79b424ee50308ad18a7447d03f6fba300c2 100644 (file)
@@ -20,7 +20,6 @@
 struct clk;
 struct device;
 struct drm_device;
-struct drm_fbdev_cma;
 struct rcar_du_device;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0)  /* Per-CRTC IRQ and clock */
@@ -78,8 +77,6 @@ struct rcar_du_device {
        void __iomem *mmio;
 
        struct drm_device *ddev;
-       struct drm_fbdev_cma *fbdev;
-       struct drm_atomic_state *suspend_state;
 
        struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
        unsigned int num_crtcs;
index 4ebd61ecbee177ab928d7837b28469d049f3d491..9c7007d45408b921ce7a909ee1f4d661ca55db67 100644 (file)
@@ -255,13 +255,6 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
        return drm_gem_fb_create(dev, file_priv, mode_cmd);
 }
 
-static void rcar_du_output_poll_changed(struct drm_device *dev)
-{
-       struct rcar_du_device *rcdu = dev->dev_private;
-
-       drm_fbdev_cma_hotplug_event(rcdu->fbdev);
-}
-
 /* -----------------------------------------------------------------------------
  * Atomic Check and Update
  */
@@ -308,7 +301,6 @@ static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = {
 
 static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
        .fb_create = rcar_du_fb_create,
-       .output_poll_changed = rcar_du_output_poll_changed,
        .atomic_check = rcar_du_atomic_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
@@ -543,7 +535,6 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
 
        struct drm_device *dev = rcdu->ddev;
        struct drm_encoder *encoder;
-       struct drm_fbdev_cma *fbdev;
        unsigned int dpad0_sources;
        unsigned int num_encoders;
        unsigned int num_groups;
@@ -582,7 +573,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
         * Initialize vertical blanking interrupts handling. Start with vblank
         * disabled for all CRTCs.
         */
-       ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1);
+       ret = drm_vblank_init(dev, rcdu->num_crtcs);
        if (ret < 0)
                return ret;
 
@@ -682,17 +673,5 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
 
        drm_kms_helper_poll_init(dev);
 
-       if (dev->mode_config.num_connector) {
-               fbdev = drm_fbdev_cma_init(dev, 32,
-                                          dev->mode_config.num_connector);
-               if (IS_ERR(fbdev))
-                       return PTR_ERR(fbdev);
-
-               rcdu->fbdev = fbdev;
-       } else {
-               dev_info(rcdu->dev,
-                        "no connector found, disabling fbdev emulation\n");
-       }
-
        return 0;
 }
index 9e07758a755c254ee8fc200037196237ee841948..39d5ae3fdf72b1de5ffa079751b378a080a2087d 100644 (file)
@@ -783,13 +783,14 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
                drm_plane_helper_add(&plane->plane,
                                     &rcar_du_plane_helper_funcs);
 
+               drm_plane_create_alpha_property(&plane->plane);
+
                if (type == DRM_PLANE_TYPE_PRIMARY)
                        continue;
 
                drm_object_attach_property(&plane->plane.base,
                                           rcdu->props.colorkey,
                                           RCAR_DU_COLORKEY_NONE);
-               drm_plane_create_alpha_property(&plane->plane);
                drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
        }
 
index 173d7ad0b991b49257882d1f8ceacec4d6c07cc8..534a128a869d51e438ed5e5c7172ec306ef5a025 100644 (file)
@@ -790,6 +790,7 @@ static const struct of_device_id rcar_lvds_of_table[] = {
        { .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
        { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
        { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
+       { .compatible = "renesas,r8a77965-lvds", .data = &rcar_lvds_gen3_info },
        { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
        { .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info },
        { .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info },
index 26438d45732bf3edeaa017dc89a25b80e645fd3f..1e75196f9659df605bdac0c28612914171cbbda3 100644 (file)
@@ -7,7 +7,7 @@ config DRM_ROCKCHIP
        select VIDEOMODE_HELPERS
        select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
        select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
-       select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
+       select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
        select DRM_RGB if ROCKCHIP_RGB
        select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
        help
index 868263ff03025d5173fdc99ad30daca8ed818d3d..f6fc9d5dd0ad4f10ccbbcae1dc0252794f659dd7 100644 (file)
@@ -11,7 +11,7 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
-rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
 rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
 rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
index 3105965fc26034e921de4c86d39475180e70b03c..5a485489a1e23cca8b3c455d368d42320140774e 100644 (file)
@@ -147,7 +147,7 @@ static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
 }
 
 static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp,
-                                      u8 *buff, u8 buff_size)
+                                      u8 *buff, u16 buff_size)
 {
        u32 i;
        int ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
new file mode 100644 (file)
index 0000000..7ee359b
--- /dev/null
@@ -0,0 +1,1076 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:
+ *      Chris Zhong <zyw@rock-chips.com>
+ *      Nickey Yang <nickey.yang@rock-chips.com>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/math64.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <video/mipi_display.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_vop.h"
+
+#define DSI_PHY_RSTZ                   0xa0
+#define PHY_DISFORCEPLL                        0
+#define PHY_ENFORCEPLL                 BIT(3)
+#define PHY_DISABLECLK                 0
+#define PHY_ENABLECLK                  BIT(2)
+#define PHY_RSTZ                       0
+#define PHY_UNRSTZ                     BIT(1)
+#define PHY_SHUTDOWNZ                  0
+#define PHY_UNSHUTDOWNZ                        BIT(0)
+
+#define DSI_PHY_IF_CFG                 0xa4
+#define N_LANES(n)                     ((((n) - 1) & 0x3) << 0)
+#define PHY_STOP_WAIT_TIME(cycle)      (((cycle) & 0xff) << 8)
+
+#define DSI_PHY_STATUS                 0xb0
+#define LOCK                           BIT(0)
+#define STOP_STATE_CLK_LANE            BIT(2)
+
+#define DSI_PHY_TST_CTRL0              0xb4
+#define PHY_TESTCLK                    BIT(1)
+#define PHY_UNTESTCLK                  0
+#define PHY_TESTCLR                    BIT(0)
+#define PHY_UNTESTCLR                  0
+
+#define DSI_PHY_TST_CTRL1              0xb8
+#define PHY_TESTEN                     BIT(16)
+#define PHY_UNTESTEN                   0
+#define PHY_TESTDOUT(n)                        (((n) & 0xff) << 8)
+#define PHY_TESTDIN(n)                 (((n) & 0xff) << 0)
+
+#define DSI_INT_ST0                    0xbc
+#define DSI_INT_ST1                    0xc0
+#define DSI_INT_MSK0                   0xc4
+#define DSI_INT_MSK1                   0xc8
+
+#define PHY_STATUS_TIMEOUT_US          10000
+#define CMD_PKT_STATUS_TIMEOUT_US      20000
+
+#define BYPASS_VCO_RANGE       BIT(7)
+#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
+#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
+#define VCO_IN_CAP_CON_LOW     (0x1 << 1)
+#define VCO_IN_CAP_CON_HIGH    (0x2 << 1)
+#define REF_BIAS_CUR_SEL       BIT(0)
+
+#define CP_CURRENT_3UA 0x1
+#define CP_CURRENT_4_5UA       0x2
+#define CP_CURRENT_7_5UA       0x6
+#define CP_CURRENT_6UA 0x9
+#define CP_CURRENT_12UA        0xb
+#define CP_CURRENT_SEL(val)    ((val) & 0xf)
+#define CP_PROGRAM_EN          BIT(7)
+
+#define LPF_RESISTORS_15_5KOHM 0x1
+#define LPF_RESISTORS_13KOHM   0x2
+#define LPF_RESISTORS_11_5KOHM 0x4
+#define LPF_RESISTORS_10_5KOHM 0x8
+#define LPF_RESISTORS_8KOHM    0x10
+#define LPF_PROGRAM_EN         BIT(6)
+#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
+
+#define HSFREQRANGE_SEL(val)   (((val) & 0x3f) << 1)
+
+#define INPUT_DIVIDER(val)     (((val) - 1) & 0x7f)
+#define LOW_PROGRAM_EN         0
+#define HIGH_PROGRAM_EN                BIT(7)
+#define LOOP_DIV_LOW_SEL(val)  (((val) - 1) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
+#define PLL_LOOP_DIV_EN                BIT(5)
+#define PLL_INPUT_DIV_EN       BIT(4)
+
+#define POWER_CONTROL          BIT(6)
+#define INTERNAL_REG_CURRENT   BIT(3)
+#define BIAS_BLOCK_ON          BIT(2)
+#define BANDGAP_ON             BIT(0)
+
+#define TER_RESISTOR_HIGH      BIT(7)
+#define        TER_RESISTOR_LOW        0
+#define LEVEL_SHIFTERS_ON      BIT(6)
+#define TER_CAL_DONE           BIT(5)
+#define SETRD_MAX              (0x7 << 2)
+#define POWER_MANAGE           BIT(1)
+#define TER_RESISTORS_ON       BIT(0)
+
+#define BIASEXTR_SEL(val)      ((val) & 0x7)
+#define BANDGAP_SEL(val)       ((val) & 0x7)
+#define TLP_PROGRAM_EN         BIT(7)
+#define THS_PRE_PROGRAM_EN     BIT(7)
+#define THS_ZERO_PROGRAM_EN    BIT(6)
+
+#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL               0x10
+#define PLL_CP_CONTROL_PLL_LOCK_BYPASS                 0x11
+#define PLL_LPF_AND_CP_CONTROL                         0x12
+#define PLL_INPUT_DIVIDER_RATIO                                0x17
+#define PLL_LOOP_DIVIDER_RATIO                         0x18
+#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL      0x19
+#define BANDGAP_AND_BIAS_CONTROL                       0x20
+#define TERMINATION_RESISTER_CONTROL                   0x21
+#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY                0x22
+#define HS_RX_CONTROL_OF_LANE_0                                0x44
+#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL    0x60
+#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL    0x61
+#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL    0x62
+#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL      0x63
+#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL       0x64
+#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL             0x65
+#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL     0x70
+#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL     0x71
+#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL     0x72
+#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL       0x73
+#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL                0x74
+
+#define DW_MIPI_NEEDS_PHY_CFG_CLK      BIT(0)
+#define DW_MIPI_NEEDS_GRF_CLK          BIT(1)
+
+#define RK3288_GRF_SOC_CON6            0x025c
+#define RK3288_DSI0_LCDC_SEL           BIT(6)
+#define RK3288_DSI1_LCDC_SEL           BIT(9)
+
+#define RK3399_GRF_SOC_CON20           0x6250
+#define RK3399_DSI0_LCDC_SEL           BIT(0)
+#define RK3399_DSI1_LCDC_SEL           BIT(4)
+
+#define RK3399_GRF_SOC_CON22           0x6258
+#define RK3399_DSI0_TURNREQUEST                (0xf << 12)
+#define RK3399_DSI0_TURNDISABLE                (0xf << 8)
+#define RK3399_DSI0_FORCETXSTOPMODE    (0xf << 4)
+#define RK3399_DSI0_FORCERXMODE                (0xf << 0)
+
+#define RK3399_GRF_SOC_CON23           0x625c
+#define RK3399_DSI1_TURNDISABLE                (0xf << 12)
+#define RK3399_DSI1_FORCETXSTOPMODE    (0xf << 8)
+#define RK3399_DSI1_FORCERXMODE                (0xf << 4)
+#define RK3399_DSI1_ENABLE             (0xf << 0)
+
+#define RK3399_GRF_SOC_CON24           0x6260
+#define RK3399_TXRX_MASTERSLAVEZ       BIT(7)
+#define RK3399_TXRX_ENABLECLK          BIT(6)
+#define RK3399_TXRX_BASEDIR            BIT(5)
+
+#define HIWORD_UPDATE(val, mask)       (val | (mask) << 16)
+
+#define to_dsi(nm)     container_of(nm, struct dw_mipi_dsi_rockchip, nm)
+
+enum {
+       BANDGAP_97_07,
+       BANDGAP_98_05,
+       BANDGAP_99_02,
+       BANDGAP_100_00,
+       BANDGAP_93_17,
+       BANDGAP_94_15,
+       BANDGAP_95_12,
+       BANDGAP_96_10,
+};
+
+enum {
+       BIASEXTR_87_1,
+       BIASEXTR_91_5,
+       BIASEXTR_95_9,
+       BIASEXTR_100,
+       BIASEXTR_105_94,
+       BIASEXTR_111_88,
+       BIASEXTR_118_8,
+       BIASEXTR_127_7,
+};
+
+struct rockchip_dw_dsi_chip_data {
+       u32 reg;
+
+       u32 lcdsel_grf_reg;
+       u32 lcdsel_big;
+       u32 lcdsel_lit;
+
+       u32 enable_grf_reg;
+       u32 enable;
+
+       u32 lanecfg1_grf_reg;
+       u32 lanecfg1;
+       u32 lanecfg2_grf_reg;
+       u32 lanecfg2;
+
+       unsigned int flags;
+       unsigned int max_data_lanes;
+};
+
+struct dw_mipi_dsi_rockchip {
+       struct device *dev;
+       struct drm_encoder encoder;
+       void __iomem *base;
+
+       struct regmap *grf_regmap;
+       struct clk *pllref_clk;
+       struct clk *grf_clk;
+       struct clk *phy_cfg_clk;
+
+       /* dual-channel */
+       bool is_slave;
+       struct dw_mipi_dsi_rockchip *slave;
+
+       unsigned int lane_mbps; /* per lane */
+       u16 input_div;
+       u16 feedback_div;
+       u32 format;
+
+       struct dw_mipi_dsi *dmd;
+       const struct rockchip_dw_dsi_chip_data *cdata;
+       struct dw_mipi_dsi_plat_data pdata;
+       int devcnt;
+};
+
+struct dphy_pll_parameter_map {
+       unsigned int max_mbps;
+       u8 hsfreqrange;
+       u8 icpctrl;
+       u8 lpfctrl;
+};
+
+/* The table is based on 27MHz DPHY pll reference clock. */
+static const struct dphy_pll_parameter_map dppa_map[] = {
+       {  89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+       {  99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+       { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+       { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+       { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+       { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+       { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+       { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+       { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+       { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
+       { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
+       { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+       { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
+       { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
+       { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+       { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+       { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+       {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+       {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+       {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+       {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }
+};
+
+static int max_mbps_to_parameter(unsigned int max_mbps)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
+               if (dppa_map[i].max_mbps >= max_mbps)
+                       return i;
+
+       return -EINVAL;
+}
+
+static inline void dsi_write(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 val)
+{
+       writel(val, dsi->base + reg);
+}
+
+static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg)
+{
+       return readl(dsi->base + reg);
+}
+
+static inline void dsi_set(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 mask)
+{
+       dsi_write(dsi, reg, dsi_read(dsi, reg) | mask);
+}
+
+static inline void dsi_update_bits(struct dw_mipi_dsi_rockchip *dsi, u32 reg,
+                                  u32 mask, u32 val)
+{
+       dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
+}
+
+static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi,
+                                 u8 test_code,
+                                 u8 test_data)
+{
+       /*
+        * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
+        * is latched internally as the current test code. Test data is
+        * programmed internally by rising edge on TESTCLK.
+        */
+       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+
+       dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
+                                         PHY_TESTDIN(test_code));
+
+       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+
+       dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
+                                         PHY_TESTDIN(test_data));
+
+       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+}
+
+/**
+ * ns2bc - Nanoseconds to byte clock cycles
+ */
+static inline unsigned int ns2bc(struct dw_mipi_dsi_rockchip *dsi, int ns)
+{
+       return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
+}
+
+/**
+ * ns2ui - Nanoseconds to UI time periods
+ */
+static inline unsigned int ns2ui(struct dw_mipi_dsi_rockchip *dsi, int ns)
+{
+       return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
+}
+
+static int dw_mipi_dsi_phy_init(void *priv_data)
+{
+       struct dw_mipi_dsi_rockchip *dsi = priv_data;
+       int ret, i, vco;
+
+       /*
+        * Get vco from frequency(lane_mbps)
+        * vco  frequency table
+        * 000 - between   80 and  200 MHz
+        * 001 - between  200 and  300 MHz
+        * 010 - between  300 and  500 MHz
+        * 011 - between  500 and  700 MHz
+        * 100 - between  700 and  900 MHz
+        * 101 - between  900 and 1100 MHz
+        * 110 - between 1100 and 1300 MHz
+        * 111 - between 1300 and 1500 MHz
+        */
+       vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
+
+       i = max_mbps_to_parameter(dsi->lane_mbps);
+       if (i < 0) {
+               DRM_DEV_ERROR(dsi->dev,
+                             "failed to get parameter for %dmbps clock\n",
+                             dsi->lane_mbps);
+               return i;
+       }
+
+       ret = clk_prepare_enable(dsi->phy_cfg_clk);
+       if (ret) {
+               DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
+               return ret;
+       }
+
+       dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
+                             BYPASS_VCO_RANGE |
+                             VCO_RANGE_CON_SEL(vco) |
+                             VCO_IN_CAP_CON_LOW |
+                             REF_BIAS_CUR_SEL);
+
+       dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
+                             CP_CURRENT_SEL(dppa_map[i].icpctrl));
+       dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
+                             CP_PROGRAM_EN | LPF_PROGRAM_EN |
+                             LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
+
+       dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
+                             HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
+
+       dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
+                             INPUT_DIVIDER(dsi->input_div));
+       dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+                             LOOP_DIV_LOW_SEL(dsi->feedback_div) |
+                             LOW_PROGRAM_EN);
+       /*
+        * We need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
+        * to make the configured LSB effective according to IP simulation
+        * and lab test results.
+        * Only in this way can we get correct mipi phy pll frequency.
+        */
+       dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+                             PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+       dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+                             LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
+                             HIGH_PROGRAM_EN);
+       dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+                             PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+
+       dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+                             LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
+       dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+                             HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
+
+       dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
+                             POWER_CONTROL | INTERNAL_REG_CURRENT |
+                             BIAS_BLOCK_ON | BANDGAP_ON);
+
+       dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+                             TER_RESISTOR_LOW | TER_CAL_DONE |
+                             SETRD_MAX | TER_RESISTORS_ON);
+       dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+                             TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
+                             SETRD_MAX | POWER_MANAGE |
+                             TER_RESISTORS_ON);
+
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
+                             TLP_PROGRAM_EN | ns2bc(dsi, 500));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
+                             THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
+                             THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
+                             THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
+                             BIT(5) | ns2bc(dsi, 100));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
+                             BIT(5) | (ns2bc(dsi, 60) + 7));
+
+       dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
+                             TLP_PROGRAM_EN | ns2bc(dsi, 500));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
+                             THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
+                             THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
+                             THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
+       dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
+                             BIT(5) | ns2bc(dsi, 100));
+
+       clk_disable_unprepare(dsi->phy_cfg_clk);
+
+       return ret;
+}
+
+static int
+dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
+                         unsigned long mode_flags, u32 lanes, u32 format,
+                         unsigned int *lane_mbps)
+{
+       struct dw_mipi_dsi_rockchip *dsi = priv_data;
+       int bpp;
+       unsigned long mpclk, tmp;
+       unsigned int target_mbps = 1000;
+       unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
+       unsigned long best_freq = 0;
+       unsigned long fvco_min, fvco_max, fin, fout;
+       unsigned int min_prediv, max_prediv;
+       unsigned int _prediv, uninitialized_var(best_prediv);
+       unsigned long _fbdiv, uninitialized_var(best_fbdiv);
+       unsigned long min_delta = ULONG_MAX;
+
+       dsi->format = format;
+       bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+       if (bpp < 0) {
+               DRM_DEV_ERROR(dsi->dev,
+                             "failed to get bpp for pixel format %d\n",
+                             dsi->format);
+               return bpp;
+       }
+
+       mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
+       if (mpclk) {
+               /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
+               tmp = mpclk * (bpp / lanes) * 10 / 8;
+               if (tmp < max_mbps)
+                       target_mbps = tmp;
+               else
+                       DRM_DEV_ERROR(dsi->dev,
+                                     "DPHY clock frequency is out of range\n");
+       }
+
+       fin = clk_get_rate(dsi->pllref_clk);
+       fout = target_mbps * USEC_PER_SEC;
+
+       /* constraint: 5Mhz <= Fref / N <= 40MHz */
+       min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
+       max_prediv = fin / (5 * USEC_PER_SEC);
+
+       /* constraint: 80MHz <= Fvco <= 1500Mhz */
+       fvco_min = 80 * USEC_PER_SEC;
+       fvco_max = 1500 * USEC_PER_SEC;
+
+       for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
+               u64 tmp;
+               u32 delta;
+               /* Fvco = Fref * M / N */
+               tmp = (u64)fout * _prediv;
+               do_div(tmp, fin);
+               _fbdiv = tmp;
+               /*
+                * Due to the use of a "by 2 pre-scaler," the range of the
+                * feedback multiplication value M is limited to even division
+                * numbers, and m must be greater than 6, not bigger than 512.
+                */
+               if (_fbdiv < 6 || _fbdiv > 512)
+                       continue;
+
+               _fbdiv += _fbdiv % 2;
+
+               tmp = (u64)_fbdiv * fin;
+               do_div(tmp, _prediv);
+               if (tmp < fvco_min || tmp > fvco_max)
+                       continue;
+
+               delta = abs(fout - tmp);
+               if (delta < min_delta) {
+                       best_prediv = _prediv;
+                       best_fbdiv = _fbdiv;
+                       min_delta = delta;
+                       best_freq = tmp;
+               }
+       }
+
+       if (best_freq) {
+               dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
+               *lane_mbps = dsi->lane_mbps;
+               dsi->input_div = best_prediv;
+               dsi->feedback_div = best_fbdiv;
+       } else {
+               DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
+       .init = dw_mipi_dsi_phy_init,
+       .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
+};
+
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
+                                       int mux)
+{
+       if (dsi->cdata->lcdsel_grf_reg)
+               regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+                       mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+
+       if (dsi->cdata->lanecfg1_grf_reg)
+               regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
+                                             dsi->cdata->lanecfg1);
+
+       if (dsi->cdata->lanecfg2_grf_reg)
+               regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg2_grf_reg,
+                                             dsi->cdata->lanecfg2);
+
+       if (dsi->cdata->enable_grf_reg)
+               regmap_write(dsi->grf_regmap, dsi->cdata->enable_grf_reg,
+                                             dsi->cdata->enable);
+}
+
+static int
+dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+                                struct drm_crtc_state *crtc_state,
+                                struct drm_connector_state *conn_state)
+{
+       struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+       struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+
+       switch (dsi->format) {
+       case MIPI_DSI_FMT_RGB888:
+               s->output_mode = ROCKCHIP_OUT_MODE_P888;
+               break;
+       case MIPI_DSI_FMT_RGB666:
+               s->output_mode = ROCKCHIP_OUT_MODE_P666;
+               break;
+       case MIPI_DSI_FMT_RGB565:
+               s->output_mode = ROCKCHIP_OUT_MODE_P565;
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       s->output_type = DRM_MODE_CONNECTOR_DSI;
+       if (dsi->slave)
+               s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL;
+
+       return 0;
+}
+
+static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+       struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+       int ret, mux;
+
+       mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
+                                               &dsi->encoder);
+       if (mux < 0)
+               return;
+
+       pm_runtime_get_sync(dsi->dev);
+       if (dsi->slave)
+               pm_runtime_get_sync(dsi->slave->dev);
+
+       /*
+        * For the RK3399, the clk of grf must be enabled before writing grf
+        * register. And for RK3288 or other soc, this grf_clk must be NULL,
+        * the clk_prepare_enable return true directly.
+        */
+       ret = clk_prepare_enable(dsi->grf_clk);
+       if (ret) {
+               DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+               return;
+       }
+
+       dw_mipi_dsi_rockchip_config(dsi, mux);
+       if (dsi->slave)
+               dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+
+       clk_disable_unprepare(dsi->grf_clk);
+}
+
+static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+       struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+
+       if (dsi->slave)
+               pm_runtime_put(dsi->slave->dev);
+       pm_runtime_put(dsi->dev);
+}
+
+static const struct drm_encoder_helper_funcs
+dw_mipi_dsi_encoder_helper_funcs = {
+       .atomic_check = dw_mipi_dsi_encoder_atomic_check,
+       .enable = dw_mipi_dsi_encoder_enable,
+       .disable = dw_mipi_dsi_encoder_disable,
+};
+
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
+                                          struct drm_device *drm_dev)
+{
+       struct drm_encoder *encoder = &dsi->encoder;
+       int ret;
+
+       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
+                                                            dsi->dev->of_node);
+
+       ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi_encoder_funcs,
+                              DRM_MODE_ENCODER_DSI, NULL);
+       if (ret) {
+               DRM_ERROR("Failed to initialize encoder with drm\n");
+               return ret;
+       }
+
+       drm_encoder_helper_add(encoder, &dw_mipi_dsi_encoder_helper_funcs);
+
+       return 0;
+}
+
+static struct device
+*dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi)
+{
+       const struct of_device_id *match;
+       struct device_node *node = NULL, *local;
+
+       match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev);
+
+       local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0);
+       if (!local)
+               return NULL;
+
+       while ((node = of_find_compatible_node(node, NULL,
+                                              match->compatible))) {
+               struct device_node *remote;
+
+               /* found ourself */
+               if (node == dsi->dev->of_node)
+                       continue;
+
+               remote = of_graph_get_remote_node(node, 1, 0);
+               if (!remote)
+                       continue;
+
+               /* same display device in port1-ep0 for both */
+               if (remote == local) {
+                       struct dw_mipi_dsi_rockchip *dsi2;
+                       struct platform_device *pdev;
+
+                       pdev = of_find_device_by_node(node);
+
+                       /*
+                        * we have found the second, so will either return it
+                        * or return with an error. In any case won't need the
+                        * nodes anymore nor continue the loop.
+                        */
+                       of_node_put(remote);
+                       of_node_put(node);
+                       of_node_put(local);
+
+                       if (!pdev)
+                               return ERR_PTR(-EPROBE_DEFER);
+
+                       dsi2 = platform_get_drvdata(pdev);
+                       if (!dsi2) {
+                               platform_device_put(pdev);
+                               return ERR_PTR(-EPROBE_DEFER);
+                       }
+
+                       return &pdev->dev;
+               }
+
+               of_node_put(remote);
+       }
+
+       of_node_put(local);
+
+       return NULL;
+}
+
+static int dw_mipi_dsi_rockchip_bind(struct device *dev,
+                                    struct device *master,
+                                    void *data)
+{
+       struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
+       struct device *second;
+       bool master1, master2;
+       int ret;
+
+       second = dw_mipi_dsi_rockchip_find_second(dsi);
+       if (IS_ERR(second))
+               return PTR_ERR(second);
+
+       if (second) {
+               master1 = of_property_read_bool(dsi->dev->of_node,
+                                               "clock-master");
+               master2 = of_property_read_bool(second->of_node,
+                                               "clock-master");
+
+               if (master1 && master2) {
+                       DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n");
+                       return -EINVAL;
+               }
+
+               if (!master1 && !master2) {
+                       DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n");
+                       return -EINVAL;
+               }
+
+               /* we are the slave in dual-DSI */
+               if (!master1) {
+                       dsi->is_slave = true;
+                       return 0;
+               }
+
+               dsi->slave = dev_get_drvdata(second);
+               if (!dsi->slave) {
+                       DRM_DEV_ERROR(dev, "could not get slaves data\n");
+                       return -ENODEV;
+               }
+
+               dsi->slave->is_slave = true;
+               dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd);
+               put_device(second);
+       }
+
+       ret = clk_prepare_enable(dsi->pllref_clk);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
+               return ret;
+       }
+
+       ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
+                                       struct device *master,
+                                       void *data)
+{
+       struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
+
+       if (dsi->is_slave)
+               return;
+
+       dw_mipi_dsi_unbind(dsi->dmd);
+
+       clk_disable_unprepare(dsi->pllref_clk);
+}
+
+static const struct component_ops dw_mipi_dsi_rockchip_ops = {
+       .bind   = dw_mipi_dsi_rockchip_bind,
+       .unbind = dw_mipi_dsi_rockchip_unbind,
+};
+
+static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
+                                           struct mipi_dsi_device *device)
+{
+       struct dw_mipi_dsi_rockchip *dsi = priv_data;
+       struct device *second;
+       int ret;
+
+       ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+       if (ret) {
+               DRM_DEV_ERROR(dsi->dev, "Failed to register component: %d\n",
+                                       ret);
+               return ret;
+       }
+
+       second = dw_mipi_dsi_rockchip_find_second(dsi);
+       if (IS_ERR(second))
+               return PTR_ERR(second);
+       if (second) {
+               ret = component_add(second, &dw_mipi_dsi_rockchip_ops);
+               if (ret) {
+                       DRM_DEV_ERROR(second,
+                                     "Failed to register component: %d\n",
+                                     ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int dw_mipi_dsi_rockchip_host_detach(void *priv_data,
+                                           struct mipi_dsi_device *device)
+{
+       struct dw_mipi_dsi_rockchip *dsi = priv_data;
+       struct device *second;
+
+       second = dw_mipi_dsi_rockchip_find_second(dsi);
+       if (second && !IS_ERR(second))
+               component_del(second, &dw_mipi_dsi_rockchip_ops);
+
+       component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+
+       return 0;
+}
+
+static const struct dw_mipi_dsi_host_ops dw_mipi_dsi_rockchip_host_ops = {
+       .attach = dw_mipi_dsi_rockchip_host_attach,
+       .detach = dw_mipi_dsi_rockchip_host_detach,
+};
+
+static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct dw_mipi_dsi_rockchip *dsi;
+       struct resource *res;
+       const struct rockchip_dw_dsi_chip_data *cdata =
+                               of_device_get_match_data(dev);
+       int ret, i;
+
+       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dsi->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dsi->base)) {
+               DRM_DEV_ERROR(dev, "Unable to get dsi registers\n");
+               return PTR_ERR(dsi->base);
+       }
+
+       i = 0;
+       while (cdata[i].reg) {
+               if (cdata[i].reg == res->start) {
+                       dsi->cdata = &cdata[i];
+                       break;
+               }
+
+               i++;
+       }
+
+       if (!dsi->cdata) {
+               dev_err(dev, "no dsi-config for %s node\n", np->name);
+               return -EINVAL;
+       }
+
+       dsi->pllref_clk = devm_clk_get(dev, "ref");
+       if (IS_ERR(dsi->pllref_clk)) {
+               ret = PTR_ERR(dsi->pllref_clk);
+               DRM_DEV_ERROR(dev,
+                             "Unable to get pll reference clock: %d\n", ret);
+               return ret;
+       }
+
+       if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
+               dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+               if (IS_ERR(dsi->phy_cfg_clk)) {
+                       ret = PTR_ERR(dsi->phy_cfg_clk);
+                       DRM_DEV_ERROR(dev,
+                                     "Unable to get phy_cfg_clk: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (dsi->cdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
+               dsi->grf_clk = devm_clk_get(dev, "grf");
+               if (IS_ERR(dsi->grf_clk)) {
+                       ret = PTR_ERR(dsi->grf_clk);
+                       DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+       if (IS_ERR(dsi->grf_regmap)) {
+               DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
+               return PTR_ERR(dsi->grf_regmap);
+       }
+
+       dsi->dev = dev;
+       dsi->pdata.base = dsi->base;
+       dsi->pdata.max_data_lanes = dsi->cdata->max_data_lanes;
+       dsi->pdata.phy_ops = &dw_mipi_dsi_rockchip_phy_ops;
+       dsi->pdata.host_ops = &dw_mipi_dsi_rockchip_host_ops;
+       dsi->pdata.priv_data = dsi;
+       platform_set_drvdata(pdev, dsi);
+
+       dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
+       if (IS_ERR(dsi->dmd)) {
+               ret = PTR_ERR(dsi->dmd);
+               if (ret != -EPROBE_DEFER)
+                       DRM_DEV_ERROR(dev,
+                                     "Failed to probe dw_mipi_dsi: %d\n", ret);
+               goto err_clkdisable;
+       }
+
+       return 0;
+
+err_clkdisable:
+       clk_disable_unprepare(dsi->pllref_clk);
+       return ret;
+}
+
+static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
+{
+       struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
+
+       if (dsi->devcnt == 0)
+               component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+
+       dw_mipi_dsi_remove(dsi->dmd);
+
+       return 0;
+}
+
+static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
+       {
+               .reg = 0xff960000,
+               .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
+               .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI0_LCDC_SEL),
+               .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI0_LCDC_SEL, RK3288_DSI0_LCDC_SEL),
+
+               .max_data_lanes = 4,
+       },
+       {
+               .reg = 0xff964000,
+               .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
+               .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI1_LCDC_SEL),
+               .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI1_LCDC_SEL, RK3288_DSI1_LCDC_SEL),
+
+               .max_data_lanes = 4,
+       },
+       { /* sentinel */ }
+};
+
+static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
+       {
+               .reg = 0xff960000,
+               .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
+               .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL),
+               .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL,
+                                           RK3399_DSI0_LCDC_SEL),
+
+               .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22,
+               .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST |
+                                            RK3399_DSI0_TURNDISABLE |
+                                            RK3399_DSI0_FORCETXSTOPMODE |
+                                            RK3399_DSI0_FORCERXMODE),
+
+               .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
+               .max_data_lanes = 4,
+       },
+       {
+               .reg = 0xff968000,
+               .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
+               .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL),
+               .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL,
+                                           RK3399_DSI1_LCDC_SEL),
+
+               .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23,
+               .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE |
+                                            RK3399_DSI1_FORCETXSTOPMODE |
+                                            RK3399_DSI1_FORCERXMODE |
+                                            RK3399_DSI1_ENABLE),
+
+               .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24,
+               .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ |
+                                         RK3399_TXRX_ENABLECLK,
+                                         RK3399_TXRX_MASTERSLAVEZ |
+                                         RK3399_TXRX_ENABLECLK |
+                                         RK3399_TXRX_BASEDIR),
+
+               .enable_grf_reg = RK3399_GRF_SOC_CON23,
+               .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE),
+
+               .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
+               .max_data_lanes = 4,
+       },
+       { /* sentinel */ }
+};
+
+static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
+       {
+        .compatible = "rockchip,rk3288-mipi-dsi",
+        .data = &rk3288_chip_data,
+       }, {
+        .compatible = "rockchip,rk3399-mipi-dsi",
+        .data = &rk3399_chip_data,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dw_mipi_dsi_rockchip_dt_ids);
+
+struct platform_driver dw_mipi_dsi_rockchip_driver = {
+       .probe          = dw_mipi_dsi_rockchip_probe,
+       .remove         = dw_mipi_dsi_rockchip_remove,
+       .driver         = {
+               .of_match_table = dw_mipi_dsi_rockchip_dt_ids,
+               .name   = "dw-mipi-dsi-rockchip",
+       },
+};
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
deleted file mode 100644 (file)
index 662b6cb..0000000
+++ /dev/null
@@ -1,1349 +0,0 @@
-/*
- * Copyright (c) 2016, Fuzhou Rockchip 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.
- */
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <linux/iopoll.h>
-#include <linux/math64.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/reset.h>
-#include <linux/mfd/syscon.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drmP.h>
-#include <video/mipi_display.h>
-
-#include "rockchip_drm_drv.h"
-#include "rockchip_drm_vop.h"
-
-#define DRIVER_NAME    "dw-mipi-dsi"
-
-#define RK3288_GRF_SOC_CON6            0x025c
-#define RK3288_DSI0_SEL_VOP_LIT                BIT(6)
-#define RK3288_DSI1_SEL_VOP_LIT                BIT(9)
-
-#define RK3399_GRF_SOC_CON20           0x6250
-#define RK3399_DSI0_SEL_VOP_LIT                BIT(0)
-#define RK3399_DSI1_SEL_VOP_LIT                BIT(4)
-
-/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
-#define RK3399_GRF_SOC_CON22           0x6258
-#define RK3399_GRF_DSI_MODE            0xffff0000
-
-#define DSI_VERSION                    0x00
-#define DSI_PWR_UP                     0x04
-#define RESET                          0
-#define POWERUP                                BIT(0)
-
-#define DSI_CLKMGR_CFG                 0x08
-#define TO_CLK_DIVIDSION(div)          (((div) & 0xff) << 8)
-#define TX_ESC_CLK_DIVIDSION(div)      (((div) & 0xff) << 0)
-
-#define DSI_DPI_VCID                   0x0c
-#define DPI_VID(vid)                   (((vid) & 0x3) << 0)
-
-#define DSI_DPI_COLOR_CODING           0x10
-#define EN18_LOOSELY                   BIT(8)
-#define DPI_COLOR_CODING_16BIT_1       0x0
-#define DPI_COLOR_CODING_16BIT_2       0x1
-#define DPI_COLOR_CODING_16BIT_3       0x2
-#define DPI_COLOR_CODING_18BIT_1       0x3
-#define DPI_COLOR_CODING_18BIT_2       0x4
-#define DPI_COLOR_CODING_24BIT         0x5
-
-#define DSI_DPI_CFG_POL                        0x14
-#define COLORM_ACTIVE_LOW              BIT(4)
-#define SHUTD_ACTIVE_LOW               BIT(3)
-#define HSYNC_ACTIVE_LOW               BIT(2)
-#define VSYNC_ACTIVE_LOW               BIT(1)
-#define DATAEN_ACTIVE_LOW              BIT(0)
-
-#define DSI_DPI_LP_CMD_TIM             0x18
-#define OUTVACT_LPCMD_TIME(p)          (((p) & 0xff) << 16)
-#define INVACT_LPCMD_TIME(p)           ((p) & 0xff)
-
-#define DSI_DBI_CFG                    0x20
-#define DSI_DBI_CMDSIZE                        0x28
-
-#define DSI_PCKHDL_CFG                 0x2c
-#define EN_CRC_RX                      BIT(4)
-#define EN_ECC_RX                      BIT(3)
-#define EN_BTA                         BIT(2)
-#define EN_EOTP_RX                     BIT(1)
-#define EN_EOTP_TX                     BIT(0)
-
-#define DSI_MODE_CFG                   0x34
-#define ENABLE_VIDEO_MODE              0
-#define ENABLE_CMD_MODE                        BIT(0)
-
-#define DSI_VID_MODE_CFG               0x38
-#define FRAME_BTA_ACK                  BIT(14)
-#define ENABLE_LOW_POWER               (0x3f << 8)
-#define ENABLE_LOW_POWER_MASK          (0x3f << 8)
-#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES    0x0
-#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS    0x1
-#define VID_MODE_TYPE_BURST                    0x2
-#define VID_MODE_TYPE_MASK                     0x3
-
-#define DSI_VID_PKT_SIZE               0x3c
-#define VID_PKT_SIZE(p)                        (((p) & 0x3fff) << 0)
-#define VID_PKT_MAX_SIZE               0x3fff
-
-#define DSI_VID_HSA_TIME               0x48
-#define DSI_VID_HBP_TIME               0x4c
-#define DSI_VID_HLINE_TIME             0x50
-#define DSI_VID_VSA_LINES              0x54
-#define DSI_VID_VBP_LINES              0x58
-#define DSI_VID_VFP_LINES              0x5c
-#define DSI_VID_VACTIVE_LINES          0x60
-#define DSI_CMD_MODE_CFG               0x68
-#define MAX_RD_PKT_SIZE_LP             BIT(24)
-#define DCS_LW_TX_LP                   BIT(19)
-#define DCS_SR_0P_TX_LP                        BIT(18)
-#define DCS_SW_1P_TX_LP                        BIT(17)
-#define DCS_SW_0P_TX_LP                        BIT(16)
-#define GEN_LW_TX_LP                   BIT(14)
-#define GEN_SR_2P_TX_LP                        BIT(13)
-#define GEN_SR_1P_TX_LP                        BIT(12)
-#define GEN_SR_0P_TX_LP                        BIT(11)
-#define GEN_SW_2P_TX_LP                        BIT(10)
-#define GEN_SW_1P_TX_LP                        BIT(9)
-#define GEN_SW_0P_TX_LP                        BIT(8)
-#define EN_ACK_RQST                    BIT(1)
-#define EN_TEAR_FX                     BIT(0)
-
-#define CMD_MODE_ALL_LP                        (MAX_RD_PKT_SIZE_LP | \
-                                        DCS_LW_TX_LP | \
-                                        DCS_SR_0P_TX_LP | \
-                                        DCS_SW_1P_TX_LP | \
-                                        DCS_SW_0P_TX_LP | \
-                                        GEN_LW_TX_LP | \
-                                        GEN_SR_2P_TX_LP | \
-                                        GEN_SR_1P_TX_LP | \
-                                        GEN_SR_0P_TX_LP | \
-                                        GEN_SW_2P_TX_LP | \
-                                        GEN_SW_1P_TX_LP | \
-                                        GEN_SW_0P_TX_LP)
-
-#define DSI_GEN_HDR                    0x6c
-#define GEN_HDATA(data)                        (((data) & 0xffff) << 8)
-#define GEN_HDATA_MASK                 (0xffff << 8)
-#define GEN_HTYPE(type)                        (((type) & 0xff) << 0)
-#define GEN_HTYPE_MASK                 0xff
-
-#define DSI_GEN_PLD_DATA               0x70
-
-#define DSI_CMD_PKT_STATUS             0x74
-#define GEN_CMD_EMPTY                  BIT(0)
-#define GEN_CMD_FULL                   BIT(1)
-#define GEN_PLD_W_EMPTY                        BIT(2)
-#define GEN_PLD_W_FULL                 BIT(3)
-#define GEN_PLD_R_EMPTY                        BIT(4)
-#define GEN_PLD_R_FULL                 BIT(5)
-#define GEN_RD_CMD_BUSY                        BIT(6)
-
-#define DSI_TO_CNT_CFG                 0x78
-#define HSTX_TO_CNT(p)                 (((p) & 0xffff) << 16)
-#define LPRX_TO_CNT(p)                 ((p) & 0xffff)
-
-#define DSI_BTA_TO_CNT                 0x8c
-#define DSI_LPCLK_CTRL                 0x94
-#define AUTO_CLKLANE_CTRL              BIT(1)
-#define PHY_TXREQUESTCLKHS             BIT(0)
-
-#define DSI_PHY_TMR_LPCLK_CFG          0x98
-#define PHY_CLKHS2LP_TIME(lbcc)                (((lbcc) & 0x3ff) << 16)
-#define PHY_CLKLP2HS_TIME(lbcc)                ((lbcc) & 0x3ff)
-
-#define DSI_PHY_TMR_CFG                        0x9c
-#define PHY_HS2LP_TIME(lbcc)           (((lbcc) & 0xff) << 24)
-#define PHY_LP2HS_TIME(lbcc)           (((lbcc) & 0xff) << 16)
-#define MAX_RD_TIME(lbcc)              ((lbcc) & 0x7fff)
-
-#define DSI_PHY_RSTZ                   0xa0
-#define PHY_DISFORCEPLL                        0
-#define PHY_ENFORCEPLL                 BIT(3)
-#define PHY_DISABLECLK                 0
-#define PHY_ENABLECLK                  BIT(2)
-#define PHY_RSTZ                       0
-#define PHY_UNRSTZ                     BIT(1)
-#define PHY_SHUTDOWNZ                  0
-#define PHY_UNSHUTDOWNZ                        BIT(0)
-
-#define DSI_PHY_IF_CFG                 0xa4
-#define N_LANES(n)                     ((((n) - 1) & 0x3) << 0)
-#define PHY_STOP_WAIT_TIME(cycle)      (((cycle) & 0xff) << 8)
-
-#define DSI_PHY_STATUS                 0xb0
-#define LOCK                           BIT(0)
-#define STOP_STATE_CLK_LANE            BIT(2)
-
-#define DSI_PHY_TST_CTRL0              0xb4
-#define PHY_TESTCLK                    BIT(1)
-#define PHY_UNTESTCLK                  0
-#define PHY_TESTCLR                    BIT(0)
-#define PHY_UNTESTCLR                  0
-
-#define DSI_PHY_TST_CTRL1              0xb8
-#define PHY_TESTEN                     BIT(16)
-#define PHY_UNTESTEN                   0
-#define PHY_TESTDOUT(n)                        (((n) & 0xff) << 8)
-#define PHY_TESTDIN(n)                 (((n) & 0xff) << 0)
-
-#define DSI_INT_ST0                    0xbc
-#define DSI_INT_ST1                    0xc0
-#define DSI_INT_MSK0                   0xc4
-#define DSI_INT_MSK1                   0xc8
-
-#define PHY_STATUS_TIMEOUT_US          10000
-#define CMD_PKT_STATUS_TIMEOUT_US      20000
-
-#define BYPASS_VCO_RANGE       BIT(7)
-#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
-#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
-#define VCO_IN_CAP_CON_LOW     (0x1 << 1)
-#define VCO_IN_CAP_CON_HIGH    (0x2 << 1)
-#define REF_BIAS_CUR_SEL       BIT(0)
-
-#define CP_CURRENT_3MA         BIT(3)
-#define CP_PROGRAM_EN          BIT(7)
-#define LPF_PROGRAM_EN         BIT(6)
-#define LPF_RESISTORS_20_KOHM  0
-
-#define HSFREQRANGE_SEL(val)   (((val) & 0x3f) << 1)
-
-#define INPUT_DIVIDER(val)     (((val) - 1) & 0x7f)
-#define LOW_PROGRAM_EN         0
-#define HIGH_PROGRAM_EN                BIT(7)
-#define LOOP_DIV_LOW_SEL(val)  (((val) - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
-#define PLL_LOOP_DIV_EN                BIT(5)
-#define PLL_INPUT_DIV_EN       BIT(4)
-
-#define POWER_CONTROL          BIT(6)
-#define INTERNAL_REG_CURRENT   BIT(3)
-#define BIAS_BLOCK_ON          BIT(2)
-#define BANDGAP_ON             BIT(0)
-
-#define TER_RESISTOR_HIGH      BIT(7)
-#define        TER_RESISTOR_LOW        0
-#define LEVEL_SHIFTERS_ON      BIT(6)
-#define TER_CAL_DONE           BIT(5)
-#define SETRD_MAX              (0x7 << 2)
-#define POWER_MANAGE           BIT(1)
-#define TER_RESISTORS_ON       BIT(0)
-
-#define BIASEXTR_SEL(val)      ((val) & 0x7)
-#define BANDGAP_SEL(val)       ((val) & 0x7)
-#define TLP_PROGRAM_EN         BIT(7)
-#define THS_PRE_PROGRAM_EN     BIT(7)
-#define THS_ZERO_PROGRAM_EN    BIT(6)
-
-#define DW_MIPI_NEEDS_PHY_CFG_CLK      BIT(0)
-#define DW_MIPI_NEEDS_GRF_CLK          BIT(1)
-
-enum {
-       BANDGAP_97_07,
-       BANDGAP_98_05,
-       BANDGAP_99_02,
-       BANDGAP_100_00,
-       BANDGAP_93_17,
-       BANDGAP_94_15,
-       BANDGAP_95_12,
-       BANDGAP_96_10,
-};
-
-enum {
-       BIASEXTR_87_1,
-       BIASEXTR_91_5,
-       BIASEXTR_95_9,
-       BIASEXTR_100,
-       BIASEXTR_105_94,
-       BIASEXTR_111_88,
-       BIASEXTR_118_8,
-       BIASEXTR_127_7,
-};
-
-struct dw_mipi_dsi_plat_data {
-       u32 dsi0_en_bit;
-       u32 dsi1_en_bit;
-       u32 grf_switch_reg;
-       u32 grf_dsi0_mode;
-       u32 grf_dsi0_mode_reg;
-       unsigned int flags;
-       unsigned int max_data_lanes;
-};
-
-struct dw_mipi_dsi {
-       struct drm_encoder encoder;
-       struct drm_connector connector;
-       struct mipi_dsi_host dsi_host;
-       struct drm_panel *panel;
-       struct device *dev;
-       struct regmap *grf_regmap;
-       void __iomem *base;
-
-       struct clk *grf_clk;
-       struct clk *pllref_clk;
-       struct clk *pclk;
-       struct clk *phy_cfg_clk;
-
-       int dpms_mode;
-       unsigned int lane_mbps; /* per lane */
-       u32 channel;
-       u32 lanes;
-       u32 format;
-       u16 input_div;
-       u16 feedback_div;
-       unsigned long mode_flags;
-
-       const struct dw_mipi_dsi_plat_data *pdata;
-};
-
-enum dw_mipi_dsi_mode {
-       DW_MIPI_DSI_CMD_MODE,
-       DW_MIPI_DSI_VID_MODE,
-};
-
-struct dphy_pll_testdin_map {
-       unsigned int max_mbps;
-       u8 testdin;
-};
-
-/* The table is based on 27MHz DPHY pll reference clock. */
-static const struct dphy_pll_testdin_map dptdin_map[] = {
-       {  90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
-       { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
-       { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
-       { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
-       { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
-       { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
-       { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
-       {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
-       {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
-       {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
-};
-
-static int max_mbps_to_testdin(unsigned int max_mbps)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
-               if (dptdin_map[i].max_mbps > max_mbps)
-                       return dptdin_map[i].testdin;
-
-       return -EINVAL;
-}
-
-/*
- * The controller should generate 2 frames before
- * preparing the peripheral.
- */
-static void dw_mipi_dsi_wait_for_two_frames(struct drm_display_mode *mode)
-{
-       int refresh, two_frames;
-
-       refresh = drm_mode_vrefresh(mode);
-       two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2;
-       msleep(two_frames);
-}
-
-static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host)
-{
-       return container_of(host, struct dw_mipi_dsi, dsi_host);
-}
-
-static inline struct dw_mipi_dsi *con_to_dsi(struct drm_connector *con)
-{
-       return container_of(con, struct dw_mipi_dsi, connector);
-}
-
-static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
-{
-       return container_of(encoder, struct dw_mipi_dsi, encoder);
-}
-
-static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
-{
-       writel(val, dsi->base + reg);
-}
-
-static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
-{
-       return readl(dsi->base + reg);
-}
-
-static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
-                                 u8 test_data)
-{
-       /*
-        * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
-        * is latched internally as the current test code. Test data is
-        * programmed internally by rising edge on TESTCLK.
-        */
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-
-       dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
-                                         PHY_TESTDIN(test_code));
-
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
-
-       dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
-                                         PHY_TESTDIN(test_data));
-
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-}
-
-/**
- * ns2bc - Nanoseconds to byte clock cycles
- */
-static inline unsigned int ns2bc(struct dw_mipi_dsi *dsi, int ns)
-{
-       return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
-}
-
-/**
- * ns2ui - Nanoseconds to UI time periods
- */
-static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
-{
-       return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
-}
-
-static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
-{
-       int ret, testdin, vco, val;
-
-       vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
-
-       testdin = max_mbps_to_testdin(dsi->lane_mbps);
-       if (testdin < 0) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "failed to get testdin for %dmbps lane clock\n",
-                             dsi->lane_mbps);
-               return testdin;
-       }
-
-       /* Start by clearing PHY state */
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR);
-       dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
-
-       ret = clk_prepare_enable(dsi->phy_cfg_clk);
-       if (ret) {
-               DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
-               return ret;
-       }
-
-       dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
-                                        VCO_RANGE_CON_SEL(vco) |
-                                        VCO_IN_CAP_CON_LOW |
-                                        REF_BIAS_CUR_SEL);
-
-       dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
-       dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
-                                        LPF_RESISTORS_20_KOHM);
-
-       dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
-
-       dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
-       dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
-                                        LOW_PROGRAM_EN);
-       dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
-                                        HIGH_PROGRAM_EN);
-       dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
-
-       dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
-                                        BIASEXTR_SEL(BIASEXTR_127_7));
-       dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
-                                        BANDGAP_SEL(BANDGAP_96_10));
-
-       dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
-                                        BIAS_BLOCK_ON | BANDGAP_ON);
-
-       dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
-                                        SETRD_MAX | TER_RESISTORS_ON);
-       dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
-                                        SETRD_MAX | POWER_MANAGE |
-                                        TER_RESISTORS_ON);
-
-       dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
-       dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
-       dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
-       dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
-       dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
-       dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
-
-       dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
-       dw_mipi_dsi_phy_write(dsi, 0x71,
-                             THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
-       dw_mipi_dsi_phy_write(dsi, 0x72,
-                             THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
-       dw_mipi_dsi_phy_write(dsi, 0x73,
-                             THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
-       dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
-
-       dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
-                                    PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
-
-       ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
-                                val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
-       if (ret < 0) {
-               DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n");
-               goto phy_init_end;
-       }
-
-       ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
-                                val, val & STOP_STATE_CLK_LANE, 1000,
-                                PHY_STATUS_TIMEOUT_US);
-       if (ret < 0)
-               DRM_DEV_ERROR(dsi->dev,
-                             "failed to wait for phy clk lane stop state\n");
-
-phy_init_end:
-       clk_disable_unprepare(dsi->phy_cfg_clk);
-
-       return ret;
-}
-
-static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
-                                   struct drm_display_mode *mode)
-{
-       unsigned int i, pre;
-       unsigned long mpclk, pllref, tmp;
-       unsigned int m = 1, n = 1, target_mbps = 1000;
-       unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
-       int bpp;
-
-       bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
-       if (bpp < 0) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "failed to get bpp for pixel format %d\n",
-                             dsi->format);
-               return bpp;
-       }
-
-       mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
-       if (mpclk) {
-               /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
-               tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
-               if (tmp < max_mbps)
-                       target_mbps = tmp;
-               else
-                       DRM_DEV_ERROR(dsi->dev,
-                                     "DPHY clock frequency is out of range\n");
-       }
-
-       pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
-       tmp = pllref;
-
-       /*
-        * The limits on the PLL divisor are:
-        *
-        *      5MHz <= (pllref / n) <= 40MHz
-        *
-        * we walk over these values in descreasing order so that if we hit
-        * an exact match for target_mbps it is more likely that "m" will be
-        * even.
-        *
-        * TODO: ensure that "m" is even after this loop.
-        */
-       for (i = pllref / 5; i > (pllref / 40); i--) {
-               pre = pllref / i;
-               if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
-                       tmp = target_mbps % pre;
-                       n = i;
-                       m = target_mbps / pre;
-               }
-               if (tmp == 0)
-                       break;
-       }
-
-       dsi->lane_mbps = pllref / n * m;
-       dsi->input_div = n;
-       dsi->feedback_div = m;
-
-       return 0;
-}
-
-static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
-                                  struct mipi_dsi_device *device)
-{
-       struct dw_mipi_dsi *dsi = host_to_dsi(host);
-
-       if (device->lanes > dsi->pdata->max_data_lanes) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "the number of data lanes(%u) is too many\n",
-                             device->lanes);
-               return -EINVAL;
-       }
-
-       dsi->lanes = device->lanes;
-       dsi->channel = device->channel;
-       dsi->format = device->format;
-       dsi->mode_flags = device->mode_flags;
-       dsi->panel = of_drm_find_panel(device->dev.of_node);
-       if (!IS_ERR(dsi->panel))
-               return drm_panel_attach(dsi->panel, &dsi->connector);
-
-       return -EINVAL;
-}
-
-static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
-                                  struct mipi_dsi_device *device)
-{
-       struct dw_mipi_dsi *dsi = host_to_dsi(host);
-
-       drm_panel_detach(dsi->panel);
-
-       return 0;
-}
-
-static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
-                                  const struct mipi_dsi_msg *msg)
-{
-       bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
-       u32 val = 0;
-
-       if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
-               val |= EN_ACK_RQST;
-       if (lpm)
-               val |= CMD_MODE_ALL_LP;
-
-       dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
-       dsi_write(dsi, DSI_CMD_MODE_CFG, val);
-}
-
-static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
-{
-       int ret;
-       u32 val, mask;
-
-       ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
-                                val, !(val & GEN_CMD_FULL), 1000,
-                                CMD_PKT_STATUS_TIMEOUT_US);
-       if (ret < 0) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "failed to get available command FIFO\n");
-               return ret;
-       }
-
-       dsi_write(dsi, DSI_GEN_HDR, hdr_val);
-
-       mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
-       ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
-                                val, (val & mask) == mask,
-                                1000, CMD_PKT_STATUS_TIMEOUT_US);
-       if (ret < 0) {
-               DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
-                                      const struct mipi_dsi_msg *msg)
-{
-       const u8 *tx_buf = msg->tx_buf;
-       u16 data = 0;
-       u32 val;
-
-       if (msg->tx_len > 0)
-               data |= tx_buf[0];
-       if (msg->tx_len > 1)
-               data |= tx_buf[1] << 8;
-
-       if (msg->tx_len > 2) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "too long tx buf length %zu for short write\n",
-                             msg->tx_len);
-               return -EINVAL;
-       }
-
-       val = GEN_HDATA(data) | GEN_HTYPE(msg->type);
-       return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
-}
-
-static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
-                                     const struct mipi_dsi_msg *msg)
-{
-       const u8 *tx_buf = msg->tx_buf;
-       int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret;
-       u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
-       u32 remainder;
-       u32 val;
-
-       if (msg->tx_len < 3) {
-               DRM_DEV_ERROR(dsi->dev,
-                             "wrong tx buf length %zu for long write\n",
-                             msg->tx_len);
-               return -EINVAL;
-       }
-
-       while (DIV_ROUND_UP(len, pld_data_bytes)) {
-               if (len < pld_data_bytes) {
-                       remainder = 0;
-                       memcpy(&remainder, tx_buf, len);
-                       dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
-                       len = 0;
-               } else {
-                       memcpy(&remainder, tx_buf, pld_data_bytes);
-                       dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
-                       tx_buf += pld_data_bytes;
-                       len -= pld_data_bytes;
-               }
-
-               ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
-                                        val, !(val & GEN_PLD_W_FULL), 1000,
-                                        CMD_PKT_STATUS_TIMEOUT_US);
-               if (ret < 0) {
-                       DRM_DEV_ERROR(dsi->dev,
-                                     "failed to get available write payload FIFO\n");
-                       return ret;
-               }
-       }
-
-       return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val);
-}
-
-static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
-                                        const struct mipi_dsi_msg *msg)
-{
-       struct dw_mipi_dsi *dsi = host_to_dsi(host);
-       int ret;
-
-       dw_mipi_message_config(dsi, msg);
-
-       switch (msg->type) {
-       case MIPI_DSI_DCS_SHORT_WRITE:
-       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
-       case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
-               ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
-               break;
-       case MIPI_DSI_DCS_LONG_WRITE:
-               ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
-               break;
-       default:
-               DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n",
-                             msg->type);
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
-       .attach = dw_mipi_dsi_host_attach,
-       .detach = dw_mipi_dsi_host_detach,
-       .transfer = dw_mipi_dsi_host_transfer,
-};
-
-static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
-{
-       u32 val;
-
-       val = ENABLE_LOW_POWER;
-
-       if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
-               val |= VID_MODE_TYPE_BURST;
-       else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
-               val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;
-       else
-               val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
-
-       dsi_write(dsi, DSI_VID_MODE_CFG, val);
-}
-
-static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
-                                enum dw_mipi_dsi_mode mode)
-{
-       if (mode == DW_MIPI_DSI_CMD_MODE) {
-               dsi_write(dsi, DSI_PWR_UP, RESET);
-               dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
-               dsi_write(dsi, DSI_PWR_UP, POWERUP);
-       } else {
-               dsi_write(dsi, DSI_PWR_UP, RESET);
-               dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
-               dw_mipi_dsi_video_mode_config(dsi);
-               dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
-               dsi_write(dsi, DSI_PWR_UP, POWERUP);
-       }
-}
-
-static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
-{
-       dsi_write(dsi, DSI_PWR_UP, RESET);
-       dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
-}
-
-static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
-{
-       /*
-        * The maximum permitted escape clock is 20MHz and it is derived from
-        * lanebyteclk, which is running at "lane_mbps / 8".  Thus we want:
-        *
-        *     (lane_mbps >> 3) / esc_clk_division < 20
-        * which is:
-        *     (lane_mbps >> 3) / 20 > esc_clk_division
-        */
-       u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1;
-
-       dsi_write(dsi, DSI_PWR_UP, RESET);
-       dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK
-                 | PHY_RSTZ | PHY_SHUTDOWNZ);
-       dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) |
-                 TX_ESC_CLK_DIVIDSION(esc_clk_division));
-}
-
-static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
-                                  struct drm_display_mode *mode)
-{
-       u32 val = 0, color = 0;
-
-       switch (dsi->format) {
-       case MIPI_DSI_FMT_RGB888:
-               color = DPI_COLOR_CODING_24BIT;
-               break;
-       case MIPI_DSI_FMT_RGB666:
-               color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
-               break;
-       case MIPI_DSI_FMT_RGB666_PACKED:
-               color = DPI_COLOR_CODING_18BIT_1;
-               break;
-       case MIPI_DSI_FMT_RGB565:
-               color = DPI_COLOR_CODING_16BIT_1;
-               break;
-       }
-
-       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-               val |= VSYNC_ACTIVE_LOW;
-       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-               val |= HSYNC_ACTIVE_LOW;
-
-       dsi_write(dsi, DSI_DPI_VCID, DPI_VID(dsi->channel));
-       dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
-       dsi_write(dsi, DSI_DPI_CFG_POL, val);
-       dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4)
-                 | INVACT_LPCMD_TIME(4));
-}
-
-static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
-{
-       dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA);
-}
-
-static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
-                                           struct drm_display_mode *mode)
-{
-       dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
-}
-
-static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
-{
-       dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
-       dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00);
-       dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
-}
-
-/* Get lane byte clock cycles. */
-static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
-                                          struct drm_display_mode *mode,
-                                          u32 hcomponent)
-{
-       u32 frac, lbcc;
-
-       lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
-
-       frac = lbcc % mode->clock;
-       lbcc = lbcc / mode->clock;
-       if (frac)
-               lbcc++;
-
-       return lbcc;
-}
-
-static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi,
-                                         struct drm_display_mode *mode)
-{
-       u32 htotal, hsa, hbp, lbcc;
-
-       htotal = mode->htotal;
-       hsa = mode->hsync_end - mode->hsync_start;
-       hbp = mode->htotal - mode->hsync_end;
-
-       lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal);
-       dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc);
-
-       lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa);
-       dsi_write(dsi, DSI_VID_HSA_TIME, lbcc);
-
-       lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp);
-       dsi_write(dsi, DSI_VID_HBP_TIME, lbcc);
-}
-
-static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
-                                              struct drm_display_mode *mode)
-{
-       u32 vactive, vsa, vfp, vbp;
-
-       vactive = mode->vdisplay;
-       vsa = mode->vsync_end - mode->vsync_start;
-       vfp = mode->vsync_start - mode->vdisplay;
-       vbp = mode->vtotal - mode->vsync_end;
-
-       dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive);
-       dsi_write(dsi, DSI_VID_VSA_LINES, vsa);
-       dsi_write(dsi, DSI_VID_VFP_LINES, vfp);
-       dsi_write(dsi, DSI_VID_VBP_LINES, vbp);
-}
-
-static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
-{
-       dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40)
-                 | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
-
-       dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
-                 | PHY_CLKLP2HS_TIME(0x40));
-}
-
-static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
-{
-       dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
-                 N_LANES(dsi->lanes));
-}
-
-static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
-{
-       dsi_read(dsi, DSI_INT_ST0);
-       dsi_read(dsi, DSI_INT_ST1);
-       dsi_write(dsi, DSI_INT_MSK0, 0);
-       dsi_write(dsi, DSI_INT_MSK1, 0);
-}
-
-static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
-{
-       struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-
-       if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
-               return;
-
-       if (clk_prepare_enable(dsi->pclk)) {
-               DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
-               return;
-       }
-
-       drm_panel_disable(dsi->panel);
-
-       dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
-       drm_panel_unprepare(dsi->panel);
-
-       dw_mipi_dsi_disable(dsi);
-       pm_runtime_put(dsi->dev);
-       clk_disable_unprepare(dsi->pclk);
-       dsi->dpms_mode = DRM_MODE_DPMS_OFF;
-}
-
-static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
-{
-       struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
-       const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
-       int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
-       u32 val;
-       int ret;
-
-       ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
-       if (ret < 0)
-               return;
-
-       if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
-               return;
-
-       if (clk_prepare_enable(dsi->pclk)) {
-               DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
-               return;
-       }
-
-       pm_runtime_get_sync(dsi->dev);
-       dw_mipi_dsi_init(dsi);
-       dw_mipi_dsi_dpi_config(dsi, mode);
-       dw_mipi_dsi_packet_handler_config(dsi);
-       dw_mipi_dsi_video_mode_config(dsi);
-       dw_mipi_dsi_video_packet_config(dsi, mode);
-       dw_mipi_dsi_command_mode_config(dsi);
-       dw_mipi_dsi_line_timer_config(dsi, mode);
-       dw_mipi_dsi_vertical_timing_config(dsi, mode);
-       dw_mipi_dsi_dphy_timing_config(dsi);
-       dw_mipi_dsi_dphy_interface_config(dsi);
-       dw_mipi_dsi_clear_err(dsi);
-
-       /*
-        * For the RK3399, the clk of grf must be enabled before writing grf
-        * register. And for RK3288 or other soc, this grf_clk must be NULL,
-        * the clk_prepare_enable return true directly.
-        */
-       ret = clk_prepare_enable(dsi->grf_clk);
-       if (ret) {
-               DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
-               return;
-       }
-
-       if (pdata->grf_dsi0_mode_reg)
-               regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
-                            pdata->grf_dsi0_mode);
-
-       dw_mipi_dsi_phy_init(dsi);
-       dw_mipi_dsi_wait_for_two_frames(mode);
-
-       dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
-       if (drm_panel_prepare(dsi->panel))
-               DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n");
-
-       dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
-       drm_panel_enable(dsi->panel);
-
-       clk_disable_unprepare(dsi->pclk);
-
-       if (mux)
-               val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
-       else
-               val = pdata->dsi0_en_bit << 16;
-
-       regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
-       DRM_DEV_DEBUG(dsi->dev,
-                     "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
-       dsi->dpms_mode = DRM_MODE_DPMS_ON;
-
-       clk_disable_unprepare(dsi->grf_clk);
-}
-
-static int
-dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
-                                struct drm_crtc_state *crtc_state,
-                                struct drm_connector_state *conn_state)
-{
-       struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
-       struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-
-       switch (dsi->format) {
-       case MIPI_DSI_FMT_RGB888:
-               s->output_mode = ROCKCHIP_OUT_MODE_P888;
-               break;
-       case MIPI_DSI_FMT_RGB666:
-               s->output_mode = ROCKCHIP_OUT_MODE_P666;
-               break;
-       case MIPI_DSI_FMT_RGB565:
-               s->output_mode = ROCKCHIP_OUT_MODE_P565;
-               break;
-       default:
-               WARN_ON(1);
-               return -EINVAL;
-       }
-
-       s->output_type = DRM_MODE_CONNECTOR_DSI;
-
-       return 0;
-}
-
-static const struct drm_encoder_helper_funcs
-dw_mipi_dsi_encoder_helper_funcs = {
-       .enable = dw_mipi_dsi_encoder_enable,
-       .disable = dw_mipi_dsi_encoder_disable,
-       .atomic_check = dw_mipi_dsi_encoder_atomic_check,
-};
-
-static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
-       .destroy = drm_encoder_cleanup,
-};
-
-static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
-{
-       struct dw_mipi_dsi *dsi = con_to_dsi(connector);
-
-       return drm_panel_get_modes(dsi->panel);
-}
-
-static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
-       .get_modes = dw_mipi_dsi_connector_get_modes,
-};
-
-static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .destroy = dw_mipi_dsi_drm_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 int dw_mipi_dsi_register(struct drm_device *drm,
-                               struct dw_mipi_dsi *dsi)
-{
-       struct drm_encoder *encoder = &dsi->encoder;
-       struct drm_connector *connector = &dsi->connector;
-       struct device *dev = dsi->dev;
-       int ret;
-
-       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,
-                                                            dev->of_node);
-       /*
-        * If we failed to find the CRTC(s) which this encoder is
-        * supposed to be connected to, it's because the CRTC has
-        * not been registered yet.  Defer probing, and hope that
-        * the required CRTC is added later.
-        */
-       if (encoder->possible_crtcs == 0)
-               return -EPROBE_DEFER;
-
-       drm_encoder_helper_add(&dsi->encoder,
-                              &dw_mipi_dsi_encoder_helper_funcs);
-       ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
-                              DRM_MODE_ENCODER_DSI, NULL);
-       if (ret) {
-               DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n");
-               return ret;
-       }
-
-       drm_connector_helper_add(connector,
-                                &dw_mipi_dsi_connector_helper_funcs);
-
-       drm_connector_init(drm, &dsi->connector,
-                          &dw_mipi_dsi_atomic_connector_funcs,
-                          DRM_MODE_CONNECTOR_DSI);
-
-       drm_connector_attach_encoder(connector, encoder);
-
-       return 0;
-}
-
-static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
-{
-       struct device_node *np = dsi->dev->of_node;
-
-       dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
-       if (IS_ERR(dsi->grf_regmap)) {
-               DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
-               return PTR_ERR(dsi->grf_regmap);
-       }
-
-       return 0;
-}
-
-static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
-       .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
-       .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
-       .grf_switch_reg = RK3288_GRF_SOC_CON6,
-       .max_data_lanes = 4,
-};
-
-static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
-       .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
-       .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
-       .grf_switch_reg = RK3399_GRF_SOC_CON20,
-       .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
-       .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
-       .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
-       .max_data_lanes = 4,
-};
-
-static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
-       {
-        .compatible = "rockchip,rk3288-mipi-dsi",
-        .data = &rk3288_mipi_dsi_drv_data,
-       }, {
-        .compatible = "rockchip,rk3399-mipi-dsi",
-        .data = &rk3399_mipi_dsi_drv_data,
-       },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
-
-static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
-                           void *data)
-{
-       const struct of_device_id *of_id =
-                       of_match_device(dw_mipi_dsi_dt_ids, dev);
-       const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct reset_control *apb_rst;
-       struct drm_device *drm = data;
-       struct dw_mipi_dsi *dsi;
-       struct resource *res;
-       int ret;
-
-       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
-       if (!dsi)
-               return -ENOMEM;
-
-       dsi->dev = dev;
-       dsi->pdata = pdata;
-       dsi->dpms_mode = DRM_MODE_DPMS_OFF;
-
-       ret = rockchip_mipi_parse_dt(dsi);
-       if (ret)
-               return ret;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dsi->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(dsi->base))
-               return PTR_ERR(dsi->base);
-
-       dsi->pllref_clk = devm_clk_get(dev, "ref");
-       if (IS_ERR(dsi->pllref_clk)) {
-               ret = PTR_ERR(dsi->pllref_clk);
-               DRM_DEV_ERROR(dev,
-                             "Unable to get pll reference clock: %d\n", ret);
-               return ret;
-       }
-
-       dsi->pclk = devm_clk_get(dev, "pclk");
-       if (IS_ERR(dsi->pclk)) {
-               ret = PTR_ERR(dsi->pclk);
-               DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret);
-               return ret;
-       }
-
-       /*
-        * Note that the reset was not defined in the initial device tree, so
-        * we have to be prepared for it not being found.
-        */
-       apb_rst = devm_reset_control_get(dev, "apb");
-       if (IS_ERR(apb_rst)) {
-               ret = PTR_ERR(apb_rst);
-               if (ret == -ENOENT) {
-                       apb_rst = NULL;
-               } else {
-                       DRM_DEV_ERROR(dev,
-                                     "Unable to get reset control: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       if (apb_rst) {
-               ret = clk_prepare_enable(dsi->pclk);
-               if (ret) {
-                       DRM_DEV_ERROR(dev, "Failed to enable pclk\n");
-                       return ret;
-               }
-
-               reset_control_assert(apb_rst);
-               usleep_range(10, 20);
-               reset_control_deassert(apb_rst);
-
-               clk_disable_unprepare(dsi->pclk);
-       }
-
-       if (pdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
-               dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
-               if (IS_ERR(dsi->phy_cfg_clk)) {
-                       ret = PTR_ERR(dsi->phy_cfg_clk);
-                       DRM_DEV_ERROR(dev,
-                                     "Unable to get phy_cfg_clk: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       if (pdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
-               dsi->grf_clk = devm_clk_get(dev, "grf");
-               if (IS_ERR(dsi->grf_clk)) {
-                       ret = PTR_ERR(dsi->grf_clk);
-                       DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       ret = clk_prepare_enable(dsi->pllref_clk);
-       if (ret) {
-               DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n");
-               return ret;
-       }
-
-       ret = dw_mipi_dsi_register(drm, dsi);
-       if (ret) {
-               DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
-               goto err_pllref;
-       }
-
-       dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
-       dsi->dsi_host.dev = dev;
-       ret = mipi_dsi_host_register(&dsi->dsi_host);
-       if (ret) {
-               DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
-               goto err_cleanup;
-       }
-
-       if (!dsi->panel) {
-               ret = -EPROBE_DEFER;
-               goto err_mipi_dsi_host;
-       }
-
-       dev_set_drvdata(dev, dsi);
-       pm_runtime_enable(dev);
-       return 0;
-
-err_mipi_dsi_host:
-       mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
-       dsi->connector.funcs->destroy(&dsi->connector);
-       dsi->encoder.funcs->destroy(&dsi->encoder);
-err_pllref:
-       clk_disable_unprepare(dsi->pllref_clk);
-       return ret;
-}
-
-static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
-                              void *data)
-{
-       struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
-
-       mipi_dsi_host_unregister(&dsi->dsi_host);
-       pm_runtime_disable(dev);
-
-       dsi->connector.funcs->destroy(&dsi->connector);
-       dsi->encoder.funcs->destroy(&dsi->encoder);
-
-       clk_disable_unprepare(dsi->pllref_clk);
-}
-
-static const struct component_ops dw_mipi_dsi_ops = {
-       .bind   = dw_mipi_dsi_bind,
-       .unbind = dw_mipi_dsi_unbind,
-};
-
-static int dw_mipi_dsi_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &dw_mipi_dsi_ops);
-}
-
-static int dw_mipi_dsi_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &dw_mipi_dsi_ops);
-       return 0;
-}
-
-struct platform_driver dw_mipi_dsi_driver = {
-       .probe          = dw_mipi_dsi_probe,
-       .remove         = dw_mipi_dsi_remove,
-       .driver         = {
-               .of_match_table = dw_mipi_dsi_dt_ids,
-               .name   = DRIVER_NAME,
-       },
-};
index 11309a2a4e435fdee87ba9aff83787dee8e848d1..89c63cfde5c85073de5603cc8a2be3253f7bfb82 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/phy/phy.h>
 #include <linux/regmap.h>
 
 #include <drm/drm_of.h>
 
 #define RK3288_GRF_SOC_CON6            0x025C
 #define RK3288_HDMI_LCDC_SEL           BIT(4)
+#define RK3328_GRF_SOC_CON2            0x0408
+
+#define RK3328_HDMI_SDAIN_MSK          BIT(11)
+#define RK3328_HDMI_SCLIN_MSK          BIT(10)
+#define RK3328_HDMI_HPD_IOE            BIT(2)
+#define RK3328_GRF_SOC_CON3            0x040c
+/* need to be unset if hdmi or i2c should control voltage */
+#define RK3328_HDMI_SDA5V_GRF          BIT(15)
+#define RK3328_HDMI_SCL5V_GRF          BIT(14)
+#define RK3328_HDMI_HPD5V_GRF          BIT(13)
+#define RK3328_HDMI_CEC5V_GRF          BIT(12)
+#define RK3328_GRF_SOC_CON4            0x0410
+#define RK3328_HDMI_HPD_SARADC         BIT(13)
+#define RK3328_HDMI_CEC_5V             BIT(11)
+#define RK3328_HDMI_SDA_5V             BIT(10)
+#define RK3328_HDMI_SCL_5V             BIT(9)
+#define RK3328_HDMI_HPD_5V             BIT(8)
+
 #define RK3399_GRF_SOC_CON20           0x6250
 #define RK3399_HDMI_LCDC_SEL           BIT(6)
 
@@ -36,7 +55,7 @@
  * @lcdsel_lit: reg value of selecting vop little for HDMI
  */
 struct rockchip_hdmi_chip_data {
-       u32     lcdsel_grf_reg;
+       int     lcdsel_grf_reg;
        u32     lcdsel_big;
        u32     lcdsel_lit;
 };
@@ -49,6 +68,7 @@ struct rockchip_hdmi {
        struct clk *vpll_clk;
        struct clk *grf_clk;
        struct dw_hdmi *hdmi;
+       struct phy *phy;
 };
 
 #define to_rockchip_hdmi(x)    container_of(x, struct rockchip_hdmi, x)
@@ -245,6 +265,9 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
        u32 val;
        int ret;
 
+       if (hdmi->chip_data->lcdsel_grf_reg < 0)
+               return;
+
        ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
        if (ret)
                val = hdmi->chip_data->lcdsel_lit;
@@ -287,6 +310,66 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun
        .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
 };
 
+static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
+                            struct drm_display_mode *mode)
+{
+       struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+       return phy_power_on(hdmi->phy);
+}
+
+static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
+{
+       struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+       phy_power_off(hdmi->phy);
+}
+
+static enum drm_connector_status
+dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
+{
+       struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+       enum drm_connector_status status;
+
+       status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
+
+       if (status == connector_status_connected)
+               regmap_write(hdmi->regmap,
+                       RK3328_GRF_SOC_CON4,
+                       HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
+                                     RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
+       else
+               regmap_write(hdmi->regmap,
+                       RK3328_GRF_SOC_CON4,
+                       HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
+                                        RK3328_HDMI_SCL_5V));
+       return status;
+}
+
+static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
+{
+       struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+       dw_hdmi_phy_setup_hpd(dw_hdmi, data);
+
+       /* Enable and map pins to 3V grf-controlled io-voltage */
+       regmap_write(hdmi->regmap,
+               RK3328_GRF_SOC_CON4,
+               HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
+                                RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
+                                RK3328_HDMI_HPD_5V));
+       regmap_write(hdmi->regmap,
+               RK3328_GRF_SOC_CON3,
+               HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
+                                RK3328_HDMI_HPD5V_GRF |
+                                RK3328_HDMI_CEC5V_GRF));
+       regmap_write(hdmi->regmap,
+               RK3328_GRF_SOC_CON2,
+               HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
+                             RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
+                             RK3328_HDMI_HPD_IOE));
+}
+
 static struct rockchip_hdmi_chip_data rk3288_chip_data = {
        .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
        .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
@@ -301,6 +384,29 @@ static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
        .phy_data = &rk3288_chip_data,
 };
 
+static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
+       .init           = dw_hdmi_rockchip_genphy_init,
+       .disable        = dw_hdmi_rockchip_genphy_disable,
+       .read_hpd       = dw_hdmi_rk3328_read_hpd,
+       .update_hpd     = dw_hdmi_phy_update_hpd,
+       .setup_hpd      = dw_hdmi_rk3328_setup_hpd,
+};
+
+static struct rockchip_hdmi_chip_data rk3328_chip_data = {
+       .lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
+       .mode_valid = dw_hdmi_rockchip_mode_valid,
+       .mpll_cfg = rockchip_mpll_cfg,
+       .cur_ctr = rockchip_cur_ctr,
+       .phy_config = rockchip_phy_config,
+       .phy_data = &rk3328_chip_data,
+       .phy_ops = &rk3328_hdmi_phy_ops,
+       .phy_name = "inno_dw_hdmi_phy2",
+       .phy_force_vendor = true,
+};
+
 static struct rockchip_hdmi_chip_data rk3399_chip_data = {
        .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
        .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
@@ -319,6 +425,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
        { .compatible = "rockchip,rk3288-dw-hdmi",
          .data = &rk3288_hdmi_drv_data
        },
+       { .compatible = "rockchip,rk3328-dw-hdmi",
+         .data = &rk3328_hdmi_drv_data
+       },
        { .compatible = "rockchip,rk3399-dw-hdmi",
          .data = &rk3399_hdmi_drv_data
        },
@@ -330,7 +439,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                                 void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       const struct dw_hdmi_plat_data *plat_data;
+       struct dw_hdmi_plat_data *plat_data;
        const struct of_device_id *match;
        struct drm_device *drm = data;
        struct drm_encoder *encoder;
@@ -345,9 +454,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return -ENOMEM;
 
        match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
-       plat_data = match->data;
+       plat_data = devm_kmemdup(&pdev->dev, match->data,
+                                            sizeof(*plat_data), GFP_KERNEL);
+       if (!plat_data)
+               return -ENOMEM;
+
        hdmi->dev = &pdev->dev;
        hdmi->chip_data = plat_data->phy_data;
+       plat_data->phy_data = hdmi;
        encoder = &hdmi->encoder;
 
        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -373,6 +487,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return ret;
        }
 
+       hdmi->phy = devm_phy_optional_get(dev, "hdmi");
+       if (IS_ERR(hdmi->phy)) {
+               ret = PTR_ERR(hdmi->phy);
+               if (ret != -EPROBE_DEFER)
+                       DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
+               return ret;
+       }
+
        drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
        drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS, NULL);
index 5864cb452c5c7710b6c38950f715125567217097..be6c2573039af0c82749828100b48fef5c8dc75c 100644 (file)
@@ -483,7 +483,7 @@ static int __init rockchip_drm_init(void)
        ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
        ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
                                CONFIG_ROCKCHIP_DW_HDMI);
-       ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver,
+       ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
                                CONFIG_ROCKCHIP_DW_MIPI_DSI);
        ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
 
index 21a023a97bb8e0d198aa1fa0b935dec05786d659..ce48568ec8a0bd13b1dc86ffa280f110b19c4342 100644 (file)
@@ -37,6 +37,7 @@ struct rockchip_crtc_state {
        int output_type;
        int output_mode;
        int output_bpc;
+       int output_flags;
 };
 #define to_rockchip_crtc_state(s) \
                container_of(s, struct rockchip_crtc_state, base)
@@ -67,7 +68,7 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
 int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
 extern struct platform_driver cdn_dp_driver;
 extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
-extern struct platform_driver dw_mipi_dsi_driver;
+extern struct platform_driver dw_mipi_dsi_rockchip_driver;
 extern struct platform_driver inno_hdmi_driver;
 extern struct platform_driver rockchip_dp_driver;
 extern struct platform_driver rockchip_lvds_driver;
index 79d00d861a31f701451d3387a6cc6e8fc8e71234..01ff3c8588750ea466be307a1f820f4ed73f2fff 100644 (file)
@@ -189,12 +189,14 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
 int rockchip_drm_psr_register(struct drm_encoder *encoder,
                        int (*psr_set)(struct drm_encoder *, bool enable))
 {
-       struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
+       struct rockchip_drm_private *drm_drv;
        struct psr_drv *psr;
 
        if (!encoder || !psr_set)
                return -EINVAL;
 
+       drm_drv = encoder->dev->dev_private;
+
        psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
        if (!psr)
                return -ENOMEM;
index 0c35a88e33dde45fdf6e0184d0d09d1185ec10a0..fb70fb486fbf4a57da6755a4c513d2dd426d1f33 100644 (file)
@@ -916,6 +916,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
        pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
                   BIT(VSYNC_POSITIVE) : 0;
        VOP_REG_SET(vop, output, pin_pol, pin_pol);
+       VOP_REG_SET(vop, output, mipi_dual_channel_en, 0);
 
        switch (s->output_type) {
        case DRM_MODE_CONNECTOR_LVDS:
@@ -933,6 +934,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
        case DRM_MODE_CONNECTOR_DSI:
                VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
                VOP_REG_SET(vop, output, mipi_en, 1);
+               VOP_REG_SET(vop, output, mipi_dual_channel_en,
+                           !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL));
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
                pin_pol &= ~BIT(DCLK_INVERT);
index fd5765dfd63752a4e7ba5c3bd7ed30e1e1722bf3..0fe40e1983d97bef4d12f9f8e305fdc38767066b 100644 (file)
@@ -60,6 +60,7 @@ struct vop_output {
        struct vop_reg edp_en;
        struct vop_reg hdmi_en;
        struct vop_reg mipi_en;
+       struct vop_reg mipi_dual_channel_en;
        struct vop_reg rgb_en;
 };
 
@@ -214,6 +215,9 @@ struct vop_data {
 /* for use special outface */
 #define ROCKCHIP_OUT_MODE_AAAA 15
 
+/* output flags */
+#define ROCKCHIP_OUTPUT_DSI_DUAL       BIT(0)
+
 enum alpha_mode {
        ALPHA_STRAIGHT,
        ALPHA_INVERSE,
index a6db3cd5544bda960d40e49375c30f81f6522881..08fc40af52c89d36b4964fc0714990d2d82b4ea6 100644 (file)
@@ -361,7 +361,11 @@ static const struct vop_win_data rk3188_vop_win_data[] = {
 };
 
 static const int rk3188_vop_intrs[] = {
-       0,
+       /*
+        * hs_start interrupt fires at frame-start, so serves
+        * the same purpose as dsp_hold in the driver.
+        */
+       DSP_HOLD_VALID_INTR,
        FS_INTR,
        LINE_FLAG_INTR,
        BUS_ERROR_INTR,
@@ -630,6 +634,7 @@ static const struct vop_output rk3399_output = {
        .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
        .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
        .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
+       .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
 };
 
 static const struct vop_data rk3399_vop_big = {
index 3e22a54a99c25b52c62ece421596695faf3d3489..4463d3826ecbec0432ee363087c8e6d1f86755cc 100644 (file)
@@ -130,7 +130,14 @@ drm_sched_entity_get_free_sched(struct drm_sched_entity *entity)
        int i;
 
        for (i = 0; i < entity->num_rq_list; ++i) {
-               num_jobs = atomic_read(&entity->rq_list[i]->sched->num_jobs);
+               struct drm_gpu_scheduler *sched = entity->rq_list[i]->sched;
+
+               if (!entity->rq_list[i]->sched->ready) {
+                       DRM_WARN("sched%s is not ready, skipping", sched->name);
+                       continue;
+               }
+
+               num_jobs = atomic_read(&sched->num_jobs);
                if (num_jobs < min_jobs) {
                        min_jobs = num_jobs;
                        rq = entity->rq_list[i];
@@ -204,7 +211,6 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
 
        drm_sched_fence_finished(job->s_fence);
        WARN_ON(job->s_fence->parent);
-       dma_fence_put(&job->s_fence->finished);
        job->sched->ops->free_job(job);
 }
 
index 44fe587aaef97d30d4bb744fef25c851eacdcf82..dbb69063b3d5e21ee7f3b696cd54d198e7ee92be 100644 (file)
@@ -60,6 +60,8 @@
 
 static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb);
 
+static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job);
+
 /**
  * drm_sched_rq_init - initialize a given run queue struct
  *
@@ -196,6 +198,75 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched)
                schedule_delayed_work(&sched->work_tdr, sched->timeout);
 }
 
+/**
+ * drm_sched_fault - immediately start timeout handler
+ *
+ * @sched: scheduler where the timeout handling should be started.
+ *
+ * Start timeout handling immediately when the driver detects a hardware fault.
+ */
+void drm_sched_fault(struct drm_gpu_scheduler *sched)
+{
+       mod_delayed_work(system_wq, &sched->work_tdr, 0);
+}
+EXPORT_SYMBOL(drm_sched_fault);
+
+/**
+ * drm_sched_suspend_timeout - Suspend scheduler job timeout
+ *
+ * @sched: scheduler instance for which to suspend the timeout
+ *
+ * Suspend the delayed work timeout for the scheduler. This is done by
+ * modifying the delayed work timeout to an arbitrary large value,
+ * MAX_SCHEDULE_TIMEOUT in this case. Note that this function can be
+ * called from an IRQ context.
+ *
+ * Returns the timeout remaining
+ *
+ */
+unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched)
+{
+       unsigned long sched_timeout, now = jiffies;
+
+       sched_timeout = sched->work_tdr.timer.expires;
+
+       /*
+        * Modify the timeout to an arbitrarily large value. This also prevents
+        * the timeout to be restarted when new submissions arrive
+        */
+       if (mod_delayed_work(system_wq, &sched->work_tdr, MAX_SCHEDULE_TIMEOUT)
+                       && time_after(sched_timeout, now))
+               return sched_timeout - now;
+       else
+               return sched->timeout;
+}
+EXPORT_SYMBOL(drm_sched_suspend_timeout);
+
+/**
+ * drm_sched_resume_timeout - Resume scheduler job timeout
+ *
+ * @sched: scheduler instance for which to resume the timeout
+ * @remaining: remaining timeout
+ *
+ * Resume the delayed work timeout for the scheduler. Note that
+ * this function can be called from an IRQ context.
+ */
+void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
+               unsigned long remaining)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sched->job_list_lock, flags);
+
+       if (list_empty(&sched->ring_mirror_list))
+               cancel_delayed_work(&sched->work_tdr);
+       else
+               mod_delayed_work(system_wq, &sched->work_tdr, remaining);
+
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
+}
+EXPORT_SYMBOL(drm_sched_resume_timeout);
+
 /* job_finish is called after hw fence signaled
  */
 static void drm_sched_job_finish(struct work_struct *work)
@@ -203,6 +274,7 @@ static void drm_sched_job_finish(struct work_struct *work)
        struct drm_sched_job *s_job = container_of(work, struct drm_sched_job,
                                                   finish_work);
        struct drm_gpu_scheduler *sched = s_job->sched;
+       unsigned long flags;
 
        /*
         * Canceling the timeout without removing our job from the ring mirror
@@ -213,14 +285,13 @@ static void drm_sched_job_finish(struct work_struct *work)
         */
        cancel_delayed_work_sync(&sched->work_tdr);
 
-       spin_lock(&sched->job_list_lock);
+       spin_lock_irqsave(&sched->job_list_lock, flags);
        /* remove job from ring_mirror_list */
-       list_del(&s_job->node);
+       list_del_init(&s_job->node);
        /* queue TDR for next job */
        drm_sched_start_timeout(sched);
-       spin_unlock(&sched->job_list_lock);
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
 
-       dma_fence_put(&s_job->s_fence->finished);
        sched->ops->free_job(s_job);
 }
 
@@ -235,55 +306,33 @@ static void drm_sched_job_finish_cb(struct dma_fence *f,
 static void drm_sched_job_begin(struct drm_sched_job *s_job)
 {
        struct drm_gpu_scheduler *sched = s_job->sched;
+       unsigned long flags;
 
        dma_fence_add_callback(&s_job->s_fence->finished, &s_job->finish_cb,
                               drm_sched_job_finish_cb);
 
-       spin_lock(&sched->job_list_lock);
+       spin_lock_irqsave(&sched->job_list_lock, flags);
        list_add_tail(&s_job->node, &sched->ring_mirror_list);
        drm_sched_start_timeout(sched);
-       spin_unlock(&sched->job_list_lock);
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
 }
 
 static void drm_sched_job_timedout(struct work_struct *work)
 {
        struct drm_gpu_scheduler *sched;
        struct drm_sched_job *job;
-       int r;
+       unsigned long flags;
 
        sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
-
-       spin_lock(&sched->job_list_lock);
-       list_for_each_entry_reverse(job, &sched->ring_mirror_list, node) {
-               struct drm_sched_fence *fence = job->s_fence;
-
-               if (!dma_fence_remove_callback(fence->parent, &fence->cb))
-                       goto already_signaled;
-       }
-
        job = list_first_entry_or_null(&sched->ring_mirror_list,
                                       struct drm_sched_job, node);
-       spin_unlock(&sched->job_list_lock);
 
        if (job)
-               sched->ops->timedout_job(job);
-
-       spin_lock(&sched->job_list_lock);
-       list_for_each_entry(job, &sched->ring_mirror_list, node) {
-               struct drm_sched_fence *fence = job->s_fence;
+               job->sched->ops->timedout_job(job);
 
-               if (!fence->parent || !list_empty(&fence->cb.node))
-                       continue;
-
-               r = dma_fence_add_callback(fence->parent, &fence->cb,
-                                          drm_sched_process_job);
-               if (r)
-                       drm_sched_process_job(fence->parent, &fence->cb);
-
-already_signaled:
-               ;
-       }
-       spin_unlock(&sched->job_list_lock);
+       spin_lock_irqsave(&sched->job_list_lock, flags);
+       drm_sched_start_timeout(sched);
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
 }
 
 /**
@@ -297,9 +346,10 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo
 {
        struct drm_sched_job *s_job;
        struct drm_sched_entity *entity, *tmp;
+       unsigned long flags;
        int i;
 
-       spin_lock(&sched->job_list_lock);
+       spin_lock_irqsave(&sched->job_list_lock, flags);
        list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) {
                if (s_job->s_fence->parent &&
                    dma_fence_remove_callback(s_job->s_fence->parent,
@@ -309,7 +359,7 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo
                        atomic_dec(&sched->hw_rq_count);
                }
        }
-       spin_unlock(&sched->job_list_lock);
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
 
        if (bad && bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
                atomic_inc(&bad->karma);
@@ -347,9 +397,10 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
 {
        struct drm_sched_job *s_job, *tmp;
        bool found_guilty = false;
+       unsigned long flags;
        int r;
 
-       spin_lock(&sched->job_list_lock);
+       spin_lock_irqsave(&sched->job_list_lock, flags);
        list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
                struct drm_sched_fence *s_fence = s_job->s_fence;
                struct dma_fence *fence;
@@ -363,7 +414,7 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
                if (found_guilty && s_job->s_fence->scheduled.context == guilty_context)
                        dma_fence_set_error(&s_fence->finished, -ECANCELED);
 
-               spin_unlock(&sched->job_list_lock);
+               spin_unlock_irqrestore(&sched->job_list_lock, flags);
                fence = sched->ops->run_job(s_job);
                atomic_inc(&sched->hw_rq_count);
 
@@ -378,12 +429,14 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched)
                                          r);
                        dma_fence_put(fence);
                } else {
+                       if (s_fence->finished.error < 0)
+                               drm_sched_expel_job_unlocked(s_job);
                        drm_sched_process_job(NULL, &s_fence->cb);
                }
-               spin_lock(&sched->job_list_lock);
+               spin_lock_irqsave(&sched->job_list_lock, flags);
        }
        drm_sched_start_timeout(sched);
-       spin_unlock(&sched->job_list_lock);
+       spin_unlock_irqrestore(&sched->job_list_lock, flags);
 }
 EXPORT_SYMBOL(drm_sched_job_recovery);
 
@@ -406,6 +459,9 @@ int drm_sched_job_init(struct drm_sched_job *job,
        struct drm_gpu_scheduler *sched;
 
        drm_sched_entity_select_rq(entity);
+       if (!entity->rq)
+               return -ENOENT;
+
        sched = entity->rq->sched;
 
        job->sched = sched;
@@ -423,6 +479,18 @@ int drm_sched_job_init(struct drm_sched_job *job,
 }
 EXPORT_SYMBOL(drm_sched_job_init);
 
+/**
+ * drm_sched_job_cleanup - clean up scheduler job resources
+ *
+ * @job: scheduler job to clean up
+ */
+void drm_sched_job_cleanup(struct drm_sched_job *job)
+{
+       dma_fence_put(&job->s_fence->finished);
+       job->s_fence = NULL;
+}
+EXPORT_SYMBOL(drm_sched_job_cleanup);
+
 /**
  * drm_sched_ready - is the scheduler ready
  *
@@ -567,6 +635,8 @@ static int drm_sched_main(void *param)
                                          r);
                        dma_fence_put(fence);
                } else {
+                       if (s_fence->finished.error < 0)
+                               drm_sched_expel_job_unlocked(sched_job);
                        drm_sched_process_job(NULL, &s_fence->cb);
                }
 
@@ -575,6 +645,15 @@ static int drm_sched_main(void *param)
        return 0;
 }
 
+static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job)
+{
+       struct drm_gpu_scheduler *sched = s_job->sched;
+
+       spin_lock(&sched->job_list_lock);
+       list_del_init(&s_job->node);
+       spin_unlock(&sched->job_list_lock);
+}
+
 /**
  * drm_sched_init - Init a gpu scheduler instance
  *
@@ -594,7 +673,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
                   long timeout,
                   const char *name)
 {
-       int i;
+       int i, ret;
        sched->ops = ops;
        sched->hw_submission_limit = hw_submission;
        sched->name = name;
@@ -615,10 +694,13 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
        /* Each scheduler will run on a seperate kernel thread */
        sched->thread = kthread_run(drm_sched_main, sched, sched->name);
        if (IS_ERR(sched->thread)) {
+               ret = PTR_ERR(sched->thread);
+               sched->thread = NULL;
                DRM_ERROR("Failed to create scheduler for %s.\n", name);
-               return PTR_ERR(sched->thread);
+               return ret;
        }
 
+       sched->ready = true;
        return 0;
 }
 EXPORT_SYMBOL(drm_sched_init);
@@ -634,5 +716,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
 {
        if (sched->thread)
                kthread_stop(sched->thread);
+
+       sched->ready = false;
 }
 EXPORT_SYMBOL(drm_sched_fini);
index 9fc349fa18e9d57b3318e423b2343eafdf41d8bf..1bb73dc4c88ce06520eee0c44ae20fbbf82b364f 100644 (file)
@@ -1 +1,5 @@
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o
+test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
+                      test-drm_format.o test-drm_framebuffer.o \
+                     test-drm_damage_helper.o
+
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
diff --git a/drivers/gpu/drm/selftests/drm_helper_selftests.h b/drivers/gpu/drm/selftests/drm_helper_selftests.h
deleted file mode 100644 (file)
index 9771290..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_selftests_helper
- */
-selftest(check_plane_state, igt_check_plane_state)
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
new file mode 100644 (file)
index 0000000..4647537
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* List each unit test as selftest(name, function)
+ *
+ * The name is used as both an enum and expanded as igt__name to create
+ * a module parameter. It must be unique and legal for a C identifier.
+ *
+ * Tests are executed in order by igt/drm_selftests_helper
+ */
+selftest(check_plane_state, igt_check_plane_state)
+selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
+selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
+selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
+selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
+selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
+selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
+selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
+selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
+selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
+selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
+selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
+selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
+selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
+selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
+selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
+selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
+selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
+selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
+selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
+selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
+selftest(damage_iter_damage, igt_damage_iter_damage)
+selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
+selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
+selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
+selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
diff --git a/drivers/gpu/drm/selftests/test-drm-helper.c b/drivers/gpu/drm/selftests/test-drm-helper.c
deleted file mode 100644 (file)
index a015712..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Test cases for the drm_kms_helper functions
- */
-
-#define pr_fmt(fmt) "drm_kms_helper: " fmt
-
-#include <linux/module.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_modes.h>
-
-#define TESTS "drm_helper_selftests.h"
-#include "drm_selftest.h"
-
-#define FAIL(test, msg, ...) \
-       do { \
-               if (test) { \
-                       pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-                       return -EINVAL; \
-               } \
-       } while (0)
-
-#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
-
-static void set_src(struct drm_plane_state *plane_state,
-                   unsigned src_x, unsigned src_y,
-                   unsigned src_w, unsigned src_h)
-{
-       plane_state->src_x = src_x;
-       plane_state->src_y = src_y;
-       plane_state->src_w = src_w;
-       plane_state->src_h = src_h;
-}
-
-static bool check_src_eq(struct drm_plane_state *plane_state,
-                        unsigned src_x, unsigned src_y,
-                        unsigned src_w, unsigned src_h)
-{
-       if (plane_state->src.x1 < 0) {
-               pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
-               drm_rect_debug_print("src: ", &plane_state->src, true);
-               return false;
-       }
-       if (plane_state->src.y1 < 0) {
-               pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
-               drm_rect_debug_print("src: ", &plane_state->src, true);
-               return false;
-       }
-
-       if (plane_state->src.x1 != src_x ||
-           plane_state->src.y1 != src_y ||
-           drm_rect_width(&plane_state->src) != src_w ||
-           drm_rect_height(&plane_state->src) != src_h) {
-               drm_rect_debug_print("src: ", &plane_state->src, true);
-               return false;
-       }
-
-       return true;
-}
-
-static void set_crtc(struct drm_plane_state *plane_state,
-                    int crtc_x, int crtc_y,
-                    unsigned crtc_w, unsigned crtc_h)
-{
-       plane_state->crtc_x = crtc_x;
-       plane_state->crtc_y = crtc_y;
-       plane_state->crtc_w = crtc_w;
-       plane_state->crtc_h = crtc_h;
-}
-
-static bool check_crtc_eq(struct drm_plane_state *plane_state,
-                         int crtc_x, int crtc_y,
-                         unsigned crtc_w, unsigned crtc_h)
-{
-       if (plane_state->dst.x1 != crtc_x ||
-           plane_state->dst.y1 != crtc_y ||
-           drm_rect_width(&plane_state->dst) != crtc_w ||
-           drm_rect_height(&plane_state->dst) != crtc_h) {
-               drm_rect_debug_print("dst: ", &plane_state->dst, false);
-
-               return false;
-       }
-
-       return true;
-}
-
-static int igt_check_plane_state(void *ignored)
-{
-       int ret;
-
-       const struct drm_crtc_state crtc_state = {
-               .crtc = ZERO_SIZE_PTR,
-               .enable = true,
-               .active = true,
-               .mode = {
-                       DRM_MODE("1024x768", 0, 65000, 1024, 1048,
-                               1184, 1344, 0, 768, 771, 777, 806, 0,
-                               DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
-               },
-       };
-       struct drm_framebuffer fb = {
-               .width = 2048,
-               .height = 2048
-       };
-       struct drm_plane_state plane_state = {
-               .crtc = ZERO_SIZE_PTR,
-               .fb = &fb,
-               .rotation = DRM_MODE_ROTATE_0
-       };
-
-       /* Simple clipping, no scaling. */
-       set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
-       set_crtc(&plane_state, 0, 0, fb.width, fb.height);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(ret < 0, "Simple clipping check should pass\n");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-       /* Rotated clipping + reflection, no scaling. */
-       plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(ret < 0, "Rotated clipping check should pass\n");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-       plane_state.rotation = DRM_MODE_ROTATE_0;
-
-       /* Check whether positioning works correctly. */
-       set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
-       set_crtc(&plane_state, 0, 0, 1023, 767);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n");
-
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 true, false);
-       FAIL(ret < 0, "Simple positioning should work\n");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767));
-
-       /* Simple scaling tests. */
-       set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
-       set_crtc(&plane_state, 0, 0, 1024, 768);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 0x8001,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(!ret, "Upscaling out of range should fail.\n");
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 0x8000,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(ret < 0, "Upscaling exactly 2x should work\n");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-       set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 0x1ffff, false, false);
-       FAIL(!ret, "Downscaling out of range should fail.\n");
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 0x20000, false, false);
-       FAIL(ret < 0, "Should succeed with exact scaling limit\n");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-       /* Testing rounding errors. */
-       set_src(&plane_state, 0, 0, 0x40001, 0x40001);
-       set_crtc(&plane_state, 1022, 766, 4, 4);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 0x10001,
-                                                 true, false);
-       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-       set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
-       set_crtc(&plane_state, -2, -2, 1028, 772);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 0x10001,
-                                                 false, false);
-       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-       set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
-       set_crtc(&plane_state, 1022, 766, 4, 4);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 0xffff,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 true, false);
-       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-       FAIL_ON(!plane_state.visible);
-       /* Should not be rounded to 0x20001, which would be upscaling. */
-       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-       set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
-       set_crtc(&plane_state, -2, -2, 1028, 772);
-       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-                                                 0xffff,
-                                                 DRM_PLANE_HELPER_NO_SCALING,
-                                                 false, false);
-       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-       FAIL_ON(!plane_state.visible);
-       FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16));
-       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-       return 0;
-}
-
-#include "drm_selftest.c"
-
-static int __init test_drm_helper_init(void)
-{
-       int err;
-
-       err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
-
-       return err > 0 ? 0 : err;
-}
-
-module_init(test_drm_helper_init);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
new file mode 100644 (file)
index 0000000..9d2bcdf
--- /dev/null
@@ -0,0 +1,811 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test case for drm_damage_helper functions
+ */
+
+#define pr_fmt(fmt) "drm_damage_helper: " fmt
+
+#include <drm/drm_damage_helper.h>
+
+#include "test-drm_modeset_common.h"
+
+static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
+                         int y2)
+{
+       state->src.x1 = x1;
+       state->src.y1 = y1;
+       state->src.x2 = x2;
+       state->src.y2 = y2;
+}
+
+static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
+                           int y2)
+{
+       r->x1 = x1;
+       r->y1 = y1;
+       r->x2 = x2;
+       r->y2 = y2;
+}
+
+static void set_damage_blob(struct drm_property_blob *damage_blob,
+                           struct drm_mode_rect *r, uint32_t size)
+{
+       damage_blob->length = size;
+       damage_blob->data = r;
+}
+
+static void set_plane_damage(struct drm_plane_state *state,
+                            struct drm_property_blob *damage_blob)
+{
+       state->fb_damage_clips = damage_blob;
+}
+
+static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
+                             int x1, int y1, int x2, int y2)
+{
+       /*
+        * Round down x1/y1 and round up x2/y2. This is because damage is not in
+        * 16.16 fixed point so to catch all pixels.
+        */
+       int src_x1 = state->src.x1 >> 16;
+       int src_y1 = state->src.y1 >> 16;
+       int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
+       int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
+
+       if (x1 >= x2 || y1 >= y2) {
+               pr_err("Cannot have damage clip with no dimension.\n");
+               return false;
+       }
+
+       if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
+               pr_err("Damage cannot be outside rounded plane src.\n");
+               return false;
+       }
+
+       if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
+               pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
+               return false;
+       }
+
+       return true;
+}
+
+int igt_damage_iter_no_damage(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src same as fb size. */
+       set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
+       set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_fractional_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src has fractional part. */
+       set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       set_plane_src(&state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_src_moved(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src moved since old plane state. */
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 10 << 16, 10 << 16,
+                     (10 + 1024) << 16, (10 + 768) << 16);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src has fractional part and it moved since old plane state. */
+       set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_not_visible(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = false,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should have no damage.");
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_no_crtc(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = 0,
+               .fb = &fb,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should have no damage.");
+
+       return 0;
+}
+
+int igt_damage_iter_no_damage_no_fb(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = 0,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should have no damage.");
+
+       return 0;
+}
+
+int igt_damage_iter_simple_damage(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       /* Damage set to plane src */
+       set_damage_clip(&damage, 0, 0, 1024, 768);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage when set.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       set_damage_clip(&damage, 256, 192, 768, 576);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage when set.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_intersect_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       /* Damage intersect with plane src. */
+       set_damage_clip(&damage, 256, 192, 1360, 768);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage clipped to src.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_outside_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       /* Damage clip outside plane src */
+       set_damage_clip(&damage, 1360, 1360, 1380, 1380);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should have no damage.");
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_fractional_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src has fractional part. */
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_damage_clip(&damage, 10, 10, 256, 330);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage when set.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src has fractional part. */
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       /* Damage intersect with plane src. */
+       set_damage_clip(&damage, 10, 1, 1360, 330);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src has fractional part. */
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       /* Damage clip outside plane src */
+       set_damage_clip(&damage, 1360, 1360, 1380, 1380);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should have no damage.");
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_src_moved(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src moved since old plane state. */
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 10 << 16, 10 << 16,
+                     (10 + 1024) << 16, (10 + 768) << 16);
+       set_damage_clip(&damage, 20, 30, 256, 256);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
+
+       return 0;
+}
+
+int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage;
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       /* Plane src with fractional part moved since old plane state. */
+       set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       /* Damage intersect with plane src. */
+       set_damage_clip(&damage, 20, 30, 1360, 256);
+       set_damage_blob(&damage_blob, &damage, sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+
+       return 0;
+}
+
+int igt_damage_iter_damage(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage[2];
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       /* 2 damage clips. */
+       set_damage_clip(&damage[0], 20, 30, 200, 180);
+       set_damage_clip(&damage[1], 240, 200, 280, 250);
+       set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip) {
+               if (num_hits == 0)
+                       FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+               if (num_hits == 1)
+                       FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+               num_hits++;
+       }
+
+       FAIL(num_hits != 2, "Should return damage when set.");
+
+       return 0;
+}
+
+int igt_damage_iter_damage_one_intersect(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage[2];
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       /* 2 damage clips, one intersect plane src. */
+       set_damage_clip(&damage[0], 20, 30, 200, 180);
+       set_damage_clip(&damage[1], 2, 2, 1360, 1360);
+       set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip) {
+               if (num_hits == 0)
+                       FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+               if (num_hits == 1)
+                       FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+               num_hits++;
+       }
+
+       FAIL(num_hits != 2, "Should return damage when set.");
+
+       return 0;
+}
+
+int igt_damage_iter_damage_one_outside(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage[2];
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+       set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+       /* 2 damage clips, one outside plane src. */
+       set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+       set_damage_clip(&damage[1], 240, 200, 280, 250);
+       set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return damage when set.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+
+       return 0;
+}
+
+int igt_damage_iter_damage_src_moved(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage[2];
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = true,
+       };
+
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       /* 2 damage clips, one outside plane src. */
+       set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+       set_damage_clip(&damage[1], 240, 200, 280, 250);
+       set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 1, "Should return round off plane src as damage.");
+       FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
+
+       return 0;
+}
+
+int igt_damage_iter_damage_not_visible(void *ignored)
+{
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_plane_state old_state;
+       struct drm_property_blob damage_blob;
+       struct drm_mode_rect damage[2];
+       struct drm_rect clip;
+       uint32_t num_hits = 0;
+
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+
+       struct drm_plane_state state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .visible = false,
+       };
+
+       set_plane_src(&old_state, 0x40002, 0x40002,
+                     0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+       set_plane_src(&state, 0x3fffe, 0x3fffe,
+                     0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+       /* 2 damage clips, one outside plane src. */
+       set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+       set_damage_clip(&damage[1], 240, 200, 280, 250);
+       set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+       set_plane_damage(&state, &damage_blob);
+       drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       FAIL(num_hits != 0, "Should not return any damage.");
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c
new file mode 100644 (file)
index 0000000..c5e212a
--- /dev/null
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_format functions
+ */
+
+#define pr_fmt(fmt) "drm_format: " fmt
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#include <drm/drm_fourcc.h>
+
+#include "test-drm_modeset_common.h"
+
+int igt_check_drm_format_block_width(void *ignored)
+{
+       const struct drm_format_info *info = NULL;
+
+       /* Test invalid arguments */
+       FAIL_ON(drm_format_info_block_width(info, 0) != 0);
+       FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+       FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+
+       /* Test 1 plane format */
+       info = drm_format_info(DRM_FORMAT_XRGB4444);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+       FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+       /* Test 2 planes format */
+       info = drm_format_info(DRM_FORMAT_NV12);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 1) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 2) != 0);
+       FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+       /* Test 3 planes format */
+       info = drm_format_info(DRM_FORMAT_YUV422);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 1) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 2) != 1);
+       FAIL_ON(drm_format_info_block_width(info, 3) != 0);
+       FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+       /* Test a tiled format */
+       info = drm_format_info(DRM_FORMAT_X0L0);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_width(info, 0) != 2);
+       FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+       FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+       return 0;
+}
+
+int igt_check_drm_format_block_height(void *ignored)
+{
+       const struct drm_format_info *info = NULL;
+
+       /* Test invalid arguments */
+       FAIL_ON(drm_format_info_block_height(info, 0) != 0);
+       FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+       FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+
+       /* Test 1 plane format */
+       info = drm_format_info(DRM_FORMAT_XRGB4444);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+       FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+       /* Test 2 planes format */
+       info = drm_format_info(DRM_FORMAT_NV12);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 1) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 2) != 0);
+       FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+       /* Test 3 planes format */
+       info = drm_format_info(DRM_FORMAT_YUV422);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 1) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 2) != 1);
+       FAIL_ON(drm_format_info_block_height(info, 3) != 0);
+       FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+       /* Test a tiled format */
+       info = drm_format_info(DRM_FORMAT_X0L0);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_block_height(info, 0) != 2);
+       FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+       FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+       return 0;
+}
+
+int igt_check_drm_format_min_pitch(void *ignored)
+{
+       const struct drm_format_info *info = NULL;
+
+       /* Test invalid arguments */
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       /* Test 1 plane 8 bits per pixel format */
+       info = drm_format_info(DRM_FORMAT_RGB332);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+                       (uint64_t)(UINT_MAX - 1));
+
+       /* Test 1 plane 16 bits per pixel format */
+       info = drm_format_info(DRM_FORMAT_XRGB4444);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX * 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+                       (uint64_t)(UINT_MAX - 1) * 2);
+
+       /* Test 1 plane 24 bits per pixel format */
+       info = drm_format_info(DRM_FORMAT_RGB888);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX * 3);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+                       (uint64_t)(UINT_MAX - 1) * 3);
+
+       /* Test 1 plane 32 bits per pixel format */
+       info = drm_format_info(DRM_FORMAT_ABGR8888);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX * 4);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+                       (uint64_t)(UINT_MAX - 1) * 4);
+
+       /* Test 2 planes format */
+       info = drm_format_info(DRM_FORMAT_NV12);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+                       (uint64_t)UINT_MAX + 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+                       (uint64_t)(UINT_MAX - 1));
+       FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2) !=
+                       (uint64_t)(UINT_MAX - 1));
+
+       /* Test 3 planes 8 bits per pixel format */
+       info = drm_format_info(DRM_FORMAT_YUV422);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+                       (uint64_t)UINT_MAX / 2 + 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+                       (uint64_t)UINT_MAX / 2 + 1);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+                       (uint64_t)(UINT_MAX - 1) / 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+                       (uint64_t)(UINT_MAX - 1) / 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+                       (uint64_t)(UINT_MAX - 1) / 2);
+
+       /* Test tiled format */
+       info = drm_format_info(DRM_FORMAT_X0L2);
+       FAIL_ON(!info);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+       FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+                       (uint64_t)UINT_MAX * 2);
+       FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+                       (uint64_t)(UINT_MAX - 1) * 2);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
new file mode 100644 (file)
index 0000000..a04d02d
--- /dev/null
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_framebuffer functions
+ */
+
+#include <drm/drmP.h>
+#include "../drm_crtc_internal.h"
+
+#include "test-drm_modeset_common.h"
+
+#define MIN_WIDTH 4
+#define MAX_WIDTH 4096
+#define MIN_HEIGHT 4
+#define MAX_HEIGHT 4096
+
+struct drm_framebuffer_test {
+       int buffer_created;
+       struct drm_mode_fb_cmd2 cmd;
+       const char *name;
+};
+
+static struct drm_framebuffer_test createbuffer_tests[] = {
+{ .buffer_created = 1, .name = "ABGR8888 normal sizes",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 max sizes",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid width",
+       .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "No pixel format",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Width 0",
+       .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Height 0",
+       .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+                .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+                .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+                .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+                .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+                .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "NV12 Normal sizes",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "NV12 Max sizes",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 Invalid pitch",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 Invalid modifier/misssing DRM_MODE_FB_MODIFIERS flag",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+                .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 different  modifier per-plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+                .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
+                .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
+                                                      DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
+                .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
+                              DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
+                .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
+                .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 Normal sizes",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .pitches = { 600, 300, 300 },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 Max sizes",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
+                                                     DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Invalid pitch",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
+                                                     DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 Different pitches",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
+                                                     DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH  + MAX_WIDTH * MAX_HEIGHT,
+                                                     MAX_WIDTH  + 2 * MAX_WIDTH * MAX_HEIGHT },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 1, .name = "YVU420 Valid modifier",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
+                              AFBC_FORMAT_MOD_SPARSE },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+                .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
+                              AFBC_FORMAT_MOD_SPARSE },
+                .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+       }
+},
+{ .buffer_created = 1, .name = "X0L2 Normal sizes",
+       .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
+       }
+},
+{ .buffer_created = 1, .name = "X0L2 Max sizes",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
+       }
+},
+{ .buffer_created = 0, .name = "X0L2 Invalid pitch",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
+       }
+},
+{ .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+       }
+},
+{ .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+                .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+       }
+},
+{ .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
+                .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+       }
+},
+{ .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
+       }
+},
+{ .buffer_created = 1, .name = "X0L2 Valid modifier",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+                .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+       }
+},
+{ .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
+       .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
+                .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
+                .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+                .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+                .flags = DRM_MODE_FB_MODIFIERS,
+       }
+},
+};
+
+static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
+                                             struct drm_file *file_priv,
+                                             const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       int *buffer_created = dev->dev_private;
+       *buffer_created = 1;
+       return ERR_PTR(-EINVAL);
+}
+
+static struct drm_mode_config_funcs mock_config_funcs = {
+       .fb_create = fb_create_mock,
+};
+
+static struct drm_device mock_drm_device = {
+       .mode_config = {
+               .min_width = MIN_WIDTH,
+               .max_width = MAX_WIDTH,
+               .min_height = MIN_HEIGHT,
+               .max_height = MAX_HEIGHT,
+               .allow_fb_modifiers = true,
+               .funcs = &mock_config_funcs,
+       },
+};
+
+static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
+{
+       int buffer_created = 0;
+       struct drm_framebuffer *fb;
+
+       mock_drm_device.dev_private = &buffer_created;
+       fb = drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
+       return buffer_created;
+}
+
+int igt_check_drm_framebuffer_create(void *ignored)
+{
+       int i = 0;
+
+       for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
+               FAIL(createbuffer_tests[i].buffer_created !=
+                               execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
+                    "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
new file mode 100644 (file)
index 0000000..2a7f937
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common file for modeset selftests.
+ */
+
+#include <linux/module.h>
+
+#include "test-drm_modeset_common.h"
+
+#define TESTS "drm_modeset_selftests.h"
+#include "drm_selftest.h"
+
+#include "drm_selftest.c"
+
+static int __init test_drm_modeset_init(void)
+{
+       int err;
+
+       err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+
+       return err > 0 ? 0 : err;
+}
+
+static void __exit test_drm_modeset_exit(void)
+{
+}
+
+module_init(test_drm_modeset_init);
+module_exit(test_drm_modeset_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
new file mode 100644 (file)
index 0000000..8c76f09
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __TEST_DRM_MODESET_COMMON_H__
+#define __TEST_DRM_MODESET_COMMON_H__
+
+#define FAIL(test, msg, ...) \
+       do { \
+               if (test) { \
+                       pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+                       return -EINVAL; \
+               } \
+       } while (0)
+
+#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+
+int igt_check_plane_state(void *ignored);
+int igt_check_drm_format_block_width(void *ignored);
+int igt_check_drm_format_block_height(void *ignored);
+int igt_check_drm_format_min_pitch(void *ignored);
+int igt_check_drm_framebuffer_create(void *ignored);
+int igt_damage_iter_no_damage(void *ignored);
+int igt_damage_iter_no_damage_fractional_src(void *ignored);
+int igt_damage_iter_no_damage_src_moved(void *ignored);
+int igt_damage_iter_no_damage_fractional_src_moved(void *ignored);
+int igt_damage_iter_no_damage_not_visible(void *ignored);
+int igt_damage_iter_no_damage_no_crtc(void *ignored);
+int igt_damage_iter_no_damage_no_fb(void *ignored);
+int igt_damage_iter_simple_damage(void *ignored);
+int igt_damage_iter_single_damage(void *ignored);
+int igt_damage_iter_single_damage_intersect_src(void *ignored);
+int igt_damage_iter_single_damage_outside_src(void *ignored);
+int igt_damage_iter_single_damage_fractional_src(void *ignored);
+int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored);
+int igt_damage_iter_single_damage_outside_fractional_src(void *ignored);
+int igt_damage_iter_single_damage_src_moved(void *ignored);
+int igt_damage_iter_single_damage_fractional_src_moved(void *ignored);
+int igt_damage_iter_damage(void *ignored);
+int igt_damage_iter_damage_one_intersect(void *ignored);
+int igt_damage_iter_damage_one_outside(void *ignored);
+int igt_damage_iter_damage_src_moved(void *ignored);
+int igt_damage_iter_damage_not_visible(void *ignored);
+
+#endif
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
new file mode 100644 (file)
index 0000000..0a9553f
--- /dev/null
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_plane_helper functions
+ */
+
+#define pr_fmt(fmt) "drm_plane_helper: " fmt
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_modes.h>
+
+#include "test-drm_modeset_common.h"
+
+static void set_src(struct drm_plane_state *plane_state,
+                   unsigned src_x, unsigned src_y,
+                   unsigned src_w, unsigned src_h)
+{
+       plane_state->src_x = src_x;
+       plane_state->src_y = src_y;
+       plane_state->src_w = src_w;
+       plane_state->src_h = src_h;
+}
+
+static bool check_src_eq(struct drm_plane_state *plane_state,
+                        unsigned src_x, unsigned src_y,
+                        unsigned src_w, unsigned src_h)
+{
+       if (plane_state->src.x1 < 0) {
+               pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
+               drm_rect_debug_print("src: ", &plane_state->src, true);
+               return false;
+       }
+       if (plane_state->src.y1 < 0) {
+               pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
+               drm_rect_debug_print("src: ", &plane_state->src, true);
+               return false;
+       }
+
+       if (plane_state->src.x1 != src_x ||
+           plane_state->src.y1 != src_y ||
+           drm_rect_width(&plane_state->src) != src_w ||
+           drm_rect_height(&plane_state->src) != src_h) {
+               drm_rect_debug_print("src: ", &plane_state->src, true);
+               return false;
+       }
+
+       return true;
+}
+
+static void set_crtc(struct drm_plane_state *plane_state,
+                    int crtc_x, int crtc_y,
+                    unsigned crtc_w, unsigned crtc_h)
+{
+       plane_state->crtc_x = crtc_x;
+       plane_state->crtc_y = crtc_y;
+       plane_state->crtc_w = crtc_w;
+       plane_state->crtc_h = crtc_h;
+}
+
+static bool check_crtc_eq(struct drm_plane_state *plane_state,
+                         int crtc_x, int crtc_y,
+                         unsigned crtc_w, unsigned crtc_h)
+{
+       if (plane_state->dst.x1 != crtc_x ||
+           plane_state->dst.y1 != crtc_y ||
+           drm_rect_width(&plane_state->dst) != crtc_w ||
+           drm_rect_height(&plane_state->dst) != crtc_h) {
+               drm_rect_debug_print("dst: ", &plane_state->dst, false);
+
+               return false;
+       }
+
+       return true;
+}
+
+int igt_check_plane_state(void *ignored)
+{
+       int ret;
+
+       const struct drm_crtc_state crtc_state = {
+               .crtc = ZERO_SIZE_PTR,
+               .enable = true,
+               .active = true,
+               .mode = {
+                       DRM_MODE("1024x768", 0, 65000, 1024, 1048,
+                               1184, 1344, 0, 768, 771, 777, 806, 0,
+                               DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+               },
+       };
+       struct drm_framebuffer fb = {
+               .width = 2048,
+               .height = 2048
+       };
+       struct drm_plane_state plane_state = {
+               .crtc = ZERO_SIZE_PTR,
+               .fb = &fb,
+               .rotation = DRM_MODE_ROTATE_0
+       };
+
+       /* Simple clipping, no scaling. */
+       set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
+       set_crtc(&plane_state, 0, 0, fb.width, fb.height);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(ret < 0, "Simple clipping check should pass\n");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+
+       /* Rotated clipping + reflection, no scaling. */
+       plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(ret < 0, "Rotated clipping check should pass\n");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+       plane_state.rotation = DRM_MODE_ROTATE_0;
+
+       /* Check whether positioning works correctly. */
+       set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
+       set_crtc(&plane_state, 0, 0, 1023, 767);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n");
+
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 true, false);
+       FAIL(ret < 0, "Simple positioning should work\n");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767));
+
+       /* Simple scaling tests. */
+       set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
+       set_crtc(&plane_state, 0, 0, 1024, 768);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 0x8001,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(!ret, "Upscaling out of range should fail.\n");
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 0x8000,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(ret < 0, "Upscaling exactly 2x should work\n");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+
+       set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 0x1ffff, false, false);
+       FAIL(!ret, "Downscaling out of range should fail.\n");
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 0x20000, false, false);
+       FAIL(ret < 0, "Should succeed with exact scaling limit\n");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+
+       /* Testing rounding errors. */
+       set_src(&plane_state, 0, 0, 0x40001, 0x40001);
+       set_crtc(&plane_state, 1022, 766, 4, 4);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 0x10001,
+                                                 true, false);
+       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
+
+       set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
+       set_crtc(&plane_state, -2, -2, 1028, 772);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 0x10001,
+                                                 false, false);
+       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+
+       set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
+       set_crtc(&plane_state, 1022, 766, 4, 4);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 0xffff,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 true, false);
+       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
+       FAIL_ON(!plane_state.visible);
+       /* Should not be rounded to 0x20001, which would be upscaling. */
+       FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
+
+       set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
+       set_crtc(&plane_state, -2, -2, 1028, 772);
+       ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
+                                                 0xffff,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 false, false);
+       FAIL(ret < 0, "Should succeed by clipping to exact multiple");
+       FAIL_ON(!plane_state.visible);
+       FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16));
+       FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+
+       return 0;
+}
index 6ececad6f84574043db9d9d33515f1c24a2d40ea..8554102a6ead189e3b29f380c89867f942b2b73e 100644 (file)
@@ -194,7 +194,7 @@ static int shmob_drm_remove(struct platform_device *pdev)
        drm_kms_helper_poll_fini(ddev);
        drm_mode_config_cleanup(ddev);
        drm_irq_uninstall(ddev);
-       drm_dev_unref(ddev);
+       drm_dev_put(ddev);
 
        return 0;
 }
@@ -290,7 +290,7 @@ err_modeset_cleanup:
        drm_kms_helper_poll_fini(ddev);
        drm_mode_config_cleanup(ddev);
 err_free_drm_dev:
-       drm_dev_unref(ddev);
+       drm_dev_put(ddev);
 
        return ret;
 }
index 5824e6aca8f4af17c23050a6ec1bd59905b1f22c..ed76e52eb21333dd3d042bafe938f062c1069e4f 100644 (file)
@@ -40,6 +40,8 @@ static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
        DRM_DEBUG_DRIVER("\n");
 
        mixer->status = STI_MIXER_DISABLING;
+
+       drm_crtc_wait_one_vblank(crtc);
 }
 
 static int
@@ -250,10 +252,8 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
        struct sti_compositor *compo;
        struct drm_crtc *crtc = data;
        struct sti_mixer *mixer;
-       struct sti_private *priv;
        unsigned int pipe;
 
-       priv = crtc->dev->dev_private;
        pipe = drm_crtc_index(crtc);
        compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]);
        mixer = compo->mixer[pipe];
index 57b870e1e6964ae1739d81b5163f371dbf6daa92..bc908453ffb3550f91cf7febbf315ca2c4059fd1 100644 (file)
@@ -332,7 +332,6 @@ static void sti_cursor_destroy(struct drm_plane *drm_plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       drm_plane_helper_disable(drm_plane, NULL);
        drm_plane_cleanup(drm_plane);
 }
 
index 6dced8abcf163881d5bdfd4efc7a157d47eef04f..ac54e0f9caea3068ab75bca15cc774cb2f36e4ab 100644 (file)
@@ -206,6 +206,8 @@ static void sti_cleanup(struct drm_device *ddev)
        struct sti_private *private = ddev->dev_private;
 
        drm_kms_helper_poll_fini(ddev);
+       drm_atomic_helper_shutdown(ddev);
+       drm_mode_config_cleanup(ddev);
        component_unbind_all(ddev->dev, ddev);
        kfree(private);
        ddev->dev_private = NULL;
@@ -230,7 +232,7 @@ static int sti_bind(struct device *dev)
 
        ret = drm_dev_register(ddev, 0);
        if (ret)
-               goto err_register;
+               goto err_cleanup;
 
        drm_mode_config_reset(ddev);
 
@@ -238,8 +240,6 @@ static int sti_bind(struct device *dev)
 
        return 0;
 
-err_register:
-       drm_mode_config_cleanup(ddev);
 err_cleanup:
        sti_cleanup(ddev);
 err_drm_dev_put:
index c32de6cbf06164cb9a95542dfcdc2173976249e6..cff7b2b5ee9ed07f848a8ebdaf55bb31384aba1f 100644 (file)
@@ -517,7 +517,7 @@ static void sti_gdp_init(struct sti_gdp *gdp)
        /* Allocate all the nodes within a single memory page */
        size = sizeof(struct sti_gdp_node) *
            GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
-       base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL | GFP_DMA);
+       base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL);
 
        if (!base) {
                DRM_ERROR("Failed to allocate memory for GDP node\n");
@@ -883,7 +883,6 @@ static void sti_gdp_destroy(struct drm_plane *drm_plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       drm_plane_helper_disable(drm_plane, NULL);
        drm_plane_cleanup(drm_plane);
 }
 
index 03ac3b4a44692d529aec1b4f496d4648728e56c8..23565f52dd719e8e19ae92cbf3752f8899b5eccc 100644 (file)
@@ -1260,7 +1260,6 @@ static void sti_hqvdp_destroy(struct drm_plane *drm_plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       drm_plane_helper_disable(drm_plane, NULL);
        drm_plane_cleanup(drm_plane);
 }
 
index f2021b23554d316b5270563fbb45f4ddf939bef9..8dec001b9d37c4ffde3700c0d49cf874b7face64 100644 (file)
@@ -26,7 +26,6 @@
 
 static const struct drm_mode_config_funcs drv_mode_config_funcs = {
        .fb_create = drm_gem_fb_create,
-       .output_poll_changed = drm_fb_helper_output_poll_changed,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
@@ -52,7 +51,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
 static struct drm_driver drv_driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
                           DRIVER_ATOMIC,
-       .lastclose = drm_fb_helper_lastclose,
        .name = "stm",
        .desc = "STMicroelectronics SoC DRM",
        .date = "20170330",
@@ -72,6 +70,8 @@ static struct drm_driver drv_driver = {
        .gem_prime_vmap = drm_gem_cma_prime_vmap,
        .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
        .gem_prime_mmap = drm_gem_cma_prime_mmap,
+       .get_scanout_position = ltdc_crtc_scanoutpos,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
 };
 
 static int drv_load(struct drm_device *ddev)
@@ -108,12 +108,6 @@ static int drv_load(struct drm_device *ddev)
        drm_mode_config_reset(ddev);
        drm_kms_helper_poll_init(ddev);
 
-       if (ddev->mode_config.num_connector) {
-               ret = drm_fb_cma_fbdev_init(ddev, 16, 0);
-               if (ret)
-                       DRM_DEBUG("Warning: fails to create fbdev\n");
-       }
-
        platform_set_drvdata(pdev, ddev);
 
        return 0;
@@ -126,7 +120,6 @@ static void drv_unload(struct drm_device *ddev)
 {
        DRM_DEBUG("%s\n", __func__);
 
-       drm_fb_cma_fbdev_fini(ddev);
        drm_kms_helper_poll_fini(ddev);
        ltdc_unload(ddev);
        drm_mode_config_cleanup(ddev);
@@ -154,6 +147,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev)
        if (ret)
                goto err_put;
 
+       drm_fbdev_generic_setup(ddev, 16);
+
        return 0;
 
 err_put:
index 808d9fb627e97ab07562c17183ade0508abfe0b7..61dd661aa0acbde3abfe9481c9a32f4d20c79240 100644 (file)
 #define IER_TERRIE     BIT(2)          /* Transfer ERRor Interrupt Enable */
 #define IER_RRIE       BIT(3)          /* Register Reload Interrupt enable */
 
+#define CPSR_CYPOS     GENMASK(15, 0)  /* Current Y position */
+
 #define ISR_LIF                BIT(0)          /* Line Interrupt Flag */
 #define ISR_FUIF       BIT(1)          /* Fifo Underrun Interrupt Flag */
 #define ISR_TERRIF     BIT(2)          /* Transfer ERRor Interrupt Flag */
@@ -626,6 +628,49 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
        reg_clear(ldev->regs, LTDC_IER, IER_LIE);
 }
 
+bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
+                         bool in_vblank_irq, int *vpos, int *hpos,
+                         ktime_t *stime, ktime_t *etime,
+                         const struct drm_display_mode *mode)
+{
+       struct ltdc_device *ldev = ddev->dev_private;
+       int line, vactive_start, vactive_end, vtotal;
+
+       if (stime)
+               *stime = ktime_get();
+
+       /* The active area starts after vsync + front porch and ends
+        * at vsync + front porc + display size.
+        * The total height also include back porch.
+        * We have 3 possible cases to handle:
+        * - line < vactive_start: vpos = line - vactive_start and will be
+        * negative
+        * - vactive_start < line < vactive_end: vpos = line - vactive_start
+        * and will be positive
+        * - line > vactive_end: vpos = line - vtotal - vactive_start
+        * and will negative
+        *
+        * Computation for the two first cases are identical so we can
+        * simplify the code and only test if line > vactive_end
+        */
+       line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
+       vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
+       vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
+       vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
+
+       if (line > vactive_end)
+               *vpos = line - vtotal - vactive_start;
+       else
+               *vpos = line - vactive_start;
+
+       *hpos = 0;
+
+       if (etime)
+               *etime = ktime_get();
+
+       return true;
+}
+
 static const struct drm_crtc_funcs ltdc_crtc_funcs = {
        .destroy = drm_crtc_cleanup,
        .set_config = drm_atomic_helper_set_config,
index d5afb89608671153681aca3983b0daacca528eda..e46f477a849448dfe2e6f7e04f7d9770ded32de7 100644 (file)
@@ -38,6 +38,11 @@ struct ltdc_device {
        struct fps_info plane_fpsi[LTDC_MAX_LAYER];
 };
 
+bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
+                         bool in_vblank_irq, int *vpos, int *hpos,
+                         ktime_t *stime, ktime_t *etime,
+                         const struct drm_display_mode *mode);
+
 int ltdc_load(struct drm_device *ddev);
 void ltdc_unload(struct drm_device *ddev);
 
index bf49c55b0f2c7de6d62b3ca3dbf34824be512315..9e9255ee59cd83138f5572f0d31df50aec9cc244 100644 (file)
@@ -48,8 +48,12 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
 /*
  * These coefficients are taken from the A33 BSP from Allwinner.
  *
- * The formula is for each component, each coefficient being multiplied by
- * 1024 and each constant being multiplied by 16:
+ * The first three values of each row are coded as 13-bit signed fixed-point
+ * numbers, with 10 bits for the fractional part. The fourth value is a
+ * constant coded as a 14-bit signed fixed-point number with 4 bits for the
+ * fractional part.
+ *
+ * The values in table order give the following colorspace translation:
  * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
  * R = 1.164 * Y + 1.596 * V - 222
  * B = 1.164 * Y + 2.018 * U + 276
@@ -155,6 +159,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
        return 0;
 }
 
+static const uint32_t sun4i_backend_formats[] = {
+       DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_RGBA4444,
+       DRM_FORMAT_RGBA5551,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+};
+
+bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier)
+{
+       unsigned int i;
+
+       if (modifier != DRM_FORMAT_MOD_LINEAR)
+               return false;
+
+       for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++)
+               if (sun4i_backend_formats[i] == fmt)
+                       return true;
+
+       return false;
+}
+
 int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
                                     int layer, struct drm_plane *plane)
 {
@@ -395,6 +429,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
        return 0;
 }
 
+void sun4i_backend_cleanup_layer(struct sun4i_backend *backend,
+                                int layer)
+{
+       regmap_update_bits(backend->engine.regs,
+                          SUN4I_BACKEND_ATTCTL_REG0(layer),
+                          SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN |
+                          SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
+}
+
 static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
 {
        u16 src_h = state->src_h >> 16;
@@ -413,11 +456,50 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
 {
        struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
        struct sun4i_backend *backend = layer->backend;
+       uint32_t format = state->fb->format->format;
+       uint64_t modifier = state->fb->modifier;
 
        if (IS_ERR(backend->frontend))
                return false;
 
-       return sun4i_backend_plane_uses_scaler(state);
+       if (!sun4i_frontend_format_is_supported(format, modifier))
+               return false;
+
+       if (!sun4i_backend_format_is_supported(format, modifier))
+               return true;
+
+       /*
+        * TODO: The backend alone allows 2x and 4x integer scaling, including
+        * support for an alpha component (which the frontend doesn't support).
+        * Use the backend directly instead of the frontend in this case, with
+        * another test to return false.
+        */
+
+       if (sun4i_backend_plane_uses_scaler(state))
+               return true;
+
+       /*
+        * Here the format is supported by both the frontend and the backend
+        * and no frontend scaling is required, so use the backend directly.
+        */
+       return false;
+}
+
+static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state,
+                                            bool *uses_frontend)
+{
+       if (sun4i_backend_plane_uses_frontend(state)) {
+               *uses_frontend = true;
+               return true;
+       }
+
+       *uses_frontend = false;
+
+       /* Scaling is not supported without the frontend. */
+       if (sun4i_backend_plane_uses_scaler(state))
+               return false;
+
+       return true;
 }
 
 static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
@@ -460,14 +542,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
                struct drm_framebuffer *fb = plane_state->fb;
                struct drm_format_name_buf format_name;
 
-               if (sun4i_backend_plane_uses_frontend(plane_state)) {
+               if (!sun4i_backend_plane_is_supported(plane_state,
+                                                     &layer_state->uses_frontend))
+                       return -EINVAL;
+
+               if (layer_state->uses_frontend) {
                        DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
                                         plane->index);
-
-                       layer_state->uses_frontend = true;
                        num_frontend_planes++;
                } else {
-                       layer_state->uses_frontend = false;
+                       if (fb->format->is_yuv) {
+                               DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
+                               num_yuv_planes++;
+                       }
                }
 
                DRM_DEBUG_DRIVER("Plane FB format is %s\n",
@@ -476,11 +563,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
                if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
                        num_alpha_planes++;
 
-               if (fb->format->is_yuv) {
-                       DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
-                       num_yuv_planes++;
-               }
-
                DRM_DEBUG_DRIVER("Plane zpos is %d\n",
                                 plane_state->normalized_zpos);
 
index e3d4c6035eb2511b32fd8a93f90cc1498a11cb5e..01f66463271b211fe7d3bc7a1d2dcd3ad8e95aae 100644 (file)
@@ -198,6 +198,7 @@ engine_to_sun4i_backend(struct sunxi_engine *engine)
 
 void sun4i_backend_layer_enable(struct sun4i_backend *backend,
                                int layer, bool enable);
+bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier);
 int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
                                     int layer, struct drm_plane *plane);
 int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
@@ -208,5 +209,7 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
                                        int layer, uint32_t in_fmt);
 int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend,
                                    int layer, struct drm_plane *plane);
+void sun4i_backend_cleanup_layer(struct sun4i_backend *backend,
+                                int layer);
 
 #endif /* _SUN4I_BACKEND_H_ */
index 1e41c3f5fd6d1c851ac4d2e0dbb2aede2419c404..9e4c375ccc96fac1edfed181f9ffe2de540ce2be 100644 (file)
 #include "sun4i_tcon.h"
 #include "sun8i_tcon_top.h"
 
+static int drm_sun4i_gem_dumb_create(struct drm_file *file_priv,
+                                    struct drm_device *drm,
+                                    struct drm_mode_create_dumb *args)
+{
+       /* The hardware only allows even pitches for YUV buffers. */
+       args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2);
+
+       return drm_gem_cma_dumb_create_internal(file_priv, drm, args);
+}
+
 DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
 
 static struct drm_driver sun4i_drv_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 
        /* Generic Operations */
-       .lastclose              = drm_fb_helper_lastclose,
        .fops                   = &sun4i_drv_fops,
        .name                   = "sun4i-drm",
        .desc                   = "Allwinner sun4i Display Engine",
@@ -43,7 +52,7 @@ static struct drm_driver sun4i_drv_driver = {
        .minor                  = 0,
 
        /* GEM Operations */
-       .dumb_create            = drm_gem_cma_dumb_create,
+       .dumb_create            = drm_sun4i_gem_dumb_create,
        .gem_free_object_unlocked = drm_gem_cma_free_object,
        .gem_vm_ops             = &drm_gem_cma_vm_ops,
 
@@ -105,12 +114,7 @@ static int sun4i_drv_bind(struct device *dev)
        /* Remove early framebuffers (ie. simplefb) */
        drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false);
 
-       /* Create our framebuffer */
-       ret = sun4i_framebuffer_init(drm);
-       if (ret) {
-               dev_err(drm->dev, "Couldn't create our framebuffer\n");
-               goto cleanup_mode_config;
-       }
+       sun4i_framebuffer_init(drm);
 
        /* Enable connectors polling */
        drm_kms_helper_poll_init(drm);
@@ -119,11 +123,12 @@ static int sun4i_drv_bind(struct device *dev)
        if (ret)
                goto finish_poll;
 
+       drm_fbdev_generic_setup(drm, 32);
+
        return 0;
 
 finish_poll:
        drm_kms_helper_poll_fini(drm);
-       sun4i_framebuffer_free(drm);
 cleanup_mode_config:
        drm_mode_config_cleanup(drm);
        of_reserved_mem_device_release(dev);
@@ -138,7 +143,6 @@ static void sun4i_drv_unbind(struct device *dev)
 
        drm_dev_unregister(drm);
        drm_kms_helper_poll_fini(drm);
-       sun4i_framebuffer_free(drm);
        drm_mode_config_cleanup(drm);
        of_reserved_mem_device_release(dev);
        drm_dev_put(drm);
@@ -406,6 +410,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
        { .compatible = "allwinner,sun8i-v3s-display-engine" },
        { .compatible = "allwinner,sun9i-a80-display-engine" },
        { .compatible = "allwinner,sun50i-a64-display-engine" },
+       { .compatible = "allwinner,sun50i-h6-display-engine" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
index 5f29850ef8acf4318772ec0fa791670884dca1ea..cb828028ae06212f26c146b7552eae2f0352741d 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drmP.h>
 
@@ -37,7 +35,6 @@ static int sun4i_de_atomic_check(struct drm_device *dev,
 }
 
 static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
-       .output_poll_changed    = drm_fb_helper_output_poll_changed,
        .atomic_check           = sun4i_de_atomic_check,
        .atomic_commit          = drm_atomic_helper_commit,
        .fb_create              = drm_gem_fb_create,
@@ -47,7 +44,7 @@ static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
        .atomic_commit_tail     = drm_atomic_helper_commit_tail_rpm,
 };
 
-int sun4i_framebuffer_init(struct drm_device *drm)
+void sun4i_framebuffer_init(struct drm_device *drm)
 {
        drm_mode_config_reset(drm);
 
@@ -56,11 +53,4 @@ int sun4i_framebuffer_init(struct drm_device *drm)
 
        drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
        drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
-
-       return drm_fb_cma_fbdev_init(drm, 32, 0);
-}
-
-void sun4i_framebuffer_free(struct drm_device *drm)
-{
-       drm_fb_cma_fbdev_fini(drm);
 }
index 7ef0aed8384ce8741b9aafeb7cbe490f75ef4e94..6fe5bd8c4026b4c40c391731ed8ae6fbeed36477 100644 (file)
@@ -13,7 +13,6 @@
 #ifndef _SUN4I_FRAMEBUFFER_H_
 #define _SUN4I_FRAMEBUFFER_H_
 
-int sun4i_framebuffer_init(struct drm_device *drm);
-void sun4i_framebuffer_free(struct drm_device *drm);
+void sun4i_framebuffer_init(struct drm_device *drm);
 
 #endif /* _SUN4I_FRAMEBUFFER_H_ */
index ddf6cfa6dd2353e7fa94b94171ef913f36afd6fd..1a7ebc45747ec9d9c498adb6a793625661eff945 100644 (file)
@@ -107,8 +107,34 @@ EXPORT_SYMBOL(sun4i_frontend_update_buffer);
 static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
 {
        switch (fmt) {
-       case DRM_FORMAT_ARGB8888:
-               *val = 5;
+       case DRM_FORMAT_XRGB8888:
+               *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB;
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val)
+{
+       if (drm_format_num_planes(fmt) == 1)
+               *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val)
+{
+       switch (fmt) {
+       case DRM_FORMAT_BGRX8888:
+               *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX;
+               return 0;
+
+       case DRM_FORMAT_XRGB8888:
+               *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;
                return 0;
 
        default:
@@ -119,9 +145,12 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
 static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
 {
        switch (fmt) {
+       case DRM_FORMAT_BGRX8888:
+               *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888;
+               return 0;
+
        case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_ARGB8888:
-               *val = 2;
+               *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;
                return 0;
 
        default:
@@ -129,22 +158,54 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
        }
 }
 
+static const uint32_t sun4i_frontend_formats[] = {
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_XRGB8888,
+};
+
+bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier)
+{
+       unsigned int i;
+
+       if (modifier != DRM_FORMAT_MOD_LINEAR)
+               return false;
+
+       for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++)
+               if (sun4i_frontend_formats[i] == fmt)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL(sun4i_frontend_format_is_supported);
+
 int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
                                  struct drm_plane *plane, uint32_t out_fmt)
 {
        struct drm_plane_state *state = plane->state;
        struct drm_framebuffer *fb = state->fb;
+       uint32_t format = fb->format->format;
        u32 out_fmt_val;
-       u32 in_fmt_val;
+       u32 in_fmt_val, in_mod_val, in_ps_val;
        int ret;
 
-       ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
-                                                    &in_fmt_val);
+       ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
        if (ret) {
                DRM_DEBUG_DRIVER("Invalid input format\n");
                return ret;
        }
 
+       ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Invalid input mode\n");
+               return ret;
+       }
+
+       ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Invalid pixel sequence\n");
+               return ret;
+       }
+
        ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
        if (ret) {
                DRM_DEBUG_DRIVER("Invalid output format\n");
@@ -162,10 +223,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
 
+       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+                          SUN4I_FRONTEND_BYPASS_CSC_EN,
+                          SUN4I_FRONTEND_BYPASS_CSC_EN);
+
        regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
-                    SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) |
-                    SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) |
-                    SUN4I_FRONTEND_INPUT_FMT_PS(1));
+                    in_mod_val | in_fmt_val | in_ps_val);
 
        /*
         * TODO: It look like the A31 and A80 at least will need the
@@ -173,7 +236,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
         * ARGB8888).
         */
        regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
-                    SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val));
+                    out_fmt_val);
 
        return 0;
 }
@@ -183,16 +246,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
                                 struct drm_plane *plane)
 {
        struct drm_plane_state *state = plane->state;
+       struct drm_framebuffer *fb = state->fb;
+       uint32_t luma_width, luma_height;
+       uint32_t chroma_width, chroma_height;
 
        /* Set height and width */
        DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
                         state->crtc_w, state->crtc_h);
+
+       luma_width = state->src_w >> 16;
+       luma_height = state->src_h >> 16;
+
+       chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub);
+       chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub);
+
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
-                    SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
-                                          state->src_w >> 16));
+                    SUN4I_FRONTEND_INSIZE(luma_height, luma_width));
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
-                    SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
-                                          state->src_w >> 16));
+                    SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));
 
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
                     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
@@ -200,14 +271,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
                     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
 
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
-                    state->src_w / state->crtc_w);
+                    (luma_width << 16) / state->crtc_w);
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
-                    state->src_w / state->crtc_w);
+                    (chroma_width << 16) / state->crtc_w);
 
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
-                    state->src_h / state->crtc_h);
+                    (luma_height << 16) / state->crtc_h);
        regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
-                    state->src_h / state->crtc_h);
+                    (chroma_height << 16) / state->crtc_h);
 
        regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
                          SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
@@ -339,10 +410,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev)
                           SUN4I_FRONTEND_EN_EN,
                           SUN4I_FRONTEND_EN_EN);
 
-       regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
-                          SUN4I_FRONTEND_BYPASS_CSC_EN,
-                          SUN4I_FRONTEND_BYPASS_CSC_EN);
-
        sun4i_frontend_scaler_init(frontend);
 
        return 0;
index 02661ce81f3e31c81e8203b6fcc42f0914937bc8..ad146e8d8d70d1d05e82420cd45bb0f7e4257bef 100644 (file)
 #define SUN4I_FRONTEND_LINESTRD0_REG           0x040
 
 #define SUN4I_FRONTEND_INPUT_FMT_REG           0x04c
-#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)         ((mod) << 8)
-#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)         ((fmt) << 4)
-#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)                        (ps)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED       (1 << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB          (5 << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX          0
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB          1
 
 #define SUN4I_FRONTEND_OUTPUT_FMT_REG          0x05c
-#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)                (fmt)
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888    1
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888    2
 
 #define SUN4I_FRONTEND_CH0_INSIZE_REG          0x100
 #define SUN4I_FRONTEND_INSIZE(h, w)                    ((((h) - 1) << 16) | (((w) - 1)))
@@ -95,5 +97,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
                                 struct drm_plane *plane);
 int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
                                  struct drm_plane *plane, uint32_t out_fmt);
+bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier);
 
 #endif /* _SUN4I_FRONTEND_H_ */
index 3ecffa52c81466f6998575cf87b830a353478c72..fb985ba1a17613f99bd36c66a8a5e0822c7fd6a6 100644 (file)
@@ -35,7 +35,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
 {
        unsigned long best_rate = 0;
        u8 best_m = 0, m;
-       bool is_double;
+       bool is_double = false;
 
        for (m = div_offset ?: 1; m < (16 + div_offset); m++) {
                u8 d;
@@ -52,7 +52,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
                            (rate - tmp_rate) < (rate - best_rate)) {
                                best_rate = tmp_rate;
                                best_m = m;
-                               is_double = d;
+                               is_double = (d == 2) ? true : false;
                        }
                }
        }
index 78f77af8805ace3597295548f37a38462c293111..29631e0efde37ce709023995634dceac8c412f6a 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
@@ -92,14 +93,16 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
        struct sun4i_backend *backend = layer->backend;
        struct sun4i_frontend *frontend = backend->frontend;
 
+       sun4i_backend_cleanup_layer(backend, layer->id);
+
        if (layer_state->uses_frontend) {
                sun4i_frontend_init(frontend);
                sun4i_frontend_update_coord(frontend, plane);
                sun4i_frontend_update_buffer(frontend, plane);
                sun4i_frontend_update_formats(frontend, plane,
-                                             DRM_FORMAT_ARGB8888);
+                                             DRM_FORMAT_XRGB8888);
                sun4i_backend_update_layer_frontend(backend, layer->id,
-                                                   DRM_FORMAT_ARGB8888);
+                                                   DRM_FORMAT_XRGB8888);
                sun4i_frontend_enable(frontend);
        } else {
                sun4i_backend_update_layer_formats(backend, layer->id, plane);
@@ -112,6 +115,7 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
 }
 
 static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
+       .prepare_fb     = drm_gem_fb_prepare_fb,
        .atomic_disable = sun4i_backend_layer_atomic_disable,
        .atomic_update  = sun4i_backend_layer_atomic_update,
 };
@@ -125,10 +129,11 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
        .update_plane           = drm_atomic_helper_update_plane,
 };
 
-static const uint32_t sun4i_backend_layer_formats[] = {
+static const uint32_t sun4i_layer_formats[] = {
        DRM_FORMAT_ARGB8888,
        DRM_FORMAT_ARGB4444,
        DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_BGRX8888,
        DRM_FORMAT_RGBA5551,
        DRM_FORMAT_RGBA4444,
        DRM_FORMAT_RGB888,
@@ -154,8 +159,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
        /* possible crtcs are set later */
        ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun4i_backend_layer_funcs,
-                                      sun4i_backend_layer_formats,
-                                      ARRAY_SIZE(sun4i_backend_layer_formats),
+                                      sun4i_layer_formats,
+                                      ARRAY_SIZE(sun4i_layer_formats),
                                       NULL, type, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
index f949287d926cd07f6859331c769ef02621ef130f..0420f5c978b9d641926150f0d7987331b9fdb55d 100644 (file)
@@ -478,8 +478,11 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
 }
 
 static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
+                                    const struct drm_encoder *encoder,
                                     const struct drm_display_mode *mode)
 {
+       struct drm_connector *connector = sun4i_tcon_get_connector(encoder);
+       struct drm_display_info display_info = connector->display_info;
        unsigned int bp, hsync, vsync;
        u8 clk_delay;
        u32 val = 0;
@@ -491,8 +494,7 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
        sun4i_tcon0_mode_set_common(tcon, mode);
 
        /* Set dithering if needed */
-       if (tcon->panel)
-               sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
+       sun4i_tcon0_mode_set_dithering(tcon, connector);
 
        /* Adjust clock delay */
        clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -541,6 +543,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
 
+       if (display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
+               val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE;
+
        /*
         * On A20 and similar SoCs, the only way to achieve Positive Edge
         * (Rising Edge), is setting dclk clock phase to 2/3(240°).
@@ -556,20 +561,16 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
         * Following code is a way to avoid quirks all around TCON
         * and DOTCLOCK drivers.
         */
-       if (tcon->panel) {
-               struct drm_panel *panel = tcon->panel;
-               struct drm_connector *connector = panel->connector;
-               struct drm_display_info display_info = connector->display_info;
+       if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+               clk_set_phase(tcon->dclk, 240);
 
-               if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
-                       clk_set_phase(tcon->dclk, 240);
-
-               if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
-                       clk_set_phase(tcon->dclk, 0);
-       }
+       if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+               clk_set_phase(tcon->dclk, 0);
 
        regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
-                          SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
+                          SUN4I_TCON0_IO_POL_HSYNC_POSITIVE |
+                          SUN4I_TCON0_IO_POL_VSYNC_POSITIVE |
+                          SUN4I_TCON0_IO_POL_DE_NEGATIVE,
                           val);
 
        /* Map output pins to channel 0 */
@@ -684,7 +685,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
                sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
                break;
        case DRM_MODE_ENCODER_NONE:
-               sun4i_tcon0_mode_set_rgb(tcon, mode);
+               sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);
                sun4i_tcon_set_mux(tcon, 0, encoder);
                break;
        case DRM_MODE_ENCODER_TVDAC:
index 3d492c8be1fc306010c438fba0536e1242ff1ece..b5214d71610f19c648a2bf931f155185ac8fbdce 100644 (file)
 
 #define SUN4I_TCON0_IO_POL_REG                 0x88
 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase)           ((phase & 3) << 28)
+#define SUN4I_TCON0_IO_POL_DE_NEGATIVE                 BIT(27)
 #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE              BIT(25)
 #define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE              BIT(24)
 
index b14925b40ccf692cb8e57df786063321cccdc7b5..e7608a72f26fc1fe92e4424511e5a5a483971f0f 100644 (file)
@@ -34,6 +34,41 @@ static const u32 yvu2rgb[] = {
        0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
 };
 
+/*
+ * DE3 has a bit different CSC units. Factors are in two's complement format.
+ * First three factors in a row are multiplication factors which have 17 bits
+ * for fractional part. Fourth value in a row is comprised of two factors.
+ * Upper 16 bits represents difference, which is subtracted from the input
+ * value before multiplication and lower 16 bits represents constant, which
+ * is addes at the end.
+ *
+ * x' = c00 * (x + d0) + c01 * (y + d1) + c02 * (z + d2) + const0
+ * y' = c10 * (x + d0) + c11 * (y + d1) + c12 * (z + d2) + const1
+ * z' = c20 * (x + d0) + c21 * (y + d1) + c22 * (z + d2) + const2
+ *
+ * Please note that above formula is true only for Blender CSC. Other DE3 CSC
+ * units takes only positive value for difference. From what can be deducted
+ * from BSP driver code, those units probably automatically assume that
+ * difference has to be subtracted.
+ *
+ * Layout of factors in table:
+ * c00 c01 c02 [d0 const0]
+ * c10 c11 c12 [d1 const1]
+ * c20 c21 c22 [d2 const2]
+ */
+
+static const u32 yuv2rgb_de3[] = {
+       0x0002542a, 0x00000000, 0x0003312a, 0xffc00000,
+       0x0002542a, 0xffff376b, 0xfffe5fc3, 0xfe000000,
+       0x0002542a, 0x000408d3, 0x00000000, 0xfe000000,
+};
+
+static const u32 yvu2rgb_de3[] = {
+       0x0002542a, 0x0003312a, 0x00000000, 0xffc00000,
+       0x0002542a, 0xfffe5fc3, 0xffff376b, 0xfe000000,
+       0x0002542a, 0x00000000, 0x000408d3, 0xfe000000,
+};
+
 static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
                                       enum sun8i_csc_mode mode)
 {
@@ -61,6 +96,28 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
        }
 }
 
+static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
+                                           enum sun8i_csc_mode mode)
+{
+       const u32 *table;
+       u32 base_reg;
+
+       switch (mode) {
+       case SUN8I_CSC_MODE_YUV2RGB:
+               table = yuv2rgb_de3;
+               break;
+       case SUN8I_CSC_MODE_YVU2RGB:
+               table = yvu2rgb_de3;
+               break;
+       default:
+               DRM_WARN("Wrong CSC mode specified.\n");
+               return;
+       }
+
+       base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0);
+       regmap_bulk_write(map, base_reg, table, 12);
+}
+
 static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
 {
        u32 val;
@@ -73,11 +130,32 @@ static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
        regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
 }
 
+static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
+{
+       u32 val, mask;
+
+       mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
+
+       if (enable)
+               val = mask;
+       else
+               val = 0;
+
+       regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
+                          mask, val);
+}
+
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
                                     enum sun8i_csc_mode mode)
 {
        u32 base;
 
+       if (mixer->cfg->is_de3) {
+               sun8i_de3_ccsc_set_coefficients(mixer->engine.regs,
+                                               layer, mode);
+               return;
+       }
+
        base = ccsc_base[mixer->cfg->ccsc][layer];
 
        sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
@@ -87,6 +165,11 @@ void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
 {
        u32 base;
 
+       if (mixer->cfg->is_de3) {
+               sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
+               return;
+       }
+
        base = ccsc_base[mixer->cfg->ccsc][layer];
 
        sun8i_csc_enable(mixer->engine.regs, base, enable);
index ed2983770e9cb598bf6c60da201f9b2988701161..dc47720c99ba5689a8c12f217c7859960bfa394d 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/component.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #include <drm/drm_of.h>
@@ -20,7 +21,8 @@ static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 {
        struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
 
-       clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
+       if (hdmi->quirks->set_rate)
+               clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
 }
 
 static const struct drm_encoder_helper_funcs
@@ -33,8 +35,8 @@ static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
 };
 
 static enum drm_mode_status
-sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
-                        const struct drm_display_mode *mode)
+sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector,
+                             const struct drm_display_mode *mode)
 {
        if (mode->clock > 297000)
                return MODE_CLOCK_HIGH;
@@ -42,6 +44,17 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
+static enum drm_mode_status
+sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector,
+                           const struct drm_display_mode *mode)
+{
+       /* This is max for HDMI 2.0b (4K@60Hz) */
+       if (mode->clock > 594000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
 static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node)
 {
        return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
@@ -102,6 +115,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
        hdmi->dev = &pdev->dev;
        encoder = &hdmi->encoder;
 
+       hdmi->quirks = of_device_get_match_data(dev);
+
        encoder->possible_crtcs =
                sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node);
        /*
@@ -168,10 +183,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
 
        sun8i_hdmi_phy_init(hdmi->phy);
 
-       plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
-       plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
-       plat_data->phy_name = "sun8i_dw_hdmi_phy";
-       plat_data->phy_data = hdmi->phy;
+       plat_data->mode_valid = hdmi->quirks->mode_valid;
+       sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
 
        platform_set_drvdata(pdev, hdmi);
 
@@ -230,8 +243,24 @@ static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = {
+       .mode_valid = sun8i_dw_hdmi_mode_valid_a83t,
+       .set_rate = true,
+};
+
+static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = {
+       .mode_valid = sun8i_dw_hdmi_mode_valid_h6,
+};
+
 static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
-       { .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
+       {
+               .compatible = "allwinner,sun8i-a83t-dw-hdmi",
+               .data = &sun8i_a83t_quirks,
+       },
+       {
+               .compatible = "allwinner,sun50i-h6-dw-hdmi",
+               .data = &sun50i_h6_quirks,
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
index 7fdc1ecd28922189f7fd1de9163006850a95fac5..720c5aa8adc14288ff1d44fe6d66fb498da41b47 100644 (file)
@@ -150,6 +150,10 @@ struct sun8i_hdmi_phy;
 struct sun8i_hdmi_phy_variant {
        bool has_phy_clk;
        bool has_second_pll;
+       unsigned int is_custom_phy : 1;
+       const struct dw_hdmi_curr_ctrl *cur_ctr;
+       const struct dw_hdmi_mpll_config *mpll_cfg;
+       const struct dw_hdmi_phy_config *phy_cfg;
        void (*phy_init)(struct sun8i_hdmi_phy *phy);
        void (*phy_disable)(struct dw_hdmi *hdmi,
                            struct sun8i_hdmi_phy *phy);
@@ -170,6 +174,12 @@ struct sun8i_hdmi_phy {
        struct sun8i_hdmi_phy_variant   *variant;
 };
 
+struct sun8i_dw_hdmi_quirks {
+       enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+                                          const struct drm_display_mode *mode);
+       unsigned int set_rate : 1;
+};
+
 struct sun8i_dw_hdmi {
        struct clk                      *clk_tmds;
        struct device                   *dev;
@@ -178,6 +188,7 @@ struct sun8i_dw_hdmi {
        struct sun8i_hdmi_phy           *phy;
        struct dw_hdmi_plat_data        plat_data;
        struct regulator                *regulator;
+       const struct sun8i_dw_hdmi_quirks *quirks;
        struct reset_control            *rst_ctrl;
 };
 
@@ -191,7 +202,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
 void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
 
 void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
-const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
+void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
+                           struct dw_hdmi_plat_data *plat_data);
 
 int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
                         bool second_parent);
index 471993097ceda3b3c35a29ab2ae681026e278d93..66ea3a902e363041b80ecc9127076af84598f933 100644 (file)
  */
 #define I2C_ADDR       0x69
 
+static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
+       {
+               30666000, {
+                       { 0x00b3, 0x0000 },
+                       { 0x2153, 0x0000 },
+                       { 0x40f3, 0x0000 },
+               },
+       },  {
+               36800000, {
+                       { 0x00b3, 0x0000 },
+                       { 0x2153, 0x0000 },
+                       { 0x40a2, 0x0001 },
+               },
+       },  {
+               46000000, {
+                       { 0x00b3, 0x0000 },
+                       { 0x2142, 0x0001 },
+                       { 0x40a2, 0x0001 },
+               },
+       },  {
+               61333000, {
+                       { 0x0072, 0x0001 },
+                       { 0x2142, 0x0001 },
+                       { 0x40a2, 0x0001 },
+               },
+       },  {
+               73600000, {
+                       { 0x0072, 0x0001 },
+                       { 0x2142, 0x0001 },
+                       { 0x4061, 0x0002 },
+               },
+       },  {
+               92000000, {
+                       { 0x0072, 0x0001 },
+                       { 0x2145, 0x0002 },
+                       { 0x4061, 0x0002 },
+               },
+       },  {
+               122666000, {
+                       { 0x0051, 0x0002 },
+                       { 0x2145, 0x0002 },
+                       { 0x4061, 0x0002 },
+               },
+       },  {
+               147200000, {
+                       { 0x0051, 0x0002 },
+                       { 0x2145, 0x0002 },
+                       { 0x4064, 0x0003 },
+               },
+       },  {
+               184000000, {
+                       { 0x0051, 0x0002 },
+                       { 0x214c, 0x0003 },
+                       { 0x4064, 0x0003 },
+               },
+       },  {
+               226666000, {
+                       { 0x0040, 0x0003 },
+                       { 0x214c, 0x0003 },
+                       { 0x4064, 0x0003 },
+               },
+       },  {
+               272000000, {
+                       { 0x0040, 0x0003 },
+                       { 0x214c, 0x0003 },
+                       { 0x5a64, 0x0003 },
+               },
+       },  {
+               340000000, {
+                       { 0x0040, 0x0003 },
+                       { 0x3b4c, 0x0003 },
+                       { 0x5a64, 0x0003 },
+               },
+       },  {
+               594000000, {
+                       { 0x1a40, 0x0003 },
+                       { 0x3b4c, 0x0003 },
+                       { 0x5a64, 0x0003 },
+               },
+       }, {
+               ~0UL, {
+                       { 0x0000, 0x0000 },
+                       { 0x0000, 0x0000 },
+                       { 0x0000, 0x0000 },
+               },
+       }
+};
+
+static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
+       /* pixelclk    bpp8    bpp10   bpp12 */
+       { 25175000,  { 0x0000, 0x0000, 0x0000 }, },
+       { 27000000,  { 0x0012, 0x0000, 0x0000 }, },
+       { 59400000,  { 0x0008, 0x0008, 0x0008 }, },
+       { 72000000,  { 0x0008, 0x0008, 0x001b }, },
+       { 74250000,  { 0x0013, 0x0013, 0x0013 }, },
+       { 90000000,  { 0x0008, 0x001a, 0x001b }, },
+       { 118800000, { 0x001b, 0x001a, 0x001b }, },
+       { 144000000, { 0x001b, 0x001a, 0x0034 }, },
+       { 180000000, { 0x001b, 0x0033, 0x0034 }, },
+       { 216000000, { 0x0036, 0x0033, 0x0034 }, },
+       { 237600000, { 0x0036, 0x0033, 0x001b }, },
+       { 288000000, { 0x0036, 0x001b, 0x001b }, },
+       { 297000000, { 0x0019, 0x001b, 0x0019 }, },
+       { 330000000, { 0x0036, 0x001b, 0x001b }, },
+       { 594000000, { 0x003f, 0x001b, 0x001b }, },
+       { ~0UL,      { 0x0000, 0x0000, 0x0000 }, }
+};
+
+static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
+       /*pixelclk   symbol   term   vlev*/
+       { 74250000,  0x8009, 0x0004, 0x0232},
+       { 148500000, 0x8029, 0x0004, 0x0273},
+       { 594000000, 0x8039, 0x0004, 0x014a},
+       { ~0UL,      0x0000, 0x0000, 0x0000}
+};
+
 static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
                                      struct sun8i_hdmi_phy *phy,
                                      unsigned int clk_rate)
@@ -279,8 +395,31 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
        .setup_hpd = &dw_hdmi_phy_setup_hpd,
 };
 
+static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
+{
+       /* enable read access to HDMI controller */
+       regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
+                    SUN8I_HDMI_PHY_READ_EN_MAGIC);
+
+       /* unscramble register offsets */
+       regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+                    SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
+}
+
+static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
+{
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+                          SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
+                          SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
+
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+                          0xffff0000, 0x80c00000);
+}
+
 static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
 {
+       sun8i_hdmi_phy_unlock(phy);
+
        regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
                           SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
                           SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
@@ -298,6 +437,8 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
 {
        unsigned int val;
 
+       sun8i_hdmi_phy_unlock(phy);
+
        regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
        regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
                           SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
@@ -372,20 +513,23 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
 
 void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
 {
-       /* enable read access to HDMI controller */
-       regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
-                    SUN8I_HDMI_PHY_READ_EN_MAGIC);
-
-       /* unscramble register offsets */
-       regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
-                    SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
-
        phy->variant->phy_init(phy);
 }
 
-const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
+void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
+                           struct dw_hdmi_plat_data *plat_data)
 {
-       return &sun8i_hdmi_phy_ops;
+       struct sun8i_hdmi_phy_variant *variant = phy->variant;
+
+       if (variant->is_custom_phy) {
+               plat_data->phy_ops = &sun8i_hdmi_phy_ops;
+               plat_data->phy_name = "sun8i_dw_hdmi_phy";
+               plat_data->phy_data = phy;
+       } else {
+               plat_data->mpll_cfg = variant->mpll_cfg;
+               plat_data->cur_ctr = variant->cur_ctr;
+               plat_data->phy_config = variant->phy_cfg;
+       }
 }
 
 static struct regmap_config sun8i_hdmi_phy_regmap_config = {
@@ -396,14 +540,8 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
        .name           = "phy"
 };
 
-static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
-       .has_phy_clk = true,
-       .phy_init = &sun8i_hdmi_phy_init_h3,
-       .phy_disable = &sun8i_hdmi_phy_disable_h3,
-       .phy_config = &sun8i_hdmi_phy_config_h3,
-};
-
 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
+       .is_custom_phy = true,
        .phy_init = &sun8i_hdmi_phy_init_a83t,
        .phy_disable = &sun8i_hdmi_phy_disable_a83t,
        .phy_config = &sun8i_hdmi_phy_config_a83t,
@@ -411,6 +549,7 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
 
 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
        .has_phy_clk = true,
+       .is_custom_phy = true,
        .phy_init = &sun8i_hdmi_phy_init_h3,
        .phy_disable = &sun8i_hdmi_phy_disable_h3,
        .phy_config = &sun8i_hdmi_phy_config_h3,
@@ -419,16 +558,28 @@ static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
        .has_phy_clk = true,
        .has_second_pll = true,
+       .is_custom_phy = true,
+       .phy_init = &sun8i_hdmi_phy_init_h3,
+       .phy_disable = &sun8i_hdmi_phy_disable_h3,
+       .phy_config = &sun8i_hdmi_phy_config_h3,
+};
+
+static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
+       .has_phy_clk = true,
+       .is_custom_phy = true,
        .phy_init = &sun8i_hdmi_phy_init_h3,
        .phy_disable = &sun8i_hdmi_phy_disable_h3,
        .phy_config = &sun8i_hdmi_phy_config_h3,
 };
 
+static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
+       .cur_ctr  = sun50i_h6_cur_ctr,
+       .mpll_cfg = sun50i_h6_mpll_cfg,
+       .phy_cfg  = sun50i_h6_phy_config,
+       .phy_init = &sun50i_hdmi_phy_init_h6,
+};
+
 static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
-       {
-               .compatible = "allwinner,sun50i-a64-hdmi-phy",
-               .data = &sun50i_a64_hdmi_phy,
-       },
        {
                .compatible = "allwinner,sun8i-a83t-hdmi-phy",
                .data = &sun8i_a83t_hdmi_phy,
@@ -441,6 +592,14 @@ static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
                .compatible = "allwinner,sun8i-r40-hdmi-phy",
                .data = &sun8i_r40_hdmi_phy,
        },
+       {
+               .compatible = "allwinner,sun50i-a64-hdmi-phy",
+               .data = &sun50i_a64_hdmi_phy,
+       },
+       {
+               .compatible = "allwinner,sun50i-h6-hdmi-phy",
+               .data = &sun50i_h6_hdmi_phy,
+       },
        { /* sentinel */ }
 };
 
index 8b3d02b146b7a57c5cfe6f25ef7dc83155339180..44a9ba7d843336b703f5bded9af69a3e31a19c33 100644 (file)
@@ -368,6 +368,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
        struct sun8i_mixer *mixer;
        struct resource *res;
        void __iomem *regs;
+       unsigned int base;
        int plane_cnt;
        int i, ret;
 
@@ -456,33 +457,60 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
 
        list_add_tail(&mixer->engine.list, &drv->engine_list);
 
-       /* Reset the registers */
-       for (i = 0x0; i < 0x20000; i += 4)
-               regmap_write(mixer->engine.regs, i, 0);
+       base = sun8i_blender_base(mixer);
+
+       /* Reset registers and disable unused sub-engines */
+       if (mixer->cfg->is_de3) {
+               for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
+                       regmap_write(mixer->engine.regs, i, 0);
+
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
+               regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
+       } else {
+               for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
+                       regmap_write(mixer->engine.regs, i, 0);
+
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
+               regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
+       }
 
        /* Enable the mixer */
        regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
                     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
 
        /* Set background color to black */
-       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
+       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
                     SUN8I_MIXER_BLEND_COLOR_BLACK);
 
        /*
         * Set fill color of bottom plane to black. Generally not needed
         * except when VI plane is at bottom (zpos = 0) and enabled.
         */
-       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
+       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
                     SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
-       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
+       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
                     SUN8I_MIXER_BLEND_COLOR_BLACK);
 
        plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
        for (i = 0; i < plane_cnt; i++)
-               regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
+               regmap_write(mixer->engine.regs,
+                            SUN8I_MIXER_BLEND_MODE(base, i),
                             SUN8I_MIXER_BLEND_MODE_DEF);
 
-       regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
+       regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
                           SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
 
        return 0;
@@ -585,6 +613,15 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
        .vi_num         = 1,
 };
 
+static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
+       .ccsc           = 0,
+       .is_de3         = true,
+       .mod_rate       = 600000000,
+       .scaler_mask    = 0xf,
+       .ui_num         = 3,
+       .vi_num         = 1,
+};
+
 static const struct of_device_id sun8i_mixer_of_table[] = {
        {
                .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
@@ -618,6 +655,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
                .compatible = "allwinner,sun50i-a64-de2-mixer-1",
                .data = &sun50i_a64_mixer1_cfg,
        },
+       {
+               .compatible = "allwinner,sun50i-h6-de3-mixer-0",
+               .data = &sun50i_h6_mixer0_cfg,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
index 406c42e752d75c5c96faf1dd079c71539b3c4d20..913d14ce68b0093941ef0b2a0308c1381303f7d8 100644 (file)
 
 #define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE                BIT(0)
 
-#define SUN8I_MIXER_BLEND_PIPE_CTL             0x1000
-#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x)       (0x1004 + 0x10 * (x) + 0x0)
-#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x)       (0x1004 + 0x10 * (x) + 0x4)
-#define SUN8I_MIXER_BLEND_ATTR_COORD(x)                (0x1004 + 0x10 * (x) + 0x8)
-#define SUN8I_MIXER_BLEND_ROUTE                        0x1080
-#define SUN8I_MIXER_BLEND_PREMULTIPLY          0x1084
-#define SUN8I_MIXER_BLEND_BKCOLOR              0x1088
-#define SUN8I_MIXER_BLEND_OUTSIZE              0x108c
-#define SUN8I_MIXER_BLEND_MODE(x)              (0x1090 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_CK_CTL               0x10b0
-#define SUN8I_MIXER_BLEND_CK_CFG               0x10b4
-#define SUN8I_MIXER_BLEND_CK_MAX(x)            (0x10c0 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_CK_MIN(x)            (0x10e0 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_OUTCTL               0x10fc
+#define DE2_MIXER_UNIT_SIZE                    0x6000
+#define DE3_MIXER_UNIT_SIZE                    0x3000
+
+#define DE2_BLD_BASE                           0x1000
+#define DE2_CH_BASE                            0x2000
+#define DE2_CH_SIZE                            0x1000
+
+#define DE3_BLD_BASE                           0x0800
+#define DE3_CH_BASE                            0x1000
+#define DE3_CH_SIZE                            0x0800
+
+#define SUN8I_MIXER_BLEND_PIPE_CTL(base)       ((base) + 0)
+#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, x) ((base) + 0x4 + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ATTR_INSIZE(base, x) ((base) + 0x8 + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ATTR_COORD(base, x)  ((base) + 0xc + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ROUTE(base)          ((base) + 0x80)
+#define SUN8I_MIXER_BLEND_PREMULTIPLY(base)    ((base) + 0x84)
+#define SUN8I_MIXER_BLEND_BKCOLOR(base)                ((base) + 0x88)
+#define SUN8I_MIXER_BLEND_OUTSIZE(base)                ((base) + 0x8c)
+#define SUN8I_MIXER_BLEND_MODE(base, x)                ((base) + 0x90 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_CTL(base)         ((base) + 0xb0)
+#define SUN8I_MIXER_BLEND_CK_CFG(base)         ((base) + 0xb4)
+#define SUN8I_MIXER_BLEND_CK_MAX(base, x)      ((base) + 0xc0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_MIN(base, x)      ((base) + 0xe0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_OUTCTL(base)         ((base) + 0xfc)
+#define SUN50I_MIXER_BLEND_CSC_CTL(base)       ((base) + 0x100)
+#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \
+       ((base) + 0x110 + (layer) * 0x30 +  (x) * 0x10 + 4 * (y))
+#define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \
+       ((base) + 0x110 + (layer) * 0x30 +  (i) * 0x10 + 0x0c)
 
 #define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK      GENMASK(12, 8)
 #define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe)    BIT(8 + pipe)
 #define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe)
+
 /* colors are always in AARRGGBB format */
 #define SUN8I_MIXER_BLEND_COLOR_BLACK          0xff000000
 /* The following numbers are some still unknown magic numbers */
@@ -57,6 +74,9 @@
 
 #define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED    BIT(1)
 
+#define SUN50I_MIXER_BLEND_CSC_CTL_EN(ch)      BIT(ch)
+#define SUN50I_MIXER_BLEND_CSC_CONST_VAL(d, c) (((d) << 16) | ((c) & 0xffff))
+
 #define SUN8I_MIXER_FBFMT_ARGB8888     0
 #define SUN8I_MIXER_FBFMT_ABGR8888     1
 #define SUN8I_MIXER_FBFMT_RGBA8888     2
 #define SUN8I_MIXER_FBFMT_YUV411       14
 
 /*
- * These sub-engines are still unknown now, the EN registers are here only to
- * be used to disable these sub-engines.
+ * Sub-engines listed bellow are unused for now. The EN registers are here only
+ * to be used to disable these sub-engines.
  */
 #define SUN8I_MIXER_FCE_EN                     0xa0000
 #define SUN8I_MIXER_BWS_EN                     0xa2000
 #define SUN8I_MIXER_FCC_EN                     0xaa000
 #define SUN8I_MIXER_DCSC_EN                    0xb0000
 
+#define SUN50I_MIXER_FCE_EN                    0x70000
+#define SUN50I_MIXER_PEAK_EN                   0x70800
+#define SUN50I_MIXER_LCTI_EN                   0x71000
+#define SUN50I_MIXER_BLS_EN                    0x71800
+#define SUN50I_MIXER_FCC_EN                    0x72000
+#define SUN50I_MIXER_DNS_EN                    0x80000
+#define SUN50I_MIXER_DRC_EN                    0xa0000
+#define SUN50I_MIXER_FMT_EN                    0xa8000
+#define SUN50I_MIXER_CDC0_EN                   0xd0000
+#define SUN50I_MIXER_CDC1_EN                   0xd8000
+
 struct de2_fmt_info {
        u32                     drm_fmt;
        u32                     de2_fmt;
@@ -127,6 +158,7 @@ struct de2_fmt_info {
  *     are invalid.
  * @mod_rate: module clock rate that needs to be set in order to have
  *     a functional block.
+ * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
  */
 struct sun8i_mixer_cfg {
        int             vi_num;
@@ -134,6 +166,7 @@ struct sun8i_mixer_cfg {
        int             scaler_mask;
        int             ccsc;
        unsigned long   mod_rate;
+       unsigned int    is_de3 : 1;
 };
 
 struct sun8i_mixer {
@@ -153,5 +186,20 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
        return container_of(engine, struct sun8i_mixer, engine);
 }
 
+static inline u32
+sun8i_blender_base(struct sun8i_mixer *mixer)
+{
+       return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
+}
+
+static inline u32
+sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
+{
+       if (mixer->cfg->is_de3)
+               return DE3_CH_BASE + channel * DE3_CH_SIZE;
+       else
+               return DE2_CH_BASE + channel * DE2_CH_SIZE;
+}
+
 const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
 #endif /* _SUN8I_MIXER_H_ */
index 3040a79f298ffa2348b258c14a0307ee76fbd7ce..fc36e0c10a374a2a33a054a4102944dfb0b03009 100644 (file)
@@ -9,11 +9,17 @@
 #include <linux/component.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 
 #include "sun8i_tcon_top.h"
 
+struct sun8i_tcon_top_quirks {
+       bool has_tcon_tv1;
+       bool has_dsi;
+};
+
 static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node)
 {
        return !!of_match_node(sun8i_tcon_top_of_table, node);
@@ -121,10 +127,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
        struct platform_device *pdev = to_platform_device(dev);
        struct clk_hw_onecell_data *clk_data;
        struct sun8i_tcon_top *tcon_top;
+       const struct sun8i_tcon_top_quirks *quirks;
        struct resource *res;
        void __iomem *regs;
        int ret, i;
 
+       quirks = of_device_get_match_data(&pdev->dev);
+
        tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
        if (!tcon_top)
                return -ENOMEM;
@@ -167,6 +176,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
                goto err_assert_reset;
        }
 
+       /*
+        * At least on H6, some registers have some bits set by default
+        * which may cause issues. Clear them here.
+        */
+       writel(0, regs + TCON_TOP_PORT_SEL_REG);
+       writel(0, regs + TCON_TOP_GATE_SRC_REG);
+
        /*
         * TCON TOP has two muxes, which select parent clock for each TCON TV
         * channel clock. Parent could be either TCON TV or TVE clock. For now
@@ -180,15 +196,17 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
                                             &tcon_top->reg_lock,
                                             TCON_TOP_TCON_TV0_GATE, 0);
 
-       clk_data->hws[CLK_TCON_TOP_TV1] =
-               sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs,
-                                            &tcon_top->reg_lock,
-                                            TCON_TOP_TCON_TV1_GATE, 1);
+       if (quirks->has_tcon_tv1)
+               clk_data->hws[CLK_TCON_TOP_TV1] =
+                       sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs,
+                                                    &tcon_top->reg_lock,
+                                                    TCON_TOP_TCON_TV1_GATE, 1);
 
-       clk_data->hws[CLK_TCON_TOP_DSI] =
-               sun8i_tcon_top_register_gate(dev, "dsi", regs,
-                                            &tcon_top->reg_lock,
-                                            TCON_TOP_TCON_DSI_GATE, 2);
+       if (quirks->has_dsi)
+               clk_data->hws[CLK_TCON_TOP_DSI] =
+                       sun8i_tcon_top_register_gate(dev, "dsi", regs,
+                                                    &tcon_top->reg_lock,
+                                                    TCON_TOP_TCON_DSI_GATE, 2);
 
        for (i = 0; i < CLK_NUM; i++)
                if (IS_ERR(clk_data->hws[i])) {
@@ -250,9 +268,25 @@ static int sun8i_tcon_top_remove(struct platform_device *pdev)
        return 0;
 }
 
+const struct sun8i_tcon_top_quirks sun8i_r40_tcon_top_quirks = {
+       .has_tcon_tv1   = true,
+       .has_dsi        = true,
+};
+
+const struct sun8i_tcon_top_quirks sun50i_h6_tcon_top_quirks = {
+       /* Nothing special */
+};
+
 /* sun4i_drv uses this list to check if a device node is a TCON TOP */
 const struct of_device_id sun8i_tcon_top_of_table[] = {
-       { .compatible = "allwinner,sun8i-r40-tcon-top" },
+       {
+               .compatible = "allwinner,sun8i-r40-tcon-top",
+               .data = &sun8i_r40_tcon_top_quirks
+       },
+       {
+               .compatible = "allwinner,sun50i-h6-tcon-top",
+               .data = &sun50i_h6_tcon_top_quirks
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
index 28c15c6ef1efbea5fc92e4d11c7bdcc4b03b2a73..18534263a05d827fe4e87b5e65355f98094ffb46 100644 (file)
@@ -19,6 +19,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drmP.h>
 
@@ -30,7 +31,10 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
                                  int overlay, bool enable, unsigned int zpos,
                                  unsigned int old_zpos)
 {
-       u32 val;
+       u32 val, bld_base, ch_base;
+
+       bld_base = sun8i_blender_base(mixer);
+       ch_base = sun8i_channel_base(mixer, channel);
 
        DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
                         enable ? "En" : "Dis", channel, overlay);
@@ -41,17 +45,17 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
                val = 0;
 
        regmap_update_bits(mixer->engine.regs,
-                          SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+                          SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
                           SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
 
        if (!enable || zpos != old_zpos) {
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_PIPE_CTL,
+                                  SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
                                   SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
                                   0);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_ROUTE,
+                                  SUN8I_MIXER_BLEND_ROUTE(bld_base),
                                   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
                                   0);
        }
@@ -60,12 +64,13 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
                val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_PIPE_CTL, val, val);
+                                  SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+                                  val, val);
 
                val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_ROUTE,
+                                  SUN8I_MIXER_BLEND_ROUTE(bld_base),
                                   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
                                   val);
        }
@@ -77,12 +82,16 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
 {
        struct drm_plane_state *state = plane->state;
        u32 src_w, src_h, dst_w, dst_h;
+       u32 bld_base, ch_base;
        u32 outsize, insize;
        u32 hphase, vphase;
 
        DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
                         channel, overlay);
 
+       bld_base = sun8i_blender_base(mixer);
+       ch_base = sun8i_channel_base(mixer, channel);
+
        src_w = drm_rect_width(&state->src) >> 16;
        src_h = drm_rect_height(&state->src) >> 16;
        dst_w = drm_rect_width(&state->dst);
@@ -103,8 +112,8 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                regmap_write(mixer->engine.regs,
                             SUN8I_MIXER_GLOBAL_SIZE,
                             outsize);
-               regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
-                            outsize);
+               regmap_write(mixer->engine.regs,
+                            SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize);
 
                if (state->crtc)
                        interlaced = state->crtc->state->adjusted_mode.flags
@@ -116,7 +125,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                        val = 0;
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_OUTCTL,
+                                  SUN8I_MIXER_BLEND_OUTCTL(bld_base),
                                   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
                                   val);
 
@@ -129,10 +138,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                         state->src.x1 >> 16, state->src.y1 >> 16);
        DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay),
+                    SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
                     insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel),
+                    SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
                     insize);
 
        if (insize != outsize || hphase || vphase) {
@@ -156,10 +165,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                         state->dst.x1, state->dst.y1);
        DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_BLEND_ATTR_COORD(zpos),
+                    SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
                     SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos),
+                    SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
                     outsize);
 
        return 0;
@@ -170,7 +179,9 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 {
        struct drm_plane_state *state = plane->state;
        const struct de2_fmt_info *fmt_info;
-       u32 val;
+       u32 val, ch_base;
+
+       ch_base = sun8i_channel_base(mixer, channel);
 
        fmt_info = sun8i_mixer_format_info(state->fb->format->format);
        if (!fmt_info || !fmt_info->rgb) {
@@ -180,7 +191,7 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 
        val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
        regmap_update_bits(mixer->engine.regs,
-                          SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+                          SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
                           SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
 
        return 0;
@@ -193,8 +204,11 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
        struct drm_framebuffer *fb = state->fb;
        struct drm_gem_cma_object *gem;
        dma_addr_t paddr;
+       u32 ch_base;
        int bpp;
 
+       ch_base = sun8i_channel_base(mixer, channel);
+
        /* Get the physical address of the buffer in memory */
        gem = drm_fb_cma_get_gem_obj(fb, 0);
 
@@ -211,13 +225,13 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
        /* Set the line width */
        DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay),
+                    SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
                     fb->pitches[0]);
 
        DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
 
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay),
+                    SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
                     lower_32_bits(paddr));
 
        return 0;
@@ -287,6 +301,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
 }
 
 static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
+       .prepare_fb     = drm_gem_fb_prepare_fb,
        .atomic_check   = sun8i_ui_layer_atomic_check,
        .atomic_disable = sun8i_ui_layer_atomic_disable,
        .atomic_update  = sun8i_ui_layer_atomic_update,
index 123b15ea9918dbe1c0638390cccd73e8a2107822..f4389cf0ba2009bc5c6a00632e4f0ed82be6624c 100644 (file)
 
 #include <drm/drm_plane.h>
 
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
-#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
-#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
-#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
-#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
-#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
-                       (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
-#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch)      (0x2000 + 0x1000 * (ch) + 0x80)
-#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch)      (0x2000 + 0x1000 * (ch) + 0x84)
-#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch)       (0x2000 + 0x1000 * (ch) + 0x88)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(base, layer) \
+                       ((base) + 0x20 * (layer) + 0xc)
+#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x10)
+#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x14)
+#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(base, layer) \
+                       ((base) + 0x20 * (layer) + 0x18)
+#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(base) \
+                       ((base) + 0x80)
+#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(base) \
+                       ((base) + 0x84)
+#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(base) \
+                       ((base) + 0x88)
 
 #define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN              BIT(0)
 #define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
index 6bb2aa164c8e181191e7729bf2d5f81a85f22f8a..ae0806bccac7fef86b99fd572d75e1cedb61c9af 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
 
 static const u32 lan2coefftab16[240] = {
        0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
@@ -88,6 +89,20 @@ static const u32 lan2coefftab16[240] = {
        0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
 };
 
+static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
+{
+       int vi_num = mixer->cfg->vi_num;
+
+       if (mixer->cfg->is_de3)
+               return DE3_VI_SCALER_UNIT_BASE +
+                      DE3_VI_SCALER_UNIT_SIZE * vi_num +
+                      DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num);
+       else
+               return DE2_VI_SCALER_UNIT_BASE +
+                      DE2_VI_SCALER_UNIT_SIZE * vi_num +
+                      DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num);
+}
+
 static int sun8i_ui_scaler_coef_index(unsigned int step)
 {
        unsigned int scale, int_part, float_part;
@@ -114,33 +129,35 @@ static int sun8i_ui_scaler_coef_index(unsigned int step)
 
 void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
 {
-       int vi_cnt = mixer->cfg->vi_num;
-       u32 val;
+       u32 val, base;
 
-       if (WARN_ON(layer < vi_cnt))
+       if (WARN_ON(layer < mixer->cfg->vi_num))
                return;
 
+       base = sun8i_ui_scaler_base(mixer, layer);
+
        if (enable)
                val = SUN8I_SCALER_GSU_CTRL_EN |
                      SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
        else
                val = 0;
 
-       regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_CTRL(vi_cnt, layer - vi_cnt), val);
+       regmap_write(mixer->engine.regs, SUN8I_SCALER_GSU_CTRL(base), val);
 }
 
 void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
                           u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
                           u32 hscale, u32 vscale, u32 hphase, u32 vphase)
 {
-       int vi_cnt = mixer->cfg->vi_num;
        u32 insize, outsize;
        int i, offset;
+       u32 base;
 
-       if (WARN_ON(layer < vi_cnt))
+       if (WARN_ON(layer < mixer->cfg->vi_num))
                return;
 
+       base = sun8i_ui_scaler_base(mixer, layer);
+
        hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
        vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
        hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
@@ -149,24 +166,22 @@ void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
        insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
        outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
 
-       layer -= vi_cnt;
-
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, layer), outsize);
+                    SUN8I_SCALER_GSU_OUTSIZE(base), outsize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_INSIZE(vi_cnt, layer), insize);
+                    SUN8I_SCALER_GSU_INSIZE(base), insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_HSTEP(vi_cnt, layer), hscale);
+                    SUN8I_SCALER_GSU_HSTEP(base), hscale);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_VSTEP(vi_cnt, layer), vscale);
+                    SUN8I_SCALER_GSU_VSTEP(base), vscale);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_HPHASE(vi_cnt, layer), hphase);
+                    SUN8I_SCALER_GSU_HPHASE(base), hphase);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_GSU_VPHASE(vi_cnt, layer), vphase);
+                    SUN8I_SCALER_GSU_VPHASE(base), vphase);
        offset = sun8i_ui_scaler_coef_index(hscale) *
                        SUN8I_UI_SCALER_COEFF_COUNT;
        for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
                regmap_write(mixer->engine.regs,
-                            SUN8I_SCALER_GSU_HCOEFF(vi_cnt, layer, i),
+                            SUN8I_SCALER_GSU_HCOEFF(base, i),
                             lan2coefftab16[offset + i]);
 }
index 86295be8be785b411019bba2aba0ece42131c07c..1ef4bd6f27189ff719e2b4fb7f97c1b8a94c524d 100644 (file)
@@ -11,6 +11,9 @@
 
 #include "sun8i_mixer.h"
 
+#define DE2_UI_SCALER_UNIT_SIZE 0x10000
+#define DE3_UI_SCALER_UNIT_SIZE 0x08000
+
 /* this two macros assumes 16 fractional bits which is standard in DRM */
 #define SUN8I_UI_SCALER_SCALE_MIN              1
 #define SUN8I_UI_SCALER_SCALE_MAX              ((1UL << 20) - 1)
 #define SUN8I_UI_SCALER_COEFF_COUNT            16
 #define SUN8I_UI_SCALER_SIZE(w, h)             (((h) - 1) << 16 | ((w) - 1))
 
-#define SUN8I_SCALER_GSU_CTRL(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x0)
-#define SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x40)
-#define SUN8I_SCALER_GSU_INSIZE(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x80)
-#define SUN8I_SCALER_GSU_HSTEP(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x88)
-#define SUN8I_SCALER_GSU_VSTEP(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x8c)
-#define SUN8I_SCALER_GSU_HPHASE(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x90)
-#define SUN8I_SCALER_GSU_VPHASE(vi_cnt, ui_idx) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x98)
-#define SUN8I_SCALER_GSU_HCOEFF(vi_cnt, ui_idx, index) \
-       (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x200 + \
-       0x4 * (index))
+#define SUN8I_SCALER_GSU_CTRL(base)            ((base) + 0x0)
+#define SUN8I_SCALER_GSU_OUTSIZE(base)         ((base) + 0x40)
+#define SUN8I_SCALER_GSU_INSIZE(base)          ((base) + 0x80)
+#define SUN8I_SCALER_GSU_HSTEP(base)           ((base) + 0x88)
+#define SUN8I_SCALER_GSU_VSTEP(base)           ((base) + 0x8c)
+#define SUN8I_SCALER_GSU_HPHASE(base)          ((base) + 0x90)
+#define SUN8I_SCALER_GSU_VPHASE(base)          ((base) + 0x98)
+#define SUN8I_SCALER_GSU_HCOEFF(base, index)   ((base) + 0x200 + 0x4 * (index))
 
 #define SUN8I_SCALER_GSU_CTRL_EN               BIT(0)
 #define SUN8I_SCALER_GSU_CTRL_COEFF_RDY                BIT(4)
index f4fe97813f943f61b061c91604ad542b9446c4f8..87be898f9b7a090cf732e9c9b2187e1986031aaf 100644 (file)
@@ -13,6 +13,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drmP.h>
 
@@ -24,7 +25,10 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
                                  int overlay, bool enable, unsigned int zpos,
                                  unsigned int old_zpos)
 {
-       u32 val;
+       u32 val, bld_base, ch_base;
+
+       bld_base = sun8i_blender_base(mixer);
+       ch_base = sun8i_channel_base(mixer, channel);
 
        DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
                         enable ? "En" : "Dis", channel, overlay);
@@ -35,17 +39,17 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
                val = 0;
 
        regmap_update_bits(mixer->engine.regs,
-                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
                           SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
 
        if (!enable || zpos != old_zpos) {
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_PIPE_CTL,
+                                  SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
                                   SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
                                   0);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_ROUTE,
+                                  SUN8I_MIXER_BLEND_ROUTE(bld_base),
                                   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
                                   0);
        }
@@ -54,12 +58,13 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
                val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_PIPE_CTL, val, val);
+                                  SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+                                  val, val);
 
                val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
 
                regmap_update_bits(mixer->engine.regs,
-                                  SUN8I_MIXER_BLEND_ROUTE,
+                                  SUN8I_MIXER_BLEND_ROUTE(bld_base),
                                   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
                                   val);
        }
@@ -72,6 +77,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
        struct drm_plane_state *state = plane->state;
        const struct drm_format_info *format = state->fb->format;
        u32 src_w, src_h, dst_w, dst_h;
+       u32 bld_base, ch_base;
        u32 outsize, insize;
        u32 hphase, vphase;
        bool subsampled;
@@ -79,6 +85,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
        DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
                         channel, overlay);
 
+       bld_base = sun8i_blender_base(mixer);
+       ch_base = sun8i_channel_base(mixer, channel);
+
        src_w = drm_rect_width(&state->src) >> 16;
        src_h = drm_rect_height(&state->src) >> 16;
        dst_w = drm_rect_width(&state->dst);
@@ -115,10 +124,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                         (state->src.y1 >> 16) & ~(format->vsub - 1));
        DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
+                    SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
                     insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
+                    SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
                     insize);
 
        /*
@@ -149,10 +158,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
                         state->dst.x1, state->dst.y1);
        DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_BLEND_ATTR_COORD(zpos),
+                    SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
                     SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
        regmap_write(mixer->engine.regs,
-                    SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos),
+                    SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
                     outsize);
 
        return 0;
@@ -163,7 +172,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 {
        struct drm_plane_state *state = plane->state;
        const struct de2_fmt_info *fmt_info;
-       u32 val;
+       u32 val, ch_base;
+
+       ch_base = sun8i_channel_base(mixer, channel);
 
        fmt_info = sun8i_mixer_format_info(state->fb->format->format);
        if (!fmt_info) {
@@ -173,7 +184,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 
        val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
        regmap_update_bits(mixer->engine.regs,
-                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
                           SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
 
        if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
@@ -189,9 +200,17 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
                val = 0;
 
        regmap_update_bits(mixer->engine.regs,
-                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+                          SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
                           SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
 
+       /* It seems that YUV formats use global alpha setting. */
+       if (mixer->cfg->is_de3)
+               regmap_update_bits(mixer->engine.regs,
+                                  SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
+                                                                 overlay),
+                                  SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
+                                  SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
+
        return 0;
 }
 
@@ -204,8 +223,11 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
        struct drm_gem_cma_object *gem;
        u32 dx, dy, src_x, src_y;
        dma_addr_t paddr;
+       u32 ch_base;
        int i;
 
+       ch_base = sun8i_channel_base(mixer, channel);
+
        /* Adjust x and y to be dividable by subsampling factor */
        src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
        src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
@@ -235,17 +257,17 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
                DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
                                 i + 1, fb->pitches[i]);
                regmap_write(mixer->engine.regs,
-                            SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
+                            SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
                                                             overlay, i),
-              fb->pitches[i]);
+                            fb->pitches[i]);
 
                DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
                                 i + 1, &paddr);
 
                regmap_write(mixer->engine.regs,
-                            SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
+                            SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
                                                                 overlay, i),
-              lower_32_bits(paddr));
+                            lower_32_bits(paddr));
        }
 
        return 0;
@@ -315,6 +337,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
 }
 
 static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
+       .prepare_fb     = drm_gem_fb_prepare_fb,
        .atomic_check   = sun8i_vi_layer_atomic_check,
        .atomic_disable = sun8i_vi_layer_atomic_disable,
        .atomic_update  = sun8i_vi_layer_atomic_update,
index 6996627a0a76837553f7a8de6de8fe41751c3504..8a5e6d01c85d26a0be54c11cc696ff129b921a37 100644 (file)
 
 #include <drm/drm_plane.h>
 
-#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch, layer) \
-               (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x0)
-#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch, layer) \
-               (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x4)
-#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(ch, layer) \
-               (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x8)
-#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch, layer, plane) \
-               (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0xc + 4 * (plane))
-#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch, layer, plane) \
-               (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x18 + 4 * (plane))
-#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch)       (0x2000 + 0x1000 * (ch) + 0xe8)
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, layer) \
+               ((base) + 0x30 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(base, layer) \
+               ((base) + 0x30 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(base, layer) \
+               ((base) + 0x30 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(base, layer, plane) \
+               ((base) + 0x30 * (layer) + 0xc + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(base, layer, plane) \
+               ((base) + 0x30 * (layer) + 0x18 + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(base) \
+               ((base) + 0xe8)
 
 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN              BIT(0)
 /* RGB mode should be set for RGB formats and cleared for YCbCr */
 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE                BIT(15)
 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET    8
 #define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK      GENMASK(12, 8)
+#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK     GENMASK(31, 24)
+#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(x)       ((x) << 24)
 
 struct sun8i_mixer;
 
index d3f1acb234b7ac216fe295a26eaee4cb52a1b81f..7ba75011adf9fa3a8a95e4ace1b06144c16a5640 100644 (file)
@@ -833,6 +833,16 @@ static const u32 bicubic4coefftab32[480] = {
        0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
 };
 
+static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
+{
+       if (mixer->cfg->is_de3)
+               return DE3_VI_SCALER_UNIT_BASE +
+                      DE3_VI_SCALER_UNIT_SIZE * channel;
+       else
+               return DE2_VI_SCALER_UNIT_BASE +
+                      DE2_VI_SCALER_UNIT_SIZE * channel;
+}
+
 static int sun8i_vi_scaler_coef_index(unsigned int step)
 {
        unsigned int scale, int_part, float_part;
@@ -857,7 +867,7 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
        }
 }
 
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
+static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
                                      u32 hstep, u32 vstep,
                                      const struct drm_format_info *format)
 {
@@ -877,29 +887,31 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
        offset = sun8i_vi_scaler_coef_index(hstep) *
                        SUN8I_VI_SCALER_COEFF_COUNT;
        for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-               regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
                             lan3coefftab32_left[offset + i]);
-               regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
                             lan3coefftab32_right[offset + i]);
-               regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
                             ch_left[offset + i]);
-               regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
                             ch_right[offset + i]);
        }
 
        offset = sun8i_vi_scaler_coef_index(hstep) *
                        SUN8I_VI_SCALER_COEFF_COUNT;
        for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-               regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
                             lan2coefftab32[offset + i]);
-               regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(layer, i),
+               regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
                             cy[offset + i]);
        }
 }
 
 void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
 {
-       u32 val;
+       u32 val, base;
+
+       base = sun8i_vi_scaler_base(mixer, layer);
 
        if (enable)
                val = SUN8I_SCALER_VSU_CTRL_EN |
@@ -907,7 +919,8 @@ void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
        else
                val = 0;
 
-       regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(layer), val);
+       regmap_write(mixer->engine.regs,
+                    SUN8I_SCALER_VSU_CTRL(base), val);
 }
 
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -917,6 +930,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
 {
        u32 chphase, cvphase;
        u32 insize, outsize;
+       u32 base;
+
+       base = sun8i_vi_scaler_base(mixer, layer);
 
        hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
        vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
@@ -940,32 +956,44 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
                cvphase = vphase;
        }
 
+       if (mixer->cfg->is_de3) {
+               u32 val;
+
+               if (format->hsub == 1 && format->vsub == 1)
+                       val = SUN50I_SCALER_VSU_SCALE_MODE_UI;
+               else
+                       val = SUN50I_SCALER_VSU_SCALE_MODE_NORMAL;
+
+               regmap_write(mixer->engine.regs,
+                            SUN50I_SCALER_VSU_SCALE_MODE(base), val);
+       }
+
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_OUTSIZE(layer), outsize);
+                    SUN8I_SCALER_VSU_OUTSIZE(base), outsize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_YINSIZE(layer), insize);
+                    SUN8I_SCALER_VSU_YINSIZE(base), insize);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_YHSTEP(layer), hscale);
+                    SUN8I_SCALER_VSU_YHSTEP(base), hscale);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_YVSTEP(layer), vscale);
+                    SUN8I_SCALER_VSU_YVSTEP(base), vscale);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_YHPHASE(layer), hphase);
+                    SUN8I_SCALER_VSU_YHPHASE(base), hphase);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_YVPHASE(layer), vphase);
+                    SUN8I_SCALER_VSU_YVPHASE(base), vphase);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_CINSIZE(layer),
+                    SUN8I_SCALER_VSU_CINSIZE(base),
                     SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
                                          src_h / format->vsub));
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_CHSTEP(layer),
+                    SUN8I_SCALER_VSU_CHSTEP(base),
                     hscale / format->hsub);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_CVSTEP(layer),
+                    SUN8I_SCALER_VSU_CVSTEP(base),
                     vscale / format->vsub);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_CHPHASE(layer), chphase);
+                    SUN8I_SCALER_VSU_CHPHASE(base), chphase);
        regmap_write(mixer->engine.regs,
-                    SUN8I_SCALER_VSU_CVPHASE(layer), cvphase);
-       sun8i_vi_scaler_set_coeff(mixer->engine.regs, layer,
+                    SUN8I_SCALER_VSU_CVPHASE(base), cvphase);
+       sun8i_vi_scaler_set_coeff(mixer->engine.regs, base,
                                  hscale, vscale, format);
 }
index a595ab643a5a669803ac48348e1247b07b3d4160..68f6593b369ab35c292bcae2c59da99e4bc38af5 100644 (file)
 #include <drm/drm_fourcc.h>
 #include "sun8i_mixer.h"
 
+#define DE2_VI_SCALER_UNIT_BASE 0x20000
+#define DE2_VI_SCALER_UNIT_SIZE 0x20000
+
+#define DE3_VI_SCALER_UNIT_BASE 0x20000
+#define DE3_VI_SCALER_UNIT_SIZE 0x08000
+
 /* this two macros assumes 16 fractional bits which is standard in DRM */
 #define SUN8I_VI_SCALER_SCALE_MIN              1
 #define SUN8I_VI_SCALER_SCALE_MAX              ((1UL << 20) - 1)
 #define SUN8I_VI_SCALER_COEFF_COUNT            32
 #define SUN8I_VI_SCALER_SIZE(w, h)             (((h) - 1) << 16 | ((w) - 1))
 
-#define SUN8I_SCALER_VSU_CTRL(ch)      (0x20000 + 0x20000 * (ch) + 0x0)
-#define SUN8I_SCALER_VSU_OUTSIZE(ch)   (0x20000 + 0x20000 * (ch) + 0x40)
-#define SUN8I_SCALER_VSU_YINSIZE(ch)   (0x20000 + 0x20000 * (ch) + 0x80)
-#define SUN8I_SCALER_VSU_YHSTEP(ch)    (0x20000 + 0x20000 * (ch) + 0x88)
-#define SUN8I_SCALER_VSU_YVSTEP(ch)    (0x20000 + 0x20000 * (ch) + 0x8c)
-#define SUN8I_SCALER_VSU_YHPHASE(ch)   (0x20000 + 0x20000 * (ch) + 0x90)
-#define SUN8I_SCALER_VSU_YVPHASE(ch)   (0x20000 + 0x20000 * (ch) + 0x98)
-#define SUN8I_SCALER_VSU_CINSIZE(ch)   (0x20000 + 0x20000 * (ch) + 0xc0)
-#define SUN8I_SCALER_VSU_CHSTEP(ch)    (0x20000 + 0x20000 * (ch) + 0xc8)
-#define SUN8I_SCALER_VSU_CVSTEP(ch)    (0x20000 + 0x20000 * (ch) + 0xcc)
-#define SUN8I_SCALER_VSU_CHPHASE(ch)   (0x20000 + 0x20000 * (ch) + 0xd0)
-#define SUN8I_SCALER_VSU_CVPHASE(ch)   (0x20000 + 0x20000 * (ch) + 0xd8)
-#define SUN8I_SCALER_VSU_YHCOEFF0(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x200 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_YHCOEFF1(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x300 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_YVCOEFF(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x400 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CHCOEFF0(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x600 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CHCOEFF1(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x700 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CVCOEFF(ch, i) \
-       (0x20000 + 0x20000 * (ch) + 0x800 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CTRL(base)            ((base) + 0x0)
+#define SUN50I_SCALER_VSU_SCALE_MODE(base)             ((base) + 0x10)
+#define SUN50I_SCALER_VSU_DIR_THR(base)                ((base) + 0x20)
+#define SUN50I_SCALER_VSU_EDGE_THR(base)               ((base) + 0x24)
+#define SUN50I_SCALER_VSU_EDSCL_CTRL(base)             ((base) + 0x28)
+#define SUN50I_SCALER_VSU_ANGLE_THR(base)              ((base) + 0x2c)
+#define SUN8I_SCALER_VSU_OUTSIZE(base)         ((base) + 0x40)
+#define SUN8I_SCALER_VSU_YINSIZE(base)         ((base) + 0x80)
+#define SUN8I_SCALER_VSU_YHSTEP(base)          ((base) + 0x88)
+#define SUN8I_SCALER_VSU_YVSTEP(base)          ((base) + 0x8c)
+#define SUN8I_SCALER_VSU_YHPHASE(base)         ((base) + 0x90)
+#define SUN8I_SCALER_VSU_YVPHASE(base)         ((base) + 0x98)
+#define SUN8I_SCALER_VSU_CINSIZE(base)         ((base) + 0xc0)
+#define SUN8I_SCALER_VSU_CHSTEP(base)          ((base) + 0xc8)
+#define SUN8I_SCALER_VSU_CVSTEP(base)          ((base) + 0xcc)
+#define SUN8I_SCALER_VSU_CHPHASE(base)         ((base) + 0xd0)
+#define SUN8I_SCALER_VSU_CVPHASE(base)         ((base) + 0xd8)
+#define SUN8I_SCALER_VSU_YHCOEFF0(base, i)     ((base) + 0x200 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YHCOEFF1(base, i)     ((base) + 0x300 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YVCOEFF(base, i)      ((base) + 0x400 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF0(base, i)     ((base) + 0x600 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF1(base, i)     ((base) + 0x700 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CVCOEFF(base, i)      ((base) + 0x800 + 0x4 * (i))
 
 #define SUN8I_SCALER_VSU_CTRL_EN               BIT(0)
 #define SUN8I_SCALER_VSU_CTRL_COEFF_RDY                BIT(4)
 
+#define SUN50I_SCALER_VSU_SUB_ZERO_DIR_THR(x)  (((x) << 24) & 0xFF)
+#define SUN50I_SCALER_VSU_ZERO_DIR_THR(x)              (((x) << 16) & 0xFF)
+#define SUN50I_SCALER_VSU_HORZ_DIR_THR(x)              (((x) << 8) & 0xFF)
+#define SUN50I_SCALER_VSU_VERT_DIR_THR(x)              ((x) & 0xFF)
+
+#define SUN50I_SCALER_VSU_SCALE_MODE_UI                0
+#define SUN50I_SCALER_VSU_SCALE_MODE_NORMAL    1
+#define SUN50I_SCALER_VSU_SCALE_MODE_ED_SCALE  2
+
+#define SUN50I_SCALER_VSU_EDGE_SHIFT(x)                (((x) << 16) & 0xF)
+#define SUN50I_SCALER_VSU_EDGE_OFFSET(x)               ((x) & 0xFF)
+
+#define SUN50I_SCALER_VSU_ANGLE_SHIFT(x)               (((x) << 16) & 0xF)
+#define SUN50I_SCALER_VSU_ANGLE_OFFSET(x)              ((x) & 0xFF)
+
 void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
                           u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
index f80e82e164759457ae02f85ecb7354930c0f344f..607a6ea17ecc534b0f8433b63fff0383f1bde190 100644 (file)
@@ -1978,6 +1978,23 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static bool tegra_dc_has_window_groups(struct tegra_dc *dc)
+{
+       unsigned int i;
+
+       if (!dc->soc->wgrps)
+               return true;
+
+       for (i = 0; i < dc->soc->num_wgrps; i++) {
+               const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];
+
+               if (wgrp->dc == dc->pipe && wgrp->num_windows > 0)
+                       return true;
+       }
+
+       return false;
+}
+
 static int tegra_dc_init(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
@@ -1993,22 +2010,8 @@ static int tegra_dc_init(struct host1x_client *client)
         * assign a primary plane to them, which in turn will cause KMS to
         * crash.
         */
-       if (dc->soc->wgrps) {
-               bool has_wgrps = false;
-               unsigned int i;
-
-               for (i = 0; i < dc->soc->num_wgrps; i++) {
-                       const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];
-
-                       if (wgrp->dc == dc->pipe && wgrp->num_windows > 0) {
-                               has_wgrps = true;
-                               break;
-                       }
-               }
-
-               if (!has_wgrps)
-                       return 0;
-       }
+       if (!tegra_dc_has_window_groups(dc))
+               return 0;
 
        dc->syncpt = host1x_syncpt_request(client, flags);
        if (!dc->syncpt)
@@ -2094,6 +2097,9 @@ static int tegra_dc_exit(struct host1x_client *client)
        struct tegra_dc *dc = host1x_client_to_dc(client);
        int err;
 
+       if (!tegra_dc_has_window_groups(dc))
+               return 0;
+
        devm_free_irq(dc->dev, dc->irq, dc);
 
        err = tegra_dc_rgb_exit(dc);
index 65ea4988b332e2d121ddd482c79d70f7ecc57ac5..4b70ce664c4185e36f8e173dfd43353eee404fa5 100644 (file)
@@ -1274,6 +1274,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra194-display", },
        { .compatible = "nvidia,tegra194-dc", },
        { .compatible = "nvidia,tegra194-sor", },
+       { .compatible = "nvidia,tegra194-vic", },
        { /* sentinel */ }
 };
 
index f685e72949d16b59c74cff8a230a08871eff747c..352d05feabb09507db689f8106fcef00705c76c3 100644 (file)
@@ -141,9 +141,9 @@ int falcon_load_firmware(struct falcon *falcon)
        /* allocate iova space for the firmware */
        falcon->firmware.vaddr = falcon->ops->alloc(falcon, firmware->size,
                                                    &falcon->firmware.paddr);
-       if (!falcon->firmware.vaddr) {
-               dev_err(falcon->dev, "dma memory mapping failed\n");
-               return -ENOMEM;
+       if (IS_ERR(falcon->firmware.vaddr)) {
+               dev_err(falcon->dev, "DMA memory mapping failed\n");
+               return PTR_ERR(falcon->firmware.vaddr);
        }
 
        /* copy firmware image into local area. this also ensures endianness */
@@ -197,11 +197,19 @@ void falcon_exit(struct falcon *falcon)
 int falcon_boot(struct falcon *falcon)
 {
        unsigned long offset;
+       u32 value;
        int err;
 
        if (!falcon->firmware.vaddr)
                return -EINVAL;
 
+       err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value,
+                                (value & (FALCON_DMACTL_IMEM_SCRUBBING |
+                                          FALCON_DMACTL_DMEM_SCRUBBING)) == 0,
+                                10, 10000);
+       if (err < 0)
+               return err;
+
        falcon_writel(falcon, 0, FALCON_DMACTL);
 
        /* setup the address of the binary data so Falcon can access it later */
index 6112d90429799582098c01a3282fc571aa665517..922a48d5a483fbc217197e09984d9d1c7c7c2ed1 100644 (file)
@@ -742,7 +742,9 @@ static const struct host1x_client_ops tegra_display_hub_ops = {
 
 static int tegra_display_hub_probe(struct platform_device *pdev)
 {
+       struct device_node *child = NULL;
        struct tegra_display_hub *hub;
+       struct clk *clk;
        unsigned int i;
        int err;
 
@@ -801,6 +803,34 @@ static int tegra_display_hub_probe(struct platform_device *pdev)
                        return err;
        }
 
+       hub->num_heads = of_get_child_count(pdev->dev.of_node);
+
+       hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk),
+                                     GFP_KERNEL);
+       if (!hub->clk_heads)
+               return -ENOMEM;
+
+       for (i = 0; i < hub->num_heads; i++) {
+               child = of_get_next_child(pdev->dev.of_node, child);
+               if (!child) {
+                       dev_err(&pdev->dev, "failed to find node for head %u\n",
+                               i);
+                       return -ENODEV;
+               }
+
+               clk = devm_get_clk_from_child(&pdev->dev, child, "dc");
+               if (IS_ERR(clk)) {
+                       dev_err(&pdev->dev, "failed to get clock for head %u\n",
+                               i);
+                       of_node_put(child);
+                       return PTR_ERR(clk);
+               }
+
+               hub->clk_heads[i] = clk;
+       }
+
+       of_node_put(child);
+
        /* XXX: enable clock across reset? */
        err = reset_control_assert(hub->rst);
        if (err < 0)
@@ -840,12 +870,16 @@ static int tegra_display_hub_remove(struct platform_device *pdev)
 static int __maybe_unused tegra_display_hub_suspend(struct device *dev)
 {
        struct tegra_display_hub *hub = dev_get_drvdata(dev);
+       unsigned int i = hub->num_heads;
        int err;
 
        err = reset_control_assert(hub->rst);
        if (err < 0)
                return err;
 
+       while (i--)
+               clk_disable_unprepare(hub->clk_heads[i]);
+
        clk_disable_unprepare(hub->clk_hub);
        clk_disable_unprepare(hub->clk_dsc);
        clk_disable_unprepare(hub->clk_disp);
@@ -856,6 +890,7 @@ static int __maybe_unused tegra_display_hub_suspend(struct device *dev)
 static int __maybe_unused tegra_display_hub_resume(struct device *dev)
 {
        struct tegra_display_hub *hub = dev_get_drvdata(dev);
+       unsigned int i;
        int err;
 
        err = clk_prepare_enable(hub->clk_disp);
@@ -870,13 +905,22 @@ static int __maybe_unused tegra_display_hub_resume(struct device *dev)
        if (err < 0)
                goto disable_dsc;
 
+       for (i = 0; i < hub->num_heads; i++) {
+               err = clk_prepare_enable(hub->clk_heads[i]);
+               if (err < 0)
+                       goto disable_heads;
+       }
+
        err = reset_control_deassert(hub->rst);
        if (err < 0)
-               goto disable_hub;
+               goto disable_heads;
 
        return 0;
 
-disable_hub:
+disable_heads:
+       while (i--)
+               clk_disable_unprepare(hub->clk_heads[i]);
+
        clk_disable_unprepare(hub->clk_hub);
 disable_dsc:
        clk_disable_unprepare(hub->clk_dsc);
index 6696a85fc1f204389f2973a6839e4eddca06a1d7..479087c0705a78a65acadc6c1bbe82cbe377d1ca 100644 (file)
@@ -49,6 +49,9 @@ struct tegra_display_hub {
        struct clk *clk_hub;
        struct reset_control *rst;
 
+       unsigned int num_heads;
+       struct clk **clk_heads;
+
        const struct tegra_display_hub_soc *soc;
        struct tegra_windowgroup *wgrps;
 };
index b129da2e5afd5ede520bb60e442cc18fb5624d46..ef8692b7075ab0f82262b0aae3cb6c57f160d160 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <soc/tegra/pmc.h>
 
+#include <sound/hda_verbs.h>
+
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_panel.h>
 #include "sor.h"
 #include "trace.h"
 
-/*
- * XXX Remove this after the commit adding it to soc/tegra/pmc.h has been
- * merged. Having this around after the commit is merged should be safe since
- * the preprocessor will effectively replace all occurrences and therefore no
- * duplicate will be defined.
- */
-#define TEGRA_IO_PAD_HDMI_DP0 26
-
 #define SOR_REKEY 0x38
 
 struct tegra_sor_hdmi_settings {
@@ -407,6 +401,7 @@ struct tegra_sor {
        const struct tegra_sor_soc *soc;
        void __iomem *regs;
        unsigned int index;
+       unsigned int irq;
 
        struct reset_control *rst;
        struct clk *clk_parent;
@@ -433,6 +428,11 @@ struct tegra_sor {
 
        struct delayed_work scdc;
        bool scdc_enabled;
+
+       struct {
+               unsigned int sample_rate;
+               unsigned int channels;
+       } audio;
 };
 
 struct tegra_sor_state {
@@ -2139,6 +2139,144 @@ tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor,
        return 0;
 }
 
+static void tegra_sor_write_eld(struct tegra_sor *sor)
+{
+       size_t length = drm_eld_size(sor->output.connector.eld), i;
+
+       for (i = 0; i < length; i++)
+               tegra_sor_writel(sor, i << 8 | sor->output.connector.eld[i],
+                                SOR_AUDIO_HDA_ELD_BUFWR);
+
+       /*
+        * The HDA codec will always report an ELD buffer size of 96 bytes and
+        * the HDA codec driver will check that each byte read from the buffer
+        * is valid. Therefore every byte must be written, even if no 96 bytes
+        * were parsed from EDID.
+        */
+       for (i = length; i < 96; i++)
+               tegra_sor_writel(sor, i << 8 | 0, SOR_AUDIO_HDA_ELD_BUFWR);
+}
+
+static void tegra_sor_audio_prepare(struct tegra_sor *sor)
+{
+       u32 value;
+
+       tegra_sor_write_eld(sor);
+
+       value = SOR_AUDIO_HDA_PRESENSE_ELDV | SOR_AUDIO_HDA_PRESENSE_PD;
+       tegra_sor_writel(sor, value, SOR_AUDIO_HDA_PRESENSE);
+}
+
+static void tegra_sor_audio_unprepare(struct tegra_sor *sor)
+{
+       tegra_sor_writel(sor, 0, SOR_AUDIO_HDA_PRESENSE);
+}
+
+static int tegra_sor_hdmi_enable_audio_infoframe(struct tegra_sor *sor)
+{
+       u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
+       struct hdmi_audio_infoframe frame;
+       u32 value;
+       int err;
+
+       err = hdmi_audio_infoframe_init(&frame);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to setup audio infoframe: %d\n", err);
+               return err;
+       }
+
+       frame.channels = sor->audio.channels;
+
+       err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+       if (err < 0) {
+               dev_err(sor->dev, "failed to pack audio infoframe: %d\n", err);
+               return err;
+       }
+
+       tegra_sor_hdmi_write_infopack(sor, buffer, err);
+
+       value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
+       value |= INFOFRAME_CTRL_CHECKSUM_ENABLE;
+       value |= INFOFRAME_CTRL_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
+
+       return 0;
+}
+
+static void tegra_sor_hdmi_audio_enable(struct tegra_sor *sor)
+{
+       u32 value;
+
+       value = tegra_sor_readl(sor, SOR_AUDIO_CNTRL);
+
+       /* select HDA audio input */
+       value &= ~SOR_AUDIO_CNTRL_SOURCE_SELECT(SOURCE_SELECT_MASK);
+       value |= SOR_AUDIO_CNTRL_SOURCE_SELECT(SOURCE_SELECT_HDA);
+
+       /* inject null samples */
+       if (sor->audio.channels != 2)
+               value &= ~SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
+       else
+               value |= SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
+
+       value |= SOR_AUDIO_CNTRL_AFIFO_FLUSH;
+
+       tegra_sor_writel(sor, value, SOR_AUDIO_CNTRL);
+
+       /* enable advertising HBR capability */
+       tegra_sor_writel(sor, SOR_AUDIO_SPARE_HBR_ENABLE, SOR_AUDIO_SPARE);
+
+       tegra_sor_writel(sor, 0, SOR_HDMI_ACR_CTRL);
+
+       value = SOR_HDMI_SPARE_ACR_PRIORITY_HIGH |
+               SOR_HDMI_SPARE_CTS_RESET(1) |
+               SOR_HDMI_SPARE_HW_CTS_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_SPARE);
+
+       /* enable HW CTS */
+       value = SOR_HDMI_ACR_SUBPACK_LOW_SB1(0);
+       tegra_sor_writel(sor, value, SOR_HDMI_ACR_0441_SUBPACK_LOW);
+
+       /* allow packet to be sent */
+       value = SOR_HDMI_ACR_SUBPACK_HIGH_ENABLE;
+       tegra_sor_writel(sor, value, SOR_HDMI_ACR_0441_SUBPACK_HIGH);
+
+       /* reset N counter and enable lookup */
+       value = SOR_HDMI_AUDIO_N_RESET | SOR_HDMI_AUDIO_N_LOOKUP;
+       tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_N);
+
+       value = (24000 * 4096) / (128 * sor->audio.sample_rate / 1000);
+       tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0320);
+       tegra_sor_writel(sor, 4096, SOR_AUDIO_NVAL_0320);
+
+       tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_0441);
+       tegra_sor_writel(sor, 4704, SOR_AUDIO_NVAL_0441);
+
+       tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_0882);
+       tegra_sor_writel(sor, 9408, SOR_AUDIO_NVAL_0882);
+
+       tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_1764);
+       tegra_sor_writel(sor, 18816, SOR_AUDIO_NVAL_1764);
+
+       value = (24000 * 6144) / (128 * sor->audio.sample_rate / 1000);
+       tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0480);
+       tegra_sor_writel(sor, 6144, SOR_AUDIO_NVAL_0480);
+
+       value = (24000 * 12288) / (128 * sor->audio.sample_rate / 1000);
+       tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0960);
+       tegra_sor_writel(sor, 12288, SOR_AUDIO_NVAL_0960);
+
+       value = (24000 * 24576) / (128 * sor->audio.sample_rate / 1000);
+       tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_1920);
+       tegra_sor_writel(sor, 24576, SOR_AUDIO_NVAL_1920);
+
+       value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_N);
+       value &= ~SOR_HDMI_AUDIO_N_RESET;
+       tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_N);
+
+       tegra_sor_hdmi_enable_audio_infoframe(sor);
+}
+
 static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor)
 {
        u32 value;
@@ -2148,6 +2286,11 @@ static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor)
        tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
 }
 
+static void tegra_sor_hdmi_audio_disable(struct tegra_sor *sor)
+{
+       tegra_sor_hdmi_disable_audio_infoframe(sor);
+}
+
 static struct tegra_sor_hdmi_settings *
 tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency)
 {
@@ -2243,6 +2386,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
        u32 value;
        int err;
 
+       tegra_sor_audio_unprepare(sor);
        tegra_sor_hdmi_scdc_stop(sor);
 
        err = tegra_sor_detach(sor);
@@ -2651,6 +2795,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
                dev_err(sor->dev, "failed to wakeup SOR: %d\n", err);
 
        tegra_sor_hdmi_scdc_start(sor);
+       tegra_sor_audio_prepare(sor);
 }
 
 static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = {
@@ -2666,6 +2811,7 @@ static int tegra_sor_init(struct host1x_client *client)
        struct tegra_sor *sor = host1x_client_to_sor(client);
        int connector = DRM_MODE_CONNECTOR_Unknown;
        int encoder = DRM_MODE_ENCODER_NONE;
+       u32 value;
        int err;
 
        if (!sor->aux) {
@@ -2759,6 +2905,15 @@ static int tegra_sor_init(struct host1x_client *client)
        if (err < 0)
                return err;
 
+       /*
+        * Enable and unmask the HDA codec SCRATCH0 register interrupt. This
+        * is used for interoperability between the HDA codec driver and the
+        * HDMI/DP driver.
+        */
+       value = SOR_INT_CODEC_SCRATCH1 | SOR_INT_CODEC_SCRATCH0;
+       tegra_sor_writel(sor, value, SOR_INT_ENABLE);
+       tegra_sor_writel(sor, value, SOR_INT_MASK);
+
        return 0;
 }
 
@@ -2767,6 +2922,9 @@ static int tegra_sor_exit(struct host1x_client *client)
        struct tegra_sor *sor = host1x_client_to_sor(client);
        int err;
 
+       tegra_sor_writel(sor, 0, SOR_INT_MASK);
+       tegra_sor_writel(sor, 0, SOR_INT_ENABLE);
+
        tegra_output_exit(&sor->output);
 
        if (sor->aux) {
@@ -3037,6 +3195,54 @@ static int tegra_sor_parse_dt(struct tegra_sor *sor)
        return 0;
 }
 
+static void tegra_hda_parse_format(unsigned int format, unsigned int *rate,
+                                  unsigned int *channels)
+{
+       unsigned int mul, div;
+
+       if (format & AC_FMT_BASE_44K)
+               *rate = 44100;
+       else
+               *rate = 48000;
+
+       mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT;
+       div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT;
+
+       *rate = *rate * (mul + 1) / (div + 1);
+
+       *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT;
+}
+
+static irqreturn_t tegra_sor_irq(int irq, void *data)
+{
+       struct tegra_sor *sor = data;
+       u32 value;
+
+       value = tegra_sor_readl(sor, SOR_INT_STATUS);
+       tegra_sor_writel(sor, value, SOR_INT_STATUS);
+
+       if (value & SOR_INT_CODEC_SCRATCH0) {
+               value = tegra_sor_readl(sor, SOR_AUDIO_HDA_CODEC_SCRATCH0);
+
+               if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) {
+                       unsigned int format, sample_rate, channels;
+
+                       format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK;
+
+                       tegra_hda_parse_format(format, &sample_rate, &channels);
+
+                       sor->audio.sample_rate = sample_rate;
+                       sor->audio.channels = channels;
+
+                       tegra_sor_hdmi_audio_enable(sor);
+               } else {
+                       tegra_sor_hdmi_audio_disable(sor);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int tegra_sor_probe(struct platform_device *pdev)
 {
        struct device_node *np;
@@ -3119,14 +3325,38 @@ static int tegra_sor_probe(struct platform_device *pdev)
                goto remove;
        }
 
-       if (!pdev->dev.pm_domain) {
-               sor->rst = devm_reset_control_get(&pdev->dev, "sor");
-               if (IS_ERR(sor->rst)) {
-                       err = PTR_ERR(sor->rst);
+       err = platform_get_irq(pdev, 0);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to get IRQ: %d\n", err);
+               goto remove;
+       }
+
+       sor->irq = err;
+
+       err = devm_request_irq(sor->dev, sor->irq, tegra_sor_irq, 0,
+                              dev_name(sor->dev), sor);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
+               goto remove;
+       }
+
+       sor->rst = devm_reset_control_get(&pdev->dev, "sor");
+       if (IS_ERR(sor->rst)) {
+               err = PTR_ERR(sor->rst);
+
+               if (err != -EBUSY || WARN_ON(!pdev->dev.pm_domain)) {
                        dev_err(&pdev->dev, "failed to get reset control: %d\n",
                                err);
                        goto remove;
                }
+
+               /*
+                * At this point, the reset control is most likely being used
+                * by the generic power domain implementation. With any luck
+                * the power domain will have taken care of resetting the SOR
+                * and we don't have to do anything.
+                */
+               sor->rst = NULL;
        }
 
        sor->clk = devm_clk_get(&pdev->dev, NULL);
index fb0854d92a2790f6390bb5ec6fd79dbacea114e6..13f7e68bec42f35527f7b5a5576e3a74074ed367 100644 (file)
 #define  INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
 #define  INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
 
+#define SOR_HDMI_ACR_CTRL 0xb1
+
+#define SOR_HDMI_ACR_0320_SUBPACK_LOW 0xb2
+#define  SOR_HDMI_ACR_SUBPACK_LOW_SB1(x) (((x) & 0xff) << 24)
+
+#define SOR_HDMI_ACR_0320_SUBPACK_HIGH 0xb3
+#define  SOR_HDMI_ACR_SUBPACK_HIGH_ENABLE (1 << 31)
+
+#define SOR_HDMI_ACR_0441_SUBPACK_LOW 0xb4
+#define SOR_HDMI_ACR_0441_SUBPACK_HIGH 0xb5
+
 #define SOR_HDMI_CTRL 0xc0
 #define  SOR_HDMI_CTRL_ENABLE (1 << 30)
 #define  SOR_HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
 #define  SOR_HDMI_CTRL_AUDIO_LAYOUT (1 << 10)
 #define  SOR_HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
 
+#define SOR_HDMI_SPARE 0xcb
+#define  SOR_HDMI_SPARE_ACR_PRIORITY_HIGH (1 << 31)
+#define  SOR_HDMI_SPARE_CTS_RESET(x) (((x) & 0x7) << 16)
+#define  SOR_HDMI_SPARE_HW_CTS_ENABLE (1 << 0)
+
 #define SOR_REFCLK 0xe6
 #define  SOR_REFCLK_DIV_INT(x) ((((x) >> 2) & 0xff) << 8)
 #define  SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6)
 #define  SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED (1 << 1)
 #define  SOR_INPUT_CONTROL_HDMI_SRC_SELECT(x) (((x) & 0x1) << 0)
 
+#define SOR_AUDIO_CNTRL 0xfc
+#define  SOR_AUDIO_CNTRL_INJECT_NULLSMPL (1 << 29)
+#define  SOR_AUDIO_CNTRL_SOURCE_SELECT(x) (((x) & 0x3) << 20)
+#define   SOURCE_SELECT_MASK 0x3
+#define   SOURCE_SELECT_HDA 0x2
+#define   SOURCE_SELECT_SPDIF 0x1
+#define   SOURCE_SELECT_AUTO 0x0
+#define  SOR_AUDIO_CNTRL_AFIFO_FLUSH (1 << 12)
+
+#define SOR_AUDIO_SPARE 0xfe
+#define  SOR_AUDIO_SPARE_HBR_ENABLE (1 << 27)
+
+#define SOR_AUDIO_NVAL_0320 0xff
+#define SOR_AUDIO_NVAL_0441 0x100
+#define SOR_AUDIO_NVAL_0882 0x101
+#define SOR_AUDIO_NVAL_1764 0x102
+#define SOR_AUDIO_NVAL_0480 0x103
+#define SOR_AUDIO_NVAL_0960 0x104
+#define SOR_AUDIO_NVAL_1920 0x105
+
+#define SOR_AUDIO_HDA_CODEC_SCRATCH0 0x10a
+#define  SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID (1 << 30)
+#define  SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK 0xffff
+
+#define SOR_AUDIO_HDA_ELD_BUFWR 0x10c
+#define  SOR_AUDIO_HDA_ELD_BUFWR_INDEX(x) (((x) & 0xff) << 8)
+#define  SOR_AUDIO_HDA_ELD_BUFWR_DATA(x) (((x) & 0xff) << 0)
+
+#define SOR_AUDIO_HDA_PRESENSE 0x10d
+#define  SOR_AUDIO_HDA_PRESENSE_ELDV (1 << 1)
+#define  SOR_AUDIO_HDA_PRESENSE_PD (1 << 0)
+
+#define SOR_AUDIO_AVAL_0320 0x10f
+#define SOR_AUDIO_AVAL_0441 0x110
+#define SOR_AUDIO_AVAL_0882 0x111
+#define SOR_AUDIO_AVAL_1764 0x112
+#define SOR_AUDIO_AVAL_0480 0x113
+#define SOR_AUDIO_AVAL_0960 0x114
+#define SOR_AUDIO_AVAL_1920 0x115
+
+#define SOR_INT_STATUS 0x11c
+#define  SOR_INT_CODEC_CP_REQUEST (1 << 2)
+#define  SOR_INT_CODEC_SCRATCH1 (1 << 1)
+#define  SOR_INT_CODEC_SCRATCH0 (1 << 0)
+
+#define SOR_INT_MASK 0x11d
+#define SOR_INT_ENABLE 0x11e
+
 #define SOR_HDMI_VSI_INFOFRAME_CTRL 0x123
 #define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124
 #define SOR_HDMI_VSI_INFOFRAME_HEADER 0x125
 
+#define SOR_HDMI_AUDIO_N 0x13c
+#define SOR_HDMI_AUDIO_N_LOOKUP (1 << 28)
+#define SOR_HDMI_AUDIO_N_RESET (1 << 20)
+
 #define SOR_HDMI2_CTRL 0x13e
 #define  SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4 (1 << 1)
 #define  SOR_HDMI2_CTRL_SCRAMBLE (1 << 0)
index 9f657a63b0bb4a59943c436f3fece4efc460b074..d47983deb1cff6ecd5fee2be06b59091c16115d6 100644 (file)
@@ -38,6 +38,7 @@ struct vic {
        struct iommu_domain *domain;
        struct device *dev;
        struct clk *clk;
+       struct reset_control *rst;
 
        /* Platform configuration */
        const struct vic_config *config;
@@ -56,13 +57,37 @@ static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
 static int vic_runtime_resume(struct device *dev)
 {
        struct vic *vic = dev_get_drvdata(dev);
+       int err;
+
+       err = clk_prepare_enable(vic->clk);
+       if (err < 0)
+               return err;
+
+       usleep_range(10, 20);
+
+       err = reset_control_deassert(vic->rst);
+       if (err < 0)
+               goto disable;
+
+       usleep_range(10, 20);
+
+       return 0;
 
-       return clk_prepare_enable(vic->clk);
+disable:
+       clk_disable_unprepare(vic->clk);
+       return err;
 }
 
 static int vic_runtime_suspend(struct device *dev)
 {
        struct vic *vic = dev_get_drvdata(dev);
+       int err;
+
+       err = reset_control_assert(vic->rst);
+       if (err < 0)
+               return err;
+
+       usleep_range(2000, 4000);
 
        clk_disable_unprepare(vic->clk);
 
@@ -282,10 +307,18 @@ static const struct vic_config vic_t186_config = {
        .version = 0x18,
 };
 
+#define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
+
+static const struct vic_config vic_t194_config = {
+       .firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
+       .version = 0x19,
+};
+
 static const struct of_device_id vic_match[] = {
        { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
        { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
        { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
+       { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
        { },
 };
 
@@ -323,6 +356,14 @@ static int vic_probe(struct platform_device *pdev)
                return PTR_ERR(vic->clk);
        }
 
+       if (!dev->pm_domain) {
+               vic->rst = devm_reset_control_get(dev, "vic");
+               if (IS_ERR(vic->rst)) {
+                       dev_err(&pdev->dev, "failed to get reset\n");
+                       return PTR_ERR(vic->rst);
+               }
+       }
+
        vic->falcon.dev = dev;
        vic->falcon.regs = vic->regs;
        vic->falcon.ops = &vic_falcon_ops;
@@ -418,3 +459,6 @@ MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
 MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
 #endif
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE);
+#endif
index 33e5332684882c51c5567dc375494aa42980973a..3dac08b24140fe5c16c90c76f2379f6d63ecd9ba 100644 (file)
@@ -140,7 +140,6 @@ static int tilcdc_commit(struct drm_device *dev,
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = tilcdc_fb_create,
-       .output_poll_changed = drm_fb_helper_output_poll_changed,
        .atomic_check = tilcdc_atomic_check,
        .atomic_commit = tilcdc_commit,
 };
@@ -191,9 +190,6 @@ static void tilcdc_fini(struct drm_device *dev)
                drm_dev_unregister(dev);
 
        drm_kms_helper_poll_fini(dev);
-
-       drm_fb_cma_fbdev_fini(dev);
-
        drm_irq_uninstall(dev);
        drm_mode_config_cleanup(dev);
        tilcdc_remove_external_device(dev);
@@ -396,16 +392,14 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
 
        drm_mode_config_reset(ddev);
 
-       ret = drm_fb_cma_fbdev_init(ddev, bpp, 0);
-       if (ret)
-               goto init_failed;
-
        drm_kms_helper_poll_init(ddev);
 
        ret = drm_dev_register(ddev, 0);
        if (ret)
                goto init_failed;
 
+       drm_fbdev_generic_setup(ddev, bpp);
+
        priv->is_registered = true;
        return 0;
 
@@ -519,7 +513,6 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
 static struct drm_driver tilcdc_driver = {
        .driver_features    = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
                               DRIVER_PRIME | DRIVER_ATOMIC),
-       .lastclose          = drm_fb_helper_lastclose,
        .irq_handler        = tilcdc_irq,
        .gem_free_object_unlocked = drm_gem_cma_free_object,
        .gem_print_info     = drm_gem_cma_print_info,
index 16f4b5c91f1b604b16fffde48aeaca845b5c1eee..2c408ac1a9003a0dd4873847da04c7d6beb8423f 100644 (file)
@@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM
 config TINYDRM_MIPI_DBI
        tristate
 
+config TINYDRM_HX8357D
+       tristate "DRM support for HX8357D display panels"
+       depends on DRM_TINYDRM && SPI
+       depends on BACKLIGHT_CLASS_DEVICE
+       select TINYDRM_MIPI_DBI
+       help
+         DRM driver for the following HX8357D panels:
+         * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
+
+         If M is selected the module will be called hx8357d.
+
 config TINYDRM_ILI9225
        tristate "DRM support for ILI9225 display panels"
        depends on DRM_TINYDRM && SPI
index 14d99080665a4a8d84ebfd4eb022c22902cc5f8d..f823066f774308b8c2a0187d118b0901ff410505 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM)               += core/
 obj-$(CONFIG_TINYDRM_MIPI_DBI)         += mipi-dbi.o
 
 # Displays
+obj-$(CONFIG_TINYDRM_HX8357D)          += hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)          += ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)          += ili9341.o
 obj-$(CONFIG_TINYDRM_MI0283QT)         += mi0283qt.o
index 255341ee4eb944df08deae554bf850bdd0f3f8cd..01a6f2d42440e0c2f3573698abfe6ea70f3408b1 100644 (file)
  * and registers the DRM device using devm_tinydrm_register().
  */
 
-/**
- * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from
- *     another driver's scatter/gather table of pinned pages
- * @drm: DRM device to import into
- * @attach: DMA-BUF attachment
- * @sgt: Scatter/gather table of pinned pages
- *
- * This function imports a scatter/gather table exported via DMA-BUF by
- * another driver using drm_gem_cma_prime_import_sg_table(). It sets the
- * kernel virtual address on the CMA object. Drivers should use this as their
- * &drm_driver->gem_prime_import_sg_table callback if they need the virtual
- * address. tinydrm_gem_cma_free_object() should be used in combination with
- * this function.
- *
- * Returns:
- * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
- * error code on failure.
- */
-struct drm_gem_object *
-tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
-                                     struct dma_buf_attachment *attach,
-                                     struct sg_table *sgt)
-{
-       struct drm_gem_cma_object *cma_obj;
-       struct drm_gem_object *obj;
-       void *vaddr;
-
-       vaddr = dma_buf_vmap(attach->dmabuf);
-       if (!vaddr) {
-               DRM_ERROR("Failed to vmap PRIME buffer\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt);
-       if (IS_ERR(obj)) {
-               dma_buf_vunmap(attach->dmabuf, vaddr);
-               return obj;
-       }
-
-       cma_obj = to_drm_gem_cma_obj(obj);
-       cma_obj->vaddr = vaddr;
-
-       return obj;
-}
-EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table);
-
-/**
- * tinydrm_gem_cma_free_object - Free resources associated with a CMA GEM
- *                               object
- * @gem_obj: GEM object to free
- *
- * This function frees the backing memory of the CMA GEM object, cleans up the
- * GEM object state and frees the memory used to store the object itself using
- * drm_gem_cma_free_object(). It also handles PRIME buffers which has the kernel
- * virtual address set by tinydrm_gem_cma_prime_import_sg_table(). Drivers
- * can use this as their &drm_driver->gem_free_object_unlocked callback.
- */
-void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj)
-{
-       if (gem_obj->import_attach) {
-               struct drm_gem_cma_object *cma_obj;
-
-               cma_obj = to_drm_gem_cma_obj(gem_obj);
-               dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr);
-               cma_obj->vaddr = NULL;
-       }
-
-       drm_gem_cma_free_object(gem_obj);
-}
-EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object);
-
 static struct drm_framebuffer *
 tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
                  const struct drm_mode_fb_cmd2 *mode_cmd)
@@ -146,6 +75,7 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
        drm->dev_private = tdev;
        drm_mode_config_init(drm);
        drm->mode_config.funcs = &tinydrm_mode_config_funcs;
+       drm->mode_config.allow_fb_modifiers = true;
 
        return 0;
 }
index dcd390163a4a9bcef2e93185414c7444083e3d25..bf6bfbc5d412c8c2bb2e8a14fed1d16a139f1b88 100644 (file)
@@ -9,12 +9,18 @@
 
 #include <linux/backlight.h>
 #include <linux/dma-buf.h>
+#include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
 #include <linux/swab.h>
 
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
+#include <uapi/drm/drm.h>
 
 static unsigned int spi_max;
 module_param(spi_max, uint, 0400);
index 7e8e24d0b7a7a3295e059e0542976b1ceea13433..eacfc0ec8ff1dd0a1db5c9501b495e9c3f9b27d7 100644 (file)
@@ -184,6 +184,10 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
        struct drm_display_mode mode_copy;
        struct drm_connector *connector;
        int ret;
+       static const uint64_t modifiers[] = {
+               DRM_FORMAT_MOD_LINEAR,
+               DRM_FORMAT_MOD_INVALID
+       };
 
        drm_mode_copy(&mode_copy, mode);
        ret = tinydrm_rotate_mode(&mode_copy, rotation);
@@ -202,6 +206,6 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
                return PTR_ERR(connector);
 
        return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
-                                           format_count, NULL, connector);
+                                           format_count, modifiers, connector);
 }
 EXPORT_SYMBOL(tinydrm_display_pipe_init);
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
new file mode 100644 (file)
index 0000000..81a2bbe
--- /dev/null
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DRM driver for the HX8357D LCD controller
+ *
+ * Copyright 2018 Broadcom
+ * Copyright 2018 David Lechner <david@lechnology.com>
+ * Copyright 2016 Noralf Trønnes
+ * Copyright (C) 2015 Adafruit Industries
+ * Copyright (C) 2013 Christian Vogelgsang
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+#include <video/mipi_display.h>
+
+#define HX8357D_SETOSC 0xb0
+#define HX8357D_SETPOWER 0xb1
+#define HX8357D_SETRGB 0xb3
+#define HX8357D_SETCYC 0xb3
+#define HX8357D_SETCOM 0xb6
+#define HX8357D_SETEXTC 0xb9
+#define HX8357D_SETSTBA 0xc0
+#define HX8357D_SETPANEL 0xcc
+#define HX8357D_SETGAMMA 0xe0
+
+#define HX8357D_MADCTL_MY  0x80
+#define HX8357D_MADCTL_MX  0x40
+#define HX8357D_MADCTL_MV  0x20
+#define HX8357D_MADCTL_ML  0x10
+#define HX8357D_MADCTL_RGB 0x00
+#define HX8357D_MADCTL_BGR 0x08
+#define HX8357D_MADCTL_MH  0x04
+
+static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
+                            struct drm_crtc_state *crtc_state,
+                            struct drm_plane_state *plane_state)
+{
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       u8 addr_mode;
+       int ret;
+
+       DRM_DEBUG_KMS("\n");
+
+       ret = mipi_dbi_poweron_conditional_reset(mipi);
+       if (ret < 0)
+               return;
+       if (ret == 1)
+               goto out_enable;
+
+       /* setextc */
+       mipi_dbi_command(mipi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
+       msleep(150);
+
+       /* setRGB which also enables SDO */
+       mipi_dbi_command(mipi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
+
+       /* -1.52V */
+       mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
+
+       /* Normal mode 70Hz, Idle mode 55 Hz */
+       mipi_dbi_command(mipi, HX8357D_SETOSC, 0x68);
+
+       /* Set Panel - BGR, Gate direction swapped */
+       mipi_dbi_command(mipi, HX8357D_SETPANEL, 0x05);
+
+       mipi_dbi_command(mipi, HX8357D_SETPOWER,
+                        0x00,  /* Not deep standby */
+                        0x15,  /* BT */
+                        0x1C,  /* VSPR */
+                        0x1C,  /* VSNR */
+                        0x83,  /* AP */
+                        0xAA);  /* FS */
+
+       mipi_dbi_command(mipi, HX8357D_SETSTBA,
+                        0x50,  /* OPON normal */
+                        0x50,  /* OPON idle */
+                        0x01,  /* STBA */
+                        0x3C,  /* STBA */
+                        0x1E,  /* STBA */
+                        0x08);  /* GEN */
+
+       mipi_dbi_command(mipi, HX8357D_SETCYC,
+                        0x02,  /* NW 0x02 */
+                        0x40,  /* RTN */
+                        0x00,  /* DIV */
+                        0x2A,  /* DUM */
+                        0x2A,  /* DUM */
+                        0x0D,  /* GDON */
+                        0x78);  /* GDOFF */
+
+       mipi_dbi_command(mipi, HX8357D_SETGAMMA,
+                        0x02,
+                        0x0A,
+                        0x11,
+                        0x1d,
+                        0x23,
+                        0x35,
+                        0x41,
+                        0x4b,
+                        0x4b,
+                        0x42,
+                        0x3A,
+                        0x27,
+                        0x1B,
+                        0x08,
+                        0x09,
+                        0x03,
+                        0x02,
+                        0x0A,
+                        0x11,
+                        0x1d,
+                        0x23,
+                        0x35,
+                        0x41,
+                        0x4b,
+                        0x4b,
+                        0x42,
+                        0x3A,
+                        0x27,
+                        0x1B,
+                        0x08,
+                        0x09,
+                        0x03,
+                        0x00,
+                        0x01);
+
+       /* 16 bit */
+       mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
+                        MIPI_DCS_PIXEL_FMT_16BIT);
+
+       /* TE off */
+       mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
+
+       /* tear line */
+       mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
+
+       /* Exit Sleep */
+       mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
+       msleep(150);
+
+       /* display on */
+       mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
+       usleep_range(5000, 7000);
+
+out_enable:
+       switch (mipi->rotation) {
+       default:
+               addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
+               break;
+       case 90:
+               addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
+               break;
+       case 180:
+               addr_mode = 0;
+               break;
+       case 270:
+               addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
+               break;
+       }
+       mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
+       mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
+}
+
+static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
+       .enable = yx240qv29_enable,
+       .disable = mipi_dbi_pipe_disable,
+       .update = tinydrm_display_pipe_update,
+       .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const struct drm_display_mode yx350hv15_mode = {
+       TINYDRM_MODE(320, 480, 60, 75),
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
+
+static struct drm_driver hx8357d_driver = {
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
+       .fops                   = &hx8357d_fops,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
+       .debugfs_init           = mipi_dbi_debugfs_init,
+       .name                   = "hx8357d",
+       .desc                   = "HX8357D",
+       .date                   = "20181023",
+       .major                  = 1,
+       .minor                  = 0,
+};
+
+static const struct of_device_id hx8357d_of_match[] = {
+       { .compatible = "adafruit,yx350hv15" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, hx8357d_of_match);
+
+static const struct spi_device_id hx8357d_id[] = {
+       { "yx350hv15", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, hx8357d_id);
+
+static int hx8357d_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct mipi_dbi *mipi;
+       struct gpio_desc *dc;
+       u32 rotation = 0;
+       int ret;
+
+       mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
+       if (!mipi)
+               return -ENOMEM;
+
+       dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+       if (IS_ERR(dc)) {
+               DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
+               return PTR_ERR(dc);
+       }
+
+       mipi->backlight = devm_of_find_backlight(dev);
+       if (IS_ERR(mipi->backlight))
+               return PTR_ERR(mipi->backlight);
+
+       device_property_read_u32(dev, "rotation", &rotation);
+
+       ret = mipi_dbi_spi_init(spi, mipi, dc);
+       if (ret)
+               return ret;
+
+       ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
+                           &hx8357d_driver, &yx350hv15_mode, rotation);
+       if (ret)
+               return ret;
+
+       spi_set_drvdata(spi, mipi);
+
+       return devm_tinydrm_register(&mipi->tinydrm);
+}
+
+static void hx8357d_shutdown(struct spi_device *spi)
+{
+       struct mipi_dbi *mipi = spi_get_drvdata(spi);
+
+       tinydrm_shutdown(&mipi->tinydrm);
+}
+
+static struct spi_driver hx8357d_spi_driver = {
+       .driver = {
+               .name = "hx8357d",
+               .of_match_table = hx8357d_of_match,
+       },
+       .id_table = hx8357d_id,
+       .probe = hx8357d_probe,
+       .shutdown = hx8357d_shutdown,
+};
+module_spi_driver(hx8357d_spi_driver);
+
+MODULE_DESCRIPTION("HX8357D DRM driver");
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_LICENSE("GPL");
index 455fefe012f5912e825b4296e8c96b0129b814ea..78f7c2d1b4494078ec42959e22afd5429b06080e 100644 (file)
@@ -20,7 +20,8 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -367,7 +368,7 @@ static struct drm_driver ili9225_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
        .fops                   = &ili9225_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .name                   = "ili9225",
        .desc                   = "Ilitek ILI9225",
        .date                   = "20171106",
index 6701037749a74f862f8993fc3c5d7c95d5c69282..51395bdc6ca22a731d5bf9cd70d4bc29ca1387d1 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/property.h>
 #include <linux/spi/spi.h>
 
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
@@ -144,7 +144,7 @@ DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops);
 static struct drm_driver ili9341_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
        .fops                   = &ili9341_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .debugfs_init           = mipi_dbi_debugfs_init,
        .name                   = "ili9341",
        .desc                   = "Ilitek ILI9341",
index d7bb4c5e6657a723e9ae03f2cd91e043c942b847..3fa62e77c30b2ceff4a3aeaf9c6f5b8d7eafce6a 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_modeset_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 #include <video/mipi_display.h>
@@ -153,7 +153,7 @@ static struct drm_driver mi0283qt_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
        .fops                   = &mi0283qt_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .debugfs_init           = mipi_dbi_debugfs_init,
        .name                   = "mi0283qt",
        .desc                   = "Multi-Inno MI0283QT",
index cb3441e51d5f03f4c3e1f6b82cb091ef64af7637..3a05e56f9b0d81c0cd15780478927086ee3af3c9 100644 (file)
@@ -9,15 +9,19 @@
  * (at your option) any later version.
  */
 
-#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/tinydrm/mipi-dbi.h>
-#include <drm/tinydrm/tinydrm-helpers.h>
 #include <linux/debugfs.h>
 #include <linux/dma-buf.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+#include <uapi/drm/drm.h>
 #include <video/mipi_display.h>
 
 #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
@@ -240,10 +244,10 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
 
        mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
                         (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
-                        (clip.x2 >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
+                        ((clip.x2 - 1) >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
        mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
                         (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
-                        (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
+                        ((clip.y2 - 1) >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
 
        ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
                                (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
index 50a1d4216ce782ff2327ce7ad043fe3af9ee8092..54d6fe0f37ce8b2a72133027d4a313bd4458557c 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/spi/spi.h>
 #include <linux/thermal.h>
 
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -106,12 +108,11 @@ static int repaper_spi_transfer(struct spi_device *spi, u8 header,
 
        /* Stack allocated tx? */
        if (tx && len <= 32) {
-               txbuf = kmalloc(len, GFP_KERNEL);
+               txbuf = kmemdup(tx, len, GFP_KERNEL);
                if (!txbuf) {
                        ret = -ENOMEM;
                        goto out_free;
                }
-               memcpy(txbuf, tx, len);
        }
 
        if (rx) {
@@ -882,7 +883,7 @@ static struct drm_driver repaper_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
        .fops                   = &repaper_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .name                   = "repaper",
        .desc                   = "Pervasive Displays RePaper e-ink panels",
        .date                   = "20170405",
index 2fcbc3067d71b237d3a8a49ffd496d25367ac000..a6a8a1081b73de27256d12b00bda06a4204a4017 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -303,7 +304,7 @@ static struct drm_driver st7586_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
        .fops                   = &st7586_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .debugfs_init           = mipi_dbi_debugfs_init,
        .name                   = "st7586",
        .desc                   = "Sitronix ST7586",
index 3081bc57c1166dc6849d24ea2abfab47d07e780b..b39779e0dcd8765c58be58b97e63c60848aa82ea 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -119,7 +119,7 @@ static struct drm_driver st7735r_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                                  DRIVER_ATOMIC,
        .fops                   = &st7735r_fops,
-       TINYDRM_GEM_DRIVER_OPS,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
        .debugfs_init           = mipi_dbi_debugfs_init,
        .name                   = "st7735r",
        .desc                   = "Sitronix ST7735R",
index 26b889f866707eaaed398e593b3be6bfcd775d14..d87935bf8e308f81e13ccde697fe35e86fa446c6 100644 (file)
 
 static void ttm_bo_global_kobj_release(struct kobject *kobj);
 
+/**
+ * ttm_global_mutex - protecting the global BO state
+ */
+DEFINE_MUTEX(ttm_global_mutex);
+struct ttm_bo_global ttm_bo_glob = {
+       .use_count = 0
+};
+
 static struct attribute ttm_bo_count = {
        .name = "bo_count",
        .mode = S_IRUGO
@@ -872,7 +880,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
        if (fence) {
                reservation_object_add_shared_fence(bo->resv, fence);
 
-               ret = reservation_object_reserve_shared(bo->resv);
+               ret = reservation_object_reserve_shared(bo->resv, 1);
                if (unlikely(ret))
                        return ret;
 
@@ -977,7 +985,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
        bool has_erestartsys = false;
        int i, ret;
 
-       ret = reservation_object_reserve_shared(bo->resv);
+       ret = reservation_object_reserve_shared(bo->resv, 1);
        if (unlikely(ret))
                return ret;
 
@@ -1519,35 +1527,45 @@ static void ttm_bo_global_kobj_release(struct kobject *kobj)
                container_of(kobj, struct ttm_bo_global, kobj);
 
        __free_page(glob->dummy_read_page);
-       kfree(glob);
 }
 
-void ttm_bo_global_release(struct drm_global_reference *ref)
+static void ttm_bo_global_release(void)
 {
-       struct ttm_bo_global *glob = ref->object;
+       struct ttm_bo_global *glob = &ttm_bo_glob;
+
+       mutex_lock(&ttm_global_mutex);
+       if (--glob->use_count > 0)
+               goto out;
 
        kobject_del(&glob->kobj);
        kobject_put(&glob->kobj);
+       ttm_mem_global_release(&ttm_mem_glob);
+out:
+       mutex_unlock(&ttm_global_mutex);
 }
-EXPORT_SYMBOL(ttm_bo_global_release);
 
-int ttm_bo_global_init(struct drm_global_reference *ref)
+static int ttm_bo_global_init(void)
 {
-       struct ttm_bo_global_ref *bo_ref =
-               container_of(ref, struct ttm_bo_global_ref, ref);
-       struct ttm_bo_global *glob = ref->object;
-       int ret;
+       struct ttm_bo_global *glob = &ttm_bo_glob;
+       int ret = 0;
        unsigned i;
 
-       mutex_init(&glob->device_list_mutex);
+       mutex_lock(&ttm_global_mutex);
+       if (++glob->use_count > 1)
+               goto out;
+
+       ret = ttm_mem_global_init(&ttm_mem_glob);
+       if (ret)
+               goto out;
+
        spin_lock_init(&glob->lru_lock);
-       glob->mem_glob = bo_ref->mem_glob;
+       glob->mem_glob = &ttm_mem_glob;
        glob->mem_glob->bo_glob = glob;
        glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
 
        if (unlikely(glob->dummy_read_page == NULL)) {
                ret = -ENOMEM;
-               goto out_no_drp;
+               goto out;
        }
 
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
@@ -1559,13 +1577,10 @@ int ttm_bo_global_init(struct drm_global_reference *ref)
                &glob->kobj, &ttm_bo_glob_kobj_type, ttm_get_kobj(), "buffer_objects");
        if (unlikely(ret != 0))
                kobject_put(&glob->kobj);
-       return ret;
-out_no_drp:
-       kfree(glob);
+out:
+       mutex_unlock(&ttm_global_mutex);
        return ret;
 }
-EXPORT_SYMBOL(ttm_bo_global_init);
-
 
 int ttm_bo_device_release(struct ttm_bo_device *bdev)
 {
@@ -1587,9 +1602,9 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
                }
        }
 
-       mutex_lock(&glob->device_list_mutex);
+       mutex_lock(&ttm_global_mutex);
        list_del(&bdev->device_list);
-       mutex_unlock(&glob->device_list_mutex);
+       mutex_unlock(&ttm_global_mutex);
 
        cancel_delayed_work_sync(&bdev->wq);
 
@@ -1604,18 +1619,25 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
 
        drm_vma_offset_manager_destroy(&bdev->vma_manager);
 
+       if (!ret)
+               ttm_bo_global_release();
+
        return ret;
 }
 EXPORT_SYMBOL(ttm_bo_device_release);
 
 int ttm_bo_device_init(struct ttm_bo_device *bdev,
-                      struct ttm_bo_global *glob,
                       struct ttm_bo_driver *driver,
                       struct address_space *mapping,
                       uint64_t file_page_offset,
                       bool need_dma32)
 {
-       int ret = -EINVAL;
+       struct ttm_bo_global *glob = &ttm_bo_glob;
+       int ret;
+
+       ret = ttm_bo_global_init();
+       if (ret)
+               return ret;
 
        bdev->driver = driver;
 
@@ -1636,12 +1658,13 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
        bdev->dev_mapping = mapping;
        bdev->glob = glob;
        bdev->need_dma32 = need_dma32;
-       mutex_lock(&glob->device_list_mutex);
+       mutex_lock(&ttm_global_mutex);
        list_add_tail(&bdev->device_list, &glob->device_list);
-       mutex_unlock(&glob->device_list_mutex);
+       mutex_unlock(&ttm_global_mutex);
 
        return 0;
 out_no_sys:
+       ttm_bo_global_release();
        return ret;
 }
 EXPORT_SYMBOL(ttm_bo_device_init);
index e73ae0d228976f6708cffcaa5602133fec0a2c22..93860346c42600b455a3f4db1394cc43cc74ae11 100644 (file)
@@ -126,10 +126,11 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
                }
 
                if (!ret) {
-                       if (!entry->shared)
+                       if (!entry->num_shared)
                                continue;
 
-                       ret = reservation_object_reserve_shared(bo->resv);
+                       ret = reservation_object_reserve_shared(bo->resv,
+                                                               entry->num_shared);
                        if (!ret)
                                continue;
                }
@@ -150,8 +151,9 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
                        }
                }
 
-               if (!ret && entry->shared)
-                       ret = reservation_object_reserve_shared(bo->resv);
+               if (!ret && entry->num_shared)
+                       ret = reservation_object_reserve_shared(bo->resv,
+                                                               entry->num_shared);
 
                if (unlikely(ret != 0)) {
                        if (ret == -EINTR)
@@ -187,21 +189,19 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
        struct ttm_buffer_object *bo;
        struct ttm_bo_global *glob;
        struct ttm_bo_device *bdev;
-       struct ttm_bo_driver *driver;
 
        if (list_empty(list))
                return;
 
        bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo;
        bdev = bo->bdev;
-       driver = bdev->driver;
        glob = bo->bdev->glob;
 
        spin_lock(&glob->lru_lock);
 
        list_for_each_entry(entry, list, head) {
                bo = entry->bo;
-               if (entry->shared)
+               if (entry->num_shared)
                        reservation_object_add_shared_fence(bo->resv, fence);
                else
                        reservation_object_add_excl_fence(bo->resv, fence);
index 450387c92b63510df8b9e8ff340b511472b69462..f1567c353b543a3376c6b64ab5fb6c4550f91b23 100644 (file)
@@ -41,6 +41,9 @@
 
 #define TTM_MEMORY_ALLOC_RETRIES 4
 
+struct ttm_mem_global ttm_mem_glob;
+EXPORT_SYMBOL(ttm_mem_glob);
+
 struct ttm_mem_zone {
        struct kobject kobj;
        struct ttm_mem_global *glob;
@@ -216,14 +219,6 @@ static ssize_t ttm_mem_global_store(struct kobject *kobj,
        return size;
 }
 
-static void ttm_mem_global_kobj_release(struct kobject *kobj)
-{
-       struct ttm_mem_global *glob =
-               container_of(kobj, struct ttm_mem_global, kobj);
-
-       kfree(glob);
-}
-
 static struct attribute *ttm_mem_global_attrs[] = {
        &ttm_mem_global_lower_mem_limit,
        NULL
@@ -235,7 +230,6 @@ static const struct sysfs_ops ttm_mem_global_ops = {
 };
 
 static struct kobj_type ttm_mem_glob_kobj_type = {
-       .release = &ttm_mem_global_kobj_release,
        .sysfs_ops = &ttm_mem_global_ops,
        .default_attrs = ttm_mem_global_attrs,
 };
@@ -464,7 +458,6 @@ out_no_zone:
        ttm_mem_global_release(glob);
        return ret;
 }
-EXPORT_SYMBOL(ttm_mem_global_init);
 
 void ttm_mem_global_release(struct ttm_mem_global *glob)
 {
@@ -486,7 +479,6 @@ void ttm_mem_global_release(struct ttm_mem_global *glob)
        kobject_del(&glob->kobj);
        kobject_put(&glob->kobj);
 }
-EXPORT_SYMBOL(ttm_mem_global_release);
 
 static void ttm_check_swapping(struct ttm_mem_global *glob)
 {
index 72efcecb44f75446fcb3335d7296b0c4304580f8..28e2d03c0ccffa5b7403ec723ea0a676638872cb 100644 (file)
@@ -249,7 +249,7 @@ static int tve200_probe(struct platform_device *pdev)
 clk_disable:
        clk_disable_unprepare(priv->pclk);
 dev_unref:
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
        return ret;
 }
 
@@ -263,7 +263,7 @@ static int tve200_remove(struct platform_device *pdev)
                drm_panel_bridge_remove(priv->bridge);
        drm_mode_config_cleanup(drm);
        clk_disable_unprepare(priv->pclk);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return 0;
 }
index f455f095a14685d234569eaed56121d6269393b1..1b014d92855b93991b17911b1fe40e823585dba1 100644 (file)
@@ -350,15 +350,10 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto err;
 
-       ret = drm_vblank_init(dev, 1);
-       if (ret)
-               goto err_fb;
-
        drm_kms_helper_poll_init(dev);
 
        return 0;
-err_fb:
-       udl_fbdev_cleanup(dev);
+
 err:
        if (udl->urbs.count)
                udl_free_urb_list(dev);
index 54d96518a131672ae02223be468fc6e6ca71fa96..a08766d39eab535d1c62d091cbed11ae781b4074 100644 (file)
@@ -293,6 +293,7 @@ v3d_prime_import_sg_table(struct drm_device *dev,
        bo->resv = attach->dmabuf->resv;
 
        bo->sgt = sgt;
+       obj->import_attach = attach;
        v3d_bo_get_pages(bo);
 
        v3d_mmu_insert_ptes(bo);
index 4db62c54574828315f56215bf59ca5986cb7995e..eb2b2d2f85538381810b1ecc915ac3e128d9bc8f 100644 (file)
@@ -71,10 +71,13 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
                           V3D_READ(v3d_hub_reg_defs[i].reg));
        }
 
-       for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
-               seq_printf(m, "%s (0x%04x): 0x%08x\n",
-                          v3d_gca_reg_defs[i].name, v3d_gca_reg_defs[i].reg,
-                          V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
+       if (v3d->ver < 41) {
+               for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
+                       seq_printf(m, "%s (0x%04x): 0x%08x\n",
+                                  v3d_gca_reg_defs[i].name,
+                                  v3d_gca_reg_defs[i].reg,
+                                  V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
+               }
        }
 
        for (core = 0; core < v3d->cores; core++) {
@@ -176,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int v3d_measure_clock(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct v3d_dev *v3d = to_v3d_dev(dev);
+       uint32_t cycles;
+       int core = 0;
+       int measure_ms = 1000;
+
+       if (v3d->ver >= 40) {
+               V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
+                              V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
+                                            V3D_PCTR_S0));
+               V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
+               V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
+       } else {
+               V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
+                              V3D_PCTR_CYCLE_COUNT);
+               V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
+               V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
+                              V3D_V3_PCTR_0_EN_ENABLE |
+                              1);
+       }
+       msleep(measure_ms);
+       cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
+
+       seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
+                  cycles,
+                  cycles / (measure_ms * 1000),
+                  (cycles / (measure_ms * 100)) % 10);
+
+       return 0;
+}
+
 static const struct drm_info_list v3d_debugfs_list[] = {
        {"v3d_ident", v3d_v3d_debugfs_ident, 0},
        {"v3d_regs", v3d_v3d_debugfs_regs, 0},
+       {"measure_clock", v3d_measure_clock, 0},
        {"bo_stats", v3d_debugfs_bo_stats, 0},
 };
 
index 2a85fa68ffea51042b4c08dd8dc3497153590197..f0afcec72c348f703ffb03b8da25b2c6015df467 100644 (file)
@@ -112,10 +112,15 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
                return 0;
        }
 
-       /* Any params that aren't just register reads would go here. */
 
-       DRM_DEBUG("Unknown parameter %d\n", args->param);
-       return -EINVAL;
+       switch (args->param) {
+       case DRM_V3D_PARAM_SUPPORTS_TFU:
+               args->value = 1;
+               return 0;
+       default:
+               DRM_DEBUG("Unknown parameter %d\n", args->param);
+               return -EINVAL;
+       }
 }
 
 static int
@@ -170,7 +175,8 @@ static const struct file_operations v3d_drm_fops = {
 /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP
  * protection between clients.  Note that render nodes would be be
  * able to submit CLs that could access BOs from clients authenticated
- * with the master node.
+ * with the master node.  The TFU doesn't use the GMP, so it would
+ * need to stay DRM_AUTH until we do buffer size/offset validation.
  */
 static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
        DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
@@ -179,6 +185,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
        DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
 };
 
 static const struct vm_operations_struct v3d_vm_ops = {
index e6fed696ad869e2d700a94c2e6f4a10d36bf7529..dcb772a191919c15c567bd7cbb7c1292e635835d 100644 (file)
@@ -7,19 +7,18 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_gem.h>
 #include <drm/gpu_scheduler.h>
+#include "uapi/drm/v3d_drm.h"
 
 #define GMP_GRANULARITY (128 * 1024)
 
-/* Enum for each of the V3D queues.  We maintain various queue
- * tracking as an array because at some point we'll want to support
- * the TFU (texture formatting unit) as another queue.
- */
+/* Enum for each of the V3D queues. */
 enum v3d_queue {
        V3D_BIN,
        V3D_RENDER,
+       V3D_TFU,
 };
 
-#define V3D_MAX_QUEUES (V3D_RENDER + 1)
+#define V3D_MAX_QUEUES (V3D_TFU + 1)
 
 struct v3d_queue_state {
        struct drm_gpu_scheduler sched;
@@ -68,6 +67,7 @@ struct v3d_dev {
 
        struct v3d_exec_info *bin_job;
        struct v3d_exec_info *render_job;
+       struct v3d_tfu_job *tfu_job;
 
        struct v3d_queue_state queue[V3D_MAX_QUEUES];
 
@@ -198,6 +198,11 @@ struct v3d_exec_info {
         */
        struct dma_fence *bin_done_fence;
 
+       /* Fence for when the scheduler considers the render to be
+        * done, for when the BOs reservations should be complete.
+        */
+       struct dma_fence *render_done_fence;
+
        struct kref refcount;
 
        /* This is the array of BOs that were looked up at the start of exec. */
@@ -213,6 +218,25 @@ struct v3d_exec_info {
        u32 qma, qms, qts;
 };
 
+struct v3d_tfu_job {
+       struct drm_sched_job base;
+
+       struct drm_v3d_submit_tfu args;
+
+       /* An optional fence userspace can pass in for the job to depend on. */
+       struct dma_fence *in_fence;
+
+       /* v3d fence to be signaled by IRQ handler when the job is complete. */
+       struct dma_fence *done_fence;
+
+       struct v3d_dev *v3d;
+
+       struct kref refcount;
+
+       /* This is the array of BOs that were looked up at the start of exec. */
+       struct v3d_bo *bo[4];
+};
+
 /**
  * _wait_for - magic (register) wait macro
  *
@@ -276,9 +300,12 @@ int v3d_gem_init(struct drm_device *dev);
 void v3d_gem_destroy(struct drm_device *dev);
 int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
+int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
 int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
                      struct drm_file *file_priv);
 void v3d_exec_put(struct v3d_exec_info *exec);
+void v3d_tfu_job_put(struct v3d_tfu_job *exec);
 void v3d_reset(struct v3d_dev *v3d);
 void v3d_invalidate_caches(struct v3d_dev *v3d);
 void v3d_flush_caches(struct v3d_dev *v3d);
index 50bfcf9a8a1ac57d536fe4883f2727e88b42cdf7..b0a2a1ae2eb1a6a6dccfebf6b43342a6f78cf359 100644 (file)
@@ -29,10 +29,16 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence)
 {
        struct v3d_fence *f = to_v3d_fence(fence);
 
-       if (f->queue == V3D_BIN)
+       switch (f->queue) {
+       case V3D_BIN:
                return "v3d-bin";
-       else
+       case V3D_RENDER:
                return "v3d-render";
+       case V3D_TFU:
+               return "v3d-tfu";
+       default:
+               return NULL;
+       }
 }
 
 const struct dma_fence_ops v3d_fence_ops = {
index 70c54774400b39bbca6442db44cd50ffa5f71e05..05ca6319065e2287cc9264c41c3aec994c000413 100644 (file)
@@ -207,32 +207,26 @@ v3d_flush_caches(struct v3d_dev *v3d)
 }
 
 static void
-v3d_attach_object_fences(struct v3d_exec_info *exec)
+v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
+                        struct dma_fence *fence)
 {
-       struct dma_fence *out_fence = &exec->render.base.s_fence->finished;
-       struct v3d_bo *bo;
        int i;
 
-       for (i = 0; i < exec->bo_count; i++) {
-               bo = to_v3d_bo(&exec->bo[i]->base);
-
+       for (i = 0; i < bo_count; i++) {
                /* XXX: Use shared fences for read-only objects. */
-               reservation_object_add_excl_fence(bo->resv, out_fence);
+               reservation_object_add_excl_fence(bos[i]->resv, fence);
        }
 }
 
 static void
-v3d_unlock_bo_reservations(struct drm_device *dev,
-                          struct v3d_exec_info *exec,
+v3d_unlock_bo_reservations(struct v3d_bo **bos,
+                          int bo_count,
                           struct ww_acquire_ctx *acquire_ctx)
 {
        int i;
 
-       for (i = 0; i < exec->bo_count; i++) {
-               struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base);
-
-               ww_mutex_unlock(&bo->resv->lock);
-       }
+       for (i = 0; i < bo_count; i++)
+               ww_mutex_unlock(&bos[i]->resv->lock);
 
        ww_acquire_fini(acquire_ctx);
 }
@@ -245,19 +239,19 @@ v3d_unlock_bo_reservations(struct drm_device *dev,
  * to v3d, so we don't attach dma-buf fences to them.
  */
 static int
-v3d_lock_bo_reservations(struct drm_device *dev,
-                        struct v3d_exec_info *exec,
+v3d_lock_bo_reservations(struct v3d_bo **bos,
+                        int bo_count,
                         struct ww_acquire_ctx *acquire_ctx)
 {
        int contended_lock = -1;
        int i, ret;
-       struct v3d_bo *bo;
 
        ww_acquire_init(acquire_ctx, &reservation_ww_class);
 
 retry:
        if (contended_lock != -1) {
-               bo = to_v3d_bo(&exec->bo[contended_lock]->base);
+               struct v3d_bo *bo = bos[contended_lock];
+
                ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
                                                       acquire_ctx);
                if (ret) {
@@ -266,23 +260,20 @@ retry:
                }
        }
 
-       for (i = 0; i < exec->bo_count; i++) {
+       for (i = 0; i < bo_count; i++) {
                if (i == contended_lock)
                        continue;
 
-               bo = to_v3d_bo(&exec->bo[i]->base);
-
-               ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx);
+               ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock,
+                                                 acquire_ctx);
                if (ret) {
                        int j;
 
-                       for (j = 0; j < i; j++) {
-                               bo = to_v3d_bo(&exec->bo[j]->base);
-                               ww_mutex_unlock(&bo->resv->lock);
-                       }
+                       for (j = 0; j < i; j++)
+                               ww_mutex_unlock(&bos[j]->resv->lock);
 
                        if (contended_lock != -1 && contended_lock >= i) {
-                               bo = to_v3d_bo(&exec->bo[contended_lock]->base);
+                               struct v3d_bo *bo = bos[contended_lock];
 
                                ww_mutex_unlock(&bo->resv->lock);
                        }
@@ -302,12 +293,11 @@ retry:
        /* Reserve space for our shared (read-only) fence references,
         * before we commit the CL to the hardware.
         */
-       for (i = 0; i < exec->bo_count; i++) {
-               bo = to_v3d_bo(&exec->bo[i]->base);
-
-               ret = reservation_object_reserve_shared(bo->resv);
+       for (i = 0; i < bo_count; i++) {
+               ret = reservation_object_reserve_shared(bos[i]->resv, 1);
                if (ret) {
-                       v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
+                       v3d_unlock_bo_reservations(bos, bo_count,
+                                                  acquire_ctx);
                        return ret;
                }
        }
@@ -409,6 +399,7 @@ v3d_exec_cleanup(struct kref *ref)
        dma_fence_put(exec->render.done_fence);
 
        dma_fence_put(exec->bin_done_fence);
+       dma_fence_put(exec->render_done_fence);
 
        for (i = 0; i < exec->bo_count; i++)
                drm_gem_object_put_unlocked(&exec->bo[i]->base);
@@ -429,6 +420,33 @@ void v3d_exec_put(struct v3d_exec_info *exec)
        kref_put(&exec->refcount, v3d_exec_cleanup);
 }
 
+static void
+v3d_tfu_job_cleanup(struct kref *ref)
+{
+       struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
+                                              refcount);
+       struct v3d_dev *v3d = job->v3d;
+       unsigned int i;
+
+       dma_fence_put(job->in_fence);
+       dma_fence_put(job->done_fence);
+
+       for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
+               if (job->bo[i])
+                       drm_gem_object_put_unlocked(&job->bo[i]->base);
+       }
+
+       pm_runtime_mark_last_busy(v3d->dev);
+       pm_runtime_put_autosuspend(v3d->dev);
+
+       kfree(job);
+}
+
+void v3d_tfu_job_put(struct v3d_tfu_job *job)
+{
+       kref_put(&job->refcount, v3d_tfu_job_cleanup);
+}
+
 int
 v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
@@ -503,6 +521,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
        struct drm_syncobj *sync_out;
        int ret = 0;
 
+       trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
+
        if (args->pad != 0) {
                DRM_INFO("pad must be zero: %d\n", args->pad);
                return -EINVAL;
@@ -521,12 +541,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
        kref_init(&exec->refcount);
 
        ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
-                                    0, &exec->bin.in_fence);
+                                    0, 0, &exec->bin.in_fence);
        if (ret == -EINVAL)
                goto fail;
 
        ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
-                                    0, &exec->render.in_fence);
+                                    0, 0, &exec->render.in_fence);
        if (ret == -EINVAL)
                goto fail;
 
@@ -546,7 +566,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
        if (ret)
                goto fail;
 
-       ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx);
+       ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
+                                      &acquire_ctx);
        if (ret)
                goto fail;
 
@@ -572,20 +593,23 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
        if (ret)
                goto fail_unreserve;
 
+       exec->render_done_fence =
+               dma_fence_get(&exec->render.base.s_fence->finished);
+
        kref_get(&exec->refcount); /* put by scheduler job completion */
        drm_sched_entity_push_job(&exec->render.base,
                                  &v3d_priv->sched_entity[V3D_RENDER]);
        mutex_unlock(&v3d->sched_lock);
 
-       v3d_attach_object_fences(exec);
+       v3d_attach_object_fences(exec->bo, exec->bo_count,
+                                exec->render_done_fence);
 
-       v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
+       v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
 
        /* Update the return sync object for the */
        sync_out = drm_syncobj_find(file_priv, args->out_sync);
        if (sync_out) {
-               drm_syncobj_replace_fence(sync_out, 0,
-                                         &exec->render.base.s_fence->finished);
+               drm_syncobj_replace_fence(sync_out, exec->render_done_fence);
                drm_syncobj_put(sync_out);
        }
 
@@ -595,13 +619,121 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
 
 fail_unreserve:
        mutex_unlock(&v3d->sched_lock);
-       v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
+       v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
 fail:
        v3d_exec_put(exec);
 
        return ret;
 }
 
+/**
+ * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D.
+ * @dev: DRM device
+ * @data: ioctl argument
+ * @file_priv: DRM file for this fd
+ *
+ * Userspace provides the register setup for the TFU, which we don't
+ * need to validate since the TFU is behind the MMU.
+ */
+int
+v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct v3d_dev *v3d = to_v3d_dev(dev);
+       struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
+       struct drm_v3d_submit_tfu *args = data;
+       struct v3d_tfu_job *job;
+       struct ww_acquire_ctx acquire_ctx;
+       struct drm_syncobj *sync_out;
+       struct dma_fence *sched_done_fence;
+       int ret = 0;
+       int bo_count;
+
+       trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
+
+       job = kcalloc(1, sizeof(*job), GFP_KERNEL);
+       if (!job)
+               return -ENOMEM;
+
+       ret = pm_runtime_get_sync(v3d->dev);
+       if (ret < 0) {
+               kfree(job);
+               return ret;
+       }
+
+       kref_init(&job->refcount);
+
+       ret = drm_syncobj_find_fence(file_priv, args->in_sync,
+                                    0, 0, &job->in_fence);
+       if (ret == -EINVAL)
+               goto fail;
+
+       job->args = *args;
+       job->v3d = v3d;
+
+       spin_lock(&file_priv->table_lock);
+       for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
+               struct drm_gem_object *bo;
+
+               if (!args->bo_handles[bo_count])
+                       break;
+
+               bo = idr_find(&file_priv->object_idr,
+                             args->bo_handles[bo_count]);
+               if (!bo) {
+                       DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
+                                 bo_count, args->bo_handles[bo_count]);
+                       ret = -ENOENT;
+                       spin_unlock(&file_priv->table_lock);
+                       goto fail;
+               }
+               drm_gem_object_get(bo);
+               job->bo[bo_count] = to_v3d_bo(bo);
+       }
+       spin_unlock(&file_priv->table_lock);
+
+       ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+       if (ret)
+               goto fail;
+
+       mutex_lock(&v3d->sched_lock);
+       ret = drm_sched_job_init(&job->base,
+                                &v3d_priv->sched_entity[V3D_TFU],
+                                v3d_priv);
+       if (ret)
+               goto fail_unreserve;
+
+       sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
+
+       kref_get(&job->refcount); /* put by scheduler job completion */
+       drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
+       mutex_unlock(&v3d->sched_lock);
+
+       v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
+
+       v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+
+       /* Update the return sync object */
+       sync_out = drm_syncobj_find(file_priv, args->out_sync);
+       if (sync_out) {
+               drm_syncobj_replace_fence(sync_out, sched_done_fence);
+               drm_syncobj_put(sync_out);
+       }
+       dma_fence_put(sched_done_fence);
+
+       v3d_tfu_job_put(job);
+
+       return 0;
+
+fail_unreserve:
+       mutex_unlock(&v3d->sched_lock);
+       v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+fail:
+       v3d_tfu_job_put(job);
+
+       return ret;
+}
+
 int
 v3d_gem_init(struct drm_device *dev)
 {
index e07514eb11b511ddaacd9ddd0cf0c3e3fbbbb1a7..69338da70ddcea18ec17bbfb97876ab9cc2269d3 100644 (file)
@@ -4,8 +4,8 @@
 /**
  * DOC: Interrupt management for the V3D engine
  *
- * When we take a binning or rendering flush done interrupt, we need
- * to signal the fence for that job so that the scheduler can queue up
+ * When we take a bin, render, or TFU done interrupt, we need to
+ * signal the fence for that job so that the scheduler can queue up
  * the next one and unblock any waiters.
  *
  * When we take the binner out of memory interrupt, we need to
@@ -15,6 +15,7 @@
 
 #include "v3d_drv.h"
 #include "v3d_regs.h"
+#include "v3d_trace.h"
 
 #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
                             V3D_INT_FLDONE |   \
@@ -23,7 +24,8 @@
 
 #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV |      \
                            V3D_HUB_INT_MMU_PTI |       \
-                           V3D_HUB_INT_MMU_CAP))
+                           V3D_HUB_INT_MMU_CAP |       \
+                           V3D_HUB_INT_TFUC))
 
 static void
 v3d_overflow_mem_work(struct work_struct *work)
@@ -87,12 +89,20 @@ v3d_irq(int irq, void *arg)
        }
 
        if (intsts & V3D_INT_FLDONE) {
-               dma_fence_signal(v3d->bin_job->bin.done_fence);
+               struct v3d_fence *fence =
+                       to_v3d_fence(v3d->bin_job->bin.done_fence);
+
+               trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
+               dma_fence_signal(&fence->base);
                status = IRQ_HANDLED;
        }
 
        if (intsts & V3D_INT_FRDONE) {
-               dma_fence_signal(v3d->render_job->render.done_fence);
+               struct v3d_fence *fence =
+                       to_v3d_fence(v3d->render_job->render.done_fence);
+
+               trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
+               dma_fence_signal(&fence->base);
                status = IRQ_HANDLED;
        }
 
@@ -117,6 +127,15 @@ v3d_hub_irq(int irq, void *arg)
        /* Acknowledge the interrupts we're handling here. */
        V3D_WRITE(V3D_HUB_INT_CLR, intsts);
 
+       if (intsts & V3D_HUB_INT_TFUC) {
+               struct v3d_fence *fence =
+                       to_v3d_fence(v3d->tfu_job->done_fence);
+
+               trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
+               dma_fence_signal(&fence->base);
+               status = IRQ_HANDLED;
+       }
+
        if (intsts & (V3D_HUB_INT_MMU_WRV |
                      V3D_HUB_INT_MMU_PTI |
                      V3D_HUB_INT_MMU_CAP)) {
index 854046565989e12c5b2e822f82b8fae40c01e5b0..6ccdee9d47bd7c4290aad8d73b3fb5b4cd2ed67f 100644 (file)
 # define V3D_TOP_GR_BRIDGE_SW_INIT_1                   0x0000c
 # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0)
 
+#define V3D_TFU_CS                                     0x00400
+/* Stops current job, empties input fifo. */
+# define V3D_TFU_CS_TFURST                             BIT(31)
+# define V3D_TFU_CS_CVTCT_MASK                         V3D_MASK(23, 16)
+# define V3D_TFU_CS_CVTCT_SHIFT                        16
+# define V3D_TFU_CS_NFREE_MASK                         V3D_MASK(13, 8)
+# define V3D_TFU_CS_NFREE_SHIFT                        8
+# define V3D_TFU_CS_BUSY                               BIT(0)
+
+#define V3D_TFU_SU                                     0x00404
+/* Interrupt when FINTTHR input slots are free (0 = disabled) */
+# define V3D_TFU_SU_FINTTHR_MASK                       V3D_MASK(13, 8)
+# define V3D_TFU_SU_FINTTHR_SHIFT                      8
+/* Skips resetting the CRC at the start of CRC generation. */
+# define V3D_TFU_SU_CRCCHAIN                           BIT(4)
+/* skips writes, computes CRC of the image.  miplevels must be 0. */
+# define V3D_TFU_SU_CRC                                BIT(3)
+# define V3D_TFU_SU_THROTTLE_MASK                      V3D_MASK(1, 0)
+# define V3D_TFU_SU_THROTTLE_SHIFT                     0
+
+#define V3D_TFU_ICFG                                   0x00408
+/* Interrupt when the conversion is complete. */
+# define V3D_TFU_ICFG_IOC                              BIT(0)
+
+/* Input Image Address */
+#define V3D_TFU_IIA                                    0x0040c
+/* Input Chroma Address */
+#define V3D_TFU_ICA                                    0x00410
+/* Input Image Stride */
+#define V3D_TFU_IIS                                    0x00414
+/* Input Image U-Plane Address */
+#define V3D_TFU_IUA                                    0x00418
+/* Output Image Address */
+#define V3D_TFU_IOA                                    0x0041c
+/* Image Output Size */
+#define V3D_TFU_IOS                                    0x00420
+/* TFU YUV Coefficient 0 */
+#define V3D_TFU_COEF0                                  0x00424
+/* Use these regs instead of the defaults. */
+# define V3D_TFU_COEF0_USECOEF                         BIT(31)
+/* TFU YUV Coefficient 1 */
+#define V3D_TFU_COEF1                                  0x00428
+/* TFU YUV Coefficient 2 */
+#define V3D_TFU_COEF2                                  0x0042c
+/* TFU YUV Coefficient 3 */
+#define V3D_TFU_COEF3                                  0x00430
+
+#define V3D_TFU_CRC                                    0x00434
+
 /* Per-MMU registers. */
 
 #define V3D_MMUC_CONTROL                               0x01000
 # define V3D_PTB_BXCF_RWORDERDISA                      BIT(1)
 # define V3D_PTB_BXCF_CLIPDISA                         BIT(0)
 
+#define V3D_V3_PCTR_0_EN                               0x00674
+#define V3D_V3_PCTR_0_EN_ENABLE                        BIT(31)
+#define V3D_V4_PCTR_0_EN                               0x00650
+/* When a bit is set, resets the counter to 0. */
+#define V3D_V3_PCTR_0_CLR                              0x00670
+#define V3D_V4_PCTR_0_CLR                              0x00654
+#define V3D_PCTR_0_OVERFLOW                            0x00658
+
+#define V3D_V3_PCTR_0_PCTRS0                           0x00684
+#define V3D_V3_PCTR_0_PCTRS15                          0x00660
+#define V3D_V3_PCTR_0_PCTRSX(x)                        (V3D_V3_PCTR_0_PCTRS0 + \
+                                                       4 * (x))
+/* Each src reg muxes four counters each. */
+#define V3D_V4_PCTR_0_SRC_0_3                          0x00660
+#define V3D_V4_PCTR_0_SRC_28_31                        0x0067c
+# define V3D_PCTR_S0_MASK                              V3D_MASK(6, 0)
+# define V3D_PCTR_S0_SHIFT                             0
+# define V3D_PCTR_S1_MASK                              V3D_MASK(14, 8)
+# define V3D_PCTR_S1_SHIFT                             8
+# define V3D_PCTR_S2_MASK                              V3D_MASK(22, 16)
+# define V3D_PCTR_S2_SHIFT                             16
+# define V3D_PCTR_S3_MASK                              V3D_MASK(30, 24)
+# define V3D_PCTR_S3_SHIFT                             24
+# define V3D_PCTR_CYCLE_COUNT                          32
+
+/* Output values of the counters. */
+#define V3D_PCTR_0_PCTR0                               0x00680
+#define V3D_PCTR_0_PCTR31                              0x006fc
+#define V3D_PCTR_0_PCTRX(x)                            (V3D_PCTR_0_PCTR0 + \
+                                                       4 * (x))
 #define V3D_GMP_STATUS                                 0x00800
 # define V3D_GMP_STATUS_GMPRST                         BIT(31)
 # define V3D_GMP_STATUS_WR_COUNT_MASK                  V3D_MASK(30, 24)
index 9243dea6e6ad106169c81dd384d5d4bc36c6d3ea..f7508e907536c63b1d5542f90749f2919ad32a5f 100644 (file)
@@ -30,16 +30,34 @@ to_v3d_job(struct drm_sched_job *sched_job)
        return container_of(sched_job, struct v3d_job, base);
 }
 
+static struct v3d_tfu_job *
+to_tfu_job(struct drm_sched_job *sched_job)
+{
+       return container_of(sched_job, struct v3d_tfu_job, base);
+}
+
 static void
 v3d_job_free(struct drm_sched_job *sched_job)
 {
        struct v3d_job *job = to_v3d_job(sched_job);
 
+       drm_sched_job_cleanup(sched_job);
+
        v3d_exec_put(job->exec);
 }
 
+static void
+v3d_tfu_job_free(struct drm_sched_job *sched_job)
+{
+       struct v3d_tfu_job *job = to_tfu_job(sched_job);
+
+       drm_sched_job_cleanup(sched_job);
+
+       v3d_tfu_job_put(job);
+}
+
 /**
- * Returns the fences that the bin job depends on, one by one.
+ * Returns the fences that the bin or render job depends on, one by one.
  * v3d_job_run() won't be called until all of them have been signaled.
  */
 static struct dma_fence *
@@ -76,6 +94,27 @@ v3d_job_dependency(struct drm_sched_job *sched_job,
        return fence;
 }
 
+/**
+ * Returns the fences that the TFU job depends on, one by one.
+ * v3d_tfu_job_run() won't be called until all of them have been
+ * signaled.
+ */
+static struct dma_fence *
+v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
+                      struct drm_sched_entity *s_entity)
+{
+       struct v3d_tfu_job *job = to_tfu_job(sched_job);
+       struct dma_fence *fence;
+
+       fence = job->in_fence;
+       if (fence) {
+               job->in_fence = NULL;
+               return fence;
+       }
+
+       return NULL;
+}
+
 static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
 {
        struct v3d_job *job = to_v3d_job(sched_job);
@@ -147,31 +186,47 @@ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
        return fence;
 }
 
-static void
-v3d_job_timedout(struct drm_sched_job *sched_job)
+static struct dma_fence *
+v3d_tfu_job_run(struct drm_sched_job *sched_job)
 {
-       struct v3d_job *job = to_v3d_job(sched_job);
-       struct v3d_exec_info *exec = job->exec;
-       struct v3d_dev *v3d = exec->v3d;
-       enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
-       enum v3d_queue q;
-       u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
-       u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
+       struct v3d_tfu_job *job = to_tfu_job(sched_job);
+       struct v3d_dev *v3d = job->v3d;
+       struct drm_device *dev = &v3d->drm;
+       struct dma_fence *fence;
 
-       /* If the current address or return address have changed, then
-        * the GPU has probably made progress and we should delay the
-        * reset.  This could fail if the GPU got in an infinite loop
-        * in the CL, but that is pretty unlikely outside of an i-g-t
-        * testcase.
-        */
-       if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
-               job->timedout_ctca = ctca;
-               job->timedout_ctra = ctra;
+       fence = v3d_fence_create(v3d, V3D_TFU);
+       if (IS_ERR(fence))
+               return NULL;
 
-               schedule_delayed_work(&job->base.sched->work_tdr,
-                                     job->base.sched->timeout);
-               return;
+       v3d->tfu_job = job;
+       if (job->done_fence)
+               dma_fence_put(job->done_fence);
+       job->done_fence = dma_fence_get(fence);
+
+       trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
+
+       V3D_WRITE(V3D_TFU_IIA, job->args.iia);
+       V3D_WRITE(V3D_TFU_IIS, job->args.iis);
+       V3D_WRITE(V3D_TFU_ICA, job->args.ica);
+       V3D_WRITE(V3D_TFU_IUA, job->args.iua);
+       V3D_WRITE(V3D_TFU_IOA, job->args.ioa);
+       V3D_WRITE(V3D_TFU_IOS, job->args.ios);
+       V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]);
+       if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) {
+               V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]);
+               V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]);
+               V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]);
        }
+       /* ICFG kicks off the job. */
+       V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC);
+
+       return fence;
+}
+
+static void
+v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
+{
+       enum v3d_queue q;
 
        mutex_lock(&v3d->reset_lock);
 
@@ -196,6 +251,39 @@ v3d_job_timedout(struct drm_sched_job *sched_job)
        mutex_unlock(&v3d->reset_lock);
 }
 
+static void
+v3d_job_timedout(struct drm_sched_job *sched_job)
+{
+       struct v3d_job *job = to_v3d_job(sched_job);
+       struct v3d_exec_info *exec = job->exec;
+       struct v3d_dev *v3d = exec->v3d;
+       enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
+       u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
+       u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
+
+       /* If the current address or return address have changed, then
+        * the GPU has probably made progress and we should delay the
+        * reset.  This could fail if the GPU got in an infinite loop
+        * in the CL, but that is pretty unlikely outside of an i-g-t
+        * testcase.
+        */
+       if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
+               job->timedout_ctca = ctca;
+               job->timedout_ctra = ctra;
+               return;
+       }
+
+       v3d_gpu_reset_for_timeout(v3d, sched_job);
+}
+
+static void
+v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
+{
+       struct v3d_tfu_job *job = to_tfu_job(sched_job);
+
+       v3d_gpu_reset_for_timeout(job->v3d, sched_job);
+}
+
 static const struct drm_sched_backend_ops v3d_sched_ops = {
        .dependency = v3d_job_dependency,
        .run_job = v3d_job_run,
@@ -203,6 +291,13 @@ static const struct drm_sched_backend_ops v3d_sched_ops = {
        .free_job = v3d_job_free
 };
 
+static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
+       .dependency = v3d_tfu_job_dependency,
+       .run_job = v3d_tfu_job_run,
+       .timedout_job = v3d_tfu_job_timedout,
+       .free_job = v3d_tfu_job_free
+};
+
 int
 v3d_sched_init(struct v3d_dev *v3d)
 {
@@ -233,6 +328,19 @@ v3d_sched_init(struct v3d_dev *v3d)
                return ret;
        }
 
+       ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
+                            &v3d_tfu_sched_ops,
+                            hw_jobs_limit, job_hang_limit,
+                            msecs_to_jiffies(hang_limit_ms),
+                            "v3d_tfu");
+       if (ret) {
+               dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
+                       ret);
+               drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
+               drm_sched_fini(&v3d->queue[V3D_BIN].sched);
+               return ret;
+       }
+
        return 0;
 }
 
index 85dd351e1e09af5c8d92e2f712505f8adb30a8ab..edd984afa33fb22a1c44453d6cdd58a583029882 100644 (file)
 #define TRACE_SYSTEM v3d
 #define TRACE_INCLUDE_FILE v3d_trace
 
+TRACE_EVENT(v3d_submit_cl_ioctl,
+           TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea),
+           TP_ARGS(dev, ct1qba, ct1qea),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u32, ct1qba)
+                            __field(u32, ct1qea)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->ct1qba = ct1qba;
+                          __entry->ct1qea = ct1qea;
+                          ),
+
+           TP_printk("dev=%u, RCL 0x%08x..0x%08x",
+                     __entry->dev,
+                     __entry->ct1qba,
+                     __entry->ct1qea)
+);
+
 TRACE_EVENT(v3d_submit_cl,
            TP_PROTO(struct drm_device *dev, bool is_render,
                     uint64_t seqno,
@@ -42,6 +64,105 @@ TRACE_EVENT(v3d_submit_cl,
                      __entry->ctnqea)
 );
 
+TRACE_EVENT(v3d_bcl_irq,
+           TP_PROTO(struct drm_device *dev,
+                    uint64_t seqno),
+           TP_ARGS(dev, seqno),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u64, seqno)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->seqno = seqno;
+                          ),
+
+           TP_printk("dev=%u, seqno=%llu",
+                     __entry->dev,
+                     __entry->seqno)
+);
+
+TRACE_EVENT(v3d_rcl_irq,
+           TP_PROTO(struct drm_device *dev,
+                    uint64_t seqno),
+           TP_ARGS(dev, seqno),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u64, seqno)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->seqno = seqno;
+                          ),
+
+           TP_printk("dev=%u, seqno=%llu",
+                     __entry->dev,
+                     __entry->seqno)
+);
+
+TRACE_EVENT(v3d_tfu_irq,
+           TP_PROTO(struct drm_device *dev,
+                    uint64_t seqno),
+           TP_ARGS(dev, seqno),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u64, seqno)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->seqno = seqno;
+                          ),
+
+           TP_printk("dev=%u, seqno=%llu",
+                     __entry->dev,
+                     __entry->seqno)
+);
+
+TRACE_EVENT(v3d_submit_tfu_ioctl,
+           TP_PROTO(struct drm_device *dev, u32 iia),
+           TP_ARGS(dev, iia),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u32, iia)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->iia = iia;
+                          ),
+
+           TP_printk("dev=%u, IIA 0x%08x",
+                     __entry->dev,
+                     __entry->iia)
+);
+
+TRACE_EVENT(v3d_submit_tfu,
+           TP_PROTO(struct drm_device *dev,
+                    uint64_t seqno),
+           TP_ARGS(dev, seqno),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u64, seqno)
+                            ),
+
+           TP_fast_assign(
+                          __entry->dev = dev->primary->index;
+                          __entry->seqno = seqno;
+                          ),
+
+           TP_printk("dev=%u, seqno=%llu",
+                     __entry->dev,
+                     __entry->seqno)
+);
+
 TRACE_EVENT(v3d_reset_begin,
            TP_PROTO(struct drm_device *dev),
            TP_ARGS(dev),
index 1f1780ccdbdf0279c7dfd23290079e859eab7b4e..f6f5cd80c04de355da85295457fc2a1a4011cdd9 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pm_runtime.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "uapi/drm/vc4_drm.h"
 #include "vc4_drv.h"
@@ -308,6 +309,8 @@ static void vc4_drm_unbind(struct device *dev)
 
        drm_dev_unregister(drm);
 
+       drm_atomic_helper_shutdown(drm);
+
        drm_mode_config_cleanup(drm);
 
        drm_atomic_private_obj_fini(&vc4->ctm_manager);
index bd6ef1f318220556e067b158936f9d1f6447eedb..4f87b03f837d11d547ef649b16de99ec4c764658 100644 (file)
@@ -338,6 +338,7 @@ struct vc4_plane_state {
        u32 pos0_offset;
        u32 pos2_offset;
        u32 ptr0_offset;
+       u32 lbm_offset;
 
        /* Offset where the plane's dlist was last stored in the
         * hardware at vc4_crtc_atomic_flush() time.
@@ -369,6 +370,11 @@ struct vc4_plane_state {
         * to enable background color fill.
         */
        bool needs_bg_fill;
+
+       /* Mark the dlist as initialized. Useful to avoid initializing it twice
+        * when async update is not possible.
+        */
+       bool dlist_initialized;
 };
 
 static inline struct vc4_plane_state *
index 5b22e996af6c5b6c1d335687902f74ef8ed43db6..aea2b8dfec1717648e1251c3610753dcf659679c 100644 (file)
@@ -635,7 +635,7 @@ retry:
        for (i = 0; i < exec->bo_count; i++) {
                bo = to_vc4_bo(&exec->bo[i]->base);
 
-               ret = reservation_object_reserve_shared(bo->resv);
+               ret = reservation_object_reserve_shared(bo->resv, 1);
                if (ret) {
                        vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
                        return ret;
@@ -681,7 +681,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
        exec->fence = &fence->base;
 
        if (out_sync)
-               drm_syncobj_replace_fence(out_sync, 0, exec->fence);
+               drm_syncobj_replace_fence(out_sync, exec->fence);
 
        vc4_update_bo_seqnos(exec, seqno);
 
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
 
        if (args->in_sync) {
                ret = drm_syncobj_find_fence(file_priv, args->in_sync,
-                                            0, &in_fence);
+                                            0, 0, &in_fence);
                if (ret)
                        goto fail;
 
index c6635f23918a8c1ec07531fc6aeffede5e6e528f..75db62cbe468df2324d395a2a33446c0a81cf172 100644 (file)
@@ -129,12 +129,12 @@ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
 
 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
 {
-       if (dst > src)
+       if (dst == src)
+               return VC4_SCALING_NONE;
+       if (3 * dst >= 2 * src)
                return VC4_SCALING_PPF;
-       else if (dst < src)
-               return VC4_SCALING_TPZ;
        else
-               return VC4_SCALING_NONE;
+               return VC4_SCALING_TPZ;
 }
 
 static bool plane_enabled(struct drm_plane_state *state)
@@ -154,6 +154,7 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
                return NULL;
 
        memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
+       vc4_state->dlist_initialized = 0;
 
        __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
 
@@ -259,37 +260,51 @@ static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
 
 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
 {
-       struct drm_plane *plane = state->plane;
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
        struct drm_framebuffer *fb = state->fb;
        struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
        u32 subpixel_src_mask = (1 << 16) - 1;
        u32 format = fb->format->format;
        int num_planes = fb->format->num_planes;
-       u32 h_subsample = 1;
-       u32 v_subsample = 1;
-       int i;
+       struct drm_crtc_state *crtc_state;
+       u32 h_subsample, v_subsample;
+       int i, ret;
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+                                                       state->crtc);
+       if (!crtc_state) {
+               DRM_DEBUG_KMS("Invalid crtc state\n");
+               return -EINVAL;
+       }
+
+       ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,
+                                                 INT_MAX, true, true);
+       if (ret)
+               return ret;
+
+       h_subsample = drm_format_horz_chroma_subsampling(format);
+       v_subsample = drm_format_vert_chroma_subsampling(format);
 
        for (i = 0; i < num_planes; i++)
                vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
 
        /* We don't support subpixel source positioning for scaling. */
-       if ((state->src_x & subpixel_src_mask) ||
-           (state->src_y & subpixel_src_mask) ||
-           (state->src_w & subpixel_src_mask) ||
-           (state->src_h & subpixel_src_mask)) {
+       if ((state->src.x1 & subpixel_src_mask) ||
+           (state->src.x2 & subpixel_src_mask) ||
+           (state->src.y1 & subpixel_src_mask) ||
+           (state->src.y2 & subpixel_src_mask)) {
                return -EINVAL;
        }
 
-       vc4_state->src_x = state->src_x >> 16;
-       vc4_state->src_y = state->src_y >> 16;
-       vc4_state->src_w[0] = state->src_w >> 16;
-       vc4_state->src_h[0] = state->src_h >> 16;
+       vc4_state->src_x = state->src.x1 >> 16;
+       vc4_state->src_y = state->src.y1 >> 16;
+       vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
+       vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
 
-       vc4_state->crtc_x = state->crtc_x;
-       vc4_state->crtc_y = state->crtc_y;
-       vc4_state->crtc_w = state->crtc_w;
-       vc4_state->crtc_h = state->crtc_h;
+       vc4_state->crtc_x = state->dst.x1;
+       vc4_state->crtc_y = state->dst.y1;
+       vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
+       vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
 
        vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
                                                       vc4_state->crtc_w);
@@ -302,8 +317,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
        if (num_planes > 1) {
                vc4_state->is_yuv = true;
 
-               h_subsample = drm_format_horz_chroma_subsampling(format);
-               v_subsample = drm_format_vert_chroma_subsampling(format);
                vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
                vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
 
@@ -314,52 +327,20 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
                        vc4_get_scaling_mode(vc4_state->src_h[1],
                                             vc4_state->crtc_h);
 
-               /* YUV conversion requires that horizontal scaling be enabled,
-                * even on a plane that's otherwise 1:1. Looks like only PPF
-                * works in that case, so let's pick that one.
+               /* YUV conversion requires that horizontal scaling be enabled
+                * on the UV plane even if vc4_get_scaling_mode() returned
+                * VC4_SCALING_NONE (which can happen when the down-scaling
+                * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
+                * case.
                 */
-               if (vc4_state->is_unity)
-                       vc4_state->x_scaling[0] = VC4_SCALING_PPF;
+               if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)
+                       vc4_state->x_scaling[1] = VC4_SCALING_PPF;
        } else {
+               vc4_state->is_yuv = false;
                vc4_state->x_scaling[1] = VC4_SCALING_NONE;
                vc4_state->y_scaling[1] = VC4_SCALING_NONE;
        }
 
-       /* No configuring scaling on the cursor plane, since it gets
-          non-vblank-synced updates, and scaling requires requires
-          LBM changes which have to be vblank-synced.
-        */
-       if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
-               return -EINVAL;
-
-       /* Clamp the on-screen start x/y to 0.  The hardware doesn't
-        * support negative y, and negative x wastes bandwidth.
-        */
-       if (vc4_state->crtc_x < 0) {
-               for (i = 0; i < num_planes; i++) {
-                       u32 cpp = fb->format->cpp[i];
-                       u32 subs = ((i == 0) ? 1 : h_subsample);
-
-                       vc4_state->offsets[i] += (cpp *
-                                                 (-vc4_state->crtc_x) / subs);
-               }
-               vc4_state->src_w[0] += vc4_state->crtc_x;
-               vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
-               vc4_state->crtc_x = 0;
-       }
-
-       if (vc4_state->crtc_y < 0) {
-               for (i = 0; i < num_planes; i++) {
-                       u32 subs = ((i == 0) ? 1 : v_subsample);
-
-                       vc4_state->offsets[i] += (fb->pitches[i] *
-                                                 (-vc4_state->crtc_y) / subs);
-               }
-               vc4_state->src_h[0] += vc4_state->crtc_y;
-               vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
-               vc4_state->crtc_y = 0;
-       }
-
        return 0;
 }
 
@@ -400,10 +381,13 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
        u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
        u32 lbm;
 
+       /* LBM is not needed when there's no vertical scaling. */
+       if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
+           vc4_state->y_scaling[1] == VC4_SCALING_NONE)
+               return 0;
+
        if (!vc4_state->is_yuv) {
-               if (vc4_state->is_unity)
-                       return 0;
-               else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
+               if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
                        lbm = pix_per_line * 8;
                else {
                        /* In special cases, this multiplier might be 12. */
@@ -454,6 +438,43 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state,
        }
 }
 
+static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
+{
+       struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
+       struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+       unsigned long irqflags;
+       u32 lbm_size;
+
+       lbm_size = vc4_lbm_size(state);
+       if (!lbm_size)
+               return 0;
+
+       if (WARN_ON(!vc4_state->lbm_offset))
+               return -EINVAL;
+
+       /* Allocate the LBM memory that the HVS will use for temporary
+        * storage due to our scaling/format conversion.
+        */
+       if (!vc4_state->lbm.allocated) {
+               int ret;
+
+               spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
+               ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
+                                                &vc4_state->lbm,
+                                                lbm_size, 32, 0, 0);
+               spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
+
+               if (ret)
+                       return ret;
+       } else {
+               WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
+       }
+
+       vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
+
+       return 0;
+}
+
 /* Writes out a full display list for an active plane to the plane's
  * private dlist state.
  */
@@ -467,34 +488,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
        u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
        int num_planes = drm_format_num_planes(format->drm);
+       u32 h_subsample, v_subsample;
        bool mix_plane_alpha;
        bool covers_screen;
        u32 scl0, scl1, pitch0;
-       u32 lbm_size, tiling;
-       unsigned long irqflags;
+       u32 tiling;
        u32 hvs_format = format->hvs;
        int ret, i;
 
-       ret = vc4_plane_setup_clipping_and_scaling(state);
-       if (ret)
-               return ret;
-
-       /* Allocate the LBM memory that the HVS will use for temporary
-        * storage due to our scaling/format conversion.
-        */
-       lbm_size = vc4_lbm_size(state);
-       if (lbm_size) {
-               if (!vc4_state->lbm.allocated) {
-                       spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
-                       ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
-                                                        &vc4_state->lbm,
-                                                        lbm_size, 32, 0, 0);
-                       spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
-               } else {
-                       WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
-               }
-       }
+       if (vc4_state->dlist_initialized)
+               return 0;
 
+       ret = vc4_plane_setup_clipping_and_scaling(state);
        if (ret)
                return ret;
 
@@ -512,26 +517,77 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                scl1 = vc4_get_scl_field(state, 0);
        }
 
+       h_subsample = drm_format_horz_chroma_subsampling(format->drm);
+       v_subsample = drm_format_vert_chroma_subsampling(format->drm);
+
        switch (base_format_mod) {
        case DRM_FORMAT_MOD_LINEAR:
                tiling = SCALER_CTL0_TILING_LINEAR;
                pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
+
+               /* Adjust the base pointer to the first pixel to be scanned
+                * out.
+                */
+               for (i = 0; i < num_planes; i++) {
+                       vc4_state->offsets[i] += vc4_state->src_y /
+                                                (i ? v_subsample : 1) *
+                                                fb->pitches[i];
+                       vc4_state->offsets[i] += vc4_state->src_x /
+                                                (i ? h_subsample : 1) *
+                                                fb->format->cpp[i];
+               }
+
                break;
 
        case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
-               /* For T-tiled, the FB pitch is "how many bytes from
-                * one row to the next, such that pitch * tile_h ==
-                * tile_size * tiles_per_row."
-                */
                u32 tile_size_shift = 12; /* T tiles are 4kb */
+               /* Whole-tile offsets, mostly for setting the pitch. */
+               u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
                u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
+               u32 tile_w_mask = (1 << tile_w_shift) - 1;
+               /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
+                * the height (in pixels) of a 4k tile.
+                */
+               u32 tile_h_mask = (2 << tile_h_shift) - 1;
+               /* For T-tiled, the FB pitch is "how many bytes from one row to
+                * the next, such that
+                *
+                *      pitch * tile_h == tile_size * tiles_per_row
+                */
                u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
+               u32 tiles_l = vc4_state->src_x >> tile_w_shift;
+               u32 tiles_r = tiles_w - tiles_l;
+               u32 tiles_t = vc4_state->src_y >> tile_h_shift;
+               /* Intra-tile offsets, which modify the base address (the
+                * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
+                * base address).
+                */
+               u32 tile_y = (vc4_state->src_y >> 4) & 1;
+               u32 subtile_y = (vc4_state->src_y >> 2) & 3;
+               u32 utile_y = vc4_state->src_y & 3;
+               u32 x_off = vc4_state->src_x & tile_w_mask;
+               u32 y_off = vc4_state->src_y & tile_h_mask;
 
                tiling = SCALER_CTL0_TILING_256B_OR_T;
+               pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
+                         VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
+                         VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
+                         VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
+               vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
+               vc4_state->offsets[0] += subtile_y << 8;
+               vc4_state->offsets[0] += utile_y << 4;
+
+               /* Rows of tiles alternate left-to-right and right-to-left. */
+               if (tiles_t & 1) {
+                       pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
+                       vc4_state->offsets[0] += (tiles_w - tiles_l) <<
+                                                tile_size_shift;
+                       vc4_state->offsets[0] -= (1 + !tile_y) << 10;
+               } else {
+                       vc4_state->offsets[0] += tiles_l << tile_size_shift;
+                       vc4_state->offsets[0] += tile_y << 10;
+               }
 
-               pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
-                         VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
-                         VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
                break;
        }
 
@@ -667,15 +723,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
        }
 
+       vc4_state->lbm_offset = 0;
+
        if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
            vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
            vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
            vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
-               /* LBM Base Address. */
+               /* Reserve a slot for the LBM Base Address. The real value will
+                * be set when calling vc4_plane_allocate_lbm().
+                */
                if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
-                   vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
-                       vc4_dlist_write(vc4_state, vc4_state->lbm.start);
-               }
+                   vc4_state->y_scaling[1] != VC4_SCALING_NONE)
+                       vc4_state->lbm_offset = vc4_state->dlist_count++;
 
                if (num_planes > 1) {
                        /* Emit Cb/Cr as channel 0 and Y as channel
@@ -721,6 +780,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
                                   state->alpha != DRM_BLEND_ALPHA_OPAQUE;
 
+       /* Flag the dlist as initialized to avoid checking it twice in case
+        * the async update check already called vc4_plane_mode_set() and
+        * decided to fallback to sync update because async update was not
+        * possible.
+        */
+       vc4_state->dlist_initialized = 1;
+
        return 0;
 }
 
@@ -735,13 +801,18 @@ static int vc4_plane_atomic_check(struct drm_plane *plane,
                                  struct drm_plane_state *state)
 {
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
+       int ret;
 
        vc4_state->dlist_count = 0;
 
-       if (plane_enabled(state))
-               return vc4_plane_mode_set(plane, state);
-       else
+       if (!plane_enabled(state))
                return 0;
+
+       ret = vc4_plane_mode_set(plane, state);
+       if (ret)
+               return ret;
+
+       return vc4_plane_allocate_lbm(state);
 }
 
 static void vc4_plane_atomic_update(struct drm_plane *plane,
@@ -809,30 +880,50 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
 {
        struct vc4_plane_state *vc4_state, *new_vc4_state;
 
-       if (plane->state->fb != state->fb) {
-               vc4_plane_async_set_fb(plane, state->fb);
-               drm_atomic_set_fb_for_plane(plane->state, state->fb);
-       }
-
-       /* Set the cursor's position on the screen.  This is the
-        * expected change from the drm_mode_cursor_universal()
-        * helper.
-        */
+       drm_atomic_set_fb_for_plane(plane->state, state->fb);
        plane->state->crtc_x = state->crtc_x;
        plane->state->crtc_y = state->crtc_y;
-
-       /* Allow changing the start position within the cursor BO, if
-        * that matters.
-        */
+       plane->state->crtc_w = state->crtc_w;
+       plane->state->crtc_h = state->crtc_h;
        plane->state->src_x = state->src_x;
        plane->state->src_y = state->src_y;
-
-       /* Update the display list based on the new crtc_x/y. */
-       vc4_plane_atomic_check(plane, state);
+       plane->state->src_w = state->src_w;
+       plane->state->src_h = state->src_h;
+       plane->state->src_h = state->src_h;
+       plane->state->alpha = state->alpha;
+       plane->state->pixel_blend_mode = state->pixel_blend_mode;
+       plane->state->rotation = state->rotation;
+       plane->state->zpos = state->zpos;
+       plane->state->normalized_zpos = state->normalized_zpos;
+       plane->state->color_encoding = state->color_encoding;
+       plane->state->color_range = state->color_range;
+       plane->state->src = state->src;
+       plane->state->dst = state->dst;
+       plane->state->visible = state->visible;
 
        new_vc4_state = to_vc4_plane_state(state);
        vc4_state = to_vc4_plane_state(plane->state);
 
+       vc4_state->crtc_x = new_vc4_state->crtc_x;
+       vc4_state->crtc_y = new_vc4_state->crtc_y;
+       vc4_state->crtc_h = new_vc4_state->crtc_h;
+       vc4_state->crtc_w = new_vc4_state->crtc_w;
+       vc4_state->src_x = new_vc4_state->src_x;
+       vc4_state->src_y = new_vc4_state->src_y;
+       memcpy(vc4_state->src_w, new_vc4_state->src_w,
+              sizeof(vc4_state->src_w));
+       memcpy(vc4_state->src_h, new_vc4_state->src_h,
+              sizeof(vc4_state->src_h));
+       memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,
+              sizeof(vc4_state->x_scaling));
+       memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,
+              sizeof(vc4_state->y_scaling));
+       vc4_state->is_unity = new_vc4_state->is_unity;
+       vc4_state->is_yuv = new_vc4_state->is_yuv;
+       memcpy(vc4_state->offsets, new_vc4_state->offsets,
+              sizeof(vc4_state->offsets));
+       vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;
+
        /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
        vc4_state->dlist[vc4_state->pos0_offset] =
                new_vc4_state->dlist[vc4_state->pos0_offset];
@@ -856,13 +947,38 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
 static int vc4_plane_atomic_async_check(struct drm_plane *plane,
                                        struct drm_plane_state *state)
 {
-       /* No configuring new scaling in the fast path. */
-       if (plane->state->crtc_w != state->crtc_w ||
-           plane->state->crtc_h != state->crtc_h ||
-           plane->state->src_w != state->src_w ||
-           plane->state->src_h != state->src_h)
+       struct vc4_plane_state *old_vc4_state, *new_vc4_state;
+       int ret;
+       u32 i;
+
+       ret = vc4_plane_mode_set(plane, state);
+       if (ret)
+               return ret;
+
+       old_vc4_state = to_vc4_plane_state(plane->state);
+       new_vc4_state = to_vc4_plane_state(state);
+       if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||
+           old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||
+           old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||
+           old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset ||
+           vc4_lbm_size(plane->state) != vc4_lbm_size(state))
                return -EINVAL;
 
+       /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
+        * if anything else has changed, fallback to a sync update.
+        */
+       for (i = 0; i < new_vc4_state->dlist_count; i++) {
+               if (i == new_vc4_state->pos0_offset ||
+                   i == new_vc4_state->pos2_offset ||
+                   i == new_vc4_state->ptr0_offset ||
+                   (new_vc4_state->lbm_offset &&
+                    i == new_vc4_state->lbm_offset))
+                       continue;
+
+               if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -914,7 +1030,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
 
 static void vc4_plane_destroy(struct drm_plane *plane)
 {
-       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 }
 
@@ -980,7 +1095,6 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
        struct drm_plane *plane = NULL;
        struct vc4_plane *vc4_plane;
        u32 formats[ARRAY_SIZE(hvs_formats)];
-       u32 num_formats = 0;
        int ret = 0;
        unsigned i;
        static const uint64_t modifiers[] = {
@@ -997,20 +1111,13 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
        if (!vc4_plane)
                return ERR_PTR(-ENOMEM);
 
-       for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
-               /* Don't allow YUV in cursor planes, since that means
-                * tuning on the scaler, which we don't allow for the
-                * cursor.
-                */
-               if (type != DRM_PLANE_TYPE_CURSOR ||
-                   hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) {
-                       formats[num_formats++] = hvs_formats[i].drm;
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
+               formats[i] = hvs_formats[i].drm;
+
        plane = &vc4_plane->base;
        ret = drm_universal_plane_init(dev, plane, 0,
                                       &vc4_plane_funcs,
-                                      formats, num_formats,
+                                      formats, ARRAY_SIZE(formats),
                                       modifiers, type, NULL);
 
        drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
index d6864fa4bd141d032a4cfb730841e16e8321d192..931088014272438e2a15293543c0eb2dcbbef08f 100644 (file)
@@ -1037,14 +1037,18 @@ enum hvs_pixel_format {
 #define SCALER_TILE_HEIGHT_MASK                        VC4_MASK(15, 0)
 #define SCALER_TILE_HEIGHT_SHIFT               0
 
+/* Common PITCH0 fields */
+#define SCALER_PITCH0_SINK_PIX_MASK            VC4_MASK(31, 26)
+#define SCALER_PITCH0_SINK_PIX_SHIFT           26
+
 /* PITCH0 fields for T-tiled. */
 #define SCALER_PITCH0_TILE_WIDTH_L_MASK                VC4_MASK(22, 16)
 #define SCALER_PITCH0_TILE_WIDTH_L_SHIFT       16
 #define SCALER_PITCH0_TILE_LINE_DIR            BIT(15)
 #define SCALER_PITCH0_TILE_INITIAL_LINE_DIR    BIT(14)
 /* Y offset within a tile. */
-#define SCALER_PITCH0_TILE_Y_OFFSET_MASK       VC4_MASK(13, 7)
-#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT      7
+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK       VC4_MASK(13, 8)
+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT      8
 #define SCALER_PITCH0_TILE_WIDTH_R_MASK                VC4_MASK(6, 0)
 #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT       0
 
index ec6af8b920daa222917f9514cd3dbe9c2b9370e9..5930facd6d2d85cca81cb9c1f5247a6be3632546 100644 (file)
@@ -431,7 +431,8 @@ static void vgem_release(struct drm_device *dev)
 }
 
 static struct drm_driver vgem_driver = {
-       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
+       .driver_features                = DRIVER_GEM | DRIVER_PRIME |
+                                         DRIVER_RENDER,
        .release                        = vgem_release,
        .open                           = vgem_open,
        .postclose                      = vgem_postclose,
@@ -471,31 +472,31 @@ static int __init vgem_init(void)
        if (!vgem_device)
                return -ENOMEM;
 
-       ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL);
-       if (ret)
-               goto out_free;
-
        vgem_device->platform =
                platform_device_register_simple("vgem", -1, NULL, 0);
        if (IS_ERR(vgem_device->platform)) {
                ret = PTR_ERR(vgem_device->platform);
-               goto out_fini;
+               goto out_free;
        }
 
        dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
                                     DMA_BIT_MASK(64));
+       ret = drm_dev_init(&vgem_device->drm, &vgem_driver,
+                          &vgem_device->platform->dev);
+       if (ret)
+               goto out_unregister;
 
        /* Final step: expose the device/driver to userspace */
        ret  = drm_dev_register(&vgem_device->drm, 0);
        if (ret)
-               goto out_unregister;
+               goto out_fini;
 
        return 0;
 
-out_unregister:
-       platform_device_unregister(vgem_device->platform);
 out_fini:
        drm_dev_fini(&vgem_device->drm);
+out_unregister:
+       platform_device_unregister(vgem_device->platform);
 out_free:
        kfree(vgem_device);
        return ret;
index e6ee71323a66bfe762a1aa7c3294ad0aa08cc657..c1c420afe2dd130af9b4faf1df1fa649c1820f92 100644 (file)
@@ -180,7 +180,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
        reservation_object_lock(resv, NULL);
        if (arg->flags & VGEM_FENCE_WRITE)
                reservation_object_add_excl_fence(resv, fence);
-       else if ((ret = reservation_object_reserve_shared(resv)) == 0)
+       else if ((ret = reservation_object_reserve_shared(resv, 1)) == 0)
                reservation_object_add_shared_fence(resv, fence);
        reservation_object_unlock(resv);
 
index 8f8fed471e34b296d7d2efce36deb877656e61a6..b5580b11a063606e79d8d43005b4cf4423ef5629 100644 (file)
@@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
        struct drm_display_mode *mode = NULL;
        int count, width, height;
 
+       if (output->edid) {
+               count = drm_add_edid_modes(connector, output->edid);
+               if (count)
+                       return count;
+       }
+
        width  = le32_to_cpu(output->info.r.width);
        height = le32_to_cpu(output->info.r.height);
        count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
@@ -287,6 +293,8 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)
        drm_connector_init(dev, connector, &virtio_gpu_connector_funcs,
                           DRM_MODE_CONNECTOR_VIRTUAL);
        drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs);
+       if (vgdev->has_edid)
+               drm_connector_attach_edid_property(connector);
 
        drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,
                         DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
 
 void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev)
 {
+       int i;
+
+       for (i = 0 ; i < vgdev->num_scanouts; ++i)
+               kfree(vgdev->outputs[i].edid);
        virtio_gpu_fbdev_fini(vgdev);
        drm_mode_config_cleanup(vgdev->ddev);
 }
index 757ca28ab93e439a860d9b6fe59dfa862febbdf3..0887e0b64b9cf537d6e81a4a6afdf307bc48126d 100644 (file)
@@ -53,6 +53,37 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
                                                                          0,
                                                                          "virtiodrmfb");
 
+               /*
+                * Normally the drm_dev_set_unique() call is done by core DRM.
+                * The following comment covers, why virtio cannot rely on it.
+                *
+                * Unlike the other virtual GPU drivers, virtio abstracts the
+                * underlying bus type by using struct virtio_device.
+                *
+                * Hence the dev_is_pci() check, used in core DRM, will fail
+                * and the unique returned will be the virtio_device "virtio0",
+                * while a "pci:..." one is required.
+                *
+                * A few other ideas were considered:
+                * - Extend the dev_is_pci() check [in drm_set_busid] to
+                *   consider virtio.
+                *   Seems like a bigger hack than what we have already.
+                *
+                * - Point drm_device::dev to the parent of the virtio_device
+                *   Semantic changes:
+                *   * Using the wrong device for i2c, framebuffer_alloc and
+                *     prime import.
+                *   Visual changes:
+                *   * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer,
+                *     will print the wrong information.
+                *
+                * We could address the latter issues, by introducing
+                * drm_device::bus_dev, ... which would be used solely for this.
+                *
+                * So for the moment keep things as-is, with a bulky comment
+                * for the next person who feels like removing this
+                * drm_dev_set_unique() quirk.
+                */
                snprintf(unique, sizeof(unique), "pci:%s", pname);
                ret = drm_dev_set_unique(dev, unique);
                if (ret)
index d9287c144fe5ea11d15d24aff55c5bf1d2ce2cdd..f7f32a885af79902a4c02ce4c4c801c1a119cc83 100644 (file)
@@ -80,6 +80,7 @@ static unsigned int features[] = {
         */
        VIRTIO_GPU_F_VIRGL,
 #endif
+       VIRTIO_GPU_F_EDID,
 };
 static struct virtio_driver virtio_gpu_driver = {
        .feature_table = features,
index d29f0c7c768c199b7e959883becf6f893d54ee9a..1deb41d42ea4d2ffa7d08a06c15d411be556cce4 100644 (file)
@@ -47,8 +47,8 @@
 #define DRIVER_DATE "0"
 
 #define DRIVER_MAJOR 0
-#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 1
+#define DRIVER_MINOR 1
+#define DRIVER_PATCHLEVEL 0
 
 /* virtgpu_drm_bus.c */
 int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev);
@@ -65,6 +65,7 @@ struct virtio_gpu_object {
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
+       bool created;
 };
 #define gem_to_virtio_gpu_obj(gobj) \
        container_of((gobj), struct virtio_gpu_object, gem_base)
@@ -114,6 +115,7 @@ struct virtio_gpu_output {
        struct drm_encoder enc;
        struct virtio_gpu_display_one info;
        struct virtio_gpu_update_cursor cursor;
+       struct edid *edid;
        int cur_x;
        int cur_y;
        bool enabled;
@@ -130,6 +132,7 @@ struct virtio_gpu_framebuffer {
        int x1, y1, x2, y2; /* dirty rect */
        spinlock_t dirty_lock;
        uint32_t hw_res_handle;
+       struct virtio_gpu_fence *fence;
 };
 #define to_virtio_gpu_framebuffer(x) \
        container_of(x, struct virtio_gpu_framebuffer, base)
@@ -142,9 +145,6 @@ struct virtio_gpu_fbdev {
 };
 
 struct virtio_gpu_mman {
-       struct ttm_bo_global_ref        bo_global_ref;
-       struct drm_global_reference     mem_global_ref;
-       bool                            mem_global_referenced;
        struct ttm_bo_device            bdev;
 };
 
@@ -190,8 +190,7 @@ struct virtio_gpu_device {
        struct kmem_cache *vbufs;
        bool vqs_ready;
 
-       struct idr      resource_idr;
-       spinlock_t resource_idr_lock;
+       struct ida      resource_ida;
 
        wait_queue_head_t resp_wq;
        /* current display info */
@@ -200,10 +199,10 @@ struct virtio_gpu_device {
 
        struct virtio_gpu_fence_driver fence_drv;
 
-       struct idr      ctx_id_idr;
-       spinlock_t ctx_id_idr_lock;
+       struct ida      ctx_id_ida;
 
        bool has_virgl_3d;
+       bool has_edid;
 
        struct work_struct config_changed_work;
 
@@ -259,11 +258,8 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *qfb,
 /* virtio vg */
 int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
 void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev);
-void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
-                              uint32_t *resid);
-void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id);
 void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
-                                   uint32_t resource_id,
+                                   struct virtio_gpu_object *bo,
                                    uint32_t format,
                                    uint32_t width,
                                    uint32_t height);
@@ -274,7 +270,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
                                        uint64_t offset,
                                        __le32 width, __le32 height,
                                        __le32 x, __le32 y,
-                                       struct virtio_gpu_fence **fence);
+                                       struct virtio_gpu_fence *fence);
 void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev,
                                   uint32_t resource_id,
                                   uint32_t x, uint32_t y,
@@ -285,8 +281,7 @@ void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
                                uint32_t x, uint32_t y);
 int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
                             struct virtio_gpu_object *obj,
-                            uint32_t resource_id,
-                            struct virtio_gpu_fence **fence);
+                            struct virtio_gpu_fence *fence);
 void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
                              struct virtio_gpu_object *obj);
 int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev);
@@ -298,6 +293,7 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx);
 int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
                              int idx, int version,
                              struct virtio_gpu_drv_cap_cache **cache_p);
+int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev);
 void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
                                   uint32_t nlen, const char *name);
 void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev,
@@ -310,22 +306,22 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev,
                                            uint32_t resource_id);
 void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
                           void *data, uint32_t data_size,
-                          uint32_t ctx_id, struct virtio_gpu_fence **fence);
+                          uint32_t ctx_id, struct virtio_gpu_fence *fence);
 void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
                                          uint32_t resource_id, uint32_t ctx_id,
                                          uint64_t offset, uint32_t level,
                                          struct virtio_gpu_box *box,
-                                         struct virtio_gpu_fence **fence);
+                                         struct virtio_gpu_fence *fence);
 void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
                                        struct virtio_gpu_object *bo,
                                        uint32_t ctx_id,
                                        uint64_t offset, uint32_t level,
                                        struct virtio_gpu_box *box,
-                                       struct virtio_gpu_fence **fence);
+                                       struct virtio_gpu_fence *fence);
 void
 virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
-                                 struct virtio_gpu_resource_create_3d *rc_3d,
-                                 struct virtio_gpu_fence **fence);
+                                 struct virtio_gpu_object *bo,
+                                 struct virtio_gpu_resource_create_3d *rc_3d);
 void virtio_gpu_ctrl_ack(struct virtqueue *vq);
 void virtio_gpu_cursor_ack(struct virtqueue *vq);
 void virtio_gpu_fence_ack(struct virtqueue *vq);
@@ -353,9 +349,12 @@ void virtio_gpu_ttm_fini(struct virtio_gpu_device *vgdev);
 int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma);
 
 /* virtio_gpu_fence.c */
+struct virtio_gpu_fence *virtio_gpu_fence_alloc(
+       struct virtio_gpu_device *vgdev);
+void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence);
 int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
                          struct virtio_gpu_ctrl_hdr *cmd_hdr,
-                         struct virtio_gpu_fence **fence);
+                         struct virtio_gpu_fence *fence);
 void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev,
                                    u64 last_seq);
 
index cea749f4ec3930886f8c9f0dc14287bfccfd77c0..fb1cc8b2f119d9aadd794583c500f9715c1525fa 100644 (file)
@@ -214,7 +214,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd = {};
        struct virtio_gpu_object *obj;
-       uint32_t resid, format, size;
+       uint32_t format, size;
        int ret;
 
        mode_cmd.width = sizes->surface_width;
@@ -231,8 +231,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        if (IS_ERR(obj))
                return PTR_ERR(obj);
 
-       virtio_gpu_resource_id_get(vgdev, &resid);
-       virtio_gpu_cmd_create_resource(vgdev, resid, format,
+       virtio_gpu_cmd_create_resource(vgdev, obj, format,
                                       mode_cmd.width, mode_cmd.height);
 
        ret = virtio_gpu_object_kmap(obj);
@@ -242,7 +241,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
        }
 
        /* attach the object to the resource */
-       ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
+       ret = virtio_gpu_object_attach(vgdev, obj, NULL);
        if (ret)
                goto err_obj_attach;
 
index 00c742a441bfc546b2369b55bebd0a0f9bec6e05..4d6826b27814ee3002eb119216c2cc569ea880c2 100644 (file)
@@ -67,28 +67,43 @@ static const struct dma_fence_ops virtio_fence_ops = {
        .timeline_value_str  = virtio_timeline_value_str,
 };
 
+struct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev)
+{
+       struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
+       struct virtio_gpu_fence *fence = kzalloc(sizeof(struct virtio_gpu_fence),
+                                                       GFP_ATOMIC);
+       if (!fence)
+               return fence;
+
+       fence->drv = drv;
+       dma_fence_init(&fence->f, &virtio_fence_ops, &drv->lock, drv->context, 0);
+
+       return fence;
+}
+
+void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence)
+{
+       if (!fence)
+               return;
+
+       dma_fence_put(&fence->f);
+}
+
 int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
                          struct virtio_gpu_ctrl_hdr *cmd_hdr,
-                         struct virtio_gpu_fence **fence)
+                         struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
        unsigned long irq_flags;
 
-       *fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_ATOMIC);
-       if ((*fence) == NULL)
-               return -ENOMEM;
-
        spin_lock_irqsave(&drv->lock, irq_flags);
-       (*fence)->drv = drv;
-       (*fence)->seq = ++drv->sync_seq;
-       dma_fence_init(&(*fence)->f, &virtio_fence_ops, &drv->lock,
-                      drv->context, (*fence)->seq);
-       dma_fence_get(&(*fence)->f);
-       list_add_tail(&(*fence)->node, &drv->fences);
+       fence->seq = ++drv->sync_seq;
+       dma_fence_get(&fence->f);
+       list_add_tail(&fence->node, &drv->fences);
        spin_unlock_irqrestore(&drv->lock, irq_flags);
 
        cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE);
-       cmd_hdr->fence_id = cpu_to_le64((*fence)->seq);
+       cmd_hdr->fence_id = cpu_to_le64(fence->seq);
        return 0;
 }
 
index 82c817f37cf7d68ebe2cf72fe022978fb1b02291..f0658639397475f40800622091aef258ce759139 100644 (file)
@@ -87,7 +87,6 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
        struct virtio_gpu_object *obj;
        int ret;
        uint32_t pitch;
-       uint32_t resid;
        uint32_t format;
 
        if (args->bpp != 32)
@@ -103,13 +102,12 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
                goto fail;
 
        format = virtio_gpu_translate_format(DRM_FORMAT_HOST_XRGB8888);
-       virtio_gpu_resource_id_get(vgdev, &resid);
-       virtio_gpu_cmd_create_resource(vgdev, resid, format,
+       obj = gem_to_virtio_gpu_obj(gobj);
+       virtio_gpu_cmd_create_resource(vgdev, obj, format,
                                       args->width, args->height);
 
        /* attach the object to the resource */
-       obj = gem_to_virtio_gpu_obj(gobj);
-       ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
+       ret = virtio_gpu_object_attach(vgdev, obj, NULL);
        if (ret)
                goto fail;
 
index f16b875d6a46b32c4c8a6a3694aaec05da3727f7..161b80fee492564346262d954a0bb8d9864aaae4 100644 (file)
@@ -28,6 +28,7 @@
 #include <drm/drmP.h>
 #include <drm/virtgpu_drm.h>
 #include <drm/ttm/ttm_execbuf_util.h>
+#include <linux/sync_file.h>
 
 #include "virtgpu_drv.h"
 
@@ -105,7 +106,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_fpriv *vfpriv = drm_file->driver_priv;
        struct drm_gem_object *gobj;
-       struct virtio_gpu_fence *fence;
+       struct virtio_gpu_fence *out_fence;
        struct virtio_gpu_object *qobj;
        int ret;
        uint32_t *bo_handles = NULL;
@@ -114,11 +115,46 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
        struct ttm_validate_buffer *buflist = NULL;
        int i;
        struct ww_acquire_ctx ticket;
+       struct sync_file *sync_file;
+       int in_fence_fd = exbuf->fence_fd;
+       int out_fence_fd = -1;
        void *buf;
 
        if (vgdev->has_virgl_3d == false)
                return -ENOSYS;
 
+       if ((exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS))
+               return -EINVAL;
+
+       exbuf->fence_fd = -1;
+
+       if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) {
+               struct dma_fence *in_fence;
+
+               in_fence = sync_file_get_fence(in_fence_fd);
+
+               if (!in_fence)
+                       return -EINVAL;
+
+               /*
+                * Wait if the fence is from a foreign context, or if the fence
+                * array contains any fence from a foreign context.
+                */
+               ret = 0;
+               if (!dma_fence_match_context(in_fence, vgdev->fence_drv.context))
+                       ret = dma_fence_wait(in_fence, true);
+
+               dma_fence_put(in_fence);
+               if (ret)
+                       return ret;
+       }
+
+       if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) {
+               out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
+               if (out_fence_fd < 0)
+                       return out_fence_fd;
+       }
+
        INIT_LIST_HEAD(&validate_list);
        if (exbuf->num_bo_handles) {
 
@@ -128,26 +164,22 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
                                           sizeof(struct ttm_validate_buffer),
                                           GFP_KERNEL | __GFP_ZERO);
                if (!bo_handles || !buflist) {
-                       kvfree(bo_handles);
-                       kvfree(buflist);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto out_unused_fd;
                }
 
                user_bo_handles = (void __user *)(uintptr_t)exbuf->bo_handles;
                if (copy_from_user(bo_handles, user_bo_handles,
                                   exbuf->num_bo_handles * sizeof(uint32_t))) {
                        ret = -EFAULT;
-                       kvfree(bo_handles);
-                       kvfree(buflist);
-                       return ret;
+                       goto out_unused_fd;
                }
 
                for (i = 0; i < exbuf->num_bo_handles; i++) {
                        gobj = drm_gem_object_lookup(drm_file, bo_handles[i]);
                        if (!gobj) {
-                               kvfree(bo_handles);
-                               kvfree(buflist);
-                               return -ENOENT;
+                               ret = -ENOENT;
+                               goto out_unused_fd;
                        }
 
                        qobj = gem_to_virtio_gpu_obj(gobj);
@@ -156,6 +188,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
                        list_add(&buflist[i].head, &validate_list);
                }
                kvfree(bo_handles);
+               bo_handles = NULL;
        }
 
        ret = virtio_gpu_object_list_validate(&ticket, &validate_list);
@@ -168,22 +201,48 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
                ret = PTR_ERR(buf);
                goto out_unresv;
        }
+
+       out_fence = virtio_gpu_fence_alloc(vgdev);
+       if(!out_fence) {
+               ret = -ENOMEM;
+               goto out_memdup;
+       }
+
+       if (out_fence_fd >= 0) {
+               sync_file = sync_file_create(&out_fence->f);
+               if (!sync_file) {
+                       dma_fence_put(&out_fence->f);
+                       ret = -ENOMEM;
+                       goto out_memdup;
+               }
+
+               exbuf->fence_fd = out_fence_fd;
+               fd_install(out_fence_fd, sync_file->file);
+       }
+
        virtio_gpu_cmd_submit(vgdev, buf, exbuf->size,
-                             vfpriv->ctx_id, &fence);
+                             vfpriv->ctx_id, out_fence);
 
-       ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f);
+       ttm_eu_fence_buffer_objects(&ticket, &validate_list, &out_fence->f);
 
        /* fence the command bo */
        virtio_gpu_unref_list(&validate_list);
        kvfree(buflist);
-       dma_fence_put(&fence->f);
        return 0;
 
+out_memdup:
+       kfree(buf);
 out_unresv:
        ttm_eu_backoff_reservation(&ticket, &validate_list);
 out_free:
        virtio_gpu_unref_list(&validate_list);
+out_unused_fd:
+       kvfree(bo_handles);
        kvfree(buflist);
+
+       if (out_fence_fd >= 0)
+               put_unused_fd(out_fence_fd);
+
        return ret;
 }
 
@@ -217,7 +276,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct drm_virtgpu_resource_create *rc = data;
        int ret;
-       uint32_t res_id;
        struct virtio_gpu_object *qobj;
        struct drm_gem_object *obj;
        uint32_t handle = 0;
@@ -244,8 +302,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
        INIT_LIST_HEAD(&validate_list);
        memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer));
 
-       virtio_gpu_resource_id_get(vgdev, &res_id);
-
        size = rc->size;
 
        /* allocate a single page size object */
@@ -253,17 +309,15 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
                size = PAGE_SIZE;
 
        qobj = virtio_gpu_alloc_object(dev, size, false, false);
-       if (IS_ERR(qobj)) {
-               ret = PTR_ERR(qobj);
-               goto fail_id;
-       }
+       if (IS_ERR(qobj))
+               return PTR_ERR(qobj);
        obj = &qobj->gem_base;
 
        if (!vgdev->has_virgl_3d) {
-               virtio_gpu_cmd_create_resource(vgdev, res_id, rc->format,
+               virtio_gpu_cmd_create_resource(vgdev, qobj, rc->format,
                                               rc->width, rc->height);
 
-               ret = virtio_gpu_object_attach(vgdev, qobj, res_id, NULL);
+               ret = virtio_gpu_object_attach(vgdev, qobj, NULL);
        } else {
                /* use a gem reference since unref list undoes them */
                drm_gem_object_get(&qobj->gem_base);
@@ -276,7 +330,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
                        goto fail_unref;
                }
 
-               rc_3d.resource_id = cpu_to_le32(res_id);
+               rc_3d.resource_id = cpu_to_le32(qobj->hw_res_handle);
                rc_3d.target = cpu_to_le32(rc->target);
                rc_3d.format = cpu_to_le32(rc->format);
                rc_3d.bind = cpu_to_le32(rc->bind);
@@ -288,17 +342,21 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
                rc_3d.nr_samples = cpu_to_le32(rc->nr_samples);
                rc_3d.flags = cpu_to_le32(rc->flags);
 
-               virtio_gpu_cmd_resource_create_3d(vgdev, &rc_3d, NULL);
-               ret = virtio_gpu_object_attach(vgdev, qobj, res_id, &fence);
+               fence = virtio_gpu_fence_alloc(vgdev);
+               if (!fence) {
+                       ret = -ENOMEM;
+                       goto fail_backoff;
+               }
+
+               virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d);
+               ret = virtio_gpu_object_attach(vgdev, qobj, fence);
                if (ret) {
-                       ttm_eu_backoff_reservation(&ticket, &validate_list);
-                       goto fail_unref;
+                       virtio_gpu_fence_cleanup(fence);
+                       goto fail_backoff;
                }
                ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f);
        }
 
-       qobj->hw_res_handle = res_id;
-
        ret = drm_gem_handle_create(file_priv, obj, &handle);
        if (ret) {
 
@@ -311,7 +369,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
        }
        drm_gem_object_put_unlocked(obj);
 
-       rc->res_handle = res_id; /* similiar to a VM address */
+       rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
        rc->bo_handle = handle;
 
        if (vgdev->has_virgl_3d) {
@@ -319,6 +377,8 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
                dma_fence_put(&fence->f);
        }
        return 0;
+fail_backoff:
+       ttm_eu_backoff_reservation(&ticket, &validate_list);
 fail_unref:
        if (vgdev->has_virgl_3d) {
                virtio_gpu_unref_list(&validate_list);
@@ -326,8 +386,6 @@ fail_unref:
        }
 //fail_obj:
 //     drm_gem_object_handle_unreference_unlocked(obj);
-fail_id:
-       virtio_gpu_resource_id_put(vgdev, res_id);
        return ret;
 }
 
@@ -383,10 +441,16 @@ static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev,
                goto out_unres;
 
        convert_to_hw_box(&box, &args->box);
+
+       fence = virtio_gpu_fence_alloc(vgdev);
+       if (!fence) {
+               ret = -ENOMEM;
+               goto out_unres;
+       }
        virtio_gpu_cmd_transfer_from_host_3d
                (vgdev, qobj->hw_res_handle,
                 vfpriv->ctx_id, offset, args->level,
-                &box, &fence);
+                &box, fence);
        reservation_object_add_excl_fence(qobj->tbo.resv,
                                          &fence->f);
 
@@ -432,10 +496,15 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data,
                        (vgdev, qobj, offset,
                         box.w, box.h, box.x, box.y, NULL);
        } else {
+               fence = virtio_gpu_fence_alloc(vgdev);
+               if (!fence) {
+                       ret = -ENOMEM;
+                       goto out_unres;
+               }
                virtio_gpu_cmd_transfer_to_host_3d
                        (vgdev, qobj,
                         vfpriv ? vfpriv->ctx_id : 0, offset,
-                        args->level, &box, &fence);
+                        args->level, &box, fence);
                reservation_object_add_excl_fence(qobj->tbo.resv,
                                                  &fence->f);
                dma_fence_put(&fence->f);
index 65060c08522d79b6df6eaeabe2499d98d67d80c6..3af6181c05a852cccf91880e34388f78723e1835 100644 (file)
@@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
        virtio_cread(vgdev->vdev, struct virtio_gpu_config,
                     events_read, &events_read);
        if (events_read & VIRTIO_GPU_EVENT_DISPLAY) {
+               if (vgdev->has_edid)
+                       virtio_gpu_cmd_get_edids(vgdev);
                virtio_gpu_cmd_get_display_info(vgdev);
                drm_helper_hpd_irq_event(vgdev->ddev);
                events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
@@ -52,39 +54,23 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
                      events_clear, &events_clear);
 }
 
-static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev,
-                                 uint32_t *resid)
+static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
+                                     uint32_t nlen, const char *name)
 {
-       int handle;
-
-       idr_preload(GFP_KERNEL);
-       spin_lock(&vgdev->ctx_id_idr_lock);
-       handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0);
-       spin_unlock(&vgdev->ctx_id_idr_lock);
-       idr_preload_end();
-       *resid = handle;
-}
+       int handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL);
 
-static void virtio_gpu_ctx_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
-{
-       spin_lock(&vgdev->ctx_id_idr_lock);
-       idr_remove(&vgdev->ctx_id_idr, id);
-       spin_unlock(&vgdev->ctx_id_idr_lock);
-}
-
-static void virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
-                                     uint32_t nlen, const char *name,
-                                     uint32_t *ctx_id)
-{
-       virtio_gpu_ctx_id_get(vgdev, ctx_id);
-       virtio_gpu_cmd_context_create(vgdev, *ctx_id, nlen, name);
+       if (handle < 0)
+               return handle;
+       handle += 1;
+       virtio_gpu_cmd_context_create(vgdev, handle, nlen, name);
+       return handle;
 }
 
 static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev,
                                      uint32_t ctx_id)
 {
        virtio_gpu_cmd_context_destroy(vgdev, ctx_id);
-       virtio_gpu_ctx_id_put(vgdev, ctx_id);
+       ida_free(&vgdev->ctx_id_ida, ctx_id - 1);
 }
 
 static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
@@ -151,10 +137,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
        vgdev->dev = dev->dev;
 
        spin_lock_init(&vgdev->display_info_lock);
-       spin_lock_init(&vgdev->ctx_id_idr_lock);
-       idr_init(&vgdev->ctx_id_idr);
-       spin_lock_init(&vgdev->resource_idr_lock);
-       idr_init(&vgdev->resource_idr);
+       ida_init(&vgdev->ctx_id_ida);
+       ida_init(&vgdev->resource_ida);
        init_waitqueue_head(&vgdev->resp_wq);
        virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func);
        virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func);
@@ -174,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
 #else
        DRM_INFO("virgl 3d acceleration not supported by guest\n");
 #endif
+       if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) {
+               vgdev->has_edid = true;
+               DRM_INFO("EDID support available.\n");
+       }
 
        ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);
        if (ret) {
@@ -219,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
 
        if (num_capsets)
                virtio_gpu_get_capsets(vgdev, num_capsets);
+       if (vgdev->has_edid)
+               virtio_gpu_cmd_get_edids(vgdev);
        virtio_gpu_cmd_get_display_info(vgdev);
        wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
                           5 * HZ);
@@ -271,7 +261,7 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
 {
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_fpriv *vfpriv;
-       uint32_t id;
+       int id;
        char dbgname[TASK_COMM_LEN];
 
        /* can't create contexts without 3d renderer */
@@ -284,7 +274,11 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
                return -ENOMEM;
 
        get_task_comm(dbgname, current);
-       virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id);
+       id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname);
+       if (id < 0) {
+               kfree(vfpriv);
+               return id;
+       }
 
        vfpriv->ctx_id = id;
        file->driver_priv = vfpriv;
index eca7655374701f628990410c99f7a71ea20b5435..f39a183d59c2b1dcf678ddd31b9dc0941733fb1a 100644 (file)
 
 #include "virtgpu_drv.h"
 
+static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
+                                      uint32_t *resid)
+{
+       int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
+
+       if (handle < 0)
+               return handle;
+
+       *resid = handle + 1;
+       return 0;
+}
+
+static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
+{
+       ida_free(&vgdev->resource_ida, id - 1);
+}
+
 static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
 {
        struct virtio_gpu_object *bo;
@@ -33,13 +50,14 @@ static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        bo = container_of(tbo, struct virtio_gpu_object, tbo);
        vgdev = (struct virtio_gpu_device *)bo->gem_base.dev->dev_private;
 
-       if (bo->hw_res_handle)
+       if (bo->created)
                virtio_gpu_cmd_unref_resource(vgdev, bo->hw_res_handle);
        if (bo->pages)
                virtio_gpu_object_free_sg_table(bo);
        if (bo->vmap)
                virtio_gpu_object_kunmap(bo);
        drm_gem_object_release(&bo->gem_base);
+       virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
        kfree(bo);
 }
 
@@ -81,9 +99,15 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
        bo = kzalloc(sizeof(struct virtio_gpu_object), GFP_KERNEL);
        if (bo == NULL)
                return -ENOMEM;
+       ret = virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle);
+       if (ret < 0) {
+               kfree(bo);
+               return ret;
+       }
        size = roundup(size, PAGE_SIZE);
        ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
        if (ret != 0) {
+               virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
                kfree(bo);
                return ret;
        }
index a9f4ae7d448395a8b8596499305fe872ab0b9bbe..ead5c53d4e2163f02f9b859ca79d600ad9ae00ac 100644 (file)
@@ -137,6 +137,41 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
                                      plane->state->src_h >> 16);
 }
 
+static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane,
+                                       struct drm_plane_state *new_state)
+{
+       struct drm_device *dev = plane->dev;
+       struct virtio_gpu_device *vgdev = dev->dev_private;
+       struct virtio_gpu_framebuffer *vgfb;
+       struct virtio_gpu_object *bo;
+
+       if (!new_state->fb)
+               return 0;
+
+       vgfb = to_virtio_gpu_framebuffer(new_state->fb);
+       bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
+       if (bo && bo->dumb && (plane->state->fb != new_state->fb)) {
+               vgfb->fence = virtio_gpu_fence_alloc(vgdev);
+               if (!vgfb->fence)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void virtio_gpu_cursor_cleanup_fb(struct drm_plane *plane,
+                                        struct drm_plane_state *old_state)
+{
+       struct virtio_gpu_framebuffer *vgfb;
+
+       if (!plane->state->fb)
+               return;
+
+       vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
+       if (vgfb->fence)
+               virtio_gpu_fence_cleanup(vgfb->fence);
+}
+
 static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
                                           struct drm_plane_state *old_state)
 {
@@ -144,7 +179,6 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_output *output = NULL;
        struct virtio_gpu_framebuffer *vgfb;
-       struct virtio_gpu_fence *fence = NULL;
        struct virtio_gpu_object *bo = NULL;
        uint32_t handle;
        int ret = 0;
@@ -170,13 +204,13 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
                        (vgdev, bo, 0,
                         cpu_to_le32(plane->state->crtc_w),
                         cpu_to_le32(plane->state->crtc_h),
-                        0, 0, &fence);
+                        0, 0, vgfb->fence);
                ret = virtio_gpu_object_reserve(bo, false);
                if (!ret) {
                        reservation_object_add_excl_fence(bo->tbo.resv,
-                                                         &fence->f);
-                       dma_fence_put(&fence->f);
-                       fence = NULL;
+                                                         &vgfb->fence->f);
+                       dma_fence_put(&vgfb->fence->f);
+                       vgfb->fence = NULL;
                        virtio_gpu_object_unreserve(bo);
                        virtio_gpu_object_wait(bo, false);
                }
@@ -218,6 +252,8 @@ static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
 };
 
 static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
+       .prepare_fb             = virtio_gpu_cursor_prepare_fb,
+       .cleanup_fb             = virtio_gpu_cursor_cleanup_fb,
        .atomic_check           = virtio_gpu_plane_atomic_check,
        .atomic_update          = virtio_gpu_cursor_plane_update,
 };
index e3152d45c5f12c609defd3ddae25d793465d1ba9..4bfbf25fabff8091cab1518f5fc4302a0e4dfd56 100644 (file)
@@ -50,62 +50,6 @@ virtio_gpu_device *virtio_gpu_get_vgdev(struct ttm_bo_device *bdev)
        return vgdev;
 }
 
-static int virtio_gpu_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void virtio_gpu_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-static int virtio_gpu_ttm_global_init(struct virtio_gpu_device *vgdev)
-{
-       struct drm_global_reference *global_ref;
-       int r;
-
-       vgdev->mman.mem_global_referenced = false;
-       global_ref = &vgdev->mman.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &virtio_gpu_ttm_mem_global_init;
-       global_ref->release = &virtio_gpu_ttm_mem_global_release;
-
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM memory accounting "
-                         "subsystem.\n");
-               return r;
-       }
-
-       vgdev->mman.bo_global_ref.mem_glob =
-               vgdev->mman.mem_global_ref.object;
-       global_ref = &vgdev->mman.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       r = drm_global_item_ref(global_ref);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&vgdev->mman.mem_global_ref);
-               return r;
-       }
-
-       vgdev->mman.mem_global_referenced = true;
-       return 0;
-}
-
-static void virtio_gpu_ttm_global_fini(struct virtio_gpu_device *vgdev)
-{
-       if (vgdev->mman.mem_global_referenced) {
-               drm_global_item_unref(&vgdev->mman.bo_global_ref.ref);
-               drm_global_item_unref(&vgdev->mman.mem_global_ref);
-               vgdev->mman.mem_global_referenced = false;
-       }
-}
-
 int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *file_priv;
@@ -347,8 +291,7 @@ static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo,
 
        } else if (new_mem->placement & TTM_PL_FLAG_TT) {
                if (bo->hw_res_handle) {
-                       virtio_gpu_object_attach(vgdev, bo, bo->hw_res_handle,
-                                                NULL);
+                       virtio_gpu_object_attach(vgdev, bo, NULL);
                }
        }
 }
@@ -383,12 +326,8 @@ int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev)
 {
        int r;
 
-       r = virtio_gpu_ttm_global_init(vgdev);
-       if (r)
-               return r;
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&vgdev->mman.bdev,
-                              vgdev->mman.bo_global_ref.ref.object,
                               &virtio_gpu_bo_driver,
                               vgdev->ddev->anon_inode->i_mapping,
                               DRM_FILE_PAGE_OFFSET, 0);
@@ -407,13 +346,11 @@ int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev)
 err_mm_init:
        ttm_bo_device_release(&vgdev->mman.bdev);
 err_dev_init:
-       virtio_gpu_ttm_global_fini(vgdev);
        return r;
 }
 
 void virtio_gpu_ttm_fini(struct virtio_gpu_device *vgdev)
 {
        ttm_bo_device_release(&vgdev->mman.bdev);
-       virtio_gpu_ttm_global_fini(vgdev);
        DRM_INFO("virtio_gpu: ttm finalized\n");
 }
index 4e2e037aed34a22551225f2cb623f5492484c72a..e27c4aedb8093e16a886aa74c1a20a85062ba1f4 100644 (file)
                               + MAX_INLINE_CMD_SIZE             \
                               + MAX_INLINE_RESP_SIZE)
 
-void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
-                               uint32_t *resid)
-{
-       int handle;
-
-       idr_preload(GFP_KERNEL);
-       spin_lock(&vgdev->resource_idr_lock);
-       handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, GFP_NOWAIT);
-       spin_unlock(&vgdev->resource_idr_lock);
-       idr_preload_end();
-       *resid = handle;
-}
-
-void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
-{
-       spin_lock(&vgdev->resource_idr_lock);
-       idr_remove(&vgdev->resource_idr, id);
-       spin_unlock(&vgdev->resource_idr_lock);
-}
-
 void virtio_gpu_ctrl_ack(struct virtqueue *vq)
 {
        struct drm_device *dev = vq->vdev->priv;
@@ -98,10 +78,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
 {
        struct virtio_gpu_vbuffer *vbuf;
 
-       vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL);
+       vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL);
        if (!vbuf)
                return ERR_PTR(-ENOMEM);
-       memset(vbuf, 0, VBUFFER_SIZE);
 
        BUG_ON(size > MAX_INLINE_CMD_SIZE);
        vbuf->buf = (void *)vbuf + sizeof(*vbuf);
@@ -319,7 +298,7 @@ static int virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev,
 static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev,
                                               struct virtio_gpu_vbuffer *vbuf,
                                               struct virtio_gpu_ctrl_hdr *hdr,
-                                              struct virtio_gpu_fence **fence)
+                                              struct virtio_gpu_fence *fence)
 {
        struct virtqueue *vq = vgdev->ctrlq.vq;
        int rc;
@@ -388,7 +367,7 @@ retry:
 
 /* create a basic resource */
 void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
-                                   uint32_t resource_id,
+                                   struct virtio_gpu_object *bo,
                                    uint32_t format,
                                    uint32_t width,
                                    uint32_t height)
@@ -400,12 +379,13 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
        memset(cmd_p, 0, sizeof(*cmd_p));
 
        cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
-       cmd_p->resource_id = cpu_to_le32(resource_id);
+       cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle);
        cmd_p->format = cpu_to_le32(format);
        cmd_p->width = cpu_to_le32(width);
        cmd_p->height = cpu_to_le32(height);
 
        virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+       bo->created = true;
 }
 
 void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
@@ -425,7 +405,7 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
 
 static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
                                                  uint32_t resource_id,
-                                                 struct virtio_gpu_fence **fence)
+                                                 struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_resource_detach_backing *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -487,7 +467,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
                                        uint64_t offset,
                                        __le32 width, __le32 height,
                                        __le32 x, __le32 y,
-                                       struct virtio_gpu_fence **fence)
+                                       struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_transfer_to_host_2d *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -517,7 +497,7 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev,
                                       uint32_t resource_id,
                                       struct virtio_gpu_mem_entry *ents,
                                       uint32_t nents,
-                                      struct virtio_gpu_fence **fence)
+                                      struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_resource_attach_backing *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -604,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,
        wake_up(&vgdev->resp_wq);
 }
 
+static int virtio_get_edid_block(void *data, u8 *buf,
+                                unsigned int block, size_t len)
+{
+       struct virtio_gpu_resp_edid *resp = data;
+       size_t start = block * EDID_LENGTH;
+
+       if (start + len > le32_to_cpu(resp->size))
+               return -1;
+       memcpy(buf, resp->edid + start, len);
+       return 0;
+}
+
+static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev,
+                                      struct virtio_gpu_vbuffer *vbuf)
+{
+       struct virtio_gpu_cmd_get_edid *cmd =
+               (struct virtio_gpu_cmd_get_edid *)vbuf->buf;
+       struct virtio_gpu_resp_edid *resp =
+               (struct virtio_gpu_resp_edid *)vbuf->resp_buf;
+       uint32_t scanout = le32_to_cpu(cmd->scanout);
+       struct virtio_gpu_output *output;
+       struct edid *new_edid, *old_edid;
+
+       if (scanout >= vgdev->num_scanouts)
+               return;
+       output = vgdev->outputs + scanout;
+
+       new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp);
+
+       spin_lock(&vgdev->display_info_lock);
+       old_edid = output->edid;
+       output->edid = new_edid;
+       drm_connector_update_edid_property(&output->conn, output->edid);
+       spin_unlock(&vgdev->display_info_lock);
+
+       kfree(old_edid);
+       wake_up(&vgdev->resp_wq);
+}
+
 int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev)
 {
        struct virtio_gpu_ctrl_hdr *cmd_p;
@@ -706,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
        return 0;
 }
 
+int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev)
+{
+       struct virtio_gpu_cmd_get_edid *cmd_p;
+       struct virtio_gpu_vbuffer *vbuf;
+       void *resp_buf;
+       int scanout;
+
+       if (WARN_ON(!vgdev->has_edid))
+               return -EINVAL;
+
+       for (scanout = 0; scanout < vgdev->num_scanouts; scanout++) {
+               resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_edid),
+                                  GFP_KERNEL);
+               if (!resp_buf)
+                       return -ENOMEM;
+
+               cmd_p = virtio_gpu_alloc_cmd_resp
+                       (vgdev, &virtio_gpu_cmd_get_edid_cb, &vbuf,
+                        sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_edid),
+                        resp_buf);
+               cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID);
+               cmd_p->scanout = cpu_to_le32(scanout);
+               virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+       }
+
+       return 0;
+}
+
 void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
                                   uint32_t nlen, const char *name)
 {
@@ -772,8 +819,8 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev,
 
 void
 virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
-                                 struct virtio_gpu_resource_create_3d *rc_3d,
-                                 struct virtio_gpu_fence **fence)
+                                 struct virtio_gpu_object *bo,
+                                 struct virtio_gpu_resource_create_3d *rc_3d)
 {
        struct virtio_gpu_resource_create_3d *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -785,7 +832,8 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
        cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D);
        cmd_p->hdr.flags = 0;
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+       bo->created = true;
 }
 
 void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
@@ -793,7 +841,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
                                        uint32_t ctx_id,
                                        uint64_t offset, uint32_t level,
                                        struct virtio_gpu_box *box,
-                                       struct virtio_gpu_fence **fence)
+                                       struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_transfer_host_3d *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -821,7 +869,7 @@ void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
                                          uint32_t resource_id, uint32_t ctx_id,
                                          uint64_t offset, uint32_t level,
                                          struct virtio_gpu_box *box,
-                                         struct virtio_gpu_fence **fence)
+                                         struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_transfer_host_3d *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -841,7 +889,7 @@ void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
 
 void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
                           void *data, uint32_t data_size,
-                          uint32_t ctx_id, struct virtio_gpu_fence **fence)
+                          uint32_t ctx_id, struct virtio_gpu_fence *fence)
 {
        struct virtio_gpu_cmd_submit *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -861,14 +909,16 @@ void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
 
 int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
                             struct virtio_gpu_object *obj,
-                            uint32_t resource_id,
-                            struct virtio_gpu_fence **fence)
+                            struct virtio_gpu_fence *fence)
 {
        bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
        struct virtio_gpu_mem_entry *ents;
        struct scatterlist *sg;
        int si, nents;
 
+       if (!obj->created)
+               return 0;
+
        if (!obj->pages) {
                int ret;
 
@@ -902,10 +952,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
                ents[si].padding = 0;
        }
 
-       virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id,
+       virtio_gpu_cmd_resource_attach_backing(vgdev, obj->hw_res_handle,
                                               ents, nents,
                                               fence);
-       obj->hw_res_handle = resource_id;
        return 0;
 }
 
@@ -913,11 +962,11 @@ void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
                              struct virtio_gpu_object *obj)
 {
        bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
-       struct virtio_gpu_fence *fence;
 
        if (use_dma_api && obj->mapped) {
+               struct virtio_gpu_fence *fence = virtio_gpu_fence_alloc(vgdev);
                /* detach backing and wait for the host process it ... */
-               virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence);
+               virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, fence);
                dma_fence_wait(&fence->f, true);
                dma_fence_put(&fence->f);
 
index 07cfde1b4132b197113e0d3b63948fb121120d3f..83087877565cf77b9104d67636c183231fdd19c4 100644 (file)
@@ -68,7 +68,6 @@ static struct drm_driver vkms_driver = {
        .release                = vkms_release,
        .fops                   = &vkms_driver_fops,
        .dumb_create            = vkms_dumb_create,
-       .dumb_map_offset        = vkms_dumb_map,
        .gem_vm_ops             = &vkms_gem_vm_ops,
        .gem_free_object_unlocked = vkms_gem_free_object,
        .get_vblank_timestamp   = vkms_get_vblank_timestamp,
@@ -108,17 +107,18 @@ static int __init vkms_init(void)
        if (!vkms_device)
                return -ENOMEM;
 
-       ret = drm_dev_init(&vkms_device->drm, &vkms_driver, NULL);
-       if (ret)
-               goto out_free;
-
        vkms_device->platform =
                platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
        if (IS_ERR(vkms_device->platform)) {
                ret = PTR_ERR(vkms_device->platform);
-               goto out_fini;
+               goto out_free;
        }
 
+       ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
+                          &vkms_device->platform->dev);
+       if (ret)
+               goto out_unregister;
+
        vkms_device->drm.irq_enabled = true;
 
        ret = drm_vblank_init(&vkms_device->drm, 1);
@@ -129,20 +129,20 @@ static int __init vkms_init(void)
 
        ret = vkms_modeset_init(vkms_device);
        if (ret)
-               goto out_unregister;
+               goto out_fini;
 
        ret = drm_dev_register(&vkms_device->drm, 0);
        if (ret)
-               goto out_unregister;
+               goto out_fini;
 
        return 0;
 
-out_unregister:
-       platform_device_unregister(vkms_device->platform);
-
 out_fini:
        drm_dev_fini(&vkms_device->drm);
 
+out_unregister:
+       platform_device_unregister(vkms_device->platform);
+
 out_free:
        kfree(vkms_device);
        return ret;
index 1c93990693e3d0e65a70fcb4ee7dea34826d3a89..e4469cd3d25491198209e3898189fc52e54e5ed7 100644 (file)
@@ -127,9 +127,6 @@ vm_fault_t vkms_gem_fault(struct vm_fault *vmf);
 int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
                     struct drm_mode_create_dumb *args);
 
-int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
-                 u32 handle, u64 *offset);
-
 void vkms_gem_free_object(struct drm_gem_object *obj);
 
 int vkms_gem_vmap(struct drm_gem_object *obj);
index d04e988b4cbef88dacc54db05681078b5b29d529..80311daed47a0ac752a3e1e68bd54f9d8b60d412 100644 (file)
@@ -153,32 +153,6 @@ int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
        return 0;
 }
 
-int vkms_dumb_map(struct drm_file *file, struct drm_device *dev,
-                 u32 handle, u64 *offset)
-{
-       struct drm_gem_object *obj;
-       int ret;
-
-       obj = drm_gem_object_lookup(file, handle);
-       if (!obj)
-               return -ENOENT;
-
-       if (!obj->filp) {
-               ret = -EINVAL;
-               goto unref;
-       }
-
-       ret = drm_gem_create_mmap_offset(obj);
-       if (ret)
-               goto unref;
-
-       *offset = drm_vma_node_offset_addr(&obj->vma_node);
-unref:
-       drm_gem_object_put_unlocked(obj);
-
-       return ret;
-}
-
 static struct page **_get_pages(struct vkms_gem_object *vkms_obj)
 {
        struct drm_gem_object *gem_obj = &vkms_obj->gem;
index 7041007396ae8830094357f6baf0d0f8db0f4c3d..418817600ad11052105418572e6c2a6965bba71a 100644 (file)
@@ -23,8 +23,11 @@ vkms_plane_duplicate_state(struct drm_plane *plane)
                return NULL;
 
        crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL);
-       if (WARN_ON(!crc_data))
-               DRM_INFO("Couldn't allocate crc_data");
+       if (!crc_data) {
+               DRM_DEBUG_KMS("Couldn't allocate crc_data\n");
+               kfree(vkms_state);
+               return NULL;
+       }
 
        vkms_state->crc_data = crc_data;
 
@@ -138,14 +141,12 @@ static int vkms_prepare_fb(struct drm_plane *plane,
                           struct drm_plane_state *state)
 {
        struct drm_gem_object *gem_obj;
-       struct vkms_gem_object *vkms_obj;
        int ret;
 
        if (!state->fb)
                return 0;
 
        gem_obj = drm_gem_fb_get_obj(state->fb, 0);
-       vkms_obj = drm_gem_to_vkms_gem(gem_obj);
        ret = vkms_gem_vmap(gem_obj);
        if (ret)
                DRM_ERROR("vmap failed: %d\n", ret);
index d7a2dfb8ee9b1101ed99a6ca6fe28e7000a8391c..f05a29ff586e1b5330a169e8eb74087ac9c6a849 100644 (file)
@@ -667,7 +667,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        mutex_init(&dev_priv->cmdbuf_mutex);
        mutex_init(&dev_priv->release_mutex);
        mutex_init(&dev_priv->binding_mutex);
-       mutex_init(&dev_priv->requested_layout_mutex);
        mutex_init(&dev_priv->global_kms_state_mutex);
        ttm_lock_init(&dev_priv->reservation_sem);
        spin_lock_init(&dev_priv->resource_lock);
@@ -803,11 +802,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        DRM_INFO("MMIO at 0x%08x size is %u kiB\n",
                 dev_priv->mmio_start, dev_priv->mmio_size / 1024);
 
-       ret = vmw_ttm_global_init(dev_priv);
-       if (unlikely(ret != 0))
-               goto out_err0;
-
-
        vmw_master_init(&dev_priv->fbdev_master);
        ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
        dev_priv->active_master = &dev_priv->fbdev_master;
@@ -818,7 +812,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        if (unlikely(dev_priv->mmio_virt == NULL)) {
                ret = -ENOMEM;
                DRM_ERROR("Failed mapping MMIO.\n");
-               goto out_err3;
+               goto out_err0;
        }
 
        /* Need mmio memory to check for fifo pitchlock cap. */
@@ -830,8 +824,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_err4;
        }
 
-       dev_priv->tdev = ttm_object_device_init
-               (dev_priv->mem_global_ref.object, 12, &vmw_prime_dmabuf_ops);
+       dev_priv->tdev = ttm_object_device_init(&ttm_mem_glob, 12,
+                                               &vmw_prime_dmabuf_ops);
 
        if (unlikely(dev_priv->tdev == NULL)) {
                DRM_ERROR("Unable to initialize TTM object management.\n");
@@ -872,7 +866,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        }
 
        ret = ttm_bo_device_init(&dev_priv->bdev,
-                                dev_priv->bo_global_ref.ref.object,
                                 &vmw_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 VMWGFX_FILE_PAGE_OFFSET,
@@ -994,8 +987,6 @@ out_no_device:
        ttm_object_device_release(&dev_priv->tdev);
 out_err4:
        memunmap(dev_priv->mmio_virt);
-out_err3:
-       vmw_ttm_global_release(dev_priv);
 out_err0:
        for (i = vmw_res_context; i < vmw_res_max; ++i)
                idr_destroy(&dev_priv->res_idr[i]);
@@ -1047,7 +1038,6 @@ static void vmw_driver_unload(struct drm_device *dev)
        memunmap(dev_priv->mmio_virt);
        if (dev_priv->ctx.staged_bindings)
                vmw_binding_state_free(dev_priv->ctx.staged_bindings);
-       vmw_ttm_global_release(dev_priv);
 
        for (i = vmw_res_context; i < vmw_res_max; ++i)
                idr_destroy(&dev_priv->res_idr[i]);
index aca974b14b550b11d02e7d3d83ac77fc60e4f439..cd607ba9c2fed484f6895f91d7abf4be4cb2b4f4 100644 (file)
@@ -417,8 +417,6 @@ enum {
 
 struct vmw_private {
        struct ttm_bo_device bdev;
-       struct ttm_bo_global_ref bo_global_ref;
-       struct drm_global_reference mem_global_ref;
 
        struct vmw_fifo_state fifo;
 
@@ -467,15 +465,6 @@ struct vmw_private {
 
        uint32_t num_displays;
 
-       /*
-        * Currently requested_layout_mutex is used to protect the gui
-        * positionig state in display unit. With that use case currently this
-        * mutex is only taken during layout ioctl and atomic check_modeset.
-        * Other display unit state can be protected with this mutex but that
-        * needs careful consideration.
-        */
-       struct mutex requested_layout_mutex;
-
        /*
         * Framebuffer info.
         */
@@ -486,8 +475,6 @@ struct vmw_private {
        struct vmw_overlay *overlay_priv;
        struct drm_property *hotplug_mode_update_property;
        struct drm_property *implicit_placement_property;
-       unsigned num_implicit;
-       struct vmw_framebuffer *implicit_fb;
        struct mutex global_kms_state_mutex;
        spinlock_t cursor_lock;
        struct drm_atomic_state *suspend_state;
@@ -845,8 +832,6 @@ extern int vmw_fifo_flush(struct vmw_private *dev_priv,
  * TTM glue - vmwgfx_ttm_glue.c
  */
 
-extern int vmw_ttm_global_init(struct vmw_private *dev_priv);
-extern void vmw_ttm_global_release(struct vmw_private *dev_priv);
 extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
 
 extern void vmw_validation_mem_init_ttm(struct vmw_private *dev_priv,
@@ -1368,7 +1353,7 @@ vmw_bo_reference(struct vmw_buffer_object *buf)
 
 static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv)
 {
-       return (struct ttm_mem_global *) dev_priv->mem_global_ref.object;
+       return &ttm_mem_glob;
 }
 
 static inline void vmw_fifo_resource_inc(struct vmw_private *dev_priv)
index f87261545f2c1e8123846af64d406f32efcb4883..301260e23e52d3d63d98e38b537e1971daef6a63 100644 (file)
@@ -906,13 +906,10 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
                container_of(action, struct vmw_event_fence_action, action);
        struct drm_device *dev = eaction->dev;
        struct drm_pending_event *event = eaction->event;
-       struct drm_file *file_priv;
-
 
        if (unlikely(event == NULL))
                return;
 
-       file_priv = event->file_priv;
        spin_lock_irq(&dev->event_lock);
 
        if (likely(eaction->tv_sec != NULL)) {
index dca04d4246ea8d826b2e31b6ce507b64c14f7bda..b351fb5214d33b9b84f6223ba72a6210862e9b80 100644 (file)
@@ -30,6 +30,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_damage_helper.h>
 
 /* Might need a hrtimer here? */
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
@@ -456,21 +457,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
                struct drm_crtc *crtc = state->crtc;
                struct vmw_connector_state *vcs;
                struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
-               struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-               struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
 
                vcs = vmw_connector_state_to_vcs(du->connector.state);
-
-               /* Only one active implicit framebuffer at a time. */
-               mutex_lock(&dev_priv->global_kms_state_mutex);
-               if (vcs->is_implicit && dev_priv->implicit_fb &&
-                   !(dev_priv->num_implicit == 1 && du->active_implicit)
-                   && dev_priv->implicit_fb != vfb) {
-                       DRM_ERROR("Multiple implicit framebuffers "
-                                 "not supported.\n");
-                       ret = -EINVAL;
-               }
-               mutex_unlock(&dev_priv->global_kms_state_mutex);
        }
 
 
@@ -493,24 +481,24 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
                                     struct drm_plane_state *new_state)
 {
        int ret = 0;
+       struct drm_crtc_state *crtc_state = NULL;
        struct vmw_surface *surface = NULL;
        struct drm_framebuffer *fb = new_state->fb;
 
-       struct drm_rect src = drm_plane_state_src(new_state);
-       struct drm_rect dest = drm_plane_state_dest(new_state);
+       if (new_state->crtc)
+               crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
+                                                          new_state->crtc);
 
-       /* Turning off */
-       if (!fb)
+       ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 DRM_PLANE_HELPER_NO_SCALING,
+                                                 true, true);
+       if (ret)
                return ret;
 
-       ret = drm_plane_helper_check_update(plane, new_state->crtc, fb,
-                                           &src, &dest,
-                                           DRM_MODE_ROTATE_0,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           DRM_PLANE_HELPER_NO_SCALING,
-                                           true, true, &new_state->visible);
-       if (!ret)
-               return ret;
+       /* Turning off */
+       if (!fb)
+               return 0;
 
        /* A lot of the code assumes this */
        if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
@@ -846,58 +834,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
        kfree(vfbs);
 }
 
-static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
-                                 struct drm_file *file_priv,
-                                 unsigned flags, unsigned color,
-                                 struct drm_clip_rect *clips,
-                                 unsigned num_clips)
-{
-       struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
-       struct vmw_framebuffer_surface *vfbs =
-               vmw_framebuffer_to_vfbs(framebuffer);
-       struct drm_clip_rect norect;
-       int ret, inc = 1;
-
-       /* Legacy Display Unit does not support 3D */
-       if (dev_priv->active_display_unit == vmw_du_legacy)
-               return -EINVAL;
-
-       drm_modeset_lock_all(dev_priv->dev);
-
-       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
-       if (unlikely(ret != 0)) {
-               drm_modeset_unlock_all(dev_priv->dev);
-               return ret;
-       }
-
-       if (!num_clips) {
-               num_clips = 1;
-               clips = &norect;
-               norect.x1 = norect.y1 = 0;
-               norect.x2 = framebuffer->width;
-               norect.y2 = framebuffer->height;
-       } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
-               num_clips /= 2;
-               inc = 2; /* skip source rects */
-       }
-
-       if (dev_priv->active_display_unit == vmw_du_screen_object)
-               ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base,
-                                                  clips, NULL, NULL, 0, 0,
-                                                  num_clips, inc, NULL, NULL);
-       else
-               ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base,
-                                                clips, NULL, NULL, 0, 0,
-                                                num_clips, inc, NULL, NULL);
-
-       vmw_fifo_flush(dev_priv, false);
-       ttm_read_unlock(&dev_priv->reservation_sem);
-
-       drm_modeset_unlock_all(dev_priv->dev);
-
-       return 0;
-}
-
 /**
  * vmw_kms_readback - Perform a readback from the screen system to
  * a buffer-object backed framebuffer.
@@ -941,7 +877,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
 
 static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
        .destroy = vmw_framebuffer_surface_destroy,
-       .dirty = vmw_framebuffer_surface_dirty,
+       .dirty = drm_atomic_helper_dirtyfb,
 };
 
 static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
@@ -1084,16 +1020,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
        }
 
        switch (dev_priv->active_display_unit) {
-       case vmw_du_screen_target:
-               ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL,
-                                      clips, NULL, num_clips, increment,
-                                      true, true, NULL);
-               break;
-       case vmw_du_screen_object:
-               ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base,
-                                             clips, NULL, num_clips,
-                                             increment, true, NULL, NULL);
-               break;
        case vmw_du_legacy:
                ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0,
                                              clips, num_clips, increment);
@@ -1112,9 +1038,25 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
        return ret;
 }
 
+static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer,
+                                       struct drm_file *file_priv,
+                                       unsigned int flags, unsigned int color,
+                                       struct drm_clip_rect *clips,
+                                       unsigned int num_clips)
+{
+       struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+
+       if (dev_priv->active_display_unit == vmw_du_legacy)
+               return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags,
+                                               color, clips, num_clips);
+
+       return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color,
+                                        clips, num_clips);
+}
+
 static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = {
        .destroy = vmw_framebuffer_bo_destroy,
-       .dirty = vmw_framebuffer_bo_dirty,
+       .dirty = vmw_framebuffer_bo_dirty_ext,
 };
 
 /**
@@ -1564,6 +1506,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
        return 0;
 }
 
+/**
+ * vmw_crtc_state_and_lock - Return new or current crtc state with locked
+ * crtc mutex
+ * @state: The atomic state pointer containing the new atomic state
+ * @crtc: The crtc
+ *
+ * This function returns the new crtc state if it's part of the state update.
+ * Otherwise returns the current crtc state. It also makes sure that the
+ * crtc mutex is locked.
+ *
+ * Returns: A valid crtc state pointer or NULL. It may also return a
+ * pointer error, in particular -EDEADLK if locking needs to be rerun.
+ */
+static struct drm_crtc_state *
+vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc)
+{
+       struct drm_crtc_state *crtc_state;
+
+       crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       if (crtc_state) {
+               lockdep_assert_held(&crtc->mutex.mutex.base);
+       } else {
+               int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+
+               if (ret != 0 && ret != -EALREADY)
+                       return ERR_PTR(ret);
+
+               crtc_state = crtc->state;
+       }
+
+       return crtc_state;
+}
+
+/**
+ * vmw_kms_check_implicit - Verify that all implicit display units scan out
+ * from the same fb after the new state is committed.
+ * @dev: The drm_device.
+ * @state: The new state to be checked.
+ *
+ * Returns:
+ *   Zero on success,
+ *   -EINVAL on invalid state,
+ *   -EDEADLK if modeset locking needs to be rerun.
+ */
+static int vmw_kms_check_implicit(struct drm_device *dev,
+                                 struct drm_atomic_state *state)
+{
+       struct drm_framebuffer *implicit_fb = NULL;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane_state *plane_state;
+
+       drm_for_each_crtc(crtc, dev) {
+               struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
+
+               if (!du->is_implicit)
+                       continue;
+
+               crtc_state = vmw_crtc_state_and_lock(state, crtc);
+               if (IS_ERR(crtc_state))
+                       return PTR_ERR(crtc_state);
+
+               if (!crtc_state || !crtc_state->enable)
+                       continue;
+
+               /*
+                * Can't move primary planes across crtcs, so this is OK.
+                * It also means we don't need to take the plane mutex.
+                */
+               plane_state = du->primary.state;
+               if (plane_state->crtc != crtc)
+                       continue;
+
+               if (!implicit_fb)
+                       implicit_fb = plane_state->fb;
+               else if (implicit_fb != plane_state->fb)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * vmw_kms_check_topology - Validates topology in drm_atomic_state
  * @dev: DRM device
@@ -1575,7 +1599,6 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
 static int vmw_kms_check_topology(struct drm_device *dev,
                                  struct drm_atomic_state *state)
 {
-       struct vmw_private *dev_priv = vmw_priv(dev);
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
        struct drm_rect *rects;
        struct drm_crtc *crtc;
@@ -1587,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev,
        if (!rects)
                return -ENOMEM;
 
-       mutex_lock(&dev_priv->requested_layout_mutex);
-
        drm_for_each_crtc(crtc, dev) {
                struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
-               struct drm_crtc_state *crtc_state = crtc->state;
+               struct drm_crtc_state *crtc_state;
 
                i = drm_crtc_index(crtc);
 
-               if (crtc_state && crtc_state->enable) {
+               crtc_state = vmw_crtc_state_and_lock(state, crtc);
+               if (IS_ERR(crtc_state)) {
+                       ret = PTR_ERR(crtc_state);
+                       goto clean;
+               }
+
+               if (!crtc_state)
+                       continue;
+
+               if (crtc_state->enable) {
                        rects[i].x1 = du->gui_x;
                        rects[i].y1 = du->gui_y;
                        rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay;
                        rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay;
+               } else {
+                       rects[i].x1 = 0;
+                       rects[i].y1 = 0;
+                       rects[i].x2 = 0;
+                       rects[i].y2 = 0;
                }
        }
 
@@ -1611,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
                struct drm_connector_state *conn_state;
                struct vmw_connector_state *vmw_conn_state;
 
-               if (!new_crtc_state->enable) {
-                       rects[i].x1 = 0;
-                       rects[i].y1 = 0;
-                       rects[i].x2 = 0;
-                       rects[i].y2 = 0;
-                       continue;
-               }
-
                if (!du->pref_active) {
                        ret = -EINVAL;
                        goto clean;
@@ -1639,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev,
                vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
                vmw_conn_state->gui_x = du->gui_x;
                vmw_conn_state->gui_y = du->gui_y;
-
-               rects[i].x1 = du->gui_x;
-               rects[i].y1 = du->gui_y;
-               rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay;
-               rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay;
        }
 
        ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc,
                                           rects);
 
 clean:
-       mutex_unlock(&dev_priv->requested_layout_mutex);
        kfree(rects);
        return ret;
 }
@@ -1681,6 +1702,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev,
        if (ret)
                return ret;
 
+       ret = vmw_kms_check_implicit(dev, state);
+       if (ret)
+               return ret;
+
        if (!state->allow_modeset)
                return ret;
 
@@ -2003,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
        struct vmw_display_unit *du;
        struct drm_connector *con;
        struct drm_connector_list_iter conn_iter;
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_crtc *crtc;
+       int ret;
+
+       /* Currently gui_x/y is protected with the crtc mutex */
+       mutex_lock(&dev->mode_config.mutex);
+       drm_modeset_acquire_init(&ctx, 0);
+retry:
+       drm_for_each_crtc(crtc, dev) {
+               ret = drm_modeset_lock(&crtc->mutex, &ctx);
+               if (ret < 0) {
+                       if (ret == -EDEADLK) {
+                               drm_modeset_backoff(&ctx);
+                               goto retry;
+               }
+                       goto out_fini;
+               }
+       }
 
-       /*
-        * Currently only gui_x/y is protected with requested_layout_mutex.
-        */
-       mutex_lock(&dev_priv->requested_layout_mutex);
        drm_connector_list_iter_begin(dev, &conn_iter);
        drm_for_each_connector_iter(con, &conn_iter) {
                du = vmw_connector_to_du(con);
@@ -2026,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
                }
        }
        drm_connector_list_iter_end(&conn_iter);
-       mutex_unlock(&dev_priv->requested_layout_mutex);
 
-       mutex_lock(&dev->mode_config.mutex);
        list_for_each_entry(con, &dev->mode_config.connector_list, head) {
                du = vmw_connector_to_du(con);
                if (num_rects > du->unit) {
@@ -2048,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
                }
                con->status = vmw_du_connector_detect(con, true);
        }
-       mutex_unlock(&dev->mode_config.mutex);
 
        drm_sysfs_hotplug_event(dev);
-
+out_fini:
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+       mutex_unlock(&dev->mode_config.mutex);
        return 0;
 }
 
@@ -2275,84 +2315,6 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
        return 1;
 }
 
-int vmw_du_connector_set_property(struct drm_connector *connector,
-                                 struct drm_property *property,
-                                 uint64_t val)
-{
-       struct vmw_display_unit *du = vmw_connector_to_du(connector);
-       struct vmw_private *dev_priv = vmw_priv(connector->dev);
-
-       if (property == dev_priv->implicit_placement_property)
-               du->is_implicit = val;
-
-       return 0;
-}
-
-
-
-/**
- * vmw_du_connector_atomic_set_property - Atomic version of get property
- *
- * @crtc - crtc the property is associated with
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int
-vmw_du_connector_atomic_set_property(struct drm_connector *connector,
-                                    struct drm_connector_state *state,
-                                    struct drm_property *property,
-                                    uint64_t val)
-{
-       struct vmw_private *dev_priv = vmw_priv(connector->dev);
-       struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
-       struct vmw_display_unit *du = vmw_connector_to_du(connector);
-
-
-       if (property == dev_priv->implicit_placement_property) {
-               vcs->is_implicit = val;
-
-               /*
-                * We should really be doing a drm_atomic_commit() to
-                * commit the new state, but since this doesn't cause
-                * an immedate state change, this is probably ok
-                */
-               du->is_implicit = vcs->is_implicit;
-       } else {
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-
-/**
- * vmw_du_connector_atomic_get_property - Atomic version of get property
- *
- * @connector - connector the property is associated with
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int
-vmw_du_connector_atomic_get_property(struct drm_connector *connector,
-                                    const struct drm_connector_state *state,
-                                    struct drm_property *property,
-                                    uint64_t *val)
-{
-       struct vmw_private *dev_priv = vmw_priv(connector->dev);
-       struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
-
-       if (property == dev_priv->implicit_placement_property)
-               *val = vcs->is_implicit;
-       else {
-               DRM_ERROR("Invalid Property %s\n", property->name);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 /**
  * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl
  * @dev: drm device for the ioctl
@@ -2741,144 +2703,26 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
        return ret;
 }
 
-/**
- * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer
- *
- * @dev_priv: Pointer to a device private struct.
- * @du: The display unit of the crtc.
- */
-void vmw_kms_del_active(struct vmw_private *dev_priv,
-                       struct vmw_display_unit *du)
-{
-       mutex_lock(&dev_priv->global_kms_state_mutex);
-       if (du->active_implicit) {
-               if (--(dev_priv->num_implicit) == 0)
-                       dev_priv->implicit_fb = NULL;
-               du->active_implicit = false;
-       }
-       mutex_unlock(&dev_priv->global_kms_state_mutex);
-}
-
-/**
- * vmw_kms_add_active - register a crtc binding to an implicit framebuffer
- *
- * @vmw_priv: Pointer to a device private struct.
- * @du: The display unit of the crtc.
- * @vfb: The implicit framebuffer
- *
- * Registers a binding to an implicit framebuffer.
- */
-void vmw_kms_add_active(struct vmw_private *dev_priv,
-                       struct vmw_display_unit *du,
-                       struct vmw_framebuffer *vfb)
-{
-       mutex_lock(&dev_priv->global_kms_state_mutex);
-       WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb);
-
-       if (!du->active_implicit && du->is_implicit) {
-               dev_priv->implicit_fb = vfb;
-               du->active_implicit = true;
-               dev_priv->num_implicit++;
-       }
-       mutex_unlock(&dev_priv->global_kms_state_mutex);
-}
-
-/**
- * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc.
- *
- * @dev_priv: Pointer to device-private struct.
- * @crtc: The crtc we want to flip.
- *
- * Returns true or false depending whether it's OK to flip this crtc
- * based on the criterion that we must not have more than one implicit
- * frame-buffer at any one time.
- */
-bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
-                           struct drm_crtc *crtc)
-{
-       struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
-       bool ret;
-
-       mutex_lock(&dev_priv->global_kms_state_mutex);
-       ret = !du->is_implicit || dev_priv->num_implicit == 1;
-       mutex_unlock(&dev_priv->global_kms_state_mutex);
-
-       return ret;
-}
-
-/**
- * vmw_kms_update_implicit_fb - Update the implicit fb.
- *
- * @dev_priv: Pointer to device-private struct.
- * @crtc: The crtc the new implicit frame-buffer is bound to.
- */
-void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
-                               struct drm_crtc *crtc)
-{
-       struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
-       struct drm_plane *plane = crtc->primary;
-       struct vmw_framebuffer *vfb;
-
-       mutex_lock(&dev_priv->global_kms_state_mutex);
-
-       if (!du->is_implicit)
-               goto out_unlock;
-
-       vfb = vmw_framebuffer_to_vfb(plane->state->fb);
-       WARN_ON_ONCE(dev_priv->num_implicit != 1 &&
-                    dev_priv->implicit_fb != vfb);
-
-       dev_priv->implicit_fb = vfb;
-out_unlock:
-       mutex_unlock(&dev_priv->global_kms_state_mutex);
-}
-
 /**
  * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement
  * property.
  *
  * @dev_priv: Pointer to a device private struct.
- * @immutable: Whether the property is immutable.
  *
  * Sets up the implicit placement property unless it's already set up.
  */
 void
-vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
-                                          bool immutable)
+vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv)
 {
        if (dev_priv->implicit_placement_property)
                return;
 
        dev_priv->implicit_placement_property =
                drm_property_create_range(dev_priv->dev,
-                                         immutable ?
-                                         DRM_MODE_PROP_IMMUTABLE : 0,
+                                         DRM_MODE_PROP_IMMUTABLE,
                                          "implicit_placement", 0, 1);
-
 }
 
-
-/**
- * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config
- *
- * @set: The configuration to set.
- *
- * The vmwgfx Xorg driver doesn't assign the mode::type member, which
- * when drm_mode_set_crtcinfo is called as part of the configuration setting
- * causes it to return incorrect crtc dimensions causing severe problems in
- * the vmwgfx modesetting. So explicitly clear that member before calling
- * into drm_atomic_helper_set_config.
- */
-int vmw_kms_set_config(struct drm_mode_set *set,
-                      struct drm_modeset_acquire_ctx *ctx)
-{
-       if (set && set->mode)
-               set->mode->type = 0;
-
-       return drm_atomic_helper_set_config(set, ctx);
-}
-
-
 /**
  * vmw_kms_suspend - Save modesetting state and turn modesetting off.
  *
@@ -2935,3 +2779,124 @@ void vmw_kms_lost_device(struct drm_device *dev)
 {
        drm_atomic_helper_shutdown(dev);
 }
+
+/**
+ * vmw_du_helper_plane_update - Helper to do plane update on a display unit.
+ * @update: The closure structure.
+ *
+ * Call this helper after setting callbacks in &vmw_du_update_plane to do plane
+ * update on display unit.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
+{
+       struct drm_plane_state *state = update->plane->state;
+       struct drm_plane_state *old_state = update->old_state;
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_rect clip;
+       struct drm_rect bb;
+       DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
+       uint32_t reserved_size = 0;
+       uint32_t submit_size = 0;
+       uint32_t curr_size = 0;
+       uint32_t num_hits = 0;
+       void *cmd_start;
+       char *cmd_next;
+       int ret;
+
+       /*
+        * Iterate in advance to check if really need plane update and find the
+        * number of clips that actually are in plane src for fifo allocation.
+        */
+       drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       if (num_hits == 0)
+               return 0;
+
+       if (update->vfb->bo) {
+               struct vmw_framebuffer_bo *vfbbo =
+                       container_of(update->vfb, typeof(*vfbbo), base);
+
+               ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false,
+                                           update->cpu_blit);
+       } else {
+               struct vmw_framebuffer_surface *vfbs =
+                       container_of(update->vfb, typeof(*vfbs), base);
+
+               ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res,
+                                                 0, NULL, NULL);
+       }
+
+       if (ret)
+               return ret;
+
+       ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr);
+       if (ret)
+               goto out_unref;
+
+       reserved_size = update->calc_fifo_size(update, num_hits);
+       cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size);
+       if (!cmd_start) {
+               ret = -ENOMEM;
+               goto out_revert;
+       }
+
+       cmd_next = cmd_start;
+
+       if (update->post_prepare) {
+               curr_size = update->post_prepare(update, cmd_next);
+               cmd_next += curr_size;
+               submit_size += curr_size;
+       }
+
+       if (update->pre_clip) {
+               curr_size = update->pre_clip(update, cmd_next, num_hits);
+               cmd_next += curr_size;
+               submit_size += curr_size;
+       }
+
+       bb.x1 = INT_MAX;
+       bb.y1 = INT_MAX;
+       bb.x2 = INT_MIN;
+       bb.y2 = INT_MIN;
+
+       drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+       drm_atomic_for_each_plane_damage(&iter, &clip) {
+               uint32_t fb_x = clip.x1;
+               uint32_t fb_y = clip.y1;
+
+               vmw_du_translate_to_crtc(state, &clip);
+               if (update->clip) {
+                       curr_size = update->clip(update, cmd_next, &clip, fb_x,
+                                                fb_y);
+                       cmd_next += curr_size;
+                       submit_size += curr_size;
+               }
+               bb.x1 = min_t(int, bb.x1, clip.x1);
+               bb.y1 = min_t(int, bb.y1, clip.y1);
+               bb.x2 = max_t(int, bb.x2, clip.x2);
+               bb.y2 = max_t(int, bb.y2, clip.y2);
+       }
+
+       curr_size = update->post_clip(update, cmd_next, &bb);
+       submit_size += curr_size;
+
+       if (reserved_size < submit_size)
+               submit_size = 0;
+
+       vmw_fifo_commit(update->dev_priv, submit_size);
+
+       vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx,
+                                        update->out_fence, NULL);
+       return ret;
+
+out_revert:
+       vmw_validation_revert(&val_ctx);
+
+out_unref:
+       vmw_validation_unref_lists(&val_ctx);
+       return ret;
+}
index 76ec570c0684f4c2e17dad2973912840c3b9281f..655abbcd4058272da076f8039bf1e942a13d78c8 100644 (file)
 #include <drm/drm_encoder.h>
 #include "vmwgfx_drv.h"
 
+/**
+ * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update
+ * @plane: Plane which is being updated.
+ * @old_state: Old state of plane.
+ * @dev_priv: Device private.
+ * @du: Display unit on which to update the plane.
+ * @vfb: Framebuffer which is blitted to display unit.
+ * @out_fence: Out fence for resource finish.
+ * @mutex: The mutex used to protect resource reservation.
+ * @cpu_blit: True if need cpu blit.
+ * @intr: Whether to perform waits interruptible if possible.
+ *
+ * This structure loosely represent the set of operations needed to perform a
+ * plane update on a display unit. Implementer will define that functionality
+ * according to the function callbacks for this structure. In brief it involves
+ * surface/buffer object validation, populate FIFO commands and command
+ * submission to the device.
+ */
+struct vmw_du_update_plane {
+       /**
+        * @calc_fifo_size: Calculate fifo size.
+        *
+        * Determine fifo size for the commands needed for update. The number of
+        * damage clips on display unit @num_hits will be passed to allocate
+        * sufficient fifo space.
+        *
+        * Return: Fifo size needed
+        */
+       uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update,
+                                  uint32_t num_hits);
+
+       /**
+        * @post_prepare: Populate fifo for resource preparation.
+        *
+        * Some surface resource or buffer object need some extra cmd submission
+        * like update GB image for proxy surface and define a GMRFB for screen
+        * object. That should should be done here as this callback will be
+        * called after FIFO allocation with the address of command buufer.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd);
+
+       /**
+        * @pre_clip: Populate fifo before clip.
+        *
+        * This is where pre clip related command should be populated like
+        * surface copy/DMA, etc.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd,
+                            uint32_t num_hits);
+
+       /**
+        * @clip: Populate fifo for clip.
+        *
+        * This is where to populate clips for surface copy/dma or blit commands
+        * if needed. This will be called times have damage in display unit,
+        * which is one if doing full update. @clip is the damage in destination
+        * coordinates which is crtc/DU and @src_x, @src_y is damage clip src in
+        * framebuffer coordinate.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd,
+                        struct drm_rect *clip, uint32_t src_x, uint32_t src_y);
+
+       /**
+        * @post_clip: Populate fifo after clip.
+        *
+        * This is where to populate display unit update commands or blit
+        * commands.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd,
+                                   struct drm_rect *bb);
+
+       struct drm_plane *plane;
+       struct drm_plane_state *old_state;
+       struct vmw_private *dev_priv;
+       struct vmw_display_unit *du;
+       struct vmw_framebuffer *vfb;
+       struct vmw_fence_obj **out_fence;
+       struct mutex *mutex;
+       bool cpu_blit;
+       bool intr;
+};
+
+/**
+ * struct vmw_du_update_plane_surface - closure structure for surface
+ * @base: base closure structure.
+ * @cmd_start: FIFO command start address (used by SOU only).
+ */
+struct vmw_du_update_plane_surface {
+       struct vmw_du_update_plane base;
+       /* This member is to handle special case SOU surface update */
+       void *cmd_start;
+};
 
+/**
+ * struct vmw_du_update_plane_buffer - Closure structure for buffer object
+ * @base: Base closure structure.
+ * @fb_left: x1 for fb damage bounding box.
+ * @fb_top: y1 for fb damage bounding box.
+ */
+struct vmw_du_update_plane_buffer {
+       struct vmw_du_update_plane base;
+       int fb_left, fb_top;
+};
 
 /**
  * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty
@@ -191,8 +307,6 @@ struct vmw_plane_state {
 struct vmw_connector_state {
        struct drm_connector_state base;
 
-       bool is_implicit;
-
        /**
         * @gui_x:
         *
@@ -254,7 +368,6 @@ struct vmw_display_unit {
        int gui_x;
        int gui_y;
        bool is_implicit;
-       bool active_implicit;
        int set_gui_x;
        int set_gui_y;
 };
@@ -334,17 +447,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
                            struct drm_crtc **p_crtc,
                            struct drm_display_mode **p_mode);
 void vmw_guess_mode_timing(struct drm_display_mode *mode);
-void vmw_kms_del_active(struct vmw_private *dev_priv,
-                       struct vmw_display_unit *du);
-void vmw_kms_add_active(struct vmw_private *dev_priv,
-                       struct vmw_display_unit *du,
-                       struct vmw_framebuffer *vfb);
-bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
-                           struct drm_crtc *crtc);
-void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
-                               struct drm_crtc *crtc);
-void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
-                                               bool immutable);
+void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
+void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
 
 /* Universal Plane Helpers */
 void vmw_du_primary_plane_destroy(struct drm_plane *plane);
@@ -456,6 +560,20 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
                     bool interruptible,
                     struct drm_crtc *crtc);
 
-int vmw_kms_set_config(struct drm_mode_set *set,
-                      struct drm_modeset_acquire_ctx *ctx);
+int vmw_du_helper_plane_update(struct vmw_du_update_plane *update);
+
+/**
+ * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc
+ * @state: Plane state.
+ * @r: Rectangle to translate.
+ */
+static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state,
+                                           struct drm_rect *r)
+{
+       int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x);
+       int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y);
+
+       drm_rect_translate(r, translate_crtc_x, translate_crtc_y);
+}
+
 #endif
index 72357811719122f70f36ea420786b0333a787e0a..16be515c4c0f3d3ae737de90c408ba8209d72833 100644 (file)
@@ -233,7 +233,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
        .reset = vmw_du_crtc_reset,
        .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
        .atomic_destroy_state = vmw_du_crtc_destroy_state,
-       .set_config = vmw_kms_set_config,
+       .set_config = drm_atomic_helper_set_config,
 };
 
 
@@ -263,18 +263,14 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
        .dpms = vmw_du_connector_dpms,
        .detect = vmw_du_connector_detect,
        .fill_modes = vmw_du_connector_fill_modes,
-       .set_property = vmw_du_connector_set_property,
        .destroy = vmw_ldu_connector_destroy,
        .reset = vmw_du_connector_reset,
        .atomic_duplicate_state = vmw_du_connector_duplicate_state,
        .atomic_destroy_state = vmw_du_connector_destroy_state,
-       .atomic_set_property = vmw_du_connector_atomic_set_property,
-       .atomic_get_property = vmw_du_connector_atomic_get_property,
 };
 
 static const struct
 drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {
-       .best_encoder = drm_atomic_helper_best_encoder,
 };
 
 /*
@@ -417,7 +413,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
 
-
        vmw_du_connector_reset(connector);
        ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
                                 DRM_MODE_CONNECTOR_VIRTUAL);
@@ -428,8 +423,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs);
        connector->status = vmw_du_connector_detect(connector, true);
-       vmw_connector_state_to_vcs(connector->state)->is_implicit = true;
-
 
        ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
                               DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -448,7 +441,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
                goto err_free_encoder;
        }
 
-
        vmw_du_crtc_reset(crtc);
        ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary,
                                        &ldu->base.cursor,
@@ -514,7 +506,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
        if (ret != 0)
                goto err_free;
 
-       vmw_kms_create_implicit_placement_property(dev_priv, true);
+       vmw_kms_create_implicit_placement_property(dev_priv);
 
        if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
                for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
index 8a029bade32a8561e0cf12e86d1e6eb28a69b002..3025bfc001a1d2302fb902b5c38b08b88f330e15 100644 (file)
@@ -85,7 +85,7 @@ static void vmw_resource_release(struct kref *kref)
                        struct ttm_validate_buffer val_buf;
 
                        val_buf.bo = bo;
-                       val_buf.shared = false;
+                       val_buf.num_shared = 0;
                        res->func->unbind(res, false, &val_buf);
                }
                res->backup_dirty = false;
@@ -462,7 +462,7 @@ vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
 
        INIT_LIST_HEAD(&val_list);
        val_buf->bo = ttm_bo_reference(&res->backup->base);
-       val_buf->shared = false;
+       val_buf->num_shared = 0;
        list_add_tail(&val_buf->head, &val_list);
        ret = ttm_eu_reserve_buffers(ticket, &val_list, interruptible, NULL);
        if (unlikely(ret != 0))
@@ -565,7 +565,7 @@ static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket,
        BUG_ON(!func->may_evict);
 
        val_buf.bo = NULL;
-       val_buf.shared = false;
+       val_buf.num_shared = 0;
        ret = vmw_resource_check_buffer(ticket, res, interruptible, &val_buf);
        if (unlikely(ret != 0))
                return ret;
@@ -614,7 +614,7 @@ int vmw_resource_validate(struct vmw_resource *res, bool intr)
                return 0;
 
        val_buf.bo = NULL;
-       val_buf.shared = false;
+       val_buf.num_shared = 0;
        if (res->backup)
                val_buf.bo = &res->backup->base;
        do {
@@ -685,7 +685,7 @@ void vmw_resource_unbind_list(struct vmw_buffer_object *vbo)
        struct vmw_resource *res, *next;
        struct ttm_validate_buffer val_buf = {
                .bo = &vbo->base,
-               .shared = false
+               .num_shared = 0
        };
 
        lockdep_assert_held(&vbo->base.resv->lock.base);
index 53316b1bda3d6de9744313c66ebf27eda5642826..cd586c52af7e19c621965e1e620de41a684c33a8 100644 (file)
@@ -29,6 +29,7 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_damage_helper.h>
 
 
 #define vmw_crtc_to_sou(x) \
@@ -76,6 +77,11 @@ struct vmw_kms_sou_dirty_cmd {
        SVGA3dCmdBlitSurfaceToScreen body;
 };
 
+struct vmw_kms_sou_define_gmrfb {
+       uint32_t header;
+       SVGAFifoCmdDefineGMRFB body;
+};
+
 /**
  * Display unit using screen objects.
  */
@@ -241,28 +247,20 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
                sou->buffer = vps->bo;
                sou->buffer_size = vps->bo_size;
 
-               if (sou->base.is_implicit) {
-                       x = crtc->x;
-                       y = crtc->y;
-               } else {
-                       conn_state = sou->base.connector.state;
-                       vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
+               conn_state = sou->base.connector.state;
+               vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
 
-                       x = vmw_conn_state->gui_x;
-                       y = vmw_conn_state->gui_y;
-               }
+               x = vmw_conn_state->gui_x;
+               y = vmw_conn_state->gui_y;
 
                ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
                if (ret)
                        DRM_ERROR("Failed to define Screen Object %dx%d\n",
                                  crtc->x, crtc->y);
 
-               vmw_kms_add_active(dev_priv, &sou->base, vfb);
        } else {
                sou->buffer = NULL;
                sou->buffer_size = 0;
-
-               vmw_kms_del_active(dev_priv, &sou->base);
        }
 }
 
@@ -317,38 +315,14 @@ static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
        }
 }
 
-static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
-                                 struct drm_framebuffer *new_fb,
-                                 struct drm_pending_vblank_event *event,
-                                 uint32_t flags,
-                                 struct drm_modeset_acquire_ctx *ctx)
-{
-       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-       int ret;
-
-       if (!vmw_kms_crtc_flippable(dev_priv, crtc))
-               return -EINVAL;
-
-       ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
-       if (ret) {
-               DRM_ERROR("Page flip error %d.\n", ret);
-               return ret;
-       }
-
-       if (vmw_crtc_to_du(crtc)->is_implicit)
-               vmw_kms_update_implicit_fb(dev_priv, crtc);
-
-       return ret;
-}
-
 static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_sou_crtc_destroy,
        .reset = vmw_du_crtc_reset,
        .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
        .atomic_destroy_state = vmw_du_crtc_destroy_state,
-       .set_config = vmw_kms_set_config,
-       .page_flip = vmw_sou_crtc_page_flip,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
 };
 
 /*
@@ -377,19 +351,15 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
        .dpms = vmw_du_connector_dpms,
        .detect = vmw_du_connector_detect,
        .fill_modes = vmw_du_connector_fill_modes,
-       .set_property = vmw_du_connector_set_property,
        .destroy = vmw_sou_connector_destroy,
        .reset = vmw_du_connector_reset,
        .atomic_duplicate_state = vmw_du_connector_duplicate_state,
        .atomic_destroy_state = vmw_du_connector_destroy_state,
-       .atomic_set_property = vmw_du_connector_atomic_set_property,
-       .atomic_get_property = vmw_du_connector_atomic_get_property,
 };
 
 
 static const struct
 drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
-       .best_encoder = drm_atomic_helper_best_encoder,
 };
 
 
@@ -499,6 +469,263 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
        return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
 }
 
+static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update,
+                                    uint32_t num_hits)
+{
+       return sizeof(struct vmw_kms_sou_define_gmrfb) +
+               sizeof(struct vmw_kms_sou_bo_blit) * num_hits;
+}
+
+static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update,
+                                       void *cmd)
+{
+       struct vmw_framebuffer_bo *vfbbo =
+               container_of(update->vfb, typeof(*vfbbo), base);
+       struct vmw_kms_sou_define_gmrfb *gmr = cmd;
+       int depth = update->vfb->base.format->depth;
+
+       /* Emulate RGBA support, contrary to svga_reg.h this is not
+        * supported by hosts. This is only a problem if we are reading
+        * this value later and expecting what we uploaded back.
+        */
+       if (depth == 32)
+               depth = 24;
+
+       gmr->header = SVGA_CMD_DEFINE_GMRFB;
+
+       gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8;
+       gmr->body.format.colorDepth = depth;
+       gmr->body.format.reserved = 0;
+       gmr->body.bytesPerLine = update->vfb->base.pitches[0];
+       vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr);
+
+       return sizeof(*gmr);
+}
+
+static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane  *update,
+                                        void *cmd, struct drm_rect *clip,
+                                        uint32_t fb_x, uint32_t fb_y)
+{
+       struct vmw_kms_sou_bo_blit *blit = cmd;
+
+       blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
+       blit->body.destScreenId = update->du->unit;
+       blit->body.srcOrigin.x = fb_x;
+       blit->body.srcOrigin.y = fb_y;
+       blit->body.destRect.left = clip->x1;
+       blit->body.destRect.top = clip->y1;
+       blit->body.destRect.right = clip->x2;
+       blit->body.destRect.bottom = clip->y2;
+
+       return sizeof(*blit);
+}
+
+static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane  *update,
+                                     void *cmd, struct drm_rect *bb)
+{
+       return 0;
+}
+
+/**
+ * vmw_sou_plane_update_bo - Update display unit for bo backed fb.
+ * @dev_priv: Device private.
+ * @plane: Plane state.
+ * @old_state: Old plane state.
+ * @vfb: Framebuffer which is blitted to display unit.
+ * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
+ *             The returned fence pointer may be NULL in which case the device
+ *             has already synchronized.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
+                                  struct drm_plane *plane,
+                                  struct drm_plane_state *old_state,
+                                  struct vmw_framebuffer *vfb,
+                                  struct vmw_fence_obj **out_fence)
+{
+       struct vmw_du_update_plane_buffer bo_update;
+
+       memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
+       bo_update.base.plane = plane;
+       bo_update.base.old_state = old_state;
+       bo_update.base.dev_priv = dev_priv;
+       bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
+       bo_update.base.vfb = vfb;
+       bo_update.base.out_fence = out_fence;
+       bo_update.base.mutex = NULL;
+       bo_update.base.cpu_blit = false;
+       bo_update.base.intr = true;
+
+       bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size;
+       bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb;
+       bo_update.base.clip = vmw_sou_bo_populate_clip;
+       bo_update.base.post_clip = vmw_stud_bo_post_clip;
+
+       return vmw_du_helper_plane_update(&bo_update.base);
+}
+
+static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update,
+                                         uint32_t num_hits)
+{
+       return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) *
+               num_hits;
+}
+
+static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update,
+                                            void *cmd)
+{
+       struct vmw_du_update_plane_surface *srf_update;
+
+       srf_update = container_of(update, typeof(*srf_update), base);
+
+       /*
+        * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that
+        * its bounding box is filled before iterating over all the clips. So
+        * store the FIFO start address and revisit to fill the details.
+        */
+       srf_update->cmd_start = cmd;
+
+       return 0;
+}
+
+static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
+                                        void *cmd, uint32_t num_hits)
+{
+       struct vmw_kms_sou_dirty_cmd *blit = cmd;
+       struct vmw_framebuffer_surface *vfbs;
+
+       vfbs = container_of(update->vfb, typeof(*vfbs), base);
+
+       blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
+       blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) *
+               num_hits;
+
+       blit->body.srcImage.sid = vfbs->surface->res.id;
+       blit->body.destScreenId = update->du->unit;
+
+       /* Update the source and destination bounding box later in post_clip */
+       blit->body.srcRect.left = 0;
+       blit->body.srcRect.top = 0;
+       blit->body.srcRect.right = 0;
+       blit->body.srcRect.bottom = 0;
+
+       blit->body.destRect.left = 0;
+       blit->body.destRect.top = 0;
+       blit->body.destRect.right = 0;
+       blit->body.destRect.bottom = 0;
+
+       return sizeof(*blit);
+}
+
+static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update,
+                                         void *cmd, struct drm_rect *clip,
+                                         uint32_t src_x, uint32_t src_y)
+{
+       SVGASignedRect *rect = cmd;
+
+       /*
+        * rects are relative to dest bounding box rect on screen object, so
+        * translate to it later in post_clip
+        */
+       rect->left = clip->x1;
+       rect->top = clip->y1;
+       rect->right = clip->x2;
+       rect->bottom = clip->y2;
+
+       return sizeof(*rect);
+}
+
+static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update,
+                                         void *cmd, struct drm_rect *bb)
+{
+       struct vmw_du_update_plane_surface *srf_update;
+       struct drm_plane_state *state = update->plane->state;
+       struct drm_rect src_bb;
+       struct vmw_kms_sou_dirty_cmd *blit;
+       SVGASignedRect *rect;
+       uint32_t num_hits;
+       int translate_src_x;
+       int translate_src_y;
+       int i;
+
+       srf_update = container_of(update, typeof(*srf_update), base);
+
+       blit = srf_update->cmd_start;
+       rect = (SVGASignedRect *)&blit[1];
+
+       num_hits = (blit->header.size - sizeof(blit->body))/
+               sizeof(SVGASignedRect);
+
+       src_bb = *bb;
+
+       /* To translate bb back to fb src coord */
+       translate_src_x = (state->src_x >> 16) - state->crtc_x;
+       translate_src_y = (state->src_y >> 16) - state->crtc_y;
+
+       drm_rect_translate(&src_bb, translate_src_x, translate_src_y);
+
+       blit->body.srcRect.left = src_bb.x1;
+       blit->body.srcRect.top = src_bb.y1;
+       blit->body.srcRect.right = src_bb.x2;
+       blit->body.srcRect.bottom = src_bb.y2;
+
+       blit->body.destRect.left = bb->x1;
+       blit->body.destRect.top = bb->y1;
+       blit->body.destRect.right = bb->x2;
+       blit->body.destRect.bottom = bb->y2;
+
+       /* rects are relative to dest bb rect */
+       for (i = 0; i < num_hits; i++) {
+               rect->left -= bb->x1;
+               rect->top -= bb->y1;
+               rect->right -= bb->x1;
+               rect->bottom -= bb->y1;
+               rect++;
+       }
+
+       return 0;
+}
+
+/**
+ * vmw_sou_plane_update_surface - Update display unit for surface backed fb.
+ * @dev_priv: Device private.
+ * @plane: Plane state.
+ * @old_state: Old plane state.
+ * @vfb: Framebuffer which is blitted to display unit
+ * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
+ *             The returned fence pointer may be NULL in which case the device
+ *             has already synchronized.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
+                                       struct drm_plane *plane,
+                                       struct drm_plane_state *old_state,
+                                       struct vmw_framebuffer *vfb,
+                                       struct vmw_fence_obj **out_fence)
+{
+       struct vmw_du_update_plane_surface srf_update;
+
+       memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface));
+       srf_update.base.plane = plane;
+       srf_update.base.old_state = old_state;
+       srf_update.base.dev_priv = dev_priv;
+       srf_update.base.du = vmw_crtc_to_du(plane->state->crtc);
+       srf_update.base.vfb = vfb;
+       srf_update.base.out_fence = out_fence;
+       srf_update.base.mutex = &dev_priv->cmdbuf_mutex;
+       srf_update.base.cpu_blit = false;
+       srf_update.base.intr = true;
+
+       srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size;
+       srf_update.base.post_prepare = vmw_sou_surface_post_prepare;
+       srf_update.base.pre_clip = vmw_sou_surface_pre_clip;
+       srf_update.base.clip = vmw_sou_surface_clip_rect;
+       srf_update.base.post_clip = vmw_sou_surface_post_clip;
+
+       return vmw_du_helper_plane_update(&srf_update.base);
+}
 
 static void
 vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
@@ -509,47 +736,28 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
        struct vmw_fence_obj *fence = NULL;
        int ret;
 
+       /* In case of device error, maintain consistent atomic state */
        if (crtc && plane->state->fb) {
                struct vmw_private *dev_priv = vmw_priv(crtc->dev);
                struct vmw_framebuffer *vfb =
                        vmw_framebuffer_to_vfb(plane->state->fb);
-               struct drm_vmw_rect vclips;
-
-               vclips.x = crtc->x;
-               vclips.y = crtc->y;
-               vclips.w = crtc->mode.hdisplay;
-               vclips.h = crtc->mode.vdisplay;
 
                if (vfb->bo)
-                       ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL,
-                                                     &vclips, 1, 1, true,
-                                                     &fence, crtc);
+                       ret = vmw_sou_plane_update_bo(dev_priv, plane,
+                                                     old_state, vfb, &fence);
                else
-                       ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL,
-                                                          &vclips, NULL, 0, 0,
-                                                          1, 1, &fence, crtc);
-
-               /*
-                * We cannot really fail this function, so if we do, then output
-                * an error and maintain consistent atomic state.
-                */
+                       ret = vmw_sou_plane_update_surface(dev_priv, plane,
+                                                          old_state, vfb,
+                                                          &fence);
                if (ret != 0)
                        DRM_ERROR("Failed to update screen.\n");
        } else {
-               /*
-                * When disabling a plane, CRTC and FB should always be NULL
-                * together, otherwise it's an error.
-                * Here primary plane is being disable so should really blank
-                * the screen object display unit, if not already done.
-                */
+               /* Do nothing when fb and crtc is NULL (blank crtc) */
                return;
        }
 
+       /* For error case vblank event is send from vmw_du_crtc_atomic_flush */
        event = crtc->state->event;
-       /*
-        * In case of failure and other cases, vblank event will be sent in
-        * vmw_du_crtc_atomic_flush.
-        */
        if (event && fence) {
                struct drm_file *file_priv = event->base.file_priv;
 
@@ -640,7 +848,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
        primary = &sou->base.primary;
        cursor = &sou->base.cursor;
 
-       sou->base.active_implicit = false;
        sou->base.pref_active = (unit == 0);
        sou->base.pref_width = dev_priv->initial_width;
        sou->base.pref_height = dev_priv->initial_height;
@@ -666,6 +873,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
        }
 
        drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
+       drm_plane_enable_fb_damage_clips(primary);
 
        /* Initialize cursor plane */
        vmw_du_plane_reset(cursor);
@@ -693,8 +901,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs);
        connector->status = vmw_du_connector_detect(connector, true);
-       vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
-
 
        ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
                               DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -733,12 +939,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
                                   dev->mode_config.suggested_x_property, 0);
        drm_object_attach_property(&connector->base,
                                   dev->mode_config.suggested_y_property, 0);
-       if (dev_priv->implicit_placement_property)
-               drm_object_attach_property
-                       (&connector->base,
-                        dev_priv->implicit_placement_property,
-                        sou->base.is_implicit);
-
        return 0;
 
 err_free_unregister:
@@ -764,15 +964,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
        }
 
        ret = -ENOMEM;
-       dev_priv->num_implicit = 0;
-       dev_priv->implicit_fb = NULL;
 
        ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
        if (unlikely(ret != 0))
                return ret;
 
-       vmw_kms_create_implicit_placement_property(dev_priv, false);
-
        for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
                vmw_sou_init(dev_priv, i);
 
index e086565c1da6d80f2a924947230ccd14ca7175fc..096c2941a8e41ac528c30219f9743f4b0241582a 100644 (file)
@@ -30,7 +30,7 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
-
+#include <drm/drm_damage_helper.h>
 
 #define vmw_crtc_to_stdu(x) \
        container_of(x, struct vmw_screen_target_display_unit, base.crtc)
@@ -92,6 +92,10 @@ struct vmw_stdu_surface_copy {
        SVGA3dCmdSurfaceCopy body;
 };
 
+struct vmw_stdu_update_gb_image {
+       SVGA3dCmdHeader header;
+       SVGA3dCmdUpdateGBImage body;
+};
 
 /**
  * struct vmw_screen_target_display_unit
@@ -396,13 +400,8 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
        if (!crtc->state->enable)
                return;
 
-       if (stdu->base.is_implicit) {
-               x = crtc->x;
-               y = crtc->y;
-       } else {
-               x = vmw_conn_state->gui_x;
-               y = vmw_conn_state->gui_y;
-       }
+       x = vmw_conn_state->gui_x;
+       y = vmw_conn_state->gui_y;
 
        vmw_svga_enable(dev_priv);
        ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y);
@@ -417,27 +416,9 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
 {
 }
 
-
 static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc,
                                        struct drm_crtc_state *old_state)
 {
-       struct drm_plane_state *plane_state = crtc->primary->state;
-       struct vmw_private *dev_priv;
-       struct vmw_screen_target_display_unit *stdu;
-       struct vmw_framebuffer *vfb;
-       struct drm_framebuffer *fb;
-
-
-       stdu     = vmw_crtc_to_stdu(crtc);
-       dev_priv = vmw_priv(crtc->dev);
-       fb       = plane_state->fb;
-
-       vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
-
-       if (vfb)
-               vmw_kms_add_active(dev_priv, &stdu->base, vfb);
-       else
-               vmw_kms_del_active(dev_priv, &stdu->base);
 }
 
 static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -471,49 +452,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
        }
 }
 
-/**
- * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target
- *
- * @crtc: CRTC to attach FB to
- * @fb: FB to attach
- * @event: Event to be posted. This event should've been alloced
- *         using k[mz]alloc, and should've been completely initialized.
- * @page_flip_flags: Input flags.
- *
- * If the STDU uses the same display and content buffers, i.e. a true flip,
- * this function will replace the existing display buffer with the new content
- * buffer.
- *
- * If the STDU uses different display and content buffers, i.e. a blit, then
- * only the content buffer will be updated.
- *
- * RETURNS:
- * 0 on success, error code on failure
- */
-static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
-                                  struct drm_framebuffer *new_fb,
-                                  struct drm_pending_vblank_event *event,
-                                  uint32_t flags,
-                                  struct drm_modeset_acquire_ctx *ctx)
-
-{
-       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-       struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
-       int ret;
-
-       if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
-               return -EINVAL;
-
-       ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
-       if (ret) {
-               DRM_ERROR("Page flip error %d.\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-
 /**
  * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect
  *
@@ -986,8 +924,8 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
        .reset = vmw_du_crtc_reset,
        .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
        .atomic_destroy_state = vmw_du_crtc_destroy_state,
-       .set_config = vmw_kms_set_config,
-       .page_flip = vmw_stdu_crtc_page_flip,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
 };
 
 
@@ -1042,19 +980,15 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
        .dpms = vmw_du_connector_dpms,
        .detect = vmw_du_connector_detect,
        .fill_modes = vmw_du_connector_fill_modes,
-       .set_property = vmw_du_connector_set_property,
        .destroy = vmw_stdu_connector_destroy,
        .reset = vmw_du_connector_reset,
        .atomic_duplicate_state = vmw_du_connector_duplicate_state,
        .atomic_destroy_state = vmw_du_connector_destroy_state,
-       .atomic_set_property = vmw_du_connector_atomic_set_property,
-       .atomic_get_property = vmw_du_connector_atomic_get_property,
 };
 
 
 static const struct
 drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
-       .best_encoder = drm_atomic_helper_best_encoder,
 };
 
 
@@ -1257,11 +1191,402 @@ out_srf_unref:
        return ret;
 }
 
+static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update,
+                                     uint32_t num_hits)
+{
+       return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits +
+               sizeof(SVGA3dCmdSurfaceDMASuffix) +
+               sizeof(struct vmw_stdu_update);
+}
+
+static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update,
+                                         uint32_t num_hits)
+{
+       return sizeof(struct vmw_stdu_update_gb_image) +
+               sizeof(struct vmw_stdu_update);
+}
+
+static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane  *update,
+                                        void *cmd, uint32_t num_hits)
+{
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer_bo *vfbbo;
+       struct vmw_stdu_dma *cmd_dma = cmd;
+
+       stdu = container_of(update->du, typeof(*stdu), base);
+       vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
+
+       cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA;
+       cmd_dma->header.size = sizeof(cmd_dma->body) +
+               sizeof(struct SVGA3dCopyBox) * num_hits +
+               sizeof(SVGA3dCmdSurfaceDMASuffix);
+       vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr);
+       cmd_dma->body.guest.pitch = update->vfb->base.pitches[0];
+       cmd_dma->body.host.sid = stdu->display_srf->res.id;
+       cmd_dma->body.host.face = 0;
+       cmd_dma->body.host.mipmap = 0;
+       cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM;
+
+       return sizeof(*cmd_dma);
+}
+
+static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane  *update,
+                                         void *cmd, struct drm_rect *clip,
+                                         uint32_t fb_x, uint32_t fb_y)
+{
+       struct SVGA3dCopyBox *box = cmd;
+
+       box->srcx = fb_x;
+       box->srcy = fb_y;
+       box->srcz = 0;
+       box->x = clip->x1;
+       box->y = clip->y1;
+       box->z = 0;
+       box->w = drm_rect_width(clip);
+       box->h = drm_rect_height(clip);
+       box->d = 1;
+
+       return sizeof(*box);
+}
+
+static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane  *update,
+                                           void *cmd, struct drm_rect *bb)
+{
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer_bo *vfbbo;
+       SVGA3dCmdSurfaceDMASuffix *suffix = cmd;
+
+       stdu = container_of(update->du, typeof(*stdu), base);
+       vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
+
+       suffix->suffixSize = sizeof(*suffix);
+       suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE;
+
+       vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2,
+                                bb->y1, bb->y2);
+
+       return sizeof(*suffix) + sizeof(struct vmw_stdu_update);
+}
+
+static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane  *update,
+                                        void *cmd, uint32_t num_hits)
+{
+       struct vmw_du_update_plane_buffer *bo_update =
+               container_of(update, typeof(*bo_update), base);
+
+       bo_update->fb_left = INT_MAX;
+       bo_update->fb_top = INT_MAX;
+
+       return 0;
+}
+
+static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane  *update,
+                                    void *cmd, struct drm_rect *clip,
+                                    uint32_t fb_x, uint32_t fb_y)
+{
+       struct vmw_du_update_plane_buffer *bo_update =
+               container_of(update, typeof(*bo_update), base);
+
+       bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x);
+       bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y);
+
+       return 0;
+}
+
+static uint32_t
+vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane  *update, void *cmd,
+                               struct drm_rect *bb)
+{
+       struct vmw_du_update_plane_buffer *bo_update;
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer_bo *vfbbo;
+       struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0);
+       struct vmw_stdu_update_gb_image *cmd_img = cmd;
+       struct vmw_stdu_update *cmd_update;
+       struct ttm_buffer_object *src_bo, *dst_bo;
+       u32 src_offset, dst_offset;
+       s32 src_pitch, dst_pitch;
+       s32 width, height;
+
+       bo_update = container_of(update, typeof(*bo_update), base);
+       stdu = container_of(update->du, typeof(*stdu), base);
+       vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
+
+       width = bb->x2 - bb->x1;
+       height = bb->y2 - bb->y1;
+
+       diff.cpp = stdu->cpp;
+
+       dst_bo = &stdu->display_srf->res.backup->base;
+       dst_pitch = stdu->display_srf->base_size.width * stdu->cpp;
+       dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp;
+
+       src_bo = &vfbbo->buffer->base;
+       src_pitch = update->vfb->base.pitches[0];
+       src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left *
+               stdu->cpp;
+
+       (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo,
+                              src_offset, src_pitch, width * stdu->cpp, height,
+                              &diff);
+
+       if (drm_rect_visible(&diff.rect)) {
+               SVGA3dBox *box = &cmd_img->body.box;
+
+               cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
+               cmd_img->header.size = sizeof(cmd_img->body);
+               cmd_img->body.image.sid = stdu->display_srf->res.id;
+               cmd_img->body.image.face = 0;
+               cmd_img->body.image.mipmap = 0;
+
+               box->x = diff.rect.x1;
+               box->y = diff.rect.y1;
+               box->z = 0;
+               box->w = drm_rect_width(&diff.rect);
+               box->h = drm_rect_height(&diff.rect);
+               box->d = 1;
+
+               cmd_update = (struct vmw_stdu_update *)&cmd_img[1];
+               vmw_stdu_populate_update(cmd_update, stdu->base.unit,
+                                        diff.rect.x1, diff.rect.x2,
+                                        diff.rect.y1, diff.rect.y2);
+
+               return sizeof(*cmd_img) + sizeof(*cmd_update);
+       }
+
+       return 0;
+}
+
+/**
+ * vmw_stdu_plane_update_bo - Update display unit for bo backed fb.
+ * @dev_priv: device private.
+ * @plane: plane state.
+ * @old_state: old plane state.
+ * @vfb: framebuffer which is blitted to display unit.
+ * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
+ *             The returned fence pointer may be NULL in which case the device
+ *             has already synchronized.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
+                                   struct drm_plane *plane,
+                                   struct drm_plane_state *old_state,
+                                   struct vmw_framebuffer *vfb,
+                                   struct vmw_fence_obj **out_fence)
+{
+       struct vmw_du_update_plane_buffer bo_update;
+
+       memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
+       bo_update.base.plane = plane;
+       bo_update.base.old_state = old_state;
+       bo_update.base.dev_priv = dev_priv;
+       bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
+       bo_update.base.vfb = vfb;
+       bo_update.base.out_fence = out_fence;
+       bo_update.base.mutex = NULL;
+       bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
+       bo_update.base.intr = false;
+
+       /*
+        * VM without 3D support don't have surface DMA command and framebuffer
+        * should be moved out of VRAM.
+        */
+       if (bo_update.base.cpu_blit) {
+               bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu;
+               bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu;
+               bo_update.base.clip = vmw_stdu_bo_clip_cpu;
+               bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu;
+       } else {
+               bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size;
+               bo_update.base.pre_clip = vmw_stdu_bo_populate_dma;
+               bo_update.base.clip = vmw_stdu_bo_populate_clip;
+               bo_update.base.post_clip = vmw_stdu_bo_populate_update;
+       }
+
+       return vmw_du_helper_plane_update(&bo_update.base);
+}
+
+static uint32_t
+vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
+                                       uint32_t num_hits)
+{
+       struct vmw_framebuffer_surface *vfbs;
+       uint32_t size = 0;
+
+       vfbs = container_of(update->vfb, typeof(*vfbs), base);
+
+       if (vfbs->is_bo_proxy)
+               size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
+
+       size += sizeof(struct vmw_stdu_update);
+
+       return size;
+}
+
+static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update,
+                                          uint32_t num_hits)
+{
+       struct vmw_framebuffer_surface *vfbs;
+       uint32_t size = 0;
+
+       vfbs = container_of(update->vfb, typeof(*vfbs), base);
+
+       if (vfbs->is_bo_proxy)
+               size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
+
+       size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) *
+               num_hits + sizeof(struct vmw_stdu_update);
+
+       return size;
+}
+
+static uint32_t
+vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd)
+{
+       struct vmw_framebuffer_surface *vfbs;
+       struct drm_plane_state *state = update->plane->state;
+       struct drm_plane_state *old_state = update->old_state;
+       struct vmw_stdu_update_gb_image *cmd_update = cmd;
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_rect clip;
+       uint32_t copy_size = 0;
+
+       vfbs = container_of(update->vfb, typeof(*vfbs), base);
+
+       /*
+        * proxy surface is special where a buffer object type fb is wrapped
+        * in a surface and need an update gb image command to sync with device.
+        */
+       drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+       drm_atomic_for_each_plane_damage(&iter, &clip) {
+               SVGA3dBox *box = &cmd_update->body.box;
+
+               cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
+               cmd_update->header.size = sizeof(cmd_update->body);
+               cmd_update->body.image.sid = vfbs->surface->res.id;
+               cmd_update->body.image.face = 0;
+               cmd_update->body.image.mipmap = 0;
+
+               box->x = clip.x1;
+               box->y = clip.y1;
+               box->z = 0;
+               box->w = drm_rect_width(&clip);
+               box->h = drm_rect_height(&clip);
+               box->d = 1;
+
+               copy_size += sizeof(*cmd_update);
+               cmd_update++;
+       }
+
+       return copy_size;
+}
+
+static uint32_t
+vmw_stdu_surface_populate_copy(struct vmw_du_update_plane  *update, void *cmd,
+                              uint32_t num_hits)
+{
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer_surface *vfbs;
+       struct vmw_stdu_surface_copy *cmd_copy = cmd;
+
+       stdu = container_of(update->du, typeof(*stdu), base);
+       vfbs = container_of(update->vfb, typeof(*vfbs), base);
+
+       cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY;
+       cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) *
+               num_hits;
+       cmd_copy->body.src.sid = vfbs->surface->res.id;
+       cmd_copy->body.dest.sid = stdu->display_srf->res.id;
+
+       return sizeof(*cmd_copy);
+}
+
+static uint32_t
+vmw_stdu_surface_populate_clip(struct vmw_du_update_plane  *update, void *cmd,
+                              struct drm_rect *clip, uint32_t fb_x,
+                              uint32_t fb_y)
+{
+       struct SVGA3dCopyBox *box = cmd;
+
+       box->srcx = fb_x;
+       box->srcy = fb_y;
+       box->srcz = 0;
+       box->x = clip->x1;
+       box->y = clip->y1;
+       box->z = 0;
+       box->w = drm_rect_width(clip);
+       box->h = drm_rect_height(clip);
+       box->d = 1;
+
+       return sizeof(*box);
+}
+
+static uint32_t
+vmw_stdu_surface_populate_update(struct vmw_du_update_plane  *update, void *cmd,
+                                struct drm_rect *bb)
+{
+       vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1,
+                                bb->y2);
 
+       return sizeof(struct vmw_stdu_update);
+}
 
 /**
- * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
+ * vmw_stdu_plane_update_surface - Update display unit for surface backed fb
+ * @dev_priv: Device private
+ * @plane: Plane state
+ * @old_state: Old plane state
+ * @vfb: Framebuffer which is blitted to display unit
+ * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
+ *             The returned fence pointer may be NULL in which case the device
+ *             has already synchronized.
  *
+ * Return: 0 on success or a negative error code on failure.
+ */
+static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
+                                        struct drm_plane *plane,
+                                        struct drm_plane_state *old_state,
+                                        struct vmw_framebuffer *vfb,
+                                        struct vmw_fence_obj **out_fence)
+{
+       struct vmw_du_update_plane srf_update;
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer_surface *vfbs;
+
+       stdu = vmw_crtc_to_stdu(plane->state->crtc);
+       vfbs = container_of(vfb, typeof(*vfbs), base);
+
+       memset(&srf_update, 0, sizeof(struct vmw_du_update_plane));
+       srf_update.plane = plane;
+       srf_update.old_state = old_state;
+       srf_update.dev_priv = dev_priv;
+       srf_update.du = vmw_crtc_to_du(plane->state->crtc);
+       srf_update.vfb = vfb;
+       srf_update.out_fence = out_fence;
+       srf_update.mutex = &dev_priv->cmdbuf_mutex;
+       srf_update.cpu_blit = false;
+       srf_update.intr = true;
+
+       if (vfbs->is_bo_proxy)
+               srf_update.post_prepare = vmw_stdu_surface_update_proxy;
+
+       if (vfbs->surface->res.id != stdu->display_srf->res.id) {
+               srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size;
+               srf_update.pre_clip = vmw_stdu_surface_populate_copy;
+               srf_update.clip = vmw_stdu_surface_populate_clip;
+       } else {
+               srf_update.calc_fifo_size =
+                       vmw_stdu_surface_fifo_size_same_display;
+       }
+
+       srf_update.post_clip = vmw_stdu_surface_populate_update;
+
+       return vmw_du_helper_plane_update(&srf_update);
+}
+
+/**
+ * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
  * @plane: display plane
  * @old_state: Only used to get crtc info
  *
@@ -1278,17 +1603,14 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
        struct drm_crtc *crtc = plane->state->crtc;
        struct vmw_screen_target_display_unit *stdu;
        struct drm_pending_vblank_event *event;
+       struct vmw_fence_obj *fence = NULL;
        struct vmw_private *dev_priv;
        int ret;
 
-       /*
-        * We cannot really fail this function, so if we do, then output an
-        * error and maintain consistent atomic state.
-        */
+       /* If case of device error, maintain consistent atomic state */
        if (crtc && plane->state->fb) {
                struct vmw_framebuffer *vfb =
                        vmw_framebuffer_to_vfb(plane->state->fb);
-               struct drm_vmw_rect vclips;
                stdu = vmw_crtc_to_stdu(crtc);
                dev_priv = vmw_priv(crtc->dev);
 
@@ -1296,23 +1618,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
                stdu->content_fb_type = vps->content_fb_type;
                stdu->cpp = vps->cpp;
 
-               vclips.x = crtc->x;
-               vclips.y = crtc->y;
-               vclips.w = crtc->mode.hdisplay;
-               vclips.h = crtc->mode.vdisplay;
-
                ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
                if (ret)
                        DRM_ERROR("Failed to bind surface to STDU.\n");
 
                if (vfb->bo)
-                       ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL,
-                                              &vclips, 1, 1, true, false,
-                                              crtc);
+                       ret = vmw_stdu_plane_update_bo(dev_priv, plane,
+                                                      old_state, vfb, &fence);
                else
-                       ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL,
-                                                        &vclips, NULL, 0, 0,
-                                                        1, 1, NULL, crtc);
+                       ret = vmw_stdu_plane_update_surface(dev_priv, plane,
+                                                           old_state, vfb,
+                                                           &fence);
                if (ret)
                        DRM_ERROR("Failed to update STDU.\n");
        } else {
@@ -1320,12 +1636,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
                stdu = vmw_crtc_to_stdu(crtc);
                dev_priv = vmw_priv(crtc->dev);
 
-               /*
-                * When disabling a plane, CRTC and FB should always be NULL
-                * together, otherwise it's an error.
-                * Here primary plane is being disable so blank the screen
-                * target display unit, if not already done.
-                */
+               /* Blank STDU when fb and crtc are NULL */
                if (!stdu->defined)
                        return;
 
@@ -1340,36 +1651,25 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
                return;
        }
 
+       /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */
        event = crtc->state->event;
-       /*
-        * In case of failure and other cases, vblank event will be sent in
-        * vmw_du_crtc_atomic_flush.
-        */
-       if (event && (ret == 0)) {
-               struct vmw_fence_obj *fence = NULL;
+       if (event && fence) {
                struct drm_file *file_priv = event->base.file_priv;
 
-               vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
-
-               /*
-                * If fence is NULL, then already sync.
-                */
-               if (fence) {
-                       ret = vmw_event_fence_action_queue(
-                               file_priv, fence, &event->base,
-                               &event->event.vbl.tv_sec,
-                               &event->event.vbl.tv_usec,
-                               true);
-                       if (ret)
-                               DRM_ERROR("Failed to queue event on fence.\n");
-                       else
-                               crtc->state->event = NULL;
-
-                       vmw_fence_obj_unreference(&fence);
-               }
-       } else {
-               (void) vmw_fifo_flush(dev_priv, false);
+               ret = vmw_event_fence_action_queue(file_priv,
+                                                  fence,
+                                                  &event->base,
+                                                  &event->event.vbl.tv_sec,
+                                                  &event->event.vbl.tv_usec,
+                                                  true);
+               if (ret)
+                       DRM_ERROR("Failed to queue event on fence.\n");
+               else
+                       crtc->state->event = NULL;
        }
+
+       if (fence)
+               vmw_fence_obj_unreference(&fence);
 }
 
 
@@ -1457,11 +1757,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
        stdu->base.pref_active = (unit == 0);
        stdu->base.pref_width  = dev_priv->initial_width;
        stdu->base.pref_height = dev_priv->initial_height;
-
-       /*
-        * Remove this after enabling atomic because property values can
-        * only exist in a state object
-        */
        stdu->base.is_implicit = false;
 
        /* Initialize primary plane */
@@ -1478,6 +1773,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
        }
 
        drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
+       drm_plane_enable_fb_damage_clips(primary);
 
        /* Initialize cursor plane */
        vmw_du_plane_reset(cursor);
@@ -1506,7 +1802,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
 
        drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs);
        connector->status = vmw_du_connector_detect(connector, false);
-       vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
 
        ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
                               DRM_MODE_ENCODER_VIRTUAL, NULL);
@@ -1544,11 +1839,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
                                   dev->mode_config.suggested_x_property, 0);
        drm_object_attach_property(&connector->base,
                                   dev->mode_config.suggested_y_property, 0);
-       if (dev_priv->implicit_placement_property)
-               drm_object_attach_property
-                       (&connector->base,
-                        dev_priv->implicit_placement_property,
-                        stdu->base.is_implicit);
        return 0;
 
 err_free_unregister:
@@ -1617,8 +1907,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
 
        dev_priv->active_display_unit = vmw_du_screen_target;
 
-       vmw_kms_create_implicit_placement_property(dev_priv, false);
-
        for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
                ret = vmw_stdu_init(dev_priv, i);
 
index f882470467218bef553223b72ab1e0420523a514..e6d75e377dd8b0b827cf758c9e05d8a29c5f20d1 100644 (file)
@@ -43,60 +43,6 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
        return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
 }
 
-static int vmw_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       DRM_INFO("global init.\n");
-       return ttm_mem_global_init(ref->object);
-}
-
-static void vmw_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-int vmw_ttm_global_init(struct vmw_private *dev_priv)
-{
-       struct drm_global_reference *global_ref;
-       int ret;
-
-       global_ref = &dev_priv->mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &vmw_ttm_mem_global_init;
-       global_ref->release = &vmw_ttm_mem_global_release;
-
-       ret = drm_global_item_ref(global_ref);
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed setting up TTM memory accounting.\n");
-               return ret;
-       }
-
-       dev_priv->bo_global_ref.mem_glob =
-               dev_priv->mem_global_ref.object;
-       global_ref = &dev_priv->bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-       ret = drm_global_item_ref(global_ref);
-
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed setting up TTM buffer objects.\n");
-               goto out_no_bo;
-       }
-
-       return 0;
-out_no_bo:
-       drm_global_item_unref(&dev_priv->mem_global_ref);
-       return ret;
-}
-
-void vmw_ttm_global_release(struct vmw_private *dev_priv)
-{
-       drm_global_item_unref(&dev_priv->bo_global_ref.ref);
-       drm_global_item_unref(&dev_priv->mem_global_ref);
-}
-
 /* struct vmw_validation_mem callback */
 static int vmw_vmt_reserve(struct vmw_validation_mem *m, size_t size)
 {
index f116f092e00bcbf33a4c73a12f504a2580435e6c..b3f547fc5d3d849c8483d95283a3ba33e5126039 100644 (file)
@@ -285,7 +285,7 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx,
                val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
                if (!val_buf->bo)
                        return -ESRCH;
-               val_buf->shared = false;
+               val_buf->num_shared = 0;
                list_add_tail(&val_buf->head, &ctx->bo_list);
                bo_node->as_mob = as_mob;
                bo_node->cpu_blit = cpu_blit;
index 11ef17c2d1c1f8961875afc6e3975d935c09a188..f5ea32ae8600b70beb46ce5fdafe3d1a316a6832 100644 (file)
@@ -114,7 +114,7 @@ out_unbind:
        component_unbind_all(dev, drm);
 out_unregister:
        dev_set_drvdata(dev, NULL);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
        return ret;
 }
 
@@ -124,10 +124,11 @@ static void zx_drm_unbind(struct device *dev)
 
        drm_dev_unregister(drm);
        drm_kms_helper_poll_fini(drm);
+       drm_atomic_helper_shutdown(drm);
        drm_mode_config_cleanup(drm);
        component_unbind_all(dev, drm);
        dev_set_drvdata(dev, NULL);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 }
 
 static const struct component_master_ops zx_drm_master_ops = {
index ae8c53b4b261b70eeb6f08b4f721cbd660212b5f..83d236fd893c5e96c6e3c9518919e8a04ceedcd4 100644 (file)
@@ -446,7 +446,6 @@ static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
 
 static void zx_plane_destroy(struct drm_plane *plane)
 {
-       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 }
 
index b92016ce09b77c442d8e19f7bedba305456fe187..096017b8789d257037664273b09026b0c2463bd5 100644 (file)
@@ -13,6 +13,7 @@ host1x-y = \
        hw/host1x02.o \
        hw/host1x04.o \
        hw/host1x05.o \
-       hw/host1x06.o
+       hw/host1x06.o \
+       hw/host1x07.o
 
 obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
index de6bc4e7fa23960705ccd55f5c52f34a84979444..419d8929a98f8f7ca2abf13d00ab3b8f3373f6b7 100644 (file)
@@ -44,6 +44,7 @@
 #include "hw/host1x04.h"
 #include "hw/host1x05.h"
 #include "hw/host1x06.h"
+#include "hw/host1x07.h"
 
 void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
 {
@@ -130,7 +131,19 @@ static const struct host1x_info host1x06_info = {
        .has_hypervisor = true,
 };
 
+static const struct host1x_info host1x07_info = {
+       .nb_channels = 63,
+       .nb_pts = 704,
+       .nb_mlocks = 32,
+       .nb_bases = 0,
+       .init = host1x07_init,
+       .sync_offset = 0x0,
+       .dma_mask = DMA_BIT_MASK(40),
+       .has_hypervisor = true,
+};
+
 static const struct of_device_id host1x_of_match[] = {
+       { .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, },
        { .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
        { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
        { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
index d188f9068b9109c707d7ec6b5d9f826e6e1fe11d..95ea81172a83460d95139428d64f980f460c3263 100644 (file)
@@ -26,7 +26,6 @@
 #include "../intr.h"
 #include "../job.h"
 
-#define HOST1X_CHANNEL_SIZE 16384
 #define TRACE_MAX_LENGTH 128U
 
 static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
@@ -203,7 +202,11 @@ static void enable_gather_filter(struct host1x *host,
 static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
                               unsigned int index)
 {
-       ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE;
+#if HOST1X_HW < 6
+       ch->regs = dev->regs + index * 0x4000;
+#else
+       ch->regs = dev->regs + index * 0x100;
+#endif
        enable_gather_filter(dev, ch);
        return 0;
 }
index b503c740c022dae1cb6d9d2bacb79cd9a045e393..8b749516c0518622f3c8549fec1a07fad5ce0c51 100644 (file)
@@ -62,9 +62,12 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
                                           struct host1x_channel *ch,
                                           struct output *o)
 {
-       u32 val, rd_ptr, wr_ptr, start, end;
+#if HOST1X_HW <= 6
+       u32 rd_ptr, wr_ptr, start, end;
        u32 payload = INVALID_PAYLOAD;
        unsigned int data_count = 0;
+#endif
+       u32 val;
 
        host1x_debug_output(o, "%u: fifo:\n", ch->id);
 
@@ -78,6 +81,7 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
        val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDFIFO_RDATA);
        host1x_debug_output(o, "CMDFIFO_RDATA %08x\n", val);
 
+#if HOST1X_HW <= 6
        /* Peek pointer values are invalid during SLCG, so disable it */
        host1x_hypervisor_writel(host, 0x1, HOST1X_HV_ICG_EN_OVERRIDE);
 
@@ -127,6 +131,7 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
 
        host1x_hypervisor_writel(host, 0x0, HOST1X_HV_CMDFIFO_PEEK_CTRL);
        host1x_hypervisor_writel(host, 0x0, HOST1X_HV_ICG_EN_OVERRIDE);
+#endif
 }
 
 static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
diff --git a/drivers/gpu/host1x/hw/host1x07.c b/drivers/gpu/host1x/hw/host1x07.c
new file mode 100644 (file)
index 0000000..04b779a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Host1x init for Tegra194 SoCs
+ *
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* include hw specification */
+#include "host1x07.h"
+#include "host1x07_hardware.h"
+
+/* include code */
+#define HOST1X_HW 7
+
+#include "cdma_hw.c"
+#include "channel_hw.c"
+#include "debug_hw.c"
+#include "intr_hw.c"
+#include "syncpt_hw.c"
+
+#include "../dev.h"
+
+int host1x07_init(struct host1x *host)
+{
+       host->channel_op = &host1x_channel_ops;
+       host->cdma_op = &host1x_cdma_ops;
+       host->cdma_pb_op = &host1x_pushbuffer_ops;
+       host->syncpt_op = &host1x_syncpt_ops;
+       host->intr_op = &host1x_intr_ops;
+       host->debug_op = &host1x_debug_ops;
+
+       return 0;
+}
diff --git a/drivers/gpu/host1x/hw/host1x07.h b/drivers/gpu/host1x/hw/host1x07.h
new file mode 100644 (file)
index 0000000..57b19f3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Host1x init for Tegra194 SoCs
+ *
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HOST1X_HOST1X07_H
+#define HOST1X_HOST1X07_H
+
+struct host1x;
+
+int host1x07_init(struct host1x *host);
+
+#endif
diff --git a/drivers/gpu/host1x/hw/host1x07_hardware.h b/drivers/gpu/host1x/hw/host1x07_hardware.h
new file mode 100644 (file)
index 0000000..1353e7a
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Tegra host1x Register Offsets for Tegra194
+ *
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST1X_HOST1X07_HARDWARE_H
+#define __HOST1X_HOST1X07_HARDWARE_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#include "hw_host1x07_uclass.h"
+#include "hw_host1x07_vm.h"
+#include "hw_host1x07_hypervisor.h"
+
+static inline u32 host1x_class_host_wait_syncpt(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_wait_syncpt_indx_f(indx)
+               | host1x_uclass_wait_syncpt_thresh_f(threshold);
+}
+
+static inline u32 host1x_class_host_load_syncpt_base(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_load_syncpt_base_base_indx_f(indx)
+               | host1x_uclass_load_syncpt_base_value_f(threshold);
+}
+
+static inline u32 host1x_class_host_wait_syncpt_base(
+       unsigned indx, unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_wait_syncpt_base_indx_f(indx)
+               | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_wait_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt_base(
+       unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_incr_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt(
+       unsigned cond, unsigned indx)
+{
+       return host1x_uclass_incr_syncpt_cond_f(cond)
+               | host1x_uclass_incr_syncpt_indx_f(indx);
+}
+
+static inline u32 host1x_class_host_indoff_reg_write(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indbe_f(0xf)
+               | host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset);
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+static inline u32 host1x_class_host_indoff_reg_read(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset)
+               | host1x_uclass_indoff_rwn_read_v();
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+/* cdma opcodes */
+static inline u32 host1x_opcode_setclass(
+       unsigned class_id, unsigned offset, unsigned mask)
+{
+       return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
+}
+
+static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
+{
+       return (1 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
+{
+       return (2 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
+{
+       return (3 << 28) | (offset << 16) | mask;
+}
+
+static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
+{
+       return (4 << 28) | (offset << 16) | value;
+}
+
+static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
+{
+       return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(),
+               host1x_class_host_incr_syncpt(cond, indx));
+}
+
+static inline u32 host1x_opcode_restart(unsigned address)
+{
+       return (5 << 28) | (address >> 4);
+}
+
+static inline u32 host1x_opcode_gather(unsigned count)
+{
+       return (6 << 28) | count;
+}
+
+static inline u32 host1x_opcode_gather_nonincr(unsigned offset,        unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | count;
+}
+
+static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
+}
+
+#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
+
+#endif
index 4457486c72b05e0dd5f2b3ddade15276e5fa98c7..e599e15bf999aa44a70d0c796956739b02adc126 100644 (file)
@@ -59,7 +59,7 @@ static inline u32 host1x_uclass_incr_syncpt_r(void)
        host1x_uclass_incr_syncpt_r()
 static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
 {
-       return (v & 0xff) << 8;
+       return (v & 0xff) << 10;
 }
 #define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
        host1x_uclass_incr_syncpt_cond_f(v)
diff --git a/drivers/gpu/host1x/hw/hw_host1x07_hypervisor.h b/drivers/gpu/host1x/hw/hw_host1x07_hypervisor.h
new file mode 100644 (file)
index 0000000..2b99d68
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define HOST1X_HV_SYNCPT_PROT_EN                       0x1ac4
+#define HOST1X_HV_SYNCPT_PROT_EN_CH_EN                 BIT(1)
+#define HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(x)          (0x2020 + (x * 4))
+#define HOST1X_HV_CMDFIFO_PEEK_CTRL                    0x233c
+#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ADDR(x)            (x)
+#define HOST1X_HV_CMDFIFO_PEEK_CTRL_CHANNEL(x)         ((x) << 16)
+#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ENABLE             BIT(31)
+#define HOST1X_HV_CMDFIFO_PEEK_READ                    0x2340
+#define HOST1X_HV_CMDFIFO_PEEK_PTRS                    0x2344
+#define HOST1X_HV_CMDFIFO_PEEK_PTRS_WR_PTR_V(x)                (((x) >> 16) & 0xfff)
+#define HOST1X_HV_CMDFIFO_PEEK_PTRS_RD_PTR_V(x)                ((x) & 0xfff)
+#define HOST1X_HV_CMDFIFO_SETUP(x)                     (0x2588 + (x * 4))
+#define HOST1X_HV_CMDFIFO_SETUP_LIMIT_V(x)             (((x) >> 16) & 0xfff)
+#define HOST1X_HV_CMDFIFO_SETUP_BASE_V(x)              ((x) & 0xfff)
+#define HOST1X_HV_ICG_EN_OVERRIDE                      0x2aa8
diff --git a/drivers/gpu/host1x/hw/hw_host1x07_uclass.h b/drivers/gpu/host1x/hw/hw_host1x07_uclass.h
new file mode 100644 (file)
index 0000000..7e4e3b3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X07_UCLASS_H
+#define HOST1X_HW_HOST1X07_UCLASS_H
+
+static inline u32 host1x_uclass_incr_syncpt_r(void)
+{
+       return 0x0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT \
+       host1x_uclass_incr_syncpt_r()
+static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
+{
+       return (v & 0xff) << 10;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
+       host1x_uclass_incr_syncpt_cond_f(v)
+static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
+       host1x_uclass_incr_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_r(void)
+{
+       return 0x8;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT \
+       host1x_uclass_wait_syncpt_r()
+static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \
+       host1x_uclass_wait_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
+       host1x_uclass_wait_syncpt_thresh_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_r(void)
+{
+       return 0x9;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
+       host1x_uclass_wait_syncpt_base_r()
+static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 16;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_wait_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_r(void)
+{
+       return 0xb;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
+       host1x_uclass_load_syncpt_base_r()
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_load_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \
+       host1x_uclass_load_syncpt_base_value_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_incr_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_incr_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_indoff_r(void)
+{
+       return 0x2d;
+}
+#define HOST1X_UCLASS_INDOFF \
+       host1x_uclass_indoff_r()
+static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
+{
+       return (v & 0xf) << 28;
+}
+#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \
+       host1x_uclass_indoff_indbe_f(v)
+static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
+{
+       return (v & 0x1) << 27;
+}
+#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \
+       host1x_uclass_indoff_autoinc_f(v)
+static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
+{
+       return (v & 0xff) << 18;
+}
+#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \
+       host1x_uclass_indoff_indmodid_f(v)
+static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
+{
+       return (v & 0xffff) << 2;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+static inline u32 host1x_uclass_indoff_rwn_read_v(void)
+{
+       return 1;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x07_vm.h b/drivers/gpu/host1x/hw/hw_host1x07_vm.h
new file mode 100644 (file)
index 0000000..7e4629e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define HOST1X_CHANNEL_DMASTART                                0x0000
+#define HOST1X_CHANNEL_DMASTART_HI                     0x0004
+#define HOST1X_CHANNEL_DMAPUT                          0x0008
+#define HOST1X_CHANNEL_DMAPUT_HI                       0x000c
+#define HOST1X_CHANNEL_DMAGET                          0x0010
+#define HOST1X_CHANNEL_DMAGET_HI                       0x0014
+#define HOST1X_CHANNEL_DMAEND                          0x0018
+#define HOST1X_CHANNEL_DMAEND_HI                       0x001c
+#define HOST1X_CHANNEL_DMACTRL                         0x0020
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP                 BIT(0)
+#define HOST1X_CHANNEL_DMACTRL_DMAGETRST               BIT(1)
+#define HOST1X_CHANNEL_DMACTRL_DMAINITGET              BIT(2)
+#define HOST1X_CHANNEL_CMDFIFO_STAT                    0x0024
+#define HOST1X_CHANNEL_CMDFIFO_STAT_EMPTY              BIT(13)
+#define HOST1X_CHANNEL_CMDFIFO_RDATA                   0x0028
+#define HOST1X_CHANNEL_CMDP_OFFSET                     0x0030
+#define HOST1X_CHANNEL_CMDP_CLASS                      0x0034
+#define HOST1X_CHANNEL_CHANNELSTAT                     0x0038
+#define HOST1X_CHANNEL_CMDPROC_STOP                    0x0048
+#define HOST1X_CHANNEL_TEARDOWN                                0x004c
+
+#define HOST1X_SYNC_SYNCPT_CPU_INCR(x)                 (0x6400 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(x)   (0x6464 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(x)   (0x652c + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(x)       (0x6590 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT(x)                          (0x8080 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_INT_THRESH(x)               (0x8d00 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_CH_APP(x)                   (0xa604 + 4 * (x))
+#define HOST1X_SYNC_SYNCPT_CH_APP_CH(v)                        (((v) & 0x3f) << 8)
index a23bb3352d029303a4c3a750532a5e3a73053c0a..d946660d47f8325e7fd76bf0a88b50eeebd8b95f 100644 (file)
@@ -37,10 +37,12 @@ static void syncpt_restore(struct host1x_syncpt *sp)
  */
 static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
 {
+#if HOST1X_HW < 7
        struct host1x *host = sp->host;
 
        host1x_sync_writel(host, sp->base_val,
                           HOST1X_SYNC_SYNCPT_BASE(sp->id));
+#endif
 }
 
 /*
@@ -48,10 +50,12 @@ static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
  */
 static void syncpt_read_wait_base(struct host1x_syncpt *sp)
 {
+#if HOST1X_HW < 7
        struct host1x *host = sp->host;
 
        sp->base_val =
                host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id));
+#endif
 }
 
 /*
index a9d2501500a19750d0249b82d52ff67553507b74..163fadb8a33a5807196ff1e40a2dff91245b2791 100644 (file)
@@ -259,6 +259,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
 
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
 {
+       WARN_ON_ONCE(buf & 0x7);
+
        if (bufnum)
                ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
        else
@@ -268,6 +270,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
 
 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
 {
+       WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
+
        ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
        ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
 }
@@ -435,6 +439,8 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
                                   unsigned int uv_stride,
                                   unsigned int u_offset, unsigned int v_offset)
 {
+       WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
+
        ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
        ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
        ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
@@ -739,48 +745,56 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
        switch (pix->pixelformat) {
        case V4L2_PIX_FMT_YUV420:
                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-               u_offset = U_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - offset;
-               v_offset = V_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - offset;
+               u_offset = image->u_offset ?
+                       image->u_offset : U_OFFSET(pix, image->rect.left,
+                                                  image->rect.top) - offset;
+               v_offset = image->v_offset ?
+                       image->v_offset : V_OFFSET(pix, image->rect.left,
+                                                  image->rect.top) - offset;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
                                              u_offset, v_offset);
                break;
        case V4L2_PIX_FMT_YVU420:
                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-               u_offset = U_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - offset;
-               v_offset = V_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - offset;
+               u_offset = image->u_offset ?
+                       image->u_offset : V_OFFSET(pix, image->rect.left,
+                                                  image->rect.top) - offset;
+               v_offset = image->v_offset ?
+                       image->v_offset : U_OFFSET(pix, image->rect.left,
+                                                  image->rect.top) - offset;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
-                                             v_offset, u_offset);
+                                             u_offset, v_offset);
                break;
        case V4L2_PIX_FMT_YUV422P:
                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-               u_offset = U2_OFFSET(pix, image->rect.left,
-                                    image->rect.top) - offset;
-               v_offset = V2_OFFSET(pix, image->rect.left,
-                                    image->rect.top) - offset;
+               u_offset = image->u_offset ?
+                       image->u_offset : U2_OFFSET(pix, image->rect.left,
+                                                   image->rect.top) - offset;
+               v_offset = image->v_offset ?
+                       image->v_offset : V2_OFFSET(pix, image->rect.left,
+                                                   image->rect.top) - offset;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
                                              u_offset, v_offset);
                break;
        case V4L2_PIX_FMT_NV12:
                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-               u_offset = UV_OFFSET(pix, image->rect.left,
-                                    image->rect.top) - offset;
-               v_offset = 0;
+               u_offset = image->u_offset ?
+                       image->u_offset : UV_OFFSET(pix, image->rect.left,
+                                                   image->rect.top) - offset;
+               v_offset = image->v_offset ? image->v_offset : 0;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
                                              u_offset, v_offset);
                break;
        case V4L2_PIX_FMT_NV16:
                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-               u_offset = UV2_OFFSET(pix, image->rect.left,
-                                     image->rect.top) - offset;
-               v_offset = 0;
+               u_offset = image->u_offset ?
+                       image->u_offset : UV2_OFFSET(pix, image->rect.left,
+                                                    image->rect.top) - offset;
+               v_offset = image->v_offset ? image->v_offset : 0;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
                                              u_offset, v_offset);
index 67cc820253a99b84341825437e9e0bfce3cd16d6..594c3cbc8291b217a2ad6d5b87fe16a6782634fe 100644 (file)
@@ -442,36 +442,40 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
 
-int ipu_ic_task_init(struct ipu_ic *ic,
-                    int in_width, int in_height,
-                    int out_width, int out_height,
-                    enum ipu_color_space in_cs,
-                    enum ipu_color_space out_cs)
+int ipu_ic_task_init_rsc(struct ipu_ic *ic,
+                        int in_width, int in_height,
+                        int out_width, int out_height,
+                        enum ipu_color_space in_cs,
+                        enum ipu_color_space out_cs,
+                        u32 rsc)
 {
        struct ipu_ic_priv *priv = ic->priv;
-       u32 reg, downsize_coeff, resize_coeff;
+       u32 downsize_coeff, resize_coeff;
        unsigned long flags;
        int ret = 0;
 
-       /* Setup vertical resizing */
-       ret = calc_resize_coeffs(ic, in_height, out_height,
-                                &resize_coeff, &downsize_coeff);
-       if (ret)
-               return ret;
+       if (!rsc) {
+               /* Setup vertical resizing */
 
-       reg = (downsize_coeff << 30) | (resize_coeff << 16);
+               ret = calc_resize_coeffs(ic, in_height, out_height,
+                                        &resize_coeff, &downsize_coeff);
+               if (ret)
+                       return ret;
+
+               rsc = (downsize_coeff << 30) | (resize_coeff << 16);
 
-       /* Setup horizontal resizing */
-       ret = calc_resize_coeffs(ic, in_width, out_width,
-                                &resize_coeff, &downsize_coeff);
-       if (ret)
-               return ret;
+               /* Setup horizontal resizing */
+               ret = calc_resize_coeffs(ic, in_width, out_width,
+                                        &resize_coeff, &downsize_coeff);
+               if (ret)
+                       return ret;
 
-       reg |= (downsize_coeff << 14) | resize_coeff;
+               rsc |= (downsize_coeff << 14) | resize_coeff;
+       }
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       ipu_ic_write(ic, reg, ic->reg->rsc);
+       ipu_ic_write(ic, rsc, ic->reg->rsc);
 
        /* Setup color space conversion */
        ic->in_cs = in_cs;
@@ -487,6 +491,16 @@ unlock:
        spin_unlock_irqrestore(&priv->lock, flags);
        return ret;
 }
+
+int ipu_ic_task_init(struct ipu_ic *ic,
+                    int in_width, int in_height,
+                    int out_width, int out_height,
+                    enum ipu_color_space in_cs,
+                    enum ipu_color_space out_cs)
+{
+       return ipu_ic_task_init_rsc(ic, in_width, in_height, out_width,
+                                   out_height, in_cs, out_cs, 0);
+}
 EXPORT_SYMBOL_GPL(ipu_ic_task_init);
 
 int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
index f4081962784ccee322282a5099590c42dcbcccc9..13103ab860502f248df328d285a250deec8a4fca 100644 (file)
  * when double_buffering boolean is set).
  *
  * Note that the input frame must be split up into the same number
- * of tiles as the output frame.
+ * of tiles as the output frame:
  *
- * FIXME: at this point there is no attempt to deal with visible seams
- * at the tile boundaries when upscaling. The seams are caused by a reset
- * of the bilinear upscale interpolation when starting a new tile. The
- * seams are barely visible for small upscale factors, but become
- * increasingly visible as the upscale factor gets larger, since more
- * interpolated pixels get thrown out at the tile boundaries. A possilble
- * fix might be to overlap tiles of different sizes, but this must be done
- * while also maintaining the IDMAC dma buffer address alignment and 8x8 IRT
- * alignment restrictions of each tile.
+ *                       +---------+-----+
+ *   +-----+---+         |  A      | B   |
+ *   | A   | B |         |         |     |
+ *   +-----+---+   -->   +---------+-----+
+ *   | C   | D |         |  C      | D   |
+ *   +-----+---+         |         |     |
+ *                       +---------+-----+
+ *
+ * Clockwise 90° rotations are handled by first rescaling into a
+ * reusable temporary tile buffer and then rotating with the 8x8
+ * block rotator, writing to the correct destination:
+ *
+ *                                         +-----+-----+
+ *                                         |     |     |
+ *   +-----+---+         +---------+       | C   | A   |
+ *   | A   | B |         | A,B, |  |       |     |     |
+ *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
+ *   | C   | D |         +---------+       +-----+-----+
+ *   +-----+---+                           | D   | B   |
+ *                                         |     |     |
+ *                                         +-----+-----+
+ *
+ * If the 8x8 block rotator is used, horizontal or vertical flipping
+ * is done during the rotation step, otherwise flipping is done
+ * during the scaling step.
+ * With rotation or flipping, tile order changes between input and
+ * output image. Tiles are numbered row major from top left to bottom
+ * right for both input and output image.
  */
 
 #define MAX_STRIPES_W    4
@@ -84,6 +103,8 @@ struct ipu_image_convert_dma_chan {
 struct ipu_image_tile {
        u32 width;
        u32 height;
+       u32 left;
+       u32 top;
        /* size and strides are in bytes */
        u32 size;
        u32 stride;
@@ -135,6 +156,12 @@ struct ipu_image_convert_ctx {
        struct ipu_image_convert_image in;
        struct ipu_image_convert_image out;
        enum ipu_rotate_mode rot_mode;
+       u32 downsize_coeff_h;
+       u32 downsize_coeff_v;
+       u32 image_resize_coeff_h;
+       u32 image_resize_coeff_v;
+       u32 resize_coeffs_h[MAX_STRIPES_W];
+       u32 resize_coeffs_v[MAX_STRIPES_H];
 
        /* intermediate buffer for rotation */
        struct ipu_image_convert_dma_buf rot_intermediate[2];
@@ -300,12 +327,11 @@ static void dump_format(struct ipu_image_convert_ctx *ctx,
        struct ipu_image_convert_priv *priv = chan->priv;
 
        dev_dbg(priv->ipu->dev,
-               "task %u: ctx %p: %s format: %dx%d (%dx%d tiles of size %dx%d), %c%c%c%c\n",
+               "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
                chan->ic_task, ctx,
                ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
                ic_image->base.pix.width, ic_image->base.pix.height,
                ic_image->num_cols, ic_image->num_rows,
-               ic_image->tile[0].width, ic_image->tile[0].height,
                ic_image->fmt->fourcc & 0xff,
                (ic_image->fmt->fourcc >> 8) & 0xff,
                (ic_image->fmt->fourcc >> 16) & 0xff,
@@ -353,24 +379,459 @@ static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
 
 static inline int num_stripes(int dim)
 {
-       if (dim <= 1024)
-               return 1;
-       else if (dim <= 2048)
+       return (dim - 1) / 1024 + 1;
+}
+
+/*
+ * Calculate downsizing coefficients, which are the same for all tiles,
+ * and bilinear resizing coefficients, which are used to find the best
+ * seam positions.
+ */
+static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
+                                         struct ipu_image *in,
+                                         struct ipu_image *out)
+{
+       u32 downsized_width = in->rect.width;
+       u32 downsized_height = in->rect.height;
+       u32 downsize_coeff_v = 0;
+       u32 downsize_coeff_h = 0;
+       u32 resized_width = out->rect.width;
+       u32 resized_height = out->rect.height;
+       u32 resize_coeff_h;
+       u32 resize_coeff_v;
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               resized_width = out->rect.height;
+               resized_height = out->rect.width;
+       }
+
+       /* Do not let invalid input lead to an endless loop below */
+       if (WARN_ON(resized_width == 0 || resized_height == 0))
+               return -EINVAL;
+
+       while (downsized_width >= resized_width * 2) {
+               downsized_width >>= 1;
+               downsize_coeff_h++;
+       }
+
+       while (downsized_height >= resized_height * 2) {
+               downsized_height >>= 1;
+               downsize_coeff_v++;
+       }
+
+       /*
+        * Calculate the bilinear resizing coefficients that could be used if
+        * we were converting with a single tile. The bottom right output pixel
+        * should sample as close as possible to the bottom right input pixel
+        * out of the decimator, but not overshoot it:
+        */
+       resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
+       resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
+
+       dev_dbg(ctx->chan->priv->ipu->dev,
+               "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
+               __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
+               resize_coeff_v, ctx->in.num_cols, ctx->in.num_rows);
+
+       if (downsize_coeff_h > 2 || downsize_coeff_v  > 2 ||
+           resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
+               return -EINVAL;
+
+       ctx->downsize_coeff_h = downsize_coeff_h;
+       ctx->downsize_coeff_v = downsize_coeff_v;
+       ctx->image_resize_coeff_h = resize_coeff_h;
+       ctx->image_resize_coeff_v = resize_coeff_v;
+
+       return 0;
+}
+
+#define round_closest(x, y) round_down((x) + (y)/2, (y))
+
+/*
+ * Find the best aligned seam position in the inverval [out_start, out_end].
+ * Rotation and image offsets are out of scope.
+ *
+ * @out_start: start of inverval, must be within 1024 pixels / lines
+ *             of out_end
+ * @out_end: end of interval, smaller than or equal to out_edge
+ * @in_edge: input right / bottom edge
+ * @out_edge: output right / bottom edge
+ * @in_align: input alignment, either horizontal 8-byte line start address
+ *            alignment, or pixel alignment due to image format
+ * @out_align: output alignment, either horizontal 8-byte line start address
+ *             alignment, or pixel alignment due to image format or rotator
+ *             block size
+ * @in_burst: horizontal input burst size in case of horizontal flip
+ * @out_burst: horizontal output burst size or rotator block size
+ * @downsize_coeff: downsizing section coefficient
+ * @resize_coeff: main processing section resizing coefficient
+ * @_in_seam: aligned input seam position return value
+ * @_out_seam: aligned output seam position return value
+ */
+static void find_best_seam(struct ipu_image_convert_ctx *ctx,
+                          unsigned int out_start,
+                          unsigned int out_end,
+                          unsigned int in_edge,
+                          unsigned int out_edge,
+                          unsigned int in_align,
+                          unsigned int out_align,
+                          unsigned int in_burst,
+                          unsigned int out_burst,
+                          unsigned int downsize_coeff,
+                          unsigned int resize_coeff,
+                          u32 *_in_seam,
+                          u32 *_out_seam)
+{
+       struct device *dev = ctx->chan->priv->ipu->dev;
+       unsigned int out_pos;
+       /* Input / output seam position candidates */
+       unsigned int out_seam = 0;
+       unsigned int in_seam = 0;
+       unsigned int min_diff = UINT_MAX;
+
+       /*
+        * Output tiles must start at a multiple of 8 bytes horizontally and
+        * possibly at an even line horizontally depending on the pixel format.
+        * Only consider output aligned positions for the seam.
+        */
+       out_start = round_up(out_start, out_align);
+       for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
+               unsigned int in_pos;
+               unsigned int in_pos_aligned;
+               unsigned int abs_diff;
+
+               /*
+                * Tiles in the right row / bottom column may not be allowed to
+                * overshoot horizontally / vertically. out_burst may be the
+                * actual DMA burst size, or the rotator block size.
+                */
+               if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
+                       continue;
+
+               /*
+                * Input sample position, corresponding to out_pos, 19.13 fixed
+                * point.
+                */
+               in_pos = (out_pos * resize_coeff) << downsize_coeff;
+               /*
+                * The closest input sample position that we could actually
+                * start the input tile at, 19.13 fixed point.
+                */
+               in_pos_aligned = round_closest(in_pos, 8192U * in_align);
+
+               if ((in_burst > 1) &&
+                   (in_edge - in_pos_aligned / 8192U) % in_burst)
+                       continue;
+
+               if (in_pos < in_pos_aligned)
+                       abs_diff = in_pos_aligned - in_pos;
+               else
+                       abs_diff = in_pos - in_pos_aligned;
+
+               if (abs_diff < min_diff) {
+                       in_seam = in_pos_aligned;
+                       out_seam = out_pos;
+                       min_diff = abs_diff;
+               }
+       }
+
+       *_out_seam = out_seam;
+       /* Convert 19.13 fixed point to integer seam position */
+       *_in_seam = DIV_ROUND_CLOSEST(in_seam, 8192U);
+
+       dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) diff %u.%03u\n",
+               __func__, out_seam, out_align, out_start, out_end,
+               *_in_seam, in_align, min_diff / 8192,
+               DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
+}
+
+/*
+ * Tile left edges are required to be aligned to multiples of 8 bytes
+ * by the IDMAC.
+ */
+static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
+{
+       if (fmt->planar)
+               return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
+       else
+               return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
+}
+
+/*
+ * Tile top edge alignment is only limited by chroma subsampling.
+ */
+static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
+{
+       return fmt->uv_height_dec > 1 ? 2 : 1;
+}
+
+static inline u32 tile_width_align(enum ipu_image_convert_type type,
+                                  const struct ipu_image_pixfmt *fmt,
+                                  enum ipu_rotate_mode rot_mode)
+{
+       if (type == IMAGE_CONVERT_IN) {
+               /*
+                * The IC burst reads 8 pixels at a time. Reading beyond the
+                * end of the line is usually acceptable. Those pixels are
+                * ignored, unless the IC has to write the scaled line in
+                * reverse.
+                */
+               return (!ipu_rot_mode_is_irt(rot_mode) &&
+                       (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
+       }
+
+       /*
+        * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+        * formats to guarantee 8-byte aligned line start addresses in the
+        * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+        * for all other formats.
+        */
+       return (ipu_rot_mode_is_irt(rot_mode) &&
+               fmt->planar && !fmt->uv_packed) ?
+               8 * fmt->uv_width_dec : 8;
+}
+
+static inline u32 tile_height_align(enum ipu_image_convert_type type,
+                                   const struct ipu_image_pixfmt *fmt,
+                                   enum ipu_rotate_mode rot_mode)
+{
+       if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
                return 2;
+
+       /*
+        * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
+        * formats to guarantee 8-byte aligned line start addresses in the
+        * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
+        * for all other formats.
+        */
+       return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
+}
+
+/*
+ * Fill in left position and width and for all tiles in an input column, and
+ * for all corresponding output tiles. If the 90° rotator is used, the output
+ * tiles are in a row, and output tile top position and height are set.
+ */
+static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
+                            unsigned int col,
+                            struct ipu_image_convert_image *in,
+                            unsigned int in_left, unsigned int in_width,
+                            struct ipu_image_convert_image *out,
+                            unsigned int out_left, unsigned int out_width)
+{
+       unsigned int row, tile_idx;
+       struct ipu_image_tile *in_tile, *out_tile;
+
+       for (row = 0; row < in->num_rows; row++) {
+               tile_idx = in->num_cols * row + col;
+               in_tile = &in->tile[tile_idx];
+               out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+
+               in_tile->left = in_left;
+               in_tile->width = in_width;
+
+               if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+                       out_tile->top = out_left;
+                       out_tile->height = out_width;
+               } else {
+                       out_tile->left = out_left;
+                       out_tile->width = out_width;
+               }
+       }
+}
+
+/*
+ * Fill in top position and height and for all tiles in an input row, and
+ * for all corresponding output tiles. If the 90° rotator is used, the output
+ * tiles are in a column, and output tile left position and width are set.
+ */
+static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
+                         struct ipu_image_convert_image *in,
+                         unsigned int in_top, unsigned int in_height,
+                         struct ipu_image_convert_image *out,
+                         unsigned int out_top, unsigned int out_height)
+{
+       unsigned int col, tile_idx;
+       struct ipu_image_tile *in_tile, *out_tile;
+
+       for (col = 0; col < in->num_cols; col++) {
+               tile_idx = in->num_cols * row + col;
+               in_tile = &in->tile[tile_idx];
+               out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
+
+               in_tile->top = in_top;
+               in_tile->height = in_height;
+
+               if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+                       out_tile->left = out_top;
+                       out_tile->width = out_height;
+               } else {
+                       out_tile->top = out_top;
+                       out_tile->height = out_height;
+               }
+       }
+}
+
+/*
+ * Find the best horizontal and vertical seam positions to split into tiles.
+ * Minimize the fractional part of the input sampling position for the
+ * top / left pixels of each tile.
+ */
+static void find_seams(struct ipu_image_convert_ctx *ctx,
+                      struct ipu_image_convert_image *in,
+                      struct ipu_image_convert_image *out)
+{
+       struct device *dev = ctx->chan->priv->ipu->dev;
+       unsigned int resized_width = out->base.rect.width;
+       unsigned int resized_height = out->base.rect.height;
+       unsigned int col;
+       unsigned int row;
+       unsigned int in_left_align = tile_left_align(in->fmt);
+       unsigned int in_top_align = tile_top_align(in->fmt);
+       unsigned int out_left_align = tile_left_align(out->fmt);
+       unsigned int out_top_align = tile_top_align(out->fmt);
+       unsigned int out_width_align = tile_width_align(out->type, out->fmt,
+                                                       ctx->rot_mode);
+       unsigned int out_height_align = tile_height_align(out->type, out->fmt,
+                                                         ctx->rot_mode);
+       unsigned int in_right = in->base.rect.width;
+       unsigned int in_bottom = in->base.rect.height;
+       unsigned int out_right = out->base.rect.width;
+       unsigned int out_bottom = out->base.rect.height;
+       unsigned int flipped_out_left;
+       unsigned int flipped_out_top;
+
+       if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               /* Switch width/height and align top left to IRT block size */
+               resized_width = out->base.rect.height;
+               resized_height = out->base.rect.width;
+               out_left_align = out_height_align;
+               out_top_align = out_width_align;
+               out_width_align = out_left_align;
+               out_height_align = out_top_align;
+               out_right = out->base.rect.height;
+               out_bottom = out->base.rect.width;
+       }
+
+       for (col = in->num_cols - 1; col > 0; col--) {
+               bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
+                                         !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+               bool allow_out_overshoot = (col < in->num_cols - 1) &&
+                                          !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+               unsigned int out_start;
+               unsigned int out_end;
+               unsigned int in_left;
+               unsigned int out_left;
+
+               /*
+                * Align input width to burst length if the scaling step flips
+                * horizontally.
+                */
+
+               /* Start within 1024 pixels of the right edge */
+               out_start = max_t(int, 0, out_right - 1024);
+               /* End before having to add more columns to the left */
+               out_end = min_t(unsigned int, out_right, col * 1024);
+
+               find_best_seam(ctx, out_start, out_end,
+                              in_right, out_right,
+                              in_left_align, out_left_align,
+                              allow_in_overshoot ? 1 : 8 /* burst length */,
+                              allow_out_overshoot ? 1 : out_width_align,
+                              ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
+                              &in_left, &out_left);
+
+               if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
+                       flipped_out_left = resized_width - out_right;
+               else
+                       flipped_out_left = out_left;
+
+               fill_tile_column(ctx, col, in, in_left, in_right - in_left,
+                                out, flipped_out_left, out_right - out_left);
+
+               dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
+                       in_left, in_right - in_left,
+                       flipped_out_left, out_right - out_left);
+
+               in_right = in_left;
+               out_right = out_left;
+       }
+
+       flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
+                          resized_width - out_right : 0;
+
+       fill_tile_column(ctx, 0, in, 0, in_right,
+                        out, flipped_out_left, out_right);
+
+       dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
+               in_right, flipped_out_left, out_right);
+
+       for (row = in->num_rows - 1; row > 0; row--) {
+               bool allow_overshoot = row < in->num_rows - 1;
+               unsigned int out_start;
+               unsigned int out_end;
+               unsigned int in_top;
+               unsigned int out_top;
+
+               /* Start within 1024 lines of the bottom edge */
+               out_start = max_t(int, 0, out_bottom - 1024);
+               /* End before having to add more rows above */
+               out_end = min_t(unsigned int, out_bottom, row * 1024);
+
+               find_best_seam(ctx, out_start, out_end,
+                              in_bottom, out_bottom,
+                              in_top_align, out_top_align,
+                              1, allow_overshoot ? 1 : out_height_align,
+                              ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
+                              &in_top, &out_top);
+
+               if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+                   ipu_rot_mode_is_irt(ctx->rot_mode))
+                       flipped_out_top = resized_height - out_bottom;
+               else
+                       flipped_out_top = out_top;
+
+               fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
+                             out, flipped_out_top, out_bottom - out_top);
+
+               dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
+                       in_top, in_bottom - in_top,
+                       flipped_out_top, out_bottom - out_top);
+
+               in_bottom = in_top;
+               out_bottom = out_top;
+       }
+
+       if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
+           ipu_rot_mode_is_irt(ctx->rot_mode))
+               flipped_out_top = resized_height - out_bottom;
        else
-               return 4;
+               flipped_out_top = 0;
+
+       fill_tile_row(ctx, 0, in, 0, in_bottom,
+                     out, flipped_out_top, out_bottom);
+
+       dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
+               in_bottom, flipped_out_top, out_bottom);
 }
 
 static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
                                 struct ipu_image_convert_image *image)
 {
-       int i;
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       unsigned int i;
 
        for (i = 0; i < ctx->num_tiles; i++) {
-               struct ipu_image_tile *tile = &image->tile[i];
+               struct ipu_image_tile *tile;
+               const unsigned int row = i / image->num_cols;
+               const unsigned int col = i % image->num_cols;
+
+               if (image->type == IMAGE_CONVERT_OUT)
+                       tile = &image->tile[ctx->out_tile_map[i]];
+               else
+                       tile = &image->tile[i];
 
-               tile->height = image->base.pix.height / image->num_rows;
-               tile->width = image->base.pix.width / image->num_cols;
                tile->size = ((tile->height * image->fmt->bpp) >> 3) *
                        tile->width;
 
@@ -383,6 +844,13 @@ static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
                        tile->rot_stride =
                                (image->fmt->bpp * tile->height) >> 3;
                }
+
+               dev_dbg(priv->ipu->dev,
+                       "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
+                       chan->ic_task, ctx,
+                       image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
+                       row, col,
+                       tile->width, tile->height, tile->left, tile->top);
        }
 }
 
@@ -459,14 +927,14 @@ static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
        }
 }
 
-static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
-                                    struct ipu_image_convert_image *image)
+static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
+                                   struct ipu_image_convert_image *image)
 {
        struct ipu_image_convert_chan *chan = ctx->chan;
        struct ipu_image_convert_priv *priv = chan->priv;
        const struct ipu_image_pixfmt *fmt = image->fmt;
        unsigned int row, col, tile = 0;
-       u32 H, w, h, y_stride, uv_stride;
+       u32 H, top, y_stride, uv_stride;
        u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
        u32 y_row_off, y_col_off, y_off;
        u32 y_size, uv_size;
@@ -483,13 +951,12 @@ static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
        uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
 
        for (row = 0; row < image->num_rows; row++) {
-               w = image->tile[tile].width;
-               h = image->tile[tile].height;
-               y_row_off = row * h * y_stride;
-               uv_row_off = (row * h * uv_stride) / fmt->uv_height_dec;
+               top = image->tile[tile].top;
+               y_row_off = top * y_stride;
+               uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
 
                for (col = 0; col < image->num_cols; col++) {
-                       y_col_off = col * w;
+                       y_col_off = image->tile[tile].left;
                        uv_col_off = y_col_off / fmt->uv_width_dec;
                        if (fmt->uv_packed)
                                uv_col_off *= 2;
@@ -509,24 +976,30 @@ static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
                        image->tile[tile].u_off = u_off;
                        image->tile[tile++].v_off = v_off;
 
-                       dev_dbg(priv->ipu->dev,
-                               "task %u: ctx %p: %s@[%d,%d]: y_off %08x, u_off %08x, v_off %08x\n",
-                               chan->ic_task, ctx,
-                               image->type == IMAGE_CONVERT_IN ?
-                               "Input" : "Output", row, col,
-                               y_off, u_off, v_off);
+                       if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
+                               dev_err(priv->ipu->dev,
+                                       "task %u: ctx %p: %s@[%d,%d]: "
+                                       "y_off %08x, u_off %08x, v_off %08x\n",
+                                       chan->ic_task, ctx,
+                                       image->type == IMAGE_CONVERT_IN ?
+                                       "Input" : "Output", row, col,
+                                       y_off, u_off, v_off);
+                               return -EINVAL;
+                       }
                }
        }
+
+       return 0;
 }
 
-static void calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
-                                    struct ipu_image_convert_image *image)
+static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
+                                   struct ipu_image_convert_image *image)
 {
        struct ipu_image_convert_chan *chan = ctx->chan;
        struct ipu_image_convert_priv *priv = chan->priv;
        const struct ipu_image_pixfmt *fmt = image->fmt;
        unsigned int row, col, tile = 0;
-       u32 w, h, bpp, stride;
+       u32 bpp, stride, offset;
        u32 row_off, col_off;
 
        /* setup some convenience vars */
@@ -534,34 +1007,183 @@ static void calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
        bpp = fmt->bpp;
 
        for (row = 0; row < image->num_rows; row++) {
-               w = image->tile[tile].width;
-               h = image->tile[tile].height;
-               row_off = row * h * stride;
+               row_off = image->tile[tile].top * stride;
 
                for (col = 0; col < image->num_cols; col++) {
-                       col_off = (col * w * bpp) >> 3;
+                       col_off = (image->tile[tile].left * bpp) >> 3;
+
+                       offset = row_off + col_off;
 
-                       image->tile[tile].offset = row_off + col_off;
+                       image->tile[tile].offset = offset;
                        image->tile[tile].u_off = 0;
                        image->tile[tile++].v_off = 0;
 
-                       dev_dbg(priv->ipu->dev,
-                               "task %u: ctx %p: %s@[%d,%d]: phys %08x\n",
-                               chan->ic_task, ctx,
-                               image->type == IMAGE_CONVERT_IN ?
-                               "Input" : "Output", row, col,
-                               row_off + col_off);
+                       if (offset & 0x7) {
+                               dev_err(priv->ipu->dev,
+                                       "task %u: ctx %p: %s@[%d,%d]: "
+                                       "phys %08x\n",
+                                       chan->ic_task, ctx,
+                                       image->type == IMAGE_CONVERT_IN ?
+                                       "Input" : "Output", row, col,
+                                       row_off + col_off);
+                               return -EINVAL;
+                       }
                }
        }
+
+       return 0;
 }
 
-static void calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
+static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
                              struct ipu_image_convert_image *image)
 {
        if (image->fmt->planar)
-               calc_tile_offsets_planar(ctx, image);
+               return calc_tile_offsets_planar(ctx, image);
+
+       return calc_tile_offsets_packed(ctx, image);
+}
+
+/*
+ * Calculate the resizing ratio for the IC main processing section given input
+ * size, fixed downsizing coefficient, and output size.
+ * Either round to closest for the next tile's first pixel to minimize seams
+ * and distortion (for all but right column / bottom row), or round down to
+ * avoid sampling beyond the edges of the input image for this tile's last
+ * pixel.
+ * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
+ */
+static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
+                            u32 output_size, bool allow_overshoot)
+{
+       u32 downsized = input_size >> downsize_coeff;
+
+       if (allow_overshoot)
+               return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
        else
-               calc_tile_offsets_packed(ctx, image);
+               return 8192 * (downsized - 1) / (output_size - 1);
+}
+
+/*
+ * Slightly modify resize coefficients per tile to hide the bilinear
+ * interpolator reset at tile borders, shifting the right / bottom edge
+ * by up to a half input pixel. This removes noticeable seams between
+ * tiles at higher upscaling factors.
+ */
+static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
+{
+       struct ipu_image_convert_chan *chan = ctx->chan;
+       struct ipu_image_convert_priv *priv = chan->priv;
+       struct ipu_image_tile *in_tile, *out_tile;
+       unsigned int col, row, tile_idx;
+       unsigned int last_output;
+
+       for (col = 0; col < ctx->in.num_cols; col++) {
+               bool closest = (col < ctx->in.num_cols - 1) &&
+                              !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
+               u32 resized_width;
+               u32 resize_coeff_h;
+
+               tile_idx = col;
+               in_tile = &ctx->in.tile[tile_idx];
+               out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+
+               if (ipu_rot_mode_is_irt(ctx->rot_mode))
+                       resized_width = out_tile->height;
+               else
+                       resized_width = out_tile->width;
+
+               resize_coeff_h = calc_resize_coeff(in_tile->width,
+                                                  ctx->downsize_coeff_h,
+                                                  resized_width, closest);
+
+               dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
+                       __func__, col, resize_coeff_h);
+
+
+               for (row = 0; row < ctx->in.num_rows; row++) {
+                       tile_idx = row * ctx->in.num_cols + col;
+                       in_tile = &ctx->in.tile[tile_idx];
+                       out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+
+                       /*
+                        * With the horizontal scaling factor known, round up
+                        * resized width (output width or height) to burst size.
+                        */
+                       if (ipu_rot_mode_is_irt(ctx->rot_mode))
+                               out_tile->height = round_up(resized_width, 8);
+                       else
+                               out_tile->width = round_up(resized_width, 8);
+
+                       /*
+                        * Calculate input width from the last accessed input
+                        * pixel given resized width and scaling coefficients.
+                        * Round up to burst size.
+                        */
+                       last_output = round_up(resized_width, 8) - 1;
+                       if (closest)
+                               last_output++;
+                       in_tile->width = round_up(
+                               (DIV_ROUND_UP(last_output * resize_coeff_h,
+                                             8192) + 1)
+                               << ctx->downsize_coeff_h, 8);
+               }
+
+               ctx->resize_coeffs_h[col] = resize_coeff_h;
+       }
+
+       for (row = 0; row < ctx->in.num_rows; row++) {
+               bool closest = (row < ctx->in.num_rows - 1) &&
+                              !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
+               u32 resized_height;
+               u32 resize_coeff_v;
+
+               tile_idx = row * ctx->in.num_cols;
+               in_tile = &ctx->in.tile[tile_idx];
+               out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+
+               if (ipu_rot_mode_is_irt(ctx->rot_mode))
+                       resized_height = out_tile->width;
+               else
+                       resized_height = out_tile->height;
+
+               resize_coeff_v = calc_resize_coeff(in_tile->height,
+                                                  ctx->downsize_coeff_v,
+                                                  resized_height, closest);
+
+               dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
+                       __func__, row, resize_coeff_v);
+
+               for (col = 0; col < ctx->in.num_cols; col++) {
+                       tile_idx = row * ctx->in.num_cols + col;
+                       in_tile = &ctx->in.tile[tile_idx];
+                       out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
+
+                       /*
+                        * With the vertical scaling factor known, round up
+                        * resized height (output width or height) to IDMAC
+                        * limitations.
+                        */
+                       if (ipu_rot_mode_is_irt(ctx->rot_mode))
+                               out_tile->width = round_up(resized_height, 2);
+                       else
+                               out_tile->height = round_up(resized_height, 2);
+
+                       /*
+                        * Calculate input width from the last accessed input
+                        * pixel given resized height and scaling coefficients.
+                        * Align to IDMAC restrictions.
+                        */
+                       last_output = round_up(resized_height, 2) - 1;
+                       if (closest)
+                               last_output++;
+                       in_tile->height = round_up(
+                               (DIV_ROUND_UP(last_output * resize_coeff_v,
+                                             8192) + 1)
+                               << ctx->downsize_coeff_v, 2);
+               }
+
+               ctx->resize_coeffs_v[row] = resize_coeff_v;
+       }
 }
 
 /*
@@ -611,7 +1233,8 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
                               struct ipuv3_channel *channel,
                               struct ipu_image_convert_image *image,
                               enum ipu_rotate_mode rot_mode,
-                              bool rot_swap_width_height)
+                              bool rot_swap_width_height,
+                              unsigned int tile)
 {
        struct ipu_image_convert_chan *chan = ctx->chan;
        unsigned int burst_size;
@@ -621,23 +1244,23 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
        unsigned int tile_idx[2];
 
        if (image->type == IMAGE_CONVERT_OUT) {
-               tile_idx[0] = ctx->out_tile_map[0];
+               tile_idx[0] = ctx->out_tile_map[tile];
                tile_idx[1] = ctx->out_tile_map[1];
        } else {
-               tile_idx[0] = 0;
+               tile_idx[0] = tile;
                tile_idx[1] = 1;
        }
 
        if (rot_swap_width_height) {
-               width = image->tile[0].height;
-               height = image->tile[0].width;
-               stride = image->tile[0].rot_stride;
+               width = image->tile[tile_idx[0]].height;
+               height = image->tile[tile_idx[0]].width;
+               stride = image->tile[tile_idx[0]].rot_stride;
                addr0 = ctx->rot_intermediate[0].phys;
                if (ctx->double_buffering)
                        addr1 = ctx->rot_intermediate[1].phys;
        } else {
-               width = image->tile[0].width;
-               height = image->tile[0].height;
+               width = image->tile[tile_idx[0]].width;
+               height = image->tile[tile_idx[0]].height;
                stride = image->stride;
                addr0 = image->base.phys0 +
                        image->tile[tile_idx[0]].offset;
@@ -655,12 +1278,12 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
        tile_image.pix.pixelformat =  image->fmt->fourcc;
        tile_image.phys0 = addr0;
        tile_image.phys1 = addr1;
-       ipu_cpmem_set_image(channel, &tile_image);
+       if (image->fmt->planar && !rot_swap_width_height) {
+               tile_image.u_offset = image->tile[tile_idx[0]].u_off;
+               tile_image.v_offset = image->tile[tile_idx[0]].v_off;
+       }
 
-       if (image->fmt->planar && !rot_swap_width_height)
-               ipu_cpmem_set_uv_offset(channel,
-                                       image->tile[tile_idx[0]].u_off,
-                                       image->tile[tile_idx[0]].v_off);
+       ipu_cpmem_set_image(channel, &tile_image);
 
        if (rot_mode)
                ipu_cpmem_set_rotation(channel, rot_mode);
@@ -687,7 +1310,7 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
        ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
 }
 
-static int convert_start(struct ipu_image_convert_run *run)
+static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
 {
        struct ipu_image_convert_ctx *ctx = run->ctx;
        struct ipu_image_convert_chan *chan = ctx->chan;
@@ -695,31 +1318,47 @@ static int convert_start(struct ipu_image_convert_run *run)
        struct ipu_image_convert_image *s_image = &ctx->in;
        struct ipu_image_convert_image *d_image = &ctx->out;
        enum ipu_color_space src_cs, dest_cs;
+       unsigned int dst_tile = ctx->out_tile_map[tile];
        unsigned int dest_width, dest_height;
+       unsigned int col, row;
+       u32 rsc;
        int ret;
 
-       dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p\n",
-               __func__, chan->ic_task, ctx, run);
+       dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
+               __func__, chan->ic_task, ctx, run, tile, dst_tile);
 
        src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc);
        dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc);
 
        if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
                /* swap width/height for resizer */
-               dest_width = d_image->tile[0].height;
-               dest_height = d_image->tile[0].width;
+               dest_width = d_image->tile[dst_tile].height;
+               dest_height = d_image->tile[dst_tile].width;
        } else {
-               dest_width = d_image->tile[0].width;
-               dest_height = d_image->tile[0].height;
+               dest_width = d_image->tile[dst_tile].width;
+               dest_height = d_image->tile[dst_tile].height;
        }
 
+       row = tile / s_image->num_cols;
+       col = tile % s_image->num_cols;
+
+       rsc =  (ctx->downsize_coeff_v << 30) |
+              (ctx->resize_coeffs_v[row] << 16) |
+              (ctx->downsize_coeff_h << 14) |
+              (ctx->resize_coeffs_h[col]);
+
+       dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
+               __func__, s_image->tile[tile].width,
+               s_image->tile[tile].height, dest_width, dest_height, rsc);
+
        /* setup the IC resizer and CSC */
-       ret = ipu_ic_task_init(chan->ic,
-                              s_image->tile[0].width,
-                              s_image->tile[0].height,
+       ret = ipu_ic_task_init_rsc(chan->ic,
+                              s_image->tile[tile].width,
+                              s_image->tile[tile].height,
                               dest_width,
                               dest_height,
-                              src_cs, dest_cs);
+                              src_cs, dest_cs,
+                              rsc);
        if (ret) {
                dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
                return ret;
@@ -727,27 +1366,27 @@ static int convert_start(struct ipu_image_convert_run *run)
 
        /* init the source MEM-->IC PP IDMAC channel */
        init_idmac_channel(ctx, chan->in_chan, s_image,
-                          IPU_ROTATE_NONE, false);
+                          IPU_ROTATE_NONE, false, tile);
 
        if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
                /* init the IC PP-->MEM IDMAC channel */
                init_idmac_channel(ctx, chan->out_chan, d_image,
-                                  IPU_ROTATE_NONE, true);
+                                  IPU_ROTATE_NONE, true, tile);
 
                /* init the MEM-->IC PP ROT IDMAC channel */
                init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
-                                  ctx->rot_mode, true);
+                                  ctx->rot_mode, true, tile);
 
                /* init the destination IC PP ROT-->MEM IDMAC channel */
                init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
-                                  IPU_ROTATE_NONE, false);
+                                  IPU_ROTATE_NONE, false, tile);
 
                /* now link IC PP-->MEM to MEM-->IC PP ROT */
                ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
        } else {
                /* init the destination IC PP-->MEM IDMAC channel */
                init_idmac_channel(ctx, chan->out_chan, d_image,
-                                  ctx->rot_mode, false);
+                                  ctx->rot_mode, false, tile);
        }
 
        /* enable the IC */
@@ -805,7 +1444,7 @@ static int do_run(struct ipu_image_convert_run *run)
        list_del(&run->list);
        chan->current_run = run;
 
-       return convert_start(run);
+       return convert_start(run, 0);
 }
 
 /* hold irqlock when calling */
@@ -896,7 +1535,7 @@ static irqreturn_t do_bh(int irq, void *dev_id)
                        dev_dbg(priv->ipu->dev,
                                "%s: task %u: signaling abort for ctx %p\n",
                                __func__, chan->ic_task, ctx);
-                       complete(&ctx->aborted);
+                       complete_all(&ctx->aborted);
                }
        }
 
@@ -908,6 +1547,24 @@ static irqreturn_t do_bh(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
+{
+       unsigned int cur_tile = ctx->next_tile - 1;
+       unsigned int next_tile = ctx->next_tile;
+
+       if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
+           ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
+           ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
+           ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
+           ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
+           ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
+           ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
+           ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
+               return true;
+
+       return false;
+}
+
 /* hold irqlock when calling */
 static irqreturn_t do_irq(struct ipu_image_convert_run *run)
 {
@@ -951,27 +1608,32 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run)
         * not done, place the next tile buffers.
         */
        if (!ctx->double_buffering) {
-
-               src_tile = &s_image->tile[ctx->next_tile];
-               dst_idx = ctx->out_tile_map[ctx->next_tile];
-               dst_tile = &d_image->tile[dst_idx];
-
-               ipu_cpmem_set_buffer(chan->in_chan, 0,
-                                    s_image->base.phys0 + src_tile->offset);
-               ipu_cpmem_set_buffer(outch, 0,
-                                    d_image->base.phys0 + dst_tile->offset);
-               if (s_image->fmt->planar)
-                       ipu_cpmem_set_uv_offset(chan->in_chan,
-                                               src_tile->u_off,
-                                               src_tile->v_off);
-               if (d_image->fmt->planar)
-                       ipu_cpmem_set_uv_offset(outch,
-                                               dst_tile->u_off,
-                                               dst_tile->v_off);
-
-               ipu_idmac_select_buffer(chan->in_chan, 0);
-               ipu_idmac_select_buffer(outch, 0);
-
+               if (ic_settings_changed(ctx)) {
+                       convert_stop(run);
+                       convert_start(run, ctx->next_tile);
+               } else {
+                       src_tile = &s_image->tile[ctx->next_tile];
+                       dst_idx = ctx->out_tile_map[ctx->next_tile];
+                       dst_tile = &d_image->tile[dst_idx];
+
+                       ipu_cpmem_set_buffer(chan->in_chan, 0,
+                                            s_image->base.phys0 +
+                                            src_tile->offset);
+                       ipu_cpmem_set_buffer(outch, 0,
+                                            d_image->base.phys0 +
+                                            dst_tile->offset);
+                       if (s_image->fmt->planar)
+                               ipu_cpmem_set_uv_offset(chan->in_chan,
+                                                       src_tile->u_off,
+                                                       src_tile->v_off);
+                       if (d_image->fmt->planar)
+                               ipu_cpmem_set_uv_offset(outch,
+                                                       dst_tile->u_off,
+                                                       dst_tile->v_off);
+
+                       ipu_idmac_select_buffer(chan->in_chan, 0);
+                       ipu_idmac_select_buffer(outch, 0);
+               }
        } else if (ctx->next_tile < ctx->num_tiles - 1) {
 
                src_tile = &s_image->tile[ctx->next_tile + 1];
@@ -1198,9 +1860,6 @@ static int fill_image(struct ipu_image_convert_ctx *ctx,
        else
                ic_image->stride  = ic_image->base.pix.bytesperline;
 
-       calc_tile_dimensions(ctx, ic_image);
-       calc_tile_offsets(ctx, ic_image);
-
        return 0;
 }
 
@@ -1221,40 +1880,11 @@ static unsigned int clamp_align(unsigned int x, unsigned int min,
        return x;
 }
 
-/*
- * We have to adjust the tile width such that the tile physaddrs and
- * U and V plane offsets are multiples of 8 bytes as required by
- * the IPU DMA Controller. For the planar formats, this corresponds
- * to a pixel alignment of 16 (but use a more formal equation since
- * the variables are available). For all the packed formats, 8 is
- * good enough.
- */
-static inline u32 tile_width_align(const struct ipu_image_pixfmt *fmt)
-{
-       return fmt->planar ? 8 * fmt->uv_width_dec : 8;
-}
-
-/*
- * For tile height alignment, we have to ensure that the output tile
- * heights are multiples of 8 lines if the IRT is required by the
- * given rotation mode (the IRT performs rotations on 8x8 blocks
- * at a time). If the IRT is not used, or for input image tiles,
- * 2 lines are good enough.
- */
-static inline u32 tile_height_align(enum ipu_image_convert_type type,
-                                   enum ipu_rotate_mode rot_mode)
-{
-       return (type == IMAGE_CONVERT_OUT &&
-               ipu_rot_mode_is_irt(rot_mode)) ? 8 : 2;
-}
-
 /* Adjusts input/output images to IPU restrictions */
 void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
                              enum ipu_rotate_mode rot_mode)
 {
        const struct ipu_image_pixfmt *infmt, *outfmt;
-       unsigned int num_in_rows, num_in_cols;
-       unsigned int num_out_rows, num_out_cols;
        u32 w_align, h_align;
 
        infmt = get_format(in->pix.pixelformat);
@@ -1286,36 +1916,31 @@ void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
                                        in->pix.height / 4);
        }
 
-       /* get tiling rows/cols from output format */
-       num_out_rows = num_stripes(out->pix.height);
-       num_out_cols = num_stripes(out->pix.width);
-       if (ipu_rot_mode_is_irt(rot_mode)) {
-               num_in_rows = num_out_cols;
-               num_in_cols = num_out_rows;
-       } else {
-               num_in_rows = num_out_rows;
-               num_in_cols = num_out_cols;
-       }
-
        /* align input width/height */
-       w_align = ilog2(tile_width_align(infmt) * num_in_cols);
-       h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, rot_mode) *
-                       num_in_rows);
+       w_align = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, rot_mode));
+       h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, rot_mode));
        in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align);
        in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align);
 
        /* align output width/height */
-       w_align = ilog2(tile_width_align(outfmt) * num_out_cols);
-       h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, rot_mode) *
-                       num_out_rows);
+       w_align = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
+       h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
        out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align);
        out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align);
 
        /* set input/output strides and image sizes */
-       in->pix.bytesperline = (in->pix.width * infmt->bpp) >> 3;
-       in->pix.sizeimage = in->pix.height * in->pix.bytesperline;
-       out->pix.bytesperline = (out->pix.width * outfmt->bpp) >> 3;
-       out->pix.sizeimage = out->pix.height * out->pix.bytesperline;
+       in->pix.bytesperline = infmt->planar ?
+               clamp_align(in->pix.width, 2 << w_align, MAX_W, w_align) :
+               clamp_align((in->pix.width * infmt->bpp) >> 3,
+                           2 << w_align, MAX_W, w_align);
+       in->pix.sizeimage = infmt->planar ?
+               (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
+               in->pix.height * in->pix.bytesperline;
+       out->pix.bytesperline = outfmt->planar ? out->pix.width :
+               (out->pix.width * outfmt->bpp) >> 3;
+       out->pix.sizeimage = outfmt->planar ?
+               (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
+               out->pix.height * out->pix.bytesperline;
 }
 EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
 
@@ -1360,6 +1985,7 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
        struct ipu_image_convert_chan *chan;
        struct ipu_image_convert_ctx *ctx;
        unsigned long flags;
+       unsigned int i;
        bool get_res;
        int ret;
 
@@ -1412,8 +2038,26 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
        if (ret)
                goto out_free;
 
+       ret = calc_image_resize_coefficients(ctx, in, out);
+       if (ret)
+               goto out_free;
+
        calc_out_tile_map(ctx);
 
+       find_seams(ctx, s_image, d_image);
+
+       calc_tile_dimensions(ctx, s_image);
+       ret = calc_tile_offsets(ctx, s_image);
+       if (ret)
+               goto out_free;
+
+       calc_tile_dimensions(ctx, d_image);
+       ret = calc_tile_offsets(ctx, d_image);
+       if (ret)
+               goto out_free;
+
+       calc_tile_resize_coefficients(ctx);
+
        dump_format(ctx, s_image);
        dump_format(ctx, d_image);
 
@@ -1429,21 +2073,51 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
         * for every tile, and therefore would have to be updated for
         * each buffer which is not possible. So double-buffering is
         * impossible when either the source or destination images are
-        * a planar format (YUV420, YUV422P, etc.).
+        * a planar format (YUV420, YUV422P, etc.). Further, differently
+        * sized tiles or different resizing coefficients per tile
+        * prevent double-buffering as well.
         */
        ctx->double_buffering = (ctx->num_tiles > 1 &&
                                 !s_image->fmt->planar &&
                                 !d_image->fmt->planar);
+       for (i = 1; i < ctx->num_tiles; i++) {
+               if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
+                   ctx->in.tile[i].height != ctx->in.tile[0].height ||
+                   ctx->out.tile[i].width != ctx->out.tile[0].width ||
+                   ctx->out.tile[i].height != ctx->out.tile[0].height) {
+                       ctx->double_buffering = false;
+                       break;
+               }
+       }
+       for (i = 1; i < ctx->in.num_cols; i++) {
+               if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
+                       ctx->double_buffering = false;
+                       break;
+               }
+       }
+       for (i = 1; i < ctx->in.num_rows; i++) {
+               if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
+                       ctx->double_buffering = false;
+                       break;
+               }
+       }
 
        if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+               unsigned long intermediate_size = d_image->tile[0].size;
+
+               for (i = 1; i < ctx->num_tiles; i++) {
+                       if (d_image->tile[i].size > intermediate_size)
+                               intermediate_size = d_image->tile[i].size;
+               }
+
                ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
-                                   d_image->tile[0].size);
+                                   intermediate_size);
                if (ret)
                        goto out_free;
                if (ctx->double_buffering) {
                        ret = alloc_dma_buf(priv,
                                            &ctx->rot_intermediate[1],
-                                           d_image->tile[0].size);
+                                           intermediate_size);
                        if (ret)
                                goto out_free_dmabuf0;
                }
@@ -1524,16 +2198,13 @@ unlock:
 EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
 
 /* Abort any active or pending conversions for this context */
-void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
 {
        struct ipu_image_convert_chan *chan = ctx->chan;
        struct ipu_image_convert_priv *priv = chan->priv;
        struct ipu_image_convert_run *run, *active_run, *tmp;
        unsigned long flags;
        int run_count, ret;
-       bool need_abort;
-
-       reinit_completion(&ctx->aborted);
 
        spin_lock_irqsave(&chan->irqlock, flags);
 
@@ -1549,22 +2220,28 @@ void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
        active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
                chan->current_run : NULL;
 
-       need_abort = (run_count || active_run);
+       if (active_run)
+               reinit_completion(&ctx->aborted);
 
-       ctx->aborting = need_abort;
+       ctx->aborting = true;
 
        spin_unlock_irqrestore(&chan->irqlock, flags);
 
-       if (!need_abort) {
+       if (!run_count && !active_run) {
                dev_dbg(priv->ipu->dev,
                        "%s: task %u: no abort needed for ctx %p\n",
                        __func__, chan->ic_task, ctx);
                return;
        }
 
+       if (!active_run) {
+               empty_done_q(chan);
+               return;
+       }
+
        dev_dbg(priv->ipu->dev,
-               "%s: task %u: wait for completion: %d runs, active run %p\n",
-               __func__, chan->ic_task, run_count, active_run);
+               "%s: task %u: wait for completion: %d runs\n",
+               __func__, chan->ic_task, run_count);
 
        ret = wait_for_completion_timeout(&ctx->aborted,
                                          msecs_to_jiffies(10000));
@@ -1572,7 +2249,11 @@ void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
                dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
                force_abort(ctx);
        }
+}
 
+void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+{
+       __ipu_image_convert_abort(ctx);
        ctx->aborting = false;
 }
 EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
@@ -1586,7 +2267,7 @@ void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
        bool put_res;
 
        /* make sure no runs are hanging around */
-       ipu_image_convert_abort(ctx);
+       __ipu_image_convert_abort(ctx);
 
        dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
                chan->ic_task, ctx);
index c61b045557798e073778ba1efcb786f6bc3c946e..dc8e039bfab57f207801afba2c0bfb0e6a2acd38 100644 (file)
@@ -676,7 +676,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
        vga_arbiter_check_bridge_sharing(vgadev);
 
        /* Add to the list */
-       list_add(&vgadev->list, &vga_list);
+       list_add_tail(&vgadev->list, &vga_list);
        vga_count++;
        vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n",
                vga_iostate_to_str(vgadev->decodes),
@@ -1408,6 +1408,18 @@ static void __init vga_arb_select_default_device(void)
        struct vga_device *vgadev;
 
 #if defined(CONFIG_X86) || defined(CONFIG_IA64)
+       u64 base = screen_info.lfb_base;
+       u64 size = screen_info.lfb_size;
+       u64 limit;
+       resource_size_t start, end;
+       unsigned long flags;
+       int i;
+
+       if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+               base |= (u64)screen_info.ext_lfb_base << 32;
+
+       limit = base + size;
+
        list_for_each_entry(vgadev, &vga_list, list) {
                struct device *dev = &vgadev->pdev->dev;
                /*
@@ -1418,11 +1430,6 @@ static void __init vga_arb_select_default_device(void)
                 * Select the device owning the boot framebuffer if there is
                 * one.
                 */
-               resource_size_t start, end, limit;
-               unsigned long flags;
-               int i;
-
-               limit = screen_info.lfb_base + screen_info.lfb_size;
 
                /* Does firmware framebuffer belong to us? */
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1437,7 +1444,7 @@ static void __init vga_arb_select_default_device(void)
                        if (!start || !end)
                                continue;
 
-                       if (screen_info.lfb_base < start || limit >= end)
+                       if (base < start || limit >= end)
                                continue;
 
                        if (!vga_default_device())
index 97954f575c3f691df222aa7102f01b5d296ff893..1c1a2514d6f31b8a2e8ce04293c949922b4e92ee 100644 (file)
@@ -4,7 +4,7 @@ menu "Microsoft Hyper-V guest support"
 
 config HYPERV
        tristate "Microsoft Hyper-V client drivers"
-       depends on X86 && ACPI && PCI && X86_LOCAL_APIC && HYPERVISOR_GUEST
+       depends on X86 && ACPI && X86_LOCAL_APIC && HYPERVISOR_GUEST
        select PARAVIRT
        help
          Select this option to run Linux as a Hyper-V client operating
index 283d184280aff10470d30c1314f4b349f3bcba68..d0ff65675292bd8b9ac7c6fa99d708e94484a62b 100644 (file)
@@ -316,6 +316,8 @@ static ssize_t out_intr_mask_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
        return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
 }
@@ -329,6 +331,8 @@ static ssize_t out_read_index_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
        return sprintf(buf, "%d\n", outbound.current_read_index);
 }
@@ -343,6 +347,8 @@ static ssize_t out_write_index_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
        return sprintf(buf, "%d\n", outbound.current_write_index);
 }
@@ -357,6 +363,8 @@ static ssize_t out_read_bytes_avail_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
        return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
 }
@@ -371,6 +379,8 @@ static ssize_t out_write_bytes_avail_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
        return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
 }
@@ -384,6 +394,8 @@ static ssize_t in_intr_mask_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
        return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
 }
@@ -397,6 +409,8 @@ static ssize_t in_read_index_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
        return sprintf(buf, "%d\n", inbound.current_read_index);
 }
@@ -410,6 +424,8 @@ static ssize_t in_write_index_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
        return sprintf(buf, "%d\n", inbound.current_write_index);
 }
@@ -424,6 +440,8 @@ static ssize_t in_read_bytes_avail_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
        return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
 }
@@ -438,6 +456,8 @@ static ssize_t in_write_bytes_avail_show(struct device *dev,
 
        if (!hv_dev->channel)
                return -ENODEV;
+       if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+               return -EINVAL;
        hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
        return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
 }
index e99c3bb5835137c8ad02cda35b6475eacc363355..4e67d5ed480e627d2d19042974bd6eac78dcc9a4 100644 (file)
@@ -342,7 +342,7 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
        pci_free_irq_vectors(pdev);
 }
 
-static int gpu_i2c_resume(struct device *dev)
+static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
        struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
index 32affd3fa8bd1ffe462c5f66abd6b9e40ba6a36f..272800692088820cfdafdcb626d8f6f4cb4716ce 100644 (file)
@@ -45,6 +45,33 @@ struct i2c_acpi_lookup {
        u32 min_speed;
 };
 
+/**
+ * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches
+ * @ares:      ACPI resource
+ * @i2c:       Pointer to I2cSerialBus resource will be returned here
+ *
+ * Checks if the given ACPI resource is of type I2cSerialBus.
+ * In this case, returns a pointer to it to the caller.
+ *
+ * Returns true if resource type is of I2cSerialBus, otherwise false.
+ */
+bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
+                              struct acpi_resource_i2c_serialbus **i2c)
+{
+       struct acpi_resource_i2c_serialbus *sb;
+
+       if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+               return false;
+
+       sb = &ares->data.i2c_serial_bus;
+       if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+               return false;
+
+       *i2c = sb;
+       return true;
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource);
+
 static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
 {
        struct i2c_acpi_lookup *lookup = data;
@@ -52,11 +79,7 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
        struct acpi_resource_i2c_serialbus *sb;
        acpi_status status;
 
-       if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
-               return 1;
-
-       sb = &ares->data.i2c_serial_bus;
-       if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+       if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb))
                return 1;
 
        if (lookup->index != -1 && lookup->n++ != lookup->index)
@@ -65,7 +88,7 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
        status = acpi_get_handle(lookup->device_handle,
                                 sb->resource_source.string_ptr,
                                 &lookup->adapter_handle);
-       if (!ACPI_SUCCESS(status))
+       if (ACPI_FAILURE(status))
                return 1;
 
        info->addr = sb->slave_address;
@@ -386,20 +409,22 @@ struct notifier_block i2c_acpi_notifier = {
  *
  * Also see i2c_new_device, which this function calls to create the i2c-client.
  *
- * Returns a pointer to the new i2c-client, or NULL if the adapter is not found.
+ * Returns a pointer to the new i2c-client, or error pointer in case of failure.
+ * Specifically, -EPROBE_DEFER is returned if the adapter is not found.
  */
 struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
                                       struct i2c_board_info *info)
 {
        struct i2c_acpi_lookup lookup;
        struct i2c_adapter *adapter;
+       struct i2c_client *client;
        struct acpi_device *adev;
        LIST_HEAD(resource_list);
        int ret;
 
        adev = ACPI_COMPANION(dev);
        if (!adev)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        memset(&lookup, 0, sizeof(lookup));
        lookup.info = info;
@@ -408,16 +433,23 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
 
        ret = acpi_dev_get_resources(adev, &resource_list,
                                     i2c_acpi_fill_info, &lookup);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
        acpi_dev_free_resource_list(&resource_list);
 
-       if (ret < 0 || !info->addr)
-               return NULL;
+       if (!info->addr)
+               return ERR_PTR(-EADDRNOTAVAIL);
 
        adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
        if (!adapter)
-               return NULL;
+               return ERR_PTR(-EPROBE_DEFER);
+
+       client = i2c_new_device(adapter, info);
+       if (!client)
+               return ERR_PTR(-ENODEV);
 
-       return i2c_new_device(adapter, info);
+       return client;
 }
 EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
 
@@ -525,13 +557,7 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
                goto err;
        }
 
-       if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
-               ret = AE_BAD_PARAMETER;
-               goto err;
-       }
-
-       sb = &ares->data.i2c_serial_bus;
-       if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+       if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {
                ret = AE_BAD_PARAMETER;
                goto err;
        }
diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
new file mode 100644 (file)
index 0000000..30a4415
--- /dev/null
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig I3C
+       tristate "I3C support"
+       select I2C
+       help
+         I3C is a serial protocol standardized by the MIPI alliance.
+
+         It's supposed to be backward compatible with I2C while providing
+         support for high speed transfers and native interrupt support
+         without the need for extra pins.
+
+         The I3C protocol also standardizes the slave device types and is
+         mainly designed to communicate with sensors.
+
+         If you want I3C support, you should say Y here and also to the
+         specific driver for your bus adapter(s) below.
+
+         This I3C support can also be built as a module.  If so, the module
+         will be called i3c.
+
+if I3C
+source "drivers/i3c/master/Kconfig"
+endif # I3C
diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
new file mode 100644 (file)
index 0000000..11982ef
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+i3c-y                          := device.o master.o
+obj-$(CONFIG_I3C)              += i3c.o
+obj-$(CONFIG_I3C)              += master/
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
new file mode 100644 (file)
index 0000000..69cc040
--- /dev/null
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "internals.h"
+
+/**
+ * i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a
+ *                             specific device
+ *
+ * @dev: device with which the transfers should be done
+ * @xfers: array of transfers
+ * @nxfers: number of transfers
+ *
+ * Initiate one or several private SDR transfers with @dev.
+ *
+ * This function can sleep and thus cannot be called in atomic context.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_do_priv_xfers(struct i3c_device *dev,
+                            struct i3c_priv_xfer *xfers,
+                            int nxfers)
+{
+       int ret, i;
+
+       if (nxfers < 1)
+               return 0;
+
+       for (i = 0; i < nxfers; i++) {
+               if (!xfers[i].len || !xfers[i].data.in)
+                       return -EINVAL;
+       }
+
+       i3c_bus_normaluse_lock(dev->bus);
+       ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
+       i3c_bus_normaluse_unlock(dev->bus);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
+
+/**
+ * i3c_device_get_info() - get I3C device information
+ *
+ * @dev: device we want information on
+ * @info: the information object to fill in
+ *
+ * Retrieve I3C dev info.
+ */
+void i3c_device_get_info(struct i3c_device *dev,
+                        struct i3c_device_info *info)
+{
+       if (!info)
+               return;
+
+       i3c_bus_normaluse_lock(dev->bus);
+       if (dev->desc)
+               *info = dev->desc->info;
+       i3c_bus_normaluse_unlock(dev->bus);
+}
+EXPORT_SYMBOL_GPL(i3c_device_get_info);
+
+/**
+ * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
+ * @dev: device on which IBIs should be disabled
+ *
+ * This function disable IBIs coming from a specific device and wait for
+ * all pending IBIs to be processed.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_disable_ibi(struct i3c_device *dev)
+{
+       int ret = -ENOENT;
+
+       i3c_bus_normaluse_lock(dev->bus);
+       if (dev->desc) {
+               mutex_lock(&dev->desc->ibi_lock);
+               ret = i3c_dev_disable_ibi_locked(dev->desc);
+               mutex_unlock(&dev->desc->ibi_lock);
+       }
+       i3c_bus_normaluse_unlock(dev->bus);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
+
+/**
+ * i3c_device_enable_ibi() - Enable IBIs coming from a specific device
+ * @dev: device on which IBIs should be enabled
+ *
+ * This function enable IBIs coming from a specific device and wait for
+ * all pending IBIs to be processed. This should be called on a device
+ * where i3c_device_request_ibi() has succeeded.
+ *
+ * Note that IBIs from this device might be received before this function
+ * returns to its caller.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_enable_ibi(struct i3c_device *dev)
+{
+       int ret = -ENOENT;
+
+       i3c_bus_normaluse_lock(dev->bus);
+       if (dev->desc) {
+               mutex_lock(&dev->desc->ibi_lock);
+               ret = i3c_dev_enable_ibi_locked(dev->desc);
+               mutex_unlock(&dev->desc->ibi_lock);
+       }
+       i3c_bus_normaluse_unlock(dev->bus);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
+
+/**
+ * i3c_device_request_ibi() - Request an IBI
+ * @dev: device for which we should enable IBIs
+ * @req: setup requested for this IBI
+ *
+ * This function is responsible for pre-allocating all resources needed to
+ * process IBIs coming from @dev. When this function returns, the IBI is not
+ * enabled until i3c_device_enable_ibi() is called.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_request_ibi(struct i3c_device *dev,
+                          const struct i3c_ibi_setup *req)
+{
+       int ret = -ENOENT;
+
+       if (!req->handler || !req->num_slots)
+               return -EINVAL;
+
+       i3c_bus_normaluse_lock(dev->bus);
+       if (dev->desc) {
+               mutex_lock(&dev->desc->ibi_lock);
+               ret = i3c_dev_request_ibi_locked(dev->desc, req);
+               mutex_unlock(&dev->desc->ibi_lock);
+       }
+       i3c_bus_normaluse_unlock(dev->bus);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
+
+/**
+ * i3c_device_free_ibi() - Free all resources needed for IBI handling
+ * @dev: device on which you want to release IBI resources
+ *
+ * This function is responsible for de-allocating resources previously
+ * allocated by i3c_device_request_ibi(). It should be called after disabling
+ * IBIs with i3c_device_disable_ibi().
+ */
+void i3c_device_free_ibi(struct i3c_device *dev)
+{
+       i3c_bus_normaluse_lock(dev->bus);
+       if (dev->desc) {
+               mutex_lock(&dev->desc->ibi_lock);
+               i3c_dev_free_ibi_locked(dev->desc);
+               mutex_unlock(&dev->desc->ibi_lock);
+       }
+       i3c_bus_normaluse_unlock(dev->bus);
+}
+EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
+
+/**
+ * i3cdev_to_dev() - Returns the device embedded in @i3cdev
+ * @i3cdev: I3C device
+ *
+ * Return: a pointer to a device object.
+ */
+struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
+{
+       return &i3cdev->dev;
+}
+EXPORT_SYMBOL_GPL(i3cdev_to_dev);
+
+/**
+ * dev_to_i3cdev() - Returns the I3C device containing @dev
+ * @dev: device object
+ *
+ * Return: a pointer to an I3C device object.
+ */
+struct i3c_device *dev_to_i3cdev(struct device *dev)
+{
+       return container_of(dev, struct i3c_device, dev);
+}
+EXPORT_SYMBOL_GPL(dev_to_i3cdev);
+
+/**
+ * i3c_driver_register_with_owner() - register an I3C device driver
+ *
+ * @drv: driver to register
+ * @owner: module that owns this driver
+ *
+ * Register @drv to the core.
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
+{
+       drv->driver.owner = owner;
+       drv->driver.bus = &i3c_bus_type;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
+
+/**
+ * i3c_driver_unregister() - unregister an I3C device driver
+ *
+ * @drv: driver to unregister
+ *
+ * Unregister @drv.
+ */
+void i3c_driver_unregister(struct i3c_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(i3c_driver_unregister);
diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
new file mode 100644 (file)
index 0000000..86b7b44
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef I3C_INTERNALS_H
+#define I3C_INTERNALS_H
+
+#include <linux/i3c/master.h>
+
+extern struct bus_type i3c_bus_type;
+
+void i3c_bus_normaluse_lock(struct i3c_bus *bus);
+void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
+
+int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
+                                struct i3c_priv_xfer *xfers,
+                                int nxfers);
+int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev);
+int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
+int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
+                              const struct i3c_ibi_setup *req);
+void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
+#endif /* I3C_INTERNAL_H */
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
new file mode 100644 (file)
index 0000000..c39f89d
--- /dev/null
@@ -0,0 +1,2659 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include "internals.h"
+
+static DEFINE_IDR(i3c_bus_idr);
+static DEFINE_MUTEX(i3c_core_lock);
+
+/**
+ * i3c_bus_maintenance_lock - Lock the bus for a maintenance operation
+ * @bus: I3C bus to take the lock on
+ *
+ * This function takes the bus lock so that no other operations can occur on
+ * the bus. This is needed for all kind of bus maintenance operation, like
+ * - enabling/disabling slave events
+ * - re-triggering DAA
+ * - changing the dynamic address of a device
+ * - relinquishing mastership
+ * - ...
+ *
+ * The reason for this kind of locking is that we don't want drivers and core
+ * logic to rely on I3C device information that could be changed behind their
+ * back.
+ */
+static void i3c_bus_maintenance_lock(struct i3c_bus *bus)
+{
+       down_write(&bus->lock);
+}
+
+/**
+ * i3c_bus_maintenance_unlock - Release the bus lock after a maintenance
+ *                           operation
+ * @bus: I3C bus to release the lock on
+ *
+ * Should be called when the bus maintenance operation is done. See
+ * i3c_bus_maintenance_lock() for more details on what these maintenance
+ * operations are.
+ */
+static void i3c_bus_maintenance_unlock(struct i3c_bus *bus)
+{
+       up_write(&bus->lock);
+}
+
+/**
+ * i3c_bus_normaluse_lock - Lock the bus for a normal operation
+ * @bus: I3C bus to take the lock on
+ *
+ * This function takes the bus lock for any operation that is not a maintenance
+ * operation (see i3c_bus_maintenance_lock() for a non-exhaustive list of
+ * maintenance operations). Basically all communications with I3C devices are
+ * normal operations (HDR, SDR transfers or CCC commands that do not change bus
+ * state or I3C dynamic address).
+ *
+ * Note that this lock is not guaranteeing serialization of normal operations.
+ * In other words, transfer requests passed to the I3C master can be submitted
+ * in parallel and I3C master drivers have to use their own locking to make
+ * sure two different communications are not inter-mixed, or access to the
+ * output/input queue is not done while the engine is busy.
+ */
+void i3c_bus_normaluse_lock(struct i3c_bus *bus)
+{
+       down_read(&bus->lock);
+}
+
+/**
+ * i3c_bus_normaluse_unlock - Release the bus lock after a normal operation
+ * @bus: I3C bus to release the lock on
+ *
+ * Should be called when a normal operation is done. See
+ * i3c_bus_normaluse_lock() for more details on what these normal operations
+ * are.
+ */
+void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
+{
+       up_read(&bus->lock);
+}
+
+static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
+{
+       return container_of(dev, struct i3c_master_controller, dev);
+}
+
+static const struct device_type i3c_device_type;
+
+static struct i3c_bus *dev_to_i3cbus(struct device *dev)
+{
+       struct i3c_master_controller *master;
+
+       if (dev->type == &i3c_device_type)
+               return dev_to_i3cdev(dev)->bus;
+
+       master = dev_to_i3cmaster(dev);
+
+       return &master->bus;
+}
+
+static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev)
+{
+       struct i3c_master_controller *master;
+
+       if (dev->type == &i3c_device_type)
+               return dev_to_i3cdev(dev)->desc;
+
+       master = container_of(dev, struct i3c_master_controller, dev);
+
+       return master->this;
+}
+
+static ssize_t bcr_show(struct device *dev,
+                       struct device_attribute *da,
+                       char *buf)
+{
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+       struct i3c_dev_desc *desc;
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(bus);
+       desc = dev_to_i3cdesc(dev);
+       ret = sprintf(buf, "%x\n", desc->info.bcr);
+       i3c_bus_normaluse_unlock(bus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(bcr);
+
+static ssize_t dcr_show(struct device *dev,
+                       struct device_attribute *da,
+                       char *buf)
+{
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+       struct i3c_dev_desc *desc;
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(bus);
+       desc = dev_to_i3cdesc(dev);
+       ret = sprintf(buf, "%x\n", desc->info.dcr);
+       i3c_bus_normaluse_unlock(bus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(dcr);
+
+static ssize_t pid_show(struct device *dev,
+                       struct device_attribute *da,
+                       char *buf)
+{
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+       struct i3c_dev_desc *desc;
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(bus);
+       desc = dev_to_i3cdesc(dev);
+       ret = sprintf(buf, "%llx\n", desc->info.pid);
+       i3c_bus_normaluse_unlock(bus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(pid);
+
+static ssize_t dynamic_address_show(struct device *dev,
+                                   struct device_attribute *da,
+                                   char *buf)
+{
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+       struct i3c_dev_desc *desc;
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(bus);
+       desc = dev_to_i3cdesc(dev);
+       ret = sprintf(buf, "%02x\n", desc->info.dyn_addr);
+       i3c_bus_normaluse_unlock(bus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(dynamic_address);
+
+static const char * const hdrcap_strings[] = {
+       "hdr-ddr", "hdr-tsp", "hdr-tsl",
+};
+
+static ssize_t hdrcap_show(struct device *dev,
+                          struct device_attribute *da,
+                          char *buf)
+{
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+       struct i3c_dev_desc *desc;
+       ssize_t offset = 0, ret;
+       unsigned long caps;
+       int mode;
+
+       i3c_bus_normaluse_lock(bus);
+       desc = dev_to_i3cdesc(dev);
+       caps = desc->info.hdr_cap;
+       for_each_set_bit(mode, &caps, 8) {
+               if (mode >= ARRAY_SIZE(hdrcap_strings))
+                       break;
+
+               if (!hdrcap_strings[mode])
+                       continue;
+
+               ret = sprintf(buf + offset, offset ? " %s" : "%s",
+                             hdrcap_strings[mode]);
+               if (ret < 0)
+                       goto out;
+
+               offset += ret;
+       }
+
+       ret = sprintf(buf + offset, "\n");
+       if (ret < 0)
+               goto out;
+
+       ret = offset + ret;
+
+out:
+       i3c_bus_normaluse_unlock(bus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(hdrcap);
+
+static struct attribute *i3c_device_attrs[] = {
+       &dev_attr_bcr.attr,
+       &dev_attr_dcr.attr,
+       &dev_attr_pid.attr,
+       &dev_attr_dynamic_address.attr,
+       &dev_attr_hdrcap.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(i3c_device);
+
+static int i3c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct i3c_device *i3cdev = dev_to_i3cdev(dev);
+       struct i3c_device_info devinfo;
+       u16 manuf, part, ext;
+
+       i3c_device_get_info(i3cdev, &devinfo);
+       manuf = I3C_PID_MANUF_ID(devinfo.pid);
+       part = I3C_PID_PART_ID(devinfo.pid);
+       ext = I3C_PID_EXTRA_INFO(devinfo.pid);
+
+       if (I3C_PID_RND_LOWER_32BITS(devinfo.pid))
+               return add_uevent_var(env, "MODALIAS=i3c:dcr%02Xmanuf%04X",
+                                     devinfo.dcr, manuf);
+
+       return add_uevent_var(env,
+                             "MODALIAS=i3c:dcr%02Xmanuf%04Xpart%04xext%04x",
+                             devinfo.dcr, manuf, part, ext);
+}
+
+static const struct device_type i3c_device_type = {
+       .groups = i3c_device_groups,
+       .uevent = i3c_device_uevent,
+};
+
+static const struct i3c_device_id *
+i3c_device_match_id(struct i3c_device *i3cdev,
+                   const struct i3c_device_id *id_table)
+{
+       struct i3c_device_info devinfo;
+       const struct i3c_device_id *id;
+
+       i3c_device_get_info(i3cdev, &devinfo);
+
+       /*
+        * The lower 32bits of the provisional ID is just filled with a random
+        * value, try to match using DCR info.
+        */
+       if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
+               u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
+               u16 part = I3C_PID_PART_ID(devinfo.pid);
+               u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
+
+               /* First try to match by manufacturer/part ID. */
+               for (id = id_table; id->match_flags != 0; id++) {
+                       if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
+                           I3C_MATCH_MANUF_AND_PART)
+                               continue;
+
+                       if (manuf != id->manuf_id || part != id->part_id)
+                               continue;
+
+                       if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
+                           ext_info != id->extra_info)
+                               continue;
+
+                       return id;
+               }
+       }
+
+       /* Fallback to DCR match. */
+       for (id = id_table; id->match_flags != 0; id++) {
+               if ((id->match_flags & I3C_MATCH_DCR) &&
+                   id->dcr == devinfo.dcr)
+                       return id;
+       }
+
+       return NULL;
+}
+
+static int i3c_device_match(struct device *dev, struct device_driver *drv)
+{
+       struct i3c_device *i3cdev;
+       struct i3c_driver *i3cdrv;
+
+       if (dev->type != &i3c_device_type)
+               return 0;
+
+       i3cdev = dev_to_i3cdev(dev);
+       i3cdrv = drv_to_i3cdrv(drv);
+       if (i3c_device_match_id(i3cdev, i3cdrv->id_table))
+               return 1;
+
+       return 0;
+}
+
+static int i3c_device_probe(struct device *dev)
+{
+       struct i3c_device *i3cdev = dev_to_i3cdev(dev);
+       struct i3c_driver *driver = drv_to_i3cdrv(dev->driver);
+
+       return driver->probe(i3cdev);
+}
+
+static int i3c_device_remove(struct device *dev)
+{
+       struct i3c_device *i3cdev = dev_to_i3cdev(dev);
+       struct i3c_driver *driver = drv_to_i3cdrv(dev->driver);
+       int ret;
+
+       ret = driver->remove(i3cdev);
+       if (ret)
+               return ret;
+
+       i3c_device_free_ibi(i3cdev);
+
+       return ret;
+}
+
+struct bus_type i3c_bus_type = {
+       .name = "i3c",
+       .match = i3c_device_match,
+       .probe = i3c_device_probe,
+       .remove = i3c_device_remove,
+};
+
+static enum i3c_addr_slot_status
+i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
+{
+       int status, bitpos = addr * 2;
+
+       if (addr > I2C_MAX_ADDR)
+               return I3C_ADDR_SLOT_RSVD;
+
+       status = bus->addrslots[bitpos / BITS_PER_LONG];
+       status >>= bitpos % BITS_PER_LONG;
+
+       return status & I3C_ADDR_SLOT_STATUS_MASK;
+}
+
+static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
+                                        enum i3c_addr_slot_status status)
+{
+       int bitpos = addr * 2;
+       unsigned long *ptr;
+
+       if (addr > I2C_MAX_ADDR)
+               return;
+
+       ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
+       *ptr &= ~(I3C_ADDR_SLOT_STATUS_MASK << (bitpos % BITS_PER_LONG));
+       *ptr |= status << (bitpos % BITS_PER_LONG);
+}
+
+static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
+{
+       enum i3c_addr_slot_status status;
+
+       status = i3c_bus_get_addr_slot_status(bus, addr);
+
+       return status == I3C_ADDR_SLOT_FREE;
+}
+
+static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
+{
+       enum i3c_addr_slot_status status;
+       u8 addr;
+
+       for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
+               status = i3c_bus_get_addr_slot_status(bus, addr);
+               if (status == I3C_ADDR_SLOT_FREE)
+                       return addr;
+       }
+
+       return -ENOMEM;
+}
+
+static void i3c_bus_init_addrslots(struct i3c_bus *bus)
+{
+       int i;
+
+       /* Addresses 0 to 7 are reserved. */
+       for (i = 0; i < 8; i++)
+               i3c_bus_set_addr_slot_status(bus, i, I3C_ADDR_SLOT_RSVD);
+
+       /*
+        * Reserve broadcast address and all addresses that might collide
+        * with the broadcast address when facing a single bit error.
+        */
+       i3c_bus_set_addr_slot_status(bus, I3C_BROADCAST_ADDR,
+                                    I3C_ADDR_SLOT_RSVD);
+       for (i = 0; i < 7; i++)
+               i3c_bus_set_addr_slot_status(bus, I3C_BROADCAST_ADDR ^ BIT(i),
+                                            I3C_ADDR_SLOT_RSVD);
+}
+
+static void i3c_bus_cleanup(struct i3c_bus *i3cbus)
+{
+       mutex_lock(&i3c_core_lock);
+       idr_remove(&i3c_bus_idr, i3cbus->id);
+       mutex_unlock(&i3c_core_lock);
+}
+
+static int i3c_bus_init(struct i3c_bus *i3cbus)
+{
+       int ret;
+
+       init_rwsem(&i3cbus->lock);
+       INIT_LIST_HEAD(&i3cbus->devs.i2c);
+       INIT_LIST_HEAD(&i3cbus->devs.i3c);
+       i3c_bus_init_addrslots(i3cbus);
+       i3cbus->mode = I3C_BUS_MODE_PURE;
+
+       mutex_lock(&i3c_core_lock);
+       ret = idr_alloc(&i3c_bus_idr, i3cbus, 0, 0, GFP_KERNEL);
+       mutex_unlock(&i3c_core_lock);
+
+       if (ret < 0)
+               return ret;
+
+       i3cbus->id = ret;
+
+       return 0;
+}
+
+static const char * const i3c_bus_mode_strings[] = {
+       [I3C_BUS_MODE_PURE] = "pure",
+       [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
+       [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow",
+};
+
+static ssize_t mode_show(struct device *dev,
+                        struct device_attribute *da,
+                        char *buf)
+{
+       struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(i3cbus);
+       if (i3cbus->mode < 0 ||
+           i3cbus->mode >= ARRAY_SIZE(i3c_bus_mode_strings) ||
+           !i3c_bus_mode_strings[i3cbus->mode])
+               ret = sprintf(buf, "unknown\n");
+       else
+               ret = sprintf(buf, "%s\n", i3c_bus_mode_strings[i3cbus->mode]);
+       i3c_bus_normaluse_unlock(i3cbus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(mode);
+
+static ssize_t current_master_show(struct device *dev,
+                                  struct device_attribute *da,
+                                  char *buf)
+{
+       struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(i3cbus);
+       ret = sprintf(buf, "%d-%llx\n", i3cbus->id,
+                     i3cbus->cur_master->info.pid);
+       i3c_bus_normaluse_unlock(i3cbus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(current_master);
+
+static ssize_t i3c_scl_frequency_show(struct device *dev,
+                                     struct device_attribute *da,
+                                     char *buf)
+{
+       struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(i3cbus);
+       ret = sprintf(buf, "%ld\n", i3cbus->scl_rate.i3c);
+       i3c_bus_normaluse_unlock(i3cbus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(i3c_scl_frequency);
+
+static ssize_t i2c_scl_frequency_show(struct device *dev,
+                                     struct device_attribute *da,
+                                     char *buf)
+{
+       struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+       ssize_t ret;
+
+       i3c_bus_normaluse_lock(i3cbus);
+       ret = sprintf(buf, "%ld\n", i3cbus->scl_rate.i2c);
+       i3c_bus_normaluse_unlock(i3cbus);
+
+       return ret;
+}
+static DEVICE_ATTR_RO(i2c_scl_frequency);
+
+static struct attribute *i3c_masterdev_attrs[] = {
+       &dev_attr_mode.attr,
+       &dev_attr_current_master.attr,
+       &dev_attr_i3c_scl_frequency.attr,
+       &dev_attr_i2c_scl_frequency.attr,
+       &dev_attr_bcr.attr,
+       &dev_attr_dcr.attr,
+       &dev_attr_pid.attr,
+       &dev_attr_dynamic_address.attr,
+       &dev_attr_hdrcap.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(i3c_masterdev);
+
+static void i3c_masterdev_release(struct device *dev)
+{
+       struct i3c_master_controller *master = dev_to_i3cmaster(dev);
+       struct i3c_bus *bus = dev_to_i3cbus(dev);
+
+       if (master->wq)
+               destroy_workqueue(master->wq);
+
+       WARN_ON(!list_empty(&bus->devs.i2c) || !list_empty(&bus->devs.i3c));
+       i3c_bus_cleanup(bus);
+
+       of_node_put(dev->of_node);
+}
+
+static const struct device_type i3c_masterdev_type = {
+       .groups = i3c_masterdev_groups,
+};
+
+int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
+{
+       i3cbus->mode = mode;
+
+       if (!i3cbus->scl_rate.i3c)
+               i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+
+       if (!i3cbus->scl_rate.i2c) {
+               if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW)
+                       i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
+               else
+                       i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
+       }
+
+       /*
+        * I3C/I2C frequency may have been overridden, check that user-provided
+        * values are not exceeding max possible frequency.
+        */
+       if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE ||
+           i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct i3c_master_controller *
+i2c_adapter_to_i3c_master(struct i2c_adapter *adap)
+{
+       return container_of(adap, struct i3c_master_controller, i2c);
+}
+
+static struct i2c_adapter *
+i3c_master_to_i2c_adapter(struct i3c_master_controller *master)
+{
+       return &master->i2c;
+}
+
+static void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev)
+{
+       kfree(dev);
+}
+
+static struct i2c_dev_desc *
+i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
+                        const struct i2c_dev_boardinfo *boardinfo)
+{
+       struct i2c_dev_desc *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       dev->common.master = master;
+       dev->boardinfo = boardinfo;
+
+       return dev;
+}
+
+static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
+                                  u16 payloadlen)
+{
+       dest->addr = addr;
+       dest->payload.len = payloadlen;
+       if (payloadlen)
+               dest->payload.data = kzalloc(payloadlen, GFP_KERNEL);
+       else
+               dest->payload.data = NULL;
+
+       return dest->payload.data;
+}
+
+static void i3c_ccc_cmd_dest_cleanup(struct i3c_ccc_cmd_dest *dest)
+{
+       kfree(dest->payload.data);
+}
+
+static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id,
+                            struct i3c_ccc_cmd_dest *dests,
+                            unsigned int ndests)
+{
+       cmd->rnw = rnw ? 1 : 0;
+       cmd->id = id;
+       cmd->dests = dests;
+       cmd->ndests = ndests;
+       cmd->err = I3C_ERROR_UNKNOWN;
+}
+
+static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
+                                         struct i3c_ccc_cmd *cmd)
+{
+       int ret;
+
+       if (!cmd || !master)
+               return -EINVAL;
+
+       if (WARN_ON(master->init_done &&
+                   !rwsem_is_locked(&master->bus.lock)))
+               return -EINVAL;
+
+       if (!master->ops->send_ccc_cmd)
+               return -ENOTSUPP;
+
+       if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests))
+               return -EINVAL;
+
+       if (master->ops->supports_ccc_cmd &&
+           !master->ops->supports_ccc_cmd(master, cmd))
+               return -ENOTSUPP;
+
+       ret = master->ops->send_ccc_cmd(master, cmd);
+       if (ret) {
+               if (cmd->err != I3C_ERROR_UNKNOWN)
+                       return cmd->err;
+
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct i2c_dev_desc *
+i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
+                               u16 addr)
+{
+       struct i2c_dev_desc *dev;
+
+       i3c_bus_for_each_i2cdev(&master->bus, dev) {
+               if (dev->boardinfo->base.addr == addr)
+                       return dev;
+       }
+
+       return NULL;
+}
+
+/**
+ * i3c_master_get_free_addr() - get a free address on the bus
+ * @master: I3C master object
+ * @start_addr: where to start searching
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: the first free address starting at @start_addr (included) or -ENOMEM
+ * if there's no more address available.
+ */
+int i3c_master_get_free_addr(struct i3c_master_controller *master,
+                            u8 start_addr)
+{
+       return i3c_bus_get_free_addr(&master->bus, start_addr);
+}
+EXPORT_SYMBOL_GPL(i3c_master_get_free_addr);
+
+static void i3c_device_release(struct device *dev)
+{
+       struct i3c_device *i3cdev = dev_to_i3cdev(dev);
+
+       WARN_ON(i3cdev->desc);
+
+       of_node_put(i3cdev->dev.of_node);
+       kfree(i3cdev);
+}
+
+static void i3c_master_free_i3c_dev(struct i3c_dev_desc *dev)
+{
+       kfree(dev);
+}
+
+static struct i3c_dev_desc *
+i3c_master_alloc_i3c_dev(struct i3c_master_controller *master,
+                        const struct i3c_device_info *info)
+{
+       struct i3c_dev_desc *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       dev->common.master = master;
+       dev->info = *info;
+       mutex_init(&dev->ibi_lock);
+
+       return dev;
+}
+
+static int i3c_master_rstdaa_locked(struct i3c_master_controller *master,
+                                   u8 addr)
+{
+       enum i3c_addr_slot_status addrstat;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       if (!master)
+               return -EINVAL;
+
+       addrstat = i3c_bus_get_addr_slot_status(&master->bus, addr);
+       if (addr != I3C_BROADCAST_ADDR && addrstat != I3C_ADDR_SLOT_I3C_DEV)
+               return -EINVAL;
+
+       i3c_ccc_cmd_dest_init(&dest, addr, 0);
+       i3c_ccc_cmd_init(&cmd, false,
+                        I3C_CCC_RSTDAA(addr == I3C_BROADCAST_ADDR),
+                        &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+/**
+ * i3c_master_entdaa_locked() - start a DAA (Dynamic Address Assignment)
+ *                             procedure
+ * @master: master used to send frames on the bus
+ *
+ * Send a ENTDAA CCC command to start a DAA procedure.
+ *
+ * Note that this function only sends the ENTDAA CCC command, all the logic
+ * behind dynamic address assignment has to be handled in the I3C master
+ * driver.
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: 0 in case of success, a positive I3C error code if the error is
+ * one of the official Mx error codes, and a negative error code otherwise.
+ */
+int i3c_master_entdaa_locked(struct i3c_master_controller *master)
+{
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, 0);
+       i3c_ccc_cmd_init(&cmd, false, I3C_CCC_ENTDAA, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked);
+
+static int i3c_master_enec_disec_locked(struct i3c_master_controller *master,
+                                       u8 addr, bool enable, u8 evts)
+{
+       struct i3c_ccc_events *events;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       events = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*events));
+       if (!events)
+               return -ENOMEM;
+
+       events->events = evts;
+       i3c_ccc_cmd_init(&cmd, false,
+                        enable ?
+                        I3C_CCC_ENEC(addr == I3C_BROADCAST_ADDR) :
+                        I3C_CCC_DISEC(addr == I3C_BROADCAST_ADDR),
+                        &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+/**
+ * i3c_master_disec_locked() - send a DISEC CCC command
+ * @master: master used to send frames on the bus
+ * @addr: a valid I3C slave address or %I3C_BROADCAST_ADDR
+ * @evts: events to disable
+ *
+ * Send a DISEC CCC command to disable some or all events coming from a
+ * specific slave, or all devices if @addr is %I3C_BROADCAST_ADDR.
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: 0 in case of success, a positive I3C error code if the error is
+ * one of the official Mx error codes, and a negative error code otherwise.
+ */
+int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr,
+                           u8 evts)
+{
+       return i3c_master_enec_disec_locked(master, addr, false, evts);
+}
+EXPORT_SYMBOL_GPL(i3c_master_disec_locked);
+
+/**
+ * i3c_master_enec_locked() - send an ENEC CCC command
+ * @master: master used to send frames on the bus
+ * @addr: a valid I3C slave address or %I3C_BROADCAST_ADDR
+ * @evts: events to disable
+ *
+ * Sends an ENEC CCC command to enable some or all events coming from a
+ * specific slave, or all devices if @addr is %I3C_BROADCAST_ADDR.
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: 0 in case of success, a positive I3C error code if the error is
+ * one of the official Mx error codes, and a negative error code otherwise.
+ */
+int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr,
+                          u8 evts)
+{
+       return i3c_master_enec_disec_locked(master, addr, true, evts);
+}
+EXPORT_SYMBOL_GPL(i3c_master_enec_locked);
+
+/**
+ * i3c_master_defslvs_locked() - send a DEFSLVS CCC command
+ * @master: master used to send frames on the bus
+ *
+ * Send a DEFSLVS CCC command containing all the devices known to the @master.
+ * This is useful when you have secondary masters on the bus to propagate
+ * device information.
+ *
+ * This should be called after all I3C devices have been discovered (in other
+ * words, after the DAA procedure has finished) and instantiated in
+ * &i3c_master_controller_ops->bus_init().
+ * It should also be called if a master ACKed an Hot-Join request and assigned
+ * a dynamic address to the device joining the bus.
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: 0 in case of success, a positive I3C error code if the error is
+ * one of the official Mx error codes, and a negative error code otherwise.
+ */
+int i3c_master_defslvs_locked(struct i3c_master_controller *master)
+{
+       struct i3c_ccc_defslvs *defslvs;
+       struct i3c_ccc_dev_desc *desc;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_dev_desc *i3cdev;
+       struct i2c_dev_desc *i2cdev;
+       struct i3c_ccc_cmd cmd;
+       struct i3c_bus *bus;
+       bool send = false;
+       int ndevs = 0, ret;
+
+       if (!master)
+               return -EINVAL;
+
+       bus = i3c_master_get_bus(master);
+       i3c_bus_for_each_i3cdev(bus, i3cdev) {
+               ndevs++;
+
+               if (i3cdev == master->this)
+                       continue;
+
+               if (I3C_BCR_DEVICE_ROLE(i3cdev->info.bcr) ==
+                   I3C_BCR_I3C_MASTER)
+                       send = true;
+       }
+
+       /* No other master on the bus, skip DEFSLVS. */
+       if (!send)
+               return 0;
+
+       i3c_bus_for_each_i2cdev(bus, i2cdev)
+               ndevs++;
+
+       defslvs = i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR,
+                                       sizeof(*defslvs) +
+                                       ((ndevs - 1) *
+                                        sizeof(struct i3c_ccc_dev_desc)));
+       if (!defslvs)
+               return -ENOMEM;
+
+       defslvs->count = ndevs;
+       defslvs->master.bcr = master->this->info.bcr;
+       defslvs->master.dcr = master->this->info.dcr;
+       defslvs->master.dyn_addr = master->this->info.dyn_addr << 1;
+       defslvs->master.static_addr = I3C_BROADCAST_ADDR << 1;
+
+       desc = defslvs->slaves;
+       i3c_bus_for_each_i2cdev(bus, i2cdev) {
+               desc->lvr = i2cdev->boardinfo->lvr;
+               desc->static_addr = i2cdev->boardinfo->base.addr << 1;
+               desc++;
+       }
+
+       i3c_bus_for_each_i3cdev(bus, i3cdev) {
+               /* Skip the I3C dev representing this master. */
+               if (i3cdev == master->this)
+                       continue;
+
+               desc->bcr = i3cdev->info.bcr;
+               desc->dcr = i3cdev->info.dcr;
+               desc->dyn_addr = i3cdev->info.dyn_addr << 1;
+               desc->static_addr = i3cdev->info.static_addr << 1;
+               desc++;
+       }
+
+       i3c_ccc_cmd_init(&cmd, false, I3C_CCC_DEFSLVS, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_defslvs_locked);
+
+static int i3c_master_setda_locked(struct i3c_master_controller *master,
+                                  u8 oldaddr, u8 newaddr, bool setdasa)
+{
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_setda *setda;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       if (!oldaddr || !newaddr)
+               return -EINVAL;
+
+       setda = i3c_ccc_cmd_dest_init(&dest, oldaddr, sizeof(*setda));
+       if (!setda)
+               return -ENOMEM;
+
+       setda->addr = newaddr << 1;
+       i3c_ccc_cmd_init(&cmd, false,
+                        setdasa ? I3C_CCC_SETDASA : I3C_CCC_SETNEWDA,
+                        &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_setdasa_locked(struct i3c_master_controller *master,
+                                    u8 static_addr, u8 dyn_addr)
+{
+       return i3c_master_setda_locked(master, static_addr, dyn_addr, true);
+}
+
+static int i3c_master_setnewda_locked(struct i3c_master_controller *master,
+                                     u8 oldaddr, u8 newaddr)
+{
+       return i3c_master_setda_locked(master, oldaddr, newaddr, false);
+}
+
+static int i3c_master_getmrl_locked(struct i3c_master_controller *master,
+                                   struct i3c_device_info *info)
+{
+       struct i3c_ccc_cmd_dest dest;
+       unsigned int expected_len;
+       struct i3c_ccc_mrl *mrl;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       mrl = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*mrl));
+       if (!mrl)
+               return -ENOMEM;
+
+       /*
+        * When the device does not have IBI payload GETMRL only returns 2
+        * bytes of data.
+        */
+       if (!(info->bcr & I3C_BCR_IBI_PAYLOAD))
+               dest.payload.len -= 1;
+
+       expected_len = dest.payload.len;
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMRL, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       if (dest.payload.len != expected_len) {
+               ret = -EIO;
+               goto out;
+       }
+
+       info->max_read_len = be16_to_cpu(mrl->read_len);
+
+       if (info->bcr & I3C_BCR_IBI_PAYLOAD)
+               info->max_ibi_len = mrl->ibi_len;
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_getmwl_locked(struct i3c_master_controller *master,
+                                   struct i3c_device_info *info)
+{
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_mwl *mwl;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       mwl = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*mwl));
+       if (!mwl)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMWL, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       if (dest.payload.len != sizeof(*mwl))
+               return -EIO;
+
+       info->max_write_len = be16_to_cpu(mwl->len);
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_getmxds_locked(struct i3c_master_controller *master,
+                                    struct i3c_device_info *info)
+{
+       struct i3c_ccc_getmxds *getmaxds;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       getmaxds = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr,
+                                        sizeof(*getmaxds));
+       if (!getmaxds)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMXDS, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       if (dest.payload.len != 2 && dest.payload.len != 5) {
+               ret = -EIO;
+               goto out;
+       }
+
+       info->max_read_ds = getmaxds->maxrd;
+       info->max_write_ds = getmaxds->maxwr;
+       if (dest.payload.len == 5)
+               info->max_read_turnaround = getmaxds->maxrdturn[0] |
+                                           ((u32)getmaxds->maxrdturn[1] << 8) |
+                                           ((u32)getmaxds->maxrdturn[2] << 16);
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_gethdrcap_locked(struct i3c_master_controller *master,
+                                      struct i3c_device_info *info)
+{
+       struct i3c_ccc_gethdrcap *gethdrcap;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       gethdrcap = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr,
+                                         sizeof(*gethdrcap));
+       if (!gethdrcap)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETHDRCAP, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       if (dest.payload.len != 1) {
+               ret = -EIO;
+               goto out;
+       }
+
+       info->hdr_cap = gethdrcap->modes;
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_getpid_locked(struct i3c_master_controller *master,
+                                   struct i3c_device_info *info)
+{
+       struct i3c_ccc_getpid *getpid;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret, i;
+
+       getpid = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getpid));
+       if (!getpid)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETPID, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       info->pid = 0;
+       for (i = 0; i < sizeof(getpid->pid); i++) {
+               int sft = (sizeof(getpid->pid) - i - 1) * 8;
+
+               info->pid |= (u64)getpid->pid[i] << sft;
+       }
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_getbcr_locked(struct i3c_master_controller *master,
+                                   struct i3c_device_info *info)
+{
+       struct i3c_ccc_getbcr *getbcr;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       getbcr = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getbcr));
+       if (!getbcr)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETBCR, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       info->bcr = getbcr->bcr;
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_getdcr_locked(struct i3c_master_controller *master,
+                                   struct i3c_device_info *info)
+{
+       struct i3c_ccc_getdcr *getdcr;
+       struct i3c_ccc_cmd_dest dest;
+       struct i3c_ccc_cmd cmd;
+       int ret;
+
+       getdcr = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getdcr));
+       if (!getdcr)
+               return -ENOMEM;
+
+       i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETDCR, &dest, 1);
+       ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+       if (ret)
+               goto out;
+
+       info->dcr = getdcr->dcr;
+
+out:
+       i3c_ccc_cmd_dest_cleanup(&dest);
+
+       return ret;
+}
+
+static int i3c_master_retrieve_dev_info(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       enum i3c_addr_slot_status slot_status;
+       int ret;
+
+       if (!dev->info.dyn_addr)
+               return -EINVAL;
+
+       slot_status = i3c_bus_get_addr_slot_status(&master->bus,
+                                                  dev->info.dyn_addr);
+       if (slot_status == I3C_ADDR_SLOT_RSVD ||
+           slot_status == I3C_ADDR_SLOT_I2C_DEV)
+               return -EINVAL;
+
+       ret = i3c_master_getpid_locked(master, &dev->info);
+       if (ret)
+               return ret;
+
+       ret = i3c_master_getbcr_locked(master, &dev->info);
+       if (ret)
+               return ret;
+
+       ret = i3c_master_getdcr_locked(master, &dev->info);
+       if (ret)
+               return ret;
+
+       if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM) {
+               ret = i3c_master_getmxds_locked(master, &dev->info);
+               if (ret)
+                       return ret;
+       }
+
+       if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD)
+               dev->info.max_ibi_len = 1;
+
+       i3c_master_getmrl_locked(master, &dev->info);
+       i3c_master_getmwl_locked(master, &dev->info);
+
+       if (dev->info.bcr & I3C_BCR_HDR_CAP) {
+               ret = i3c_master_gethdrcap_locked(master, &dev->info);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void i3c_master_put_i3c_addrs(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+
+       if (dev->info.static_addr)
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            dev->info.static_addr,
+                                            I3C_ADDR_SLOT_FREE);
+
+       if (dev->info.dyn_addr)
+               i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr,
+                                            I3C_ADDR_SLOT_FREE);
+
+       if (dev->boardinfo && dev->boardinfo->init_dyn_addr)
+               i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr,
+                                            I3C_ADDR_SLOT_FREE);
+}
+
+static int i3c_master_get_i3c_addrs(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       enum i3c_addr_slot_status status;
+
+       if (!dev->info.static_addr && !dev->info.dyn_addr)
+               return 0;
+
+       if (dev->info.static_addr) {
+               status = i3c_bus_get_addr_slot_status(&master->bus,
+                                                     dev->info.static_addr);
+               if (status != I3C_ADDR_SLOT_FREE)
+                       return -EBUSY;
+
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            dev->info.static_addr,
+                                            I3C_ADDR_SLOT_I3C_DEV);
+       }
+
+       /*
+        * ->init_dyn_addr should have been reserved before that, so, if we're
+        * trying to apply a pre-reserved dynamic address, we should not try
+        * to reserve the address slot a second time.
+        */
+       if (dev->info.dyn_addr &&
+           (!dev->boardinfo ||
+            dev->boardinfo->init_dyn_addr != dev->info.dyn_addr)) {
+               status = i3c_bus_get_addr_slot_status(&master->bus,
+                                                     dev->info.dyn_addr);
+               if (status != I3C_ADDR_SLOT_FREE)
+                       goto err_release_static_addr;
+
+               i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr,
+                                            I3C_ADDR_SLOT_I3C_DEV);
+       }
+
+       return 0;
+
+err_release_static_addr:
+       if (dev->info.static_addr)
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            dev->info.static_addr,
+                                            I3C_ADDR_SLOT_FREE);
+
+       return -EBUSY;
+}
+
+static int i3c_master_attach_i3c_dev(struct i3c_master_controller *master,
+                                    struct i3c_dev_desc *dev)
+{
+       int ret;
+
+       /*
+        * We don't attach devices to the controller until they are
+        * addressable on the bus.
+        */
+       if (!dev->info.static_addr && !dev->info.dyn_addr)
+               return 0;
+
+       ret = i3c_master_get_i3c_addrs(dev);
+       if (ret)
+               return ret;
+
+       /* Do not attach the master device itself. */
+       if (master->this != dev && master->ops->attach_i3c_dev) {
+               ret = master->ops->attach_i3c_dev(dev);
+               if (ret) {
+                       i3c_master_put_i3c_addrs(dev);
+                       return ret;
+               }
+       }
+
+       list_add_tail(&dev->common.node, &master->bus.devs.i3c);
+
+       return 0;
+}
+
+static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
+                                      u8 old_dyn_addr)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       enum i3c_addr_slot_status status;
+       int ret;
+
+       if (dev->info.dyn_addr != old_dyn_addr) {
+               status = i3c_bus_get_addr_slot_status(&master->bus,
+                                                     dev->info.dyn_addr);
+               if (status != I3C_ADDR_SLOT_FREE)
+                       return -EBUSY;
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            dev->info.dyn_addr,
+                                            I3C_ADDR_SLOT_I3C_DEV);
+       }
+
+       if (master->ops->reattach_i3c_dev) {
+               ret = master->ops->reattach_i3c_dev(dev, old_dyn_addr);
+               if (ret) {
+                       i3c_master_put_i3c_addrs(dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+
+       /* Do not detach the master device itself. */
+       if (master->this != dev && master->ops->detach_i3c_dev)
+               master->ops->detach_i3c_dev(dev);
+
+       i3c_master_put_i3c_addrs(dev);
+       list_del(&dev->common.node);
+}
+
+static int i3c_master_attach_i2c_dev(struct i3c_master_controller *master,
+                                    struct i2c_dev_desc *dev)
+{
+       int ret;
+
+       if (master->ops->attach_i2c_dev) {
+               ret = master->ops->attach_i2c_dev(dev);
+               if (ret)
+                       return ret;
+       }
+
+       list_add_tail(&dev->common.node, &master->bus.devs.i2c);
+
+       return 0;
+}
+
+static void i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i2c_dev_get_master(dev);
+
+       list_del(&dev->common.node);
+
+       if (master->ops->detach_i2c_dev)
+               master->ops->detach_i2c_dev(dev);
+}
+
+static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       int ret;
+
+       if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr ||
+           !dev->boardinfo->static_addr)
+               return;
+
+       ret = i3c_master_setdasa_locked(master, dev->info.static_addr,
+                                       dev->boardinfo->init_dyn_addr);
+       if (ret)
+               return;
+
+       dev->info.dyn_addr = dev->boardinfo->init_dyn_addr;
+       ret = i3c_master_reattach_i3c_dev(dev, 0);
+       if (ret)
+               goto err_rstdaa;
+
+       ret = i3c_master_retrieve_dev_info(dev);
+       if (ret)
+               goto err_rstdaa;
+
+       return;
+
+err_rstdaa:
+       i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr);
+}
+
+static void
+i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
+{
+       struct i3c_dev_desc *desc;
+       int ret;
+
+       if (!master->init_done)
+               return;
+
+       i3c_bus_for_each_i3cdev(&master->bus, desc) {
+               if (desc->dev || !desc->info.dyn_addr || desc == master->this)
+                       continue;
+
+               desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL);
+               if (!desc->dev)
+                       continue;
+
+               desc->dev->bus = &master->bus;
+               desc->dev->desc = desc;
+               desc->dev->dev.parent = &master->dev;
+               desc->dev->dev.type = &i3c_device_type;
+               desc->dev->dev.bus = &i3c_bus_type;
+               desc->dev->dev.release = i3c_device_release;
+               dev_set_name(&desc->dev->dev, "%d-%llx", master->bus.id,
+                            desc->info.pid);
+
+               if (desc->boardinfo)
+                       desc->dev->dev.of_node = desc->boardinfo->of_node;
+
+               ret = device_register(&desc->dev->dev);
+               if (ret)
+                       dev_err(&master->dev,
+                               "Failed to add I3C device (err = %d)\n", ret);
+       }
+}
+
+/**
+ * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment)
+ * @master: master doing the DAA
+ *
+ * This function is instantiating an I3C device object and adding it to the
+ * I3C device list. All device information are automatically retrieved using
+ * standard CCC commands.
+ *
+ * The I3C device object is returned in case the master wants to attach
+ * private data to it using i3c_dev_set_master_data().
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_do_daa(struct i3c_master_controller *master)
+{
+       int ret;
+
+       i3c_bus_maintenance_lock(&master->bus);
+       ret = master->ops->do_daa(master);
+       i3c_bus_maintenance_unlock(&master->bus);
+
+       if (ret)
+               return ret;
+
+       i3c_bus_normaluse_lock(&master->bus);
+       i3c_master_register_new_i3c_devs(master);
+       i3c_bus_normaluse_unlock(&master->bus);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(i3c_master_do_daa);
+
+/**
+ * i3c_master_set_info() - set master device information
+ * @master: master used to send frames on the bus
+ * @info: I3C device information
+ *
+ * Set master device info. This should be called from
+ * &i3c_master_controller_ops->bus_init().
+ *
+ * Not all &i3c_device_info fields are meaningful for a master device.
+ * Here is a list of fields that should be properly filled:
+ *
+ * - &i3c_device_info->dyn_addr
+ * - &i3c_device_info->bcr
+ * - &i3c_device_info->dcr
+ * - &i3c_device_info->pid
+ * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in
+ *   &i3c_device_info->bcr
+ *
+ * This function must be called with the bus lock held in maintenance mode.
+ *
+ * Return: 0 if @info contains valid information (not every piece of
+ * information can be checked, but we can at least make sure @info->dyn_addr
+ * and @info->bcr are correct), -EINVAL otherwise.
+ */
+int i3c_master_set_info(struct i3c_master_controller *master,
+                       const struct i3c_device_info *info)
+{
+       struct i3c_dev_desc *i3cdev;
+       int ret;
+
+       if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr))
+               return -EINVAL;
+
+       if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER &&
+           master->secondary)
+               return -EINVAL;
+
+       if (master->this)
+               return -EINVAL;
+
+       i3cdev = i3c_master_alloc_i3c_dev(master, info);
+       if (IS_ERR(i3cdev))
+               return PTR_ERR(i3cdev);
+
+       master->this = i3cdev;
+       master->bus.cur_master = master->this;
+
+       ret = i3c_master_attach_i3c_dev(master, i3cdev);
+       if (ret)
+               goto err_free_dev;
+
+       return 0;
+
+err_free_dev:
+       i3c_master_free_i3c_dev(i3cdev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_set_info);
+
+static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
+{
+       struct i3c_dev_desc *i3cdev, *i3ctmp;
+       struct i2c_dev_desc *i2cdev, *i2ctmp;
+
+       list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c,
+                                common.node) {
+               i3c_master_detach_i3c_dev(i3cdev);
+
+               if (i3cdev->boardinfo && i3cdev->boardinfo->init_dyn_addr)
+                       i3c_bus_set_addr_slot_status(&master->bus,
+                                       i3cdev->boardinfo->init_dyn_addr,
+                                       I3C_ADDR_SLOT_FREE);
+
+               i3c_master_free_i3c_dev(i3cdev);
+       }
+
+       list_for_each_entry_safe(i2cdev, i2ctmp, &master->bus.devs.i2c,
+                                common.node) {
+               i3c_master_detach_i2c_dev(i2cdev);
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                       i2cdev->boardinfo->base.addr,
+                                       I3C_ADDR_SLOT_FREE);
+               i3c_master_free_i2c_dev(i2cdev);
+       }
+}
+
+/**
+ * i3c_master_bus_init() - initialize an I3C bus
+ * @master: main master initializing the bus
+ *
+ * This function is following all initialisation steps described in the I3C
+ * specification:
+ *
+ * 1. Attach I2C and statically defined I3C devs to the master so that the
+ *    master can fill its internal device table appropriately
+ *
+ * 2. Call &i3c_master_controller_ops->bus_init() method to initialize
+ *    the master controller. That's usually where the bus mode is selected
+ *    (pure bus or mixed fast/slow bus)
+ *
+ * 3. Instruct all devices on the bus to drop their dynamic address. This is
+ *    particularly important when the bus was previously configured by someone
+ *    else (for example the bootloader)
+ *
+ * 4. Disable all slave events.
+ *
+ * 5. Pre-assign dynamic addresses requested by the FW with SETDASA for I3C
+ *    devices that have a static address
+ *
+ * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all
+ *    remaining I3C devices
+ *
+ * Once this is done, all I3C and I2C devices should be usable.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+static int i3c_master_bus_init(struct i3c_master_controller *master)
+{
+       enum i3c_addr_slot_status status;
+       struct i2c_dev_boardinfo *i2cboardinfo;
+       struct i3c_dev_boardinfo *i3cboardinfo;
+       struct i3c_dev_desc *i3cdev;
+       struct i2c_dev_desc *i2cdev;
+       int ret;
+
+       /*
+        * First attach all devices with static definitions provided by the
+        * FW.
+        */
+       list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
+               status = i3c_bus_get_addr_slot_status(&master->bus,
+                                                     i2cboardinfo->base.addr);
+               if (status != I3C_ADDR_SLOT_FREE) {
+                       ret = -EBUSY;
+                       goto err_detach_devs;
+               }
+
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            i2cboardinfo->base.addr,
+                                            I3C_ADDR_SLOT_I2C_DEV);
+
+               i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
+               if (IS_ERR(i2cdev)) {
+                       ret = PTR_ERR(i2cdev);
+                       goto err_detach_devs;
+               }
+
+               ret = i3c_master_attach_i2c_dev(master, i2cdev);
+               if (ret) {
+                       i3c_master_free_i2c_dev(i2cdev);
+                       goto err_detach_devs;
+               }
+       }
+       list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
+               struct i3c_device_info info = {
+                       .static_addr = i3cboardinfo->static_addr,
+               };
+
+               if (i3cboardinfo->init_dyn_addr) {
+                       status = i3c_bus_get_addr_slot_status(&master->bus,
+                                               i3cboardinfo->init_dyn_addr);
+                       if (status != I3C_ADDR_SLOT_FREE) {
+                               ret = -EBUSY;
+                               goto err_detach_devs;
+                       }
+               }
+
+               i3cdev = i3c_master_alloc_i3c_dev(master, &info);
+               if (IS_ERR(i3cdev)) {
+                       ret = PTR_ERR(i3cdev);
+                       goto err_detach_devs;
+               }
+
+               i3cdev->boardinfo = i3cboardinfo;
+
+               ret = i3c_master_attach_i3c_dev(master, i3cdev);
+               if (ret) {
+                       i3c_master_free_i3c_dev(i3cdev);
+                       goto err_detach_devs;
+               }
+       }
+
+       /*
+        * Now execute the controller specific ->bus_init() routine, which
+        * might configure its internal logic to match the bus limitations.
+        */
+       ret = master->ops->bus_init(master);
+       if (ret)
+               goto err_detach_devs;
+
+       /*
+        * The master device should have been instantiated in ->bus_init(),
+        * complain if this was not the case.
+        */
+       if (!master->this) {
+               dev_err(&master->dev,
+                       "master_set_info() was not called in ->bus_init()\n");
+               ret = -EINVAL;
+               goto err_bus_cleanup;
+       }
+
+       /*
+        * Reset all dynamic address that may have been assigned before
+        * (assigned by the bootloader for example).
+        */
+       ret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
+       if (ret && ret != I3C_ERROR_M2)
+               goto err_bus_cleanup;
+
+       /* Disable all slave events before starting DAA. */
+       ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
+                                     I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
+                                     I3C_CCC_EVENT_HJ);
+       if (ret && ret != I3C_ERROR_M2)
+               goto err_bus_cleanup;
+
+       /*
+        * Pre-assign dynamic address and retrieve device information if
+        * needed.
+        */
+       i3c_bus_for_each_i3cdev(&master->bus, i3cdev)
+               i3c_master_pre_assign_dyn_addr(i3cdev);
+
+       ret = i3c_master_do_daa(master);
+       if (ret)
+               goto err_rstdaa;
+
+       return 0;
+
+err_rstdaa:
+       i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR);
+
+err_bus_cleanup:
+       if (master->ops->bus_cleanup)
+               master->ops->bus_cleanup(master);
+
+err_detach_devs:
+       i3c_master_detach_free_devs(master);
+
+       return ret;
+}
+
+static void i3c_master_bus_cleanup(struct i3c_master_controller *master)
+{
+       if (master->ops->bus_cleanup)
+               master->ops->bus_cleanup(master);
+
+       i3c_master_detach_free_devs(master);
+}
+
+static struct i3c_dev_desc *
+i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
+{
+       struct i3c_master_controller *master = refdev->common.master;
+       struct i3c_dev_desc *i3cdev;
+
+       i3c_bus_for_each_i3cdev(&master->bus, i3cdev) {
+               if (i3cdev != refdev && i3cdev->info.pid == refdev->info.pid)
+                       return i3cdev;
+       }
+
+       return NULL;
+}
+
+/**
+ * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus
+ * @master: master used to send frames on the bus
+ * @addr: I3C slave dynamic address assigned to the device
+ *
+ * This function is instantiating an I3C device object and adding it to the
+ * I3C device list. All device information are automatically retrieved using
+ * standard CCC commands.
+ *
+ * The I3C device object is returned in case the master wants to attach
+ * private data to it using i3c_dev_set_master_data().
+ *
+ * This function must be called with the bus lock held in write mode.
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
+                                 u8 addr)
+{
+       struct i3c_device_info info = { .dyn_addr = addr };
+       struct i3c_dev_desc *newdev, *olddev;
+       u8 old_dyn_addr = addr, expected_dyn_addr;
+       struct i3c_ibi_setup ibireq = { };
+       bool enable_ibi = false;
+       int ret;
+
+       if (!master)
+               return -EINVAL;
+
+       newdev = i3c_master_alloc_i3c_dev(master, &info);
+       if (IS_ERR(newdev))
+               return PTR_ERR(newdev);
+
+       ret = i3c_master_attach_i3c_dev(master, newdev);
+       if (ret)
+               goto err_free_dev;
+
+       ret = i3c_master_retrieve_dev_info(newdev);
+       if (ret)
+               goto err_free_dev;
+
+       olddev = i3c_master_search_i3c_dev_duplicate(newdev);
+       if (olddev) {
+               newdev->boardinfo = olddev->boardinfo;
+               newdev->info.static_addr = olddev->info.static_addr;
+               newdev->dev = olddev->dev;
+               if (newdev->dev)
+                       newdev->dev->desc = newdev;
+
+               /*
+                * We need to restore the IBI state too, so let's save the
+                * IBI information and try to restore them after olddev has
+                * been detached+released and its IBI has been stopped and
+                * the associated resources have been freed.
+                */
+               mutex_lock(&olddev->ibi_lock);
+               if (olddev->ibi) {
+                       ibireq.handler = olddev->ibi->handler;
+                       ibireq.max_payload_len = olddev->ibi->max_payload_len;
+                       ibireq.num_slots = olddev->ibi->num_slots;
+
+                       if (olddev->ibi->enabled) {
+                               enable_ibi = true;
+                               i3c_dev_disable_ibi_locked(olddev);
+                       }
+
+                       i3c_dev_free_ibi_locked(olddev);
+               }
+               mutex_unlock(&olddev->ibi_lock);
+
+               old_dyn_addr = olddev->info.dyn_addr;
+
+               i3c_master_detach_i3c_dev(olddev);
+               i3c_master_free_i3c_dev(olddev);
+       }
+
+       ret = i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
+       if (ret)
+               goto err_detach_dev;
+
+       /*
+        * Depending on our previous state, the expected dynamic address might
+        * differ:
+        * - if the device already had a dynamic address assigned, let's try to
+        *   re-apply this one
+        * - if the device did not have a dynamic address and the firmware
+        *   requested a specific address, pick this one
+        * - in any other case, keep the address automatically assigned by the
+        *   master
+        */
+       if (old_dyn_addr && old_dyn_addr != newdev->info.dyn_addr)
+               expected_dyn_addr = old_dyn_addr;
+       else if (newdev->boardinfo && newdev->boardinfo->init_dyn_addr)
+               expected_dyn_addr = newdev->boardinfo->init_dyn_addr;
+       else
+               expected_dyn_addr = newdev->info.dyn_addr;
+
+       if (newdev->info.dyn_addr != expected_dyn_addr) {
+               /*
+                * Try to apply the expected dynamic address. If it fails, keep
+                * the address assigned by the master.
+                */
+               ret = i3c_master_setnewda_locked(master,
+                                                newdev->info.dyn_addr,
+                                                expected_dyn_addr);
+               if (!ret) {
+                       old_dyn_addr = newdev->info.dyn_addr;
+                       newdev->info.dyn_addr = expected_dyn_addr;
+                       i3c_master_reattach_i3c_dev(newdev, old_dyn_addr);
+               } else {
+                       dev_err(&master->dev,
+                               "Failed to assign reserved/old address to device %d%llx",
+                               master->bus.id, newdev->info.pid);
+               }
+       }
+
+       /*
+        * Now is time to try to restore the IBI setup. If we're lucky,
+        * everything works as before, otherwise, all we can do is complain.
+        * FIXME: maybe we should add callback to inform the driver that it
+        * should request the IBI again instead of trying to hide that from
+        * him.
+        */
+       if (ibireq.handler) {
+               mutex_lock(&newdev->ibi_lock);
+               ret = i3c_dev_request_ibi_locked(newdev, &ibireq);
+               if (ret) {
+                       dev_err(&master->dev,
+                               "Failed to request IBI on device %d-%llx",
+                               master->bus.id, newdev->info.pid);
+               } else if (enable_ibi) {
+                       ret = i3c_dev_enable_ibi_locked(newdev);
+                       if (ret)
+                               dev_err(&master->dev,
+                                       "Failed to re-enable IBI on device %d-%llx",
+                                       master->bus.id, newdev->info.pid);
+               }
+               mutex_unlock(&newdev->ibi_lock);
+       }
+
+       return 0;
+
+err_detach_dev:
+       if (newdev->dev && newdev->dev->desc)
+               newdev->dev->desc = NULL;
+
+       i3c_master_detach_i3c_dev(newdev);
+
+err_free_dev:
+       i3c_master_free_i3c_dev(newdev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_add_i3c_dev_locked);
+
+#define OF_I3C_REG1_IS_I2C_DEV                 BIT(31)
+
+static int
+of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
+                               struct device_node *node, u32 *reg)
+{
+       struct i2c_dev_boardinfo *boardinfo;
+       struct device *dev = &master->dev;
+       int ret;
+
+       boardinfo = devm_kzalloc(dev, sizeof(*boardinfo), GFP_KERNEL);
+       if (!boardinfo)
+               return -ENOMEM;
+
+       ret = of_i2c_get_board_info(dev, node, &boardinfo->base);
+       if (ret)
+               return ret;
+
+       /* LVR is encoded in reg[2]. */
+       boardinfo->lvr = reg[2];
+
+       if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE)
+               master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
+
+       list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
+       of_node_get(node);
+
+       return 0;
+}
+
+static int
+of_i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
+                               struct device_node *node, u32 *reg)
+{
+       struct i3c_dev_boardinfo *boardinfo;
+       struct device *dev = &master->dev;
+       struct i3c_device_info info = { };
+       enum i3c_addr_slot_status addrstatus;
+       u32 init_dyn_addr = 0;
+
+       boardinfo = devm_kzalloc(dev, sizeof(*boardinfo), GFP_KERNEL);
+       if (!boardinfo)
+               return -ENOMEM;
+
+       if (reg[0]) {
+               if (reg[0] > I3C_MAX_ADDR)
+                       return -EINVAL;
+
+               addrstatus = i3c_bus_get_addr_slot_status(&master->bus,
+                                                         reg[0]);
+               if (addrstatus != I3C_ADDR_SLOT_FREE)
+                       return -EINVAL;
+       }
+
+       boardinfo->static_addr = reg[0];
+
+       if (!of_property_read_u32(node, "assigned-address", &init_dyn_addr)) {
+               if (init_dyn_addr > I3C_MAX_ADDR)
+                       return -EINVAL;
+
+               addrstatus = i3c_bus_get_addr_slot_status(&master->bus,
+                                                         init_dyn_addr);
+               if (addrstatus != I3C_ADDR_SLOT_FREE)
+                       return -EINVAL;
+       }
+
+       boardinfo->pid = ((u64)reg[1] << 32) | reg[2];
+
+       if ((info.pid & GENMASK_ULL(63, 48)) ||
+           I3C_PID_RND_LOWER_32BITS(info.pid))
+               return -EINVAL;
+
+       boardinfo->init_dyn_addr = init_dyn_addr;
+       boardinfo->of_node = of_node_get(node);
+       list_add_tail(&boardinfo->node, &master->boardinfo.i3c);
+
+       return 0;
+}
+
+static int of_i3c_master_add_dev(struct i3c_master_controller *master,
+                                struct device_node *node)
+{
+       u32 reg[3];
+       int ret;
+
+       if (!master || !node)
+               return -EINVAL;
+
+       ret = of_property_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg));
+       if (ret)
+               return ret;
+
+       /*
+        * The manufacturer ID can't be 0. If reg[1] == 0 that means we're
+        * dealing with an I2C device.
+        */
+       if (!reg[1])
+               ret = of_i3c_master_add_i2c_boardinfo(master, node, reg);
+       else
+               ret = of_i3c_master_add_i3c_boardinfo(master, node, reg);
+
+       return ret;
+}
+
+static int of_populate_i3c_bus(struct i3c_master_controller *master)
+{
+       struct device *dev = &master->dev;
+       struct device_node *i3cbus_np = dev->of_node;
+       struct device_node *node;
+       int ret;
+       u32 val;
+
+       if (!i3cbus_np)
+               return 0;
+
+       for_each_available_child_of_node(i3cbus_np, node) {
+               ret = of_i3c_master_add_dev(master, node);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * The user might want to limit I2C and I3C speed in case some devices
+        * on the bus are not supporting typical rates, or if the bus topology
+        * prevents it from using max possible rate.
+        */
+       if (!of_property_read_u32(i3cbus_np, "i2c-scl-hz", &val))
+               master->bus.scl_rate.i2c = val;
+
+       if (!of_property_read_u32(i3cbus_np, "i3c-scl-hz", &val))
+               master->bus.scl_rate.i3c = val;
+
+       return 0;
+}
+
+static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
+                                      struct i2c_msg *xfers, int nxfers)
+{
+       struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
+       struct i2c_dev_desc *dev;
+       int i, ret;
+       u16 addr;
+
+       if (!xfers || !master || nxfers <= 0)
+               return -EINVAL;
+
+       if (!master->ops->i2c_xfers)
+               return -ENOTSUPP;
+
+       /* Doing transfers to different devices is not supported. */
+       addr = xfers[0].addr;
+       for (i = 1; i < nxfers; i++) {
+               if (addr != xfers[i].addr)
+                       return -ENOTSUPP;
+       }
+
+       i3c_bus_normaluse_lock(&master->bus);
+       dev = i3c_master_find_i2c_dev_by_addr(master, addr);
+       if (!dev)
+               ret = -ENOENT;
+       else
+               ret = master->ops->i2c_xfers(dev, xfers, nxfers);
+       i3c_bus_normaluse_unlock(&master->bus);
+
+       return ret ? ret : nxfers;
+}
+
+static u32 i3c_master_i2c_functionalities(struct i2c_adapter *adap)
+{
+       struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
+
+       return master->ops->i2c_funcs(master);
+}
+
+static const struct i2c_algorithm i3c_master_i2c_algo = {
+       .master_xfer = i3c_master_i2c_adapter_xfer,
+       .functionality = i3c_master_i2c_functionalities,
+};
+
+static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
+{
+       struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
+       struct i2c_dev_desc *i2cdev;
+       int ret;
+
+       adap->dev.parent = master->dev.parent;
+       adap->owner = master->dev.parent->driver->owner;
+       adap->algo = &i3c_master_i2c_algo;
+       strncpy(adap->name, dev_name(master->dev.parent), sizeof(adap->name));
+
+       /* FIXME: Should we allow i3c masters to override these values? */
+       adap->timeout = 1000;
+       adap->retries = 3;
+
+       ret = i2c_add_adapter(adap);
+       if (ret)
+               return ret;
+
+       /*
+        * We silently ignore failures here. The bus should keep working
+        * correctly even if one or more i2c devices are not registered.
+        */
+       i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
+               i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
+
+       return 0;
+}
+
+static void i3c_master_i2c_adapter_cleanup(struct i3c_master_controller *master)
+{
+       struct i2c_dev_desc *i2cdev;
+
+       i2c_del_adapter(&master->i2c);
+
+       i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
+               i2cdev->dev = NULL;
+}
+
+static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master)
+{
+       struct i3c_dev_desc *i3cdev;
+
+       i3c_bus_for_each_i3cdev(&master->bus, i3cdev) {
+               if (!i3cdev->dev)
+                       continue;
+
+               i3cdev->dev->desc = NULL;
+               if (device_is_registered(&i3cdev->dev->dev))
+                       device_unregister(&i3cdev->dev->dev);
+               else
+                       put_device(&i3cdev->dev->dev);
+               i3cdev->dev = NULL;
+       }
+}
+
+/**
+ * i3c_master_queue_ibi() - Queue an IBI
+ * @dev: the device this IBI is coming from
+ * @slot: the IBI slot used to store the payload
+ *
+ * Queue an IBI to the controller workqueue. The IBI handler attached to
+ * the dev will be called from a workqueue context.
+ */
+void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot)
+{
+       atomic_inc(&dev->ibi->pending_ibis);
+       queue_work(dev->common.master->wq, &slot->work);
+}
+EXPORT_SYMBOL_GPL(i3c_master_queue_ibi);
+
+static void i3c_master_handle_ibi(struct work_struct *work)
+{
+       struct i3c_ibi_slot *slot = container_of(work, struct i3c_ibi_slot,
+                                                work);
+       struct i3c_dev_desc *dev = slot->dev;
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       struct i3c_ibi_payload payload;
+
+       payload.data = slot->data;
+       payload.len = slot->len;
+
+       if (dev->dev)
+               dev->ibi->handler(dev->dev, &payload);
+
+       master->ops->recycle_ibi_slot(dev, slot);
+       if (atomic_dec_and_test(&dev->ibi->pending_ibis))
+               complete(&dev->ibi->all_ibis_handled);
+}
+
+static void i3c_master_init_ibi_slot(struct i3c_dev_desc *dev,
+                                    struct i3c_ibi_slot *slot)
+{
+       slot->dev = dev;
+       INIT_WORK(&slot->work, i3c_master_handle_ibi);
+}
+
+struct i3c_generic_ibi_slot {
+       struct list_head node;
+       struct i3c_ibi_slot base;
+};
+
+struct i3c_generic_ibi_pool {
+       spinlock_t lock;
+       unsigned int num_slots;
+       struct i3c_generic_ibi_slot *slots;
+       void *payload_buf;
+       struct list_head free_slots;
+       struct list_head pending;
+};
+
+/**
+ * i3c_generic_ibi_free_pool() - Free a generic IBI pool
+ * @pool: the IBI pool to free
+ *
+ * Free all IBI slots allated by a generic IBI pool.
+ */
+void i3c_generic_ibi_free_pool(struct i3c_generic_ibi_pool *pool)
+{
+       struct i3c_generic_ibi_slot *slot;
+       unsigned int nslots = 0;
+
+       while (!list_empty(&pool->free_slots)) {
+               slot = list_first_entry(&pool->free_slots,
+                                       struct i3c_generic_ibi_slot, node);
+               list_del(&slot->node);
+               nslots++;
+       }
+
+       /*
+        * If the number of freed slots is not equal to the number of allocated
+        * slots we have a leak somewhere.
+        */
+       WARN_ON(nslots != pool->num_slots);
+
+       kfree(pool->payload_buf);
+       kfree(pool->slots);
+       kfree(pool);
+}
+EXPORT_SYMBOL_GPL(i3c_generic_ibi_free_pool);
+
+/**
+ * i3c_generic_ibi_alloc_pool() - Create a generic IBI pool
+ * @dev: the device this pool will be used for
+ * @req: IBI setup request describing what the device driver expects
+ *
+ * Create a generic IBI pool based on the information provided in @req.
+ *
+ * Return: a valid IBI pool in case of success, an ERR_PTR() otherwise.
+ */
+struct i3c_generic_ibi_pool *
+i3c_generic_ibi_alloc_pool(struct i3c_dev_desc *dev,
+                          const struct i3c_ibi_setup *req)
+{
+       struct i3c_generic_ibi_pool *pool;
+       struct i3c_generic_ibi_slot *slot;
+       unsigned int i;
+       int ret;
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool)
+               return ERR_PTR(-ENOMEM);
+
+       spin_lock_init(&pool->lock);
+       INIT_LIST_HEAD(&pool->free_slots);
+       INIT_LIST_HEAD(&pool->pending);
+
+       pool->slots = kcalloc(req->num_slots, sizeof(*slot), GFP_KERNEL);
+       if (!pool->slots) {
+               ret = -ENOMEM;
+               goto err_free_pool;
+       }
+
+       if (req->max_payload_len) {
+               pool->payload_buf = kcalloc(req->num_slots,
+                                           req->max_payload_len, GFP_KERNEL);
+               if (!pool->payload_buf) {
+                       ret = -ENOMEM;
+                       goto err_free_pool;
+               }
+       }
+
+       for (i = 0; i < req->num_slots; i++) {
+               slot = &pool->slots[i];
+               i3c_master_init_ibi_slot(dev, &slot->base);
+
+               if (req->max_payload_len)
+                       slot->base.data = pool->payload_buf +
+                                         (i * req->max_payload_len);
+
+               list_add_tail(&slot->node, &pool->free_slots);
+               pool->num_slots++;
+       }
+
+       return pool;
+
+err_free_pool:
+       i3c_generic_ibi_free_pool(pool);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(i3c_generic_ibi_alloc_pool);
+
+/**
+ * i3c_generic_ibi_get_free_slot() - Get a free slot from a generic IBI pool
+ * @pool: the pool to query an IBI slot on
+ *
+ * Search for a free slot in a generic IBI pool.
+ * The slot should be returned to the pool using i3c_generic_ibi_recycle_slot()
+ * when it's no longer needed.
+ *
+ * Return: a pointer to a free slot, or NULL if there's no free slot available.
+ */
+struct i3c_ibi_slot *
+i3c_generic_ibi_get_free_slot(struct i3c_generic_ibi_pool *pool)
+{
+       struct i3c_generic_ibi_slot *slot;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       slot = list_first_entry_or_null(&pool->free_slots,
+                                       struct i3c_generic_ibi_slot, node);
+       if (slot)
+               list_del(&slot->node);
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       return slot ? &slot->base : NULL;
+}
+EXPORT_SYMBOL_GPL(i3c_generic_ibi_get_free_slot);
+
+/**
+ * i3c_generic_ibi_recycle_slot() - Return a slot to a generic IBI pool
+ * @pool: the pool to return the IBI slot to
+ * @s: IBI slot to recycle
+ *
+ * Add an IBI slot back to its generic IBI pool. Should be called from the
+ * master driver struct_master_controller_ops->recycle_ibi() method.
+ */
+void i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool,
+                                 struct i3c_ibi_slot *s)
+{
+       struct i3c_generic_ibi_slot *slot;
+       unsigned long flags;
+
+       if (!s)
+               return;
+
+       slot = container_of(s, struct i3c_generic_ibi_slot, base);
+       spin_lock_irqsave(&pool->lock, flags);
+       list_add_tail(&slot->node, &pool->free_slots);
+       spin_unlock_irqrestore(&pool->lock, flags);
+}
+EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
+
+static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
+{
+       if (!ops || !ops->bus_init || !ops->priv_xfers ||
+           !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers ||
+           !ops->i2c_funcs)
+               return -EINVAL;
+
+       if (ops->request_ibi &&
+           (!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi ||
+            !ops->recycle_ibi_slot))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * i3c_master_register() - register an I3C master
+ * @master: master used to send frames on the bus
+ * @parent: the parent device (the one that provides this I3C master
+ *         controller)
+ * @ops: the master controller operations
+ * @secondary: true if you are registering a secondary master. Will return
+ *            -ENOTSUPP if set to true since secondary masters are not yet
+ *            supported
+ *
+ * This function takes care of everything for you:
+ *
+ * - creates and initializes the I3C bus
+ * - populates the bus with static I2C devs if @parent->of_node is not
+ *   NULL
+ * - registers all I3C devices added by the controller during bus
+ *   initialization
+ * - registers the I2C adapter and all I2C devices
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_master_register(struct i3c_master_controller *master,
+                       struct device *parent,
+                       const struct i3c_master_controller_ops *ops,
+                       bool secondary)
+{
+       struct i3c_bus *i3cbus = i3c_master_get_bus(master);
+       enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
+       struct i2c_dev_boardinfo *i2cbi;
+       int ret;
+
+       /* We do not support secondary masters yet. */
+       if (secondary)
+               return -ENOTSUPP;
+
+       ret = i3c_master_check_ops(ops);
+       if (ret)
+               return ret;
+
+       master->dev.parent = parent;
+       master->dev.of_node = of_node_get(parent->of_node);
+       master->dev.bus = &i3c_bus_type;
+       master->dev.type = &i3c_masterdev_type;
+       master->dev.release = i3c_masterdev_release;
+       master->ops = ops;
+       master->secondary = secondary;
+       INIT_LIST_HEAD(&master->boardinfo.i2c);
+       INIT_LIST_HEAD(&master->boardinfo.i3c);
+
+       ret = i3c_bus_init(i3cbus);
+       if (ret)
+               return ret;
+
+       device_initialize(&master->dev);
+       dev_set_name(&master->dev, "i3c-%d", i3cbus->id);
+
+       ret = of_populate_i3c_bus(master);
+       if (ret)
+               goto err_put_dev;
+
+       list_for_each_entry(i2cbi, &master->boardinfo.i2c, node) {
+               switch (i2cbi->lvr & I3C_LVR_I2C_INDEX_MASK) {
+               case I3C_LVR_I2C_INDEX(0):
+                       if (mode < I3C_BUS_MODE_MIXED_FAST)
+                               mode = I3C_BUS_MODE_MIXED_FAST;
+                       break;
+               case I3C_LVR_I2C_INDEX(1):
+               case I3C_LVR_I2C_INDEX(2):
+                       if (mode < I3C_BUS_MODE_MIXED_SLOW)
+                               mode = I3C_BUS_MODE_MIXED_SLOW;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto err_put_dev;
+               }
+       }
+
+       ret = i3c_bus_set_mode(i3cbus, mode);
+       if (ret)
+               goto err_put_dev;
+
+       master->wq = alloc_workqueue("%s", 0, 0, dev_name(parent));
+       if (!master->wq) {
+               ret = -ENOMEM;
+               goto err_put_dev;
+       }
+
+       ret = i3c_master_bus_init(master);
+       if (ret)
+               goto err_put_dev;
+
+       ret = device_add(&master->dev);
+       if (ret)
+               goto err_cleanup_bus;
+
+       /*
+        * Expose our I3C bus as an I2C adapter so that I2C devices are exposed
+        * through the I2C subsystem.
+        */
+       ret = i3c_master_i2c_adapter_init(master);
+       if (ret)
+               goto err_del_dev;
+
+       /*
+        * We're done initializing the bus and the controller, we can now
+        * register I3C devices dicovered during the initial DAA.
+        */
+       master->init_done = true;
+       i3c_bus_normaluse_lock(&master->bus);
+       i3c_master_register_new_i3c_devs(master);
+       i3c_bus_normaluse_unlock(&master->bus);
+
+       return 0;
+
+err_del_dev:
+       device_del(&master->dev);
+
+err_cleanup_bus:
+       i3c_master_bus_cleanup(master);
+
+err_put_dev:
+       put_device(&master->dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_register);
+
+/**
+ * i3c_master_unregister() - unregister an I3C master
+ * @master: master used to send frames on the bus
+ *
+ * Basically undo everything done in i3c_master_register().
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int i3c_master_unregister(struct i3c_master_controller *master)
+{
+       i3c_master_i2c_adapter_cleanup(master);
+       i3c_master_unregister_i3c_devs(master);
+       i3c_master_bus_cleanup(master);
+       device_unregister(&master->dev);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(i3c_master_unregister);
+
+int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
+                                struct i3c_priv_xfer *xfers,
+                                int nxfers)
+{
+       struct i3c_master_controller *master;
+
+       if (!dev)
+               return -ENOENT;
+
+       master = i3c_dev_get_master(dev);
+       if (!master || !xfers)
+               return -EINVAL;
+
+       if (!master->ops->priv_xfers)
+               return -ENOTSUPP;
+
+       return master->ops->priv_xfers(dev, xfers, nxfers);
+}
+
+int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master;
+       int ret;
+
+       if (!dev->ibi)
+               return -EINVAL;
+
+       master = i3c_dev_get_master(dev);
+       ret = master->ops->disable_ibi(dev);
+       if (ret)
+               return ret;
+
+       reinit_completion(&dev->ibi->all_ibis_handled);
+       if (atomic_read(&dev->ibi->pending_ibis))
+               wait_for_completion(&dev->ibi->all_ibis_handled);
+
+       dev->ibi->enabled = false;
+
+       return 0;
+}
+
+int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       int ret;
+
+       if (!dev->ibi)
+               return -EINVAL;
+
+       ret = master->ops->enable_ibi(dev);
+       if (!ret)
+               dev->ibi->enabled = true;
+
+       return ret;
+}
+
+int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
+                              const struct i3c_ibi_setup *req)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+       struct i3c_device_ibi_info *ibi;
+       int ret;
+
+       if (!master->ops->request_ibi)
+               return -ENOTSUPP;
+
+       if (dev->ibi)
+               return -EBUSY;
+
+       ibi = kzalloc(sizeof(*ibi), GFP_KERNEL);
+       if (!ibi)
+               return -ENOMEM;
+
+       atomic_set(&ibi->pending_ibis, 0);
+       init_completion(&ibi->all_ibis_handled);
+       ibi->handler = req->handler;
+       ibi->max_payload_len = req->max_payload_len;
+       ibi->num_slots = req->num_slots;
+
+       dev->ibi = ibi;
+       ret = master->ops->request_ibi(dev, req);
+       if (ret) {
+               kfree(ibi);
+               dev->ibi = NULL;
+       }
+
+       return ret;
+}
+
+void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+
+       if (!dev->ibi)
+               return;
+
+       if (WARN_ON(dev->ibi->enabled))
+               WARN_ON(i3c_dev_disable_ibi_locked(dev));
+
+       master->ops->free_ibi(dev);
+       kfree(dev->ibi);
+       dev->ibi = NULL;
+}
+
+static int __init i3c_init(void)
+{
+       return bus_register(&i3c_bus_type);
+}
+subsys_initcall(i3c_init);
+
+static void __exit i3c_exit(void)
+{
+       idr_destroy(&i3c_bus_idr);
+       bus_unregister(&i3c_bus_type);
+}
+module_exit(i3c_exit);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
+MODULE_DESCRIPTION("I3C core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig
new file mode 100644 (file)
index 0000000..26c6b58
--- /dev/null
@@ -0,0 +1,22 @@
+config CDNS_I3C_MASTER
+       tristate "Cadence I3C master driver"
+       depends on I3C
+       depends on HAS_IOMEM
+       depends on !(ALPHA || PARISC)
+       help
+         Enable this driver if you want to support Cadence I3C master block.
+
+config DW_I3C_MASTER
+       tristate "Synospsys DesignWare I3C master driver"
+       depends on I3C
+       depends on HAS_IOMEM
+       depends on !(ALPHA || PARISC)
+       # ALPHA and PARISC needs {read,write}sl()
+       help
+         Support for Synopsys DesignWare MIPI I3C Controller.
+
+         For details please see
+         https://www.synopsys.com/dw/ipdir.php?ds=mipi_i3c
+
+         This driver can also be built as a module.  If so, the module
+         will be called dw-i3c-master.
diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile
new file mode 100644 (file)
index 0000000..fc53939
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CDNS_I3C_MASTER)          += i3c-master-cdns.o
+obj-$(CONFIG_DW_I3C_MASTER)            += dw-i3c-master.o
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
new file mode 100644 (file)
index 0000000..b532e2c
--- /dev/null
@@ -0,0 +1,1216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+ *
+ * Author: Vitor Soares <vitor.soares@synopsys.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i3c/master.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#define DEVICE_CTRL                    0x0
+#define DEV_CTRL_ENABLE                        BIT(31)
+#define DEV_CTRL_RESUME                        BIT(30)
+#define DEV_CTRL_HOT_JOIN_NACK         BIT(8)
+#define DEV_CTRL_I2C_SLAVE_PRESENT     BIT(7)
+
+#define DEVICE_ADDR                    0x4
+#define DEV_ADDR_DYNAMIC_ADDR_VALID    BIT(31)
+#define DEV_ADDR_DYNAMIC(x)            (((x) << 16) & GENMASK(22, 16))
+
+#define HW_CAPABILITY                  0x8
+#define COMMAND_QUEUE_PORT             0xc
+#define COMMAND_PORT_TOC               BIT(30)
+#define COMMAND_PORT_READ_TRANSFER     BIT(28)
+#define COMMAND_PORT_SDAP              BIT(27)
+#define COMMAND_PORT_ROC               BIT(26)
+#define COMMAND_PORT_SPEED(x)          (((x) << 21) & GENMASK(23, 21))
+#define COMMAND_PORT_DEV_INDEX(x)      (((x) << 16) & GENMASK(20, 16))
+#define COMMAND_PORT_CP                        BIT(15)
+#define COMMAND_PORT_CMD(x)            (((x) << 7) & GENMASK(14, 7))
+#define COMMAND_PORT_TID(x)            (((x) << 3) & GENMASK(6, 3))
+
+#define COMMAND_PORT_ARG_DATA_LEN(x)   (((x) << 16) & GENMASK(31, 16))
+#define COMMAND_PORT_ARG_DATA_LEN_MAX  65536
+#define COMMAND_PORT_TRANSFER_ARG      0x01
+
+#define COMMAND_PORT_SDA_DATA_BYTE_3(x)        (((x) << 24) & GENMASK(31, 24))
+#define COMMAND_PORT_SDA_DATA_BYTE_2(x)        (((x) << 16) & GENMASK(23, 16))
+#define COMMAND_PORT_SDA_DATA_BYTE_1(x)        (((x) << 8) & GENMASK(15, 8))
+#define COMMAND_PORT_SDA_BYTE_STRB_3   BIT(5)
+#define COMMAND_PORT_SDA_BYTE_STRB_2   BIT(4)
+#define COMMAND_PORT_SDA_BYTE_STRB_1   BIT(3)
+#define COMMAND_PORT_SHORT_DATA_ARG    0x02
+
+#define COMMAND_PORT_DEV_COUNT(x)      (((x) << 21) & GENMASK(25, 21))
+#define COMMAND_PORT_ADDR_ASSGN_CMD    0x03
+
+#define RESPONSE_QUEUE_PORT            0x10
+#define RESPONSE_PORT_ERR_STATUS(x)    (((x) & GENMASK(31, 28)) >> 28)
+#define RESPONSE_NO_ERROR              0
+#define RESPONSE_ERROR_CRC             1
+#define RESPONSE_ERROR_PARITY          2
+#define RESPONSE_ERROR_FRAME           3
+#define RESPONSE_ERROR_IBA_NACK                4
+#define RESPONSE_ERROR_ADDRESS_NACK    5
+#define RESPONSE_ERROR_OVER_UNDER_FLOW 6
+#define RESPONSE_ERROR_TRANSF_ABORT    8
+#define RESPONSE_ERROR_I2C_W_NACK_ERR  9
+#define RESPONSE_PORT_TID(x)           (((x) & GENMASK(27, 24)) >> 24)
+#define RESPONSE_PORT_DATA_LEN(x)      ((x) & GENMASK(15, 0))
+
+#define RX_TX_DATA_PORT                        0x14
+#define IBI_QUEUE_STATUS               0x18
+#define QUEUE_THLD_CTRL                        0x1c
+#define QUEUE_THLD_CTRL_RESP_BUF_MASK  GENMASK(15, 8)
+#define QUEUE_THLD_CTRL_RESP_BUF(x)    (((x) - 1) << 8)
+
+#define DATA_BUFFER_THLD_CTRL          0x20
+#define DATA_BUFFER_THLD_CTRL_RX_BUF   GENMASK(11, 8)
+
+#define IBI_QUEUE_CTRL                 0x24
+#define IBI_MR_REQ_REJECT              0x2C
+#define IBI_SIR_REQ_REJECT             0x30
+#define IBI_REQ_REJECT_ALL             GENMASK(31, 0)
+
+#define RESET_CTRL                     0x34
+#define RESET_CTRL_IBI_QUEUE           BIT(5)
+#define RESET_CTRL_RX_FIFO             BIT(4)
+#define RESET_CTRL_TX_FIFO             BIT(3)
+#define RESET_CTRL_RESP_QUEUE          BIT(2)
+#define RESET_CTRL_CMD_QUEUE           BIT(1)
+#define RESET_CTRL_SOFT                        BIT(0)
+
+#define SLV_EVENT_CTRL                 0x38
+#define INTR_STATUS                    0x3c
+#define INTR_STATUS_EN                 0x40
+#define INTR_SIGNAL_EN                 0x44
+#define INTR_FORCE                     0x48
+#define INTR_BUSOWNER_UPDATE_STAT      BIT(13)
+#define INTR_IBI_UPDATED_STAT          BIT(12)
+#define INTR_READ_REQ_RECV_STAT                BIT(11)
+#define INTR_DEFSLV_STAT               BIT(10)
+#define INTR_TRANSFER_ERR_STAT         BIT(9)
+#define INTR_DYN_ADDR_ASSGN_STAT       BIT(8)
+#define INTR_CCC_UPDATED_STAT          BIT(6)
+#define INTR_TRANSFER_ABORT_STAT       BIT(5)
+#define INTR_RESP_READY_STAT           BIT(4)
+#define INTR_CMD_QUEUE_READY_STAT      BIT(3)
+#define INTR_IBI_THLD_STAT             BIT(2)
+#define INTR_RX_THLD_STAT              BIT(1)
+#define INTR_TX_THLD_STAT              BIT(0)
+#define INTR_ALL                       (INTR_BUSOWNER_UPDATE_STAT |    \
+                                       INTR_IBI_UPDATED_STAT |         \
+                                       INTR_READ_REQ_RECV_STAT |       \
+                                       INTR_DEFSLV_STAT |              \
+                                       INTR_TRANSFER_ERR_STAT |        \
+                                       INTR_DYN_ADDR_ASSGN_STAT |      \
+                                       INTR_CCC_UPDATED_STAT |         \
+                                       INTR_TRANSFER_ABORT_STAT |      \
+                                       INTR_RESP_READY_STAT |          \
+                                       INTR_CMD_QUEUE_READY_STAT |     \
+                                       INTR_IBI_THLD_STAT |            \
+                                       INTR_TX_THLD_STAT |             \
+                                       INTR_RX_THLD_STAT)
+
+#define INTR_MASTER_MASK               (INTR_TRANSFER_ERR_STAT |       \
+                                        INTR_RESP_READY_STAT)
+
+#define QUEUE_STATUS_LEVEL             0x4c
+#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24)
+#define QUEUE_STATUS_IBI_BUF_BLR(x)    (((x) & GENMASK(23, 16)) >> 16)
+#define QUEUE_STATUS_LEVEL_RESP(x)     (((x) & GENMASK(15, 8)) >> 8)
+#define QUEUE_STATUS_LEVEL_CMD(x)      ((x) & GENMASK(7, 0))
+
+#define DATA_BUFFER_STATUS_LEVEL       0x50
+#define DATA_BUFFER_STATUS_LEVEL_TX(x) ((x) & GENMASK(7, 0))
+
+#define PRESENT_STATE                  0x54
+#define CCC_DEVICE_STATUS              0x58
+#define DEVICE_ADDR_TABLE_POINTER      0x5c
+#define DEVICE_ADDR_TABLE_DEPTH(x)     (((x) & GENMASK(31, 16)) >> 16)
+#define DEVICE_ADDR_TABLE_ADDR(x)      ((x) & GENMASK(7, 0))
+
+#define DEV_CHAR_TABLE_POINTER         0x60
+#define VENDOR_SPECIFIC_REG_POINTER    0x6c
+#define SLV_PID_VALUE                  0x74
+#define SLV_CHAR_CTRL                  0x78
+#define SLV_MAX_LEN                    0x7c
+#define MAX_READ_TURNAROUND            0x80
+#define MAX_DATA_SPEED                 0x84
+#define SLV_DEBUG_STATUS               0x88
+#define SLV_INTR_REQ                   0x8c
+#define DEVICE_CTRL_EXTENDED           0xb0
+#define SCL_I3C_OD_TIMING              0xb4
+#define SCL_I3C_PP_TIMING              0xb8
+#define SCL_I3C_TIMING_HCNT(x)         (((x) << 16) & GENMASK(23, 16))
+#define SCL_I3C_TIMING_LCNT(x)         ((x) & GENMASK(7, 0))
+#define SCL_I3C_TIMING_CNT_MIN         5
+
+#define SCL_I2C_FM_TIMING              0xbc
+#define SCL_I2C_FM_TIMING_HCNT(x)      (((x) << 16) & GENMASK(31, 16))
+#define SCL_I2C_FM_TIMING_LCNT(x)      ((x) & GENMASK(15, 0))
+
+#define SCL_I2C_FMP_TIMING             0xc0
+#define SCL_I2C_FMP_TIMING_HCNT(x)     (((x) << 16) & GENMASK(23, 16))
+#define SCL_I2C_FMP_TIMING_LCNT(x)     ((x) & GENMASK(15, 0))
+
+#define SCL_EXT_LCNT_TIMING            0xc8
+#define SCL_EXT_LCNT_4(x)              (((x) << 24) & GENMASK(31, 24))
+#define SCL_EXT_LCNT_3(x)              (((x) << 16) & GENMASK(23, 16))
+#define SCL_EXT_LCNT_2(x)              (((x) << 8) & GENMASK(15, 8))
+#define SCL_EXT_LCNT_1(x)              ((x) & GENMASK(7, 0))
+
+#define SCL_EXT_TERMN_LCNT_TIMING      0xcc
+#define BUS_FREE_TIMING                        0xd4
+#define BUS_I3C_MST_FREE(x)            ((x) & GENMASK(15, 0))
+
+#define BUS_IDLE_TIMING                        0xd8
+#define I3C_VER_ID                     0xe0
+#define I3C_VER_TYPE                   0xe4
+#define EXTENDED_CAPABILITY            0xe8
+#define SLAVE_CONFIG                   0xec
+
+#define DEV_ADDR_TABLE_LEGACY_I2C_DEV  BIT(31)
+#define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16))
+#define DEV_ADDR_TABLE_STATIC_ADDR(x)  ((x) & GENMASK(6, 0))
+#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2))
+
+#define MAX_DEVS 32
+
+#define I3C_BUS_SDR1_SCL_RATE          8000000
+#define I3C_BUS_SDR2_SCL_RATE          6000000
+#define I3C_BUS_SDR3_SCL_RATE          4000000
+#define I3C_BUS_SDR4_SCL_RATE          2000000
+#define I3C_BUS_I2C_FM_TLOW_MIN_NS     1300
+#define I3C_BUS_I2C_FMP_TLOW_MIN_NS    500
+#define I3C_BUS_THIGH_MAX_NS           41
+
+#define XFER_TIMEOUT (msecs_to_jiffies(1000))
+
+struct dw_i3c_master_caps {
+       u8 cmdfifodepth;
+       u8 datafifodepth;
+};
+
+struct dw_i3c_cmd {
+       u32 cmd_lo;
+       u32 cmd_hi;
+       u16 tx_len;
+       const void *tx_buf;
+       u16 rx_len;
+       void *rx_buf;
+       u8 error;
+};
+
+struct dw_i3c_xfer {
+       struct list_head node;
+       struct completion comp;
+       int ret;
+       unsigned int ncmds;
+       struct dw_i3c_cmd cmds[0];
+};
+
+struct dw_i3c_master {
+       struct i3c_master_controller base;
+       u16 maxdevs;
+       u16 datstartaddr;
+       u32 free_pos;
+       struct {
+               struct list_head list;
+               struct dw_i3c_xfer *cur;
+               spinlock_t lock;
+       } xferqueue;
+       struct dw_i3c_master_caps caps;
+       void __iomem *regs;
+       struct reset_control *core_rst;
+       struct clk *core_clk;
+       char version[5];
+       char type[5];
+       u8 addrs[MAX_DEVS];
+};
+
+struct dw_i3c_i2c_dev_data {
+       u8 index;
+};
+
+static u8 even_parity(u8 p)
+{
+       p ^= p >> 4;
+       p &= 0xf;
+
+       return (0x9669 >> p) & 1;
+}
+
+static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
+                                          const struct i3c_ccc_cmd *cmd)
+{
+       if (cmd->ndests > 1)
+               return false;
+
+       switch (cmd->id) {
+       case I3C_CCC_ENEC(true):
+       case I3C_CCC_ENEC(false):
+       case I3C_CCC_DISEC(true):
+       case I3C_CCC_DISEC(false):
+       case I3C_CCC_ENTAS(0, true):
+       case I3C_CCC_ENTAS(0, false):
+       case I3C_CCC_RSTDAA(true):
+       case I3C_CCC_RSTDAA(false):
+       case I3C_CCC_ENTDAA:
+       case I3C_CCC_SETMWL(true):
+       case I3C_CCC_SETMWL(false):
+       case I3C_CCC_SETMRL(true):
+       case I3C_CCC_SETMRL(false):
+       case I3C_CCC_ENTHDR(0):
+       case I3C_CCC_SETDASA:
+       case I3C_CCC_SETNEWDA:
+       case I3C_CCC_GETMWL:
+       case I3C_CCC_GETMRL:
+       case I3C_CCC_GETPID:
+       case I3C_CCC_GETBCR:
+       case I3C_CCC_GETDCR:
+       case I3C_CCC_GETSTATUS:
+       case I3C_CCC_GETMXDS:
+       case I3C_CCC_GETHDRCAP:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static inline struct dw_i3c_master *
+to_dw_i3c_master(struct i3c_master_controller *master)
+{
+       return container_of(master, struct dw_i3c_master, base);
+}
+
+static void dw_i3c_master_disable(struct dw_i3c_master *master)
+{
+       writel(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_ENABLE,
+              master->regs + DEVICE_CTRL);
+}
+
+static void dw_i3c_master_enable(struct dw_i3c_master *master)
+{
+       writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_ENABLE,
+              master->regs + DEVICE_CTRL);
+}
+
+static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr)
+{
+       int pos;
+
+       for (pos = 0; pos < master->maxdevs; pos++) {
+               if (addr == master->addrs[pos])
+                       return pos;
+       }
+
+       return -EINVAL;
+}
+
+static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
+{
+       if (!(master->free_pos & GENMASK(master->maxdevs - 1, 0)))
+               return -ENOSPC;
+
+       return ffs(master->free_pos) - 1;
+}
+
+static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
+                                    const u8 *bytes, int nbytes)
+{
+       writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
+       if (nbytes & 3) {
+               u32 tmp = 0;
+
+               memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
+               writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
+       }
+}
+
+static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master,
+                                      u8 *bytes, int nbytes)
+{
+       readsl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
+       if (nbytes & 3) {
+               u32 tmp;
+
+               readsl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
+               memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
+       }
+}
+
+static struct dw_i3c_xfer *
+dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds)
+{
+       struct dw_i3c_xfer *xfer;
+
+       xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
+       if (!xfer)
+               return NULL;
+
+       INIT_LIST_HEAD(&xfer->node);
+       xfer->ncmds = ncmds;
+       xfer->ret = -ETIMEDOUT;
+
+       return xfer;
+}
+
+static void dw_i3c_master_free_xfer(struct dw_i3c_xfer *xfer)
+{
+       kfree(xfer);
+}
+
+static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
+{
+       struct dw_i3c_xfer *xfer = master->xferqueue.cur;
+       unsigned int i;
+       u32 thld_ctrl;
+
+       if (!xfer)
+               return;
+
+       for (i = 0; i < xfer->ncmds; i++) {
+               struct dw_i3c_cmd *cmd = &xfer->cmds[i];
+
+               dw_i3c_master_wr_tx_fifo(master, cmd->tx_buf, cmd->tx_len);
+       }
+
+       thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+       thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK;
+       thld_ctrl |= QUEUE_THLD_CTRL_RESP_BUF(xfer->ncmds);
+       writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+
+       for (i = 0; i < xfer->ncmds; i++) {
+               struct dw_i3c_cmd *cmd = &xfer->cmds[i];
+
+               writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT);
+               writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT);
+       }
+}
+
+static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master,
+                                      struct dw_i3c_xfer *xfer)
+{
+       unsigned long flags;
+
+       init_completion(&xfer->comp);
+       spin_lock_irqsave(&master->xferqueue.lock, flags);
+       if (master->xferqueue.cur) {
+               list_add_tail(&xfer->node, &master->xferqueue.list);
+       } else {
+               master->xferqueue.cur = xfer;
+               dw_i3c_master_start_xfer_locked(master);
+       }
+       spin_unlock_irqrestore(&master->xferqueue.lock, flags);
+}
+
+static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master,
+                                      struct dw_i3c_xfer *xfer)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->xferqueue.lock, flags);
+       if (master->xferqueue.cur == xfer) {
+               u32 status;
+
+               master->xferqueue.cur = NULL;
+
+               writel(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO |
+                      RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE,
+                      master->regs + RESET_CTRL);
+
+               readl_poll_timeout_atomic(master->regs + RESET_CTRL, status,
+                                         !status, 10, 1000000);
+       } else {
+               list_del_init(&xfer->node);
+       }
+       spin_unlock_irqrestore(&master->xferqueue.lock, flags);
+}
+
+static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr)
+{
+       struct dw_i3c_xfer *xfer = master->xferqueue.cur;
+       int i, ret = 0;
+       u32 nresp;
+
+       if (!xfer)
+               return;
+
+       nresp = readl(master->regs + QUEUE_STATUS_LEVEL);
+       nresp = QUEUE_STATUS_LEVEL_RESP(nresp);
+
+       for (i = 0; i < nresp; i++) {
+               struct dw_i3c_cmd *cmd;
+               u32 resp;
+
+               resp = readl(master->regs + RESPONSE_QUEUE_PORT);
+
+               cmd = &xfer->cmds[RESPONSE_PORT_TID(resp)];
+               cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp);
+               cmd->error = RESPONSE_PORT_ERR_STATUS(resp);
+               if (cmd->rx_len && !cmd->error)
+                       dw_i3c_master_read_rx_fifo(master, cmd->rx_buf,
+                                                  cmd->rx_len);
+       }
+
+       for (i = 0; i < nresp; i++) {
+               switch (xfer->cmds[i].error) {
+               case RESPONSE_NO_ERROR:
+                       break;
+               case RESPONSE_ERROR_PARITY:
+               case RESPONSE_ERROR_IBA_NACK:
+               case RESPONSE_ERROR_TRANSF_ABORT:
+               case RESPONSE_ERROR_CRC:
+               case RESPONSE_ERROR_FRAME:
+                       ret = -EIO;
+                       break;
+               case RESPONSE_ERROR_OVER_UNDER_FLOW:
+                       ret = -ENOSPC;
+                       break;
+               case RESPONSE_ERROR_I2C_W_NACK_ERR:
+               case RESPONSE_ERROR_ADDRESS_NACK:
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       xfer->ret = ret;
+       complete(&xfer->comp);
+
+       if (ret < 0) {
+               dw_i3c_master_dequeue_xfer(master, xfer);
+               writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME,
+                      master->regs + DEVICE_CTRL);
+       }
+
+       xfer = list_first_entry_or_null(&master->xferqueue.list,
+                                       struct dw_i3c_xfer,
+                                       node);
+       if (xfer)
+               list_del_init(&xfer->node);
+
+       master->xferqueue.cur = xfer;
+       dw_i3c_master_start_xfer_locked(master);
+}
+
+static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
+{
+       unsigned long core_rate, core_period;
+       u32 scl_timing;
+       u8 hcnt, lcnt;
+
+       core_rate = clk_get_rate(master->core_clk);
+       if (!core_rate)
+               return -EINVAL;
+
+       core_period = DIV_ROUND_UP(1000000000, core_rate);
+
+       hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1;
+       if (hcnt < SCL_I3C_TIMING_CNT_MIN)
+               hcnt = SCL_I3C_TIMING_CNT_MIN;
+
+       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_TYP_I3C_SCL_RATE) - hcnt;
+       if (lcnt < SCL_I3C_TIMING_CNT_MIN)
+               lcnt = SCL_I3C_TIMING_CNT_MIN;
+
+       scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
+       writel(scl_timing, master->regs + SCL_I3C_PP_TIMING);
+
+       if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
+               writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
+
+       lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
+       scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
+       writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
+
+       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt;
+       scl_timing = SCL_EXT_LCNT_1(lcnt);
+       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt;
+       scl_timing |= SCL_EXT_LCNT_2(lcnt);
+       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt;
+       scl_timing |= SCL_EXT_LCNT_3(lcnt);
+       lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt;
+       scl_timing |= SCL_EXT_LCNT_4(lcnt);
+       writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING);
+
+       return 0;
+}
+
+static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
+{
+       unsigned long core_rate, core_period;
+       u16 hcnt, lcnt;
+       u32 scl_timing;
+
+       core_rate = clk_get_rate(master->core_clk);
+       if (!core_rate)
+               return -EINVAL;
+
+       core_period = DIV_ROUND_UP(1000000000, core_rate);
+
+       lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period);
+       hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
+       scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) |
+                    SCL_I2C_FMP_TIMING_LCNT(lcnt);
+       writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING);
+
+       lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period);
+       hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
+       scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) |
+                    SCL_I2C_FM_TIMING_LCNT(lcnt);
+       writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
+
+       writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
+       writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT,
+              master->regs + DEVICE_CTRL);
+
+       return 0;
+}
+
+static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
+{
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       struct i3c_bus *bus = i3c_master_get_bus(m);
+       struct i3c_device_info info = { };
+       u32 thld_ctrl;
+       int ret;
+
+       switch (bus->mode) {
+       case I3C_BUS_MODE_MIXED_FAST:
+               ret = dw_i2c_clk_cfg(master);
+               if (ret)
+                       return ret;
+       case I3C_BUS_MODE_PURE:
+               ret = dw_i3c_clk_cfg(master);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+       thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK;
+       writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+
+       thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL);
+       thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF;
+       writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL);
+
+       writel(INTR_ALL, master->regs + INTR_STATUS);
+       writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
+       writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
+
+       ret = i3c_master_get_free_addr(m, 0);
+       if (ret < 0)
+               return ret;
+
+       writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
+              master->regs + DEVICE_ADDR);
+
+       memset(&info, 0, sizeof(info));
+       info.dyn_addr = ret;
+
+       ret = i3c_master_set_info(&master->base, &info);
+       if (ret)
+               return ret;
+
+       writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
+       writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
+
+       /* For now don't support Hot-Join */
+       writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
+              master->regs + DEVICE_CTRL);
+
+       dw_i3c_master_enable(master);
+
+       return 0;
+}
+
+static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m)
+{
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+
+       dw_i3c_master_disable(master);
+}
+
+static int dw_i3c_ccc_set(struct dw_i3c_master *master,
+                         struct i3c_ccc_cmd *ccc)
+{
+       struct dw_i3c_xfer *xfer;
+       struct dw_i3c_cmd *cmd;
+       int ret, pos = 0;
+
+       if (ccc->id & I3C_CCC_DIRECT) {
+               pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr);
+               if (pos < 0)
+                       return pos;
+       }
+
+       xfer = dw_i3c_master_alloc_xfer(master, 1);
+       if (!xfer)
+               return -ENOMEM;
+
+       cmd = xfer->cmds;
+       cmd->tx_buf = ccc->dests[0].payload.data;
+       cmd->tx_len = ccc->dests[0].payload.len;
+
+       cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
+                     COMMAND_PORT_TRANSFER_ARG;
+
+       cmd->cmd_lo = COMMAND_PORT_CP |
+                     COMMAND_PORT_DEV_INDEX(pos) |
+                     COMMAND_PORT_CMD(ccc->id) |
+                     COMMAND_PORT_TOC |
+                     COMMAND_PORT_ROC;
+
+       dw_i3c_master_enqueue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+               dw_i3c_master_dequeue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
+               ccc->err = I3C_ERROR_M2;
+
+       dw_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
+{
+       struct dw_i3c_xfer *xfer;
+       struct dw_i3c_cmd *cmd;
+       int ret, pos;
+
+       pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr);
+       if (pos < 0)
+               return pos;
+
+       xfer = dw_i3c_master_alloc_xfer(master, 1);
+       if (!xfer)
+               return -ENOMEM;
+
+       cmd = xfer->cmds;
+       cmd->rx_buf = ccc->dests[0].payload.data;
+       cmd->rx_len = ccc->dests[0].payload.len;
+
+       cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
+                     COMMAND_PORT_TRANSFER_ARG;
+
+       cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER |
+                     COMMAND_PORT_CP |
+                     COMMAND_PORT_DEV_INDEX(pos) |
+                     COMMAND_PORT_CMD(ccc->id) |
+                     COMMAND_PORT_TOC |
+                     COMMAND_PORT_ROC;
+
+       dw_i3c_master_enqueue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+               dw_i3c_master_dequeue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
+               ccc->err = I3C_ERROR_M2;
+       dw_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
+                                     struct i3c_ccc_cmd *ccc)
+{
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       int ret = 0;
+
+       if (ccc->id == I3C_CCC_ENTDAA)
+               return -EINVAL;
+
+       if (ccc->rnw)
+               ret = dw_i3c_ccc_get(master, ccc);
+       else
+               ret = dw_i3c_ccc_set(master, ccc);
+
+       return ret;
+}
+
+static int dw_i3c_master_daa(struct i3c_master_controller *m)
+{
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       struct dw_i3c_xfer *xfer;
+       struct dw_i3c_cmd *cmd;
+       u32 olddevs, newdevs;
+       u8 p, last_addr = 0;
+       int ret, pos;
+
+       olddevs = ~(master->free_pos);
+
+       /* Prepare DAT before launching DAA. */
+       for (pos = 0; pos < master->maxdevs; pos++) {
+               if (olddevs & BIT(pos))
+                       continue;
+
+               ret = i3c_master_get_free_addr(m, last_addr + 1);
+               if (ret < 0)
+                       return -ENOSPC;
+
+               master->addrs[pos] = ret;
+               p = even_parity(ret);
+               last_addr = ret;
+               ret |= (p << 7);
+
+               writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret),
+                      master->regs +
+                      DEV_ADDR_TABLE_LOC(master->datstartaddr, pos));
+       }
+
+       xfer = dw_i3c_master_alloc_xfer(master, 1);
+       if (!xfer)
+               return -ENOMEM;
+
+       pos = dw_i3c_master_get_free_pos(master);
+       cmd = &xfer->cmds[0];
+       cmd->cmd_hi = 0x1;
+       cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) |
+                     COMMAND_PORT_DEV_INDEX(pos) |
+                     COMMAND_PORT_CMD(I3C_CCC_ENTDAA) |
+                     COMMAND_PORT_ADDR_ASSGN_CMD |
+                     COMMAND_PORT_TOC |
+                     COMMAND_PORT_ROC;
+
+       dw_i3c_master_enqueue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+               dw_i3c_master_dequeue_xfer(master, xfer);
+
+       newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0);
+       newdevs &= ~olddevs;
+
+       for (pos = 0; pos < master->maxdevs; pos++) {
+               if (newdevs & BIT(pos))
+                       i3c_master_add_i3c_dev_locked(m, master->addrs[pos]);
+       }
+
+       dw_i3c_master_free_xfer(xfer);
+
+       i3c_master_disec_locked(m, I3C_BROADCAST_ADDR,
+                               I3C_CCC_EVENT_HJ |
+                               I3C_CCC_EVENT_MR |
+                               I3C_CCC_EVENT_SIR);
+
+       return 0;
+}
+
+static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
+                                   struct i3c_priv_xfer *i3c_xfers,
+                                   int i3c_nxfers)
+{
+       struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       unsigned int nrxwords = 0, ntxwords = 0;
+       struct dw_i3c_xfer *xfer;
+       int i, ret = 0;
+
+       if (!i3c_nxfers)
+               return 0;
+
+       if (i3c_nxfers > master->caps.cmdfifodepth)
+               return -ENOTSUPP;
+
+       for (i = 0; i < i3c_nxfers; i++) {
+               if (i3c_xfers[i].len > COMMAND_PORT_ARG_DATA_LEN_MAX)
+                       return -ENOTSUPP;
+       }
+
+       for (i = 0; i < i3c_nxfers; i++) {
+               if (i3c_xfers[i].rnw)
+                       nrxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4);
+               else
+                       ntxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4);
+       }
+
+       if (ntxwords > master->caps.datafifodepth ||
+           nrxwords > master->caps.datafifodepth)
+               return -ENOTSUPP;
+
+       xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
+       if (!xfer)
+               return -ENOMEM;
+
+       for (i = 0; i < i3c_nxfers; i++) {
+               struct dw_i3c_cmd *cmd = &xfer->cmds[i];
+
+               cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) |
+                       COMMAND_PORT_TRANSFER_ARG;
+
+               if (i3c_xfers[i].rnw) {
+                       cmd->rx_buf = i3c_xfers[i].data.in;
+                       cmd->rx_len = i3c_xfers[i].len;
+                       cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER |
+                                     COMMAND_PORT_SPEED(dev->info.max_read_ds);
+
+               } else {
+                       cmd->tx_buf = i3c_xfers[i].data.out;
+                       cmd->tx_len = i3c_xfers[i].len;
+                       cmd->cmd_lo =
+                               COMMAND_PORT_SPEED(dev->info.max_write_ds);
+               }
+
+               cmd->cmd_lo |= COMMAND_PORT_TID(i) |
+                              COMMAND_PORT_DEV_INDEX(data->index) |
+                              COMMAND_PORT_ROC;
+
+               if (i == (i3c_nxfers - 1))
+                       cmd->cmd_lo |= COMMAND_PORT_TOC;
+       }
+
+       dw_i3c_master_enqueue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+               dw_i3c_master_dequeue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       dw_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
+                                         u8 old_dyn_addr)
+{
+       struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+
+       writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr),
+              master->regs +
+              DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+
+       if (!old_dyn_addr)
+               return 0;
+
+       master->addrs[data->index] = dev->info.dyn_addr;
+
+       return 0;
+}
+
+static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       struct dw_i3c_i2c_dev_data *data;
+       int pos;
+
+       pos = dw_i3c_master_get_free_pos(master);
+       if (pos < 0)
+               return pos;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->index = pos;
+       master->addrs[pos] = dev->info.dyn_addr;
+       master->free_pos &= ~BIT(pos);
+       i3c_dev_set_master_data(dev, data);
+
+       writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr),
+              master->regs +
+              DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+
+       return 0;
+}
+
+static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+       struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+
+       writel(0,
+              master->regs +
+              DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+
+       i3c_dev_set_master_data(dev, NULL);
+       master->addrs[data->index] = 0;
+       master->free_pos |= BIT(data->index);
+       kfree(data);
+}
+
+static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
+                                  const struct i2c_msg *i2c_xfers,
+                                  int i2c_nxfers)
+{
+       struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       unsigned int nrxwords = 0, ntxwords = 0;
+       struct dw_i3c_xfer *xfer;
+       int i, ret = 0;
+
+       if (!i2c_nxfers)
+               return 0;
+
+       if (i2c_nxfers > master->caps.cmdfifodepth)
+               return -ENOTSUPP;
+
+       for (i = 0; i < i2c_nxfers; i++) {
+               if (i2c_xfers[i].len > COMMAND_PORT_ARG_DATA_LEN_MAX)
+                       return -ENOTSUPP;
+       }
+
+       for (i = 0; i < i2c_nxfers; i++) {
+               if (i2c_xfers[i].flags & I2C_M_RD)
+                       nrxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4);
+               else
+                       ntxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4);
+       }
+
+       if (ntxwords > master->caps.datafifodepth ||
+           nrxwords > master->caps.datafifodepth)
+               return -ENOTSUPP;
+
+       xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
+       if (!xfer)
+               return -ENOMEM;
+
+       for (i = 0; i < i2c_nxfers; i++) {
+               struct dw_i3c_cmd *cmd = &xfer->cmds[i];
+
+               cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) |
+                       COMMAND_PORT_TRANSFER_ARG;
+
+               cmd->cmd_lo = COMMAND_PORT_TID(i) |
+                             COMMAND_PORT_DEV_INDEX(data->index) |
+                             COMMAND_PORT_ROC;
+
+               if (i2c_xfers[i].flags & I2C_M_RD) {
+                       cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER;
+                       cmd->rx_buf = i2c_xfers[i].buf;
+                       cmd->rx_len = i2c_xfers[i].len;
+               } else {
+                       cmd->tx_buf = i2c_xfers[i].buf;
+                       cmd->tx_len = i2c_xfers[i].len;
+               }
+
+               if (i == (i2c_nxfers - 1))
+                       cmd->cmd_lo |= COMMAND_PORT_TOC;
+       }
+
+       dw_i3c_master_enqueue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+               dw_i3c_master_dequeue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       dw_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+       struct dw_i3c_i2c_dev_data *data;
+       int pos;
+
+       pos = dw_i3c_master_get_free_pos(master);
+       if (pos < 0)
+               return pos;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->index = pos;
+       master->addrs[pos] = dev->boardinfo->base.addr;
+       master->free_pos &= ~BIT(pos);
+       i2c_dev_set_master_data(dev, data);
+
+       writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV |
+              DEV_ADDR_TABLE_STATIC_ADDR(dev->boardinfo->base.addr),
+              master->regs +
+              DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+
+       return 0;
+}
+
+static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
+{
+       struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct dw_i3c_master *master = to_dw_i3c_master(m);
+
+       writel(0,
+              master->regs +
+              DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+
+       i2c_dev_set_master_data(dev, NULL);
+       master->addrs[data->index] = 0;
+       master->free_pos |= BIT(data->index);
+       kfree(data);
+}
+
+static u32 dw_i3c_master_i2c_funcs(struct i3c_master_controller *m)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
+{
+       struct dw_i3c_master *master = dev_id;
+       u32 status;
+
+       status = readl(master->regs + INTR_STATUS);
+
+       if (!(status & readl(master->regs + INTR_STATUS_EN))) {
+               writel(INTR_ALL, master->regs + INTR_STATUS);
+               return IRQ_NONE;
+       }
+
+       spin_lock(&master->xferqueue.lock);
+       dw_i3c_master_end_xfer_locked(master, status);
+       if (status & INTR_TRANSFER_ERR_STAT)
+               writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS);
+       spin_unlock(&master->xferqueue.lock);
+
+       return IRQ_HANDLED;
+}
+
+static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
+       .bus_init = dw_i3c_master_bus_init,
+       .bus_cleanup = dw_i3c_master_bus_cleanup,
+       .attach_i3c_dev = dw_i3c_master_attach_i3c_dev,
+       .reattach_i3c_dev = dw_i3c_master_reattach_i3c_dev,
+       .detach_i3c_dev = dw_i3c_master_detach_i3c_dev,
+       .do_daa = dw_i3c_master_daa,
+       .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd,
+       .send_ccc_cmd = dw_i3c_master_send_ccc_cmd,
+       .priv_xfers = dw_i3c_master_priv_xfers,
+       .attach_i2c_dev = dw_i3c_master_attach_i2c_dev,
+       .detach_i2c_dev = dw_i3c_master_detach_i2c_dev,
+       .i2c_xfers = dw_i3c_master_i2c_xfers,
+       .i2c_funcs = dw_i3c_master_i2c_funcs,
+};
+
+static int dw_i3c_probe(struct platform_device *pdev)
+{
+       struct dw_i3c_master *master;
+       struct resource *res;
+       int ret, irq;
+
+       master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       master->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(master->regs))
+               return PTR_ERR(master->regs);
+
+       master->core_clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(master->core_clk))
+               return PTR_ERR(master->core_clk);
+
+       master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                                   "core_rst");
+       if (IS_ERR(master->core_rst))
+               return PTR_ERR(master->core_rst);
+
+       ret = clk_prepare_enable(master->core_clk);
+       if (ret)
+               goto err_disable_core_clk;
+
+       reset_control_deassert(master->core_rst);
+
+       spin_lock_init(&master->xferqueue.lock);
+       INIT_LIST_HEAD(&master->xferqueue.list);
+
+       writel(INTR_ALL, master->regs + INTR_STATUS);
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, irq,
+                              dw_i3c_master_irq_handler, 0,
+                              dev_name(&pdev->dev), master);
+       if (ret)
+               goto err_assert_rst;
+
+       platform_set_drvdata(pdev, master);
+
+       /* Information regarding the FIFOs/QUEUEs depth */
+       ret = readl(master->regs + QUEUE_STATUS_LEVEL);
+       master->caps.cmdfifodepth = QUEUE_STATUS_LEVEL_CMD(ret);
+
+       ret = readl(master->regs + DATA_BUFFER_STATUS_LEVEL);
+       master->caps.datafifodepth = DATA_BUFFER_STATUS_LEVEL_TX(ret);
+
+       ret = readl(master->regs + DEVICE_ADDR_TABLE_POINTER);
+       master->datstartaddr = ret;
+       master->maxdevs = ret >> 16;
+       master->free_pos = GENMASK(master->maxdevs - 1, 0);
+
+       ret = i3c_master_register(&master->base, &pdev->dev,
+                                 &dw_mipi_i3c_ops, false);
+       if (ret)
+               goto err_assert_rst;
+
+       return 0;
+
+err_assert_rst:
+       reset_control_assert(master->core_rst);
+
+err_disable_core_clk:
+       clk_disable_unprepare(master->core_clk);
+
+       return ret;
+}
+
+static int dw_i3c_remove(struct platform_device *pdev)
+{
+       struct dw_i3c_master *master = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = i3c_master_unregister(&master->base);
+       if (ret)
+               return ret;
+
+       reset_control_assert(master->core_rst);
+
+       clk_disable_unprepare(master->core_clk);
+
+       return 0;
+}
+
+static const struct of_device_id dw_i3c_master_of_match[] = {
+       { .compatible = "snps,dw-i3c-master-1.00a", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
+
+static struct platform_driver dw_i3c_driver = {
+       .probe = dw_i3c_probe,
+       .remove = dw_i3c_remove,
+       .driver = {
+               .name = "dw-i3c-master",
+               .of_match_table = of_match_ptr(dw_i3c_master_of_match),
+       },
+};
+module_platform_driver(dw_i3c_driver);
+
+MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>");
+MODULE_DESCRIPTION("DesignWare MIPI I3C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
new file mode 100644 (file)
index 0000000..bbd79b8
--- /dev/null
@@ -0,0 +1,1666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i3c/master.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#define DEV_ID                         0x0
+#define DEV_ID_I3C_MASTER              0x5034
+
+#define CONF_STATUS0                   0x4
+#define CONF_STATUS0_CMDR_DEPTH(x)     (4 << (((x) & GENMASK(31, 29)) >> 29))
+#define CONF_STATUS0_ECC_CHK           BIT(28)
+#define CONF_STATUS0_INTEG_CHK         BIT(27)
+#define CONF_STATUS0_CSR_DAP_CHK       BIT(26)
+#define CONF_STATUS0_TRANS_TOUT_CHK    BIT(25)
+#define CONF_STATUS0_PROT_FAULTS_CHK   BIT(24)
+#define CONF_STATUS0_GPO_NUM(x)                (((x) & GENMASK(23, 16)) >> 16)
+#define CONF_STATUS0_GPI_NUM(x)                (((x) & GENMASK(15, 8)) >> 8)
+#define CONF_STATUS0_IBIR_DEPTH(x)     (4 << (((x) & GENMASK(7, 6)) >> 7))
+#define CONF_STATUS0_SUPPORTS_DDR      BIT(5)
+#define CONF_STATUS0_SEC_MASTER                BIT(4)
+#define CONF_STATUS0_DEVS_NUM(x)       ((x) & GENMASK(3, 0))
+
+#define CONF_STATUS1                   0x8
+#define CONF_STATUS1_IBI_HW_RES(x)     ((((x) & GENMASK(31, 28)) >> 28) + 1)
+#define CONF_STATUS1_CMD_DEPTH(x)      (4 << (((x) & GENMASK(27, 26)) >> 26))
+#define CONF_STATUS1_SLVDDR_RX_DEPTH(x)        (8 << (((x) & GENMASK(25, 21)) >> 21))
+#define CONF_STATUS1_SLVDDR_TX_DEPTH(x)        (8 << (((x) & GENMASK(20, 16)) >> 16))
+#define CONF_STATUS1_IBI_DEPTH(x)      (2 << (((x) & GENMASK(12, 10)) >> 10))
+#define CONF_STATUS1_RX_DEPTH(x)       (8 << (((x) & GENMASK(9, 5)) >> 5))
+#define CONF_STATUS1_TX_DEPTH(x)       (8 << ((x) & GENMASK(4, 0)))
+
+#define REV_ID                         0xc
+#define REV_ID_VID(id)                 (((id) & GENMASK(31, 20)) >> 20)
+#define REV_ID_PID(id)                 (((id) & GENMASK(19, 8)) >> 8)
+#define REV_ID_REV_MAJOR(id)           (((id) & GENMASK(7, 4)) >> 4)
+#define REV_ID_REV_MINOR(id)           ((id) & GENMASK(3, 0))
+
+#define CTRL                           0x10
+#define CTRL_DEV_EN                    BIT(31)
+#define CTRL_HALT_EN                   BIT(30)
+#define CTRL_MCS                       BIT(29)
+#define CTRL_MCS_EN                    BIT(28)
+#define CTRL_HJ_DISEC                  BIT(8)
+#define CTRL_MST_ACK                   BIT(7)
+#define CTRL_HJ_ACK                    BIT(6)
+#define CTRL_HJ_INIT                   BIT(5)
+#define CTRL_MST_INIT                  BIT(4)
+#define CTRL_AHDR_OPT                  BIT(3)
+#define CTRL_PURE_BUS_MODE             0
+#define CTRL_MIXED_FAST_BUS_MODE       2
+#define CTRL_MIXED_SLOW_BUS_MODE       3
+#define CTRL_BUS_MODE_MASK             GENMASK(1, 0)
+
+#define PRESCL_CTRL0                   0x14
+#define PRESCL_CTRL0_I2C(x)            ((x) << 16)
+#define PRESCL_CTRL0_I3C(x)            (x)
+#define PRESCL_CTRL0_MAX               GENMASK(9, 0)
+
+#define PRESCL_CTRL1                   0x18
+#define PRESCL_CTRL1_PP_LOW_MASK       GENMASK(15, 8)
+#define PRESCL_CTRL1_PP_LOW(x)         ((x) << 8)
+#define PRESCL_CTRL1_OD_LOW_MASK       GENMASK(7, 0)
+#define PRESCL_CTRL1_OD_LOW(x)         (x)
+
+#define MST_IER                                0x20
+#define MST_IDR                                0x24
+#define MST_IMR                                0x28
+#define MST_ICR                                0x2c
+#define MST_ISR                                0x30
+#define MST_INT_HALTED                 BIT(18)
+#define MST_INT_MR_DONE                        BIT(17)
+#define MST_INT_IMM_COMP               BIT(16)
+#define MST_INT_TX_THR                 BIT(15)
+#define MST_INT_TX_OVF                 BIT(14)
+#define MST_INT_IBID_THR               BIT(12)
+#define MST_INT_IBID_UNF               BIT(11)
+#define MST_INT_IBIR_THR               BIT(10)
+#define MST_INT_IBIR_UNF               BIT(9)
+#define MST_INT_IBIR_OVF               BIT(8)
+#define MST_INT_RX_THR                 BIT(7)
+#define MST_INT_RX_UNF                 BIT(6)
+#define MST_INT_CMDD_EMP               BIT(5)
+#define MST_INT_CMDD_THR               BIT(4)
+#define MST_INT_CMDD_OVF               BIT(3)
+#define MST_INT_CMDR_THR               BIT(2)
+#define MST_INT_CMDR_UNF               BIT(1)
+#define MST_INT_CMDR_OVF               BIT(0)
+
+#define MST_STATUS0                    0x34
+#define MST_STATUS0_IDLE               BIT(18)
+#define MST_STATUS0_HALTED             BIT(17)
+#define MST_STATUS0_MASTER_MODE                BIT(16)
+#define MST_STATUS0_TX_FULL            BIT(13)
+#define MST_STATUS0_IBID_FULL          BIT(12)
+#define MST_STATUS0_IBIR_FULL          BIT(11)
+#define MST_STATUS0_RX_FULL            BIT(10)
+#define MST_STATUS0_CMDD_FULL          BIT(9)
+#define MST_STATUS0_CMDR_FULL          BIT(8)
+#define MST_STATUS0_TX_EMP             BIT(5)
+#define MST_STATUS0_IBID_EMP           BIT(4)
+#define MST_STATUS0_IBIR_EMP           BIT(3)
+#define MST_STATUS0_RX_EMP             BIT(2)
+#define MST_STATUS0_CMDD_EMP           BIT(1)
+#define MST_STATUS0_CMDR_EMP           BIT(0)
+
+#define CMDR                           0x38
+#define CMDR_NO_ERROR                  0
+#define CMDR_DDR_PREAMBLE_ERROR                1
+#define CMDR_DDR_PARITY_ERROR          2
+#define CMDR_DDR_RX_FIFO_OVF           3
+#define CMDR_DDR_TX_FIFO_UNF           4
+#define CMDR_M0_ERROR                  5
+#define CMDR_M1_ERROR                  6
+#define CMDR_M2_ERROR                  7
+#define CMDR_MST_ABORT                 8
+#define CMDR_NACK_RESP                 9
+#define CMDR_INVALID_DA                        10
+#define CMDR_DDR_DROPPED               11
+#define CMDR_ERROR(x)                  (((x) & GENMASK(27, 24)) >> 24)
+#define CMDR_XFER_BYTES(x)             (((x) & GENMASK(19, 8)) >> 8)
+#define CMDR_CMDID_HJACK_DISEC         0xfe
+#define CMDR_CMDID_HJACK_ENTDAA                0xff
+#define CMDR_CMDID(x)                  ((x) & GENMASK(7, 0))
+
+#define IBIR                           0x3c
+#define IBIR_ACKED                     BIT(12)
+#define IBIR_SLVID(x)                  (((x) & GENMASK(11, 8)) >> 8)
+#define IBIR_ERROR                     BIT(7)
+#define IBIR_XFER_BYTES(x)             (((x) & GENMASK(6, 2)) >> 2)
+#define IBIR_TYPE_IBI                  0
+#define IBIR_TYPE_HJ                   1
+#define IBIR_TYPE_MR                   2
+#define IBIR_TYPE(x)                   ((x) & GENMASK(1, 0))
+
+#define SLV_IER                                0x40
+#define SLV_IDR                                0x44
+#define SLV_IMR                                0x48
+#define SLV_ICR                                0x4c
+#define SLV_ISR                                0x50
+#define SLV_INT_TM                     BIT(20)
+#define SLV_INT_ERROR                  BIT(19)
+#define SLV_INT_EVENT_UP               BIT(18)
+#define SLV_INT_HJ_DONE                        BIT(17)
+#define SLV_INT_MR_DONE                        BIT(16)
+#define SLV_INT_DA_UPD                 BIT(15)
+#define SLV_INT_SDR_FAIL               BIT(14)
+#define SLV_INT_DDR_FAIL               BIT(13)
+#define SLV_INT_M_RD_ABORT             BIT(12)
+#define SLV_INT_DDR_RX_THR             BIT(11)
+#define SLV_INT_DDR_TX_THR             BIT(10)
+#define SLV_INT_SDR_RX_THR             BIT(9)
+#define SLV_INT_SDR_TX_THR             BIT(8)
+#define SLV_INT_DDR_RX_UNF             BIT(7)
+#define SLV_INT_DDR_TX_OVF             BIT(6)
+#define SLV_INT_SDR_RX_UNF             BIT(5)
+#define SLV_INT_SDR_TX_OVF             BIT(4)
+#define SLV_INT_DDR_RD_COMP            BIT(3)
+#define SLV_INT_DDR_WR_COMP            BIT(2)
+#define SLV_INT_SDR_RD_COMP            BIT(1)
+#define SLV_INT_SDR_WR_COMP            BIT(0)
+
+#define SLV_STATUS0                    0x54
+#define SLV_STATUS0_REG_ADDR(s)                (((s) & GENMASK(23, 16)) >> 16)
+#define SLV_STATUS0_XFRD_BYTES(s)      ((s) & GENMASK(15, 0))
+
+#define SLV_STATUS1                    0x58
+#define SLV_STATUS1_AS(s)              (((s) & GENMASK(21, 20)) >> 20)
+#define SLV_STATUS1_VEN_TM             BIT(19)
+#define SLV_STATUS1_HJ_DIS             BIT(18)
+#define SLV_STATUS1_MR_DIS             BIT(17)
+#define SLV_STATUS1_PROT_ERR           BIT(16)
+#define SLV_STATUS1_DA(x)              (((s) & GENMASK(15, 9)) >> 9)
+#define SLV_STATUS1_HAS_DA             BIT(8)
+#define SLV_STATUS1_DDR_RX_FULL                BIT(7)
+#define SLV_STATUS1_DDR_TX_FULL                BIT(6)
+#define SLV_STATUS1_DDR_RX_EMPTY       BIT(5)
+#define SLV_STATUS1_DDR_TX_EMPTY       BIT(4)
+#define SLV_STATUS1_SDR_RX_FULL                BIT(3)
+#define SLV_STATUS1_SDR_TX_FULL                BIT(2)
+#define SLV_STATUS1_SDR_RX_EMPTY       BIT(1)
+#define SLV_STATUS1_SDR_TX_EMPTY       BIT(0)
+
+#define CMD0_FIFO                      0x60
+#define CMD0_FIFO_IS_DDR               BIT(31)
+#define CMD0_FIFO_IS_CCC               BIT(30)
+#define CMD0_FIFO_BCH                  BIT(29)
+#define XMIT_BURST_STATIC_SUBADDR      0
+#define XMIT_SINGLE_INC_SUBADDR                1
+#define XMIT_SINGLE_STATIC_SUBADDR     2
+#define XMIT_BURST_WITHOUT_SUBADDR     3
+#define CMD0_FIFO_PRIV_XMIT_MODE(m)    ((m) << 27)
+#define CMD0_FIFO_SBCA                 BIT(26)
+#define CMD0_FIFO_RSBC                 BIT(25)
+#define CMD0_FIFO_IS_10B               BIT(24)
+#define CMD0_FIFO_PL_LEN(l)            ((l) << 12)
+#define CMD0_FIFO_PL_LEN_MAX           4095
+#define CMD0_FIFO_DEV_ADDR(a)          ((a) << 1)
+#define CMD0_FIFO_RNW                  BIT(0)
+
+#define CMD1_FIFO                      0x64
+#define CMD1_FIFO_CMDID(id)            ((id) << 24)
+#define CMD1_FIFO_CSRADDR(a)           (a)
+#define CMD1_FIFO_CCC(id)              (id)
+
+#define TX_FIFO                                0x68
+
+#define IMD_CMD0                       0x70
+#define IMD_CMD0_PL_LEN(l)             ((l) << 12)
+#define IMD_CMD0_DEV_ADDR(a)           ((a) << 1)
+#define IMD_CMD0_RNW                   BIT(0)
+
+#define IMD_CMD1                       0x74
+#define IMD_CMD1_CCC(id)               (id)
+
+#define IMD_DATA                       0x78
+#define RX_FIFO                                0x80
+#define IBI_DATA_FIFO                  0x84
+#define SLV_DDR_TX_FIFO                        0x88
+#define SLV_DDR_RX_FIFO                        0x8c
+
+#define CMD_IBI_THR_CTRL               0x90
+#define IBIR_THR(t)                    ((t) << 24)
+#define CMDR_THR(t)                    ((t) << 16)
+#define IBI_THR(t)                     ((t) << 8)
+#define CMD_THR(t)                     (t)
+
+#define TX_RX_THR_CTRL                 0x94
+#define RX_THR(t)                      ((t) << 16)
+#define TX_THR(t)                      (t)
+
+#define SLV_DDR_TX_RX_THR_CTRL         0x98
+#define SLV_DDR_RX_THR(t)              ((t) << 16)
+#define SLV_DDR_TX_THR(t)              (t)
+
+#define FLUSH_CTRL                     0x9c
+#define FLUSH_IBI_RESP                 BIT(23)
+#define FLUSH_CMD_RESP                 BIT(22)
+#define FLUSH_SLV_DDR_RX_FIFO          BIT(22)
+#define FLUSH_SLV_DDR_TX_FIFO          BIT(21)
+#define FLUSH_IMM_FIFO                 BIT(20)
+#define FLUSH_IBI_FIFO                 BIT(19)
+#define FLUSH_RX_FIFO                  BIT(18)
+#define FLUSH_TX_FIFO                  BIT(17)
+#define FLUSH_CMD_FIFO                 BIT(16)
+
+#define TTO_PRESCL_CTRL0               0xb0
+#define TTO_PRESCL_CTRL0_DIVB(x)       ((x) << 16)
+#define TTO_PRESCL_CTRL0_DIVA(x)       (x)
+
+#define TTO_PRESCL_CTRL1               0xb4
+#define TTO_PRESCL_CTRL1_DIVB(x)       ((x) << 16)
+#define TTO_PRESCL_CTRL1_DIVA(x)       (x)
+
+#define DEVS_CTRL                      0xb8
+#define DEVS_CTRL_DEV_CLR_SHIFT                16
+#define DEVS_CTRL_DEV_CLR_ALL          GENMASK(31, 16)
+#define DEVS_CTRL_DEV_CLR(dev)         BIT(16 + (dev))
+#define DEVS_CTRL_DEV_ACTIVE(dev)      BIT(dev)
+#define DEVS_CTRL_DEVS_ACTIVE_MASK     GENMASK(15, 0)
+#define MAX_DEVS                       16
+
+#define DEV_ID_RR0(d)                  (0xc0 + ((d) * 0x10))
+#define DEV_ID_RR0_LVR_EXT_ADDR                BIT(11)
+#define DEV_ID_RR0_HDR_CAP             BIT(10)
+#define DEV_ID_RR0_IS_I3C              BIT(9)
+#define DEV_ID_RR0_DEV_ADDR_MASK       (GENMASK(6, 0) | GENMASK(15, 13))
+#define DEV_ID_RR0_SET_DEV_ADDR(a)     (((a) & GENMASK(6, 0)) |        \
+                                        (((a) & GENMASK(9, 7)) << 6))
+#define DEV_ID_RR0_GET_DEV_ADDR(x)     ((((x) >> 1) & GENMASK(6, 0)) | \
+                                        (((x) >> 6) & GENMASK(9, 7)))
+
+#define DEV_ID_RR1(d)                  (0xc4 + ((d) * 0x10))
+#define DEV_ID_RR1_PID_MSB(pid)                (pid)
+
+#define DEV_ID_RR2(d)                  (0xc8 + ((d) * 0x10))
+#define DEV_ID_RR2_PID_LSB(pid)                ((pid) << 16)
+#define DEV_ID_RR2_BCR(bcr)            ((bcr) << 8)
+#define DEV_ID_RR2_DCR(dcr)            (dcr)
+#define DEV_ID_RR2_LVR(lvr)            (lvr)
+
+#define SIR_MAP(x)                     (0x180 + ((x) * 4))
+#define SIR_MAP_DEV_REG(d)             SIR_MAP((d) / 2)
+#define SIR_MAP_DEV_SHIFT(d, fs)       ((fs) + (((d) % 2) ? 16 : 0))
+#define SIR_MAP_DEV_CONF_MASK(d)       (GENMASK(15, 0) << (((d) % 2) ? 16 : 0))
+#define SIR_MAP_DEV_CONF(d, c)         ((c) << (((d) % 2) ? 16 : 0))
+#define DEV_ROLE_SLAVE                 0
+#define DEV_ROLE_MASTER                        1
+#define SIR_MAP_DEV_ROLE(role)         ((role) << 14)
+#define SIR_MAP_DEV_SLOW               BIT(13)
+#define SIR_MAP_DEV_PL(l)              ((l) << 8)
+#define SIR_MAP_PL_MAX                 GENMASK(4, 0)
+#define SIR_MAP_DEV_DA(a)              ((a) << 1)
+#define SIR_MAP_DEV_ACK                        BIT(0)
+
+#define GPIR_WORD(x)                   (0x200 + ((x) * 4))
+#define GPI_REG(val, id)               \
+       (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0))
+
+#define GPOR_WORD(x)                   (0x220 + ((x) * 4))
+#define GPO_REG(val, id)               \
+       (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0))
+
+#define ASF_INT_STATUS                 0x300
+#define ASF_INT_RAW_STATUS             0x304
+#define ASF_INT_MASK                   0x308
+#define ASF_INT_TEST                   0x30c
+#define ASF_INT_FATAL_SELECT           0x310
+#define ASF_INTEGRITY_ERR              BIT(6)
+#define ASF_PROTOCOL_ERR               BIT(5)
+#define ASF_TRANS_TIMEOUT_ERR          BIT(4)
+#define ASF_CSR_ERR                    BIT(3)
+#define ASF_DAP_ERR                    BIT(2)
+#define ASF_SRAM_UNCORR_ERR            BIT(1)
+#define ASF_SRAM_CORR_ERR              BIT(0)
+
+#define ASF_SRAM_CORR_FAULT_STATUS     0x320
+#define ASF_SRAM_UNCORR_FAULT_STATUS   0x324
+#define ASF_SRAM_CORR_FAULT_INSTANCE(x)        ((x) >> 24)
+#define ASF_SRAM_CORR_FAULT_ADDR(x)    ((x) & GENMASK(23, 0))
+
+#define ASF_SRAM_FAULT_STATS           0x328
+#define ASF_SRAM_FAULT_UNCORR_STATS(x) ((x) >> 16)
+#define ASF_SRAM_FAULT_CORR_STATS(x)   ((x) & GENMASK(15, 0))
+
+#define ASF_TRANS_TOUT_CTRL            0x330
+#define ASF_TRANS_TOUT_EN              BIT(31)
+#define ASF_TRANS_TOUT_VAL(x)  (x)
+
+#define ASF_TRANS_TOUT_FAULT_MASK      0x334
+#define ASF_TRANS_TOUT_FAULT_STATUS    0x338
+#define ASF_TRANS_TOUT_FAULT_APB       BIT(3)
+#define ASF_TRANS_TOUT_FAULT_SCL_LOW   BIT(2)
+#define ASF_TRANS_TOUT_FAULT_SCL_HIGH  BIT(1)
+#define ASF_TRANS_TOUT_FAULT_FSCL_HIGH BIT(0)
+
+#define ASF_PROTO_FAULT_MASK           0x340
+#define ASF_PROTO_FAULT_STATUS         0x344
+#define ASF_PROTO_FAULT_SLVSDR_RD_ABORT        BIT(31)
+#define ASF_PROTO_FAULT_SLVDDR_FAIL    BIT(30)
+#define ASF_PROTO_FAULT_S(x)           BIT(16 + (x))
+#define ASF_PROTO_FAULT_MSTSDR_RD_ABORT        BIT(15)
+#define ASF_PROTO_FAULT_MSTDDR_FAIL    BIT(14)
+#define ASF_PROTO_FAULT_M(x)           BIT(x)
+
+struct cdns_i3c_master_caps {
+       u32 cmdfifodepth;
+       u32 cmdrfifodepth;
+       u32 txfifodepth;
+       u32 rxfifodepth;
+       u32 ibirfifodepth;
+};
+
+struct cdns_i3c_cmd {
+       u32 cmd0;
+       u32 cmd1;
+       u32 tx_len;
+       const void *tx_buf;
+       u32 rx_len;
+       void *rx_buf;
+       u32 error;
+};
+
+struct cdns_i3c_xfer {
+       struct list_head node;
+       struct completion comp;
+       int ret;
+       unsigned int ncmds;
+       struct cdns_i3c_cmd cmds[0];
+};
+
+struct cdns_i3c_master {
+       struct work_struct hj_work;
+       struct i3c_master_controller base;
+       u32 free_rr_slots;
+       unsigned int maxdevs;
+       struct {
+               unsigned int num_slots;
+               struct i3c_dev_desc **slots;
+               spinlock_t lock;
+       } ibi;
+       struct {
+               struct list_head list;
+               struct cdns_i3c_xfer *cur;
+               spinlock_t lock;
+       } xferqueue;
+       void __iomem *regs;
+       struct clk *sysclk;
+       struct clk *pclk;
+       struct cdns_i3c_master_caps caps;
+       unsigned long i3c_scl_lim;
+};
+
+static inline struct cdns_i3c_master *
+to_cdns_i3c_master(struct i3c_master_controller *master)
+{
+       return container_of(master, struct cdns_i3c_master, base);
+}
+
+static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
+                                         const u8 *bytes, int nbytes)
+{
+       writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
+       if (nbytes & 3) {
+               u32 tmp = 0;
+
+               memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
+               writesl(master->regs + TX_FIFO, &tmp, 1);
+       }
+}
+
+static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
+                                           u8 *bytes, int nbytes)
+{
+       readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
+       if (nbytes & 3) {
+               u32 tmp;
+
+               readsl(master->regs + RX_FIFO, &tmp, 1);
+               memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
+       }
+}
+
+static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
+                                            const struct i3c_ccc_cmd *cmd)
+{
+       if (cmd->ndests > 1)
+               return false;
+
+       switch (cmd->id) {
+       case I3C_CCC_ENEC(true):
+       case I3C_CCC_ENEC(false):
+       case I3C_CCC_DISEC(true):
+       case I3C_CCC_DISEC(false):
+       case I3C_CCC_ENTAS(0, true):
+       case I3C_CCC_ENTAS(0, false):
+       case I3C_CCC_RSTDAA(true):
+       case I3C_CCC_RSTDAA(false):
+       case I3C_CCC_ENTDAA:
+       case I3C_CCC_SETMWL(true):
+       case I3C_CCC_SETMWL(false):
+       case I3C_CCC_SETMRL(true):
+       case I3C_CCC_SETMRL(false):
+       case I3C_CCC_DEFSLVS:
+       case I3C_CCC_ENTHDR(0):
+       case I3C_CCC_SETDASA:
+       case I3C_CCC_SETNEWDA:
+       case I3C_CCC_GETMWL:
+       case I3C_CCC_GETMRL:
+       case I3C_CCC_GETPID:
+       case I3C_CCC_GETBCR:
+       case I3C_CCC_GETDCR:
+       case I3C_CCC_GETSTATUS:
+       case I3C_CCC_GETACCMST:
+       case I3C_CCC_GETMXDS:
+       case I3C_CCC_GETHDRCAP:
+               return true;
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static int cdns_i3c_master_disable(struct cdns_i3c_master *master)
+{
+       u32 status;
+
+       writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN, master->regs + CTRL);
+
+       return readl_poll_timeout(master->regs + MST_STATUS0, status,
+                                 status & MST_STATUS0_IDLE, 10, 1000000);
+}
+
+static void cdns_i3c_master_enable(struct cdns_i3c_master *master)
+{
+       writel(readl(master->regs + CTRL) | CTRL_DEV_EN, master->regs + CTRL);
+}
+
+static struct cdns_i3c_xfer *
+cdns_i3c_master_alloc_xfer(struct cdns_i3c_master *master, unsigned int ncmds)
+{
+       struct cdns_i3c_xfer *xfer;
+
+       xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
+       if (!xfer)
+               return NULL;
+
+       INIT_LIST_HEAD(&xfer->node);
+       xfer->ncmds = ncmds;
+       xfer->ret = -ETIMEDOUT;
+
+       return xfer;
+}
+
+static void cdns_i3c_master_free_xfer(struct cdns_i3c_xfer *xfer)
+{
+       kfree(xfer);
+}
+
+static void cdns_i3c_master_start_xfer_locked(struct cdns_i3c_master *master)
+{
+       struct cdns_i3c_xfer *xfer = master->xferqueue.cur;
+       unsigned int i;
+
+       if (!xfer)
+               return;
+
+       writel(MST_INT_CMDD_EMP, master->regs + MST_ICR);
+       for (i = 0; i < xfer->ncmds; i++) {
+               struct cdns_i3c_cmd *cmd = &xfer->cmds[i];
+
+               cdns_i3c_master_wr_to_tx_fifo(master, cmd->tx_buf,
+                                             cmd->tx_len);
+       }
+
+       for (i = 0; i < xfer->ncmds; i++) {
+               struct cdns_i3c_cmd *cmd = &xfer->cmds[i];
+
+               writel(cmd->cmd1 | CMD1_FIFO_CMDID(i),
+                      master->regs + CMD1_FIFO);
+               writel(cmd->cmd0, master->regs + CMD0_FIFO);
+       }
+
+       writel(readl(master->regs + CTRL) | CTRL_MCS,
+              master->regs + CTRL);
+       writel(MST_INT_CMDD_EMP, master->regs + MST_IER);
+}
+
+static void cdns_i3c_master_end_xfer_locked(struct cdns_i3c_master *master,
+                                           u32 isr)
+{
+       struct cdns_i3c_xfer *xfer = master->xferqueue.cur;
+       int i, ret = 0;
+       u32 status0;
+
+       if (!xfer)
+               return;
+
+       if (!(isr & MST_INT_CMDD_EMP))
+               return;
+
+       writel(MST_INT_CMDD_EMP, master->regs + MST_IDR);
+
+       for (status0 = readl(master->regs + MST_STATUS0);
+            !(status0 & MST_STATUS0_CMDR_EMP);
+            status0 = readl(master->regs + MST_STATUS0)) {
+               struct cdns_i3c_cmd *cmd;
+               u32 cmdr, rx_len, id;
+
+               cmdr = readl(master->regs + CMDR);
+               id = CMDR_CMDID(cmdr);
+               if (id == CMDR_CMDID_HJACK_DISEC ||
+                   id == CMDR_CMDID_HJACK_ENTDAA ||
+                   WARN_ON(id >= xfer->ncmds))
+                       continue;
+
+               cmd = &xfer->cmds[CMDR_CMDID(cmdr)];
+               rx_len = min_t(u32, CMDR_XFER_BYTES(cmdr), cmd->rx_len);
+               cdns_i3c_master_rd_from_rx_fifo(master, cmd->rx_buf, rx_len);
+               cmd->error = CMDR_ERROR(cmdr);
+       }
+
+       for (i = 0; i < xfer->ncmds; i++) {
+               switch (xfer->cmds[i].error) {
+               case CMDR_NO_ERROR:
+                       break;
+
+               case CMDR_DDR_PREAMBLE_ERROR:
+               case CMDR_DDR_PARITY_ERROR:
+               case CMDR_M0_ERROR:
+               case CMDR_M1_ERROR:
+               case CMDR_M2_ERROR:
+               case CMDR_MST_ABORT:
+               case CMDR_NACK_RESP:
+               case CMDR_DDR_DROPPED:
+                       ret = -EIO;
+                       break;
+
+               case CMDR_DDR_RX_FIFO_OVF:
+               case CMDR_DDR_TX_FIFO_UNF:
+                       ret = -ENOSPC;
+                       break;
+
+               case CMDR_INVALID_DA:
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       xfer->ret = ret;
+       complete(&xfer->comp);
+
+       xfer = list_first_entry_or_null(&master->xferqueue.list,
+                                       struct cdns_i3c_xfer, node);
+       if (xfer)
+               list_del_init(&xfer->node);
+
+       master->xferqueue.cur = xfer;
+       cdns_i3c_master_start_xfer_locked(master);
+}
+
+static void cdns_i3c_master_queue_xfer(struct cdns_i3c_master *master,
+                                      struct cdns_i3c_xfer *xfer)
+{
+       unsigned long flags;
+
+       init_completion(&xfer->comp);
+       spin_lock_irqsave(&master->xferqueue.lock, flags);
+       if (master->xferqueue.cur) {
+               list_add_tail(&xfer->node, &master->xferqueue.list);
+       } else {
+               master->xferqueue.cur = xfer;
+               cdns_i3c_master_start_xfer_locked(master);
+       }
+       spin_unlock_irqrestore(&master->xferqueue.lock, flags);
+}
+
+static void cdns_i3c_master_unqueue_xfer(struct cdns_i3c_master *master,
+                                        struct cdns_i3c_xfer *xfer)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->xferqueue.lock, flags);
+       if (master->xferqueue.cur == xfer) {
+               u32 status;
+
+               writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN,
+                      master->regs + CTRL);
+               readl_poll_timeout_atomic(master->regs + MST_STATUS0, status,
+                                         status & MST_STATUS0_IDLE, 10,
+                                         1000000);
+               master->xferqueue.cur = NULL;
+               writel(FLUSH_RX_FIFO | FLUSH_TX_FIFO | FLUSH_CMD_FIFO |
+                      FLUSH_CMD_RESP,
+                      master->regs + FLUSH_CTRL);
+               writel(MST_INT_CMDD_EMP, master->regs + MST_IDR);
+               writel(readl(master->regs + CTRL) | CTRL_DEV_EN,
+                      master->regs + CTRL);
+       } else {
+               list_del_init(&xfer->node);
+       }
+       spin_unlock_irqrestore(&master->xferqueue.lock, flags);
+}
+
+static enum i3c_error_code cdns_i3c_cmd_get_err(struct cdns_i3c_cmd *cmd)
+{
+       switch (cmd->error) {
+       case CMDR_M0_ERROR:
+               return I3C_ERROR_M0;
+
+       case CMDR_M1_ERROR:
+               return I3C_ERROR_M1;
+
+       case CMDR_M2_ERROR:
+       case CMDR_NACK_RESP:
+               return I3C_ERROR_M2;
+
+       default:
+               break;
+       }
+
+       return I3C_ERROR_UNKNOWN;
+}
+
+static int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
+                                       struct i3c_ccc_cmd *cmd)
+{
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_xfer *xfer;
+       struct cdns_i3c_cmd *ccmd;
+       int ret;
+
+       xfer = cdns_i3c_master_alloc_xfer(master, 1);
+       if (!xfer)
+               return -ENOMEM;
+
+       ccmd = xfer->cmds;
+       ccmd->cmd1 = CMD1_FIFO_CCC(cmd->id);
+       ccmd->cmd0 = CMD0_FIFO_IS_CCC |
+                    CMD0_FIFO_PL_LEN(cmd->dests[0].payload.len);
+
+       if (cmd->id & I3C_CCC_DIRECT)
+               ccmd->cmd0 |= CMD0_FIFO_DEV_ADDR(cmd->dests[0].addr);
+
+       if (cmd->rnw) {
+               ccmd->cmd0 |= CMD0_FIFO_RNW;
+               ccmd->rx_buf = cmd->dests[0].payload.data;
+               ccmd->rx_len = cmd->dests[0].payload.len;
+       } else {
+               ccmd->tx_buf = cmd->dests[0].payload.data;
+               ccmd->tx_len = cmd->dests[0].payload.len;
+       }
+
+       cdns_i3c_master_queue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
+               cdns_i3c_master_unqueue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       cmd->err = cdns_i3c_cmd_get_err(&xfer->cmds[0]);
+       cdns_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
+                                     struct i3c_priv_xfer *xfers,
+                                     int nxfers)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       int txslots = 0, rxslots = 0, i, ret;
+       struct cdns_i3c_xfer *cdns_xfer;
+
+       for (i = 0; i < nxfers; i++) {
+               if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
+                       return -ENOTSUPP;
+       }
+
+       if (!nxfers)
+               return 0;
+
+       if (nxfers > master->caps.cmdfifodepth ||
+           nxfers > master->caps.cmdrfifodepth)
+               return -ENOTSUPP;
+
+       /*
+        * First make sure that all transactions (block of transfers separated
+        * by a STOP marker) fit in the FIFOs.
+        */
+       for (i = 0; i < nxfers; i++) {
+               if (xfers[i].rnw)
+                       rxslots += DIV_ROUND_UP(xfers[i].len, 4);
+               else
+                       txslots += DIV_ROUND_UP(xfers[i].len, 4);
+       }
+
+       if (rxslots > master->caps.rxfifodepth ||
+           txslots > master->caps.txfifodepth)
+               return -ENOTSUPP;
+
+       cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
+       if (!cdns_xfer)
+               return -ENOMEM;
+
+       for (i = 0; i < nxfers; i++) {
+               struct cdns_i3c_cmd *ccmd = &cdns_xfer->cmds[i];
+               u32 pl_len = xfers[i].len;
+
+               ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(dev->info.dyn_addr) |
+                       CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR);
+
+               if (xfers[i].rnw) {
+                       ccmd->cmd0 |= CMD0_FIFO_RNW;
+                       ccmd->rx_buf = xfers[i].data.in;
+                       ccmd->rx_len = xfers[i].len;
+                       pl_len++;
+               } else {
+                       ccmd->tx_buf = xfers[i].data.out;
+                       ccmd->tx_len = xfers[i].len;
+               }
+
+               ccmd->cmd0 |= CMD0_FIFO_PL_LEN(pl_len);
+
+               if (i < nxfers - 1)
+                       ccmd->cmd0 |= CMD0_FIFO_RSBC;
+
+               if (!i)
+                       ccmd->cmd0 |= CMD0_FIFO_BCH;
+       }
+
+       cdns_i3c_master_queue_xfer(master, cdns_xfer);
+       if (!wait_for_completion_timeout(&cdns_xfer->comp,
+                                        msecs_to_jiffies(1000)))
+               cdns_i3c_master_unqueue_xfer(master, cdns_xfer);
+
+       ret = cdns_xfer->ret;
+
+       for (i = 0; i < nxfers; i++)
+               xfers[i].err = cdns_i3c_cmd_get_err(&cdns_xfer->cmds[i]);
+
+       cdns_i3c_master_free_xfer(cdns_xfer);
+
+       return ret;
+}
+
+static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
+                                    const struct i2c_msg *xfers, int nxfers)
+{
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       unsigned int nrxwords = 0, ntxwords = 0;
+       struct cdns_i3c_xfer *xfer;
+       int i, ret = 0;
+
+       if (nxfers > master->caps.cmdfifodepth)
+               return -ENOTSUPP;
+
+       for (i = 0; i < nxfers; i++) {
+               if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
+                       return -ENOTSUPP;
+
+               if (xfers[i].flags & I2C_M_RD)
+                       nrxwords += DIV_ROUND_UP(xfers[i].len, 4);
+               else
+                       ntxwords += DIV_ROUND_UP(xfers[i].len, 4);
+       }
+
+       if (ntxwords > master->caps.txfifodepth ||
+           nrxwords > master->caps.rxfifodepth)
+               return -ENOTSUPP;
+
+       xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
+       if (!xfer)
+               return -ENOMEM;
+
+       for (i = 0; i < nxfers; i++) {
+               struct cdns_i3c_cmd *ccmd = &xfer->cmds[i];
+
+               ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(xfers[i].addr) |
+                       CMD0_FIFO_PL_LEN(xfers[i].len) |
+                       CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR);
+
+               if (xfers[i].flags & I2C_M_TEN)
+                       ccmd->cmd0 |= CMD0_FIFO_IS_10B;
+
+               if (xfers[i].flags & I2C_M_RD) {
+                       ccmd->cmd0 |= CMD0_FIFO_RNW;
+                       ccmd->rx_buf = xfers[i].buf;
+                       ccmd->rx_len = xfers[i].len;
+               } else {
+                       ccmd->tx_buf = xfers[i].buf;
+                       ccmd->tx_len = xfers[i].len;
+               }
+       }
+
+       cdns_i3c_master_queue_xfer(master, xfer);
+       if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
+               cdns_i3c_master_unqueue_xfer(master, xfer);
+
+       ret = xfer->ret;
+       cdns_i3c_master_free_xfer(xfer);
+
+       return ret;
+}
+
+static u32 cdns_i3c_master_i2c_funcs(struct i3c_master_controller *m)
+{
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+struct cdns_i3c_i2c_dev_data {
+       u16 id;
+       s16 ibi;
+       struct i3c_generic_ibi_pool *ibi_pool;
+};
+
+static u32 prepare_rr0_dev_address(u32 addr)
+{
+       u32 ret = (addr << 1) & 0xff;
+
+       /* RR0[7:1] = addr[6:0] */
+       ret |= (addr & GENMASK(6, 0)) << 1;
+
+       /* RR0[15:13] = addr[9:7] */
+       ret |= (addr & GENMASK(9, 7)) << 6;
+
+       /* RR0[0] = ~XOR(addr[6:0]) */
+       if (!(hweight8(addr & 0x7f) & 1))
+               ret |= 1;
+
+       return ret;
+}
+
+static void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       u32 rr;
+
+       rr = prepare_rr0_dev_address(dev->info.dyn_addr ?
+                                    dev->info.dyn_addr :
+                                    dev->info.static_addr);
+       writel(DEV_ID_RR0_IS_I3C | rr, master->regs + DEV_ID_RR0(data->id));
+}
+
+static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
+                                      u8 dyn_addr)
+{
+       u32 activedevs, rr;
+       int i;
+
+       if (!dyn_addr) {
+               if (!master->free_rr_slots)
+                       return -ENOSPC;
+
+               return ffs(master->free_rr_slots) - 1;
+       }
+
+       activedevs = readl(master->regs + DEVS_CTRL) &
+                    DEVS_CTRL_DEVS_ACTIVE_MASK;
+
+       for (i = 1; i <= master->maxdevs; i++) {
+               if (!(BIT(i) & activedevs))
+                       continue;
+
+               rr = readl(master->regs + DEV_ID_RR0(i));
+               if (!(rr & DEV_ID_RR0_IS_I3C) ||
+                   DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr)
+                       continue;
+
+               return i;
+       }
+
+       return -EINVAL;
+}
+
+static int cdns_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
+                                           u8 old_dyn_addr)
+{
+       cdns_i3c_master_upd_i3c_addr(dev);
+
+       return 0;
+}
+
+static int cdns_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data;
+       int slot;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       slot = cdns_i3c_master_get_rr_slot(master, dev->info.dyn_addr);
+       if (slot < 0) {
+               kfree(data);
+               return slot;
+       }
+
+       data->ibi = -1;
+       data->id = slot;
+       i3c_dev_set_master_data(dev, data);
+       master->free_rr_slots &= ~BIT(slot);
+
+       if (!dev->info.dyn_addr) {
+               cdns_i3c_master_upd_i3c_addr(dev);
+               writel(readl(master->regs + DEVS_CTRL) |
+                      DEVS_CTRL_DEV_ACTIVE(data->id),
+                      master->regs + DEVS_CTRL);
+       }
+
+       return 0;
+}
+
+static void cdns_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+
+       writel(readl(master->regs + DEVS_CTRL) |
+              DEVS_CTRL_DEV_CLR(data->id),
+              master->regs + DEVS_CTRL);
+
+       i3c_dev_set_master_data(dev, NULL);
+       master->free_rr_slots |= BIT(data->id);
+       kfree(data);
+}
+
+static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data;
+       int slot;
+
+       slot = cdns_i3c_master_get_rr_slot(master, 0);
+       if (slot < 0)
+               return slot;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->id = slot;
+       master->free_rr_slots &= ~BIT(slot);
+       i2c_dev_set_master_data(dev, data);
+
+       writel(prepare_rr0_dev_address(dev->boardinfo->base.addr) |
+              (dev->boardinfo->base.flags & I2C_CLIENT_TEN ?
+               DEV_ID_RR0_LVR_EXT_ADDR : 0),
+              master->regs + DEV_ID_RR0(data->id));
+       writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id));
+       writel(readl(master->regs + DEVS_CTRL) |
+              DEVS_CTRL_DEV_ACTIVE(data->id),
+              master->regs + DEVS_CTRL);
+
+       return 0;
+}
+
+static void cdns_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i2c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
+
+       writel(readl(master->regs + DEVS_CTRL) |
+              DEVS_CTRL_DEV_CLR(data->id),
+              master->regs + DEVS_CTRL);
+       master->free_rr_slots |= BIT(data->id);
+
+       i2c_dev_set_master_data(dev, NULL);
+       kfree(data);
+}
+
+static void cdns_i3c_master_bus_cleanup(struct i3c_master_controller *m)
+{
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+
+       cdns_i3c_master_disable(master);
+}
+
+static void cdns_i3c_master_dev_rr_to_info(struct cdns_i3c_master *master,
+                                          unsigned int slot,
+                                          struct i3c_device_info *info)
+{
+       u32 rr;
+
+       memset(info, 0, sizeof(*info));
+       rr = readl(master->regs + DEV_ID_RR0(slot));
+       info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
+       rr = readl(master->regs + DEV_ID_RR2(slot));
+       info->dcr = rr;
+       info->bcr = rr >> 8;
+       info->pid = rr >> 16;
+       info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
+}
+
+static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
+{
+       struct i3c_master_controller *m = &master->base;
+       unsigned long i3c_lim_period, pres_step, ncycles;
+       struct i3c_bus *bus = i3c_master_get_bus(m);
+       unsigned long new_i3c_scl_lim = 0;
+       struct i3c_dev_desc *dev;
+       u32 prescl1, ctrl;
+
+       i3c_bus_for_each_i3cdev(bus, dev) {
+               unsigned long max_fscl;
+
+               max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds),
+                              I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds));
+               switch (max_fscl) {
+               case I3C_SDR1_FSCL_8MHZ:
+                       max_fscl = 8000000;
+                       break;
+               case I3C_SDR2_FSCL_6MHZ:
+                       max_fscl = 6000000;
+                       break;
+               case I3C_SDR3_FSCL_4MHZ:
+                       max_fscl = 4000000;
+                       break;
+               case I3C_SDR4_FSCL_2MHZ:
+                       max_fscl = 2000000;
+                       break;
+               case I3C_SDR0_FSCL_MAX:
+               default:
+                       max_fscl = 0;
+                       break;
+               }
+
+               if (max_fscl &&
+                   (new_i3c_scl_lim > max_fscl || !new_i3c_scl_lim))
+                       new_i3c_scl_lim = max_fscl;
+       }
+
+       /* Only update PRESCL_CTRL1 if the I3C SCL limitation has changed. */
+       if (new_i3c_scl_lim == master->i3c_scl_lim)
+               return;
+       master->i3c_scl_lim = new_i3c_scl_lim;
+       if (!new_i3c_scl_lim)
+               return;
+       pres_step = 1000000000UL / (bus->scl_rate.i3c * 4);
+
+       /* Configure PP_LOW to meet I3C slave limitations. */
+       prescl1 = readl(master->regs + PRESCL_CTRL1) &
+                 ~PRESCL_CTRL1_PP_LOW_MASK;
+       ctrl = readl(master->regs + CTRL);
+
+       i3c_lim_period = DIV_ROUND_UP(1000000000, master->i3c_scl_lim);
+       ncycles = DIV_ROUND_UP(i3c_lim_period, pres_step);
+       if (ncycles < 4)
+               ncycles = 0;
+       else
+               ncycles -= 4;
+
+       prescl1 |= PRESCL_CTRL1_PP_LOW(ncycles);
+
+       /* Disable I3C master before updating PRESCL_CTRL1. */
+       if (ctrl & CTRL_DEV_EN)
+               cdns_i3c_master_disable(master);
+
+       writel(prescl1, master->regs + PRESCL_CTRL1);
+
+       if (ctrl & CTRL_DEV_EN)
+               cdns_i3c_master_enable(master);
+}
+
+static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
+{
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       u32 olddevs, newdevs;
+       int ret, slot;
+       u8 addrs[MAX_DEVS] = { };
+       u8 last_addr = 0;
+
+       olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
+
+       /* Prepare RR slots before launching DAA. */
+       for (slot = 1; slot <= master->maxdevs; slot++) {
+               if (olddevs & BIT(slot))
+                       continue;
+
+               ret = i3c_master_get_free_addr(m, last_addr + 1);
+               if (ret < 0)
+                       return -ENOSPC;
+
+               last_addr = ret;
+               addrs[slot] = last_addr;
+               writel(prepare_rr0_dev_address(last_addr) | DEV_ID_RR0_IS_I3C,
+                      master->regs + DEV_ID_RR0(slot));
+               writel(0, master->regs + DEV_ID_RR1(slot));
+               writel(0, master->regs + DEV_ID_RR2(slot));
+       }
+
+       ret = i3c_master_entdaa_locked(&master->base);
+       if (ret && ret != I3C_ERROR_M2)
+               return ret;
+
+       newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
+       newdevs &= ~olddevs;
+
+       /*
+        * Clear all retaining registers filled during DAA. We already
+        * have the addressed assigned to them in the addrs array.
+        */
+       for (slot = 1; slot <= master->maxdevs; slot++) {
+               if (newdevs & BIT(slot))
+                       i3c_master_add_i3c_dev_locked(m, addrs[slot]);
+       }
+
+       /*
+        * Clear slots that ended up not being used. Can be caused by I3C
+        * device creation failure or when the I3C device was already known
+        * by the system but with a different address (in this case the device
+        * already has a slot and does not need a new one).
+        */
+       writel(readl(master->regs + DEVS_CTRL) |
+              master->free_rr_slots << DEVS_CTRL_DEV_CLR_SHIFT,
+              master->regs + DEVS_CTRL);
+
+       i3c_master_defslvs_locked(&master->base);
+
+       cdns_i3c_master_upd_i3c_scl_lim(master);
+
+       /* Unmask Hot-Join and Mastership request interrupts. */
+       i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
+                              I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR);
+
+       return 0;
+}
+
+static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
+{
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       unsigned long pres_step, sysclk_rate, max_i2cfreq;
+       struct i3c_bus *bus = i3c_master_get_bus(m);
+       u32 ctrl, prescl0, prescl1, pres, low;
+       struct i3c_device_info info = { };
+       int ret, ncycles;
+
+       switch (bus->mode) {
+       case I3C_BUS_MODE_PURE:
+               ctrl = CTRL_PURE_BUS_MODE;
+               break;
+
+       case I3C_BUS_MODE_MIXED_FAST:
+               ctrl = CTRL_MIXED_FAST_BUS_MODE;
+               break;
+
+       case I3C_BUS_MODE_MIXED_SLOW:
+               ctrl = CTRL_MIXED_SLOW_BUS_MODE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       sysclk_rate = clk_get_rate(master->sysclk);
+       if (!sysclk_rate)
+               return -EINVAL;
+
+       pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
+       if (pres > PRESCL_CTRL0_MAX)
+               return -ERANGE;
+
+       bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
+
+       prescl0 = PRESCL_CTRL0_I3C(pres);
+
+       low = ((I3C_BUS_TLOW_OD_MIN_NS * sysclk_rate) / (pres + 1)) - 2;
+       prescl1 = PRESCL_CTRL1_OD_LOW(low);
+
+       max_i2cfreq = bus->scl_rate.i2c;
+
+       pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
+       if (pres > PRESCL_CTRL0_MAX)
+               return -ERANGE;
+
+       bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
+
+       prescl0 |= PRESCL_CTRL0_I2C(pres);
+       writel(prescl0, master->regs + PRESCL_CTRL0);
+
+       /* Calculate OD and PP low. */
+       pres_step = 1000000000 / (bus->scl_rate.i3c * 4);
+       ncycles = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, pres_step) - 2;
+       if (ncycles < 0)
+               ncycles = 0;
+       prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
+       writel(prescl1, master->regs + PRESCL_CTRL1);
+
+       /* Get an address for the master. */
+       ret = i3c_master_get_free_addr(m, 0);
+       if (ret < 0)
+               return ret;
+
+       writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
+              master->regs + DEV_ID_RR0(0));
+
+       cdns_i3c_master_dev_rr_to_info(master, 0, &info);
+       if (info.bcr & I3C_BCR_HDR_CAP)
+               info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
+
+       ret = i3c_master_set_info(&master->base, &info);
+       if (ret)
+               return ret;
+
+       /*
+        * Enable Hot-Join, and, when a Hot-Join request happens, disable all
+        * events coming from this device.
+        *
+        * We will issue ENTDAA afterwards from the threaded IRQ handler.
+        */
+       ctrl |= CTRL_HJ_ACK | CTRL_HJ_DISEC | CTRL_HALT_EN | CTRL_MCS_EN;
+       writel(ctrl, master->regs + CTRL);
+
+       cdns_i3c_master_enable(master);
+
+       return 0;
+}
+
+static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
+                                      u32 ibir)
+{
+       struct cdns_i3c_i2c_dev_data *data;
+       bool data_consumed = false;
+       struct i3c_ibi_slot *slot;
+       u32 id = IBIR_SLVID(ibir);
+       struct i3c_dev_desc *dev;
+       size_t nbytes;
+       u8 *buf;
+
+       /*
+        * FIXME: maybe we should report the FIFO OVF errors to the upper
+        * layer.
+        */
+       if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR))
+               goto out;
+
+       dev = master->ibi.slots[id];
+       spin_lock(&master->ibi.lock);
+
+       data = i3c_dev_get_master_data(dev);
+       slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
+       if (!slot)
+               goto out_unlock;
+
+       buf = slot->data;
+
+       nbytes = IBIR_XFER_BYTES(ibir);
+       readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
+       if (nbytes % 3) {
+               u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
+
+               memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
+       }
+
+       slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
+                         dev->ibi->max_payload_len);
+       i3c_master_queue_ibi(dev, slot);
+       data_consumed = true;
+
+out_unlock:
+       spin_unlock(&master->ibi.lock);
+
+out:
+       /* Consume data from the FIFO if it's not been done already. */
+       if (!data_consumed) {
+               int i;
+
+               for (i = 0; i < IBIR_XFER_BYTES(ibir); i += 4)
+                       readl(master->regs + IBI_DATA_FIFO);
+       }
+}
+
+static void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master)
+{
+       u32 status0;
+
+       writel(MST_INT_IBIR_THR, master->regs + MST_ICR);
+
+       for (status0 = readl(master->regs + MST_STATUS0);
+            !(status0 & MST_STATUS0_IBIR_EMP);
+            status0 = readl(master->regs + MST_STATUS0)) {
+               u32 ibir = readl(master->regs + IBIR);
+
+               switch (IBIR_TYPE(ibir)) {
+               case IBIR_TYPE_IBI:
+                       cdns_i3c_master_handle_ibi(master, ibir);
+                       break;
+
+               case IBIR_TYPE_HJ:
+                       WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
+                       queue_work(master->base.wq, &master->hj_work);
+                       break;
+
+               case IBIR_TYPE_MR:
+                       WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
+               default:
+                       break;
+               }
+       }
+}
+
+static irqreturn_t cdns_i3c_master_interrupt(int irq, void *data)
+{
+       struct cdns_i3c_master *master = data;
+       u32 status;
+
+       status = readl(master->regs + MST_ISR);
+       if (!(status & readl(master->regs + MST_IMR)))
+               return IRQ_NONE;
+
+       spin_lock(&master->xferqueue.lock);
+       cdns_i3c_master_end_xfer_locked(master, status);
+       spin_unlock(&master->xferqueue.lock);
+
+       if (status & MST_INT_IBIR_THR)
+               cnds_i3c_master_demux_ibis(master);
+
+       return IRQ_HANDLED;
+}
+
+static int cdns_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       unsigned long flags;
+       u32 sirmap;
+       int ret;
+
+       ret = i3c_master_disec_locked(m, dev->info.dyn_addr,
+                                     I3C_CCC_EVENT_SIR);
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&master->ibi.lock, flags);
+       sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
+       sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
+       sirmap |= SIR_MAP_DEV_CONF(data->ibi,
+                                  SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
+       writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
+       spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+       return ret;
+}
+
+static int cdns_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       unsigned long flags;
+       u32 sircfg, sirmap;
+       int ret;
+
+       spin_lock_irqsave(&master->ibi.lock, flags);
+       sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
+       sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
+       sircfg = SIR_MAP_DEV_ROLE(dev->info.bcr >> 6) |
+                SIR_MAP_DEV_DA(dev->info.dyn_addr) |
+                SIR_MAP_DEV_PL(dev->info.max_ibi_len) |
+                SIR_MAP_DEV_ACK;
+
+       if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM)
+               sircfg |= SIR_MAP_DEV_SLOW;
+
+       sirmap |= SIR_MAP_DEV_CONF(data->ibi, sircfg);
+       writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
+       spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+       ret = i3c_master_enec_locked(m, dev->info.dyn_addr,
+                                    I3C_CCC_EVENT_SIR);
+       if (ret) {
+               spin_lock_irqsave(&master->ibi.lock, flags);
+               sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
+               sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
+               sirmap |= SIR_MAP_DEV_CONF(data->ibi,
+                                          SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
+               writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
+               spin_unlock_irqrestore(&master->ibi.lock, flags);
+       }
+
+       return ret;
+}
+
+static int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
+                                      const struct i3c_ibi_setup *req)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       unsigned long flags;
+       unsigned int i;
+
+       data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
+       if (IS_ERR(data->ibi_pool))
+               return PTR_ERR(data->ibi_pool);
+
+       spin_lock_irqsave(&master->ibi.lock, flags);
+       for (i = 0; i < master->ibi.num_slots; i++) {
+               if (!master->ibi.slots[i]) {
+                       data->ibi = i;
+                       master->ibi.slots[i] = dev;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+       if (i < master->ibi.num_slots)
+               return 0;
+
+       i3c_generic_ibi_free_pool(data->ibi_pool);
+       data->ibi_pool = NULL;
+
+       return -ENOSPC;
+}
+
+static void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
+{
+       struct i3c_master_controller *m = i3c_dev_get_master(dev);
+       struct cdns_i3c_master *master = to_cdns_i3c_master(m);
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->ibi.lock, flags);
+       master->ibi.slots[data->ibi] = NULL;
+       data->ibi = -1;
+       spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+       i3c_generic_ibi_free_pool(data->ibi_pool);
+}
+
+static void cdns_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
+                                            struct i3c_ibi_slot *slot)
+{
+       struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+
+       i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
+}
+
+static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
+       .bus_init = cdns_i3c_master_bus_init,
+       .bus_cleanup = cdns_i3c_master_bus_cleanup,
+       .do_daa = cdns_i3c_master_do_daa,
+       .attach_i3c_dev = cdns_i3c_master_attach_i3c_dev,
+       .reattach_i3c_dev = cdns_i3c_master_reattach_i3c_dev,
+       .detach_i3c_dev = cdns_i3c_master_detach_i3c_dev,
+       .attach_i2c_dev = cdns_i3c_master_attach_i2c_dev,
+       .detach_i2c_dev = cdns_i3c_master_detach_i2c_dev,
+       .supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd,
+       .send_ccc_cmd = cdns_i3c_master_send_ccc_cmd,
+       .priv_xfers = cdns_i3c_master_priv_xfers,
+       .i2c_xfers = cdns_i3c_master_i2c_xfers,
+       .i2c_funcs = cdns_i3c_master_i2c_funcs,
+       .enable_ibi = cdns_i3c_master_enable_ibi,
+       .disable_ibi = cdns_i3c_master_disable_ibi,
+       .request_ibi = cdns_i3c_master_request_ibi,
+       .free_ibi = cdns_i3c_master_free_ibi,
+       .recycle_ibi_slot = cdns_i3c_master_recycle_ibi_slot,
+};
+
+static void cdns_i3c_master_hj(struct work_struct *work)
+{
+       struct cdns_i3c_master *master = container_of(work,
+                                                     struct cdns_i3c_master,
+                                                     hj_work);
+
+       i3c_master_do_daa(&master->base);
+}
+
+static int cdns_i3c_master_probe(struct platform_device *pdev)
+{
+       struct cdns_i3c_master *master;
+       struct resource *res;
+       int ret, irq;
+       u32 val;
+
+       master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       master->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(master->regs))
+               return PTR_ERR(master->regs);
+
+       master->pclk = devm_clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(master->pclk))
+               return PTR_ERR(master->pclk);
+
+       master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
+       if (IS_ERR(master->pclk))
+               return PTR_ERR(master->pclk);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = clk_prepare_enable(master->pclk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(master->sysclk);
+       if (ret)
+               goto err_disable_pclk;
+
+       if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
+               ret = -EINVAL;
+               goto err_disable_sysclk;
+       }
+
+       spin_lock_init(&master->xferqueue.lock);
+       INIT_LIST_HEAD(&master->xferqueue.list);
+
+       INIT_WORK(&master->hj_work, cdns_i3c_master_hj);
+       writel(0xffffffff, master->regs + MST_IDR);
+       writel(0xffffffff, master->regs + SLV_IDR);
+       ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
+                              dev_name(&pdev->dev), master);
+       if (ret)
+               goto err_disable_sysclk;
+
+       platform_set_drvdata(pdev, master);
+
+       val = readl(master->regs + CONF_STATUS0);
+
+       /* Device ID0 is reserved to describe this master. */
+       master->maxdevs = CONF_STATUS0_DEVS_NUM(val);
+       master->free_rr_slots = GENMASK(master->maxdevs, 1);
+
+       val = readl(master->regs + CONF_STATUS1);
+       master->caps.cmdfifodepth = CONF_STATUS1_CMD_DEPTH(val);
+       master->caps.rxfifodepth = CONF_STATUS1_RX_DEPTH(val);
+       master->caps.txfifodepth = CONF_STATUS1_TX_DEPTH(val);
+       master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val);
+       master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val);
+
+       spin_lock_init(&master->ibi.lock);
+       master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val);
+       master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
+                                        sizeof(*master->ibi.slots),
+                                        GFP_KERNEL);
+       if (!master->ibi.slots)
+               goto err_disable_sysclk;
+
+       writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
+       writel(MST_INT_IBIR_THR, master->regs + MST_IER);
+       writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
+
+       ret = i3c_master_register(&master->base, &pdev->dev,
+                                 &cdns_i3c_master_ops, false);
+       if (ret)
+               goto err_disable_sysclk;
+
+       return 0;
+
+err_disable_sysclk:
+       clk_disable_unprepare(master->sysclk);
+
+err_disable_pclk:
+       clk_disable_unprepare(master->pclk);
+
+       return ret;
+}
+
+static int cdns_i3c_master_remove(struct platform_device *pdev)
+{
+       struct cdns_i3c_master *master = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = i3c_master_unregister(&master->base);
+       if (ret)
+               return ret;
+
+       clk_disable_unprepare(master->sysclk);
+       clk_disable_unprepare(master->pclk);
+
+       return 0;
+}
+
+static const struct of_device_id cdns_i3c_master_of_ids[] = {
+       { .compatible = "cdns,i3c-master" },
+       { /* sentinel */ },
+};
+
+static struct platform_driver cdns_i3c_master = {
+       .probe = cdns_i3c_master_probe,
+       .remove = cdns_i3c_master_remove,
+       .driver = {
+               .name = "cdns-i3c-master",
+               .of_match_table = cdns_i3c_master_of_ids,
+       },
+};
+module_platform_driver(cdns_i3c_master);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
+MODULE_DESCRIPTION("Cadence I3C master driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cdns-i3c-master");
index d78a10403bace100457193c64df2aa39a05b5fb0..a961b5a06fe6b1f552e8dc7ef5533016c886def0 100644 (file)
@@ -91,18 +91,14 @@ static int asus_acpi_get_sensor_info(struct acpi_device *adev,
 
 static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
 {
+       struct acpi_resource_i2c_serialbus *sb;
        u32 *addr = data;
 
-       if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
-               struct acpi_resource_i2c_serialbus *sb;
-
-               sb = &ares->data.i2c_serial_bus;
-               if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
-                       if (*addr)
-                               *addr |= (sb->slave_address << 16);
-                       else
-                               *addr = sb->slave_address;
-               }
+       if (i2c_acpi_get_i2c_resource(ares, &sb)) {
+               if (*addr)
+                       *addr |= (sb->slave_address << 16);
+               else
+                       *addr = sb->slave_address;
        }
 
        /* Tell the ACPI core that we already copied this address */
index a7dc286f406c992ebd55d764808691101dfff690..840e53732753f556a6f89e7afde3b2c1bf65edcc 100644 (file)
@@ -126,12 +126,8 @@ static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
 {
        struct omap4_keypad *keypad_data = dev_id;
 
-       if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
-               /* Disable interrupts */
-               kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-                                OMAP4_VAL_IRQDISABLE);
+       if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS))
                return IRQ_WAKE_THREAD;
-       }
 
        return IRQ_NONE;
 }
@@ -173,11 +169,6 @@ static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
                         kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
-       /* enable interrupts */
-       kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-               OMAP4_DEF_IRQENABLE_EVENTEN |
-                               OMAP4_DEF_IRQENABLE_LONGKEY);
-
        return IRQ_HANDLED;
 }
 
@@ -214,9 +205,10 @@ static void omap4_keypad_close(struct input_dev *input)
 
        disable_irq(keypad_data->irq);
 
-       /* Disable interrupts */
+       /* Disable interrupts and wake-up events */
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
                         OMAP4_VAL_IRQDISABLE);
+       kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, 0);
 
        /* clear pending interrupts */
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
@@ -365,7 +357,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
        }
 
        error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
-                                    omap4_keypad_irq_thread_fn, 0,
+                                    omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
                                     "omap4-keypad", keypad_data);
        if (error) {
                dev_err(&pdev->dev, "failed to register interrupt\n");
index 2d95e8d93cc761aefb102217473d940faf1e4d02..9fe075c137dc41bb513060d5b69871ed922e493f 100644 (file)
@@ -1767,6 +1767,18 @@ static int elantech_smbus = IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) ?
 module_param_named(elantech_smbus, elantech_smbus, int, 0644);
 MODULE_PARM_DESC(elantech_smbus, "Use a secondary bus for the Elantech device.");
 
+static const char * const i2c_blacklist_pnp_ids[] = {
+       /*
+        * These are known to not be working properly as bits are missing
+        * in elan_i2c.
+        */
+       "LEN2131", /* ThinkPad P52 w/ NFC */
+       "LEN2132", /* ThinkPad P52 */
+       "LEN2133", /* ThinkPad P72 w/ NFC */
+       "LEN2134", /* ThinkPad P72 */
+       NULL
+};
+
 static int elantech_create_smbus(struct psmouse *psmouse,
                                 struct elantech_device_info *info,
                                 bool leave_breadcrumbs)
@@ -1802,10 +1814,12 @@ static int elantech_setup_smbus(struct psmouse *psmouse,
 
        if (elantech_smbus == ELANTECH_SMBUS_NOT_SET) {
                /*
-                * New ICs are enabled by default.
+                * New ICs are enabled by default, unless mentioned in
+                * i2c_blacklist_pnp_ids.
                 * Old ICs are up to the user to decide.
                 */
-               if (!ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version))
+               if (!ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) ||
+                   psmouse_matches_pnp_id(psmouse, i2c_blacklist_pnp_ids))
                        return -ENXIO;
        }
 
index 2bd5bb11c8baec85bb9422dbfb0612e6bfed77f2..b6da0c1267e36e96cdc3b808e1fae122bec7add4 100644 (file)
@@ -171,6 +171,7 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0046", /* X250 */
        "LEN004a", /* W541 */
        "LEN005b", /* P50 */
+       "LEN005e", /* T560 */
        "LEN0071", /* T480 */
        "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
        "LEN0073", /* X1 Carbon G5 (Elantech) */
@@ -178,6 +179,7 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0096", /* X280 */
        "LEN0097", /* X280 -> ALPS trackpoint */
        "LEN200f", /* T450s */
+       "SYN3052", /* HP EliteBook 840 G4 */
        "SYN3221", /* HP 15-ay000 */
        NULL
 };
index b76fc3cdc8f8dfcc4c10b57ecb4ef10d39d820c4..23cc85e2e0e5718fe5e8e3d3ae5fc25ee0bdf058 100644 (file)
@@ -136,4 +136,11 @@ config LEDS_TRIGGER_PATTERN
          which is a series of tuples, of brightness and duration (ms).
          If unsure, say N
 
+config LEDS_TRIGGER_AUDIO
+       tristate "Audio Mute LED Trigger"
+       help
+         This allows LEDs to be controlled by audio drivers for following
+         the audio mute and mic-mute changes.
+         If unsure, say N
+
 endif # LEDS_TRIGGERS
index 9bcb64ee81231b6714938cc6b2b3992cd46970be..733a83e2a7183e8e1ef6af04fcea1ed3a1bd2526 100644 (file)
@@ -14,3 +14,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CAMERA)     += ledtrig-camera.o
 obj-$(CONFIG_LEDS_TRIGGER_PANIC)       += ledtrig-panic.o
 obj-$(CONFIG_LEDS_TRIGGER_NETDEV)      += ledtrig-netdev.o
 obj-$(CONFIG_LEDS_TRIGGER_PATTERN)     += ledtrig-pattern.o
+obj-$(CONFIG_LEDS_TRIGGER_AUDIO)       += ledtrig-audio.o
diff --git a/drivers/leds/trigger/ledtrig-audio.c b/drivers/leds/trigger/ledtrig-audio.c
new file mode 100644 (file)
index 0000000..f76621e
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Audio Mute LED trigger
+//
+
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+
+static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
+static enum led_brightness audio_state[NUM_AUDIO_LEDS];
+
+enum led_brightness ledtrig_audio_get(enum led_audio type)
+{
+       return audio_state[type];
+}
+EXPORT_SYMBOL_GPL(ledtrig_audio_get);
+
+void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
+{
+       audio_state[type] = state;
+       led_trigger_event(ledtrig_audio[type], state);
+}
+EXPORT_SYMBOL_GPL(ledtrig_audio_set);
+
+static int __init ledtrig_audio_init(void)
+{
+       led_trigger_register_simple("audio-mute",
+                                   &ledtrig_audio[LED_AUDIO_MUTE]);
+       led_trigger_register_simple("audio-micmute",
+                                   &ledtrig_audio[LED_AUDIO_MICMUTE]);
+       return 0;
+}
+module_init(ledtrig_audio_init);
+
+static void __exit ledtrig_audio_exit(void)
+{
+       led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
+       led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
+}
+module_exit(ledtrig_audio_exit);
+
+MODULE_DESCRIPTION("LED trigger for audio mute control");
+MODULE_LICENSE("GPL v2");
index 65a933a21e685b9c97fadc7662e34ad31c088798..f1261cc2b6fa58b4cefa96f8fcc9731ba08b2c4c 100644 (file)
@@ -455,7 +455,7 @@ int cec_thread_func(void *_adap)
                                (adap->needs_hpd &&
                                 (!adap->is_configured && !adap->is_configuring)) ||
                                kthread_should_stop() ||
-                               (!adap->transmitting &&
+                               (!adap->transmit_in_progress &&
                                 !list_empty(&adap->transmit_queue)),
                                msecs_to_jiffies(CEC_XFER_TIMEOUT_MS));
                        timeout = err == 0;
@@ -463,7 +463,7 @@ int cec_thread_func(void *_adap)
                        /* Otherwise we just wait for something to happen. */
                        wait_event_interruptible(adap->kthread_waitq,
                                kthread_should_stop() ||
-                               (!adap->transmitting &&
+                               (!adap->transmit_in_progress &&
                                 !list_empty(&adap->transmit_queue)));
                }
 
@@ -488,6 +488,7 @@ int cec_thread_func(void *_adap)
                        pr_warn("cec-%s: message %*ph timed out\n", adap->name,
                                adap->transmitting->msg.len,
                                adap->transmitting->msg.msg);
+                       adap->transmit_in_progress = false;
                        adap->tx_timeouts++;
                        /* Just give up on this. */
                        cec_data_cancel(adap->transmitting,
@@ -499,7 +500,7 @@ int cec_thread_func(void *_adap)
                 * If we are still transmitting, or there is nothing new to
                 * transmit, then just continue waiting.
                 */
-               if (adap->transmitting || list_empty(&adap->transmit_queue))
+               if (adap->transmit_in_progress || list_empty(&adap->transmit_queue))
                        goto unlock;
 
                /* Get a new message to transmit */
@@ -545,6 +546,8 @@ int cec_thread_func(void *_adap)
                if (adap->ops->adap_transmit(adap, data->attempts,
                                             signal_free_time, &data->msg))
                        cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
+               else
+                       adap->transmit_in_progress = true;
 
 unlock:
                mutex_unlock(&adap->lock);
@@ -575,14 +578,17 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
        data = adap->transmitting;
        if (!data) {
                /*
-                * This can happen if a transmit was issued and the cable is
+                * This might happen if a transmit was issued and the cable is
                 * unplugged while the transmit is ongoing. Ignore this
                 * transmit in that case.
                 */
-               dprintk(1, "%s was called without an ongoing transmit!\n",
-                       __func__);
-               goto unlock;
+               if (!adap->transmit_in_progress)
+                       dprintk(1, "%s was called without an ongoing transmit!\n",
+                               __func__);
+               adap->transmit_in_progress = false;
+               goto wake_thread;
        }
+       adap->transmit_in_progress = false;
 
        msg = &data->msg;
 
@@ -648,7 +654,6 @@ wake_thread:
         * for transmitting or to retry the current message.
         */
        wake_up_interruptible(&adap->kthread_waitq);
-unlock:
        mutex_unlock(&adap->lock);
 }
 EXPORT_SYMBOL_GPL(cec_transmit_done_ts);
@@ -1432,6 +1437,13 @@ configured:
                        las->log_addr[i],
                        cec_phys_addr_exp(adap->phys_addr));
                cec_transmit_msg_fh(adap, &msg, NULL, false);
+
+               /* Report Vendor ID */
+               if (adap->log_addrs.vendor_id != CEC_VENDOR_ID_NONE) {
+                       cec_msg_device_vendor_id(&msg,
+                                                adap->log_addrs.vendor_id);
+                       cec_transmit_msg_fh(adap, &msg, NULL, false);
+               }
        }
        adap->kthread_config = NULL;
        complete(&adap->config_completion);
@@ -1496,8 +1508,11 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
                if (adap->monitor_all_cnt)
                        WARN_ON(call_op(adap, adap_monitor_all_enable, false));
                mutex_lock(&adap->devnode.lock);
-               if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
+               if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) {
                        WARN_ON(adap->ops->adap_enable(adap, false));
+                       adap->transmit_in_progress = false;
+                       wake_up_interruptible(&adap->kthread_waitq);
+               }
                mutex_unlock(&adap->devnode.lock);
                if (phys_addr == CEC_PHYS_ADDR_INVALID)
                        return;
@@ -1505,6 +1520,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
 
        mutex_lock(&adap->devnode.lock);
        adap->last_initiator = 0xff;
+       adap->transmit_in_progress = false;
 
        if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) &&
            adap->ops->adap_enable(adap, true)) {
index e4edc930d4ed35c63b8515991f8c463d806fe6dd..cc875dabd7658a6a99416f540b0706e24b3be838 100644 (file)
@@ -24,6 +24,10 @@ int cec_debug;
 module_param_named(debug, cec_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 
+static bool debug_phys_addr;
+module_param(debug_phys_addr, bool, 0644);
+MODULE_PARM_DESC(debug_phys_addr, "add CEC_CAP_PHYS_ADDR if set");
+
 static dev_t cec_dev_t;
 
 /* Active devices */
@@ -270,6 +274,8 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
        adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
        adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
        adap->capabilities = caps;
+       if (debug_phys_addr)
+               adap->capabilities |= CEC_CAP_PHYS_ADDR;
        adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
        adap->available_log_addrs = available_las;
        adap->sequence = 0;
index 635db8e70ead57e24915f9d64fcfa1ccad48ec0e..8f987bc0dd883096c29851602d03ca2c62411a05 100644 (file)
@@ -601,8 +601,9 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
                        break;
                /* Was the message ACKed? */
                ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v;
-               if (!ack && !pin->tx_ignore_nack_until_eom &&
-                   pin->tx_bit / 10 < pin->tx_msg.len && !pin->tx_post_eom) {
+               if (!ack && (!pin->tx_ignore_nack_until_eom ||
+                   pin->tx_bit / 10 == pin->tx_msg.len - 1) &&
+                   !pin->tx_post_eom) {
                        /*
                         * Note: the CEC spec is ambiguous regarding
                         * what action to take when a NACK appears
index fa483b95bc5a996a4a8bb3fe737a32c791cab5bd..d9a590ae7545cfc38c22a13f20b8d68c97cde126 100644 (file)
@@ -1769,7 +1769,7 @@ typedef struct { u16 __; u8 _; } __packed x24;
                unsigned s;     \
        \
                for (s = 0; s < len; s++) {     \
-                       u8 chr = font8x16[text[s] * 16 + line]; \
+                       u8 chr = font8x16[(u8)text[s] * 16 + line];     \
        \
                        if (hdiv == 2 && tpg->hflip) { \
                                pos[3] = (chr & (0x01 << 6) ? fg : bg); \
index 8ff8722cb6b16dbf9b742eee7911dadba3037159..70e8c3366f9c80e70bfd16908875e12554aa766c 100644 (file)
@@ -679,11 +679,9 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
                 * are not in use and can be freed.
                 */
                mutex_lock(&q->mmap_lock);
-               if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
-                       mutex_unlock(&q->mmap_lock);
-                       dprintk(1, "memory in use, cannot free\n");
-                       return -EBUSY;
-               }
+               if (debug && q->memory == VB2_MEMORY_MMAP &&
+                   __buffers_in_use(q))
+                       dprintk(1, "memory in use, orphaning buffers\n");
 
                /*
                 * Call queue_cancel to clean up any buffers in the
@@ -812,6 +810,9 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
                memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
                q->memory = memory;
                q->waiting_for_buffers = !q->is_output;
+       } else if (q->memory != memory) {
+               dprintk(1, "memory model mismatch\n");
+               return -EINVAL;
        }
 
        num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
@@ -2143,9 +2144,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
                        return -EINVAL;
                }
        }
+
+       mutex_lock(&q->mmap_lock);
+
        if (vb2_fileio_is_active(q)) {
                dprintk(1, "mmap: file io in progress\n");
-               return -EBUSY;
+               ret = -EBUSY;
+               goto unlock;
        }
 
        /*
@@ -2153,7 +2158,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
         */
        ret = __find_plane_by_offset(q, off, &buffer, &plane);
        if (ret)
-               return ret;
+               goto unlock;
 
        vb = q->bufs[buffer];
 
@@ -2166,11 +2171,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
        if (length < (vma->vm_end - vma->vm_start)) {
                dprintk(1,
                        "MMAP invalid, as it would overflow buffer length\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
-       mutex_lock(&q->mmap_lock);
        ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+
+unlock:
        mutex_unlock(&q->mmap_lock);
        if (ret)
                return ret;
index 1d35aeabfd85ac79de7cb38e98d83f108acdb220..3a0ca2f9854fca34482f709724332a025cd07507 100644 (file)
@@ -158,7 +158,6 @@ static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
                return;
 
        check_once = true;
-       WARN_ON(1);
 
        pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
        if (vb->vb2_queue->allow_zero_bytesused)
@@ -627,7 +626,7 @@ EXPORT_SYMBOL(vb2_querybuf);
 
 static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
 {
-       *caps = 0;
+       *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
        if (q->io_modes & VB2_MMAP)
                *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
        if (q->io_modes & VB2_USERPTR)
@@ -710,6 +709,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
                requested_sizes[0] = f->fmt.sdr.buffersize;
                break;
        case V4L2_BUF_TYPE_META_CAPTURE:
+       case V4L2_BUF_TYPE_META_OUTPUT:
                requested_sizes[0] = f->fmt.meta.buffersize;
                break;
        default:
index 961207cf09eb489317630b3edcd470fec189a1b5..27a1d4a98d73e2b7014330db7fe0ed12be80f021 100644 (file)
@@ -917,6 +917,9 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
                         "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
                         fe->dvb->num, fe->id);
 
+       dprintk("frequency interval: tuner: %u...%u, frontend: %u...%u",
+               tuner_min, tuner_max, frontend_min, frontend_max);
+
        /* If the standard is for satellite, convert frequencies to kHz */
        switch (c->delivery_system) {
        case SYS_DVBS:
@@ -2587,8 +2590,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
                        u8 last = 1;
 
                        if (dvb_frontend_debug)
-                               dprintk("%s switch command: 0x%04lx\n",
-                                       __func__, swcmd);
+                               dprintk("switch command: 0x%04lx\n",
+                                       swcmd);
                        nexttime = ktime_get_boottime();
                        if (dvb_frontend_debug)
                                tv[0] = nexttime;
@@ -2611,8 +2614,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
                                        dvb_frontend_sleep_until(&nexttime, 8000);
                        }
                        if (dvb_frontend_debug) {
-                               dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n",
-                                       __func__, fe->dvb->num);
+                               dprintk("(adapter %d): switch delay (should be 32k followed by all 8k)\n",
+                                       fe->dvb->num);
                                for (i = 1; i < 10; i++)
                                        pr_info("%d: %d\n", i,
                                                (int)ktime_us_delta(tv[i], tv[i - 1]));
index 0cd57013ea25f8b5759508d069f65a8520ad4402..23b831ce343911d117c8633a3f01014320c4b5ed 100644 (file)
@@ -1137,16 +1137,8 @@ static int af9033_probe(struct i2c_client *client,
                 buf[4], buf[5], buf[6], buf[7]);
 
        /* Sleep as chip seems to be partly active by default */
-       switch (dev->cfg.tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               /* IT9135 did not like to sleep at that early */
-               break;
-       default:
+       /* IT9135 did not like to sleep at that early */
+       if (dev->is_af9035) {
                ret = regmap_write(dev->regmap, 0x80004c, 0x01);
                if (ret)
                        goto err_regmap_exit;
index 44a074261e698571149faa67e07fb5deae63d7f1..4813a88eb9f7c5c2a9e2b3123c0fe7f76ee33c46 100644 (file)
@@ -1072,45 +1072,45 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
 void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
 {
        struct dib0090_state *state = fe->tuner_priv;
-       u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
-       u16 *rf_ramp = NULL;
+       const u16 *bb_ramp = bb_ramp_pwm_normal; /* default baseband config */
+       const u16 *rf_ramp = NULL;
        u8 en_pwm_rf_mux = 1;
 
        /* reset the AGC */
        if (state->config->use_pwm_agc) {
                if (state->current_band == BAND_CBAND) {
                        if (state->identity.in_soc) {
-                               bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+                               bb_ramp = bb_ramp_pwm_normal_socs;
                                if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
-                                       rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
+                                       rf_ramp = rf_ramp_pwm_cband_8090;
                                else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
                                        if (state->config->is_dib7090e) {
                                                if (state->rf_ramp == NULL)
-                                                       rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
+                                                       rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
                                                else
-                                                       rf_ramp = (u16 *)state->rf_ramp;
+                                                       rf_ramp = state->rf_ramp;
                                        } else
-                                               rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
+                                               rf_ramp = rf_ramp_pwm_cband_7090p;
                                }
                        } else
-                               rf_ramp = (u16 *)&rf_ramp_pwm_cband;
+                               rf_ramp = rf_ramp_pwm_cband;
                } else
 
                        if (state->current_band == BAND_VHF) {
                                if (state->identity.in_soc) {
-                                       bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+                                       bb_ramp = bb_ramp_pwm_normal_socs;
                                        /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
                                } else
-                                       rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
+                                       rf_ramp = rf_ramp_pwm_vhf;
                        } else if (state->current_band == BAND_UHF) {
                                if (state->identity.in_soc) {
-                                       bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+                                       bb_ramp = bb_ramp_pwm_normal_socs;
                                        if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
-                                               rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
+                                               rf_ramp = rf_ramp_pwm_uhf_8090;
                                        else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
-                                               rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
+                                               rf_ramp = rf_ramp_pwm_uhf_7090;
                                } else
-                                       rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
+                                       rf_ramp = rf_ramp_pwm_uhf;
                        }
                if (rf_ramp)
                        dib0090_set_rframp_pwm(state, rf_ramp);
@@ -1416,9 +1416,9 @@ int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
        }
 
        if (cfg_sensitivity)
-               state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
+               state->rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
        else
-               state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
+               state->rf_ramp = rf_ramp_pwm_cband_7090e_aci;
        dib0090_pwm_gain_reset(fe);
 
        return 0;
index 58387860b62dcd90f203cffc62b1f0ea7877e9d6..2818e8def1b3822c7d47a34c74a4ed3b38f47fa7 100644 (file)
@@ -1871,10 +1871,13 @@ static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
                break;
        }
 
-       interleaving = interleaving;
-
        denom = bits_per_symbol * rate_num * fft_div * 384;
 
+       /*
+        * FIXME: check if the math makes sense. If so, fill the
+        * interleaving var.
+        */
+
        /* If calculus gets wrong, wait for 1s for the next stats */
        if (!denom)
                return 0;
index 84ac3f73f8fe4859c7f73f81b8fac1266b2c8240..8ea1e45be710736d13030beb5b93a769eab6b45f 100644 (file)
@@ -1474,9 +1474,11 @@ static int scu_command(struct drxk_state *state,
 
        /* assume that the command register is ready
                since it is checked afterwards */
-       for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
-               buffer[cnt++] = (parameter[ii] & 0xFF);
-               buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
+       if (parameter) {
+               for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
+                       buffer[cnt++] = (parameter[ii] & 0xFF);
+                       buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
+               }
        }
        buffer[cnt++] = (cmd & 0xFF);
        buffer[cnt++] = ((cmd >> 8) & 0xFF);
index 0e1f5daaf20cdfc39e4203ae3661718790655827..cee9c83e48de458203f07f02b2571bb0261c0a24 100644 (file)
@@ -2205,15 +2205,13 @@ static int lgdt3306a_probe(struct i2c_client *client,
        struct dvb_frontend *fe;
        int ret;
 
-       config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL);
+       config = kmemdup(client->dev.platform_data,
+                        sizeof(struct lgdt3306a_config), GFP_KERNEL);
        if (config == NULL) {
                ret = -ENOMEM;
                goto fail;
        }
 
-       memcpy(config, client->dev.platform_data,
-                       sizeof(struct lgdt3306a_config));
-
        config->i2c_addr = client->addr;
        fe = lgdt3306a_attach(config, client->adapter);
        if (fe == NULL) {
index 6191315f5970957c7f47896b03c82b96967fd7b0..290b9eab099ff756227753f3bc220fb146118f09 100644 (file)
@@ -781,7 +781,7 @@ static int set_input(struct dvb_frontend *fe, int input)
        return 0;
 }
 
-static struct dvb_frontend_ops mxl_ops = {
+static const struct dvb_frontend_ops mxl_ops = {
        .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
        .info = {
                .name                   = "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator",
index 5ce58612315da67f298f9f80979fb80a6faae588..eeb2318c102fe66d7ea7f5cb33f1ef9072aab23e 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
index 1c933b2cf7603cdc045c49671997d5f13a4e9a37..3ef5df1648d7760b735b1fcdfbfbdbc4e090d35b 100644 (file)
@@ -968,7 +968,8 @@ static int get_ca_object_length(struct avc_response_frame *r)
        return r->operand[7];
 }
 
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
+                   unsigned int *len)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
        struct avc_response_frame *r = (void *)fdtv->avc_data;
@@ -1009,7 +1010,8 @@ out:
        return ret;
 }
 
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
+               unsigned int *len)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
        struct avc_response_frame *r = (void *)fdtv->avc_data;
index 876cdec8329be30cc7f981c661535a83e44b8fc6..009905a199472ed3adc4db2c7764a8d4b291d08e 100644 (file)
@@ -124,8 +124,10 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
                    struct dvb_diseqc_master_cmd *diseqcmd);
 void avc_remote_ctrl_work(struct work_struct *work);
 int avc_register_remote_control(struct firedtv *fdtv);
-int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
-int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
+                   unsigned int *len);
+int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
+               unsigned int *len);
 int avc_ca_reset(struct firedtv *fdtv);
 int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
 int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
index 704af210e2708081700c5360d284680c7991dab9..4c936e1295003d7fad8449ff39c4cb1c60a26cba 100644 (file)
@@ -61,6 +61,7 @@ config VIDEO_TDA1997X
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
        depends on SND_SOC
        select SND_PCM
+       select HDMI
        ---help---
          V4L2 subdevice driver for the NXP TDA1997x HDMI receivers.
 
@@ -595,6 +596,18 @@ config VIDEO_APTINA_PLL
 config VIDEO_SMIAPP_PLL
        tristate
 
+config VIDEO_IMX214
+       tristate "Sony IMX214 sensor support"
+       depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
+       depends on V4L2_FWNODE
+       help
+         This is a Video4Linux2 sensor driver for the Sony
+         IMX214 camera.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx214.
+
 config VIDEO_IMX258
        tristate "Sony IMX258 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -610,6 +623,7 @@ config VIDEO_IMX274
        tristate "Sony IMX274 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        depends on MEDIA_CAMERA_SUPPORT
+       select REGMAP_I2C
        ---help---
          This is a V4L2 sensor driver for the Sony IMX274
          CMOS image sensor.
@@ -846,6 +860,7 @@ config VIDEO_MT9M032
 config VIDEO_MT9M111
        tristate "mt9m111, mt9m112 and mt9m131 support"
        depends on I2C && VIDEO_V4L2
+       select V4L2_FWNODE
        help
          This driver supports MT9M111, MT9M112 and MT9M131 cameras from
          Micron/Aptina
index 260d4d9ec2a1c60222eee4cc5227ad76bd17331b..65fae7732de0fd3e2ab4ec8de1b81a072923ed4d 100644 (file)
@@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C)             += video-i2c.o
 obj-$(CONFIG_VIDEO_ML86V7667)  += ml86v7667.o
 obj-$(CONFIG_VIDEO_OV2659)     += ov2659.o
 obj-$(CONFIG_VIDEO_TC358743)   += tc358743.o
+obj-$(CONFIG_VIDEO_IMX214)     += imx214.o
 obj-$(CONFIG_VIDEO_IMX258)     += imx258.o
 obj-$(CONFIG_VIDEO_IMX274)     += imx274.o
 obj-$(CONFIG_VIDEO_IMX319)     += imx319.o
index 5b008b0002c02c185bad782c2e3fe4f8e26a23b5..aa8b04cfed0f6c3c298bba33f48345710b0d8fe5 100644 (file)
@@ -578,7 +578,7 @@ static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
index 99697baad2ea09d27f9b497def2d2226bfa2fb34..6f3dc8862622d72cf9a49258008336a76846fab3 100644 (file)
 
 #define V4L2_CID_ADV_FAST_SWITCH       (V4L2_CID_USER_ADV7180_BASE + 0x00)
 
+/* Initial number of frames to skip to avoid possible garbage */
+#define ADV7180_NUM_OF_SKIP_FRAMES       2
+
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED     BIT(0)
@@ -769,6 +772,13 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       *frames = ADV7180_NUM_OF_SKIP_FRAMES;
+
+       return 0;
+}
+
 static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
 {
        struct adv7180_state *state = to_state(sd);
@@ -849,10 +859,15 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
        .get_fmt = adv7180_get_pad_format,
 };
 
+static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = {
+       .g_skip_frames = adv7180_get_skip_frames,
+};
+
 static const struct v4l2_subdev_ops adv7180_ops = {
        .core = &adv7180_core_ops,
        .video = &adv7180_video_ops,
        .pad = &adv7180_pad_ops,
+       .sensor = &adv7180_sensor_ops,
 };
 
 static irqreturn_t adv7180_irq(int irq, void *devid)
index f3899cc84e27f8db4c89c63e8ab1f2593dd8432a..cec5ebb1c9e6040f1fd3ae94cb0e0059648bf2f5 100644 (file)
@@ -130,7 +130,7 @@ static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
+       V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT,
                ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
@@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
        buffer[3] = 0;
        buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-       if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+       if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
                v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
                return;
        }
index 9eb7c70a7712580a6741723c9447d7439bc87b7d..28a84bf9f8a94fff20d0585ff710f2846ada6751 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/videodev2.h>
 #include <linux/workqueue.h>
 #include <linux/regmap.h>
+#include <linux/interrupt.h>
 
 #include <media/i2c/adv7604.h>
 #include <media/cec.h>
@@ -114,6 +115,11 @@ struct adv76xx_chip_info {
        unsigned int fmt_change_digital_mask;
        unsigned int cp_csc;
 
+       unsigned int cec_irq_status;
+       unsigned int cec_rx_enable;
+       unsigned int cec_rx_enable_mask;
+       bool cec_irq_swap;
+
        const struct adv76xx_format_info *formats;
        unsigned int nformats;
 
@@ -766,7 +772,7 @@ static const struct v4l2_dv_timings_cap adv7604_timings_cap_analog = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -777,7 +783,7 @@ static const struct v4l2_dv_timings_cap adv76xx_timings_cap_digital = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -2003,10 +2009,11 @@ static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status)
 static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
 {
        struct adv76xx_state *state = to_state(sd);
+       const struct adv76xx_chip_info *info = state->info;
        u8 cec_irq;
 
        /* cec controller */
-       cec_irq = io_read(sd, 0x4d) & 0x0f;
+       cec_irq = io_read(sd, info->cec_irq_status) & 0x0f;
        if (!cec_irq)
                return;
 
@@ -2024,15 +2031,21 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
 
                        for (i = 0; i < msg.len; i++)
                                msg.msg[i] = cec_read(sd, i + 0x15);
-                       cec_write(sd, 0x26, 0x01); /* re-enable rx */
+                       cec_write(sd, info->cec_rx_enable,
+                                 info->cec_rx_enable_mask); /* re-enable rx */
                        cec_received_msg(state->cec_adap, &msg);
                }
        }
 
-       /* note: the bit order is swapped between 0x4d and 0x4e */
-       cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) |
-                 ((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3);
-       io_write(sd, 0x4e, cec_irq);
+       if (info->cec_irq_swap) {
+               /*
+                * Note: the bit order is swapped between 0x4d and 0x4e
+                * on adv7604
+                */
+               cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) |
+                         ((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3);
+       }
+       io_write(sd, info->cec_irq_status + 1, cec_irq);
 
        if (handled)
                *handled = true;
@@ -2041,6 +2054,7 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
 static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
        struct adv76xx_state *state = cec_get_drvdata(adap);
+       const struct adv76xx_chip_info *info = state->info;
        struct v4l2_subdev *sd = &state->sd;
 
        if (!state->cec_enabled_adap && enable) {
@@ -2052,11 +2066,11 @@ static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable)
                /* tx: arbitration lost */
                /* tx: retry timeout */
                /* rx: ready */
-               io_write_clr_set(sd, 0x50, 0x0f, 0x0f);
-               cec_write(sd, 0x26, 0x01);            /* enable rx */
+               io_write_clr_set(sd, info->cec_irq_status + 3, 0x0f, 0x0f);
+               cec_write(sd, info->cec_rx_enable, info->cec_rx_enable_mask);
        } else if (state->cec_enabled_adap && !enable) {
                /* disable cec interrupts */
-               io_write_clr_set(sd, 0x50, 0x0f, 0x00);
+               io_write_clr_set(sd, info->cec_irq_status + 3, 0x0f, 0x00);
                /* disable address mask 1-3 */
                cec_write_clr_set(sd, 0x27, 0x70, 0x00);
                /* power down cec section */
@@ -2221,6 +2235,16 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        return 0;
 }
 
+static irqreturn_t adv76xx_irq_handler(int irq, void *dev_id)
+{
+       struct adv76xx_state *state = dev_id;
+       bool handled = false;
+
+       adv76xx_isr(&state->sd, 0, &handled);
+
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
 static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -2420,7 +2444,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
                buffer[i + 3] = infoframe_read(sd,
                                       adv76xx_cri[index].payload_addr + i);
 
-       if (hdmi_infoframe_unpack(frame, buffer) < 0) {
+       if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
                v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
                         adv76xx_cri[index].desc);
                return -ENOENT;
@@ -2960,6 +2984,10 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
                .cable_det_mask = 0x1e,
                .fmt_change_digital_mask = 0xc1,
                .cp_csc = 0xfc,
+               .cec_irq_status = 0x4d,
+               .cec_rx_enable = 0x26,
+               .cec_rx_enable_mask = 0x01,
+               .cec_irq_swap = true,
                .formats = adv7604_formats,
                .nformats = ARRAY_SIZE(adv7604_formats),
                .set_termination = adv7604_set_termination,
@@ -3006,6 +3034,9 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
                .cable_det_mask = 0x01,
                .fmt_change_digital_mask = 0x03,
                .cp_csc = 0xf4,
+               .cec_irq_status = 0x93,
+               .cec_rx_enable = 0x2c,
+               .cec_rx_enable_mask = 0x02,
                .formats = adv7611_formats,
                .nformats = ARRAY_SIZE(adv7611_formats),
                .set_termination = adv7611_set_termination,
@@ -3047,6 +3078,9 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
                .cable_det_mask = 0x01,
                .fmt_change_digital_mask = 0x03,
                .cp_csc = 0xf4,
+               .cec_irq_status = 0x93,
+               .cec_rx_enable = 0x2c,
+               .cec_rx_enable_mask = 0x02,
                .formats = adv7612_formats,
                .nformats = ARRAY_SIZE(adv7612_formats),
                .set_termination = adv7611_set_termination,
@@ -3134,7 +3168,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
                state->pdata.insert_av_codes = 1;
 
        /* Disable the interrupt for now as no DT-based board uses it. */
-       state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED;
+       state->pdata.int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH;
 
        /* Hardcode the remaining platform data fields. */
        state->pdata.disable_pwrdnb = 0;
@@ -3517,6 +3551,16 @@ static int adv76xx_probe(struct i2c_client *client,
        if (err)
                goto err_entity;
 
+       if (client->irq) {
+               err = devm_request_threaded_irq(&client->dev,
+                                               client->irq,
+                                               NULL, adv76xx_irq_handler,
+                                               IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                               client->name, state);
+               if (err)
+                       goto err_entity;
+       }
+
 #if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC)
        state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops,
                state, dev_name(&client->dev),
index 4721d49dcf0fef4bc4048e73d49bac558e3ed13e..989259488e3ddb9f620fdcac125bcc375d018911 100644 (file)
@@ -663,7 +663,7 @@ static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -674,7 +674,7 @@ static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -2574,7 +2574,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
        for (i = 0; i < len; i++)
                buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
-       if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+       if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
                v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
                return;
        }
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
new file mode 100644 (file)
index 0000000..ec3d1b8
--- /dev/null
@@ -0,0 +1,1118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * imx214.c - imx214 sensor driver
+ *
+ * Copyright 2018 Qtechnology A/S
+ *
+ * Ricardo Ribalda <ricardo.ribalda@gmail.com>
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define IMX214_DEFAULT_CLK_FREQ        24000000
+#define IMX214_DEFAULT_LINK_FREQ 480000000
+#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
+#define IMX214_FPS 30
+#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
+
+static const char * const imx214_supply_name[] = {
+       "vdda",
+       "vddd",
+       "vdddo",
+};
+
+#define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name)
+
+struct imx214 {
+       struct device *dev;
+       struct clk *xclk;
+       struct regmap *regmap;
+
+       struct v4l2_subdev sd;
+       struct media_pad pad;
+       struct v4l2_mbus_framefmt fmt;
+       struct v4l2_rect crop;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *link_freq;
+       struct v4l2_ctrl *exposure;
+
+       struct regulator_bulk_data      supplies[IMX214_NUM_SUPPLIES];
+
+       struct gpio_desc *enable_gpio;
+
+       /*
+        * Serialize control access, get/set format, get selection
+        * and start streaming.
+        */
+       struct mutex mutex;
+
+       bool streaming;
+};
+
+struct reg_8 {
+       u16 addr;
+       u8 val;
+};
+
+enum {
+       IMX214_TABLE_WAIT_MS = 0,
+       IMX214_TABLE_END,
+       IMX214_MAX_RETRIES,
+       IMX214_WAIT_MS
+};
+
+/*From imx214_mode_tbls.h*/
+static const struct reg_8 mode_4096x2304[] = {
+       {0x0114, 0x03},
+       {0x0220, 0x00},
+       {0x0221, 0x11},
+       {0x0222, 0x01},
+       {0x0340, 0x0C},
+       {0x0341, 0x7A},
+       {0x0342, 0x13},
+       {0x0343, 0x90},
+       {0x0344, 0x00},
+       {0x0345, 0x38},
+       {0x0346, 0x01},
+       {0x0347, 0x98},
+       {0x0348, 0x10},
+       {0x0349, 0x37},
+       {0x034A, 0x0A},
+       {0x034B, 0x97},
+       {0x0381, 0x01},
+       {0x0383, 0x01},
+       {0x0385, 0x01},
+       {0x0387, 0x01},
+       {0x0900, 0x00},
+       {0x0901, 0x00},
+       {0x0902, 0x00},
+       {0x3000, 0x35},
+       {0x3054, 0x01},
+       {0x305C, 0x11},
+
+       {0x0112, 0x0A},
+       {0x0113, 0x0A},
+       {0x034C, 0x10},
+       {0x034D, 0x00},
+       {0x034E, 0x09},
+       {0x034F, 0x00},
+       {0x0401, 0x00},
+       {0x0404, 0x00},
+       {0x0405, 0x10},
+       {0x0408, 0x00},
+       {0x0409, 0x00},
+       {0x040A, 0x00},
+       {0x040B, 0x00},
+       {0x040C, 0x10},
+       {0x040D, 0x00},
+       {0x040E, 0x09},
+       {0x040F, 0x00},
+
+       {0x0301, 0x05},
+       {0x0303, 0x02},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x96},
+       {0x0309, 0x0A},
+       {0x030B, 0x01},
+       {0x0310, 0x00},
+
+       {0x0820, 0x12},
+       {0x0821, 0xC0},
+       {0x0822, 0x00},
+       {0x0823, 0x00},
+
+       {0x3A03, 0x09},
+       {0x3A04, 0x50},
+       {0x3A05, 0x01},
+
+       {0x0B06, 0x01},
+       {0x30A2, 0x00},
+
+       {0x30B4, 0x00},
+
+       {0x3A02, 0xFF},
+
+       {0x3011, 0x00},
+       {0x3013, 0x01},
+
+       {0x0202, 0x0C},
+       {0x0203, 0x70},
+       {0x0224, 0x01},
+       {0x0225, 0xF4},
+
+       {0x0204, 0x00},
+       {0x0205, 0x00},
+       {0x020E, 0x01},
+       {0x020F, 0x00},
+       {0x0210, 0x01},
+       {0x0211, 0x00},
+       {0x0212, 0x01},
+       {0x0213, 0x00},
+       {0x0214, 0x01},
+       {0x0215, 0x00},
+       {0x0216, 0x00},
+       {0x0217, 0x00},
+
+       {0x4170, 0x00},
+       {0x4171, 0x10},
+       {0x4176, 0x00},
+       {0x4177, 0x3C},
+       {0xAE20, 0x04},
+       {0xAE21, 0x5C},
+
+       {IMX214_TABLE_WAIT_MS, 10},
+       {0x0138, 0x01},
+       {IMX214_TABLE_END, 0x00}
+};
+
+static const struct reg_8 mode_1920x1080[] = {
+       {0x0114, 0x03},
+       {0x0220, 0x00},
+       {0x0221, 0x11},
+       {0x0222, 0x01},
+       {0x0340, 0x0C},
+       {0x0341, 0x7A},
+       {0x0342, 0x13},
+       {0x0343, 0x90},
+       {0x0344, 0x04},
+       {0x0345, 0x78},
+       {0x0346, 0x03},
+       {0x0347, 0xFC},
+       {0x0348, 0x0B},
+       {0x0349, 0xF7},
+       {0x034A, 0x08},
+       {0x034B, 0x33},
+       {0x0381, 0x01},
+       {0x0383, 0x01},
+       {0x0385, 0x01},
+       {0x0387, 0x01},
+       {0x0900, 0x00},
+       {0x0901, 0x00},
+       {0x0902, 0x00},
+       {0x3000, 0x35},
+       {0x3054, 0x01},
+       {0x305C, 0x11},
+
+       {0x0112, 0x0A},
+       {0x0113, 0x0A},
+       {0x034C, 0x07},
+       {0x034D, 0x80},
+       {0x034E, 0x04},
+       {0x034F, 0x38},
+       {0x0401, 0x00},
+       {0x0404, 0x00},
+       {0x0405, 0x10},
+       {0x0408, 0x00},
+       {0x0409, 0x00},
+       {0x040A, 0x00},
+       {0x040B, 0x00},
+       {0x040C, 0x07},
+       {0x040D, 0x80},
+       {0x040E, 0x04},
+       {0x040F, 0x38},
+
+       {0x0301, 0x05},
+       {0x0303, 0x02},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x96},
+       {0x0309, 0x0A},
+       {0x030B, 0x01},
+       {0x0310, 0x00},
+
+       {0x0820, 0x12},
+       {0x0821, 0xC0},
+       {0x0822, 0x00},
+       {0x0823, 0x00},
+
+       {0x3A03, 0x04},
+       {0x3A04, 0xF8},
+       {0x3A05, 0x02},
+
+       {0x0B06, 0x01},
+       {0x30A2, 0x00},
+
+       {0x30B4, 0x00},
+
+       {0x3A02, 0xFF},
+
+       {0x3011, 0x00},
+       {0x3013, 0x01},
+
+       {0x0202, 0x0C},
+       {0x0203, 0x70},
+       {0x0224, 0x01},
+       {0x0225, 0xF4},
+
+       {0x0204, 0x00},
+       {0x0205, 0x00},
+       {0x020E, 0x01},
+       {0x020F, 0x00},
+       {0x0210, 0x01},
+       {0x0211, 0x00},
+       {0x0212, 0x01},
+       {0x0213, 0x00},
+       {0x0214, 0x01},
+       {0x0215, 0x00},
+       {0x0216, 0x00},
+       {0x0217, 0x00},
+
+       {0x4170, 0x00},
+       {0x4171, 0x10},
+       {0x4176, 0x00},
+       {0x4177, 0x3C},
+       {0xAE20, 0x04},
+       {0xAE21, 0x5C},
+
+       {IMX214_TABLE_WAIT_MS, 10},
+       {0x0138, 0x01},
+       {IMX214_TABLE_END, 0x00}
+};
+
+static const struct reg_8 mode_table_common[] = {
+       /* software reset */
+
+       /* software standby settings */
+       {0x0100, 0x00},
+
+       /* ATR setting */
+       {0x9300, 0x02},
+
+       /* external clock setting */
+       {0x0136, 0x18},
+       {0x0137, 0x00},
+
+       /* global setting */
+       /* basic config */
+       {0x0101, 0x00},
+       {0x0105, 0x01},
+       {0x0106, 0x01},
+       {0x4550, 0x02},
+       {0x4601, 0x00},
+       {0x4642, 0x05},
+       {0x6227, 0x11},
+       {0x6276, 0x00},
+       {0x900E, 0x06},
+       {0xA802, 0x90},
+       {0xA803, 0x11},
+       {0xA804, 0x62},
+       {0xA805, 0x77},
+       {0xA806, 0xAE},
+       {0xA807, 0x34},
+       {0xA808, 0xAE},
+       {0xA809, 0x35},
+       {0xA80A, 0x62},
+       {0xA80B, 0x83},
+       {0xAE33, 0x00},
+
+       /* analog setting */
+       {0x4174, 0x00},
+       {0x4175, 0x11},
+       {0x4612, 0x29},
+       {0x461B, 0x12},
+       {0x461F, 0x06},
+       {0x4635, 0x07},
+       {0x4637, 0x30},
+       {0x463F, 0x18},
+       {0x4641, 0x0D},
+       {0x465B, 0x12},
+       {0x465F, 0x11},
+       {0x4663, 0x11},
+       {0x4667, 0x0F},
+       {0x466F, 0x0F},
+       {0x470E, 0x09},
+       {0x4909, 0xAB},
+       {0x490B, 0x95},
+       {0x4915, 0x5D},
+       {0x4A5F, 0xFF},
+       {0x4A61, 0xFF},
+       {0x4A73, 0x62},
+       {0x4A85, 0x00},
+       {0x4A87, 0xFF},
+
+       /* embedded data */
+       {0x5041, 0x04},
+       {0x583C, 0x04},
+       {0x620E, 0x04},
+       {0x6EB2, 0x01},
+       {0x6EB3, 0x00},
+       {0x9300, 0x02},
+
+       /* imagequality */
+       /* HDR setting */
+       {0x3001, 0x07},
+       {0x6D12, 0x3F},
+       {0x6D13, 0xFF},
+       {0x9344, 0x03},
+       {0x9706, 0x10},
+       {0x9707, 0x03},
+       {0x9708, 0x03},
+       {0x9E04, 0x01},
+       {0x9E05, 0x00},
+       {0x9E0C, 0x01},
+       {0x9E0D, 0x02},
+       {0x9E24, 0x00},
+       {0x9E25, 0x8C},
+       {0x9E26, 0x00},
+       {0x9E27, 0x94},
+       {0x9E28, 0x00},
+       {0x9E29, 0x96},
+
+       /* CNR parameter setting */
+       {0x69DB, 0x01},
+
+       /* Moire reduction */
+       {0x6957, 0x01},
+
+       /* image enhancment */
+       {0x6987, 0x17},
+       {0x698A, 0x03},
+       {0x698B, 0x03},
+
+       /* white balanace */
+       {0x0B8E, 0x01},
+       {0x0B8F, 0x00},
+       {0x0B90, 0x01},
+       {0x0B91, 0x00},
+       {0x0B92, 0x01},
+       {0x0B93, 0x00},
+       {0x0B94, 0x01},
+       {0x0B95, 0x00},
+
+       /* ATR setting */
+       {0x6E50, 0x00},
+       {0x6E51, 0x32},
+       {0x9340, 0x00},
+       {0x9341, 0x3C},
+       {0x9342, 0x03},
+       {0x9343, 0xFF},
+       {IMX214_TABLE_END, 0x00}
+};
+
+/*
+ * Declare modes in order, from biggest
+ * to smallest height.
+ */
+static const struct imx214_mode {
+       u32 width;
+       u32 height;
+       const struct reg_8 *reg_table;
+} imx214_modes[] = {
+       {
+               .width = 4096,
+               .height = 2304,
+               .reg_table = mode_4096x2304,
+       },
+       {
+               .width = 1920,
+               .height = 1080,
+               .reg_table = mode_1920x1080,
+       },
+};
+
+static inline struct imx214 *to_imx214(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct imx214, sd);
+}
+
+static int __maybe_unused imx214_power_on(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx214 *imx214 = to_imx214(sd);
+       int ret;
+
+       ret = regulator_bulk_enable(IMX214_NUM_SUPPLIES, imx214->supplies);
+       if (ret < 0) {
+               dev_err(imx214->dev, "failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
+       usleep_range(2000, 3000);
+
+       ret = clk_prepare_enable(imx214->xclk);
+       if (ret < 0) {
+               regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies);
+               dev_err(imx214->dev, "clk prepare enable failed\n");
+               return ret;
+       }
+
+       gpiod_set_value_cansleep(imx214->enable_gpio, 1);
+       usleep_range(12000, 15000);
+
+       return 0;
+}
+
+static int __maybe_unused imx214_power_off(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx214 *imx214 = to_imx214(sd);
+
+       gpiod_set_value_cansleep(imx214->enable_gpio, 0);
+
+       clk_disable_unprepare(imx214->xclk);
+
+       regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies);
+       usleep_range(10, 20);
+
+       return 0;
+}
+
+static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index > 0)
+               return -EINVAL;
+
+       code->code = IMX214_MBUS_CODE;
+
+       return 0;
+}
+
+static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       if (fse->code != IMX214_MBUS_CODE)
+               return -EINVAL;
+
+       if (fse->index >= ARRAY_SIZE(imx214_modes))
+               return -EINVAL;
+
+       fse->min_width = fse->max_width = imx214_modes[fse->index].width;
+       fse->min_height = fse->max_height = imx214_modes[fse->index].height;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int imx214_s_register(struct v4l2_subdev *subdev,
+                            const struct v4l2_dbg_register *reg)
+{
+       struct imx214 *imx214 = container_of(subdev, struct imx214, sd);
+
+       return regmap_write(imx214->regmap, reg->reg, reg->val);
+}
+
+static int imx214_g_register(struct v4l2_subdev *subdev,
+                            struct v4l2_dbg_register *reg)
+{
+       struct imx214 *imx214 = container_of(subdev, struct imx214, sd);
+       unsigned int aux;
+       int ret;
+
+       reg->size = 1;
+       ret = regmap_read(imx214->regmap, reg->reg, &aux);
+       reg->val = aux;
+
+       return ret;
+}
+#endif
+
+static const struct v4l2_subdev_core_ops imx214_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = imx214_g_register,
+       .s_register = imx214_s_register,
+#endif
+};
+
+static struct v4l2_mbus_framefmt *
+__imx214_get_pad_format(struct imx214 *imx214,
+                       struct v4l2_subdev_pad_config *cfg,
+                       unsigned int pad,
+                       enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &imx214->fmt;
+       default:
+               return NULL;
+       }
+}
+
+static int imx214_get_format(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_format *format)
+{
+       struct imx214 *imx214 = to_imx214(sd);
+
+       mutex_lock(&imx214->mutex);
+       format->format = *__imx214_get_pad_format(imx214, cfg, format->pad,
+                                                 format->which);
+       mutex_unlock(&imx214->mutex);
+
+       return 0;
+}
+
+static struct v4l2_rect *
+__imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
+                     unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &imx214->crop;
+       default:
+               return NULL;
+       }
+}
+
+static int imx214_set_format(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_format *format)
+{
+       struct imx214 *imx214 = to_imx214(sd);
+       struct v4l2_mbus_framefmt *__format;
+       struct v4l2_rect *__crop;
+       const struct imx214_mode *mode;
+
+       mutex_lock(&imx214->mutex);
+
+       __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which);
+
+       if (format)
+               mode = v4l2_find_nearest_size(imx214_modes,
+                               ARRAY_SIZE(imx214_modes), width, height,
+                               format->format.width, format->format.height);
+       else
+               mode = &imx214_modes[0];
+
+       __crop->width = mode->width;
+       __crop->height = mode->height;
+
+       __format = __imx214_get_pad_format(imx214, cfg, format->pad,
+                                          format->which);
+       __format->width = __crop->width;
+       __format->height = __crop->height;
+       __format->code = IMX214_MBUS_CODE;
+       __format->field = V4L2_FIELD_NONE;
+       __format->colorspace = V4L2_COLORSPACE_SRGB;
+       __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace);
+       __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+                               __format->colorspace, __format->ycbcr_enc);
+       __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace);
+
+       format->format = *__format;
+
+       mutex_unlock(&imx214->mutex);
+
+       return 0;
+}
+
+static int imx214_get_selection(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_selection *sel)
+{
+       struct imx214 *imx214 = to_imx214(sd);
+
+       if (sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       mutex_lock(&imx214->mutex);
+       sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad,
+                                       sel->which);
+       mutex_unlock(&imx214->mutex);
+       return 0;
+}
+
+static int imx214_entity_init_cfg(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_pad_config *cfg)
+{
+       struct v4l2_subdev_format fmt = { };
+
+       fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt.format.width = imx214_modes[0].width;
+       fmt.format.height = imx214_modes[0].height;
+
+       imx214_set_format(subdev, cfg, &fmt);
+
+       return 0;
+}
+
+static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct imx214 *imx214 = container_of(ctrl->handler,
+                                            struct imx214, ctrls);
+       u8 vals[2];
+       int ret;
+
+       /*
+        * Applying V4L2 control value only happens
+        * when power is up for streaming
+        */
+       if (!pm_runtime_get_if_in_use(imx214->dev))
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               vals[1] = ctrl->val;
+               vals[0] = ctrl->val >> 8;
+               ret = regmap_bulk_write(imx214->regmap, 0x202, vals, 2);
+               if (ret < 0)
+                       dev_err(imx214->dev, "Error %d\n", ret);
+               ret = 0;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       pm_runtime_put(imx214->dev);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops imx214_ctrl_ops = {
+       .s_ctrl = imx214_set_ctrl,
+};
+
+#define MAX_CMD 4
+static int imx214_write_table(struct imx214 *imx214,
+                             const struct reg_8 table[])
+{
+       u8 vals[MAX_CMD];
+       int i;
+       int ret;
+
+       for (; table->addr != IMX214_TABLE_END ; table++) {
+               if (table->addr == IMX214_TABLE_WAIT_MS) {
+                       usleep_range(table->val * 1000,
+                                    table->val * 1000 + 500);
+                       continue;
+               }
+
+               for (i = 0; i < MAX_CMD; i++) {
+                       if (table[i].addr != (table[0].addr + i))
+                               break;
+                       vals[i] = table[i].val;
+               }
+
+               ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i);
+
+               if (ret) {
+                       dev_err(imx214->dev, "write_table error: %d\n", ret);
+                       return ret;
+               }
+
+               table += i - 1;
+       }
+
+       return 0;
+}
+
+static int imx214_start_streaming(struct imx214 *imx214)
+{
+       const struct imx214_mode *mode;
+       int ret;
+
+       mutex_lock(&imx214->mutex);
+       ret = imx214_write_table(imx214, mode_table_common);
+       if (ret < 0) {
+               dev_err(imx214->dev, "could not sent common table %d\n", ret);
+               goto error;
+       }
+
+       mode = v4l2_find_nearest_size(imx214_modes,
+                               ARRAY_SIZE(imx214_modes), width, height,
+                               imx214->fmt.width, imx214->fmt.height);
+       ret = imx214_write_table(imx214, mode->reg_table);
+       if (ret < 0) {
+               dev_err(imx214->dev, "could not sent mode table %d\n", ret);
+               goto error;
+       }
+       ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
+       if (ret < 0) {
+               dev_err(imx214->dev, "could not sync v4l2 controls\n");
+               goto error;
+       }
+       ret = regmap_write(imx214->regmap, 0x100, 1);
+       if (ret < 0) {
+               dev_err(imx214->dev, "could not sent start table %d\n", ret);
+               goto error;
+       }
+
+       mutex_unlock(&imx214->mutex);
+       return 0;
+
+error:
+       mutex_unlock(&imx214->mutex);
+       return ret;
+}
+
+static int imx214_stop_streaming(struct imx214 *imx214)
+{
+       int ret;
+
+       ret = regmap_write(imx214->regmap, 0x100, 0);
+       if (ret < 0)
+               dev_err(imx214->dev, "could not sent stop table %d\n",  ret);
+
+       return ret;
+}
+
+static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct imx214 *imx214 = to_imx214(subdev);
+       int ret;
+
+       if (imx214->streaming == enable)
+               return 0;
+
+       if (enable) {
+               ret = pm_runtime_get_sync(imx214->dev);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(imx214->dev);
+                       return ret;
+               }
+
+               ret = imx214_start_streaming(imx214);
+               if (ret < 0)
+                       goto err_rpm_put;
+       } else {
+               ret = imx214_start_streaming(imx214);
+               if (ret < 0)
+                       goto err_rpm_put;
+               pm_runtime_put(imx214->dev);
+       }
+
+       imx214->streaming = enable;
+       return 0;
+
+err_rpm_put:
+       pm_runtime_put(imx214->dev);
+       return ret;
+}
+
+static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_frame_interval *fival)
+{
+       fival->pad = 0;
+       fival->interval.numerator = 1;
+       fival->interval.denominator = IMX214_FPS;
+
+       return 0;
+}
+
+static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_frame_interval_enum *fie)
+{
+       const struct imx214_mode *mode;
+
+       if (fie->index != 0)
+               return -EINVAL;
+
+       mode = v4l2_find_nearest_size(imx214_modes,
+                               ARRAY_SIZE(imx214_modes), width, height,
+                               fie->width, fie->height);
+
+       fie->code = IMX214_MBUS_CODE;
+       fie->width = mode->width;
+       fie->height = mode->height;
+       fie->interval.numerator = 1;
+       fie->interval.denominator = IMX214_FPS;
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx214_video_ops = {
+       .s_stream = imx214_s_stream,
+       .g_frame_interval = imx214_g_frame_interval,
+       .s_frame_interval = imx214_g_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
+       .enum_mbus_code = imx214_enum_mbus_code,
+       .enum_frame_size = imx214_enum_frame_size,
+       .enum_frame_interval = imx214_enum_frame_interval,
+       .get_fmt = imx214_get_format,
+       .set_fmt = imx214_set_format,
+       .get_selection = imx214_get_selection,
+       .init_cfg = imx214_entity_init_cfg,
+};
+
+static const struct v4l2_subdev_ops imx214_subdev_ops = {
+       .core = &imx214_core_ops,
+       .video = &imx214_video_ops,
+       .pad = &imx214_subdev_pad_ops,
+};
+
+static const struct regmap_config sensor_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
+{
+       unsigned int i;
+
+       for (i = 0; i < IMX214_NUM_SUPPLIES; i++)
+               imx214->supplies[i].supply = imx214_supply_name[i];
+
+       return devm_regulator_bulk_get(dev, IMX214_NUM_SUPPLIES,
+                                      imx214->supplies);
+}
+
+static int imx214_parse_fwnode(struct device *dev)
+{
+       struct fwnode_handle *endpoint;
+       struct v4l2_fwnode_endpoint bus_cfg = {
+               .bus_type = V4L2_MBUS_CSI2_DPHY,
+       };
+       unsigned int i;
+       int ret;
+
+       endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+       if (!endpoint) {
+               dev_err(dev, "endpoint node not found\n");
+               return -EINVAL;
+       }
+
+       ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
+       if (ret) {
+               dev_err(dev, "parsing endpoint node failed\n");
+               goto done;
+       }
+
+       for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
+               if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ)
+                       break;
+
+       if (i == bus_cfg.nr_of_link_frequencies) {
+               dev_err(dev, "link-frequencies %d not supported, Please review your DT\n",
+                       IMX214_DEFAULT_LINK_FREQ);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       v4l2_fwnode_endpoint_free(&bus_cfg);
+       fwnode_handle_put(endpoint);
+       return ret;
+}
+
+static int __maybe_unused imx214_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx214 *imx214 = to_imx214(sd);
+
+       if (imx214->streaming)
+               imx214_stop_streaming(imx214);
+
+       return 0;
+}
+
+static int __maybe_unused imx214_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx214 *imx214 = to_imx214(sd);
+       int ret;
+
+       if (imx214->streaming) {
+               ret = imx214_start_streaming(imx214);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+
+error:
+       imx214_stop_streaming(imx214);
+       imx214->streaming = 0;
+       return ret;
+}
+
+static int imx214_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct imx214 *imx214;
+       static const s64 link_freq[] = {
+               IMX214_DEFAULT_LINK_FREQ,
+       };
+       int ret;
+
+       ret = imx214_parse_fwnode(dev);
+       if (ret)
+               return ret;
+
+       imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL);
+       if (!imx214)
+               return -ENOMEM;
+
+       imx214->dev = dev;
+
+       imx214->xclk = devm_clk_get(dev, NULL);
+       if (IS_ERR(imx214->xclk)) {
+               dev_err(dev, "could not get xclk");
+               return PTR_ERR(imx214->xclk);
+       }
+
+       ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ);
+       if (ret) {
+               dev_err(dev, "could not set xclk frequency\n");
+               return ret;
+       }
+
+       ret = imx214_get_regulators(dev, imx214);
+       if (ret < 0) {
+               dev_err(dev, "cannot get regulators\n");
+               return ret;
+       }
+
+       imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(imx214->enable_gpio)) {
+               dev_err(dev, "cannot get enable gpio\n");
+               return PTR_ERR(imx214->enable_gpio);
+       }
+
+       imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
+       if (IS_ERR(imx214->regmap)) {
+               dev_err(dev, "regmap init failed\n");
+               return PTR_ERR(imx214->regmap);
+       }
+
+       v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
+
+       /*
+        * Enable power initially, to avoid warnings
+        * from clk_disable on power_off
+        */
+       imx214_power_on(imx214->dev);
+
+       pm_runtime_set_active(imx214->dev);
+       pm_runtime_enable(imx214->dev);
+       pm_runtime_idle(imx214->dev);
+
+       v4l2_ctrl_handler_init(&imx214->ctrls, 3);
+
+       imx214->pixel_rate = v4l2_ctrl_new_std(&imx214->ctrls, NULL,
+                                              V4L2_CID_PIXEL_RATE, 0,
+                                              IMX214_DEFAULT_PIXEL_RATE, 1,
+                                              IMX214_DEFAULT_PIXEL_RATE);
+       imx214->link_freq = v4l2_ctrl_new_int_menu(&imx214->ctrls, NULL,
+                                                  V4L2_CID_LINK_FREQ,
+                                                  ARRAY_SIZE(link_freq) - 1,
+                                                  0, link_freq);
+       if (imx214->link_freq)
+               imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       /*
+        * WARNING!
+        * Values obtained reverse engineering blobs and/or devices.
+        * Ranges and functionality might be wrong.
+        *
+        * Sony, please release some register set documentation for the
+        * device.
+        *
+        * Yours sincerely, Ricardo.
+        */
+       imx214->exposure = v4l2_ctrl_new_std(&imx214->ctrls, &imx214_ctrl_ops,
+                                            V4L2_CID_EXPOSURE,
+                                            0, 3184, 1, 0x0c70);
+
+       ret = imx214->ctrls.error;
+       if (ret) {
+               dev_err(&client->dev, "%s control init failed (%d)\n",
+                       __func__, ret);
+               goto free_ctrl;
+       }
+
+       imx214->sd.ctrl_handler = &imx214->ctrls;
+       mutex_init(&imx214->mutex);
+       imx214->ctrls.lock = &imx214->mutex;
+
+       imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       imx214->pad.flags = MEDIA_PAD_FL_SOURCE;
+       imx214->sd.dev = &client->dev;
+       imx214->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad);
+       if (ret < 0) {
+               dev_err(dev, "could not register media entity\n");
+               goto free_ctrl;
+       }
+
+       imx214_entity_init_cfg(&imx214->sd, NULL);
+
+       ret = v4l2_async_register_subdev_sensor_common(&imx214->sd);
+       if (ret < 0) {
+               dev_err(dev, "could not register v4l2 device\n");
+               goto free_entity;
+       }
+
+       return 0;
+
+free_entity:
+       media_entity_cleanup(&imx214->sd.entity);
+free_ctrl:
+       mutex_destroy(&imx214->mutex);
+       v4l2_ctrl_handler_free(&imx214->ctrls);
+       pm_runtime_disable(imx214->dev);
+
+       return ret;
+}
+
+static int imx214_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx214 *imx214 = to_imx214(sd);
+
+       v4l2_async_unregister_subdev(&imx214->sd);
+       media_entity_cleanup(&imx214->sd.entity);
+       v4l2_ctrl_handler_free(&imx214->ctrls);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       mutex_destroy(&imx214->mutex);
+
+       return 0;
+}
+
+static const struct of_device_id imx214_of_match[] = {
+       { .compatible = "sony,imx214" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, imx214_of_match);
+
+static const struct dev_pm_ops imx214_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume)
+       SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL)
+};
+
+static struct i2c_driver imx214_i2c_driver = {
+       .driver = {
+               .of_match_table = imx214_of_match,
+               .pm = &imx214_pm_ops,
+               .name  = "imx214",
+       },
+       .probe_new  = imx214_probe,
+       .remove = imx214_remove,
+};
+
+module_i2c_driver(imx214_i2c_driver);
+
+MODULE_DESCRIPTION("Sony IMX214 Camera drier");
+MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
+MODULE_LICENSE("GPL v2");
index 31a1e2294843a4e7f8bad9a53f3ea9d23c795853..f86ae18bc104b313e47324fa79e3166800b7ed58 100644 (file)
 
 /* Test Pattern Control */
 #define IMX258_REG_TEST_PATTERN                0x0600
-#define IMX258_TEST_PATTERN_DISABLE    0
-#define IMX258_TEST_PATTERN_SOLID_COLOR        1
-#define IMX258_TEST_PATTERN_COLOR_BARS 2
-#define IMX258_TEST_PATTERN_GREY_COLOR 3
-#define IMX258_TEST_PATTERN_PN9                4
 
 /* Orientation */
 #define REG_MIRROR_FLIP_CONTROL                0x0101
@@ -504,18 +499,10 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 
 static const char * const imx258_test_pattern_menu[] = {
        "Disabled",
-       "Color Bars",
-       "Solid Color",
-       "Grey Color Bars",
-       "PN9"
-};
-
-static const int imx258_test_pattern_val[] = {
-       IMX258_TEST_PATTERN_DISABLE,
-       IMX258_TEST_PATTERN_COLOR_BARS,
-       IMX258_TEST_PATTERN_SOLID_COLOR,
-       IMX258_TEST_PATTERN_GREY_COLOR,
-       IMX258_TEST_PATTERN_PN9,
+       "Solid Colour",
+       "Eight Vertical Colour Bars",
+       "Colour Bars With Fade to Grey",
+       "Pseudorandom Sequence (PN9)",
 };
 
 /* Configurations for supported link frequencies */
@@ -778,13 +765,10 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_TEST_PATTERN:
                ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
                                IMX258_REG_VALUE_16BIT,
-                               imx258_test_pattern_val[ctrl->val]);
-
+                               ctrl->val);
                ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
                                IMX258_REG_VALUE_08BIT,
-                               ctrl->val == imx258_test_pattern_val
-                               [IMX258_TEST_PATTERN_DISABLE] ?
-                               REG_CONFIG_MIRROR_FLIP :
+                               !ctrl->val ? REG_CONFIG_MIRROR_FLIP :
                                REG_CONFIG_FLIP_TEST_PATTERN);
                break;
        default:
index 11c69281692ebe8078a15d815435061b83112afb..5fac7fd3263417a04a7d52ce874c5d63550bbe6b 100644 (file)
@@ -619,16 +619,19 @@ static int imx274_write_table(struct stimx274 *priv, const struct reg_8 table[])
 
 static inline int imx274_read_reg(struct stimx274 *priv, u16 addr, u8 *val)
 {
+       unsigned int uint_val;
        int err;
 
-       err = regmap_read(priv->regmap, addr, (unsigned int *)val);
+       err = regmap_read(priv->regmap, addr, &uint_val);
        if (err)
                dev_err(&priv->client->dev,
                        "%s : i2c read failed, addr = %x\n", __func__, addr);
        else
                dev_dbg(&priv->client->dev,
                        "%s : addr 0x%x, val=0x%x\n", __func__,
-                       addr, *val);
+                       addr, uint_val);
+
+       *val = uint_val;
        return err;
 }
 
@@ -1901,7 +1904,7 @@ static int imx274_probe(struct i2c_client *client,
        imx274_reset(imx274, 1);
 
        /* initialize controls */
-       ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 2);
+       ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 4);
        if (ret < 0) {
                dev_err(&client->dev,
                        "%s : ctrl handler init Failed\n", __func__);
index 0d3e27812b936cfed31cf737340123692ecde276..17c2e4b41221ecb41b14eb599a1fbdb77e7eb48c 100644 (file)
@@ -1648,10 +1648,10 @@ static const struct imx319_reg mode_1280x720_regs[] = {
 
 static const char * const imx319_test_pattern_menu[] = {
        "Disabled",
-       "100% color bars",
-       "Solid color",
-       "Fade to gray color bars",
-       "PN9"
+       "Solid Colour",
+       "Eight Vertical Colour Bars",
+       "Colour Bars With Fade to Grey",
+       "Pseudorandom Sequence (PN9)",
 };
 
 /* supported link frequencies */
index 20c8eea5db4bd9a2a4325cff3505ec9a7e2b91dd..bed293b60e504bb50cb3678708dd7b01c2f87250 100644 (file)
@@ -876,10 +876,10 @@ static const struct imx355_reg mode_820x616_regs[] = {
 
 static const char * const imx355_test_pattern_menu[] = {
        "Disabled",
-       "100% color bars",
-       "Solid color",
-       "Fade to gray color bars",
-       "PN9"
+       "Solid Colour",
+       "Eight Vertical Colour Bars",
+       "Colour Bars With Fade to Grey",
+       "Pseudorandom Sequence (PN9)",
 };
 
 /* supported link frequencies */
index 1395986a07bb80faa85c938ece6bf917c303e0a3..d639b9bcf64a8ced3e0fe19a6f1c49ed70982bb9 100644 (file)
 #include <linux/delay.h>
 #include <linux/v4l2-mediabus.h>
 #include <linux/module.h>
+#include <linux/property.h>
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
 
 /*
  * MT9M111, MT9M112 and MT9M131:
 #define MT9M111_REDUCER_XSIZE_A                0x1a7
 #define MT9M111_REDUCER_YZOOM_A                0x1a9
 #define MT9M111_REDUCER_YSIZE_A                0x1aa
+#define MT9M111_EFFECTS_MODE           0x1e2
 
 #define MT9M111_OUTPUT_FORMAT_CTRL2_A  0x13a
 #define MT9M111_OUTPUT_FORMAT_CTRL2_B  0x19b
 #define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
 #define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B        (1 << 0)
 #define MT9M111_TPG_SEL_MASK           GENMASK(2, 0)
+#define MT9M111_EFFECTS_MODE_MASK      GENMASK(2, 0)
+#define MT9M111_RM_PWR_MASK            BIT(10)
+#define MT9M111_RM_SKIP2_MASK          GENMASK(3, 2)
 
 /*
  * Camera control register addresses (0x200..0x2ff not implemented)
@@ -204,6 +211,23 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
        {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 };
 
+enum mt9m111_mode_id {
+       MT9M111_MODE_SXGA_8FPS,
+       MT9M111_MODE_SXGA_15FPS,
+       MT9M111_MODE_QSXGA_30FPS,
+       MT9M111_NUM_MODES,
+};
+
+struct mt9m111_mode_info {
+       unsigned int sensor_w;
+       unsigned int sensor_h;
+       unsigned int max_image_w;
+       unsigned int max_image_h;
+       unsigned int max_fps;
+       unsigned int reg_val;
+       unsigned int reg_mask;
+};
+
 struct mt9m111 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
@@ -213,15 +237,51 @@ struct mt9m111 {
        struct v4l2_clk *clk;
        unsigned int width;     /* output */
        unsigned int height;    /* sizes */
+       struct v4l2_fract frame_interval;
+       const struct mt9m111_mode_info *current_mode;
        struct mutex power_lock; /* lock to protect power_count */
        int power_count;
        const struct mt9m111_datafmt *fmt;
        int lastpage;   /* PageMap cache value */
+       bool is_streaming;
+       /* user point of view - 0: falling 1: rising edge */
+       unsigned int pclk_sample:1;
 #ifdef CONFIG_MEDIA_CONTROLLER
        struct media_pad pad;
 #endif
 };
 
+static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = {
+       [MT9M111_MODE_SXGA_8FPS] = {
+               .sensor_w = 1280,
+               .sensor_h = 1024,
+               .max_image_w = 1280,
+               .max_image_h = 1024,
+               .max_fps = 8,
+               .reg_val = MT9M111_RM_LOW_POWER_RD,
+               .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
+       },
+       [MT9M111_MODE_SXGA_15FPS] = {
+               .sensor_w = 1280,
+               .sensor_h = 1024,
+               .max_image_w = 1280,
+               .max_image_h = 1024,
+               .max_fps = 15,
+               .reg_val = MT9M111_RM_FULL_POWER_RD,
+               .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
+       },
+       [MT9M111_MODE_QSXGA_30FPS] = {
+               .sensor_w = 1280,
+               .sensor_h = 1024,
+               .max_image_w = 640,
+               .max_image_h = 512,
+               .max_fps = 30,
+               .reg_val = MT9M111_RM_LOW_POWER_RD | MT9M111_RM_COL_SKIP_2X |
+                          MT9M111_RM_ROW_SKIP_2X,
+               .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
+       },
+};
+
 /* Find a data format by a pixel code */
 static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
                                                u32 code)
@@ -538,6 +598,10 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
                return -EINVAL;
        }
 
+       /* receiver samples on falling edge, chip-hw default is rising */
+       if (mt9m111->pclk_sample == 0)
+               mask_outfmt2 |= MT9M111_OUTFMT_INV_PIX_CLOCK;
+
        ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
                               data_outfmt2, mask_outfmt2);
        if (!ret)
@@ -559,6 +623,9 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
        bool bayer;
        int ret;
 
+       if (mt9m111->is_streaming)
+               return -EBUSY;
+
        if (format->pad)
                return -EINVAL;
 
@@ -611,6 +678,61 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
        return ret;
 }
 
+static const struct mt9m111_mode_info *
+mt9m111_find_mode(struct mt9m111 *mt9m111, unsigned int req_fps,
+                 unsigned int width, unsigned int height)
+{
+       const struct mt9m111_mode_info *mode;
+       struct v4l2_rect *sensor_rect = &mt9m111->rect;
+       unsigned int gap, gap_best = (unsigned int) -1;
+       int i, best_gap_idx = MT9M111_MODE_SXGA_15FPS;
+       bool skip_30fps = false;
+
+       /*
+        * The fps selection is based on the row, column skipping mechanism.
+        * So ensure that the sensor window is set to default else the fps
+        * aren't calculated correctly within the sensor hw.
+        */
+       if (sensor_rect->width != MT9M111_MAX_WIDTH ||
+           sensor_rect->height != MT9M111_MAX_HEIGHT) {
+               dev_info(mt9m111->subdev.dev,
+                        "Framerate selection is not supported for cropped "
+                        "images\n");
+               return NULL;
+       }
+
+       /* 30fps only supported for images not exceeding 640x512 */
+       if (width > MT9M111_MAX_WIDTH / 2 || height > MT9M111_MAX_HEIGHT / 2) {
+               dev_dbg(mt9m111->subdev.dev,
+                       "Framerates > 15fps are supported only for images "
+                       "not exceeding 640x512\n");
+               skip_30fps = true;
+       }
+
+       /* find best matched fps */
+       for (i = 0; i < MT9M111_NUM_MODES; i++) {
+               unsigned int fps = mt9m111_mode_data[i].max_fps;
+
+               if (fps == 30 && skip_30fps)
+                       continue;
+
+               gap = abs(fps - req_fps);
+               if (gap < gap_best) {
+                       best_gap_idx = i;
+                       gap_best = gap;
+               }
+       }
+
+       /*
+        * Use context a/b default timing values instead of calculate blanking
+        * timing values.
+        */
+       mode = &mt9m111_mode_data[best_gap_idx];
+       mt9m111->ctx = (best_gap_idx == MT9M111_MODE_QSXGA_30FPS) ? &context_a :
+                                                                   &context_b;
+       return mode;
+}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9m111_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
@@ -726,6 +848,29 @@ static int mt9m111_set_test_pattern(struct mt9m111 *mt9m111, int val)
                                MT9M111_TPG_SEL_MASK);
 }
 
+static int mt9m111_set_colorfx(struct mt9m111 *mt9m111, int val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+       static const struct v4l2_control colorfx[] = {
+               { V4L2_COLORFX_NONE,            0 },
+               { V4L2_COLORFX_BW,              1 },
+               { V4L2_COLORFX_SEPIA,           2 },
+               { V4L2_COLORFX_NEGATIVE,        3 },
+               { V4L2_COLORFX_SOLARIZATION,    4 },
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
+               if (colorfx[i].id == val) {
+                       return mt9m111_reg_mask(client, MT9M111_EFFECTS_MODE,
+                                               colorfx[i].value,
+                                               MT9M111_EFFECTS_MODE_MASK);
+               }
+       }
+
+       return -EINVAL;
+}
+
 static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct mt9m111 *mt9m111 = container_of(ctrl->handler,
@@ -746,6 +891,8 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
                return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
        case V4L2_CID_TEST_PATTERN:
                return mt9m111_set_test_pattern(mt9m111, ctrl->val);
+       case V4L2_CID_COLORFX:
+               return mt9m111_set_colorfx(mt9m111, ctrl->val);
        }
 
        return -EINVAL;
@@ -771,11 +918,16 @@ static int mt9m111_suspend(struct mt9m111 *mt9m111)
 
 static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+
        mt9m111_set_context(mt9m111, mt9m111->ctx);
        mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
        mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
                        mt9m111->width, mt9m111->height, mt9m111->fmt->code);
        v4l2_ctrl_handler_setup(&mt9m111->hdl);
+       mt9m111_reg_mask(client, mt9m111->ctx->read_mode,
+                        mt9m111->current_mode->reg_val,
+                        mt9m111->current_mode->reg_mask);
 }
 
 static int mt9m111_resume(struct mt9m111 *mt9m111)
@@ -862,12 +1014,62 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
        .s_power        = mt9m111_s_power,
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m111_g_register,
        .s_register     = mt9m111_s_register,
 #endif
 };
 
+static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *fi)
+{
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+       fi->interval = mt9m111->frame_interval;
+
+       return 0;
+}
+
+static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *fi)
+{
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+       const struct mt9m111_mode_info *mode;
+       struct v4l2_fract *fract = &fi->interval;
+       int fps;
+
+       if (mt9m111->is_streaming)
+               return -EBUSY;
+
+       if (fi->pad != 0)
+               return -EINVAL;
+
+       if (fract->numerator == 0) {
+               fract->denominator = 30;
+               fract->numerator = 1;
+       }
+
+       fps = DIV_ROUND_CLOSEST(fract->denominator, fract->numerator);
+
+       /* Find best fitting mode. Do not update the mode if no one was found. */
+       mode = mt9m111_find_mode(mt9m111, fps, mt9m111->width, mt9m111->height);
+       if (!mode)
+               return 0;
+
+       if (mode->max_fps != fps) {
+               fract->denominator = mode->max_fps;
+               fract->numerator = 1;
+       }
+
+       mt9m111->current_mode = mode;
+       mt9m111->frame_interval = fi->interval;
+
+       return 0;
+}
+
 static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
                struct v4l2_subdev_pad_config *cfg,
                struct v4l2_subdev_mbus_code_enum *code)
@@ -879,12 +1081,26 @@ static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+       mt9m111->is_streaming = !!enable;
+       return 0;
+}
+
 static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
                                struct v4l2_mbus_config *cfg)
 {
-       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+
+       cfg->flags = V4L2_MBUS_MASTER |
                V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
                V4L2_MBUS_DATA_ACTIVE_HIGH;
+
+       cfg->flags |= mt9m111->pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING :
+               V4L2_MBUS_PCLK_SAMPLE_FALLING;
+
        cfg->type = V4L2_MBUS_PARALLEL;
 
        return 0;
@@ -892,6 +1108,9 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
        .g_mbus_config  = mt9m111_g_mbus_config,
+       .s_stream       = mt9m111_s_stream,
+       .g_frame_interval = mt9m111_g_frame_interval,
+       .s_frame_interval = mt9m111_s_frame_interval,
 };
 
 static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
@@ -951,6 +1170,30 @@ done:
        return ret;
 }
 
+static int mt9m111_probe_fw(struct i2c_client *client, struct mt9m111 *mt9m111)
+{
+       struct v4l2_fwnode_endpoint bus_cfg = {
+               .bus_type = V4L2_MBUS_PARALLEL
+       };
+       struct fwnode_handle *np;
+       int ret;
+
+       np = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+       if (!np)
+               return -EINVAL;
+
+       ret = v4l2_fwnode_endpoint_parse(np, &bus_cfg);
+       if (ret)
+               goto out_put_fw;
+
+       mt9m111->pclk_sample = !!(bus_cfg.bus.parallel.flags &
+                                 V4L2_MBUS_PCLK_SAMPLE_RISING);
+
+out_put_fw:
+       fwnode_handle_put(np);
+       return ret;
+}
+
 static int mt9m111_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
@@ -968,6 +1211,10 @@ static int mt9m111_probe(struct i2c_client *client,
        if (!mt9m111)
                return -ENOMEM;
 
+       ret = mt9m111_probe_fw(client, mt9m111);
+       if (ret)
+               return ret;
+
        mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
        if (IS_ERR(mt9m111->clk))
                return PTR_ERR(mt9m111->clk);
@@ -976,9 +1223,10 @@ static int mt9m111_probe(struct i2c_client *client,
        mt9m111->ctx = &context_b;
 
        v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
-       mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+                                V4L2_SUBDEV_FL_HAS_EVENTS;
 
-       v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
+       v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
        v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
                        V4L2_CID_VFLIP, 0, 1, 1, 0);
        v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
@@ -994,6 +1242,14 @@ static int mt9m111_probe(struct i2c_client *client,
                        &mt9m111_ctrl_ops, V4L2_CID_TEST_PATTERN,
                        ARRAY_SIZE(mt9m111_test_pattern_menu) - 1, 0, 0,
                        mt9m111_test_pattern_menu);
+       v4l2_ctrl_new_std_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
+                       V4L2_CID_COLORFX, V4L2_COLORFX_SOLARIZATION,
+                       ~(BIT(V4L2_COLORFX_NONE) |
+                               BIT(V4L2_COLORFX_BW) |
+                               BIT(V4L2_COLORFX_SEPIA) |
+                               BIT(V4L2_COLORFX_NEGATIVE) |
+                               BIT(V4L2_COLORFX_SOLARIZATION)),
+                       V4L2_COLORFX_NONE);
        mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
        if (mt9m111->hdl.error) {
                ret = mt9m111->hdl.error;
@@ -1008,6 +1264,10 @@ static int mt9m111_probe(struct i2c_client *client,
                goto out_hdlfree;
 #endif
 
+       mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS];
+       mt9m111->frame_interval.numerator = 1;
+       mt9m111->frame_interval.denominator = mt9m111->current_mode->max_fps;
+
        /* Second stage probe - when a capture adapter is there */
        mt9m111->rect.left      = MT9M111_MIN_DARK_COLS;
        mt9m111->rect.top       = MT9M111_MIN_DARK_ROWS;
index c8bbc1f522619504e8053f825183fa71865bb5bb..45bb872db3c56c7b7efaf3a16f8a2da3e8e49eb0 100644 (file)
@@ -1612,7 +1612,8 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
                                OV13858_NUM_OF_LINK_FREQS - 1,
                                0,
                                link_freq_menu_items);
-       ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       if (ov13858->link_freq)
+               ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
        pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
@@ -1635,7 +1636,8 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
        ov13858->hblank = v4l2_ctrl_new_std(
                                ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK,
                                hblank, hblank, 1, hblank);
-       ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       if (ov13858->hblank)
+               ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        exposure_max = mode->vts_def - 8;
        ov13858->exposure = v4l2_ctrl_new_std(
index 20a8853ba1e29a815386698c10756a5250c1e098..5d2d6735cc78dcfdb40eac44a613cfd4cd36a663 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/videodev2.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-image-sizes.h>
@@ -705,6 +706,11 @@ err:
        return ret;
 }
 
+static const char * const ov2640_test_pattern_menu[] = {
+       "Disabled",
+       "Eight Vertical Colour Bars",
+};
+
 /*
  * functions
  */
@@ -740,6 +746,9 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_HFLIP:
                val = ctrl->val ? REG04_HFLIP_IMG : 0x00;
                return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
+       case V4L2_CID_TEST_PATTERN:
+               val = ctrl->val ? COM7_COLOR_BAR_TEST : 0x00;
+               return ov2640_mask_set(client, COM7, COM7_COLOR_BAR_TEST, val);
        }
 
        return -EINVAL;
@@ -1088,6 +1097,9 @@ static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ov2640_g_register,
        .s_register     = ov2640_s_register,
@@ -1182,14 +1194,19 @@ static int ov2640_probe(struct i2c_client *client,
                goto err_clk;
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
-       priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+                             V4L2_SUBDEV_FL_HAS_EVENTS;
        mutex_init(&priv->lock);
-       v4l2_ctrl_handler_init(&priv->hdl, 2);
+       v4l2_ctrl_handler_init(&priv->hdl, 3);
        priv->hdl.lock = &priv->lock;
        v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
                        V4L2_CID_VFLIP, 0, 1, 1, 0);
        v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
                        V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov2640_ctrl_ops,
+                       V4L2_CID_TEST_PATTERN,
+                       ARRAY_SIZE(ov2640_test_pattern_menu) - 1, 0, 0,
+                       ov2640_test_pattern_menu);
        priv->subdev.ctrl_handler = &priv->hdl;
        if (priv->hdl.error) {
                ret = priv->hdl.error;
index 0e34e15b67b336791a4098f8cf5d5a726dcd91f2..b10bcfabaeeb05a2bc21283408b4f00062b7d116 100644 (file)
@@ -568,10 +568,6 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
        if (ret < 0)
                return ret;
 
-       ret = ov2680_mode_restore(sensor);
-       if (ret < 0)
-               goto disable;
-
        sensor->is_enabled = true;
 
        /* Set clock lane into LP-11 state */
@@ -580,12 +576,6 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
        ov2680_stream_disable(sensor);
 
        return 0;
-
-disable:
-       dev_err(dev, "failed to enable sensor: %d\n", ret);
-       ov2680_power_off(sensor);
-
-       return ret;
 }
 
 static int ov2680_s_power(struct v4l2_subdev *sd, int on)
@@ -606,6 +596,8 @@ static int ov2680_s_power(struct v4l2_subdev *sd, int on)
                ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
                if (ret < 0)
                        return ret;
+
+               ret = ov2680_mode_restore(sensor);
        }
 
        return ret;
index eaefdb58653b700bb639adc6b26a44e0f5fd514c..bef3f3aae0ed8f01fdf30b684c9ae600cc9a8136 100644 (file)
@@ -25,6 +25,7 @@
 #include <media/v4l2-async.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
 
@@ -94,9 +95,6 @@
 #define OV5640_REG_SDE_CTRL5           0x5585
 #define OV5640_REG_AVG_READOUT         0x56a1
 
-#define OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT     1
-#define OV5640_SCLK_ROOT_DIVIDER_DEFAULT       2
-
 enum ov5640_mode_id {
        OV5640_MODE_QCIF_176_144 = 0,
        OV5640_MODE_QVGA_320_240,
@@ -113,6 +111,7 @@ enum ov5640_mode_id {
 enum ov5640_frame_rate {
        OV5640_15_FPS = 0,
        OV5640_30_FPS,
+       OV5640_60_FPS,
        OV5640_NUM_FRAMERATES,
 };
 
@@ -141,6 +140,7 @@ MODULE_PARM_DESC(virtual_channel,
 static const int ov5640_framerates[] = {
        [OV5640_15_FPS] = 15,
        [OV5640_30_FPS] = 30,
+       [OV5640_60_FPS] = 60,
 };
 
 /* regulator supplies */
@@ -261,8 +261,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
 static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
        {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
        {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
-       {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
-       {0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0},
+       {0x3630, 0x36, 0, 0},
        {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
        {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
        {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -344,27 +343,8 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
        {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
 };
 
-static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
-       {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_VGA_640_480[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -382,28 +362,8 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
-       {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
-       {0x3035, 0x12, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_XGA_1024_768[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -421,8 +381,8 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
-       {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QVGA_320_240[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -440,8 +400,8 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QCIF_176_144[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -459,46 +419,8 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
-       {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
-       {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_NTSC_720_480[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -516,27 +438,8 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
-       {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_PAL_720_576[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -554,48 +457,8 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
        {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
-       {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
-       {0x3008, 0x42, 0, 0},
-       {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x31, 0, 0},
-       {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
-       {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
-       {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
-       {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
-       {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
-       {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
-       {0x3008, 0x02, 0, 0}, {0x3503, 0,    0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
-       {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+static const struct reg_value ov5640_setting_720P_1280_720[] = {
+       {0x3c07, 0x07, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x31, 0, 0},
        {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -613,9 +476,9 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
        {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
+static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
        {0x3008, 0x42, 0, 0},
-       {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x11, 0, 0},
        {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -630,8 +493,8 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
        {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
        {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
        {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
-       {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+       {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
+       {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
        {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
@@ -643,43 +506,10 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
        {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
        {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
        {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
-       {0x3503, 0, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
-       {0x3008, 0x42, 0, 0},
-       {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3814, 0x11, 0, 0},
-       {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-       {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
-       {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
-       {0x3810, 0x00, 0, 0},
-       {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
-       {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
-       {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
-       {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-       {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-       {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-       {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
-       {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-       {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0},
-       {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
-       {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-       {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
-       {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
-       {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
-       {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
-       {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
-       {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
-       {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
-       {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
-       {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
-       {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
 };
 
-static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
-       {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
+       {0x3c07, 0x08, 0, 0},
        {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
        {0x3814, 0x11, 0, 0},
        {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -705,79 +535,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = {
 };
 
 static const struct ov5640_mode_info
-ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = {
-       {
-               {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
-                176, 1896, 144, 984,
-                ov5640_setting_15fps_QCIF_176_144,
-                ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
-               {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
-                320, 1896, 240, 984,
-                ov5640_setting_15fps_QVGA_320_240,
-                ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
-               {OV5640_MODE_VGA_640_480, SUBSAMPLING,
-                640, 1896, 480, 1080,
-                ov5640_setting_15fps_VGA_640_480,
-                ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
-               {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
-                720, 1896, 480, 984,
-                ov5640_setting_15fps_NTSC_720_480,
-                ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
-               {OV5640_MODE_PAL_720_576, SUBSAMPLING,
-                720, 1896, 576, 984,
-                ov5640_setting_15fps_PAL_720_576,
-                ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
-               {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
-                1024, 1896, 768, 1080,
-                ov5640_setting_15fps_XGA_1024_768,
-                ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
-               {OV5640_MODE_720P_1280_720, SUBSAMPLING,
-                1280, 1892, 720, 740,
-                ov5640_setting_15fps_720P_1280_720,
-                ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
-               {OV5640_MODE_1080P_1920_1080, SCALING,
-                1920, 2500, 1080, 1120,
-                ov5640_setting_15fps_1080P_1920_1080,
-                ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
-               {OV5640_MODE_QSXGA_2592_1944, SCALING,
-                2592, 2844, 1944, 1968,
-                ov5640_setting_15fps_QSXGA_2592_1944,
-                ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
-       }, {
-               {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
-                176, 1896, 144, 984,
-                ov5640_setting_30fps_QCIF_176_144,
-                ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
-               {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
-                320, 1896, 240, 984,
-                ov5640_setting_30fps_QVGA_320_240,
-                ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
-               {OV5640_MODE_VGA_640_480, SUBSAMPLING,
-                640, 1896, 480, 1080,
-                ov5640_setting_30fps_VGA_640_480,
-                ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
-               {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
-                720, 1896, 480, 984,
-                ov5640_setting_30fps_NTSC_720_480,
-                ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
-               {OV5640_MODE_PAL_720_576, SUBSAMPLING,
-                720, 1896, 576, 984,
-                ov5640_setting_30fps_PAL_720_576,
-                ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
-               {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
-                1024, 1896, 768, 1080,
-                ov5640_setting_30fps_XGA_1024_768,
-                ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
-               {OV5640_MODE_720P_1280_720, SUBSAMPLING,
-                1280, 1892, 720, 740,
-                ov5640_setting_30fps_720P_1280_720,
-                ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
-               {OV5640_MODE_1080P_1920_1080, SCALING,
-                1920, 2500, 1080, 1120,
-                ov5640_setting_30fps_1080P_1920_1080,
-                ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
-               {OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0},
-       },
+ov5640_mode_data[OV5640_NUM_MODES] = {
+       {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
+        176, 1896, 144, 984,
+        ov5640_setting_QCIF_176_144,
+        ARRAY_SIZE(ov5640_setting_QCIF_176_144)},
+       {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
+        320, 1896, 240, 984,
+        ov5640_setting_QVGA_320_240,
+        ARRAY_SIZE(ov5640_setting_QVGA_320_240)},
+       {OV5640_MODE_VGA_640_480, SUBSAMPLING,
+        640, 1896, 480, 1080,
+        ov5640_setting_VGA_640_480,
+        ARRAY_SIZE(ov5640_setting_VGA_640_480)},
+       {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
+        720, 1896, 480, 984,
+        ov5640_setting_NTSC_720_480,
+        ARRAY_SIZE(ov5640_setting_NTSC_720_480)},
+       {OV5640_MODE_PAL_720_576, SUBSAMPLING,
+        720, 1896, 576, 984,
+        ov5640_setting_PAL_720_576,
+        ARRAY_SIZE(ov5640_setting_PAL_720_576)},
+       {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
+        1024, 1896, 768, 1080,
+        ov5640_setting_XGA_1024_768,
+        ARRAY_SIZE(ov5640_setting_XGA_1024_768)},
+       {OV5640_MODE_720P_1280_720, SUBSAMPLING,
+        1280, 1892, 720, 740,
+        ov5640_setting_720P_1280_720,
+        ARRAY_SIZE(ov5640_setting_720P_1280_720)},
+       {OV5640_MODE_1080P_1920_1080, SCALING,
+        1920, 2500, 1080, 1120,
+        ov5640_setting_1080P_1920_1080,
+        ARRAY_SIZE(ov5640_setting_1080P_1920_1080)},
+       {OV5640_MODE_QSXGA_2592_1944, SCALING,
+        2592, 2844, 1944, 1968,
+        ov5640_setting_QSXGA_2592_1944,
+        ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944)},
 };
 
 static int ov5640_init_slave_id(struct ov5640_dev *sensor)
@@ -909,6 +703,333 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
        return ov5640_write_reg(sensor, reg, val);
 }
 
+/*
+ * After trying the various combinations, reading various
+ * documentations spreaded around the net, and from the various
+ * feedback, the clock tree is probably as follows:
+ *
+ *   +--------------+
+ *   |  Ext. Clock  |
+ *   +-+------------+
+ *     |  +----------+
+ *     +->|   PLL1   | - reg 0x3036, for the multiplier
+ *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
+ *          |  +--------------+
+ *          +->| System Clock |  - reg 0x3035, bits 4-7
+ *             +-+------------+
+ *               |  +--------------+
+ *               +->| MIPI Divider | - reg 0x3035, bits 0-3
+ *               |  +-+------------+
+ *               |    +----------------> MIPI SCLK
+ *               |    +  +-----+
+ *               |    +->| / 2 |-------> MIPI BIT CLK
+ *               |       +-----+
+ *               |  +--------------+
+ *               +->| PLL Root Div | - reg 0x3037, bit 4
+ *                  +-+------------+
+ *                    |  +---------+
+ *                    +->| Bit Div | - reg 0x3035, bits 0-3
+ *                       +-+-------+
+ *                         |  +-------------+
+ *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
+ *                         |  +-+-----------+
+ *                         |    +---------------> SCLK
+ *                         |  +-------------+
+ *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
+ *                         |  +-+-----------+
+ *                         |    +---------------> SCLK 2X
+ *                         |  +-------------+
+ *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
+ *                            ++------------+
+ *                             +  +-----------+
+ *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
+ *                                +-----+-----+
+ *                                       +------------> PCLK
+ *
+ * This is deviating from the datasheet at least for the register
+ * 0x3108, since it's said here that the PCLK would be clocked from
+ * the PLL.
+ *
+ * There seems to be also (unverified) constraints:
+ *  - the PLL pre-divider output rate should be in the 4-27MHz range
+ *  - the PLL multiplier output rate should be in the 500-1000MHz range
+ *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
+ *
+ * In the two latter cases, these constraints are met since our
+ * factors are hardcoded. If we were to change that, we would need to
+ * take this into account. The only varying parts are the PLL
+ * multiplier and the system clock divider, which are shared between
+ * all these clocks so won't cause any issue.
+ */
+
+/*
+ * This is supposed to be ranging from 1 to 8, but the value is always
+ * set to 3 in the vendor kernels.
+ */
+#define OV5640_PLL_PREDIV      3
+
+#define OV5640_PLL_MULT_MIN    4
+#define OV5640_PLL_MULT_MAX    252
+
+/*
+ * This is supposed to be ranging from 1 to 16, but the value is
+ * always set to either 1 or 2 in the vendor kernels.
+ */
+#define OV5640_SYSDIV_MIN      1
+#define OV5640_SYSDIV_MAX      16
+
+/*
+ * Hardcode these values for scaler and non-scaler modes.
+ * FIXME: to be re-calcualted for 1 data lanes setups
+ */
+#define OV5640_MIPI_DIV_PCLK   2
+#define OV5640_MIPI_DIV_SCLK   1
+
+/*
+ * This is supposed to be ranging from 1 to 2, but the value is always
+ * set to 2 in the vendor kernels.
+ */
+#define OV5640_PLL_ROOT_DIV                    2
+#define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2                BIT(4)
+
+/*
+ * We only supports 8-bit formats at the moment
+ */
+#define OV5640_BIT_DIV                         2
+#define OV5640_PLL_CTRL0_MIPI_MODE_8BIT                0x08
+
+/*
+ * This is supposed to be ranging from 1 to 8, but the value is always
+ * set to 2 in the vendor kernels.
+ */
+#define OV5640_SCLK_ROOT_DIV   2
+
+/*
+ * This is hardcoded so that the consistency is maintained between SCLK and
+ * SCLK 2x.
+ */
+#define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
+
+/*
+ * This is supposed to be ranging from 1 to 8, but the value is always
+ * set to 1 in the vendor kernels.
+ */
+#define OV5640_PCLK_ROOT_DIV                   1
+#define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS     0x00
+
+static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
+                                           u8 pll_prediv, u8 pll_mult,
+                                           u8 sysdiv)
+{
+       unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
+
+       /* PLL1 output cannot exceed 1GHz. */
+       if (sysclk / 1000000 > 1000)
+               return 0;
+
+       return sysclk / sysdiv;
+}
+
+static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
+                                        unsigned long rate,
+                                        u8 *pll_prediv, u8 *pll_mult,
+                                        u8 *sysdiv)
+{
+       unsigned long best = ~0;
+       u8 best_sysdiv = 1, best_mult = 1;
+       u8 _sysdiv, _pll_mult;
+
+       for (_sysdiv = OV5640_SYSDIV_MIN;
+            _sysdiv <= OV5640_SYSDIV_MAX;
+            _sysdiv++) {
+               for (_pll_mult = OV5640_PLL_MULT_MIN;
+                    _pll_mult <= OV5640_PLL_MULT_MAX;
+                    _pll_mult++) {
+                       unsigned long _rate;
+
+                       /*
+                        * The PLL multiplier cannot be odd if above
+                        * 127.
+                        */
+                       if (_pll_mult > 127 && (_pll_mult % 2))
+                               continue;
+
+                       _rate = ov5640_compute_sys_clk(sensor,
+                                                      OV5640_PLL_PREDIV,
+                                                      _pll_mult, _sysdiv);
+
+                       /*
+                        * We have reached the maximum allowed PLL1 output,
+                        * increase sysdiv.
+                        */
+                       if (!rate)
+                               break;
+
+                       /*
+                        * Prefer rates above the expected clock rate than
+                        * below, even if that means being less precise.
+                        */
+                       if (_rate < rate)
+                               continue;
+
+                       if (abs(rate - _rate) < abs(rate - best)) {
+                               best = _rate;
+                               best_sysdiv = _sysdiv;
+                               best_mult = _pll_mult;
+                       }
+
+                       if (_rate == rate)
+                               goto out;
+               }
+       }
+
+out:
+       *sysdiv = best_sysdiv;
+       *pll_prediv = OV5640_PLL_PREDIV;
+       *pll_mult = best_mult;
+
+       return best;
+}
+
+/*
+ * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
+ *                         for the MIPI CSI-2 output.
+ *
+ * @rate: The requested bandwidth per lane in bytes per second.
+ *       'Bandwidth Per Lane' is calculated as:
+ *       bpl = HTOT * VTOT * FPS * bpp / num_lanes;
+ *
+ * This function use the requested bandwidth to calculate:
+ * - sample_rate = bpl / (bpp / num_lanes);
+ *              = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
+ *
+ * - mipi_sclk   = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)
+ *
+ * with these fixed parameters:
+ *     PLL_RDIV        = 2;
+ *     BIT_DIVIDER     = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
+ *     PCLK_DIV        = 1;
+ *
+ * The MIPI clock generation differs for modes that use the scaler and modes
+ * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
+ * BIT CLk, and thus:
+ *
+ * - mipi_sclk = bpl / MIPI_DIV / 2;
+ *   MIPI_DIV = 1;
+ *
+ * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
+ * from the pixel clock, and thus:
+ *
+ * - sample_rate = bpl / (bpp / num_lanes);
+ *              = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
+ *              = bpl / (4 * MIPI_DIV / num_lanes);
+ * - MIPI_DIV   = bpp / (4 * num_lanes);
+ *
+ * FIXME: this have been tested with 16bpp and 2 lanes setup only.
+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
+ * above formula for setups with 1 lane or image formats with different bpp.
+ *
+ * FIXME: this deviates from the sensor manual documentation which is quite
+ * thin on the MIPI clock tree generation part.
+ */
+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
+                               unsigned long rate)
+{
+       const struct ov5640_mode_info *mode = sensor->current_mode;
+       u8 prediv, mult, sysdiv;
+       u8 mipi_div;
+       int ret;
+
+       /*
+        * 1280x720 is reported to use 'SUBSAMPLING' only,
+        * but according to the sensor manual it goes through the
+        * scaler before subsampling.
+        */
+       if (mode->dn_mode == SCALING ||
+          (mode->id == OV5640_MODE_720P_1280_720))
+               mipi_div = OV5640_MIPI_DIV_SCLK;
+       else
+               mipi_div = OV5640_MIPI_DIV_PCLK;
+
+       ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
+                            0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
+                            0xff, sysdiv << 4 | mipi_div);
+       if (ret)
+               return ret;
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
+       if (ret)
+               return ret;
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
+                            0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
+       if (ret)
+               return ret;
+
+       return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
+                             0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
+}
+
+static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
+                                     unsigned long rate,
+                                     u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
+                                     u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
+{
+       unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
+                               OV5640_PCLK_ROOT_DIV;
+
+       _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
+                                   sysdiv);
+       *pll_rdiv = OV5640_PLL_ROOT_DIV;
+       *bit_div = OV5640_BIT_DIV;
+       *pclk_div = OV5640_PCLK_ROOT_DIV;
+
+       return _rate / *pll_rdiv / *bit_div / *pclk_div;
+}
+
+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
+{
+       u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
+       int ret;
+
+       ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
+                        &bit_div, &pclk_div);
+
+       if (bit_div == 2)
+               bit_div = 8;
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
+                            0x0f, bit_div);
+       if (ret)
+               return ret;
+
+       /*
+        * We need to set sysdiv according to the clock, and to clear
+        * the MIPI divider.
+        */
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
+                            0xff, sysdiv << 4);
+       if (ret)
+               return ret;
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
+                            0xff, mult);
+       if (ret)
+               return ret;
+
+       ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
+                            0x1f, prediv | ((pll_rdiv - 1) << 4));
+       if (ret)
+               return ret;
+
+       return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
+                             (ilog2(pclk_div) << 4));
+}
+
 /* download ov5640 settings to sensor through i2c */
 static int ov5640_set_timings(struct ov5640_dev *sensor,
                              const struct ov5640_mode_info *mode)
@@ -1061,16 +1182,6 @@ static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
         */
 
        if (on) {
-               /*
-                * reset MIPI PCLK/SERCLK divider
-                *
-                * SC PLL CONTRL1 0
-                * - [3..0]:    MIPI PCLK/SERCLK divider
-                */
-               ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0x0f, 0);
-               if (ret)
-                       return ret;
-
                /*
                 * configure parallel port control lines polarity
                 *
@@ -1444,8 +1555,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
 {
        const struct ov5640_mode_info *mode;
 
-       mode = v4l2_find_nearest_size(ov5640_mode_data[fr],
-                                     ARRAY_SIZE(ov5640_mode_data[fr]),
+       mode = v4l2_find_nearest_size(ov5640_mode_data,
+                                     ARRAY_SIZE(ov5640_mode_data),
                                      hact, vact,
                                      width, height);
 
@@ -1453,6 +1564,11 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
            (!nearest && (mode->hact != width || mode->vact != height)))
                return NULL;
 
+       /* Only 640x480 can operate at 60fps (for now) */
+       if (fr == OV5640_60_FPS &&
+           !(mode->hact == 640 && mode->vact == 480))
+               return NULL;
+
        return mode;
 }
 
@@ -1637,6 +1753,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
        enum ov5640_downsize_mode dn_mode, orig_dn_mode;
        bool auto_gain = sensor->ctrls.auto_gain->val == 1;
        bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
+       unsigned long rate;
        int ret;
 
        dn_mode = mode->dn_mode;
@@ -1655,6 +1772,23 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
                        goto restore_auto_gain;
        }
 
+       /*
+        * All the formats we support have 16 bits per pixel, seems to require
+        * the same rate than YUV, so we can just use 16 bpp all the time.
+        */
+       rate = mode->vtot * mode->htot * 16;
+       rate *= ov5640_framerates[sensor->current_fr];
+       if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
+               rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
+               ret = ov5640_set_mipi_pclk(sensor, rate);
+       } else {
+               rate = rate / sensor->ep.bus.parallel.bus_width;
+               ret = ov5640_set_dvp_pclk(sensor, rate);
+       }
+
+       if (ret < 0)
+               return 0;
+
        if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
            (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
                /*
@@ -1724,8 +1858,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
        sensor->last_mode = &ov5640_mode_init_data;
 
        ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
-                            (ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) |
-                            ilog2(OV5640_SCLK_ROOT_DIVIDER_DEFAULT));
+                            (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
+                            ilog2(OV5640_SCLK_ROOT_DIV));
        if (ret)
                return ret;
 
@@ -1925,34 +2059,39 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
                                     u32 width, u32 height)
 {
        const struct ov5640_mode_info *mode;
-       u32 minfps, maxfps, fps;
-       int ret;
+       enum ov5640_frame_rate rate = OV5640_30_FPS;
+       int minfps, maxfps, best_fps, fps;
+       int i;
 
        minfps = ov5640_framerates[OV5640_15_FPS];
-       maxfps = ov5640_framerates[OV5640_30_FPS];
+       maxfps = ov5640_framerates[OV5640_60_FPS];
 
        if (fi->numerator == 0) {
                fi->denominator = maxfps;
                fi->numerator = 1;
-               return OV5640_30_FPS;
+               rate = OV5640_60_FPS;
+               goto find_mode;
        }
 
-       fps = DIV_ROUND_CLOSEST(fi->denominator, fi->numerator);
+       fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
+                       minfps, maxfps);
 
-       fi->numerator = 1;
-       if (fps > maxfps)
-               fi->denominator = maxfps;
-       else if (fps < minfps)
-               fi->denominator = minfps;
-       else if (2 * fps >= 2 * minfps + (maxfps - minfps))
-               fi->denominator = maxfps;
-       else
-               fi->denominator = minfps;
+       best_fps = minfps;
+       for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
+               int curr_fps = ov5640_framerates[i];
 
-       ret = (fi->denominator == minfps) ? OV5640_15_FPS : OV5640_30_FPS;
+               if (abs(curr_fps - fps) < abs(best_fps - fps)) {
+                       best_fps = curr_fps;
+                       rate = i;
+               }
+       }
 
-       mode = ov5640_find_mode(sensor, ret, width, height, false);
-       return mode ? ret : -EINVAL;
+       fi->numerator = 1;
+       fi->denominator = best_fps;
+
+find_mode:
+       mode = ov5640_find_mode(sensor, rate, width, height, false);
+       return mode ? rate : -EINVAL;
 }
 
 static int ov5640_get_fmt(struct v4l2_subdev *sd,
@@ -2020,6 +2159,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
        struct ov5640_dev *sensor = to_ov5640_dev(sd);
        const struct ov5640_mode_info *new_mode;
        struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
+       struct v4l2_mbus_framefmt *fmt;
        int ret;
 
        if (format->pad != 0)
@@ -2037,22 +2177,20 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
        if (ret)
                goto out;
 
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               struct v4l2_mbus_framefmt *fmt =
-                       v4l2_subdev_get_try_format(sd, cfg, 0);
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+               fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+       else
+               fmt = &sensor->fmt;
 
-               *fmt = *mbus_fmt;
-               goto out;
-       }
+       *fmt = *mbus_fmt;
 
        if (new_mode != sensor->current_mode) {
                sensor->current_mode = new_mode;
                sensor->pending_mode_change = true;
        }
-       if (mbus_fmt->code != sensor->fmt.code) {
-               sensor->fmt = *mbus_fmt;
+       if (mbus_fmt->code != sensor->fmt.code)
                sensor->pending_fmt_change = true;
-       }
+
 out:
        mutex_unlock(&sensor->lock);
        return ret;
@@ -2502,10 +2640,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
                return -EINVAL;
 
        fse->min_width =
-               ov5640_mode_data[0][fse->index].hact;
+               ov5640_mode_data[fse->index].hact;
        fse->max_width = fse->min_width;
        fse->min_height =
-               ov5640_mode_data[0][fse->index].vact;
+               ov5640_mode_data[fse->index].vact;
        fse->max_height = fse->min_height;
 
        return 0;
@@ -2570,8 +2708,11 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
 
        frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
                                               mode->hact, mode->vact);
-       if (frame_rate < 0)
-               frame_rate = OV5640_15_FPS;
+       if (frame_rate < 0) {
+               /* Always return a valid frame interval value */
+               fi->interval = sensor->frame_interval;
+               goto out;
+       }
 
        mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
                                mode->vact, true);
@@ -2641,6 +2782,9 @@ out:
 
 static const struct v4l2_subdev_core_ops ov5640_core_ops = {
        .s_power = ov5640_s_power,
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 };
 
 static const struct v4l2_subdev_video_ops ov5640_video_ops = {
@@ -2736,7 +2880,7 @@ static int ov5640_probe(struct i2c_client *client,
        sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
        sensor->current_fr = OV5640_30_FPS;
        sensor->current_mode =
-               &ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480];
+               &ov5640_mode_data[OV5640_MODE_VGA_640_480];
        sensor->last_mode = sensor->current_mode;
 
        sensor->ae_target = 52;
@@ -2795,7 +2939,8 @@ static int ov5640_probe(struct i2c_client *client,
 
        v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
 
-       sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+                           V4L2_SUBDEV_FL_HAS_EVENTS;
        sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
        sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
        ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
index 5eba8dd7222bc5f405f5433e8f81aff6ea204000..785f326ac519f31e83d51572e89cd1ec9f42ed6c 100644 (file)
@@ -886,7 +886,7 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
        return ret;
 }
 
-static struct v4l2_ctrl_ops ov5645_ctrl_ops = {
+static const struct v4l2_ctrl_ops ov5645_ctrl_ops = {
        .s_ctrl = ov5645_s_ctrl,
 };
 
index bc68a3a5b4ec41fe64b6ba462e18f7eaf62614af..a70a6ff7b36e72337d65abdd1498aebe9beb4458 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-mediabus.h>
@@ -1651,6 +1652,9 @@ static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 static const struct v4l2_subdev_core_ops ov7670_core_ops = {
        .reset = ov7670_reset,
        .init = ov7670_init,
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ov7670_g_register,
        .s_register = ov7670_s_register,
@@ -1773,7 +1777,7 @@ static int ov7670_probe(struct i2c_client *client,
 
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
        sd->internal_ops = &ov7670_subdev_internal_ops;
-       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 #endif
 
        info->clock_speed = 30; /* default: a guess */
index fefff7fd7d686c98dd60680e9df6543f4696e9fa..2e9a758736a18c55ce50a2f80c2291a6975d894d 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-subdev.h>
 
@@ -1287,6 +1288,9 @@ static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ov772x_g_register,
        .s_register     = ov772x_s_register,
@@ -1379,7 +1383,8 @@ static int ov772x_probe(struct i2c_client *client,
        mutex_init(&priv->lock);
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
-       priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+                             V4L2_SUBDEV_FL_HAS_EVENTS;
        v4l2_ctrl_handler_init(&priv->hdl, 3);
        /* Use our mutex for the controls */
        priv->hdl.lock = &priv->lock;
index 6e9c233cfbe352589ae2b042fca4d540023ec2a9..177688afd9a66f4120075d60f4888668b578ee8e 100644 (file)
@@ -322,7 +322,7 @@ static int ov7740_set_power(struct ov7740 *ov7740, int on)
        return 0;
 }
 
-static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
        .log_status = v4l2_ctrl_subdev_log_status,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ov7740_get_register,
@@ -648,7 +648,7 @@ static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
        return 0;
 }
 
-static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
        .s_stream = ov7740_set_stream,
        .s_frame_interval = ov7740_s_frame_interval,
        .g_frame_interval = ov7740_g_frame_interval,
index 41d470d9ca943ea84653f9dd8bfb0ab83dafe1a4..bc2e35e5ce6158e1c7f0d94f09ea65462df70767 100644 (file)
@@ -59,7 +59,7 @@ static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
        /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */
-       V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 13000000, 165000000,
                        V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                        V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
                        V4L2_DV_BT_CAP_PROGRESSIVE |
@@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
 
        i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
 
-       if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+       if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
                v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
                return;
        }
index c4c2a6134e1eb047fb8687a6c235e49c358f089b..e8613e364403c9809a33ddcc7c3611efd8445632 100644 (file)
@@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
 
        /* read data */
        len = io_readn(sd, addr, sizeof(buffer), buffer);
-       err = hdmi_infoframe_unpack(&frame, buffer);
+       err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
        if (err) {
                v4l_err(state->client,
                        "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
        /* read data */
        len = io_readn(sd, addr, sizeof(buffer), buffer);
        v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
-       err = hdmi_infoframe_unpack(&frame, buffer);
+       err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
        if (err) {
                v4l_err(state->client,
                        "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
index 9b4f21237810fd4fbacdb07a26773ee8eef1df09..06a78c2cdaabbf57da57e47d7440b1f2eb25b8f1 100644 (file)
@@ -19,7 +19,7 @@
  *
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
- * maxvol   - set maximium volume to +20db (1), default is 0db(0)
+ * maxvol   - set maximum volume to +20db (1), default is 0db(0)
  */
 
 #include <linux/module.h>
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0).");
 module_param(loudness, int, S_IRUGO);
 MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0).");
 module_param(maxvol, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
+MODULE_PARM_DESC(maxvol, "Set maximum volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
 
 
 /* Structure of address and subaddresses for the tda7432 */
index 498ad2368cbcfa56d0d84ecf26cf62e1f74375b5..f5ee28058ea2af35ae7dd137ab4f27ea3115529e 100644 (file)
@@ -49,7 +49,7 @@ static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1080, 25000000, 148500000,
+       V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1080, 25000000, 148500000,
                V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
 };
 
index 0e91b9949c3a9976e58b584546730b23266be0f6..eaddd977ba40edaebcfce2c3f79cc4e7d7c2ea3d 100644 (file)
@@ -1790,7 +1790,7 @@ static int tvp5150_probe(struct i2c_client *c,
                                                tvp5150_isr, IRQF_TRIGGER_HIGH |
                                                IRQF_ONESHOT, "tvp5150", core);
                if (res)
-                       return res;
+                       goto err;
        }
 
        res = v4l2_async_register_subdev(sd);
index 4d49af86c15ee4a21b6f2e58d51dac4de6a6ddb9..01dcf179f203e6c713910b294870cb8fcabbad02 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
@@ -38,7 +40,7 @@ struct video_i2c_buffer {
 };
 
 struct video_i2c_data {
-       struct i2c_client *client;
+       struct regmap *regmap;
        const struct video_i2c_chip *chip;
        struct mutex lock;
        spinlock_t slock;
@@ -51,6 +53,8 @@ struct video_i2c_data {
 
        struct task_struct *kthread_vid_cap;
        struct list_head vid_cap_active;
+
+       struct v4l2_fract frame_interval;
 };
 
 static const struct v4l2_fmtdesc amg88xx_format = {
@@ -62,13 +66,20 @@ static const struct v4l2_frmsize_discrete amg88xx_size = {
        .height = 8,
 };
 
+static const struct regmap_config amg88xx_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xff
+};
+
 struct video_i2c_chip {
        /* video dimensions */
        const struct v4l2_fmtdesc *format;
        const struct v4l2_frmsize_discrete *size;
 
-       /* max frames per second */
-       unsigned int max_fps;
+       /* available frame intervals */
+       const struct v4l2_fract *frame_intervals;
+       unsigned int num_frame_intervals;
 
        /* pixel buffer size */
        unsigned int buffer_size;
@@ -76,33 +87,111 @@ struct video_i2c_chip {
        /* pixel size in bits */
        unsigned int bpp;
 
+       const struct regmap_config *regmap_config;
+
+       /* setup function */
+       int (*setup)(struct video_i2c_data *data);
+
        /* xfer function */
        int (*xfer)(struct video_i2c_data *data, char *buf);
 
+       /* power control function */
+       int (*set_power)(struct video_i2c_data *data, bool on);
+
        /* hwmon init function */
        int (*hwmon_init)(struct video_i2c_data *data);
 };
 
+/* Power control register */
+#define AMG88XX_REG_PCTL       0x00
+#define AMG88XX_PCTL_NORMAL            0x00
+#define AMG88XX_PCTL_SLEEP             0x10
+
+/* Reset register */
+#define AMG88XX_REG_RST                0x01
+#define AMG88XX_RST_FLAG               0x30
+#define AMG88XX_RST_INIT               0x3f
+
+/* Frame rate register */
+#define AMG88XX_REG_FPSC       0x02
+#define AMG88XX_FPSC_1FPS              BIT(0)
+
+/* Thermistor register */
+#define AMG88XX_REG_TTHL       0x0e
+
+/* Temperature register */
+#define AMG88XX_REG_T01L       0x80
+
 static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
 {
-       struct i2c_client *client = data->client;
-       struct i2c_msg msg[2];
-       u8 reg = 0x80;
+       return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf,
+                               data->chip->buffer_size);
+}
+
+static int amg88xx_setup(struct video_i2c_data *data)
+{
+       unsigned int mask = AMG88XX_FPSC_1FPS;
+       unsigned int val;
+
+       if (data->frame_interval.numerator == data->frame_interval.denominator)
+               val = mask;
+       else
+               val = 0;
+
+       return regmap_update_bits(data->regmap, AMG88XX_REG_FPSC, mask, val);
+}
+
+static int amg88xx_set_power_on(struct video_i2c_data *data)
+{
+       int ret;
+
+       ret = regmap_write(data->regmap, AMG88XX_REG_PCTL, AMG88XX_PCTL_NORMAL);
+       if (ret)
+               return ret;
+
+       msleep(50);
+
+       ret = regmap_write(data->regmap, AMG88XX_REG_RST, AMG88XX_RST_INIT);
+       if (ret)
+               return ret;
+
+       usleep_range(2000, 3000);
+
+       ret = regmap_write(data->regmap, AMG88XX_REG_RST, AMG88XX_RST_FLAG);
+       if (ret)
+               return ret;
+
+       /*
+        * Wait two frames before reading thermistor and temperature registers
+        */
+       msleep(200);
+
+       return 0;
+}
+
+static int amg88xx_set_power_off(struct video_i2c_data *data)
+{
        int ret;
 
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = 1;
-       msg[0].buf  = (char *)&reg;
+       ret = regmap_write(data->regmap, AMG88XX_REG_PCTL, AMG88XX_PCTL_SLEEP);
+       if (ret)
+               return ret;
+       /*
+        * Wait for a while to avoid resuming normal mode immediately after
+        * entering sleep mode, otherwise the device occasionally goes wrong
+        * (thermistor and temperature registers are not updated at all)
+        */
+       msleep(100);
 
-       msg[1].addr = client->addr;
-       msg[1].flags = I2C_M_RD;
-       msg[1].len = data->chip->buffer_size;
-       msg[1].buf = (char *)buf;
+       return 0;
+}
 
-       ret = i2c_transfer(client->adapter, msg, 2);
+static int amg88xx_set_power(struct video_i2c_data *data, bool on)
+{
+       if (on)
+               return amg88xx_set_power_on(data);
 
-       return (ret == 2) ? 0 : -EIO;
+       return amg88xx_set_power_off(data);
 }
 
 #if IS_ENABLED(CONFIG_HWMON)
@@ -133,12 +222,23 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type,
                        u32 attr, int channel, long *val)
 {
        struct video_i2c_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = data->client;
-       int tmp = i2c_smbus_read_word_data(client, 0x0e);
+       __le16 buf;
+       int tmp;
+
+       tmp = pm_runtime_get_sync(regmap_get_device(data->regmap));
+       if (tmp < 0) {
+               pm_runtime_put_noidle(regmap_get_device(data->regmap));
+               return tmp;
+       }
 
-       if (tmp < 0)
+       tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2);
+       pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
+       pm_runtime_put_autosuspend(regmap_get_device(data->regmap));
+       if (tmp)
                return tmp;
 
+       tmp = le16_to_cpu(buf);
+
        /*
         * Check for sign bit, this isn't a two's complement value but an
         * absolute temperature that needs to be inverted in the case of being
@@ -164,8 +264,9 @@ static const struct hwmon_chip_info amg88xx_chip_info = {
 
 static int amg88xx_hwmon_init(struct video_i2c_data *data)
 {
-       void *hwmon = devm_hwmon_device_register_with_info(&data->client->dev,
-                               "amg88xx", data, &amg88xx_chip_info, NULL);
+       struct device *dev = regmap_get_device(data->regmap);
+       void *hwmon = devm_hwmon_device_register_with_info(dev, "amg88xx", data,
+                                               &amg88xx_chip_info, NULL);
 
        return PTR_ERR_OR_ZERO(hwmon);
 }
@@ -175,14 +276,23 @@ static int amg88xx_hwmon_init(struct video_i2c_data *data)
 
 #define AMG88XX                0
 
+static const struct v4l2_fract amg88xx_frame_intervals[] = {
+       { 1, 10 },
+       { 1, 1 },
+};
+
 static const struct video_i2c_chip video_i2c_chip[] = {
        [AMG88XX] = {
                .size           = &amg88xx_size,
                .format         = &amg88xx_format,
-               .max_fps        = 10,
+               .frame_intervals        = amg88xx_frame_intervals,
+               .num_frame_intervals    = ARRAY_SIZE(amg88xx_frame_intervals),
                .buffer_size    = 128,
                .bpp            = 16,
+               .regmap_config  = &amg88xx_regmap_config,
+               .setup          = &amg88xx_setup,
                .xfer           = &amg88xx_xfer,
+               .set_power      = amg88xx_set_power,
                .hwmon_init     = amg88xx_hwmon_init,
        },
 };
@@ -246,7 +356,8 @@ static void buffer_queue(struct vb2_buffer *vb)
 static int video_i2c_thread_vid_cap(void *priv)
 {
        struct video_i2c_data *data = priv;
-       unsigned int delay = msecs_to_jiffies(1000 / data->chip->max_fps);
+       unsigned int delay = mult_frac(HZ, data->frame_interval.numerator,
+                                      data->frame_interval.denominator);
 
        set_freezable();
 
@@ -308,19 +419,36 @@ static void video_i2c_del_list(struct vb2_queue *vq, enum vb2_buffer_state state
 static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct video_i2c_data *data = vb2_get_drv_priv(vq);
+       struct device *dev = regmap_get_device(data->regmap);
+       int ret;
 
        if (data->kthread_vid_cap)
                return 0;
 
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(dev);
+               goto error_del_list;
+       }
+
+       ret = data->chip->setup(data);
+       if (ret)
+               goto error_rpm_put;
+
        data->sequence = 0;
        data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data,
                                            "%s-vid-cap", data->v4l2_dev.name);
-       if (!IS_ERR(data->kthread_vid_cap))
+       ret = PTR_ERR_OR_ZERO(data->kthread_vid_cap);
+       if (!ret)
                return 0;
 
+error_rpm_put:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+error_del_list:
        video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED);
 
-       return PTR_ERR(data->kthread_vid_cap);
+       return ret;
 }
 
 static void stop_streaming(struct vb2_queue *vq)
@@ -332,11 +460,13 @@ static void stop_streaming(struct vb2_queue *vq)
 
        kthread_stop(data->kthread_vid_cap);
        data->kthread_vid_cap = NULL;
+       pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
+       pm_runtime_put_autosuspend(regmap_get_device(data->regmap));
 
        video_i2c_del_list(vq, VB2_BUF_STATE_ERROR);
 }
 
-static struct vb2_ops video_i2c_video_qops = {
+static const struct vb2_ops video_i2c_video_qops = {
        .queue_setup            = queue_setup,
        .buf_prepare            = buffer_prepare,
        .buf_queue              = buffer_queue,
@@ -350,7 +480,8 @@ static int video_i2c_querycap(struct file *file, void  *priv,
                                struct v4l2_capability *vcap)
 {
        struct video_i2c_data *data = video_drvdata(file);
-       struct i2c_client *client = data->client;
+       struct device *dev = regmap_get_device(data->regmap);
+       struct i2c_client *client = to_i2c_client(dev);
 
        strscpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver));
        strscpy(vcap->card, data->vdev.name, sizeof(vcap->card));
@@ -426,15 +557,14 @@ static int video_i2c_enum_frameintervals(struct file *file, void *priv,
        const struct video_i2c_data *data = video_drvdata(file);
        const struct v4l2_frmsize_discrete *size = data->chip->size;
 
-       if (fe->index > 0)
+       if (fe->index >= data->chip->num_frame_intervals)
                return -EINVAL;
 
        if (fe->width != size->width || fe->height != size->height)
                return -EINVAL;
 
        fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
-       fe->discrete.numerator = 1;
-       fe->discrete.denominator = data->chip->max_fps;
+       fe->discrete = data->chip->frame_intervals[fe->index];
 
        return 0;
 }
@@ -479,12 +609,27 @@ static int video_i2c_g_parm(struct file *filp, void *priv,
 
        parm->parm.capture.readbuffers = 1;
        parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.timeperframe.numerator = 1;
-       parm->parm.capture.timeperframe.denominator = data->chip->max_fps;
+       parm->parm.capture.timeperframe = data->frame_interval;
 
        return 0;
 }
 
+static int video_i2c_s_parm(struct file *filp, void *priv,
+                             struct v4l2_streamparm *parm)
+{
+       struct video_i2c_data *data = video_drvdata(filp);
+       int i;
+
+       for (i = 0; i < data->chip->num_frame_intervals - 1; i++) {
+               if (V4L2_FRACT_COMPARE(parm->parm.capture.timeperframe, <=,
+                                      data->chip->frame_intervals[i]))
+                       break;
+       }
+       data->frame_interval = data->chip->frame_intervals[i];
+
+       return video_i2c_g_parm(filp, priv, parm);
+}
+
 static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
        .vidioc_querycap                = video_i2c_querycap,
        .vidioc_g_input                 = video_i2c_g_input,
@@ -496,7 +641,7 @@ static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
        .vidioc_g_fmt_vid_cap           = video_i2c_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap           = video_i2c_s_fmt_vid_cap,
        .vidioc_g_parm                  = video_i2c_g_parm,
-       .vidioc_s_parm                  = video_i2c_g_parm,
+       .vidioc_s_parm                  = video_i2c_s_parm,
        .vidioc_try_fmt_vid_cap         = video_i2c_try_fmt_vid_cap,
        .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
        .vidioc_create_bufs             = vb2_ioctl_create_bufs,
@@ -510,7 +655,13 @@ static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
 
 static void video_i2c_release(struct video_device *vdev)
 {
-       kfree(video_get_drvdata(vdev));
+       struct video_i2c_data *data = video_get_drvdata(vdev);
+
+       v4l2_device_unregister(&data->v4l2_dev);
+       mutex_destroy(&data->lock);
+       mutex_destroy(&data->queue_lock);
+       regmap_exit(data->regmap);
+       kfree(data);
 }
 
 static int video_i2c_probe(struct i2c_client *client,
@@ -532,13 +683,18 @@ static int video_i2c_probe(struct i2c_client *client,
        else
                goto error_free_device;
 
-       data->client = client;
+       data->regmap = regmap_init_i2c(client, data->chip->regmap_config);
+       if (IS_ERR(data->regmap)) {
+               ret = PTR_ERR(data->regmap);
+               goto error_free_device;
+       }
+
        v4l2_dev = &data->v4l2_dev;
        strscpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name));
 
        ret = v4l2_device_register(&client->dev, v4l2_dev);
        if (ret < 0)
-               goto error_free_device;
+               goto error_regmap_exit;
 
        mutex_init(&data->lock);
        mutex_init(&data->queue_lock);
@@ -575,9 +731,23 @@ static int video_i2c_probe(struct i2c_client *client,
        spin_lock_init(&data->slock);
        INIT_LIST_HEAD(&data->vid_cap_active);
 
+       data->frame_interval = data->chip->frame_intervals[0];
+
        video_set_drvdata(&data->vdev, data);
        i2c_set_clientdata(client, data);
 
+       if (data->chip->set_power) {
+               ret = data->chip->set_power(data, true);
+               if (ret)
+                       goto error_unregister_device;
+       }
+
+       pm_runtime_get_noresume(&client->dev);
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, 2000);
+       pm_runtime_use_autosuspend(&client->dev);
+
        if (data->chip->hwmon_init) {
                ret = data->chip->hwmon_init(data);
                if (ret < 0) {
@@ -588,15 +758,29 @@ static int video_i2c_probe(struct i2c_client *client,
 
        ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1);
        if (ret < 0)
-               goto error_unregister_device;
+               goto error_pm_disable;
+
+       pm_runtime_mark_last_busy(&client->dev);
+       pm_runtime_put_autosuspend(&client->dev);
 
        return 0;
 
+error_pm_disable:
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+
+       if (data->chip->set_power)
+               data->chip->set_power(data, false);
+
 error_unregister_device:
        v4l2_device_unregister(v4l2_dev);
        mutex_destroy(&data->lock);
        mutex_destroy(&data->queue_lock);
 
+error_regmap_exit:
+       regmap_exit(data->regmap);
+
 error_free_device:
        kfree(data);
 
@@ -607,15 +791,48 @@ static int video_i2c_remove(struct i2c_client *client)
 {
        struct video_i2c_data *data = i2c_get_clientdata(client);
 
-       video_unregister_device(&data->vdev);
-       v4l2_device_unregister(&data->v4l2_dev);
+       pm_runtime_get_sync(&client->dev);
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
 
-       mutex_destroy(&data->lock);
-       mutex_destroy(&data->queue_lock);
+       if (data->chip->set_power)
+               data->chip->set_power(data, false);
+
+       video_unregister_device(&data->vdev);
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int video_i2c_pm_runtime_suspend(struct device *dev)
+{
+       struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+       if (!data->chip->set_power)
+               return 0;
+
+       return data->chip->set_power(data, false);
+}
+
+static int video_i2c_pm_runtime_resume(struct device *dev)
+{
+       struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+       if (!data->chip->set_power)
+               return 0;
+
+       return data->chip->set_power(data, true);
+}
+
+#endif
+
+static const struct dev_pm_ops video_i2c_pm_ops = {
+       SET_RUNTIME_PM_OPS(video_i2c_pm_runtime_suspend,
+                          video_i2c_pm_runtime_resume, NULL)
+};
+
 static const struct i2c_device_id video_i2c_id_table[] = {
        { "amg88xx", AMG88XX },
        {}
@@ -632,6 +849,7 @@ static struct i2c_driver video_i2c_driver = {
        .driver = {
                .name   = VIDEO_I2C_DRIVER,
                .of_match_table = video_i2c_of_match,
+               .pm     = &video_i2c_pm_ops,
        },
        .probe          = video_i2c_probe,
        .remove         = video_i2c_remove,
index f07610a1646d00bde2eae7d622306efd07fdadf9..ba45b378d7394aef828d0fc50a6b91ede60084d6 100644 (file)
@@ -17,7 +17,8 @@ int flexcop_dma_allocate(struct pci_dev *pdev,
                return -EINVAL;
        }
 
-       if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+       tcpu = pci_alloc_consistent(pdev, size, &tdma);
+       if (tcpu != NULL) {
                dma->pdev = pdev;
                dma->cpu_addr0 = tcpu;
                dma->dma_addr0 = tdma;
@@ -34,7 +35,7 @@ void flexcop_dma_free(struct flexcop_dma *dma)
 {
        pci_free_consistent(dma->pdev, dma->size*2,
                        dma->cpu_addr0, dma->dma_addr0);
-       memset(dma,0,sizeof(struct flexcop_dma));
+       memset(dma, 0, sizeof(struct flexcop_dma));
 }
 EXPORT_SYMBOL(flexcop_dma_free);
 
@@ -42,23 +43,24 @@ int flexcop_dma_config(struct flexcop_device *fc,
                struct flexcop_dma *dma,
                flexcop_dma_index_t dma_idx)
 {
-       flexcop_ibi_value v0x0,v0x4,v0xc;
-       v0x0.raw = v0x4.raw = v0xc.raw = 0;
+       flexcop_ibi_value v0x0, v0x4, v0xc;
 
+       v0x0.raw = v0x4.raw = v0xc.raw = 0;
        v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
        v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
        v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
 
        if ((dma_idx & FC_DMA_1) == dma_idx) {
-               fc->write_ibi_reg(fc,dma1_000,v0x0);
-               fc->write_ibi_reg(fc,dma1_004,v0x4);
-               fc->write_ibi_reg(fc,dma1_00c,v0xc);
+               fc->write_ibi_reg(fc, dma1_000, v0x0);
+               fc->write_ibi_reg(fc, dma1_004, v0x4);
+               fc->write_ibi_reg(fc, dma1_00c, v0xc);
        } else if ((dma_idx & FC_DMA_2) == dma_idx) {
-               fc->write_ibi_reg(fc,dma2_010,v0x0);
-               fc->write_ibi_reg(fc,dma2_014,v0x4);
-               fc->write_ibi_reg(fc,dma2_01c,v0xc);
+               fc->write_ibi_reg(fc, dma2_010, v0x0);
+               fc->write_ibi_reg(fc, dma2_014, v0x4);
+               fc->write_ibi_reg(fc, dma2_01c, v0xc);
        } else {
-               err("either DMA1 or DMA2 can be configured within one flexcop_dma_config call.");
+               err("either DMA1 or DMA2 can be configured within one %s call.",
+                       __func__);
                return -EINVAL;
        }
 
@@ -72,8 +74,8 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
                flexcop_dma_addr_index_t index,
                int onoff)
 {
-       flexcop_ibi_value v0x0,v0xc;
-       flexcop_ibi_register r0x0,r0xc;
+       flexcop_ibi_value v0x0, v0xc;
+       flexcop_ibi_register r0x0, r0xc;
 
        if ((dma_idx & FC_DMA_1) == dma_idx) {
                r0x0 = dma1_000;
@@ -82,15 +84,16 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
                r0x0 = dma2_010;
                r0xc = dma2_01c;
        } else {
-               err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
+               err("transfer DMA1 or DMA2 can be started within one %s call.",
+                       __func__);
                return -EINVAL;
        }
 
-       v0x0 = fc->read_ibi_reg(fc,r0x0);
-       v0xc = fc->read_ibi_reg(fc,r0xc);
+       v0x0 = fc->read_ibi_reg(fc, r0x0);
+       v0xc = fc->read_ibi_reg(fc, r0xc);
 
-       deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
-       deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+       deb_rdump("reg: %03x: %x\n", r0x0, v0x0.raw);
+       deb_rdump("reg: %03x: %x\n", r0xc, v0xc.raw);
 
        if (index & FC_DMA_SUBADDR_0)
                v0x0.dma_0x0.dma_0start = onoff;
@@ -98,11 +101,11 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
        if (index & FC_DMA_SUBADDR_1)
                v0xc.dma_0xc.dma_1start = onoff;
 
-       fc->write_ibi_reg(fc,r0x0,v0x0);
-       fc->write_ibi_reg(fc,r0xc,v0xc);
+       fc->write_ibi_reg(fc, r0x0, v0x0);
+       fc->write_ibi_reg(fc, r0xc, v0xc);
 
-       deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
-       deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+       deb_rdump("reg: %03x: %x\n", r0x0, v0x0.raw);
+       deb_rdump("reg: %03x: %x\n", r0xc, v0xc.raw);
        return 0;
 }
 EXPORT_SYMBOL(flexcop_dma_xfer_control);
@@ -112,10 +115,11 @@ static int flexcop_dma_remap(struct flexcop_device *fc,
                int onoff)
 {
        flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-       deb_info("%s\n",__func__);
+       flexcop_ibi_value v = fc->read_ibi_reg(fc, r);
+
+       deb_info("%s\n", __func__);
        v.dma_0xc.remap_enable = onoff;
-       fc->write_ibi_reg(fc,r,v);
+       fc->write_ibi_reg(fc, r, v);
        return 0;
 }
 
@@ -123,7 +127,7 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc,
                flexcop_dma_index_t no,
                int onoff)
 {
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+       flexcop_ibi_value v = fc->read_ibi_reg(fc, ctrl_208);
 
        if (no & FC_DMA_1)
                v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
@@ -131,7 +135,7 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc,
        if (no & FC_DMA_2)
                v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
 
-       fc->write_ibi_reg(fc,ctrl_208,v);
+       fc->write_ibi_reg(fc, ctrl_208, v);
        return 0;
 }
 EXPORT_SYMBOL(flexcop_dma_control_size_irq);
@@ -140,7 +144,7 @@ int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
                flexcop_dma_index_t no,
                int onoff)
 {
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+       flexcop_ibi_value v = fc->read_ibi_reg(fc, ctrl_208);
 
        if (no & FC_DMA_1)
                v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
@@ -148,7 +152,7 @@ int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
        if (no & FC_DMA_2)
                v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
 
-       fc->write_ibi_reg(fc,ctrl_208,v);
+       fc->write_ibi_reg(fc, ctrl_208, v);
        return 0;
 }
 EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
@@ -158,13 +162,13 @@ int flexcop_dma_config_timer(struct flexcop_device *fc,
                flexcop_dma_index_t dma_idx, u8 cycles)
 {
        flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+       flexcop_ibi_value v = fc->read_ibi_reg(fc, r);
 
-       flexcop_dma_remap(fc,dma_idx,0);
+       flexcop_dma_remap(fc, dma_idx, 0);
 
-       deb_info("%s\n",__func__);
+       deb_info("%s\n", __func__);
        v.dma_0x4_write.dmatimer = cycles;
-       fc->write_ibi_reg(fc,r,v);
+       fc->write_ibi_reg(fc, r, v);
        return 0;
 }
 EXPORT_SYMBOL(flexcop_dma_config_timer);
index d4906c04dc6eeddc56e270842d48a166057abad3..d09785fd37a826a762268e37bb647e2f50835ba8 100644 (file)
@@ -2792,19 +2792,17 @@ static int bttv_g_tuner(struct file *file, void *priv,
        return 0;
 }
 
-static int bttv_cropcap(struct file *file, void *priv,
-                               struct v4l2_cropcap *cap)
+static int bttv_g_pixelaspect(struct file *file, void *priv,
+                             int type, struct v4l2_fract *f)
 {
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
 
-       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-           cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
        /* defrect and bounds are set via g_selection */
-       cap->pixelaspect = bttv_tvnorms[btv->tvnorm].cropcap.pixelaspect;
-
+       *f = bttv_tvnorms[btv->tvnorm].cropcap.pixelaspect;
        return 0;
 }
 
@@ -3162,7 +3160,7 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
        .vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
-       .vidioc_cropcap                 = bttv_cropcap,
+       .vidioc_g_pixelaspect           = bttv_g_pixelaspect,
        .vidioc_reqbufs                 = bttv_reqbufs,
        .vidioc_querybuf                = bttv_querybuf,
        .vidioc_qbuf                    = bttv_qbuf,
index 0525f5e1565b3187758a45e457f47d22ebc29771..c088de551081a0661bb76f48dfcf212c5ab52222 100644 (file)
@@ -1077,33 +1077,65 @@ static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
        return 0;
 }
 
-static int cobalt_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+static int cobalt_g_pixelaspect(struct file *file, void *fh,
+                               int type, struct v4l2_fract *f)
 {
        struct cobalt_stream *s = video_drvdata(file);
        struct v4l2_dv_timings timings;
        int err = 0;
 
-       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
+
        if (s->input == 1)
                timings = cea1080p60;
        else
                err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
-       if (!err) {
-               cc->bounds.width = cc->defrect.width = timings.bt.width;
-               cc->bounds.height = cc->defrect.height = timings.bt.height;
-               cc->pixelaspect = v4l2_dv_timings_aspect_ratio(&timings);
-       }
+       if (!err)
+               *f = v4l2_dv_timings_aspect_ratio(&timings);
        return err;
 }
 
+static int cobalt_g_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct cobalt_stream *s = video_drvdata(file);
+       struct v4l2_dv_timings timings;
+       int err = 0;
+
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (s->input == 1)
+               timings = cea1080p60;
+       else
+               err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
+
+       if (err)
+               return err;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               sel->r.top = 0;
+               sel->r.left = 0;
+               sel->r.width = timings.bt.width;
+               sel->r.height = timings.bt.height;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static const struct v4l2_ioctl_ops cobalt_ioctl_ops = {
        .vidioc_querycap                = cobalt_querycap,
        .vidioc_g_parm                  = cobalt_g_parm,
        .vidioc_log_status              = cobalt_log_status,
        .vidioc_streamon                = vb2_ioctl_streamon,
        .vidioc_streamoff               = vb2_ioctl_streamoff,
-       .vidioc_cropcap                 = cobalt_cropcap,
+       .vidioc_g_pixelaspect           = cobalt_g_pixelaspect,
+       .vidioc_g_selection             = cobalt_g_selection,
        .vidioc_enum_input              = cobalt_enum_input,
        .vidioc_g_input                 = cobalt_g_input,
        .vidioc_s_input                 = cobalt_s_input,
index 854116375a7ccb9c4af89e6c648dd192263e2fce..8c54b17f382ab63c9da484f624c5c4af6efb301d 100644 (file)
@@ -441,15 +441,16 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
        return cx18_get_input(cx, vin->index, vin);
 }
 
-static int cx18_cropcap(struct file *file, void *fh,
-                       struct v4l2_cropcap *cropcap)
+static int cx18_g_pixelaspect(struct file *file, void *fh,
+                             int type, struct v4l2_fract *f)
 {
        struct cx18 *cx = fh2id(fh)->cx;
 
-       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       cropcap->pixelaspect.numerator = cx->is_50hz ? 54 : 11;
-       cropcap->pixelaspect.denominator = cx->is_50hz ? 59 : 10;
+
+       f->numerator = cx->is_50hz ? 54 : 11;
+       f->denominator = cx->is_50hz ? 59 : 10;
        return 0;
 }
 
@@ -1079,7 +1080,7 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_g_audio                 = cx18_g_audio,
        .vidioc_enumaudio               = cx18_enumaudio,
        .vidioc_enum_input              = cx18_enum_input,
-       .vidioc_cropcap                 = cx18_cropcap,
+       .vidioc_g_pixelaspect           = cx18_g_pixelaspect,
        .vidioc_g_selection             = cx18_g_selection,
        .vidioc_g_input                 = cx18_g_input,
        .vidioc_s_input                 = cx18_s_input,
index 39804d830305c152822995d0cbb9b803a08c741e..fd5c52b21436b5fb035a9642ab5d934800a26579 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -41,6 +42,18 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(CX23885_VERSION);
 
+/*
+ * Some platforms have been found to require periodic resetting of the DMA
+ * engine. Ryzen and XEON platforms are known to be affected. The symptom
+ * encountered is "mpeg risc op code error". Only Ryzen platforms employ
+ * this workaround if the option equals 1. The workaround can be explicitly
+ * disabled for all platforms by setting to 0, the workaround can be forced
+ * on for any platform by setting to 2.
+ */
+static unsigned int dma_reset_workaround = 1;
+module_param(dma_reset_workaround, int, 0644);
+MODULE_PARM_DESC(dma_reset_workaround, "periodic RiSC dma engine reset; 0-force disable, 1-driver detect (default), 2-force enable");
+
 static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
@@ -603,8 +616,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
 
 static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
 {
-       uint32_t reg1_val = cx_read(TC_REQ); /* read-only */
-       uint32_t reg2_val = cx_read(TC_REQ_SET);
+       uint32_t reg1_val, reg2_val;
+
+       if (!dev->need_dma_reset)
+               return;
+
+       reg1_val = cx_read(TC_REQ); /* read-only */
+       reg2_val = cx_read(TC_REQ_SET);
 
        if (reg1_val && reg2_val) {
                cx_write(TC_REQ, reg1_val);
@@ -2058,6 +2076,37 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
        /* TODO: 23-19 */
 }
 
+static struct {
+       int vendor, dev;
+} const broken_dev_id[] = {
+       /* According with
+        * https://openbenchmarking.org/system/1703021-RI-AMDZEN08075/Ryzen%207%201800X/lspci,
+        * 0x1451 is PCI ID for the IOMMU found on Ryzen
+        */
+       { PCI_VENDOR_ID_AMD, 0x1451 },
+};
+
+static bool cx23885_does_need_dma_reset(void)
+{
+       int i;
+       struct pci_dev *pdev = NULL;
+
+       if (dma_reset_workaround == 0)
+               return false;
+       else if (dma_reset_workaround == 2)
+               return true;
+
+       for (i = 0; i < ARRAY_SIZE(broken_dev_id); i++) {
+               pdev = pci_get_device(broken_dev_id[i].vendor,
+                                     broken_dev_id[i].dev, NULL);
+               if (pdev) {
+                       pci_dev_put(pdev);
+                       return true;
+               }
+       }
+       return false;
+}
+
 static int cx23885_initdev(struct pci_dev *pci_dev,
                           const struct pci_device_id *pci_id)
 {
@@ -2069,6 +2118,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        if (NULL == dev)
                return -ENOMEM;
 
+       dev->need_dma_reset = cx23885_does_need_dma_reset();
+
        err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
        if (err < 0)
                goto fail_free;
index d0df3dfff694e4b3e088b8a893ae0f82eb28e37a..de6809b950ce2df7d7e5f2bda8575e2d302f7903 100644 (file)
@@ -18,7 +18,6 @@
 #include "cx23885.h"
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <asm/io.h>
index 92d32a733f1b4a32b4ef0b3dc6c49b838001d788..168178c1e574f321f7e7b04ca2af0f0e3450795d 100644 (file)
@@ -668,26 +668,43 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
-static int vidioc_cropcap(struct file *file, void *priv,
-                         struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct cx23885_dev *dev = video_drvdata(file);
        bool is_50hz = dev->tvnorm & V4L2_STD_625_50;
 
-       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       cc->bounds.left = 0;
-       cc->bounds.top = 0;
-       cc->bounds.width = 720;
-       cc->bounds.height = norm_maxh(dev->tvnorm);
-       cc->defrect = cc->bounds;
-       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
-       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+       f->numerator = is_50hz ? 54 : 11;
+       f->denominator = is_50hz ? 59 : 10;
 
        return 0;
 }
 
+static int vidioc_g_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct cx23885_dev *dev = video_drvdata(file);
+
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               sel->r.top = 0;
+               sel->r.left = 0;
+               sel->r.width = 720;
+               sel->r.height = norm_maxh(dev->tvnorm);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx23885_dev *dev = video_drvdata(file);
@@ -1122,7 +1139,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_dqbuf         = vb2_ioctl_dqbuf,
        .vidioc_streamon      = vb2_ioctl_streamon,
        .vidioc_streamoff     = vb2_ioctl_streamoff,
-       .vidioc_cropcap       = vidioc_cropcap,
+       .vidioc_g_pixelaspect = vidioc_g_pixelaspect,
+       .vidioc_g_selection   = vidioc_g_selection,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
index d54c7ee1ab218f003178b37240a80ba1ee74e277..cf965efabe66678f8c475f675ffbf818ec102ad1 100644 (file)
@@ -451,6 +451,8 @@ struct cx23885_dev {
        /* Analog raw audio */
        struct cx23885_audio_dev   *audio_dev;
 
+       /* Does the system require periodic DMA resets? */
+       unsigned int            need_dma_reset:1;
 };
 
 static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
index f137155bf79e569636ca692779c8d1f340ca71d3..b834449e78f8ce25297dcdb336b6e7d660a85f4f 100644 (file)
 #ifndef _DDBRIDGE_H_
 #define _DDBRIDGE_H_
 
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dvb/ca.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
 #include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
-#include <linux/timer.h>
-#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/spi/spi.h>
 #include <linux/swab.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <linux/completion.h>
 
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include <linux/dvb/ca.h>
-#include <linux/socket.h>
-#include <linux/device.h>
-#include <linux/io.h>
 
 #include <media/dmxdev.h>
-#include <media/dvbdev.h>
+#include <media/dvb_ca_en50221.h>
 #include <media/dvb_demux.h>
+#include <media/dvbdev.h>
 #include <media/dvb_frontend.h>
-#include <media/dvb_ringbuffer.h>
-#include <media/dvb_ca_en50221.h>
 #include <media/dvb_net.h>
+#include <media/dvb_ringbuffer.h>
 
 #define DDBRIDGE_VERSION "0.9.33-integrated"
 
index 240635be7a317c8167ede05b5471ee99bbc43690..7caab9b8c2b9974a8283236910e32a34e356bd1f 100644 (file)
@@ -10,8 +10,6 @@
 #define CIO2_PCI_ID                                    0x9d32
 #define CIO2_PCI_BAR                                   0
 #define CIO2_DMA_MASK                                  DMA_BIT_MASK(39)
-#define CIO2_IMAGE_MAX_WIDTH                           4224
-#define CIO2_IMAGE_MAX_LENGTH                          3136
 
 #define CIO2_IMAGE_MAX_WIDTH                           4224
 #define CIO2_IMAGE_MAX_LENGTH                          3136
index a66f8b87252014131f7ca2b30066e0047bc213db..6c269ecd8d05fd89407414ad413878c88c97df75 100644 (file)
@@ -829,17 +829,18 @@ static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vou
        return ivtv_get_output(itv, vout->index, vout);
 }
 
-static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+static int ivtv_g_pixelaspect(struct file *file, void *fh,
+                             int type, struct v4l2_fract *f)
 {
        struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
-       if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               cropcap->pixelaspect.numerator = itv->is_50hz ? 54 : 11;
-               cropcap->pixelaspect.denominator = itv->is_50hz ? 59 : 10;
-       } else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               cropcap->pixelaspect.numerator = itv->is_out_50hz ? 54 : 11;
-               cropcap->pixelaspect.denominator = itv->is_out_50hz ? 59 : 10;
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               f->numerator = itv->is_50hz ? 54 : 11;
+               f->denominator = itv->is_50hz ? 59 : 10;
+       } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               f->numerator = itv->is_out_50hz ? 54 : 11;
+               f->denominator = itv->is_out_50hz ? 59 : 10;
        } else {
                return -EINVAL;
        }
@@ -1923,7 +1924,7 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_enum_input                  = ivtv_enum_input,
        .vidioc_enum_output                 = ivtv_enum_output,
        .vidioc_enumaudout                  = ivtv_enumaudout,
-       .vidioc_cropcap                     = ivtv_cropcap,
+       .vidioc_g_pixelaspect               = ivtv_g_pixelaspect,
        .vidioc_s_selection                 = ivtv_s_selection,
        .vidioc_g_selection                 = ivtv_g_selection,
        .vidioc_g_input                     = ivtv_g_input,
index 7eb75cb7d75aec93f278252face98ace1ddd6d6f..e544bb9bab902de8fd412a5acff3e7216eb57f7c 100644 (file)
@@ -19,7 +19,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index 8984b1bf57a58f88604479fb5f813b7d21555545..aa98ea49558ce5615bbed1e7df60c291e4a62dd9 100644 (file)
@@ -1419,8 +1419,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
        del_timer(&dev->vbi_q.timeout);
        del_timer(&dev->ts_q.timeout);
 
-       if (dev->remote)
-               saa7134_ir_stop(dev);
+       if (dev->remote && dev->remote->dev->users)
+               saa7134_ir_close(dev->remote->dev);
 
        pci_save_state(pci_dev);
        pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
@@ -1447,8 +1447,8 @@ static int saa7134_resume(struct pci_dev *pci_dev)
                saa7134_videoport_init(dev);
        if (card_has_mpeg(dev))
                saa7134_ts_init_hw(dev);
-       if (dev->remote)
-               saa7134_ir_start(dev);
+       if (dev->remote && dev->remote->dev->users)
+               saa7134_ir_open(dev->remote->dev);
        saa7134_hw_enable1(dev);
 
        msleep(100);
index 999b2774b220afb0269d2d1b08cc825b46201689..35884d5b8337e4de51c939c99588132c57f7eca7 100644 (file)
@@ -299,43 +299,6 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol,
        return 1;
 }
 
-static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol,
-                          u32 *scancode, u8 *toggle)
-{
-       int rc;
-       unsigned char buf[5];
-
-       /* poll IR chip */
-       rc = i2c_master_recv(ir->c, buf, 5);
-       if (rc != 5) {
-               ir_dbg(ir, "read error\n");
-               if (rc < 0)
-                       return rc;
-               return -EIO;
-       }
-
-       /* Check if some key were pressed */
-       if (!(buf[0] & 0x80))
-               return 0;
-
-       /*
-        * buf[3] & 0x80 is always high.
-        * buf[3] & 0x40 is a parity bit. A repeat event is marked
-        * by preserving it into two separate readings
-        * buf[4] bits 0 and 1, and buf[1] and buf[2] are always
-        * zero.
-        *
-        * Note that the keymap which the hvr1110 uses is RC5.
-        *
-        * FIXME: start bits could maybe be used...?
-        */
-       *protocol = RC_PROTO_RC5;
-       *scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2);
-       *toggle = !!(buf[3] & 0x40);
-       return 1;
-}
-
-
 static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol,
                              u32 *scancode, u8 *toggle)
 {
@@ -485,17 +448,10 @@ static void saa7134_input_timer(struct timer_list *t)
        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
-static int __saa7134_ir_start(void *priv)
+int saa7134_ir_open(struct rc_dev *rc)
 {
-       struct saa7134_dev *dev = priv;
-       struct saa7134_card_ir *ir;
-
-       if (!dev || !dev->remote)
-               return -EINVAL;
-
-       ir  = dev->remote;
-       if (ir->running)
-               return 0;
+       struct saa7134_dev *dev = rc->priv;
+       struct saa7134_card_ir *ir = dev->remote;
 
        /* Moved here from saa7134_input_init1() because the latter
         * is not called on device resume */
@@ -544,55 +500,15 @@ static int __saa7134_ir_start(void *priv)
        return 0;
 }
 
-static void __saa7134_ir_stop(void *priv)
+void saa7134_ir_close(struct rc_dev *rc)
 {
-       struct saa7134_dev *dev = priv;
-       struct saa7134_card_ir *ir;
-
-       if (!dev || !dev->remote)
-               return;
-
-       ir  = dev->remote;
-       if (!ir->running)
-               return;
+       struct saa7134_dev *dev = rc->priv;
+       struct saa7134_card_ir *ir = dev->remote;
 
        if (ir->polling)
                del_timer_sync(&ir->timer);
 
        ir->running = false;
-
-       return;
-}
-
-int saa7134_ir_start(struct saa7134_dev *dev)
-{
-       if (dev->remote->users)
-               return __saa7134_ir_start(dev);
-
-       return 0;
-}
-
-void saa7134_ir_stop(struct saa7134_dev *dev)
-{
-       if (dev->remote->users)
-               __saa7134_ir_stop(dev);
-}
-
-static int saa7134_ir_open(struct rc_dev *rc)
-{
-       struct saa7134_dev *dev = rc->priv;
-
-       dev->remote->users++;
-       return __saa7134_ir_start(dev);
-}
-
-static void saa7134_ir_close(struct rc_dev *rc)
-{
-       struct saa7134_dev *dev = rc->priv;
-
-       dev->remote->users--;
-       if (!dev->remote->users)
-               __saa7134_ir_stop(dev);
 }
 
 int saa7134_input_init1(struct saa7134_dev *dev)
@@ -661,7 +577,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
                polling      = 50; // ms
-               /* GPIO stuff moved to __saa7134_ir_start() */
+               /* GPIO stuff moved to saa7134_ir_open() */
                break;
        case SAA7134_BOARD_AVERMEDIA_M135A:
                ir_codes     = RC_MAP_AVERMEDIA_M135A;
@@ -683,14 +599,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; // ms
-               /* GPIO stuff moved to __saa7134_ir_start() */
+               /* GPIO stuff moved to saa7134_ir_open() */
                break;
        case SAA7134_BOARD_AVERMEDIA_A16D:
                ir_codes     = RC_MAP_AVERMEDIA_A16D;
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; /* ms */
-               /* GPIO stuff moved to __saa7134_ir_start() */
+               /* GPIO stuff moved to saa7134_ir_open() */
                break;
        case SAA7134_BOARD_KWORLD_TERMINATOR:
                ir_codes     = RC_MAP_PIXELVIEW;
@@ -742,7 +658,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0003CC;
                mask_keydown = 0x000010;
                polling      = 5; /* ms */
-               /* GPIO stuff moved to __saa7134_ir_start() */
+               /* GPIO stuff moved to saa7134_ir_open() */
                break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -880,8 +796,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir->raw_decode   = raw_decode;
 
        /* init input device */
-       snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
-                saa7134_boards[dev->board].name);
        snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
                 pci_name(dev->pci));
 
@@ -893,7 +807,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
        }
 
-       rc->device_name = ir->name;
+       rc->device_name = saa7134_boards[dev->board].name;
        rc->input_phys = ir->phys;
        rc->input_id.bustype = BUS_PCI;
        rc->input_id.version = 1;
@@ -929,7 +843,6 @@ void saa7134_input_fini(struct saa7134_dev *dev)
        if (NULL == dev->remote)
                return;
 
-       saa7134_ir_stop(dev);
        rc_unregister_device(dev->remote->dev);
        kfree(dev->remote);
        dev->remote = NULL;
@@ -1031,9 +944,11 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                        (1 == rc) ? "yes" : "no");
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-               dev->init_data.name = "HVR 1110";
-               dev->init_data.get_key = get_key_hvr1110;
+               dev->init_data.name = saa7134_boards[dev->board].name;
                dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+               dev->init_data.type = RC_PROTO_BIT_RC5 |
+                               RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32;
+               dev->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
                info.addr = 0x71;
                break;
        case SAA7134_BOARD_BEHOLD_607FM_MK3:
index 8f28741ebb359c7a77456cf6637ed9e689be10d1..5bc4b8fc8ebfdd9f0e940207c6af9e004e5d37e4 100644 (file)
@@ -1650,23 +1650,22 @@ int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std)
 }
 EXPORT_SYMBOL_GPL(saa7134_querystd);
 
-static int saa7134_cropcap(struct file *file, void *priv,
-                                       struct v4l2_cropcap *cap)
+static int saa7134_g_pixelaspect(struct file *file, void *priv,
+                                int type, struct v4l2_fract *f)
 {
        struct saa7134_dev *dev = video_drvdata(file);
 
-       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-           cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
                return -EINVAL;
-       cap->pixelaspect.numerator   = 1;
-       cap->pixelaspect.denominator = 1;
+
        if (dev->tvnorm->id & V4L2_STD_525_60) {
-               cap->pixelaspect.numerator   = 11;
-               cap->pixelaspect.denominator = 10;
+               f->numerator   = 11;
+               f->denominator = 10;
        }
        if (dev->tvnorm->id & V4L2_STD_625_50) {
-               cap->pixelaspect.numerator   = 54;
-               cap->pixelaspect.denominator = 59;
+               f->numerator   = 54;
+               f->denominator = 59;
        }
        return 0;
 }
@@ -1987,7 +1986,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap         = saa7134_try_get_set_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap           = saa7134_try_get_set_fmt_vbi_cap,
-       .vidioc_cropcap                 = saa7134_cropcap,
+       .vidioc_g_pixelaspect           = saa7134_g_pixelaspect,
        .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
        .vidioc_querybuf                = vb2_ioctl_querybuf,
        .vidioc_qbuf                    = vb2_ioctl_qbuf,
index 4802284560140ec1395b69daba439ef4bdf6ceb4..50b1d07d2ac15415eb458ae2825c3feab88463f5 100644 (file)
@@ -123,9 +123,7 @@ struct saa7134_format {
 struct saa7134_card_ir {
        struct rc_dev           *dev;
 
-       char                    name[32];
        char                    phys[32];
-       unsigned                users;
 
        u32                     polling;
        u32                     last_gpio;
@@ -923,13 +921,13 @@ int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
 void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
-int saa7134_ir_start(struct saa7134_dev *dev);
-void saa7134_ir_stop(struct saa7134_dev *dev);
+int saa7134_ir_open(struct rc_dev *dev);
+void saa7134_ir_close(struct rc_dev *dev);
 #else
 #define saa7134_input_init1(dev)       ((void)0)
 #define saa7134_input_fini(dev)                ((void)0)
 #define saa7134_input_irq(dev)         ((void)0)
 #define saa7134_probe_i2c_ir(dev)      ((void)0)
-#define saa7134_ir_start(dev)          ((void)0)
-#define saa7134_ir_stop(dev)           ((void)0)
+#define saa7134_ir_open(dev)           ((void)0)
+#define saa7134_ir_close(dev)          ((void)0)
 #endif
index 70c4f6c54881cc097f8d90c8cea3bb61115a44ab..a505e9f5a1e20d68bf0ba04ce496662882096140 100644 (file)
@@ -32,6 +32,15 @@ source "drivers/media/platform/davinci/Kconfig"
 
 source "drivers/media/platform/omap/Kconfig"
 
+config VIDEO_ASPEED
+       tristate "Aspeed AST2400 and AST2500 Video Engine driver"
+       depends on VIDEO_V4L2
+       select VIDEOBUF2_DMA_CONTIG
+       help
+         Support for the Aspeed Video Engine (VE) embedded in the Aspeed
+         AST2400 and AST2500 SOCs. The VE can capture and compress video data
+         from digital or analog sources.
+
 config VIDEO_SH_VOU
        tristate "SuperH VOU video output driver"
        depends on MEDIA_CAMERA_SUPPORT
@@ -138,6 +147,7 @@ source "drivers/media/platform/am437x/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
 source "drivers/media/platform/rcar-vin/Kconfig"
 source "drivers/media/platform/atmel/Kconfig"
+source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
 
 config VIDEO_TI_CAL
        tristate "TI CAL (Camera Adaptation Layer) driver"
@@ -625,6 +635,28 @@ config VIDEO_TEGRA_HDMI_CEC
         The CEC bus is present in the HDMI connector and enables communication
         between compatible devices.
 
+config VIDEO_SECO_CEC
+       tristate "SECO Boards HDMI CEC driver"
+       depends on (X86 || IA64) || COMPILE_TEST
+       depends on PCI && DMI
+       select CEC_CORE
+       select CEC_NOTIFIER
+       help
+         This is a driver for SECO Boards integrated CEC interface.
+         Selecting it will enable support for this device.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
+config VIDEO_SECO_RC
+       bool "SECO Boards IR RC5 support"
+       depends on VIDEO_SECO_CEC
+       select RC_CORE
+       help
+         If you say yes here you will get support for the
+         SECO Boards Consumer-IR in seco-cec driver.
+         The embedded controller supports RC5 protocol only, default mapping
+         is set to rc-hauppauge.
+
 endif #CEC_PLATFORM_DRIVERS
 
 menuconfig SDR_PLATFORM_DRIVERS
index 6ab6200dd9c999aac4b30992ac775a56d6e3c66b..e6deb25977380f16bf861cf4e4e70a8ce7b034dd 100644 (file)
@@ -3,6 +3,7 @@
 # Makefile for the video capture/playback device drivers.
 #
 
+obj-$(CONFIG_VIDEO_ASPEED)             += aspeed-video.o
 obj-$(CONFIG_VIDEO_CADENCE)            += cadence/
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
@@ -55,6 +56,8 @@ obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC)    += tegra-cec/
 
 obj-y                                  += stm32/
 
+obj-$(CONFIG_VIDEO_SECO_CEC)           += seco-cec/
+
 obj-y                                  += davinci/
 
 obj-$(CONFIG_VIDEO_SH_VOU)             += sh_vou.o
@@ -98,3 +101,5 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS)               += qcom/venus/
 obj-y                                  += meson/
 
 obj-y                                  += cros-ec-cec/
+
+obj-$(CONFIG_VIDEO_SUN6I_CSI)          += sunxi/sun6i-csi/
index e13d2b3a7168ff3897f2561dc33415c86f0e86d8..5c17624aaade9797c1adb0d809eab0582d549e0d 100644 (file)
@@ -2081,24 +2081,18 @@ static void vpfe_stop_streaming(struct vb2_queue *vq)
        spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
 }
 
-static int vpfe_cropcap(struct file *file, void *priv,
-                       struct v4l2_cropcap *crop)
+static int vpfe_g_pixelaspect(struct file *file, void *priv,
+                             int type, struct v4l2_fract *f)
 {
        struct vpfe_device *vpfe = video_drvdata(file);
 
-       vpfe_dbg(2, vpfe, "vpfe_cropcap\n");
+       vpfe_dbg(2, vpfe, "vpfe_g_pixelaspect\n");
 
-       if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
                return -EINVAL;
 
-       memset(crop, 0, sizeof(struct v4l2_cropcap));
-
-       crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       crop->defrect.width = vpfe_standards[vpfe->std_index].width;
-       crop->bounds.width = crop->defrect.width;
-       crop->defrect.height = vpfe_standards[vpfe->std_index].height;
-       crop->bounds.height = crop->defrect.height;
-       crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect;
+       *f = vpfe_standards[vpfe->std_index].pixelaspect;
 
        return 0;
 }
@@ -2108,12 +2102,17 @@ vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
 {
        struct vpfe_device *vpfe = video_drvdata(file);
 
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
+               return -EINVAL;
+
        switch (s->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
        case V4L2_SEL_TGT_CROP_DEFAULT:
-               s->r.left = s->r.top = 0;
-               s->r.width = vpfe->crop.width;
-               s->r.height = vpfe->crop.height;
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = vpfe_standards[vpfe->std_index].width;
+               s->r.height = vpfe_standards[vpfe->std_index].height;
                break;
 
        case V4L2_SEL_TGT_CROP:
@@ -2282,7 +2281,7 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 
-       .vidioc_cropcap                 = vpfe_cropcap,
+       .vidioc_g_pixelaspect           = vpfe_g_pixelaspect,
        .vidioc_g_selection             = vpfe_g_selection,
        .vidioc_s_selection             = vpfe_s_selection,
 
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
new file mode 100644 (file)
index 0000000..dfec813
--- /dev/null
@@ -0,0 +1,1729 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/atomic.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/v4l2-controls.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define DEVICE_NAME                    "aspeed-video"
+
+#define ASPEED_VIDEO_JPEG_NUM_QUALITIES        12
+#define ASPEED_VIDEO_JPEG_HEADER_SIZE  10
+#define ASPEED_VIDEO_JPEG_QUANT_SIZE   116
+#define ASPEED_VIDEO_JPEG_DCT_SIZE     34
+
+#define MAX_FRAME_RATE                 60
+#define MAX_HEIGHT                     1200
+#define MAX_WIDTH                      1920
+#define MIN_HEIGHT                     480
+#define MIN_WIDTH                      640
+
+#define NUM_POLARITY_CHECKS            10
+#define INVALID_RESOLUTION_RETRIES     2
+#define INVALID_RESOLUTION_DELAY       msecs_to_jiffies(250)
+#define RESOLUTION_CHANGE_DELAY                msecs_to_jiffies(500)
+#define MODE_DETECT_TIMEOUT            msecs_to_jiffies(500)
+#define STOP_TIMEOUT                   msecs_to_jiffies(1000)
+#define DIRECT_FETCH_THRESHOLD         0x0c0000 /* 1024 * 768 */
+
+#define VE_MAX_SRC_BUFFER_SIZE         0x8ca000 /* 1920 * 1200, 32bpp */
+#define VE_JPEG_HEADER_SIZE            0x006000 /* 512 * 12 * 4 */
+
+#define VE_PROTECTION_KEY              0x000
+#define  VE_PROTECTION_KEY_UNLOCK      0x1a038aa8
+
+#define VE_SEQ_CTRL                    0x004
+#define  VE_SEQ_CTRL_TRIG_MODE_DET     BIT(0)
+#define  VE_SEQ_CTRL_TRIG_CAPTURE      BIT(1)
+#define  VE_SEQ_CTRL_FORCE_IDLE                BIT(2)
+#define  VE_SEQ_CTRL_MULT_FRAME                BIT(3)
+#define  VE_SEQ_CTRL_TRIG_COMP         BIT(4)
+#define  VE_SEQ_CTRL_AUTO_COMP         BIT(5)
+#define  VE_SEQ_CTRL_EN_WATCHDOG       BIT(7)
+#define  VE_SEQ_CTRL_YUV420            BIT(10)
+#define  VE_SEQ_CTRL_COMP_FMT          GENMASK(11, 10)
+#define  VE_SEQ_CTRL_HALT              BIT(12)
+#define  VE_SEQ_CTRL_EN_WATCHDOG_COMP  BIT(14)
+#define  VE_SEQ_CTRL_TRIG_JPG          BIT(15)
+#define  VE_SEQ_CTRL_CAP_BUSY          BIT(16)
+#define  VE_SEQ_CTRL_COMP_BUSY         BIT(18)
+
+#ifdef CONFIG_MACH_ASPEED_G5
+#define  VE_SEQ_CTRL_JPEG_MODE         BIT(13) /* AST2500 */
+#else
+#define  VE_SEQ_CTRL_JPEG_MODE         BIT(8)  /* AST2400 */
+#endif /* CONFIG_MACH_ASPEED_G5 */
+
+#define VE_CTRL                                0x008
+#define  VE_CTRL_HSYNC_POL             BIT(0)
+#define  VE_CTRL_VSYNC_POL             BIT(1)
+#define  VE_CTRL_SOURCE                        BIT(2)
+#define  VE_CTRL_INT_DE                        BIT(4)
+#define  VE_CTRL_DIRECT_FETCH          BIT(5)
+#define  VE_CTRL_YUV                   BIT(6)
+#define  VE_CTRL_RGB                   BIT(7)
+#define  VE_CTRL_CAPTURE_FMT           GENMASK(7, 6)
+#define  VE_CTRL_AUTO_OR_CURSOR                BIT(8)
+#define  VE_CTRL_CLK_INVERSE           BIT(11)
+#define  VE_CTRL_CLK_DELAY             GENMASK(11, 9)
+#define  VE_CTRL_INTERLACE             BIT(14)
+#define  VE_CTRL_HSYNC_POL_CTRL                BIT(15)
+#define  VE_CTRL_FRC                   GENMASK(23, 16)
+
+#define VE_TGS_0                       0x00c
+#define VE_TGS_1                       0x010
+#define  VE_TGS_FIRST                  GENMASK(28, 16)
+#define  VE_TGS_LAST                   GENMASK(12, 0)
+
+#define VE_SCALING_FACTOR              0x014
+#define VE_SCALING_FILTER0             0x018
+#define VE_SCALING_FILTER1             0x01c
+#define VE_SCALING_FILTER2             0x020
+#define VE_SCALING_FILTER3             0x024
+
+#define VE_CAP_WINDOW                  0x030
+#define VE_COMP_WINDOW                 0x034
+#define VE_COMP_PROC_OFFSET            0x038
+#define VE_COMP_OFFSET                 0x03c
+#define VE_JPEG_ADDR                   0x040
+#define VE_SRC0_ADDR                   0x044
+#define VE_SRC_SCANLINE_OFFSET         0x048
+#define VE_SRC1_ADDR                   0x04c
+#define VE_COMP_ADDR                   0x054
+
+#define VE_STREAM_BUF_SIZE             0x058
+#define  VE_STREAM_BUF_SIZE_N_PACKETS  GENMASK(5, 3)
+#define  VE_STREAM_BUF_SIZE_P_SIZE     GENMASK(2, 0)
+
+#define VE_COMP_CTRL                   0x060
+#define  VE_COMP_CTRL_VQ_DCT_ONLY      BIT(0)
+#define  VE_COMP_CTRL_VQ_4COLOR                BIT(1)
+#define  VE_COMP_CTRL_QUANTIZE         BIT(2)
+#define  VE_COMP_CTRL_EN_BQ            BIT(4)
+#define  VE_COMP_CTRL_EN_CRYPTO                BIT(5)
+#define  VE_COMP_CTRL_DCT_CHR          GENMASK(10, 6)
+#define  VE_COMP_CTRL_DCT_LUM          GENMASK(15, 11)
+#define  VE_COMP_CTRL_EN_HQ            BIT(16)
+#define  VE_COMP_CTRL_RSVD             BIT(19)
+#define  VE_COMP_CTRL_ENCODE           GENMASK(21, 20)
+#define  VE_COMP_CTRL_HQ_DCT_CHR       GENMASK(26, 22)
+#define  VE_COMP_CTRL_HQ_DCT_LUM       GENMASK(31, 27)
+
+#define VE_OFFSET_COMP_STREAM          0x078
+
+#define VE_SRC_LR_EDGE_DET             0x090
+#define  VE_SRC_LR_EDGE_DET_LEFT       GENMASK(11, 0)
+#define  VE_SRC_LR_EDGE_DET_NO_V       BIT(12)
+#define  VE_SRC_LR_EDGE_DET_NO_H       BIT(13)
+#define  VE_SRC_LR_EDGE_DET_NO_DISP    BIT(14)
+#define  VE_SRC_LR_EDGE_DET_NO_CLK     BIT(15)
+#define  VE_SRC_LR_EDGE_DET_RT_SHF     16
+#define  VE_SRC_LR_EDGE_DET_RT         GENMASK(27, VE_SRC_LR_EDGE_DET_RT_SHF)
+#define  VE_SRC_LR_EDGE_DET_INTERLACE  BIT(31)
+
+#define VE_SRC_TB_EDGE_DET             0x094
+#define  VE_SRC_TB_EDGE_DET_TOP                GENMASK(12, 0)
+#define  VE_SRC_TB_EDGE_DET_BOT_SHF    16
+#define  VE_SRC_TB_EDGE_DET_BOT                GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF)
+
+#define VE_MODE_DETECT_STATUS          0x098
+#define  VE_MODE_DETECT_H_PIXELS       GENMASK(11, 0)
+#define  VE_MODE_DETECT_V_LINES_SHF    16
+#define  VE_MODE_DETECT_V_LINES                GENMASK(27, VE_MODE_DETECT_V_LINES_SHF)
+#define  VE_MODE_DETECT_STATUS_VSYNC   BIT(28)
+#define  VE_MODE_DETECT_STATUS_HSYNC   BIT(29)
+
+#define VE_SYNC_STATUS                 0x09c
+#define  VE_SYNC_STATUS_HSYNC          GENMASK(11, 0)
+#define  VE_SYNC_STATUS_VSYNC_SHF      16
+#define  VE_SYNC_STATUS_VSYNC          GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF)
+
+#define VE_INTERRUPT_CTRL              0x304
+#define VE_INTERRUPT_STATUS            0x308
+#define  VE_INTERRUPT_MODE_DETECT_WD   BIT(0)
+#define  VE_INTERRUPT_CAPTURE_COMPLETE BIT(1)
+#define  VE_INTERRUPT_COMP_READY       BIT(2)
+#define  VE_INTERRUPT_COMP_COMPLETE    BIT(3)
+#define  VE_INTERRUPT_MODE_DETECT      BIT(4)
+#define  VE_INTERRUPT_FRAME_COMPLETE   BIT(5)
+#define  VE_INTERRUPT_DECODE_ERR       BIT(6)
+#define  VE_INTERRUPT_HALT_READY       BIT(8)
+#define  VE_INTERRUPT_HANG_WD          BIT(9)
+#define  VE_INTERRUPT_STREAM_DESC      BIT(10)
+#define  VE_INTERRUPT_VSYNC_DESC       BIT(11)
+
+#define VE_MODE_DETECT                 0x30c
+#define VE_MEM_RESTRICT_START          0x310
+#define VE_MEM_RESTRICT_END            0x314
+
+enum {
+       VIDEO_MODE_DETECT_DONE,
+       VIDEO_RES_CHANGE,
+       VIDEO_RES_DETECT,
+       VIDEO_STREAMING,
+       VIDEO_FRAME_INPRG,
+       VIDEO_STOPPED,
+};
+
+struct aspeed_video_addr {
+       unsigned int size;
+       dma_addr_t dma;
+       void *virt;
+};
+
+struct aspeed_video_buffer {
+       struct vb2_v4l2_buffer vb;
+       struct list_head link;
+};
+
+#define to_aspeed_video_buffer(x) \
+       container_of((x), struct aspeed_video_buffer, vb)
+
+struct aspeed_video {
+       void __iomem *base;
+       struct clk *eclk;
+       struct clk *vclk;
+       struct reset_control *rst;
+
+       struct device *dev;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_pix_format pix_fmt;
+       struct v4l2_bt_timings active_timings;
+       struct v4l2_bt_timings detected_timings;
+       u32 v4l2_input_status;
+       struct vb2_queue queue;
+       struct video_device vdev;
+       struct mutex video_lock;        /* v4l2 and videobuf2 lock */
+
+       wait_queue_head_t wait;
+       spinlock_t lock;                /* buffer list lock */
+       struct delayed_work res_work;
+       struct list_head buffers;
+       unsigned long flags;
+       unsigned int sequence;
+
+       unsigned int max_compressed_size;
+       struct aspeed_video_addr srcs[2];
+       struct aspeed_video_addr jpeg;
+
+       bool yuv420;
+       unsigned int frame_rate;
+       unsigned int jpeg_quality;
+
+       unsigned int frame_bottom;
+       unsigned int frame_left;
+       unsigned int frame_right;
+       unsigned int frame_top;
+};
+
+#define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev)
+
+static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = {
+       0xe0ffd8ff, 0x464a1000, 0x01004649, 0x60000101, 0x00006000, 0x0f00feff,
+       0x00002d05, 0x00000000, 0x00000000, 0x00dbff00
+};
+
+static const u32 aspeed_video_jpeg_quant[ASPEED_VIDEO_JPEG_QUANT_SIZE] = {
+       0x081100c0, 0x00000000, 0x00110103, 0x03011102, 0xc4ff0111, 0x00001f00,
+       0x01010501, 0x01010101, 0x00000000, 0x00000000, 0x04030201, 0x08070605,
+       0xff0b0a09, 0x10b500c4, 0x03010200, 0x03040203, 0x04040505, 0x7d010000,
+       0x00030201, 0x12051104, 0x06413121, 0x07615113, 0x32147122, 0x08a19181,
+       0xc1b14223, 0xf0d15215, 0x72623324, 0x160a0982, 0x1a191817, 0x28272625,
+       0x35342a29, 0x39383736, 0x4544433a, 0x49484746, 0x5554534a, 0x59585756,
+       0x6564635a, 0x69686766, 0x7574736a, 0x79787776, 0x8584837a, 0x89888786,
+       0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4, 0xb2aaa9a8, 0xb6b5b4b3,
+       0xbab9b8b7, 0xc5c4c3c2, 0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9,
+       0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5, 0xc4fffaf9, 0x00011f00,
+       0x01010103, 0x01010101, 0x00000101, 0x00000000, 0x04030201, 0x08070605,
+       0xff0b0a09, 0x11b500c4, 0x02010200, 0x04030404, 0x04040507, 0x77020100,
+       0x03020100, 0x21050411, 0x41120631, 0x71610751, 0x81322213, 0x91421408,
+       0x09c1b1a1, 0xf0523323, 0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918,
+       0x2a292827, 0x38373635, 0x44433a39, 0x48474645, 0x54534a49, 0x58575655,
+       0x64635a59, 0x68676665, 0x74736a69, 0x78777675, 0x83827a79, 0x87868584,
+       0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2, 0xa9a8a7a6, 0xb4b3b2aa,
+       0xb8b7b6b5, 0xc3c2bab9, 0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7,
+       0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5, 0xdafffaf9, 0x01030c00,
+       0x03110200, 0x003f0011
+};
+
+static const u32 aspeed_video_jpeg_dct[ASPEED_VIDEO_JPEG_NUM_QUALITIES]
+                                     [ASPEED_VIDEO_JPEG_DCT_SIZE] = {
+       { 0x0d140043, 0x0c0f110f, 0x11101114, 0x17141516, 0x1e20321e,
+         0x3d1e1b1b, 0x32242e2b, 0x4b4c3f48, 0x44463f47, 0x61735a50,
+         0x566c5550, 0x88644644, 0x7a766c65, 0x4d808280, 0x8c978d60,
+         0x7e73967d, 0xdbff7b80, 0x1f014300, 0x272d2121, 0x3030582d,
+         0x697bb958, 0xb8b9b97b, 0xb9b8a6a6, 0xb9b9b9b9, 0xb9b9b9b9,
+         0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9,
+         0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xffb9b9b9 },
+       { 0x0c110043, 0x0a0d0f0d, 0x0f0e0f11, 0x14111213, 0x1a1c2b1a,
+         0x351a1818, 0x2b1f2826, 0x4142373f, 0x3c3d373e, 0x55644e46,
+         0x4b5f4a46, 0x77573d3c, 0x6b675f58, 0x43707170, 0x7a847b54,
+         0x6e64836d, 0xdbff6c70, 0x1b014300, 0x22271d1d, 0x2a2a4c27,
+         0x5b6ba04c, 0xa0a0a06b, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0,
+         0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0,
+         0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xffa0a0a0 },
+       { 0x090e0043, 0x090a0c0a, 0x0c0b0c0e, 0x110e0f10, 0x15172415,
+         0x2c151313, 0x241a211f, 0x36372e34, 0x31322e33, 0x4653413a,
+         0x3e4e3d3a, 0x62483231, 0x58564e49, 0x385d5e5d, 0x656d6645,
+         0x5b536c5a, 0xdbff595d, 0x16014300, 0x1c201818, 0x22223f20,
+         0x4b58853f, 0x85858558, 0x85858585, 0x85858585, 0x85858585,
+         0x85858585, 0x85858585, 0x85858585, 0x85858585, 0x85858585,
+         0x85858585, 0x85858585, 0x85858585, 0xff858585 },
+       { 0x070b0043, 0x07080a08, 0x0a090a0b, 0x0d0b0c0c, 0x11121c11,
+         0x23110f0f, 0x1c141a19, 0x2b2b2429, 0x27282428, 0x3842332e,
+         0x313e302e, 0x4e392827, 0x46443e3a, 0x2c4a4a4a, 0x50565137,
+         0x48425647, 0xdbff474a, 0x12014300, 0x161a1313, 0x1c1c331a,
+         0x3d486c33, 0x6c6c6c48, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c,
+         0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c,
+         0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0xff6c6c6c },
+       { 0x06090043, 0x05060706, 0x07070709, 0x0a09090a, 0x0d0e160d,
+         0x1b0d0c0c, 0x16101413, 0x21221c20, 0x1e1f1c20, 0x2b332824,
+         0x26302624, 0x3d2d1f1e, 0x3735302d, 0x22393a39, 0x3f443f2b,
+         0x38334338, 0xdbff3739, 0x0d014300, 0x11130e0e, 0x15152613,
+         0x2d355026, 0x50505035, 0x50505050, 0x50505050, 0x50505050,
+         0x50505050, 0x50505050, 0x50505050, 0x50505050, 0x50505050,
+         0x50505050, 0x50505050, 0x50505050, 0xff505050 },
+       { 0x04060043, 0x03040504, 0x05040506, 0x07060606, 0x09090f09,
+         0x12090808, 0x0f0a0d0d, 0x16161315, 0x14151315, 0x1d221b18,
+         0x19201918, 0x281e1514, 0x2423201e, 0x17262726, 0x2a2d2a1c,
+         0x25222d25, 0xdbff2526, 0x09014300, 0x0b0d0a0a, 0x0e0e1a0d,
+         0x1f25371a, 0x37373725, 0x37373737, 0x37373737, 0x37373737,
+         0x37373737, 0x37373737, 0x37373737, 0x37373737, 0x37373737,
+         0x37373737, 0x37373737, 0x37373737, 0xff373737 },
+       { 0x02030043, 0x01020202, 0x02020203, 0x03030303, 0x04040704,
+         0x09040404, 0x07050606, 0x0b0b090a, 0x0a0a090a, 0x0e110d0c,
+         0x0c100c0c, 0x140f0a0a, 0x1211100f, 0x0b131313, 0x1516150e,
+         0x12111612, 0xdbff1213, 0x04014300, 0x05060505, 0x07070d06,
+         0x0f121b0d, 0x1b1b1b12, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b,
+         0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b,
+         0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0xff1b1b1b },
+       { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503,
+         0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908,
+         0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09,
+         0x0c0b0f0c, 0xdbff0c0c, 0x03014300, 0x03040303, 0x04040804,
+         0x0a0c1208, 0x1212120c, 0x12121212, 0x12121212, 0x12121212,
+         0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+         0x12121212, 0x12121212, 0x12121212, 0xff121212 },
+       { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503,
+         0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908,
+         0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09,
+         0x0c0b0f0c, 0xdbff0c0c, 0x02014300, 0x03030202, 0x04040703,
+         0x080a0f07, 0x0f0f0f0a, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f,
+         0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f,
+         0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0xff0f0f0f },
+       { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x02020302,
+         0x04020202, 0x03020303, 0x05050405, 0x05050405, 0x07080606,
+         0x06080606, 0x0a070505, 0x09080807, 0x05090909, 0x0a0b0a07,
+         0x09080b09, 0xdbff0909, 0x02014300, 0x02030202, 0x03030503,
+         0x07080c05, 0x0c0c0c08, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+         0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+         0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xff0c0c0c },
+       { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010201,
+         0x03010101, 0x02010202, 0x03030303, 0x03030303, 0x04050404,
+         0x04050404, 0x06050303, 0x06050505, 0x03060606, 0x07070704,
+         0x06050706, 0xdbff0606, 0x01014300, 0x01020101, 0x02020402,
+         0x05060904, 0x09090906, 0x09090909, 0x09090909, 0x09090909,
+         0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909,
+         0x09090909, 0x09090909, 0x09090909, 0xff090909 },
+       { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010101,
+         0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202,
+         0x02020202, 0x03020101, 0x03020202, 0x01030303, 0x03030302,
+         0x03020303, 0xdbff0403, 0x01014300, 0x01010101, 0x01010201,
+         0x03040602, 0x06060604, 0x06060606, 0x06060606, 0x06060606,
+         0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+         0x06060606, 0x06060606, 0x06060606, 0xff060606 }
+};
+
+static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = {
+       .type = V4L2_DV_BT_656_1120,
+       .bt = {
+               .min_width = MIN_WIDTH,
+               .max_width = MAX_WIDTH,
+               .min_height = MIN_HEIGHT,
+               .max_height = MAX_HEIGHT,
+               .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */
+               .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */
+               .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+                       V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
+               .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
+                       V4L2_DV_BT_CAP_REDUCED_BLANKING |
+                       V4L2_DV_BT_CAP_CUSTOM,
+       },
+};
+
+static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
+{
+       int i;
+       unsigned int base;
+
+       for (i = 0; i < ASPEED_VIDEO_JPEG_NUM_QUALITIES; i++) {
+               base = 256 * i; /* AST HW requires this header spacing */
+               memcpy(&table[base], aspeed_video_jpeg_header,
+                      sizeof(aspeed_video_jpeg_header));
+
+               base += ASPEED_VIDEO_JPEG_HEADER_SIZE;
+               memcpy(&table[base], aspeed_video_jpeg_dct[i],
+                      sizeof(aspeed_video_jpeg_dct[i]));
+
+               base += ASPEED_VIDEO_JPEG_DCT_SIZE;
+               memcpy(&table[base], aspeed_video_jpeg_quant,
+                      sizeof(aspeed_video_jpeg_quant));
+
+               if (yuv420)
+                       table[base + 2] = 0x00220103;
+       }
+}
+
+static void aspeed_video_update(struct aspeed_video *video, u32 reg, u32 clear,
+                               u32 bits)
+{
+       u32 t = readl(video->base + reg);
+       u32 before = t;
+
+       t &= ~clear;
+       t |= bits;
+       writel(t, video->base + reg);
+       dev_dbg(video->dev, "update %03x[%08x -> %08x]\n", reg, before,
+               readl(video->base + reg));
+}
+
+static u32 aspeed_video_read(struct aspeed_video *video, u32 reg)
+{
+       u32 t = readl(video->base + reg);
+
+       dev_dbg(video->dev, "read %03x[%08x]\n", reg, t);
+       return t;
+}
+
+static void aspeed_video_write(struct aspeed_video *video, u32 reg, u32 val)
+{
+       writel(val, video->base + reg);
+       dev_dbg(video->dev, "write %03x[%08x]\n", reg,
+               readl(video->base + reg));
+}
+
+static int aspeed_video_start_frame(struct aspeed_video *video)
+{
+       dma_addr_t addr;
+       unsigned long flags;
+       struct aspeed_video_buffer *buf;
+       u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
+
+       if (video->v4l2_input_status) {
+               dev_dbg(video->dev, "No signal; don't start frame\n");
+               return 0;
+       }
+
+       if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) ||
+           !(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) {
+               dev_err(video->dev, "Engine busy; don't start frame\n");
+               return -EBUSY;
+       }
+
+       spin_lock_irqsave(&video->lock, flags);
+       buf = list_first_entry_or_null(&video->buffers,
+                                      struct aspeed_video_buffer, link);
+       if (!buf) {
+               spin_unlock_irqrestore(&video->lock, flags);
+               dev_dbg(video->dev, "No buffers; don't start frame\n");
+               return -EPROTO;
+       }
+
+       set_bit(VIDEO_FRAME_INPRG, &video->flags);
+       addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+       spin_unlock_irqrestore(&video->lock, flags);
+
+       aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0);
+       aspeed_video_write(video, VE_COMP_OFFSET, 0);
+       aspeed_video_write(video, VE_COMP_ADDR, addr);
+
+       aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
+                           VE_INTERRUPT_COMP_COMPLETE |
+                           VE_INTERRUPT_CAPTURE_COMPLETE);
+
+       aspeed_video_update(video, VE_SEQ_CTRL, 0,
+                           VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP);
+
+       return 0;
+}
+
+static void aspeed_video_enable_mode_detect(struct aspeed_video *video)
+{
+       /* Enable mode detect interrupts */
+       aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
+                           VE_INTERRUPT_MODE_DETECT);
+
+       /* Trigger mode detect */
+       aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET);
+}
+
+static void aspeed_video_reset(struct aspeed_video *video)
+{
+       /* Reset the engine */
+       reset_control_assert(video->rst);
+
+       /* Don't usleep here; function may be called in interrupt context */
+       udelay(100);
+       reset_control_deassert(video->rst);
+}
+
+static void aspeed_video_off(struct aspeed_video *video)
+{
+       aspeed_video_reset(video);
+
+       /* Turn off the relevant clocks */
+       clk_disable_unprepare(video->vclk);
+       clk_disable_unprepare(video->eclk);
+}
+
+static void aspeed_video_on(struct aspeed_video *video)
+{
+       /* Turn on the relevant clocks */
+       clk_prepare_enable(video->eclk);
+       clk_prepare_enable(video->vclk);
+
+       aspeed_video_reset(video);
+}
+
+static void aspeed_video_bufs_done(struct aspeed_video *video,
+                                  enum vb2_buffer_state state)
+{
+       unsigned long flags;
+       struct aspeed_video_buffer *buf;
+
+       spin_lock_irqsave(&video->lock, flags);
+       list_for_each_entry(buf, &video->buffers, link)
+               vb2_buffer_done(&buf->vb.vb2_buf, state);
+       INIT_LIST_HEAD(&video->buffers);
+       spin_unlock_irqrestore(&video->lock, flags);
+}
+
+static void aspeed_video_irq_res_change(struct aspeed_video *video)
+{
+       dev_dbg(video->dev, "Resolution changed; resetting\n");
+
+       set_bit(VIDEO_RES_CHANGE, &video->flags);
+       clear_bit(VIDEO_FRAME_INPRG, &video->flags);
+
+       aspeed_video_off(video);
+       aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
+
+       schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY);
+}
+
+static irqreturn_t aspeed_video_irq(int irq, void *arg)
+{
+       struct aspeed_video *video = arg;
+       u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS);
+
+       /*
+        * Resolution changed or signal was lost; reset the engine and
+        * re-initialize
+        */
+       if (sts & VE_INTERRUPT_MODE_DETECT_WD) {
+               aspeed_video_irq_res_change(video);
+               return IRQ_HANDLED;
+       }
+
+       if (sts & VE_INTERRUPT_MODE_DETECT) {
+               if (test_bit(VIDEO_RES_DETECT, &video->flags)) {
+                       aspeed_video_update(video, VE_INTERRUPT_CTRL,
+                                           VE_INTERRUPT_MODE_DETECT, 0);
+                       aspeed_video_write(video, VE_INTERRUPT_STATUS,
+                                          VE_INTERRUPT_MODE_DETECT);
+
+                       set_bit(VIDEO_MODE_DETECT_DONE, &video->flags);
+                       wake_up_interruptible_all(&video->wait);
+               } else {
+                       /*
+                        * Signal acquired while NOT doing resolution
+                        * detection; reset the engine and re-initialize
+                        */
+                       aspeed_video_irq_res_change(video);
+                       return IRQ_HANDLED;
+               }
+       }
+
+       if ((sts & VE_INTERRUPT_COMP_COMPLETE) &&
+           (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) {
+               struct aspeed_video_buffer *buf;
+               u32 frame_size = aspeed_video_read(video,
+                                                  VE_OFFSET_COMP_STREAM);
+
+               spin_lock(&video->lock);
+               clear_bit(VIDEO_FRAME_INPRG, &video->flags);
+               buf = list_first_entry_or_null(&video->buffers,
+                                              struct aspeed_video_buffer,
+                                              link);
+               if (buf) {
+                       vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size);
+
+                       if (!list_is_last(&buf->link, &video->buffers)) {
+                               buf->vb.vb2_buf.timestamp = ktime_get_ns();
+                               buf->vb.sequence = video->sequence++;
+                               buf->vb.field = V4L2_FIELD_NONE;
+                               vb2_buffer_done(&buf->vb.vb2_buf,
+                                               VB2_BUF_STATE_DONE);
+                               list_del(&buf->link);
+                       }
+               }
+               spin_unlock(&video->lock);
+
+               aspeed_video_update(video, VE_SEQ_CTRL,
+                                   VE_SEQ_CTRL_TRIG_CAPTURE |
+                                   VE_SEQ_CTRL_FORCE_IDLE |
+                                   VE_SEQ_CTRL_TRIG_COMP, 0);
+               aspeed_video_update(video, VE_INTERRUPT_CTRL,
+                                   VE_INTERRUPT_COMP_COMPLETE |
+                                   VE_INTERRUPT_CAPTURE_COMPLETE, 0);
+               aspeed_video_write(video, VE_INTERRUPT_STATUS,
+                                  VE_INTERRUPT_COMP_COMPLETE |
+                                  VE_INTERRUPT_CAPTURE_COMPLETE);
+
+               if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
+                       aspeed_video_start_frame(video);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
+{
+       int i;
+       int hsync_counter = 0;
+       int vsync_counter = 0;
+       u32 sts;
+
+       for (i = 0; i < NUM_POLARITY_CHECKS; ++i) {
+               sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
+               if (sts & VE_MODE_DETECT_STATUS_VSYNC)
+                       vsync_counter--;
+               else
+                       vsync_counter++;
+
+               if (sts & VE_MODE_DETECT_STATUS_HSYNC)
+                       hsync_counter--;
+               else
+                       hsync_counter++;
+       }
+
+       if (hsync_counter < 0 || vsync_counter < 0) {
+               u32 ctrl;
+
+               if (hsync_counter < 0) {
+                       ctrl = VE_CTRL_HSYNC_POL;
+                       video->detected_timings.polarities &=
+                               ~V4L2_DV_HSYNC_POS_POL;
+               } else {
+                       video->detected_timings.polarities |=
+                               V4L2_DV_HSYNC_POS_POL;
+               }
+
+               if (vsync_counter < 0) {
+                       ctrl = VE_CTRL_VSYNC_POL;
+                       video->detected_timings.polarities &=
+                               ~V4L2_DV_VSYNC_POS_POL;
+               } else {
+                       video->detected_timings.polarities |=
+                               V4L2_DV_VSYNC_POS_POL;
+               }
+
+               aspeed_video_update(video, VE_CTRL, 0, ctrl);
+       }
+}
+
+static bool aspeed_video_alloc_buf(struct aspeed_video *video,
+                                  struct aspeed_video_addr *addr,
+                                  unsigned int size)
+{
+       addr->virt = dma_alloc_coherent(video->dev, size, &addr->dma,
+                                       GFP_KERNEL);
+       if (!addr->virt)
+               return false;
+
+       addr->size = size;
+       return true;
+}
+
+static void aspeed_video_free_buf(struct aspeed_video *video,
+                                 struct aspeed_video_addr *addr)
+{
+       dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma);
+       addr->size = 0;
+       addr->dma = 0ULL;
+       addr->virt = NULL;
+}
+
+/*
+ * Get the minimum HW-supported compression buffer size for the frame size.
+ * Assume worst-case JPEG compression size is 1/8 raw size. This should be
+ * plenty even for maximum quality; any worse and the engine will simply return
+ * incomplete JPEGs.
+ */
+static void aspeed_video_calc_compressed_size(struct aspeed_video *video,
+                                             unsigned int frame_size)
+{
+       int i, j;
+       u32 compression_buffer_size_reg = 0;
+       unsigned int size;
+       const unsigned int num_compression_packets = 4;
+       const unsigned int compression_packet_size = 1024;
+       const unsigned int max_compressed_size = frame_size / 2; /* 4bpp / 8 */
+
+       video->max_compressed_size = UINT_MAX;
+
+       for (i = 0; i < 6; ++i) {
+               for (j = 0; j < 8; ++j) {
+                       size = (num_compression_packets << i) *
+                               (compression_packet_size << j);
+                       if (size < max_compressed_size)
+                               continue;
+
+                       if (size < video->max_compressed_size) {
+                               compression_buffer_size_reg = (i << 3) | j;
+                               video->max_compressed_size = size;
+                       }
+               }
+       }
+
+       aspeed_video_write(video, VE_STREAM_BUF_SIZE,
+                          compression_buffer_size_reg);
+
+       dev_dbg(video->dev, "Max compressed size: %x\n",
+               video->max_compressed_size);
+}
+
+#define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags)
+
+static void aspeed_video_get_resolution(struct aspeed_video *video)
+{
+       bool invalid_resolution = true;
+       int rc;
+       int tries = 0;
+       u32 mds;
+       u32 src_lr_edge;
+       u32 src_tb_edge;
+       u32 sync;
+       struct v4l2_bt_timings *det = &video->detected_timings;
+
+       det->width = MIN_WIDTH;
+       det->height = MIN_HEIGHT;
+       video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
+
+       /*
+        * Since we need max buffer size for detection, free the second source
+        * buffer first.
+        */
+       if (video->srcs[1].size)
+               aspeed_video_free_buf(video, &video->srcs[1]);
+
+       if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) {
+               if (video->srcs[0].size)
+                       aspeed_video_free_buf(video, &video->srcs[0]);
+
+               if (!aspeed_video_alloc_buf(video, &video->srcs[0],
+                                           VE_MAX_SRC_BUFFER_SIZE)) {
+                       dev_err(video->dev,
+                               "Failed to allocate source buffers\n");
+                       return;
+               }
+       }
+
+       aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
+
+       do {
+               if (tries) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (schedule_timeout(INVALID_RESOLUTION_DELAY))
+                               return;
+               }
+
+               set_bit(VIDEO_RES_DETECT, &video->flags);
+               aspeed_video_enable_mode_detect(video);
+
+               rc = wait_event_interruptible_timeout(video->wait,
+                                                     res_check(video),
+                                                     MODE_DETECT_TIMEOUT);
+               if (!rc) {
+                       dev_err(video->dev, "Timed out; first mode detect\n");
+                       clear_bit(VIDEO_RES_DETECT, &video->flags);
+                       return;
+               }
+
+               /* Disable mode detect in order to re-trigger */
+               aspeed_video_update(video, VE_SEQ_CTRL,
+                                   VE_SEQ_CTRL_TRIG_MODE_DET, 0);
+
+               aspeed_video_check_and_set_polarity(video);
+
+               aspeed_video_enable_mode_detect(video);
+
+               rc = wait_event_interruptible_timeout(video->wait,
+                                                     res_check(video),
+                                                     MODE_DETECT_TIMEOUT);
+               clear_bit(VIDEO_RES_DETECT, &video->flags);
+               if (!rc) {
+                       dev_err(video->dev, "Timed out; second mode detect\n");
+                       return;
+               }
+
+               src_lr_edge = aspeed_video_read(video, VE_SRC_LR_EDGE_DET);
+               src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET);
+               mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
+               sync = aspeed_video_read(video, VE_SYNC_STATUS);
+
+               video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >>
+                       VE_SRC_TB_EDGE_DET_BOT_SHF;
+               video->frame_top = src_tb_edge & VE_SRC_TB_EDGE_DET_TOP;
+               det->vfrontporch = video->frame_top;
+               det->vbackporch = ((mds & VE_MODE_DETECT_V_LINES) >>
+                       VE_MODE_DETECT_V_LINES_SHF) - video->frame_bottom;
+               det->vsync = (sync & VE_SYNC_STATUS_VSYNC) >>
+                       VE_SYNC_STATUS_VSYNC_SHF;
+               if (video->frame_top > video->frame_bottom)
+                       continue;
+
+               video->frame_right = (src_lr_edge & VE_SRC_LR_EDGE_DET_RT) >>
+                       VE_SRC_LR_EDGE_DET_RT_SHF;
+               video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT;
+               det->hfrontporch = video->frame_left;
+               det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) -
+                       video->frame_right;
+               det->hsync = sync & VE_SYNC_STATUS_HSYNC;
+               if (video->frame_left > video->frame_right)
+                       continue;
+
+               invalid_resolution = false;
+       } while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES));
+
+       if (invalid_resolution) {
+               dev_err(video->dev, "Invalid resolution detected\n");
+               return;
+       }
+
+       det->height = (video->frame_bottom - video->frame_top) + 1;
+       det->width = (video->frame_right - video->frame_left) + 1;
+       video->v4l2_input_status = 0;
+
+       /*
+        * Enable mode-detect watchdog, resolution-change watchdog and
+        * automatic compression after frame capture.
+        */
+       aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
+                           VE_INTERRUPT_MODE_DETECT_WD);
+       aspeed_video_update(video, VE_SEQ_CTRL, 0,
+                           VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG);
+
+       dev_dbg(video->dev, "Got resolution: %dx%d\n", det->width,
+               det->height);
+}
+
+static void aspeed_video_set_resolution(struct aspeed_video *video)
+{
+       struct v4l2_bt_timings *act = &video->active_timings;
+       unsigned int size = act->width * act->height;
+
+       aspeed_video_calc_compressed_size(video, size);
+
+       /* Don't use direct mode below 1024 x 768 (irqs don't fire) */
+       if (size < DIRECT_FETCH_THRESHOLD) {
+               aspeed_video_write(video, VE_TGS_0,
+                                  FIELD_PREP(VE_TGS_FIRST,
+                                             video->frame_left - 1) |
+                                  FIELD_PREP(VE_TGS_LAST,
+                                             video->frame_right));
+               aspeed_video_write(video, VE_TGS_1,
+                                  FIELD_PREP(VE_TGS_FIRST, video->frame_top) |
+                                  FIELD_PREP(VE_TGS_LAST,
+                                             video->frame_bottom + 1));
+               aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE);
+       } else {
+               aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
+       }
+
+       /* Set capture/compression frame sizes */
+       aspeed_video_write(video, VE_CAP_WINDOW,
+                          act->width << 16 | act->height);
+       aspeed_video_write(video, VE_COMP_WINDOW,
+                          act->width << 16 | act->height);
+       aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
+
+       size *= 4;
+
+       if (size == video->srcs[0].size / 2) {
+               aspeed_video_write(video, VE_SRC1_ADDR,
+                                  video->srcs[0].dma + size);
+       } else if (size == video->srcs[0].size) {
+               if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
+                       goto err_mem;
+
+               aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
+       } else {
+               aspeed_video_free_buf(video, &video->srcs[0]);
+
+               if (!aspeed_video_alloc_buf(video, &video->srcs[0], size))
+                       goto err_mem;
+
+               if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
+                       goto err_mem;
+
+               aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
+               aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
+       }
+
+       return;
+
+err_mem:
+       dev_err(video->dev, "Failed to allocate source buffers\n");
+
+       if (video->srcs[0].size)
+               aspeed_video_free_buf(video, &video->srcs[0]);
+}
+
+static void aspeed_video_init_regs(struct aspeed_video *video)
+{
+       u32 comp_ctrl = VE_COMP_CTRL_RSVD |
+               FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
+               FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
+       u32 ctrl = VE_CTRL_AUTO_OR_CURSOR;
+       u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE;
+
+       if (video->frame_rate)
+               ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
+
+       if (video->yuv420)
+               seq_ctrl |= VE_SEQ_CTRL_YUV420;
+
+       /* Unlock VE registers */
+       aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK);
+
+       /* Disable interrupts */
+       aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
+       aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
+
+       /* Clear the offset */
+       aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0);
+       aspeed_video_write(video, VE_COMP_OFFSET, 0);
+
+       aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
+
+       /* Set control registers */
+       aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
+       aspeed_video_write(video, VE_CTRL, ctrl);
+       aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl);
+
+       /* Don't downscale */
+       aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000);
+       aspeed_video_write(video, VE_SCALING_FILTER0, 0x00200000);
+       aspeed_video_write(video, VE_SCALING_FILTER1, 0x00200000);
+       aspeed_video_write(video, VE_SCALING_FILTER2, 0x00200000);
+       aspeed_video_write(video, VE_SCALING_FILTER3, 0x00200000);
+
+       /* Set mode detection defaults */
+       aspeed_video_write(video, VE_MODE_DETECT, 0x22666500);
+}
+
+static void aspeed_video_start(struct aspeed_video *video)
+{
+       aspeed_video_on(video);
+
+       aspeed_video_init_regs(video);
+
+       /* Resolution set to 640x480 if no signal found */
+       aspeed_video_get_resolution(video);
+
+       /* Set timings since the device is being opened for the first time */
+       video->active_timings = video->detected_timings;
+       aspeed_video_set_resolution(video);
+
+       video->pix_fmt.width = video->active_timings.width;
+       video->pix_fmt.height = video->active_timings.height;
+       video->pix_fmt.sizeimage = video->max_compressed_size;
+}
+
+static void aspeed_video_stop(struct aspeed_video *video)
+{
+       set_bit(VIDEO_STOPPED, &video->flags);
+       cancel_delayed_work_sync(&video->res_work);
+
+       aspeed_video_off(video);
+
+       if (video->srcs[0].size)
+               aspeed_video_free_buf(video, &video->srcs[0]);
+
+       if (video->srcs[1].size)
+               aspeed_video_free_buf(video, &video->srcs[1]);
+
+       video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
+       video->flags = 0;
+}
+
+static int aspeed_video_querycap(struct file *file, void *fh,
+                                struct v4l2_capability *cap)
+{
+       strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver));
+       strscpy(cap->card, "Aspeed Video Engine", sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                DEVICE_NAME);
+
+       return 0;
+}
+
+static int aspeed_video_enum_format(struct file *file, void *fh,
+                                   struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+
+       f->pixelformat = V4L2_PIX_FMT_JPEG;
+
+       return 0;
+}
+
+static int aspeed_video_get_format(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       f->fmt.pix = video->pix_fmt;
+
+       return 0;
+}
+
+static int aspeed_video_enum_input(struct file *file, void *fh,
+                                  struct v4l2_input *inp)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       if (inp->index)
+               return -EINVAL;
+
+       strscpy(inp->name, "Host VGA capture", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+       inp->status = video->v4l2_input_status;
+
+       return 0;
+}
+
+static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int aspeed_video_get_parm(struct file *file, void *fh,
+                                struct v4l2_streamparm *a)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       a->parm.capture.readbuffers = 3;
+       a->parm.capture.timeperframe.numerator = 1;
+       if (!video->frame_rate)
+               a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE;
+       else
+               a->parm.capture.timeperframe.denominator = video->frame_rate;
+
+       return 0;
+}
+
+static int aspeed_video_set_parm(struct file *file, void *fh,
+                                struct v4l2_streamparm *a)
+{
+       unsigned int frame_rate = 0;
+       struct aspeed_video *video = video_drvdata(file);
+
+       a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       a->parm.capture.readbuffers = 3;
+
+       if (a->parm.capture.timeperframe.numerator)
+               frame_rate = a->parm.capture.timeperframe.denominator /
+                       a->parm.capture.timeperframe.numerator;
+
+       if (!frame_rate || frame_rate > MAX_FRAME_RATE) {
+               frame_rate = 0;
+               a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE;
+               a->parm.capture.timeperframe.numerator = 1;
+       }
+
+       if (video->frame_rate != frame_rate) {
+               video->frame_rate = frame_rate;
+               aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC,
+                                   FIELD_PREP(VE_CTRL_FRC, frame_rate));
+       }
+
+       return 0;
+}
+
+static int aspeed_video_enum_framesizes(struct file *file, void *fh,
+                                       struct v4l2_frmsizeenum *fsize)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       if (fsize->index)
+               return -EINVAL;
+
+       if (fsize->pixel_format != V4L2_PIX_FMT_JPEG)
+               return -EINVAL;
+
+       fsize->discrete.width = video->pix_fmt.width;
+       fsize->discrete.height = video->pix_fmt.height;
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+       return 0;
+}
+
+static int aspeed_video_enum_frameintervals(struct file *file, void *fh,
+                                           struct v4l2_frmivalenum *fival)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       if (fival->index)
+               return -EINVAL;
+
+       if (fival->width != video->detected_timings.width ||
+           fival->height != video->detected_timings.height)
+               return -EINVAL;
+
+       if (fival->pixel_format != V4L2_PIX_FMT_JPEG)
+               return -EINVAL;
+
+       fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+
+       fival->stepwise.min.denominator = MAX_FRAME_RATE;
+       fival->stepwise.min.numerator = 1;
+       fival->stepwise.max.denominator = 1;
+       fival->stepwise.max.numerator = 1;
+       fival->stepwise.step = fival->stepwise.max;
+
+       return 0;
+}
+
+static int aspeed_video_set_dv_timings(struct file *file, void *fh,
+                                      struct v4l2_dv_timings *timings)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       if (timings->bt.width == video->active_timings.width &&
+           timings->bt.height == video->active_timings.height)
+               return 0;
+
+       if (vb2_is_busy(&video->queue))
+               return -EBUSY;
+
+       video->active_timings = timings->bt;
+
+       aspeed_video_set_resolution(video);
+
+       video->pix_fmt.width = timings->bt.width;
+       video->pix_fmt.height = timings->bt.height;
+       video->pix_fmt.sizeimage = video->max_compressed_size;
+
+       timings->type = V4L2_DV_BT_656_1120;
+
+       return 0;
+}
+
+static int aspeed_video_get_dv_timings(struct file *file, void *fh,
+                                      struct v4l2_dv_timings *timings)
+{
+       struct aspeed_video *video = video_drvdata(file);
+
+       timings->type = V4L2_DV_BT_656_1120;
+       timings->bt = video->active_timings;
+
+       return 0;
+}
+
+static int aspeed_video_query_dv_timings(struct file *file, void *fh,
+                                        struct v4l2_dv_timings *timings)
+{
+       int rc;
+       struct aspeed_video *video = video_drvdata(file);
+
+       /*
+        * This blocks only if the driver is currently in the process of
+        * detecting a new resolution; in the event of no signal or timeout
+        * this function is woken up.
+        */
+       if (file->f_flags & O_NONBLOCK) {
+               if (test_bit(VIDEO_RES_CHANGE, &video->flags))
+                       return -EAGAIN;
+       } else {
+               rc = wait_event_interruptible(video->wait,
+                                             !test_bit(VIDEO_RES_CHANGE,
+                                                       &video->flags));
+               if (rc)
+                       return -EINTR;
+       }
+
+       timings->type = V4L2_DV_BT_656_1120;
+       timings->bt = video->detected_timings;
+
+       return video->v4l2_input_status ? -ENOLINK : 0;
+}
+
+static int aspeed_video_enum_dv_timings(struct file *file, void *fh,
+                                       struct v4l2_enum_dv_timings *timings)
+{
+       return v4l2_enum_dv_timings_cap(timings, &aspeed_video_timings_cap,
+                                       NULL, NULL);
+}
+
+static int aspeed_video_dv_timings_cap(struct file *file, void *fh,
+                                      struct v4l2_dv_timings_cap *cap)
+{
+       *cap = aspeed_video_timings_cap;
+
+       return 0;
+}
+
+static int aspeed_video_sub_event(struct v4l2_fh *fh,
+                                 const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subscribe(fh, sub);
+       }
+
+       return v4l2_ctrl_subscribe_event(fh, sub);
+}
+
+static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
+       .vidioc_querycap = aspeed_video_querycap,
+
+       .vidioc_enum_fmt_vid_cap = aspeed_video_enum_format,
+       .vidioc_g_fmt_vid_cap = aspeed_video_get_format,
+       .vidioc_s_fmt_vid_cap = aspeed_video_get_format,
+       .vidioc_try_fmt_vid_cap = aspeed_video_get_format,
+
+       .vidioc_reqbufs = vb2_ioctl_reqbufs,
+       .vidioc_querybuf = vb2_ioctl_querybuf,
+       .vidioc_qbuf = vb2_ioctl_qbuf,
+       .vidioc_expbuf = vb2_ioctl_expbuf,
+       .vidioc_dqbuf = vb2_ioctl_dqbuf,
+       .vidioc_create_bufs = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+       .vidioc_streamon = vb2_ioctl_streamon,
+       .vidioc_streamoff = vb2_ioctl_streamoff,
+
+       .vidioc_enum_input = aspeed_video_enum_input,
+       .vidioc_g_input = aspeed_video_get_input,
+       .vidioc_s_input = aspeed_video_set_input,
+
+       .vidioc_g_parm = aspeed_video_get_parm,
+       .vidioc_s_parm = aspeed_video_set_parm,
+       .vidioc_enum_framesizes = aspeed_video_enum_framesizes,
+       .vidioc_enum_frameintervals = aspeed_video_enum_frameintervals,
+
+       .vidioc_s_dv_timings = aspeed_video_set_dv_timings,
+       .vidioc_g_dv_timings = aspeed_video_get_dv_timings,
+       .vidioc_query_dv_timings = aspeed_video_query_dv_timings,
+       .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings,
+       .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap,
+
+       .vidioc_subscribe_event = aspeed_video_sub_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void aspeed_video_update_jpeg_quality(struct aspeed_video *video)
+{
+       u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
+               FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
+
+       aspeed_video_update(video, VE_COMP_CTRL,
+                           VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR,
+                           comp_ctrl);
+}
+
+static void aspeed_video_update_subsampling(struct aspeed_video *video)
+{
+       if (video->jpeg.virt)
+               aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420);
+
+       if (video->yuv420)
+               aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420);
+       else
+               aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0);
+}
+
+static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct aspeed_video *video = container_of(ctrl->handler,
+                                                 struct aspeed_video,
+                                                 ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+               video->jpeg_quality = ctrl->val;
+               aspeed_video_update_jpeg_quality(video);
+               break;
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+               if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
+                       video->yuv420 = true;
+                       aspeed_video_update_subsampling(video);
+               } else {
+                       video->yuv420 = false;
+                       aspeed_video_update_subsampling(video);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
+       .s_ctrl = aspeed_video_set_ctrl,
+};
+
+static void aspeed_video_resolution_work(struct work_struct *work)
+{
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct aspeed_video *video = container_of(dwork, struct aspeed_video,
+                                                 res_work);
+       u32 input_status = video->v4l2_input_status;
+
+       aspeed_video_on(video);
+
+       /* Exit early in case no clients remain */
+       if (test_bit(VIDEO_STOPPED, &video->flags))
+               goto done;
+
+       aspeed_video_init_regs(video);
+
+       aspeed_video_get_resolution(video);
+
+       if (video->detected_timings.width != video->active_timings.width ||
+           video->detected_timings.height != video->active_timings.height ||
+           input_status != video->v4l2_input_status) {
+               static const struct v4l2_event ev = {
+                       .type = V4L2_EVENT_SOURCE_CHANGE,
+                       .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+               };
+
+               v4l2_event_queue(&video->vdev, &ev);
+       } else if (test_bit(VIDEO_STREAMING, &video->flags)) {
+               /* No resolution change so just restart streaming */
+               aspeed_video_start_frame(video);
+       }
+
+done:
+       clear_bit(VIDEO_RES_CHANGE, &video->flags);
+       wake_up_interruptible_all(&video->wait);
+}
+
+static int aspeed_video_open(struct file *file)
+{
+       int rc;
+       struct aspeed_video *video = video_drvdata(file);
+
+       mutex_lock(&video->video_lock);
+
+       rc = v4l2_fh_open(file);
+       if (rc) {
+               mutex_unlock(&video->video_lock);
+               return rc;
+       }
+
+       if (v4l2_fh_is_singular_file(file))
+               aspeed_video_start(video);
+
+       mutex_unlock(&video->video_lock);
+
+       return 0;
+}
+
+static int aspeed_video_release(struct file *file)
+{
+       int rc;
+       struct aspeed_video *video = video_drvdata(file);
+
+       mutex_lock(&video->video_lock);
+
+       if (v4l2_fh_is_singular_file(file))
+               aspeed_video_stop(video);
+
+       rc = _vb2_fop_release(file, NULL);
+
+       mutex_unlock(&video->video_lock);
+
+       return rc;
+}
+
+static const struct v4l2_file_operations aspeed_video_v4l2_fops = {
+       .owner = THIS_MODULE,
+       .read = vb2_fop_read,
+       .poll = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = vb2_fop_mmap,
+       .open = aspeed_video_open,
+       .release = aspeed_video_release,
+};
+
+static int aspeed_video_queue_setup(struct vb2_queue *q,
+                                   unsigned int *num_buffers,
+                                   unsigned int *num_planes,
+                                   unsigned int sizes[],
+                                   struct device *alloc_devs[])
+{
+       struct aspeed_video *video = vb2_get_drv_priv(q);
+
+       if (*num_planes) {
+               if (sizes[0] < video->max_compressed_size)
+                       return -EINVAL;
+
+               return 0;
+       }
+
+       *num_planes = 1;
+       sizes[0] = video->max_compressed_size;
+
+       return 0;
+}
+
+static int aspeed_video_buf_prepare(struct vb2_buffer *vb)
+{
+       struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue);
+
+       if (vb2_plane_size(vb, 0) < video->max_compressed_size)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int aspeed_video_start_streaming(struct vb2_queue *q,
+                                       unsigned int count)
+{
+       int rc;
+       struct aspeed_video *video = vb2_get_drv_priv(q);
+
+       video->sequence = 0;
+
+       rc = aspeed_video_start_frame(video);
+       if (rc) {
+               aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED);
+               return rc;
+       }
+
+       set_bit(VIDEO_STREAMING, &video->flags);
+       return 0;
+}
+
+static void aspeed_video_stop_streaming(struct vb2_queue *q)
+{
+       int rc;
+       struct aspeed_video *video = vb2_get_drv_priv(q);
+
+       clear_bit(VIDEO_STREAMING, &video->flags);
+
+       rc = wait_event_timeout(video->wait,
+                               !test_bit(VIDEO_FRAME_INPRG, &video->flags),
+                               STOP_TIMEOUT);
+       if (!rc) {
+               dev_err(video->dev, "Timed out when stopping streaming\n");
+
+               /*
+                * Need to force stop any DMA and try and get HW into a good
+                * state for future calls to start streaming again.
+                */
+               aspeed_video_reset(video);
+               aspeed_video_init_regs(video);
+
+               aspeed_video_get_resolution(video);
+       }
+
+       aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
+}
+
+static void aspeed_video_buf_queue(struct vb2_buffer *vb)
+{
+       bool empty;
+       struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct aspeed_video_buffer *avb = to_aspeed_video_buffer(vbuf);
+       unsigned long flags;
+
+       spin_lock_irqsave(&video->lock, flags);
+       empty = list_empty(&video->buffers);
+       list_add_tail(&avb->link, &video->buffers);
+       spin_unlock_irqrestore(&video->lock, flags);
+
+       if (test_bit(VIDEO_STREAMING, &video->flags) &&
+           !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty)
+               aspeed_video_start_frame(video);
+}
+
+static const struct vb2_ops aspeed_video_vb2_ops = {
+       .queue_setup = aspeed_video_queue_setup,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .buf_prepare = aspeed_video_buf_prepare,
+       .start_streaming = aspeed_video_start_streaming,
+       .stop_streaming = aspeed_video_stop_streaming,
+       .buf_queue =  aspeed_video_buf_queue,
+};
+
+static int aspeed_video_setup_video(struct aspeed_video *video)
+{
+       const u64 mask = ~(BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_444) |
+                          BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_420));
+       struct v4l2_device *v4l2_dev = &video->v4l2_dev;
+       struct vb2_queue *vbq = &video->queue;
+       struct video_device *vdev = &video->vdev;
+       int rc;
+
+       video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
+       video->pix_fmt.field = V4L2_FIELD_NONE;
+       video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       video->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+       video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
+
+       rc = v4l2_device_register(video->dev, v4l2_dev);
+       if (rc) {
+               dev_err(video->dev, "Failed to register v4l2 device\n");
+               return rc;
+       }
+
+       v4l2_ctrl_handler_init(&video->ctrl_handler, 2);
+       v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+                         V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
+                         ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0);
+       v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops,
+                              V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+                              V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
+                              V4L2_JPEG_CHROMA_SUBSAMPLING_444);
+
+       if (video->ctrl_handler.error) {
+               v4l2_ctrl_handler_free(&video->ctrl_handler);
+               v4l2_device_unregister(v4l2_dev);
+
+               dev_err(video->dev, "Failed to init controls: %d\n",
+                       video->ctrl_handler.error);
+               return rc;
+       }
+
+       v4l2_dev->ctrl_handler = &video->ctrl_handler;
+
+       vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
+       vbq->dev = v4l2_dev->dev;
+       vbq->lock = &video->video_lock;
+       vbq->ops = &aspeed_video_vb2_ops;
+       vbq->mem_ops = &vb2_dma_contig_memops;
+       vbq->drv_priv = video;
+       vbq->buf_struct_size = sizeof(struct aspeed_video_buffer);
+       vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       vbq->min_buffers_needed = 3;
+
+       rc = vb2_queue_init(vbq);
+       if (rc) {
+               v4l2_ctrl_handler_free(&video->ctrl_handler);
+               v4l2_device_unregister(v4l2_dev);
+
+               dev_err(video->dev, "Failed to init vb2 queue\n");
+               return rc;
+       }
+
+       vdev->queue = vbq;
+       vdev->fops = &aspeed_video_v4l2_fops;
+       vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+       vdev->v4l2_dev = v4l2_dev;
+       strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name));
+       vdev->vfl_type = VFL_TYPE_GRABBER;
+       vdev->vfl_dir = VFL_DIR_RX;
+       vdev->release = video_device_release_empty;
+       vdev->ioctl_ops = &aspeed_video_ioctl_ops;
+       vdev->lock = &video->video_lock;
+
+       video_set_drvdata(vdev, video);
+       rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0);
+       if (rc) {
+               vb2_queue_release(vbq);
+               v4l2_ctrl_handler_free(&video->ctrl_handler);
+               v4l2_device_unregister(v4l2_dev);
+
+               dev_err(video->dev, "Failed to register video device\n");
+               return rc;
+       }
+
+       return 0;
+}
+
+static int aspeed_video_init(struct aspeed_video *video)
+{
+       int irq;
+       int rc;
+       struct device *dev = video->dev;
+
+       irq = irq_of_parse_and_map(dev->of_node, 0);
+       if (!irq) {
+               dev_err(dev, "Unable to find IRQ\n");
+               return -ENODEV;
+       }
+
+       rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED,
+                             DEVICE_NAME, video);
+       if (rc < 0) {
+               dev_err(dev, "Unable to request IRQ %d\n", irq);
+               return rc;
+       }
+
+       video->eclk = devm_clk_get(dev, "eclk");
+       if (IS_ERR(video->eclk)) {
+               dev_err(dev, "Unable to get ECLK\n");
+               return PTR_ERR(video->eclk);
+       }
+
+       video->vclk = devm_clk_get(dev, "vclk");
+       if (IS_ERR(video->vclk)) {
+               dev_err(dev, "Unable to get VCLK\n");
+               return PTR_ERR(video->vclk);
+       }
+
+       video->rst = devm_reset_control_get_exclusive(dev, NULL);
+       if (IS_ERR(video->rst)) {
+               dev_err(dev, "Unable to get VE reset\n");
+               return PTR_ERR(video->rst);
+       }
+
+       rc = of_reserved_mem_device_init(dev);
+       if (rc) {
+               dev_err(dev, "Unable to reserve memory\n");
+               return rc;
+       }
+
+       rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       if (rc) {
+               dev_err(dev, "Failed to set DMA mask\n");
+               of_reserved_mem_device_release(dev);
+               return rc;
+       }
+
+       if (!aspeed_video_alloc_buf(video, &video->jpeg,
+                                   VE_JPEG_HEADER_SIZE)) {
+               dev_err(dev, "Failed to allocate DMA for JPEG header\n");
+               of_reserved_mem_device_release(dev);
+               return rc;
+       }
+
+       aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420);
+
+       return 0;
+}
+
+static int aspeed_video_probe(struct platform_device *pdev)
+{
+       int rc;
+       struct resource *res;
+       struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL);
+
+       if (!video)
+               return -ENOMEM;
+
+       video->frame_rate = 30;
+       video->dev = &pdev->dev;
+       mutex_init(&video->video_lock);
+       init_waitqueue_head(&video->wait);
+       INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work);
+       INIT_LIST_HEAD(&video->buffers);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       video->base = devm_ioremap_resource(video->dev, res);
+
+       if (IS_ERR(video->base))
+               return PTR_ERR(video->base);
+
+       rc = aspeed_video_init(video);
+       if (rc)
+               return rc;
+
+       rc = aspeed_video_setup_video(video);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int aspeed_video_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+       struct aspeed_video *video = to_aspeed_video(v4l2_dev);
+
+       video_unregister_device(&video->vdev);
+
+       vb2_queue_release(&video->queue);
+
+       v4l2_ctrl_handler_free(&video->ctrl_handler);
+
+       v4l2_device_unregister(v4l2_dev);
+
+       dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt,
+                         video->jpeg.dma);
+
+       of_reserved_mem_device_release(dev);
+
+       return 0;
+}
+
+static const struct of_device_id aspeed_video_of_match[] = {
+       { .compatible = "aspeed,ast2400-video-engine" },
+       { .compatible = "aspeed,ast2500-video-engine" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
+
+static struct platform_driver aspeed_video_driver = {
+       .driver = {
+               .name = DEVICE_NAME,
+               .of_match_table = aspeed_video_of_match,
+       },
+       .probe = aspeed_video_probe,
+       .remove = aspeed_video_remove,
+};
+
+module_platform_driver(aspeed_video_driver);
+
+MODULE_DESCRIPTION("ASPEED Video Engine Driver");
+MODULE_AUTHOR("Eddie James");
+MODULE_LICENSE("GPL v2");
index d26c2d85a009463a708208a342b9d86e4e50edfc..8e0194993a52e826d82f325b22adc99a2f3313cb 100644 (file)
@@ -253,7 +253,6 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
 {
        struct vb2_v4l2_buffer *src_buf;
        struct coda_buffer_meta *meta;
-       unsigned long flags;
        u32 start;
 
        if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
@@ -269,6 +268,23 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
                    ctx->num_metas > 1)
                        break;
 
+               if (ctx->num_internal_frames &&
+                   ctx->num_metas >= ctx->num_internal_frames) {
+                       meta = list_first_entry(&ctx->buffer_meta_list,
+                                               struct coda_buffer_meta, list);
+
+                       /*
+                        * If we managed to fill in at least a full reorder
+                        * window of buffers (num_internal_frames is a
+                        * conservative estimate for this) and the bitstream
+                        * prefetcher has at least 2 256 bytes periods beyond
+                        * the first buffer to fetch, we can safely stop queuing
+                        * in order to limit the decoder drain latency.
+                        */
+                       if (coda_bitstream_can_fetch_past(ctx, meta->end))
+                               break;
+               }
+
                src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 
                /* Drop frames that do not start/end with a SOI/EOI markers */
@@ -299,8 +315,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
                }
 
                /* Buffer start position */
-               start = ctx->bitstream_fifo.kfifo.in &
-                       ctx->bitstream_fifo.kfifo.mask;
+               start = ctx->bitstream_fifo.kfifo.in;
 
                if (coda_bitstream_try_queue(ctx, src_buf)) {
                        /*
@@ -315,15 +330,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
                                meta->timecode = src_buf->timecode;
                                meta->timestamp = src_buf->vb2_buf.timestamp;
                                meta->start = start;
-                               meta->end = ctx->bitstream_fifo.kfifo.in &
-                                           ctx->bitstream_fifo.kfifo.mask;
-                               spin_lock_irqsave(&ctx->buffer_meta_lock,
-                                                 flags);
+                               meta->end = ctx->bitstream_fifo.kfifo.in;
+                               spin_lock(&ctx->buffer_meta_lock);
                                list_add_tail(&meta->list,
                                              &ctx->buffer_meta_list);
                                ctx->num_metas++;
-                               spin_unlock_irqrestore(&ctx->buffer_meta_lock,
-                                                      flags);
+                               spin_unlock(&ctx->buffer_meta_lock);
 
                                trace_coda_bit_queue(ctx, src_buf, meta);
                        }
@@ -713,8 +725,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
 
 out:
        if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "IRAM smaller than needed\n");
+               coda_dbg(1, ctx, "IRAM smaller than needed\n");
 
        if (dev->devtype->product == CODA_HX4 ||
            dev->devtype->product == CODA_7541) {
@@ -991,16 +1002,15 @@ static int coda_start_encoding(struct coda_ctx *ctx)
                else
                        coda_write(dev, CODA_STD_H264,
                                   CODA_CMD_ENC_SEQ_COD_STD);
-               if (ctx->params.h264_deblk_enabled) {
-                       value = ((ctx->params.h264_deblk_alpha &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
-                               ((ctx->params.h264_deblk_beta &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
-               } else {
-                       value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
-               }
+               value = ((ctx->params.h264_disable_deblocking_filter_idc &
+                         CODA_264PARAM_DISABLEDEBLK_MASK) <<
+                        CODA_264PARAM_DISABLEDEBLK_OFFSET) |
+                       ((ctx->params.h264_slice_alpha_c0_offset_div2 &
+                         CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
+                        CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
+                       ((ctx->params.h264_slice_beta_offset_div2 &
+                         CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
+                        CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
                coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
                break;
        case V4L2_PIX_FMT_JPEG:
@@ -1201,6 +1211,12 @@ static int coda_start_encoding(struct coda_ctx *ctx)
                goto out;
        }
 
+       coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n",
+                q_data_src->rect.width, q_data_src->rect.height,
+                (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc,
+                ctx->params.framerate & 0xffff,
+                (ctx->params.framerate >> 16) + 1);
+
        /* Save stream headers */
        buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
        switch (dst_fourcc) {
@@ -1462,8 +1478,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
                vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr);
        }
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
-                wr_ptr - start_ptr);
+       coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr);
 
        coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
        coda_read(dev, CODA_RET_ENC_PIC_FLAG);
@@ -1492,11 +1507,9 @@ static void coda_finish_encode(struct coda_ctx *ctx)
        if (ctx->gopcounter < 0)
                ctx->gopcounter = ctx->params.gop_size - 1;
 
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-               "job finished: encoding frame (%d) (%s)\n",
-               dst_buf->sequence,
-               (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ?
-               "KEYFRAME" : "PFRAME");
+       coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n",
+                (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P',
+                dst_buf->sequence);
 }
 
 static void coda_seq_end_work(struct work_struct *work)
@@ -1510,9 +1523,7 @@ static void coda_seq_end_work(struct work_struct *work)
        if (ctx->initialized == 0)
                goto out;
 
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx,
-                __func__);
+       coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__);
        if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
                v4l2_err(&dev->v4l2_dev,
                         "CODA_COMMAND_SEQ_END failed\n");
@@ -1655,8 +1666,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
        u32 val;
        int ret;
 
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "Video Data Order Adapter: %s\n",
+       coda_dbg(1, ctx, "Video Data Order Adapter: %s\n",
                 ctx->use_vdoa ? "Enabled" : "Disabled");
 
        /* Start decoding */
@@ -1736,7 +1746,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
 
        if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
                v4l2_err(&dev->v4l2_dev,
-                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
+                       "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n",
                        coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
                return -EAGAIN;
        }
@@ -1760,8 +1770,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
        width = round_up(width, 16);
        height = round_up(height, 16);
 
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
-                __func__, ctx->idx, width, height);
+       coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height);
 
        ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
        /*
@@ -1879,7 +1888,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
        struct coda_dev *dev = ctx->dev;
        struct coda_q_data *q_data_dst;
        struct coda_buffer_meta *meta;
-       unsigned long flags;
        u32 rot_mode = 0;
        u32 reg_addr, reg_stride;
 
@@ -1893,8 +1901,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
 
        if (coda_get_bitstream_payload(ctx) < 512 &&
            (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "bitstream payload: %d, skipping\n",
+               coda_dbg(1, ctx, "bitstream payload: %d, skipping\n",
                         coda_get_bitstream_payload(ctx));
                v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
                return -EAGAIN;
@@ -1973,15 +1980,14 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
                coda_write(dev, ctx->iram_info.axi_sram_use,
                                CODA7_REG_BIT_AXI_SRAM_USE);
 
-       spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
+       spin_lock(&ctx->buffer_meta_lock);
        meta = list_first_entry_or_null(&ctx->buffer_meta_list,
                                        struct coda_buffer_meta, list);
 
        if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
 
                /* If this is the last buffer in the bitstream, add padding */
-               if (meta->end == (ctx->bitstream_fifo.kfifo.in &
-                                 ctx->bitstream_fifo.kfifo.mask)) {
+               if (meta->end == ctx->bitstream_fifo.kfifo.in) {
                        static unsigned char buf[512];
                        unsigned int pad;
 
@@ -1993,7 +1999,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
                        kfifo_in(&ctx->bitstream_fifo, buf, pad);
                }
        }
-       spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
+       spin_unlock(&ctx->buffer_meta_lock);
 
        coda_kfifo_sync_to_device_full(ctx);
 
@@ -2015,7 +2021,6 @@ static void coda_finish_decode(struct coda_ctx *ctx)
        struct vb2_v4l2_buffer *dst_buf;
        struct coda_buffer_meta *meta;
        unsigned long payload;
-       unsigned long flags;
        int width, height;
        int decoded_idx;
        int display_idx;
@@ -2100,8 +2105,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
                if (val == 0) {
                        /* not enough bitstream data */
-                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                                "prescan failed: %d\n", val);
+                       coda_dbg(1, ctx, "prescan failed: %d\n", val);
                        ctx->hold = true;
                        return;
                }
@@ -2147,13 +2151,13 @@ static void coda_finish_decode(struct coda_ctx *ctx)
        } else {
                val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
                val -= ctx->sequence_offset;
-               spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
+               spin_lock(&ctx->buffer_meta_lock);
                if (!list_empty(&ctx->buffer_meta_list)) {
                        meta = list_first_entry(&ctx->buffer_meta_list,
                                              struct coda_buffer_meta, list);
                        list_del(&meta->list);
                        ctx->num_metas--;
-                       spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
+                       spin_unlock(&ctx->buffer_meta_lock);
                        /*
                         * Clamp counters to 16 bits for comparison, as the HW
                         * counter rolls over at this point for h.264. This
@@ -2170,7 +2174,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                        ctx->frame_metas[decoded_idx] = *meta;
                        kfree(meta);
                } else {
-                       spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
+                       spin_unlock(&ctx->buffer_meta_lock);
                        v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
                        memset(&ctx->frame_metas[decoded_idx], 0,
                               sizeof(struct coda_buffer_meta));
@@ -2243,18 +2247,28 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                else
                        coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
 
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: decoding frame (%d) (%s)\n",
-                       dst_buf->sequence,
-                       (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ?
-                       "KEYFRAME" : "PFRAME");
+               coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n",
+                        (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
+                        ((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'),
+                        dst_buf->sequence, ctx->qsequence);
        } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: no frame decoded\n");
+               coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n",
+                        ctx->osequence, ctx->qsequence);
        }
 
        /* The rotator will copy the current display frame next time */
        ctx->display_idx = display_idx;
+
+       /*
+        * The current decode run might have brought the bitstream fill level
+        * below the size where we can start the next decode run. As userspace
+        * might have filled the output queue completely and might thus be
+        * blocked, we can't rely on the next qbuf to trigger the bitstream
+        * refill. Check if we have data to refill the bitstream now.
+        */
+       mutex_lock(&ctx->bitstream_mutex);
+       coda_fill_bitstream(ctx, NULL);
+       mutex_unlock(&ctx->bitstream_mutex);
 }
 
 static void coda_decode_timeout(struct coda_ctx *ctx)
@@ -2308,13 +2322,11 @@ irqreturn_t coda_irq_handler(int irq, void *data)
        trace_coda_bit_done(ctx);
 
        if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "task has been aborted\n");
+               coda_dbg(1, ctx, "task has been aborted\n");
        }
 
        if (coda_isbusy(ctx->dev)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "coda is still busy!!!!\n");
+               coda_dbg(1, ctx, "coda is still busy!!!!\n");
                return IRQ_NONE;
        }
 
index 2848ea5f464d97b746f64a2a43da6651a0e8dea0..7518f01c48f762ad2d9b4f7cbadd3c2ac4b11cbd 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/firmware.h>
 #include <linux/gcd.h>
 #include <linux/genalloc.h>
+#include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -50,8 +51,8 @@
 
 #define CODA_ISRAM_SIZE        (2048 * 2)
 
-#define MIN_W 176
-#define MIN_H 144
+#define MIN_W 48
+#define MIN_H 16
 
 #define S_ALIGN                1 /* multiple of 2 */
 #define W_ALIGN                1 /* multiple of 2 */
@@ -703,7 +704,8 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
                return -EINVAL;
 
        if (vb2_is_busy(vq)) {
-               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n",
+                        __func__, v4l2_type_names[f->type], vq->num_buffers);
                return -EBUSY;
        }
 
@@ -749,11 +751,10 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
        else
                ctx->use_vdoa = false;
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-               "Setting format for type %d, wxh: %dx%d, fmt: %4.4s %c\n",
-               f->type, q_data->width, q_data->height,
-               (char *)&q_data->fourcc,
-               (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T');
+       coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n",
+                v4l2_type_names[f->type], q_data->width, q_data->height,
+                (char *)&q_data->fourcc,
+                (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T');
 
        return 0;
 }
@@ -938,32 +939,42 @@ static int coda_s_selection(struct file *file, void *fh,
        struct coda_ctx *ctx = fh_to_ctx(fh);
        struct coda_q_data *q_data;
 
-       if (ctx->inst_type == CODA_INST_ENCODER &&
-           s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-           s->target == V4L2_SEL_TGT_CROP) {
-               q_data = get_q_data(ctx, s->type);
-               if (!q_data)
-                       return -EINVAL;
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (ctx->inst_type == CODA_INST_ENCODER &&
+                   s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+                       q_data = get_q_data(ctx, s->type);
+                       if (!q_data)
+                               return -EINVAL;
 
-               s->r.left = 0;
-               s->r.top = 0;
-               s->r.width = clamp(s->r.width, 2U, q_data->width);
-               s->r.height = clamp(s->r.height, 2U, q_data->height);
+                       s->r.left = 0;
+                       s->r.top = 0;
+                       s->r.width = clamp(s->r.width, 2U, q_data->width);
+                       s->r.height = clamp(s->r.height, 2U, q_data->height);
+
+                       if (s->flags & V4L2_SEL_FLAG_LE) {
+                               s->r.width = round_up(s->r.width, 2);
+                               s->r.height = round_up(s->r.height, 2);
+                       } else {
+                               s->r.width = round_down(s->r.width, 2);
+                               s->r.height = round_down(s->r.height, 2);
+                       }
 
-               if (s->flags & V4L2_SEL_FLAG_LE) {
-                       s->r.width = round_up(s->r.width, 2);
-                       s->r.height = round_up(s->r.height, 2);
-               } else {
-                       s->r.width = round_down(s->r.width, 2);
-                       s->r.height = round_down(s->r.height, 2);
-               }
+                       q_data->rect = s->r;
 
-               q_data->rect = s->r;
+                       coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n",
+                                s->r.width, s->r.height);
 
-               return 0;
+                       return 0;
+               }
+               /* else fall through */
+       case V4L2_SEL_TGT_NATIVE_SIZE:
+       case V4L2_SEL_TGT_COMPOSE:
+               return coda_g_selection(file, fh, s);
+       default:
+               /* v4l2-compliance expects this to fail for read-only targets */
+               return -EINVAL;
        }
-
-       return coda_g_selection(file, fh, s);
 }
 
 static int coda_try_encoder_cmd(struct file *file, void *fh,
@@ -1044,6 +1055,38 @@ static int coda_decoder_cmd(struct file *file, void *fh,
        return 0;
 }
 
+static int coda_enum_frameintervals(struct file *file, void *fh,
+                                   struct v4l2_frmivalenum *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       int i;
+
+       if (f->index)
+               return -EINVAL;
+
+       /* Disallow YUYV if the vdoa is not available */
+       if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV)
+               return -EINVAL;
+
+       for (i = 0; i < CODA_MAX_FORMATS; i++) {
+               if (f->pixel_format == ctx->cvd->src_formats[i] ||
+                   f->pixel_format == ctx->cvd->dst_formats[i])
+                       break;
+       }
+       if (i == CODA_MAX_FORMATS)
+               return -EINVAL;
+
+       f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+       f->stepwise.min.numerator = 1;
+       f->stepwise.min.denominator = 65535;
+       f->stepwise.max.numerator = 65536;
+       f->stepwise.max.denominator = 1;
+       f->stepwise.step.numerator = 1;
+       f->stepwise.step.denominator = 1;
+
+       return 0;
+}
+
 static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
 {
        struct coda_ctx *ctx = fh_to_ctx(fh);
@@ -1080,10 +1123,10 @@ static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe)
                return;
        }
 
-       /* Upper bound is 65536/1, map everything above to infinity */
+       /* Upper bound is 65536/1 */
        if (s.denominator == 0 || s.numerator / s.denominator > 65536) {
-               timeperframe->numerator = 1;
-               timeperframe->denominator = 0;
+               timeperframe->numerator = 65536;
+               timeperframe->denominator = 1;
                return;
        }
 
@@ -1135,6 +1178,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
        if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
 
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
        tpf = &a->parm.output.timeperframe;
        coda_approximate_timeperframe(tpf);
        ctx->params.framerate = coda_timeperframe_to_frate(tpf);
@@ -1189,6 +1233,8 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
        .vidioc_g_parm          = coda_g_parm,
        .vidioc_s_parm          = coda_s_parm,
 
+       .vidioc_enum_frameintervals = coda_enum_frameintervals,
+
        .vidioc_subscribe_event = coda_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
@@ -1257,14 +1303,12 @@ static int coda_job_ready(void *m2m_priv)
         * the compressed frame can be in the bitstream.
         */
        if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video buffers.\n");
+               coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n");
                return 0;
        }
 
        if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video capture buffers.\n");
+               coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n");
                return 0;
        }
 
@@ -1272,49 +1316,48 @@ static int coda_job_ready(void *m2m_priv)
                bool stream_end = ctx->bit_stream_param &
                                  CODA_BIT_STREAM_END_FLAG;
                int num_metas = ctx->num_metas;
+               struct coda_buffer_meta *meta;
                unsigned int count;
 
                count = hweight32(ctx->frm_dis_flg);
                if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) {
-                       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                                "%d: not ready: all internal buffers in use: %d/%d (0x%x)",
-                                ctx->idx, count, ctx->num_internal_frames,
+                       coda_dbg(1, ctx,
+                                "not ready: all internal buffers in use: %d/%d (0x%x)",
+                                count, ctx->num_internal_frames,
                                 ctx->frm_dis_flg);
                        return 0;
                }
 
                if (ctx->hold && !src_bufs) {
-                       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                                "%d: not ready: on hold for more buffers.\n",
-                                ctx->idx);
+                       coda_dbg(1, ctx,
+                                "not ready: on hold for more buffers.\n");
                        return 0;
                }
 
                if (!stream_end && (num_metas + src_bufs) < 2) {
-                       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                                "%d: not ready: need 2 buffers available (%d, %d)\n",
-                                ctx->idx, num_metas, src_bufs);
+                       coda_dbg(1, ctx,
+                                "not ready: need 2 buffers available (queue:%d + bitstream:%d)\n",
+                                num_metas, src_bufs);
                        return 0;
                }
 
-
-               if (!src_bufs && !stream_end &&
-                   (coda_get_bitstream_payload(ctx) < 512)) {
-                       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                                "%d: not ready: not enough bitstream data (%d).\n",
-                                ctx->idx, coda_get_bitstream_payload(ctx));
+               meta = list_first_entry(&ctx->buffer_meta_list,
+                                       struct coda_buffer_meta, list);
+               if (!coda_bitstream_can_fetch_past(ctx, meta->end) &&
+                   !stream_end) {
+                       coda_dbg(1, ctx,
+                                "not ready: not enough bitstream data to read past %u (%u)\n",
+                                meta->end, ctx->bitstream_fifo.kfifo.in);
                        return 0;
                }
        }
 
        if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: aborting\n");
+               coda_dbg(1, ctx, "not ready: aborting\n");
                return 0;
        }
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "job ready\n");
+       coda_dbg(1, ctx, "job ready\n");
 
        return 1;
 }
@@ -1325,8 +1368,7 @@ static void coda_job_abort(void *priv)
 
        ctx->aborting = 1;
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "Aborting task\n");
+       coda_dbg(1, ctx, "job abort\n");
 }
 
 static const struct v4l2_m2m_ops coda_m2m_ops = {
@@ -1403,8 +1445,8 @@ static int coda_queue_setup(struct vb2_queue *vq,
        *nplanes = 1;
        sizes[0] = size;
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+       coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers,
+                size);
 
        return 0;
 }
@@ -1469,8 +1511,7 @@ static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx)
 
        profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Profile: %s\n",
-                profile_names[profile]);
+       coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]);
 }
 
 static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
@@ -1489,8 +1530,7 @@ static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
 
        level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Level: %s\n",
-                level_names[level]);
+       coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]);
 }
 
 static void coda_buf_queue(struct vb2_buffer *vb)
@@ -1595,6 +1635,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        if (count < 1)
                return -EINVAL;
 
+       coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]);
+
        INIT_LIST_HEAD(&list);
 
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -1687,14 +1729,13 @@ static void coda_stop_streaming(struct vb2_queue *q)
        struct coda_ctx *ctx = vb2_get_drv_priv(q);
        struct coda_dev *dev = ctx->dev;
        struct vb2_v4l2_buffer *buf;
-       unsigned long flags;
        bool stop;
 
        stop = ctx->streamon_out && ctx->streamon_cap;
 
+       coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]);
+
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: output\n", __func__);
                ctx->streamon_out = 0;
 
                coda_bit_stream_end_flag(ctx);
@@ -1704,8 +1745,6 @@ static void coda_stop_streaming(struct vb2_queue *q)
                while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
                        v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
        } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: capture\n", __func__);
                ctx->streamon_cap = 0;
 
                ctx->osequence = 0;
@@ -1722,7 +1761,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
                        queue_work(dev->workqueue, &ctx->seq_end_work);
                        flush_work(&ctx->seq_end_work);
                }
-               spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
+               spin_lock(&ctx->buffer_meta_lock);
                while (!list_empty(&ctx->buffer_meta_list)) {
                        meta = list_first_entry(&ctx->buffer_meta_list,
                                                struct coda_buffer_meta, list);
@@ -1730,7 +1769,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
                        kfree(meta);
                }
                ctx->num_metas = 0;
-               spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
+               spin_unlock(&ctx->buffer_meta_lock);
                kfifo_init(&ctx->bitstream_fifo,
                        ctx->bitstream.vaddr, ctx->bitstream.size);
                ctx->runcounter = 0;
@@ -1757,8 +1796,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
        struct coda_ctx *ctx =
                        container_of(ctrl->handler, struct coda_ctx, ctrls);
 
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+       coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
+                ctrl->id, ctrl->name, ctrl->val);
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
@@ -1792,14 +1831,13 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
                ctx->params.h264_max_qp = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
-               ctx->params.h264_deblk_alpha = ctrl->val;
+               ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
-               ctx->params.h264_deblk_beta = ctrl->val;
+               ctx->params.h264_slice_beta_offset_div2 = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-               ctx->params.h264_deblk_enabled = (ctrl->val ==
-                               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+               ctx->params.h264_disable_deblocking_filter_idc = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
                /* TODO: switch between baseline and constrained baseline */
@@ -1849,9 +1887,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
                ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff);
                break;
        default:
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "Invalid control, id=%d, val=%d\n",
-                       ctrl->id, ctrl->val);
+               coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n",
+                        ctrl->id, ctrl->val);
                return -EINVAL;
        }
 
@@ -1881,13 +1918,13 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0);
        v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0);
        v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+               0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
        v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_H264_PROFILE,
                V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
@@ -2099,17 +2136,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
        return coda_queue_init(priv, dst_vq);
 }
 
-static int coda_next_free_instance(struct coda_dev *dev)
-{
-       int idx = ffz(dev->instance_mask);
-
-       if ((idx < 0) ||
-           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
-               return -EBUSY;
-
-       return idx;
-}
-
 /*
  * File operations
  */
@@ -2118,7 +2144,8 @@ static int coda_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
        struct coda_dev *dev = video_get_drvdata(vdev);
-       struct coda_ctx *ctx = NULL;
+       struct coda_ctx *ctx;
+       unsigned int max = ~0;
        char *name;
        int ret;
        int idx;
@@ -2127,12 +2154,13 @@ static int coda_open(struct file *file)
        if (!ctx)
                return -ENOMEM;
 
-       idx = coda_next_free_instance(dev);
+       if (dev->devtype->product == CODA_DX6)
+               max = CODADX6_MAX_INSTANCES - 1;
+       idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL);
        if (idx < 0) {
                ret = idx;
                goto err_coda_max;
        }
-       set_bit(idx, &dev->instance_mask);
 
        name = kasprintf(GFP_KERNEL, "context%d", idx);
        if (!name) {
@@ -2156,6 +2184,9 @@ static int coda_open(struct file *file)
        v4l2_fh_add(&ctx->fh);
        ctx->dev = dev;
        ctx->idx = idx;
+
+       coda_dbg(1, ctx, "open instance (%p)\n", ctx);
+
        switch (dev->devtype->product) {
        case CODA_960:
                /*
@@ -2221,13 +2252,6 @@ static int coda_open(struct file *file)
        INIT_LIST_HEAD(&ctx->buffer_meta_list);
        spin_lock_init(&ctx->buffer_meta_lock);
 
-       mutex_lock(&dev->dev_mutex);
-       list_add(&ctx->list, &dev->instances);
-       mutex_unlock(&dev->dev_mutex);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
-                ctx->idx, ctx);
-
        return 0;
 
 err_ctrls_setup:
@@ -2241,8 +2265,8 @@ err_clk_per:
 err_pm_get:
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
 err_coda_name_init:
+       ida_free(&dev->ida, ctx->idx);
 err_coda_max:
        kfree(ctx);
        return ret;
@@ -2253,8 +2277,7 @@ static int coda_release(struct file *file)
        struct coda_dev *dev = video_drvdata(file);
        struct coda_ctx *ctx = fh_to_ctx(file->private_data);
 
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
-                ctx);
+       coda_dbg(1, ctx, "release instance (%p)\n", ctx);
 
        if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit)
                coda_bit_stream_end_flag(ctx);
@@ -2271,10 +2294,6 @@ static int coda_release(struct file *file)
                flush_work(&ctx->seq_end_work);
        }
 
-       mutex_lock(&dev->dev_mutex);
-       list_del(&ctx->list);
-       mutex_unlock(&dev->dev_mutex);
-
        if (ctx->dev->devtype->product == CODA_DX6)
                coda_free_aux_buf(dev, &ctx->workbuf);
 
@@ -2284,7 +2303,7 @@ static int coda_release(struct file *file)
        pm_runtime_put_sync(&dev->plat_dev->dev);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
+       ida_free(&dev->ida, ctx->idx);
        if (ctx->ops->release)
                ctx->ops->release(ctx);
        debugfs_remove_recursive(ctx->debugfs_entry);
@@ -2679,7 +2698,6 @@ static int coda_probe(struct platform_device *pdev)
                return -EINVAL;
 
        spin_lock_init(&dev->irqlock);
-       INIT_LIST_HEAD(&dev->instances);
 
        dev->plat_dev = pdev;
        dev->clk_per = devm_clk_get(&pdev->dev, "per");
@@ -2745,6 +2763,7 @@ static int coda_probe(struct platform_device *pdev)
 
        mutex_init(&dev->dev_mutex);
        mutex_init(&dev->coda_mutex);
+       ida_init(&dev->ida);
 
        dev->debugfs_root = debugfs_create_dir("coda", NULL);
        if (!dev->debugfs_root)
@@ -2832,6 +2851,7 @@ static int coda_remove(struct platform_device *pdev)
        coda_free_aux_buf(dev, &dev->tempbuf);
        coda_free_aux_buf(dev, &dev->workbuf);
        debugfs_remove_recursive(dev->debugfs_root);
+       ida_destroy(&dev->ida);
        return 0;
 }
 
index 19ac0b9dc6ebad27d01a7e2fabe25f55fcade73d..31cea72f5b2ac7b61b21206ccc3a5e06ba114254 100644 (file)
@@ -16,6 +16,7 @@
 #define __CODA_H__
 
 #include <linux/debugfs.h>
+#include <linux/idr.h>
 #include <linux/irqreturn.h>
 #include <linux/mutex.h>
 #include <linux/kfifo.h>
@@ -94,8 +95,7 @@ struct coda_dev {
        struct mutex            coda_mutex;
        struct workqueue_struct *workqueue;
        struct v4l2_m2m_dev     *m2m_dev;
-       struct list_head        instances;
-       unsigned long           instance_mask;
+       struct ida              ida;
        struct dentry           *debugfs_root;
 };
 
@@ -115,9 +115,9 @@ struct coda_params {
        u8                      h264_inter_qp;
        u8                      h264_min_qp;
        u8                      h264_max_qp;
-       u8                      h264_deblk_enabled;
-       u8                      h264_deblk_alpha;
-       u8                      h264_deblk_beta;
+       u8                      h264_disable_deblocking_filter_idc;
+       s8                      h264_slice_alpha_c0_offset_div2;
+       s8                      h264_slice_beta_offset_div2;
        u8                      h264_profile_idc;
        u8                      h264_level_idc;
        u8                      mpeg4_intra_qp;
@@ -144,8 +144,8 @@ struct coda_buffer_meta {
        u32                     sequence;
        struct v4l2_timecode    timecode;
        u64                     timestamp;
-       u32                     start;
-       u32                     end;
+       unsigned int            start;
+       unsigned int            end;
 };
 
 /* Per-queue, driver-specific private data */
@@ -192,7 +192,6 @@ struct coda_context_ops {
 struct coda_ctx {
        struct coda_dev                 *dev;
        struct mutex                    buffer_mutex;
-       struct list_head                list;
        struct work_struct              pic_run_work;
        struct work_struct              seq_end_work;
        struct completion               completion;
@@ -253,6 +252,13 @@ struct coda_ctx {
 
 extern int coda_debug;
 
+#define coda_dbg(level, ctx, fmt, arg...)                              \
+       do {                                                            \
+               if (coda_debug >= (level))                              \
+                       v4l2_dbg((level), coda_debug, &(ctx)->dev->v4l2_dev, \
+                        "%u: " fmt, (ctx)->idx, ##arg);                \
+       } while (0)
+
 void coda_write(struct coda_dev *dev, u32 data, u32 reg);
 unsigned int coda_read(struct coda_dev *dev, u32 reg);
 void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
@@ -295,6 +301,18 @@ static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx)
        return kfifo_len(&ctx->bitstream_fifo);
 }
 
+/*
+ * The bitstream prefetcher needs to read at least 2 256 byte periods past
+ * the desired bitstream position for all data to reach the decoder.
+ */
+static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx,
+                                                unsigned int pos)
+{
+       return (int)(ctx->bitstream_fifo.kfifo.in - ALIGN(pos, 256)) > 512;
+}
+
+bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos);
+
 void coda_bit_stream_end_flag(struct coda_ctx *ctx);
 
 void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
index 5e7b00a97671ef396426d0e2b8cf9c93c00afdb6..e675e38f3475e79737f3ac22e2e12911cede7003 100644 (file)
 #define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
 #define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
 #define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
-#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
+#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x03
 #define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
 #define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
 #define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
index ca671e315ad059d9af17f704f24ab90ce5a6c4ac..a672bfc4c6ba92dcdffe38891198981ebf399a8a 100644 (file)
@@ -97,8 +97,8 @@ DECLARE_EVENT_CLASS(coda_buf_meta_class,
        TP_fast_assign(
                __entry->minor = ctx->fh.vdev->minor;
                __entry->index = buf->vb2_buf.index;
-               __entry->start = meta->start;
-               __entry->end = meta->end;
+               __entry->start = meta->start & ctx->bitstream_fifo.kfifo.mask;
+               __entry->end = meta->end & ctx->bitstream_fifo.kfifo.mask;
                __entry->ctx = ctx->idx;
        ),
 
@@ -127,8 +127,10 @@ DECLARE_EVENT_CLASS(coda_meta_class,
 
        TP_fast_assign(
                __entry->minor = ctx->fh.vdev->minor;
-               __entry->start = meta ? meta->start : 0;
-               __entry->end = meta ? meta->end : 0;
+               __entry->start = meta ? (meta->start &
+                                        ctx->bitstream_fifo.kfifo.mask) : 0;
+               __entry->end = meta ? (meta->end &
+                                      ctx->bitstream_fifo.kfifo.mask) : 0;
                __entry->ctx = ctx->idx;
        ),
 
index 18c035ef84cfad4374978330e772600b6b959e6f..4766a7a23d16f8a479c3352699652c49d123050d 100644 (file)
@@ -92,28 +92,6 @@ static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
        return -EINVAL;
 }
 
-/**
- * vpbe_g_cropcap - Get crop capabilities of the display
- * @vpbe_dev: vpbe device ptr
- * @cropcap: cropcap is a ptr to struct v4l2_cropcap
- *
- * Update the crop capabilities in crop cap for current
- * mode
- */
-static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
-                         struct v4l2_cropcap *cropcap)
-{
-       if (!cropcap)
-               return -EINVAL;
-       cropcap->bounds.left = 0;
-       cropcap->bounds.top = 0;
-       cropcap->bounds.width = vpbe_dev->current_timings.xres;
-       cropcap->bounds.height = vpbe_dev->current_timings.yres;
-       cropcap->defrect = cropcap->bounds;
-
-       return 0;
-}
-
 /**
  * vpbe_enum_outputs - enumerate outputs
  * @vpbe_dev: vpbe device ptr
@@ -740,7 +718,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
        if (ret) {
                v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
                         def_output);
-               return ret;
+               goto fail_kfree_amp;
        }
 
        printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
@@ -748,12 +726,15 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
        if (ret) {
                v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
                         def_mode);
-               return ret;
+               goto fail_kfree_amp;
        }
        vpbe_dev->initialized = 1;
        /* TBD handling of bootargs for default output and mode */
        return 0;
 
+fail_kfree_amp:
+       mutex_lock(&vpbe_dev->lock);
+       kfree(vpbe_dev->amp);
 fail_kfree_encoders:
        kfree(vpbe_dev->encoders);
 fail_dev_unregister:
@@ -793,7 +774,6 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
 }
 
 static const struct vpbe_device_ops vpbe_dev_ops = {
-       .g_cropcap = vpbe_g_cropcap,
        .enum_outputs = vpbe_enum_outputs,
        .set_output = vpbe_set_output,
        .get_output = vpbe_get_output,
index 5c235898af7b29bcfd83249285a61db539273e8d..9e86b0d36640cd7fbf60691bc173ee4995324615 100644 (file)
@@ -759,18 +759,18 @@ static int vpbe_display_g_selection(struct file *file, void *priv,
        return 0;
 }
 
-static int vpbe_display_cropcap(struct file *file, void *priv,
-                             struct v4l2_cropcap *cropcap)
+static int vpbe_display_g_pixelaspect(struct file *file, void *priv,
+                                     int type, struct v4l2_fract *f)
 {
        struct vpbe_layer *layer = video_drvdata(file);
        struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
 
-       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+       if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
 
-       cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
+       *f = vpbe_dev->current_timings.aspect;
        return 0;
 }
 
@@ -1263,7 +1263,7 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
        .vidioc_streamoff        = vb2_ioctl_streamoff,
        .vidioc_expbuf           = vb2_ioctl_expbuf,
 
-       .vidioc_cropcap          = vpbe_display_cropcap,
+       .vidioc_g_pixelaspect    = vpbe_display_g_pixelaspect,
        .vidioc_g_selection      = vpbe_display_g_selection,
        .vidioc_s_selection      = vpbe_display_s_selection,
 
index ea3ddd5a42bd058e1c35fc6f314d1955eb34aed4..9996bab98fe3cab9a571cfd4035d6e9ac1e19bc1 100644 (file)
@@ -1558,20 +1558,20 @@ static int vpfe_streamoff(struct file *file, void *priv,
        return ret;
 }
 
-static int vpfe_cropcap(struct file *file, void *priv,
-                             struct v4l2_cropcap *crop)
+static int vpfe_g_pixelaspect(struct file *file, void *priv,
+                             int type, struct v4l2_fract *f)
 {
        struct vpfe_device *vpfe_dev = video_drvdata(file);
 
-       v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
+       v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_pixelaspect\n");
 
-       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
        /* If std_index is invalid, then just return (== 1:1 aspect) */
        if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
                return 0;
 
-       crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+       *f = vpfe_standards[vpfe_dev->std_index].pixelaspect;
        return 0;
 }
 
@@ -1677,7 +1677,7 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
        .vidioc_dqbuf            = vpfe_dqbuf,
        .vidioc_streamon         = vpfe_streamon,
        .vidioc_streamoff        = vpfe_streamoff,
-       .vidioc_cropcap          = vpfe_cropcap,
+       .vidioc_g_pixelaspect    = vpfe_g_pixelaspect,
        .vidioc_g_selection      = vpfe_g_selection,
        .vidioc_s_selection      = vpfe_s_selection,
 };
index 838c5c53de37d7e92e39926485587c11cb4f93b7..0fa3ec04ab7b4d624b7fc5c01e6ae2adc32f0f90 100644 (file)
@@ -541,20 +541,7 @@ void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
        }
 }
 
-int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
-{
-       struct gsc_frame *frame;
-
-       frame = ctx_get_frame(ctx, cr->type);
-       if (IS_ERR(frame))
-               return PTR_ERR(frame);
-
-       cr->c = frame->crop;
-
-       return 0;
-}
-
-int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
+int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s)
 {
        struct gsc_frame *f;
        struct gsc_dev *gsc = ctx->gsc_dev;
@@ -562,25 +549,25 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
        u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
        u32 min_w, min_h, max_w, max_h;
 
-       if (cr->c.top < 0 || cr->c.left < 0) {
+       if (s->r.top < 0 || s->r.left < 0) {
                pr_err("doesn't support negative values for top & left\n");
                return -EINVAL;
        }
-       pr_debug("user put w: %d, h: %d", cr->c.width, cr->c.height);
+       pr_debug("user put w: %d, h: %d", s->r.width, s->r.height);
 
-       if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                f = &ctx->d_frame;
-       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+       else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
                f = &ctx->s_frame;
        else
                return -EINVAL;
 
        max_w = f->f_width;
        max_h = f->f_height;
-       tmp_w = cr->c.width;
-       tmp_h = cr->c.height;
+       tmp_w = s->r.width;
+       tmp_h = s->r.height;
 
-       if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
+       if (V4L2_TYPE_IS_OUTPUT(s->type)) {
                if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) ||
                    is_rgb(f->fmt->color))
                        min_w = 32;
@@ -602,8 +589,8 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
                        max_h = f->f_width;
                        min_w = variant->pix_min->target_rot_en_w;
                        min_h = variant->pix_min->target_rot_en_h;
-                       tmp_w = cr->c.height;
-                       tmp_h = cr->c.width;
+                       tmp_w = s->r.height;
+                       tmp_h = s->r.width;
                } else {
                        min_w = variant->pix_min->target_rot_dis_w;
                        min_h = variant->pix_min->target_rot_dis_h;
@@ -616,29 +603,29 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
        v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
                              &tmp_h, min_h, max_h, mod_y, 0);
 
-       if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
-               (ctx->gsc_ctrls.rotate->val == 90 ||
-               ctx->gsc_ctrls.rotate->val == 270))
+       if (!V4L2_TYPE_IS_OUTPUT(s->type) &&
+           (ctx->gsc_ctrls.rotate->val == 90 ||
+            ctx->gsc_ctrls.rotate->val == 270))
                gsc_check_crop_change(tmp_h, tmp_w,
-                                       &cr->c.width, &cr->c.height);
+                                       &s->r.width, &s->r.height);
        else
                gsc_check_crop_change(tmp_w, tmp_h,
-                                       &cr->c.width, &cr->c.height);
+                                       &s->r.width, &s->r.height);
 
 
        /* adjust left/top if cropping rectangle is out of bounds */
        /* Need to add code to algin left value with 2's multiple */
-       if (cr->c.left + tmp_w > max_w)
-               cr->c.left = max_w - tmp_w;
-       if (cr->c.top + tmp_h > max_h)
-               cr->c.top = max_h - tmp_h;
+       if (s->r.left + tmp_w > max_w)
+               s->r.left = max_w - tmp_w;
+       if (s->r.top + tmp_h > max_h)
+               s->r.top = max_h - tmp_h;
 
        if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
-               cr->c.left & 1)
-                       cr->c.left -= 1;
+           s->r.left & 1)
+               s->r.left -= 1;
 
        pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
-           cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
+                s->r.left, s->r.top, s->r.width, s->r.height, max_w, max_h);
 
        return 0;
 }
index 715d9c9d8d30ad415abdf1818be66382414edfcc..c81f0a17d286418d6c8bcdaa099bdd33424c21a2 100644 (file)
@@ -392,8 +392,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
 void gsc_set_frame_size(struct gsc_frame *frame, int width, int height);
 int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
 void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h);
-int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
-int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
+int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s);
 int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
                                                        u32 *ratio);
 void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh);
index cc5d690818e17d87f901ce10da4e87b31bf4f5f3..c757f5d98bccf59b425bc2ec34ae1ab2afb2d8cb 100644 (file)
@@ -494,30 +494,27 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
 {
        struct gsc_frame *frame;
        struct gsc_ctx *ctx = fh_to_ctx(fh);
-       struct v4l2_crop cr;
        struct gsc_variant *variant = ctx->gsc_dev->variant;
+       struct v4l2_selection sel = *s;
        int ret;
 
-       cr.type = s->type;
-       cr.c = s->r;
-
        if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
            (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
                return -EINVAL;
 
-       ret = gsc_try_crop(ctx, &cr);
+       ret = gsc_try_selection(ctx, &sel);
        if (ret)
                return ret;
 
        if (s->flags & V4L2_SEL_FLAG_LE &&
-           !is_rectangle_enclosed(&cr.c, &s->r))
+           !is_rectangle_enclosed(&sel.r, &s->r))
                return -ERANGE;
 
        if (s->flags & V4L2_SEL_FLAG_GE &&
-           !is_rectangle_enclosed(&s->r, &cr.c))
+           !is_rectangle_enclosed(&s->r, &sel.r))
                return -ERANGE;
 
-       s->r = cr.c;
+       s->r = sel.r;
 
        switch (s->target) {
        case V4L2_SEL_TGT_COMPOSE_BOUNDS:
@@ -539,15 +536,15 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
        /* Check to see if scaling ratio is within supported range */
        if (gsc_ctx_state_is_set(GSC_DST_FMT | GSC_SRC_FMT, ctx)) {
                if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-                       ret = gsc_check_scaler_ratio(variant, cr.c.width,
-                               cr.c.height, ctx->d_frame.crop.width,
+                       ret = gsc_check_scaler_ratio(variant, sel.r.width,
+                               sel.r.height, ctx->d_frame.crop.width,
                                ctx->d_frame.crop.height,
                                ctx->gsc_ctrls.rotate->val, ctx->out_path);
                } else {
                        ret = gsc_check_scaler_ratio(variant,
                                ctx->s_frame.crop.width,
-                               ctx->s_frame.crop.height, cr.c.width,
-                               cr.c.height, ctx->gsc_ctrls.rotate->val,
+                               ctx->s_frame.crop.height, sel.r.width,
+                               sel.r.height, ctx->gsc_ctrls.rotate->val,
                                ctx->out_path);
                }
 
@@ -557,7 +554,7 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
                }
        }
 
-       frame->crop = cr.c;
+       frame->crop = sel.r;
 
        gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
        return 0;
index 82d514df97f04df7da66f1f1cf7eb7ddb5e72923..9f751a5efd64a7da0a51d1ad083ad657d7154dd7 100644 (file)
@@ -596,12 +596,14 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
 {
        struct fimc_frame *frame;
 
-       if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
+           type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx))
                        frame = &ctx->s_frame;
                else
                        return ERR_PTR(-EINVAL);
-       } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
+       } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+                  type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                frame = &ctx->d_frame;
        } else {
                v4l2_err(ctx->fimc_dev->v4l2_dev,
index e050e63fe358683c61e1c0c0e00e21e5e25f41d5..bbb08576492efb8e6d566d62628d2d045ec77c6b 100644 (file)
@@ -90,8 +90,8 @@ const char *fimc_is_param_strerr(unsigned int error)
                return "ERROR_SENSOR_INVALID_SIZE";
        case ERROR_SENSOR_INVALID_SETTING:
                return "ERROR_SENSOR_INVALID_SETTING";
-       case ERROR_SENSOR_ACTURATOR_INIT_FAIL:
-               return "ERROR_SENSOR_ACTURATOR_INIT_FAIL";
+       case ERROR_SENSOR_ACTUATOR_INIT_FAIL:
+               return "ERROR_SENSOR_ACTUATOR_INIT_FAIL";
        case ERROR_SENSOR_INVALID_AF_POS:
                return "ERROR_SENSOR_INVALID_AF_POS";
        case ERROR_SENSOR_UNSUPPORT_FUNC:
index ef981e74513a9f5f60df574e1045627915b3f0be..77f4fc860be576dc756f3fd40db447fab250d7cd 100644 (file)
@@ -189,7 +189,7 @@ enum fimc_is_error {
        ERROR_SENSOR_INVALID_EXPOSURETIME,
        ERROR_SENSOR_INVALID_SIZE,
        ERROR_SENSOR_INVALID_SETTING,
-       ERROR_SENSOR_ACTURATOR_INIT_FAIL,
+       ERROR_SENSOR_ACTUATOR_INIT_FAIL,
        ERROR_SENSOR_INVALID_AF_POS,
        ERROR_SENSOR_UNSUPPORT_FUNC,
        ERROR_SENSOR_UNSUPPORT_PERI,
index a19f8b164a47d460faac9c60ac8641cd70961ced..61c8177409cfdd9dda804c723cf7cb60ba564ad3 100644 (file)
@@ -383,60 +383,80 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
        return 0;
 }
 
-static int fimc_m2m_cropcap(struct file *file, void *fh,
-                           struct v4l2_cropcap *cr)
+static int fimc_m2m_g_selection(struct file *file, void *fh,
+                               struct v4l2_selection *s)
 {
        struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_frame *frame;
 
-       frame = ctx_get_frame(ctx, cr->type);
+       frame = ctx_get_frame(ctx, s->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       cr->bounds.left = 0;
-       cr->bounds.top = 0;
-       cr->bounds.width = frame->o_width;
-       cr->bounds.height = frame->o_height;
-       cr->defrect = cr->bounds;
-
-       return 0;
-}
-
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       struct fimc_frame *frame;
-
-       frame = ctx_get_frame(ctx, cr->type);
-       if (IS_ERR(frame))
-               return PTR_ERR(frame);
-
-       cr->c.left = frame->offs_h;
-       cr->c.top = frame->offs_v;
-       cr->c.width = frame->width;
-       cr->c.height = frame->height;
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       return -EINVAL;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_COMPOSE:
+               s->r.left = frame->offs_h;
+               s->r.top = frame->offs_v;
+               s->r.width = frame->width;
+               s->r.height = frame->height;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = frame->o_width;
+               s->r.height = frame->o_height;
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
 
-static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+static int fimc_m2m_try_selection(struct fimc_ctx *ctx,
+                                 struct v4l2_selection *s)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *f;
        u32 min_size, halign, depth = 0;
        int i;
 
-       if (cr->c.top < 0 || cr->c.left < 0) {
+       if (s->r.top < 0 || s->r.left < 0) {
                v4l2_err(&fimc->m2m.vfd,
                        "doesn't support negative values for top & left\n");
                return -EINVAL;
        }
-       if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+       if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                f = &ctx->d_frame;
-       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               if (s->target != V4L2_SEL_TGT_COMPOSE)
+                       return -EINVAL;
+       } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                f = &ctx->s_frame;
-       else
+               if (s->target != V4L2_SEL_TGT_CROP)
+                       return -EINVAL;
+       } else {
                return -EINVAL;
+       }
 
        min_size = (f == &ctx->s_frame) ?
                fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
@@ -450,61 +470,61 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
        for (i = 0; i < f->fmt->memplanes; i++)
                depth += f->fmt->depth[i];
 
-       v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+       v4l_bound_align_image(&s->r.width, min_size, f->o_width,
                              ffs(min_size) - 1,
-                             &cr->c.height, min_size, f->o_height,
+                             &s->r.height, min_size, f->o_height,
                              halign, 64/(ALIGN(depth, 8)));
 
        /* adjust left/top if cropping rectangle is out of bounds */
-       if (cr->c.left + cr->c.width > f->o_width)
-               cr->c.left = f->o_width - cr->c.width;
-       if (cr->c.top + cr->c.height > f->o_height)
-               cr->c.top = f->o_height - cr->c.height;
+       if (s->r.left + s->r.width > f->o_width)
+               s->r.left = f->o_width - s->r.width;
+       if (s->r.top + s->r.height > f->o_height)
+               s->r.top = f->o_height - s->r.height;
 
-       cr->c.left = round_down(cr->c.left, min_size);
-       cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
+       s->r.left = round_down(s->r.left, min_size);
+       s->r.top  = round_down(s->r.top, fimc->variant->hor_offs_align);
 
        dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
-           cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+           s->r.left, s->r.top, s->r.width, s->r.height,
            f->f_width, f->f_height);
 
        return 0;
 }
 
-static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
+static int fimc_m2m_s_selection(struct file *file, void *fh,
+                               struct v4l2_selection *s)
 {
        struct fimc_ctx *ctx = fh_to_ctx(fh);
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_crop cr = *crop;
        struct fimc_frame *f;
        int ret;
 
-       ret = fimc_m2m_try_crop(ctx, &cr);
+       ret = fimc_m2m_try_selection(ctx, s);
        if (ret)
                return ret;
 
-       f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+       f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
                &ctx->s_frame : &ctx->d_frame;
 
        /* Check to see if scaling ratio is within supported range */
-       if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               ret = fimc_check_scaler_ratio(ctx, cr.c.width,
-                               cr.c.height, ctx->d_frame.width,
+       if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               ret = fimc_check_scaler_ratio(ctx, s->r.width,
+                               s->r.height, ctx->d_frame.width,
                                ctx->d_frame.height, ctx->rotation);
        } else {
                ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
-                               ctx->s_frame.height, cr.c.width,
-                               cr.c.height, ctx->rotation);
+                               ctx->s_frame.height, s->r.width,
+                               s->r.height, ctx->rotation);
        }
        if (ret) {
                v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
                return -EINVAL;
        }
 
-       f->offs_h = cr.c.left;
-       f->offs_v = cr.c.top;
-       f->width  = cr.c.width;
-       f->height = cr.c.height;
+       f->offs_h = s->r.left;
+       f->offs_v = s->r.top;
+       f->width  = s->r.width;
+       f->height = s->r.height;
 
        fimc_ctx_state_set(FIMC_PARAMS, ctx);
 
@@ -528,9 +548,8 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
        .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
        .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
-       .vidioc_g_crop                  = fimc_m2m_g_crop,
-       .vidioc_s_crop                  = fimc_m2m_s_crop,
-       .vidioc_cropcap                 = fimc_m2m_cropcap
+       .vidioc_g_selection             = fimc_m2m_g_selection,
+       .vidioc_s_selection             = fimc_m2m_s_selection,
 
 };
 
@@ -717,6 +736,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc,
        vfd->release = video_device_release_empty;
        vfd->lock = &fimc->lock;
        vfd->vfl_dir = VFL_DIR_M2M;
+       set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
 
        snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
        video_set_drvdata(vfd, fimc);
index 870501b0f351addb127f3b29c0dec9d5dee867d1..463f2d84553e1eb3a9c97d73e5bd7d53af3d91ad 100644 (file)
@@ -445,7 +445,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
         */
        np = of_get_parent(rem);
 
-       if (np && !of_node_cmp(np->name, "i2c-isp"))
+       if (of_node_name_eq(np, "i2c-isp"))
                pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
        else
                pd->fimc_bus_type = pd->sensor_bus_type;
@@ -495,7 +495,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
        for_each_available_child_of_node(parent, node) {
                struct device_node *port;
 
-               if (of_node_cmp(node->name, "csis"))
+               if (!of_node_name_eq(node, "csis"))
                        continue;
                /* The csis node can have only port subnode. */
                port = of_get_next_child(node, NULL);
@@ -720,13 +720,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd,
                        continue;
 
                /* If driver of any entity isn't ready try all again later. */
-               if (!strcmp(node->name, CSIS_OF_NODE_NAME))
+               if (of_node_name_eq(node, CSIS_OF_NODE_NAME))
                        plat_entity = IDX_CSIS;
-               else if (!strcmp(node->name, FIMC_IS_OF_NODE_NAME))
+               else if (of_node_name_eq(node, FIMC_IS_OF_NODE_NAME))
                        plat_entity = IDX_IS_ISP;
-               else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
+               else if (of_node_name_eq(node, FIMC_LITE_OF_NODE_NAME))
                        plat_entity = IDX_FLITE;
-               else if (!strcmp(node->name, FIMC_OF_NODE_NAME) &&
+               else if (of_node_name_eq(node, FIMC_OF_NODE_NAME) &&
                         !of_property_read_bool(node, "samsung,lcd-wb"))
                        plat_entity = IDX_FIMC;
 
index b76cd0e8313c81e1fb30a4584695f823f59aa24d..c1c255408d1633b41cf8e58fbb5b51e2259adebb 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
-#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/sched.h>
@@ -1607,7 +1606,7 @@ static const struct v4l2_m2m_ops m2m_ops = {
        .job_abort      = pxp_job_abort,
 };
 
-static void pxp_soft_reset(struct pxp_dev *dev)
+static int pxp_soft_reset(struct pxp_dev *dev)
 {
        int ret;
        u32 val;
@@ -1620,10 +1619,12 @@ static void pxp_soft_reset(struct pxp_dev *dev)
        ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
                                 val & BM_PXP_CTRL_CLKGATE, 0, 100);
        if (ret < 0)
-               pr_err("PXP reset timeout\n");
+               return ret;
 
        writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
        writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+
+       return 0;
 }
 
 static int pxp_probe(struct platform_device *pdev)
@@ -1666,8 +1667,15 @@ static int pxp_probe(struct platform_device *pdev)
                return ret;
        }
 
-       clk_prepare_enable(dev->clk);
-       pxp_soft_reset(dev);
+       ret = clk_prepare_enable(dev->clk);
+       if (ret < 0)
+               return ret;
+
+       ret = pxp_soft_reset(dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "PXP reset timeout: %d\n", ret);
+               goto err_clk;
+       }
 
        spin_lock_init(&dev->irqlock);
 
index 2986cb4b88d0379cac9c5fd401cfa5561dfbe538..8d00d9d8adff87a802c08ea5a5f54869b8bea922 100644 (file)
@@ -4,7 +4,7 @@
  * sensor.
  *
  * The data sheet for this device can be found at:
- *    http://www.marvell.com/products/pc_connectivity/88alp01/
+ *    http://wiki.laptop.org/images/5/5c/88ALP01_Datasheet_July_2007.pdf
  *
  * Copyright 2006-11 One Laptop Per Child Association, Inc.
  * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
index 54631ad1c71eb760cc206322eb571203acd217f6..d1f12257bf66b0fd439784a5bf6be171090b19bf 100644 (file)
@@ -1087,7 +1087,6 @@ static void mtk_venc_worker(struct work_struct *work)
        src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
        memset(&frm_buf, 0, sizeof(frm_buf));
        for (i = 0; i < src_buf->num_planes ; i++) {
-               frm_buf.fb_addr[i].va = vb2_plane_vaddr(src_buf, i);
                frm_buf.fb_addr[i].dma_addr =
                                vb2_dma_contig_plane_dma_addr(src_buf, i);
                frm_buf.fb_addr[i].size =
@@ -1098,14 +1097,11 @@ static void mtk_venc_worker(struct work_struct *work)
        bs_buf.size = (size_t)dst_buf->planes[0].length;
 
        mtk_v4l2_debug(2,
-                       "Framebuf VA=%p PA=%llx Size=0x%zx;VA=%p PA=0x%llx Size=0x%zx;VA=%p PA=0x%llx Size=%zu",
-                       frm_buf.fb_addr[0].va,
+                       "Framebuf PA=%llx Size=0x%zx;PA=0x%llx Size=0x%zx;PA=0x%llx Size=%zu",
                        (u64)frm_buf.fb_addr[0].dma_addr,
                        frm_buf.fb_addr[0].size,
-                       frm_buf.fb_addr[1].va,
                        (u64)frm_buf.fb_addr[1].dma_addr,
                        frm_buf.fb_addr[1].size,
-                       frm_buf.fb_addr[2].va,
                        (u64)frm_buf.fb_addr[2].dma_addr,
                        frm_buf.fb_addr[2].size);
 
index 3e73e9db781f426f5682cda940c8ab0499803319..7c025045ea904ff12279c98acc05eca5b55198bf 100644 (file)
@@ -41,25 +41,27 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
        node = of_parse_phandle(dev->of_node, "mediatek,larb", 0);
        if (!node) {
                mtk_v4l2_err("no mediatek,larb found");
-               return -1;
+               return -ENODEV;
        }
        pdev = of_find_device_by_node(node);
+       of_node_put(node);
        if (!pdev) {
                mtk_v4l2_err("no mediatek,larb device found");
-               return -1;
+               return -ENODEV;
        }
        pm->larbvenc = &pdev->dev;
 
        node = of_parse_phandle(dev->of_node, "mediatek,larb", 1);
        if (!node) {
                mtk_v4l2_err("no mediatek,larb found");
-               return -1;
+               return -ENODEV;
        }
 
        pdev = of_find_device_by_node(node);
+       of_node_put(node);
        if (!pdev) {
                mtk_v4l2_err("no mediatek,larb device found");
-               return -1;
+               return -ENODEV;
        }
 
        pm->larbvenclt = &pdev->dev;
index 06c254f5c171f2451eafbb552e52402f591e3711..9bf6e8d1b9c9847475ed5db6530b5ca26773da72 100644 (file)
@@ -25,6 +25,11 @@ struct mtk_vcodec_mem {
        dma_addr_t dma_addr;
 };
 
+struct mtk_vcodec_fb {
+       size_t size;
+       dma_addr_t dma_addr;
+};
+
 struct mtk_vcodec_ctx;
 struct mtk_vcodec_dev;
 
index a6e7d32e55cb48057ec6ba2aa715b409a804d6ed..55ecda844894b3687af71af2de08172a889de62a 100644 (file)
@@ -106,7 +106,7 @@ struct venc_enc_param {
  * @fb_addr: plane frame buffer addresses
  */
 struct venc_frm_buf {
-       struct mtk_vcodec_mem fb_addr[MTK_VCODEC_MAX_PLANES];
+       struct mtk_vcodec_fb fb_addr[MTK_VCODEC_MAX_PLANES];
 };
 
 /*
index ed6a557de65da28c0e87f86d0688a7b21f2971af..a8c542fa647db185fcce25807cac4fe931a5c412 100644 (file)
@@ -37,9 +37,9 @@
 /* VFE halt timeout */
 #define VFE_HALT_TIMEOUT_MS 100
 /* Max number of frame drop updates per frame */
-#define VFE_FRAME_DROP_UPDATES 5
-/* Frame drop value. NOTE: VAL + UPDATES should not exceed 31 */
-#define VFE_FRAME_DROP_VAL 20
+#define VFE_FRAME_DROP_UPDATES 2
+/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
+#define VFE_FRAME_DROP_VAL 30
 
 #define VFE_NEXT_SOF_MS 500
 
@@ -659,7 +659,9 @@ static int vfe_enable_output(struct vfe_line *line)
        struct vfe_device *vfe = to_vfe(line);
        struct vfe_output *output = &line->output;
        const struct vfe_hw_ops *ops = vfe->ops;
+       struct media_entity *sensor;
        unsigned long flags;
+       unsigned int frame_skip = 0;
        unsigned int i;
        u16 ub_size;
 
@@ -667,6 +669,17 @@ static int vfe_enable_output(struct vfe_line *line)
        if (!ub_size)
                return -EINVAL;
 
+       sensor = camss_find_sensor(&line->subdev.entity);
+       if (sensor) {
+               struct v4l2_subdev *subdev =
+                                       media_entity_to_v4l2_subdev(sensor);
+
+               v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
+               /* Max frame skip is 29 frames */
+               if (frame_skip > VFE_FRAME_DROP_VAL - 1)
+                       frame_skip = VFE_FRAME_DROP_VAL - 1;
+       }
+
        spin_lock_irqsave(&vfe->output_lock, flags);
 
        ops->reg_update_clear(vfe, line->id);
@@ -695,10 +708,10 @@ static int vfe_enable_output(struct vfe_line *line)
 
        switch (output->state) {
        case VFE_OUTPUT_SINGLE:
-               vfe_output_frame_drop(vfe, output, 1);
+               vfe_output_frame_drop(vfe, output, 1 << frame_skip);
                break;
        case VFE_OUTPUT_CONTINUOUS:
-               vfe_output_frame_drop(vfe, output, 3);
+               vfe_output_frame_drop(vfe, output, 3 << frame_skip);
                break;
        default:
                vfe_output_frame_drop(vfe, output, 0);
index 45978db3b0bec8618efe61dce38bc08ff78f4ec3..63da18773d2459e4597ce6c49564d3456c5618f5 100644 (file)
@@ -346,7 +346,7 @@ void camss_disable_clocks(int nclocks, struct camss_clock *clock)
  *
  * Return a pointer to sensor media entity or NULL if not found
  */
-static struct media_entity *camss_find_sensor(struct media_entity *entity)
+struct media_entity *camss_find_sensor(struct media_entity *entity)
 {
        struct media_pad *pad;
 
index 57b269ca93fd6ac29e81cfab21d35e024353937b..1376b07889bf2d925c1c54c43fc20379aa3350cc 100644 (file)
@@ -106,6 +106,7 @@ void camss_add_clock_margin(u64 *rate);
 int camss_enable_clocks(int nclocks, struct camss_clock *clock,
                        struct device *dev);
 void camss_disable_clocks(int nclocks, struct camss_clock *clock);
+struct media_entity *camss_find_sensor(struct media_entity *entity);
 int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock);
 int camss_pm_domain_on(struct camss *camss, int id);
 void camss_pm_domain_off(struct camss *camss, int id);
index bb6add9d340e29cc6218d3b2ff167a723bbebfff..cb411eb85ee4055a2fd2552ac5d7d18d7a96add9 100644 (file)
@@ -76,7 +76,7 @@ static void venus_sys_error_handler(struct work_struct *work)
        hfi_core_deinit(core, true);
        hfi_destroy(core);
        mutex_lock(&core->lock);
-       venus_shutdown(core->dev);
+       venus_shutdown(core);
 
        pm_runtime_put_sync(core->dev);
 
@@ -84,7 +84,7 @@ static void venus_sys_error_handler(struct work_struct *work)
 
        pm_runtime_get_sync(core->dev);
 
-       ret |= venus_boot(core->dev, core->res->fwname);
+       ret |= venus_boot(core);
 
        ret |= hfi_core_resume(core, true);
 
@@ -264,6 +264,14 @@ static int venus_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       if (!dev->dma_parms) {
+               dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+                                             GFP_KERNEL);
+               if (!dev->dma_parms)
+                       return -ENOMEM;
+       }
+       dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+
        INIT_LIST_HEAD(&core->instances);
        mutex_init(&core->lock);
        INIT_DELAYED_WORK(&core->work, venus_sys_error_handler);
@@ -284,7 +292,15 @@ static int venus_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_runtime_disable;
 
-       ret = venus_boot(dev, core->res->fwname);
+       ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+       if (ret)
+               goto err_runtime_disable;
+
+       ret = venus_firmware_init(core);
+       if (ret)
+               goto err_runtime_disable;
+
+       ret = venus_boot(core);
        if (ret)
                goto err_runtime_disable;
 
@@ -308,10 +324,6 @@ static int venus_probe(struct platform_device *pdev)
        if (ret)
                goto err_core_deinit;
 
-       ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
-       if (ret)
-               goto err_dev_unregister;
-
        ret = pm_runtime_put_sync(dev);
        if (ret)
                goto err_dev_unregister;
@@ -323,7 +335,7 @@ err_dev_unregister:
 err_core_deinit:
        hfi_core_deinit(core, false);
 err_venus_shutdown:
-       venus_shutdown(dev);
+       venus_shutdown(core);
 err_runtime_disable:
        pm_runtime_set_suspended(dev);
        pm_runtime_disable(dev);
@@ -344,9 +356,11 @@ static int venus_remove(struct platform_device *pdev)
        WARN_ON(ret);
 
        hfi_destroy(core);
-       venus_shutdown(dev);
+       venus_shutdown(core);
        of_platform_depopulate(dev);
 
+       venus_firmware_deinit(core);
+
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
index 2f02365f4818e63636c6a90963c88e1da94a81cb..6382cea2918582af545818a3cce4c4d47245aa25 100644 (file)
@@ -98,6 +98,7 @@ struct venus_caps {
  * @dev:               convenience struct device pointer
  * @dev_dec:   convenience struct device pointer for decoder device
  * @dev_enc:   convenience struct device pointer for encoder device
+ * @use_tz:    a flag that suggests presence of trustzone
  * @lock:      a lock for this strucure
  * @instances: a list_head of all instances
  * @insts_count:       num of instances
@@ -129,6 +130,11 @@ struct venus_core {
        struct device *dev;
        struct device *dev_dec;
        struct device *dev_enc;
+       unsigned int use_tz;
+       struct video_firmware {
+               struct device *dev;
+               struct iommu_domain *iommu_domain;
+       } fw;
        struct mutex lock;
        struct list_head instances;
        atomic_t insts_count;
index c4a577848dd7a889ae474840721e5d557f5c5026..c29acfd70c1b152cd58a5783e052792582692dce 100644 (file)
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/kernel.h>
+#include <linux/iommu.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
 #include <linux/qcom_scm.h>
 #include <linux/sizes.h>
 #include <linux/soc/qcom/mdt_loader.h>
 
+#include "core.h"
 #include "firmware.h"
+#include "hfi_venus_io.h"
 
 #define VENUS_PAS_ID                   9
 #define VENUS_FW_MEM_SIZE              (6 * SZ_1M)
+#define VENUS_FW_START_ADDR            0x0
 
-int venus_boot(struct device *dev, const char *fwname)
+static void venus_reset_cpu(struct venus_core *core)
+{
+       void __iomem *base = core->base;
+
+       writel(0, base + WRAPPER_FW_START_ADDR);
+       writel(VENUS_FW_MEM_SIZE, base + WRAPPER_FW_END_ADDR);
+       writel(0, base + WRAPPER_CPA_START_ADDR);
+       writel(VENUS_FW_MEM_SIZE, base + WRAPPER_CPA_END_ADDR);
+       writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_START_ADDR);
+       writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_END_ADDR);
+       writel(0x0, base + WRAPPER_CPU_CGC_DIS);
+       writel(0x0, base + WRAPPER_CPU_CLOCK_CONFIG);
+
+       /* Bring ARM9 out of reset */
+       writel(0, base + WRAPPER_A9SS_SW_RESET);
+}
+
+int venus_set_hw_state(struct venus_core *core, bool resume)
+{
+       if (core->use_tz)
+               return qcom_scm_set_remote_state(resume, 0);
+
+       if (resume)
+               venus_reset_cpu(core);
+       else
+               writel(1, core->base + WRAPPER_A9SS_SW_RESET);
+
+       return 0;
+}
+
+static int venus_load_fw(struct venus_core *core, const char *fwname,
+                        phys_addr_t *mem_phys, size_t *mem_size)
 {
        const struct firmware *mdt;
        struct device_node *node;
-       phys_addr_t mem_phys;
+       struct device *dev;
        struct resource r;
        ssize_t fw_size;
-       size_t mem_size;
        void *mem_va;
        int ret;
 
-       if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available())
-               return -EPROBE_DEFER;
-
+       dev = core->dev;
        node = of_parse_phandle(dev->of_node, "memory-region", 0);
        if (!node) {
                dev_err(dev, "no memory-region specified\n");
@@ -51,16 +85,16 @@ int venus_boot(struct device *dev, const char *fwname)
        if (ret)
                return ret;
 
-       mem_phys = r.start;
-       mem_size = resource_size(&r);
+       *mem_phys = r.start;
+       *mem_size = resource_size(&r);
 
-       if (mem_size < VENUS_FW_MEM_SIZE)
+       if (*mem_size < VENUS_FW_MEM_SIZE)
                return -EINVAL;
 
-       mem_va = memremap(r.start, mem_size, MEMREMAP_WC);
+       mem_va = memremap(r.start, *mem_size, MEMREMAP_WC);
        if (!mem_va) {
                dev_err(dev, "unable to map memory region: %pa+%zx\n",
-                       &r.start, mem_size);
+                       &r.start, *mem_size);
                return -ENOMEM;
        }
 
@@ -75,24 +109,181 @@ int venus_boot(struct device *dev, const char *fwname)
                goto err_unmap;
        }
 
-       ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys,
-                           mem_size, NULL);
+       if (core->use_tz)
+               ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID,
+                                   mem_va, *mem_phys, *mem_size, NULL);
+       else
+               ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID,
+                                           mem_va, *mem_phys, *mem_size, NULL);
 
        release_firmware(mdt);
 
-       if (ret)
-               goto err_unmap;
-
-       ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
-       if (ret)
-               goto err_unmap;
-
 err_unmap:
        memunmap(mem_va);
        return ret;
 }
 
-int venus_shutdown(struct device *dev)
+static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys,
+                           size_t mem_size)
+{
+       struct iommu_domain *iommu;
+       struct device *dev;
+       int ret;
+
+       dev = core->fw.dev;
+       if (!dev)
+               return -EPROBE_DEFER;
+
+       iommu = core->fw.iommu_domain;
+
+       ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size,
+                       IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV);
+       if (ret) {
+               dev_err(dev, "could not map video firmware region\n");
+               return ret;
+       }
+
+       venus_reset_cpu(core);
+
+       return 0;
+}
+
+static int venus_shutdown_no_tz(struct venus_core *core)
+{
+       struct iommu_domain *iommu;
+       size_t unmapped;
+       u32 reg;
+       struct device *dev = core->fw.dev;
+       void __iomem *base = core->base;
+
+       /* Assert the reset to ARM9 */
+       reg = readl_relaxed(base + WRAPPER_A9SS_SW_RESET);
+       reg |= WRAPPER_A9SS_SW_RESET_BIT;
+       writel_relaxed(reg, base + WRAPPER_A9SS_SW_RESET);
+
+       /* Make sure reset is asserted before the mapping is removed */
+       mb();
+
+       iommu = core->fw.iommu_domain;
+
+       unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, VENUS_FW_MEM_SIZE);
+       if (unmapped != VENUS_FW_MEM_SIZE)
+               dev_err(dev, "failed to unmap firmware\n");
+
+       return 0;
+}
+
+int venus_boot(struct venus_core *core)
 {
-       return qcom_scm_pas_shutdown(VENUS_PAS_ID);
+       struct device *dev = core->dev;
+       phys_addr_t mem_phys;
+       size_t mem_size;
+       int ret;
+
+       if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ||
+           (core->use_tz && !qcom_scm_is_available()))
+               return -EPROBE_DEFER;
+
+       ret = venus_load_fw(core, core->res->fwname, &mem_phys, &mem_size);
+       if (ret) {
+               dev_err(dev, "fail to load video firmware\n");
+               return -EINVAL;
+       }
+
+       if (core->use_tz)
+               ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
+       else
+               ret = venus_boot_no_tz(core, mem_phys, mem_size);
+
+       return ret;
+}
+
+int venus_shutdown(struct venus_core *core)
+{
+       int ret;
+
+       if (core->use_tz)
+               ret = qcom_scm_pas_shutdown(VENUS_PAS_ID);
+       else
+               ret = venus_shutdown_no_tz(core);
+
+       return ret;
+}
+
+int venus_firmware_init(struct venus_core *core)
+{
+       struct platform_device_info info;
+       struct iommu_domain *iommu_dom;
+       struct platform_device *pdev;
+       struct device_node *np;
+       int ret;
+
+       np = of_get_child_by_name(core->dev->of_node, "video-firmware");
+       if (!np) {
+               core->use_tz = true;
+               return 0;
+       }
+
+       memset(&info, 0, sizeof(info));
+       info.fwnode = &np->fwnode;
+       info.parent = core->dev;
+       info.name = np->name;
+       info.dma_mask = DMA_BIT_MASK(32);
+
+       pdev = platform_device_register_full(&info);
+       if (IS_ERR(pdev)) {
+               of_node_put(np);
+               return PTR_ERR(pdev);
+       }
+
+       pdev->dev.of_node = np;
+
+       ret = of_dma_configure(&pdev->dev, np, true);
+       if (ret) {
+               dev_err(core->dev, "dma configure fail\n");
+               goto err_unregister;
+       }
+
+       core->fw.dev = &pdev->dev;
+
+       iommu_dom = iommu_domain_alloc(&platform_bus_type);
+       if (!iommu_dom) {
+               dev_err(core->fw.dev, "Failed to allocate iommu domain\n");
+               ret = -ENOMEM;
+               goto err_unregister;
+       }
+
+       ret = iommu_attach_device(iommu_dom, core->fw.dev);
+       if (ret) {
+               dev_err(core->fw.dev, "could not attach device\n");
+               goto err_iommu_free;
+       }
+
+       core->fw.iommu_domain = iommu_dom;
+
+       of_node_put(np);
+
+       return 0;
+
+err_iommu_free:
+       iommu_domain_free(iommu_dom);
+err_unregister:
+       platform_device_unregister(pdev);
+       of_node_put(np);
+       return ret;
+}
+
+void venus_firmware_deinit(struct venus_core *core)
+{
+       struct iommu_domain *iommu;
+
+       if (!core->fw.dev)
+               return;
+
+       iommu = core->fw.iommu_domain;
+
+       iommu_detach_device(iommu, core->fw.dev);
+       iommu_domain_free(iommu);
+
+       platform_device_unregister(to_platform_device(core->fw.dev));
 }
index 428efb56d3391d14f66aa8938e691cc226e42868..119a9a4fc1a2b24ada3d05cf31c18dfa019d539b 100644 (file)
 
 struct device;
 
-int venus_boot(struct device *dev, const char *fwname);
-int venus_shutdown(struct device *dev);
+int venus_firmware_init(struct venus_core *core);
+void venus_firmware_deinit(struct venus_core *core);
+int venus_boot(struct venus_core *core);
+int venus_shutdown(struct venus_core *core);
+int venus_set_hw_state(struct venus_core *core, bool suspend);
+
+static inline int venus_set_hw_state_suspend(struct venus_core *core)
+{
+       return venus_set_hw_state(core, false);
+}
+
+static inline int venus_set_hw_state_resume(struct venus_core *core)
+{
+       return venus_set_hw_state(core, true);
+}
 
 #endif
index e8389d8d8c4817061fa88f9be0a11e04fb0f28be..87a441488e1569fea7b0670bedbc6b3ffb24aad7 100644 (file)
@@ -1215,7 +1215,7 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
        }
        case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
                /* not implemented on Venus 4xx */
-               break;
+               return -ENOTSUPP;
        default:
                return pkt_session_set_property_3xx(pkt, cookie, ptype, pdata);
        }
index 124085556b94bb63a20901de301ea94550f25ab5..5c1e5b4f767a374dc65081f60a72e35feb51140e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/interrupt.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
-#include <linux/qcom_scm.h>
 #include <linux/slab.h>
 
 #include "core.h"
@@ -27,6 +26,7 @@
 #include "hfi_msgs.h"
 #include "hfi_venus.h"
 #include "hfi_venus_io.h"
+#include "firmware.h"
 
 #define HFI_MASK_QHDR_TX_TYPE          0xff000000
 #define HFI_MASK_QHDR_RX_TYPE          0x00ff0000
 #define IFACEQ_VAR_LARGE_PKT_SIZE      512
 #define IFACEQ_VAR_HUGE_PKT_SIZE       (1024 * 12)
 
-enum tzbsp_video_state {
-       TZBSP_VIDEO_STATE_SUSPEND = 0,
-       TZBSP_VIDEO_STATE_RESUME
-};
-
 struct hfi_queue_table_header {
        u32 version;
        u32 size;
@@ -575,7 +570,7 @@ static int venus_power_off(struct venus_hfi_device *hdev)
        if (!hdev->power_enabled)
                return 0;
 
-       ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
+       ret = venus_set_hw_state_suspend(hdev->core);
        if (ret)
                return ret;
 
@@ -595,7 +590,7 @@ static int venus_power_on(struct venus_hfi_device *hdev)
        if (hdev->power_enabled)
                return 0;
 
-       ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0);
+       ret = venus_set_hw_state_resume(hdev->core);
        if (ret)
                goto err;
 
@@ -608,7 +603,7 @@ static int venus_power_on(struct venus_hfi_device *hdev)
        return 0;
 
 err_suspend:
-       qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
+       venus_set_hw_state_suspend(hdev->core);
 err:
        hdev->power_enabled = false;
        return ret;
@@ -1355,6 +1350,8 @@ static int venus_session_set_property(struct venus_inst *inst, u32 ptype,
        pkt = (struct hfi_session_set_property_pkt *)packet;
 
        ret = pkt_session_set_property(pkt, inst, ptype, pdata);
+       if (ret == -ENOTSUPP)
+               return 0;
        if (ret)
                return ret;
 
index def0926a6deecdd7717d7dfc0f7bf4a35e59f413..ef0c72a0c8929aa385d422a520cd2e8ddab6ee7b 100644 (file)
 #define WRAPPER_CPU_STATUS                     (WRAPPER_BASE + 0x2014)
 #define WRAPPER_CPU_STATUS_WFI                 BIT(0)
 #define WRAPPER_SW_RESET                       (WRAPPER_BASE + 0x3000)
+#define WRAPPER_CPA_START_ADDR                 (WRAPPER_BASE + 0x1020)
+#define WRAPPER_CPA_END_ADDR                   (WRAPPER_BASE + 0x1024)
+#define WRAPPER_FW_START_ADDR                  (WRAPPER_BASE + 0x1028)
+#define WRAPPER_FW_END_ADDR                    (WRAPPER_BASE + 0x102C)
+#define WRAPPER_NONPIX_START_ADDR              (WRAPPER_BASE + 0x1030)
+#define WRAPPER_NONPIX_END_ADDR                        (WRAPPER_BASE + 0x1034)
+#define WRAPPER_A9SS_SW_RESET                  (WRAPPER_BASE + 0x3000)
+#define WRAPPER_A9SS_SW_RESET_BIT              BIT(4)
 
 /* Venus 4xx */
 #define WRAPPER_VCODEC0_MMCC_POWER_STATUS      (WRAPPER_BASE + 0x90)
index 189ec975c6bbdbe69f66558b609ced0c25e31c45..282de21cf2e1e8bc2aff1608b4dbbe34410af7ec 100644 (file)
@@ -885,10 +885,8 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
        vbuf->field = V4L2_FIELD_NONE;
 
        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               unsigned int opb_sz = venus_helper_get_opb_size(inst);
-
                vb = &vbuf->vb2_buf;
-               vb2_set_plane_payload(vb, 0, bytesused ? : opb_sz);
+               vb2_set_plane_payload(vb, 0, bytesused);
                vb->planes[0].data_offset = data_offset;
                vb->timestamp = timestamp_us * NSEC_PER_USEC;
                vbuf->sequence = inst->sequence_cap++;
index ce85962b6adcc31597a6a95cda66d4b345fc8f85..32cff294582f9abee76cc22baa589cb87f136bb5 100644 (file)
@@ -651,6 +651,8 @@ static int venc_set_properties(struct venus_inst *inst)
        struct hfi_framerate frate;
        struct hfi_bitrate brate;
        struct hfi_idr_period idrp;
+       struct hfi_quantization quant;
+       struct hfi_quantization_range quant_range;
        u32 ptype, rate_control, bitrate, profile = 0, level = 0;
        int ret;
 
@@ -770,6 +772,23 @@ static int venc_set_properties(struct venus_inst *inst)
        if (ret)
                return ret;
 
+       ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP;
+       quant.qp_i = ctr->h264_i_qp;
+       quant.qp_p = ctr->h264_p_qp;
+       quant.qp_b = ctr->h264_b_qp;
+       quant.layer_id = 0;
+       ret = hfi_session_set_property(inst, ptype, &quant);
+       if (ret)
+               return ret;
+
+       ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+       quant_range.min_qp = ctr->h264_min_qp;
+       quant_range.max_qp = ctr->h264_max_qp;
+       quant_range.layer_id = 0;
+       ret = hfi_session_set_property(inst, ptype, &quant_range);
+       if (ret)
+               return ret;
+
        if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) {
                profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE,
                                           ctr->profile.h264);
@@ -1074,7 +1093,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
        int ret;
 
        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-       src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
        src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
        src_vq->ops = &venc_vb2_ops;
        src_vq->mem_ops = &vb2_dma_sg_memops;
@@ -1090,7 +1109,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
                return ret;
 
        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
        dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
        dst_vq->ops = &venc_vb2_ops;
        dst_vq->mem_ops = &vb2_dma_sg_memops;
index 459101728d26cd2fe7c4a824c922839eda743b3f..ac1e1d26f3416086cb5c11b1b4048e72d1a978c3 100644 (file)
@@ -79,7 +79,10 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct venus_inst *inst = ctrl_to_inst(ctrl);
        struct venc_controls *ctr = &inst->controls.enc;
+       struct hfi_enable en = { .enable = 1 };
+       struct hfi_bitrate brate;
        u32 bframes;
+       u32 ptype;
        int ret;
 
        switch (ctrl->id) {
@@ -88,6 +91,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        case V4L2_CID_MPEG_VIDEO_BITRATE:
                ctr->bitrate = ctrl->val;
+               mutex_lock(&inst->lock);
+               if (inst->streamon_out && inst->streamon_cap) {
+                       ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+                       brate.bitrate = ctr->bitrate;
+                       brate.layer_id = 0;
+
+                       ret = hfi_session_set_property(inst, ptype, &brate);
+                       if (ret) {
+                               mutex_unlock(&inst->lock);
+                               return ret;
+                       }
+               }
+               mutex_unlock(&inst->lock);
                break;
        case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
                ctr->bitrate_peak = ctrl->val;
@@ -173,6 +189,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
 
                ctr->num_b_frames = bframes;
                break;
+       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+               mutex_lock(&inst->lock);
+               if (inst->streamon_out && inst->streamon_cap) {
+                       ptype = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
+                       ret = hfi_session_set_property(inst, ptype, &en);
+
+                       if (ret) {
+                               mutex_unlock(&inst->lock);
+                               return ret;
+                       }
+               }
+               mutex_unlock(&inst->lock);
+               break;
        default:
                return -EINVAL;
        }
@@ -188,7 +217,7 @@ int venc_ctrl_init(struct venus_inst *inst)
 {
        int ret;
 
-       ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 27);
+       ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28);
        if (ret)
                return ret;
 
@@ -295,7 +324,7 @@ int venc_ctrl_init(struct venus_inst *inst)
                0, INTRA_REFRESH_MBS_MAX, 1, 0);
 
        v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 12);
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30);
 
        v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, 1, 128, 1, 1);
@@ -309,6 +338,9 @@ int venc_ctrl_init(struct venus_inst *inst)
        v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
                V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0, (1 << 16) - 1, 1, 0);
 
+       v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+                         V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0);
+
        ret = inst->ctrl_handler.error;
        if (ret)
                goto err;
index f476b2f1eb354781dc4dbd654b7ff549d3bc938d..f0719ce24b97a9f95b761f307be28878d9b17d5c 100644 (file)
@@ -1088,6 +1088,50 @@ static const struct rvin_info rcar_info_r8a77970 = {
        .routes = rcar_info_r8a77970_routes,
 };
 
+static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
+       { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
+       { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
+       { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
+       { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
+       { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
+       { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
+       { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
+       { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
+       { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
+       { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
+       { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
+       { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
+       { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
+       { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
+       { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
+       { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
+       { /* Sentinel */ }
+};
+
+static const struct rvin_info rcar_info_r8a77980 = {
+       .model = RCAR_GEN3,
+       .use_mc = true,
+       .max_width = 4096,
+       .max_height = 4096,
+       .routes = rcar_info_r8a77980_routes,
+};
+
+static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
+       { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
+       { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
+       { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
+       { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
+       { /* Sentinel */ }
+};
+
+static const struct rvin_info rcar_info_r8a77990 = {
+       .model = RCAR_GEN3,
+       .use_mc = true,
+       .max_width = 4096,
+       .max_height = 4096,
+       .routes = rcar_info_r8a77990_routes,
+};
+
 static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
        { /* Sentinel */ }
 };
@@ -1145,6 +1189,14 @@ static const struct of_device_id rvin_of_id_table[] = {
                .compatible = "renesas,vin-r8a77970",
                .data = &rcar_info_r8a77970,
        },
+       {
+               .compatible = "renesas,vin-r8a77980",
+               .data = &rcar_info_r8a77980,
+       },
+       {
+               .compatible = "renesas,vin-r8a77990",
+               .data = &rcar_info_r8a77990,
+       },
        {
                .compatible = "renesas,vin-r8a77995",
                .data = &rcar_info_r8a77995,
index b0044a08e71ed017a3c95c0a2d8d59234f22b865..6d356f5a9456c4e58d8741103a8b1c7592942f71 100644 (file)
@@ -152,37 +152,37 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
 };
 
 static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
-       { .mbps =   80, .reg = 0x00 },
-       { .mbps =   90, .reg = 0x20 },
-       { .mbps =  100, .reg = 0x40 },
-       { .mbps =  110, .reg = 0x02 },
-       { .mbps =  130, .reg = 0x22 },
-       { .mbps =  140, .reg = 0x42 },
-       { .mbps =  150, .reg = 0x04 },
-       { .mbps =  170, .reg = 0x24 },
-       { .mbps =  180, .reg = 0x44 },
-       { .mbps =  200, .reg = 0x06 },
-       { .mbps =  220, .reg = 0x26 },
-       { .mbps =  240, .reg = 0x46 },
-       { .mbps =  250, .reg = 0x08 },
-       { .mbps =  270, .reg = 0x28 },
-       { .mbps =  300, .reg = 0x0a },
-       { .mbps =  330, .reg = 0x2a },
-       { .mbps =  360, .reg = 0x4a },
-       { .mbps =  400, .reg = 0x0c },
-       { .mbps =  450, .reg = 0x2c },
-       { .mbps =  500, .reg = 0x0e },
-       { .mbps =  550, .reg = 0x2e },
-       { .mbps =  600, .reg = 0x10 },
-       { .mbps =  650, .reg = 0x30 },
-       { .mbps =  700, .reg = 0x12 },
-       { .mbps =  750, .reg = 0x32 },
-       { .mbps =  800, .reg = 0x52 },
-       { .mbps =  850, .reg = 0x72 },
-       { .mbps =  900, .reg = 0x14 },
-       { .mbps =  950, .reg = 0x34 },
-       { .mbps = 1000, .reg = 0x54 },
-       { .mbps = 1050, .reg = 0x74 },
+       { .mbps =   89, .reg = 0x00 },
+       { .mbps =   99, .reg = 0x20 },
+       { .mbps =  109, .reg = 0x40 },
+       { .mbps =  129, .reg = 0x02 },
+       { .mbps =  139, .reg = 0x22 },
+       { .mbps =  149, .reg = 0x42 },
+       { .mbps =  169, .reg = 0x04 },
+       { .mbps =  179, .reg = 0x24 },
+       { .mbps =  199, .reg = 0x44 },
+       { .mbps =  219, .reg = 0x06 },
+       { .mbps =  239, .reg = 0x26 },
+       { .mbps =  249, .reg = 0x46 },
+       { .mbps =  269, .reg = 0x08 },
+       { .mbps =  299, .reg = 0x28 },
+       { .mbps =  329, .reg = 0x0a },
+       { .mbps =  359, .reg = 0x2a },
+       { .mbps =  399, .reg = 0x4a },
+       { .mbps =  449, .reg = 0x0c },
+       { .mbps =  499, .reg = 0x2c },
+       { .mbps =  549, .reg = 0x0e },
+       { .mbps =  599, .reg = 0x2e },
+       { .mbps =  649, .reg = 0x10 },
+       { .mbps =  699, .reg = 0x30 },
+       { .mbps =  749, .reg = 0x12 },
+       { .mbps =  799, .reg = 0x32 },
+       { .mbps =  849, .reg = 0x52 },
+       { .mbps =  899, .reg = 0x72 },
+       { .mbps =  949, .reg = 0x14 },
+       { .mbps =  999, .reg = 0x34 },
+       { .mbps = 1049, .reg = 0x54 },
+       { .mbps = 1099, .reg = 0x74 },
        { .mbps = 1125, .reg = 0x16 },
        { /* sentinel */ },
 };
@@ -342,6 +342,7 @@ struct rcar_csi2_info {
        int (*confirm_start)(struct rcar_csi2 *priv);
        const struct rcsi2_mbps_reg *hsfreqrange;
        unsigned int csi0clkfreqrange;
+       unsigned int num_channels;
        bool clear_ulps;
 };
 
@@ -476,13 +477,14 @@ static int rcsi2_start(struct rcar_csi2 *priv)
        format = rcsi2_code_to_fmt(priv->mf.code);
 
        /*
-        * Enable all Virtual Channels.
+        * Enable all supported CSI-2 channels with virtual channel and
+        * data type matching.
         *
         * NOTE: It's not possible to get individual datatype for each
         *       source virtual channel. Once this is possible in V4L2
         *       it should be used here.
         */
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < priv->info->num_channels; i++) {
                u32 vcdt_part;
 
                vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
@@ -511,7 +513,8 @@ static int rcsi2_start(struct rcar_csi2 *priv)
        rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 |
                    FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN);
        rcsi2_write(priv, VCDT_REG, vcdt);
-       rcsi2_write(priv, VCDT2_REG, vcdt2);
+       if (vcdt2)
+               rcsi2_write(priv, VCDT2_REG, vcdt2);
        /* Lanes are zero indexed. */
        rcsi2_write(priv, LSWAP_REG,
                    LSWAP_L0SEL(priv->lane_swap[0] - 1) |
@@ -940,27 +943,45 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
        .init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
        .hsfreqrange = hsfreqrange_h3_v3h_m3n,
        .csi0clkfreqrange = 0x20,
+       .num_channels = 4,
        .clear_ulps = true,
 };
 
 static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = {
        .hsfreqrange = hsfreqrange_m3w_h3es1,
+       .num_channels = 4,
 };
 
 static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
        .hsfreqrange = hsfreqrange_m3w_h3es1,
+       .num_channels = 4,
 };
 
 static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
        .init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
        .hsfreqrange = hsfreqrange_h3_v3h_m3n,
        .csi0clkfreqrange = 0x20,
+       .num_channels = 4,
        .clear_ulps = true,
 };
 
 static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
        .init_phtw = rcsi2_init_phtw_v3m_e3,
        .confirm_start = rcsi2_confirm_start_v3m_e3,
+       .num_channels = 4,
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
+       .init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
+       .hsfreqrange = hsfreqrange_h3_v3h_m3n,
+       .csi0clkfreqrange = 0x20,
+       .clear_ulps = true,
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
+       .init_phtw = rcsi2_init_phtw_v3m_e3,
+       .confirm_start = rcsi2_confirm_start_v3m_e3,
+       .num_channels = 2,
 };
 
 static const struct of_device_id rcar_csi2_of_table[] = {
@@ -980,6 +1001,14 @@ static const struct of_device_id rcar_csi2_of_table[] = {
                .compatible = "renesas,r8a77970-csi2",
                .data = &rcar_csi2_info_r8a77970,
        },
+       {
+               .compatible = "renesas,r8a77980-csi2",
+               .data = &rcar_csi2_info_r8a77980,
+       },
+       {
+               .compatible = "renesas,r8a77990-csi2",
+               .data = &rcar_csi2_info_r8a77990,
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
index dc77682b47857c97b820f17008dbe5f1b9115e26..7a2851790b91ce73636faeb91b2ea91dc89c31a2 100644 (file)
@@ -404,16 +404,16 @@ static int rvin_s_selection(struct file *file, void *fh,
        return 0;
 }
 
-static int rvin_cropcap(struct file *file, void *priv,
-                       struct v4l2_cropcap *crop)
+static int rvin_g_pixelaspect(struct file *file, void *priv,
+                             int type, struct v4l2_fract *f)
 {
        struct rvin_dev *vin = video_drvdata(file);
        struct v4l2_subdev *sd = vin_to_source(vin);
 
-       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       return v4l2_subdev_call(sd, video, g_pixelaspect, &crop->pixelaspect);
+       return v4l2_subdev_call(sd, video, g_pixelaspect, f);
 }
 
 static int rvin_enum_input(struct file *file, void *priv,
@@ -620,7 +620,7 @@ static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
        .vidioc_g_selection             = rvin_g_selection,
        .vidioc_s_selection             = rvin_s_selection,
 
-       .vidioc_cropcap                 = rvin_cropcap,
+       .vidioc_g_pixelaspect           = rvin_g_pixelaspect,
 
        .vidioc_enum_input              = rvin_enum_input,
        .vidioc_g_input                 = rvin_g_input,
index 9cc9db0838702f535cffc91269430e35002862b8..5c653287185fdf2a8835ed8f98f61535ba173453 100644 (file)
@@ -97,7 +97,7 @@ static irqreturn_t rga_isr(int irq, void *prv)
        return IRQ_HANDLED;
 }
 
-static struct v4l2_m2m_ops rga_m2m_ops = {
+static const struct v4l2_m2m_ops rga_m2m_ops = {
        .device_run = device_run,
 };
 
@@ -700,7 +700,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
        .vidioc_s_selection = vidioc_s_selection,
 };
 
-static struct video_device rga_videodev = {
+static const struct video_device rga_videodev = {
        .name = "rockchip-rga",
        .fops = &rga_fops,
        .ioctl_ops = &rga_ioctl_ops,
index e901201b6fcc57849f544b1e1f89069935b5f918..57ab1d1085d1fddd8564df35038f00aa597be48d 100644 (file)
@@ -89,7 +89,7 @@ static struct g2d_fmt *find_fmt(struct v4l2_format *f)
 
 
 static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
-                                                       enum v4l2_buf_type type)
+                                  enum v4l2_buf_type type)
 {
        switch (type) {
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -408,51 +408,76 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
        return 0;
 }
 
-static int vidioc_cropcap(struct file *file, void *priv,
-                                       struct v4l2_cropcap *cr)
-{
-       struct g2d_ctx *ctx = priv;
-       struct g2d_frame *f;
-
-       f = get_frame(ctx, cr->type);
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-
-       cr->bounds.left         = 0;
-       cr->bounds.top          = 0;
-       cr->bounds.width        = f->width;
-       cr->bounds.height       = f->height;
-       cr->defrect             = cr->bounds;
-       return 0;
-}
-
-static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+static int vidioc_g_selection(struct file *file, void *prv,
+                             struct v4l2_selection *s)
 {
        struct g2d_ctx *ctx = prv;
        struct g2d_frame *f;
 
-       f = get_frame(ctx, cr->type);
+       f = get_frame(ctx, s->type);
        if (IS_ERR(f))
                return PTR_ERR(f);
 
-       cr->c.left      = f->o_height;
-       cr->c.top       = f->o_width;
-       cr->c.width     = f->c_width;
-       cr->c.height    = f->c_height;
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       return -EINVAL;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_COMPOSE:
+               s->r.left = f->o_height;
+               s->r.top = f->o_width;
+               s->r.width = f->c_width;
+               s->r.height = f->c_height;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = f->width;
+               s->r.height = f->height;
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
 
-static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
+static int vidioc_try_selection(struct file *file, void *prv,
+                               const struct v4l2_selection *s)
 {
        struct g2d_ctx *ctx = prv;
        struct g2d_dev *dev = ctx->dev;
        struct g2d_frame *f;
 
-       f = get_frame(ctx, cr->type);
+       f = get_frame(ctx, s->type);
        if (IS_ERR(f))
                return PTR_ERR(f);
 
-       if (cr->c.top < 0 || cr->c.left < 0) {
+       if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (s->target != V4L2_SEL_TGT_COMPOSE)
+                       return -EINVAL;
+       } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               if (s->target != V4L2_SEL_TGT_CROP)
+                       return -EINVAL;
+       }
+
+       if (s->r.top < 0 || s->r.left < 0) {
                v4l2_err(&dev->v4l2_dev,
                        "doesn't support negative values for top & left\n");
                return -EINVAL;
@@ -461,23 +486,24 @@ static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop
        return 0;
 }
 
-static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
+static int vidioc_s_selection(struct file *file, void *prv,
+                             struct v4l2_selection *s)
 {
        struct g2d_ctx *ctx = prv;
        struct g2d_frame *f;
        int ret;
 
-       ret = vidioc_try_crop(file, prv, cr);
+       ret = vidioc_try_selection(file, prv, s);
        if (ret)
                return ret;
-       f = get_frame(ctx, cr->type);
+       f = get_frame(ctx, s->type);
        if (IS_ERR(f))
                return PTR_ERR(f);
 
-       f->c_width      = cr->c.width;
-       f->c_height     = cr->c.height;
-       f->o_width      = cr->c.left;
-       f->o_height     = cr->c.top;
+       f->c_width      = s->r.width;
+       f->c_height     = s->r.height;
+       f->o_width      = s->r.left;
+       f->o_height     = s->r.top;
        f->bottom       = f->o_height + f->c_height;
        f->right        = f->o_width + f->c_width;
        return 0;
@@ -585,9 +611,8 @@ static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
        .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
        .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
 
-       .vidioc_g_crop                  = vidioc_g_crop,
-       .vidioc_s_crop                  = vidioc_s_crop,
-       .vidioc_cropcap                 = vidioc_cropcap,
+       .vidioc_g_selection             = vidioc_g_selection,
+       .vidioc_s_selection             = vidioc_s_selection,
 };
 
 static const struct video_device g2d_videodev = {
@@ -680,6 +705,7 @@ static int g2d_probe(struct platform_device *pdev)
                goto unreg_v4l2_dev;
        }
        *vfd = g2d_videodev;
+       set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
        vfd->lock = &dev->mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
index 927a1235408de47ca854ce895b7f64211414ae28..8a5ba3bec3af2f82d2e27fd8fe99495dbf0333a2 100644 (file)
@@ -1342,6 +1342,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        vfd->lock       = &dev->mfc_mutex;
        vfd->v4l2_dev   = &dev->v4l2_dev;
        vfd->vfl_dir    = VFL_DIR_M2M;
+       set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
        snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
        dev->vfd_dec    = vfd;
        video_set_drvdata(vfd, dev);
index ece59ce1b1499f3ee7e9bdca14f33d4f7ce430c8..f4c0e3a8f27d3427680e7de16b6fa4af20b476d7 100644 (file)
@@ -773,19 +773,23 @@ static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
        .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
 };
 
-/* Get cropping information */
-static int vidioc_g_crop(struct file *file, void *priv,
-               struct v4l2_crop *cr)
+/* Get compose information */
+static int vidioc_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *s)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        struct s5p_mfc_dev *dev = ctx->dev;
        u32 left, right, top, bottom;
+       u32 width, height;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
        if (ctx->state != MFCINST_HEAD_PARSED &&
            ctx->state != MFCINST_RUNNING &&
            ctx->state != MFCINST_FINISHING &&
            ctx->state != MFCINST_FINISHED) {
-               mfc_err("Can not get crop information\n");
+               mfc_err("Can not get compose information\n");
                return -EINVAL;
        }
        if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
@@ -795,22 +799,33 @@ static int vidioc_g_crop(struct file *file, void *priv,
                top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx);
                bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
                top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
-               cr->c.left = left;
-               cr->c.top = top;
-               cr->c.width = ctx->img_width - left - right;
-               cr->c.height = ctx->img_height - top - bottom;
-               mfc_debug(2, "Cropping info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n",
-                         left, top, cr->c.width, cr->c.height, right, bottom,
+               width = ctx->img_width - left - right;
+               height = ctx->img_height - top - bottom;
+               mfc_debug(2, "Composing info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n",
+                         left, top, s->r.width, s->r.height, right, bottom,
                          ctx->buf_width, ctx->buf_height);
        } else {
-               cr->c.left = 0;
-               cr->c.top = 0;
-               cr->c.width = ctx->img_width;
-               cr->c.height = ctx->img_height;
-               mfc_debug(2, "Cropping info: w=%d h=%d fw=%d fh=%d\n",
-                         cr->c.width,  cr->c.height, ctx->buf_width,
+               left = 0;
+               top = 0;
+               width = ctx->img_width;
+               height = ctx->img_height;
+               mfc_debug(2, "Composing info: w=%d h=%d fw=%d fh=%d\n",
+                         s->r.width, s->r.height, ctx->buf_width,
                          ctx->buf_height);
        }
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               s->r.left = left;
+               s->r.top = top;
+               s->r.width = width;
+               s->r.height = height;
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -887,7 +902,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
        .vidioc_expbuf = vidioc_expbuf,
        .vidioc_streamon = vidioc_streamon,
        .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_g_crop = vidioc_g_crop,
+       .vidioc_g_selection = vidioc_g_selection,
        .vidioc_decoder_cmd = vidioc_decoder_cmd,
        .vidioc_subscribe_event = vidioc_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
diff --git a/drivers/media/platform/seco-cec/Makefile b/drivers/media/platform/seco-cec/Makefile
new file mode 100644 (file)
index 0000000..a3f2c6b
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_SECO_CEC) += seco-cec.o
diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c
new file mode 100644 (file)
index 0000000..a425a10
--- /dev/null
@@ -0,0 +1,796 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * CEC driver for SECO X86 Boards
+ *
+ * Author:  Ettore Chimenti <ek5.chimenti@gmail.com>
+ * Copyright (C) 2018, SECO SpA.
+ * Copyright (C) 2018, Aidilab Srl.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* CEC Framework */
+#include <media/cec.h>
+
+#include "seco-cec.h"
+
+struct secocec_data {
+       struct device *dev;
+       struct platform_device *pdev;
+       struct cec_adapter *cec_adap;
+       struct cec_notifier *notifier;
+       struct rc_dev *ir;
+       char ir_input_phys[32];
+       int irq;
+};
+
+#define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
+                                            cmd, data, SMBUS_WRITE, NULL)
+#define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
+                                      cmd, 0, SMBUS_READ, res)
+
+static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
+                      u8 operation, u16 *result)
+{
+       unsigned int count;
+       short _data_format;
+       int status = 0;
+
+       switch (data_format) {
+       case CMD_BYTE_DATA:
+               _data_format = BRA_SMB_CMD_BYTE_DATA;
+               break;
+       case CMD_WORD_DATA:
+               _data_format = BRA_SMB_CMD_WORD_DATA;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Active wait until ready */
+       for (count = 0; count <= SMBTIMEOUT; ++count) {
+               if (!(inb(HSTS) & BRA_INUSE_STS))
+                       break;
+               udelay(SMB_POLL_UDELAY);
+       }
+
+       if (count > SMBTIMEOUT)
+               /* Reset the lock instead of failing */
+               outb(0xff, HSTS);
+
+       outb(0x00, HCNT);
+       outb((u8)(slave_addr & 0xfe) | operation, XMIT_SLVA);
+       outb(cmd, HCMD);
+       inb(HCNT);
+
+       if (operation == SMBUS_WRITE) {
+               outb((u8)data, HDAT0);
+               outb((u8)(data >> 8), HDAT1);
+       }
+
+       outb(BRA_START + _data_format, HCNT);
+
+       for (count = 0; count <= SMBTIMEOUT; count++) {
+               if (!(inb(HSTS) & BRA_HOST_BUSY))
+                       break;
+               udelay(SMB_POLL_UDELAY);
+       }
+
+       if (count > SMBTIMEOUT) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       if (inb(HSTS) & BRA_HSTS_ERR_MASK) {
+               status = -EIO;
+               goto err;
+       }
+
+       if (operation == SMBUS_READ)
+               *result = ((inb(HDAT0) & 0xff) + ((inb(HDAT1) & 0xff) << 8));
+
+err:
+       outb(0xff, HSTS);
+       return status;
+}
+
+static int secocec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+       struct secocec_data *cec = cec_get_drvdata(adap);
+       struct device *dev = cec->dev;
+       u16 val = 0;
+       int status;
+
+       if (enable) {
+               /* Clear the status register */
+               status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
+               if (status)
+                       goto err;
+
+               status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+               if (status)
+                       goto err;
+
+               /* Enable the interrupts */
+               status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+               if (status)
+                       goto err;
+
+               status = smb_wr16(SECOCEC_ENABLE_REG_1,
+                                 val | SECOCEC_ENABLE_REG_1_CEC);
+               if (status)
+                       goto err;
+
+               dev_dbg(dev, "Device enabled");
+       } else {
+               /* Clear the status register */
+               status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
+               status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+
+               /* Disable the interrupts */
+               status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+               status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
+                                 ~SECOCEC_ENABLE_REG_1_CEC &
+                                 ~SECOCEC_ENABLE_REG_1_IR);
+
+               dev_dbg(dev, "Device disabled");
+       }
+
+       return 0;
+err:
+       return status;
+}
+
+static int secocec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+       u16 enable_val = 0;
+       int status;
+
+       /* Disable device */
+       status = smb_rd16(SECOCEC_ENABLE_REG_1, &enable_val);
+       if (status)
+               return status;
+
+       status = smb_wr16(SECOCEC_ENABLE_REG_1,
+                         enable_val & ~SECOCEC_ENABLE_REG_1_CEC);
+       if (status)
+               return status;
+
+       /* Write logical address
+        * NOTE: CEC_LOG_ADDR_INVALID is mapped to the 'Unregistered' LA
+        */
+       status = smb_wr16(SECOCEC_DEVICE_LA, logical_addr & 0xf);
+       if (status)
+               return status;
+
+       /* Re-enable device */
+       status = smb_wr16(SECOCEC_ENABLE_REG_1,
+                         enable_val | SECOCEC_ENABLE_REG_1_CEC);
+       if (status)
+               return status;
+
+       return 0;
+}
+
+static int secocec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+                                u32 signal_free_time, struct cec_msg *msg)
+{
+       u16 payload_len, payload_id_len, destination, val = 0;
+       u8 *payload_msg;
+       int status;
+       u8 i;
+
+       /* Device msg len already accounts for header */
+       payload_id_len = msg->len - 1;
+
+       /* Send data length */
+       status = smb_wr16(SECOCEC_WRITE_DATA_LENGTH, payload_id_len);
+       if (status)
+               goto err;
+
+       /* Send Operation ID if present */
+       if (payload_id_len > 0) {
+               status = smb_wr16(SECOCEC_WRITE_OPERATION_ID, msg->msg[1]);
+               if (status)
+                       goto err;
+       }
+       /* Send data if present */
+       if (payload_id_len > 1) {
+               /* Only data; */
+               payload_len = msg->len - 2;
+               payload_msg = &msg->msg[2];
+
+               /* Copy message into registers */
+               for (i = 0; i < payload_len; i += 2) {
+                       /* hi byte */
+                       val = payload_msg[i + 1] << 8;
+
+                       /* lo byte */
+                       val |= payload_msg[i];
+
+                       status = smb_wr16(SECOCEC_WRITE_DATA_00 + i / 2, val);
+                       if (status)
+                               goto err;
+               }
+       }
+       /* Send msg source/destination and fire msg */
+       destination = msg->msg[0];
+       status = smb_wr16(SECOCEC_WRITE_BYTE0, destination);
+       if (status)
+               goto err;
+
+       return 0;
+
+err:
+       return status;
+}
+
+static void secocec_tx_done(struct cec_adapter *adap, u16 status_val)
+{
+       if (status_val & SECOCEC_STATUS_TX_ERROR_MASK) {
+               if (status_val & SECOCEC_STATUS_TX_NACK_ERROR)
+                       cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK);
+               else
+                       cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR);
+       } else {
+               cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK);
+       }
+
+       /* Reset status reg */
+       status_val = SECOCEC_STATUS_TX_ERROR_MASK |
+               SECOCEC_STATUS_MSG_SENT_MASK |
+               SECOCEC_STATUS_TX_NACK_ERROR;
+       smb_wr16(SECOCEC_STATUS, status_val);
+}
+
+static void secocec_rx_done(struct cec_adapter *adap, u16 status_val)
+{
+       struct secocec_data *cec = cec_get_drvdata(adap);
+       struct device *dev = cec->dev;
+       struct cec_msg msg = { };
+       bool flag_overflow = false;
+       u8 payload_len, i = 0;
+       u8 *payload_msg;
+       u16 val = 0;
+       int status;
+
+       if (status_val & SECOCEC_STATUS_RX_OVERFLOW_MASK) {
+               /* NOTE: Untested, it also might not be necessary */
+               dev_warn(dev, "Received more than 16 bytes. Discarding");
+               flag_overflow = true;
+       }
+
+       if (status_val & SECOCEC_STATUS_RX_ERROR_MASK) {
+               dev_warn(dev, "Message received with errors. Discarding");
+               status = -EIO;
+               goto rxerr;
+       }
+
+       /* Read message length */
+       status = smb_rd16(SECOCEC_READ_DATA_LENGTH, &val);
+       if (status)
+               return;
+
+       /* Device msg len already accounts for the header */
+       msg.len = min(val + 1, CEC_MAX_MSG_SIZE);
+
+       /* Read logical address */
+       status = smb_rd16(SECOCEC_READ_BYTE0, &val);
+       if (status)
+               return;
+
+       /* device stores source LA and destination */
+       msg.msg[0] = val;
+
+       /* Read operation ID */
+       status = smb_rd16(SECOCEC_READ_OPERATION_ID, &val);
+       if (status)
+               return;
+
+       msg.msg[1] = val;
+
+       /* Read data if present */
+       if (msg.len > 1) {
+               payload_len = msg.len - 2;
+               payload_msg = &msg.msg[2];
+
+               /* device stores 2 bytes in every 16-bit val */
+               for (i = 0; i < payload_len; i += 2) {
+                       status = smb_rd16(SECOCEC_READ_DATA_00 + i / 2, &val);
+                       if (status)
+                               return;
+
+                       /* low byte, skipping header */
+                       payload_msg[i] = val & 0x00ff;
+
+                       /* hi byte */
+                       payload_msg[i + 1] = (val & 0xff00) >> 8;
+               }
+       }
+
+       cec_received_msg(cec->cec_adap, &msg);
+
+       /* Reset status reg */
+       status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK;
+       if (flag_overflow)
+               status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
+
+       status = smb_wr16(SECOCEC_STATUS, status_val);
+
+       return;
+
+rxerr:
+       /* Reset error reg */
+       status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK |
+               SECOCEC_STATUS_RX_ERROR_MASK;
+       if (flag_overflow)
+               status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
+       smb_wr16(SECOCEC_STATUS, status_val);
+}
+
+static const struct cec_adap_ops secocec_cec_adap_ops = {
+       /* Low-level callbacks */
+       .adap_enable = secocec_adap_enable,
+       .adap_log_addr = secocec_adap_log_addr,
+       .adap_transmit = secocec_adap_transmit,
+};
+
+#ifdef CONFIG_VIDEO_SECO_RC
+static int secocec_ir_probe(void *priv)
+{
+       struct secocec_data *cec = priv;
+       struct device *dev = cec->dev;
+       int status;
+       u16 val;
+
+       /* Prepare the RC input device */
+       cec->ir = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
+       if (!cec->ir)
+               return -ENOMEM;
+
+       snprintf(cec->ir_input_phys, sizeof(cec->ir_input_phys),
+                "%s/input0", dev_name(dev));
+
+       cec->ir->device_name = dev_name(dev);
+       cec->ir->input_phys = cec->ir_input_phys;
+       cec->ir->input_id.bustype = BUS_HOST;
+       cec->ir->input_id.vendor = 0;
+       cec->ir->input_id.product = 0;
+       cec->ir->input_id.version = 1;
+       cec->ir->driver_name = SECOCEC_DEV_NAME;
+       cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
+       cec->ir->priv = cec;
+       cec->ir->map_name = RC_MAP_HAUPPAUGE;
+       cec->ir->timeout = MS_TO_NS(100);
+
+       /* Clear the status register */
+       status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
+       if (status != 0)
+               goto err;
+
+       status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+       if (status != 0)
+               goto err;
+
+       /* Enable the interrupts */
+       status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+       if (status != 0)
+               goto err;
+
+       status = smb_wr16(SECOCEC_ENABLE_REG_1,
+                         val | SECOCEC_ENABLE_REG_1_IR);
+       if (status != 0)
+               goto err;
+
+       dev_dbg(dev, "IR enabled");
+
+       status = devm_rc_register_device(dev, cec->ir);
+
+       if (status) {
+               dev_err(dev, "Failed to prepare input device");
+               cec->ir = NULL;
+               goto err;
+       }
+
+       return 0;
+
+err:
+       smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+
+       smb_wr16(SECOCEC_ENABLE_REG_1,
+                val & ~SECOCEC_ENABLE_REG_1_IR);
+
+       dev_dbg(dev, "IR disabled");
+       return status;
+}
+
+static int secocec_ir_rx(struct secocec_data *priv)
+{
+       struct secocec_data *cec = priv;
+       struct device *dev = cec->dev;
+       u16 val, status, key, addr, toggle;
+
+       if (!cec->ir)
+               return -ENODEV;
+
+       status = smb_rd16(SECOCEC_IR_READ_DATA, &val);
+       if (status != 0)
+               goto err;
+
+       key = val & SECOCEC_IR_COMMAND_MASK;
+       addr = (val & SECOCEC_IR_ADDRESS_MASK) >> SECOCEC_IR_ADDRESS_SHL;
+       toggle = (val & SECOCEC_IR_TOGGLE_MASK) >> SECOCEC_IR_TOGGLE_SHL;
+
+       rc_keydown(cec->ir, RC_PROTO_RC5, RC_SCANCODE_RC5(addr, key), toggle);
+
+       dev_dbg(dev, "IR key pressed: 0x%02x addr 0x%02x toggle 0x%02x", key,
+               addr, toggle);
+
+       return 0;
+
+err:
+       dev_err(dev, "IR Receive message failed (%d)", status);
+       return -EIO;
+}
+#else
+static void secocec_ir_rx(struct secocec_data *priv)
+{
+}
+
+static int secocec_ir_probe(void *priv)
+{
+       return 0;
+}
+#endif
+
+static irqreturn_t secocec_irq_handler(int irq, void *priv)
+{
+       struct secocec_data *cec = priv;
+       struct device *dev = cec->dev;
+       u16 status_val, cec_val, val = 0;
+       int status;
+
+       /*  Read status register */
+       status = smb_rd16(SECOCEC_STATUS_REG_1, &status_val);
+       if (status)
+               goto err;
+
+       if (status_val & SECOCEC_STATUS_REG_1_CEC) {
+               /* Read CEC status register */
+               status = smb_rd16(SECOCEC_STATUS, &cec_val);
+               if (status)
+                       goto err;
+
+               if (cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK)
+                       secocec_rx_done(cec->cec_adap, cec_val);
+
+               if (cec_val & SECOCEC_STATUS_MSG_SENT_MASK)
+                       secocec_tx_done(cec->cec_adap, cec_val);
+
+               if ((~cec_val & SECOCEC_STATUS_MSG_SENT_MASK) &&
+                   (~cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK))
+                       dev_warn_once(dev,
+                                     "Message not received or sent, but interrupt fired");
+
+               val = SECOCEC_STATUS_REG_1_CEC;
+       }
+
+       if (status_val & SECOCEC_STATUS_REG_1_IR) {
+               val |= SECOCEC_STATUS_REG_1_IR;
+
+               secocec_ir_rx(cec);
+       }
+
+       /*  Reset status register */
+       status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+       if (status)
+               goto err;
+
+       return IRQ_HANDLED;
+
+err:
+       dev_err_once(dev, "IRQ: R/W SMBus operation failed (%d)", status);
+
+       /*  Reset status register */
+       val = SECOCEC_STATUS_REG_1_CEC | SECOCEC_STATUS_REG_1_IR;
+       smb_wr16(SECOCEC_STATUS_REG_1, val);
+
+       return IRQ_HANDLED;
+}
+
+struct cec_dmi_match {
+       char *sys_vendor;
+       char *product_name;
+       char *devname;
+       char *conn;
+};
+
+static const struct cec_dmi_match secocec_dmi_match_table[] = {
+       /* UDOO X86 */
+       { "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
+};
+
+static int secocec_cec_get_notifier(struct cec_notifier **notify)
+{
+       int i;
+
+       for (i = 0 ; i < ARRAY_SIZE(secocec_dmi_match_table) ; ++i) {
+               const struct cec_dmi_match *m = &secocec_dmi_match_table[i];
+
+               if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
+                   dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
+                       struct device *d;
+
+                       /* Find the device, bail out if not yet registered */
+                       d = bus_find_device_by_name(&pci_bus_type, NULL,
+                                                   m->devname);
+                       if (!d)
+                               return -EPROBE_DEFER;
+
+                       *notify = cec_notifier_get_conn(d, m->conn);
+
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int secocec_acpi_probe(struct secocec_data *sdev)
+{
+       struct device *dev = sdev->dev;
+       struct gpio_desc *gpio;
+       int irq = 0;
+
+       gpio = devm_gpiod_get(dev, NULL, GPIOF_IN);
+       if (IS_ERR(gpio)) {
+               dev_err(dev, "Cannot request interrupt gpio");
+               return PTR_ERR(gpio);
+       }
+
+       irq = gpiod_to_irq(gpio);
+       if (irq < 0) {
+               dev_err(dev, "Cannot find valid irq");
+               return -ENODEV;
+       }
+       dev_dbg(dev, "irq-gpio is bound to IRQ %d", irq);
+
+       sdev->irq = irq;
+
+       return 0;
+}
+
+static int secocec_probe(struct platform_device *pdev)
+{
+       struct secocec_data *secocec;
+       struct device *dev = &pdev->dev;
+       int ret;
+       u16 val;
+
+       secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL);
+       if (!secocec)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, secocec);
+
+       /* Request SMBus regions */
+       if (!request_muxed_region(BRA_SMB_BASE_ADDR, 7, "CEC00001")) {
+               dev_err(dev, "Request memory region failed");
+               return -ENXIO;
+       }
+
+       secocec->pdev = pdev;
+       secocec->dev = dev;
+
+       if (!has_acpi_companion(dev)) {
+               dev_dbg(dev, "Cannot find any ACPI companion");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = secocec_acpi_probe(secocec);
+       if (ret) {
+               dev_err(dev, "Cannot assign gpio to IRQ");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* Firmware version check */
+       ret = smb_rd16(SECOCEC_VERSION, &val);
+       if (ret) {
+               dev_err(dev, "Cannot check fw version");
+               goto err;
+       }
+       if (val < SECOCEC_LATEST_FW) {
+               dev_err(dev, "CEC Firmware not supported (v.%04x). Use ver > v.%04x",
+                       val, SECOCEC_LATEST_FW);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = secocec_cec_get_notifier(&secocec->notifier);
+       if (ret) {
+               dev_err(dev, "no CEC notifier available\n");
+               goto err;
+       }
+
+       ret = devm_request_threaded_irq(dev,
+                                       secocec->irq,
+                                       NULL,
+                                       secocec_irq_handler,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), secocec);
+
+       if (ret) {
+               dev_err(dev, "Cannot request IRQ %d", secocec->irq);
+               ret = -EIO;
+               goto err;
+       }
+
+       /* Allocate CEC adapter */
+       secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops,
+                                                secocec,
+                                                dev_name(dev),
+                                                CEC_CAP_DEFAULTS,
+                                                SECOCEC_MAX_ADDRS);
+
+       if (IS_ERR(secocec->cec_adap)) {
+               ret = PTR_ERR(secocec->cec_adap);
+               goto err;
+       }
+
+       ret = cec_register_adapter(secocec->cec_adap, dev);
+       if (ret)
+               goto err_delete_adapter;
+
+       if (secocec->notifier)
+               cec_register_cec_notifier(secocec->cec_adap, secocec->notifier);
+
+       ret = secocec_ir_probe(secocec);
+       if (ret)
+               goto err_delete_adapter;
+
+       platform_set_drvdata(pdev, secocec);
+
+       dev_dbg(dev, "Device registered");
+
+       return ret;
+
+err_delete_adapter:
+       cec_delete_adapter(secocec->cec_adap);
+err:
+       dev_err(dev, "%s device probe failed\n", dev_name(dev));
+
+       return ret;
+}
+
+static int secocec_remove(struct platform_device *pdev)
+{
+       struct secocec_data *secocec = platform_get_drvdata(pdev);
+       u16 val;
+
+       if (secocec->ir) {
+               smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+
+               smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR);
+
+               dev_dbg(&pdev->dev, "IR disabled");
+       }
+       cec_unregister_adapter(secocec->cec_adap);
+
+       if (secocec->notifier)
+               cec_notifier_put(secocec->notifier);
+
+       release_region(BRA_SMB_BASE_ADDR, 7);
+
+       dev_dbg(&pdev->dev, "CEC device removed");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int secocec_suspend(struct device *dev)
+{
+       int status;
+       u16 val;
+
+       dev_dbg(dev, "Device going to suspend, disabling");
+
+       /* Clear the status register */
+       status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
+       if (status)
+               goto err;
+
+       status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+       if (status)
+               goto err;
+
+       /* Disable the interrupts */
+       status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+       if (status)
+               goto err;
+
+       status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
+                         ~SECOCEC_ENABLE_REG_1_CEC & ~SECOCEC_ENABLE_REG_1_IR);
+       if (status)
+               goto err;
+
+       return 0;
+
+err:
+       dev_err(dev, "Suspend failed (err: %d)", status);
+       return status;
+}
+
+static int secocec_resume(struct device *dev)
+{
+       int status;
+       u16 val;
+
+       dev_dbg(dev, "Resuming device from suspend");
+
+       /* Clear the status register */
+       status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
+       if (status)
+               goto err;
+
+       status = smb_wr16(SECOCEC_STATUS_REG_1, val);
+       if (status)
+               goto err;
+
+       /* Enable the interrupts */
+       status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
+       if (status)
+               goto err;
+
+       status = smb_wr16(SECOCEC_ENABLE_REG_1, val | SECOCEC_ENABLE_REG_1_CEC);
+       if (status)
+               goto err;
+
+       dev_dbg(dev, "Device resumed from suspend");
+
+       return 0;
+
+err:
+       dev_err(dev, "Resume failed (err: %d)", status);
+       return status;
+}
+
+static SIMPLE_DEV_PM_OPS(secocec_pm_ops, secocec_suspend, secocec_resume);
+#define SECOCEC_PM_OPS (&secocec_pm_ops)
+#else
+#define SECOCEC_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id secocec_acpi_match[] = {
+       {"CEC00001", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
+#endif
+
+static struct platform_driver secocec_driver = {
+       .driver = {
+                  .name = SECOCEC_DEV_NAME,
+                  .acpi_match_table = ACPI_PTR(secocec_acpi_match),
+                  .pm = SECOCEC_PM_OPS,
+       },
+       .probe = secocec_probe,
+       .remove = secocec_remove,
+};
+
+module_platform_driver(secocec_driver);
+
+MODULE_DESCRIPTION("SECO CEC X86 Driver");
+MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/seco-cec/seco-cec.h b/drivers/media/platform/seco-cec/seco-cec.h
new file mode 100644 (file)
index 0000000..e632c4a
--- /dev/null
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * SECO X86 Boards CEC register defines
+ *
+ * Author:  Ettore Chimenti <ek5.chimenti@gmail.com>
+ * Copyright (C) 2018, SECO Spa.
+ * Copyright (C) 2018, Aidilab Srl.
+ */
+
+#ifndef __SECO_CEC_H__
+#define __SECO_CEC_H__
+
+#define SECOCEC_MAX_ADDRS              1
+#define SECOCEC_DEV_NAME               "secocec"
+#define SECOCEC_LATEST_FW              0x0f0b
+
+#define SMBTIMEOUT                     0xfff
+#define SMB_POLL_UDELAY                        10
+
+#define SMBUS_WRITE                    0
+#define SMBUS_READ                     1
+
+#define CMD_BYTE_DATA                  0
+#define CMD_WORD_DATA                  1
+
+/*
+ * SMBus definitons for Braswell
+ */
+
+#define BRA_DONE_STATUS                        BIT(7)
+#define BRA_INUSE_STS                  BIT(6)
+#define BRA_FAILED_OP                  BIT(4)
+#define BRA_BUS_ERR                    BIT(3)
+#define BRA_DEV_ERR                    BIT(2)
+#define BRA_INTR                       BIT(1)
+#define BRA_HOST_BUSY                  BIT(0)
+#define BRA_HSTS_ERR_MASK   (BRA_FAILED_OP | BRA_BUS_ERR | BRA_DEV_ERR)
+
+#define BRA_PEC_EN                     BIT(7)
+#define BRA_START                      BIT(6)
+#define BRA_LAST__BYTE                 BIT(5)
+#define BRA_INTREN                     BIT(0)
+#define BRA_SMB_CMD                    (7 << 2)
+#define BRA_SMB_CMD_QUICK              (0 << 2)
+#define BRA_SMB_CMD_BYTE               (1 << 2)
+#define BRA_SMB_CMD_BYTE_DATA          (2 << 2)
+#define BRA_SMB_CMD_WORD_DATA          (3 << 2)
+#define BRA_SMB_CMD_PROCESS_CALL       (4 << 2)
+#define BRA_SMB_CMD_BLOCK              (5 << 2)
+#define BRA_SMB_CMD_I2CREAD            (6 << 2)
+#define BRA_SMB_CMD_BLOCK_PROCESS      (7 << 2)
+
+#define BRA_SMB_BASE_ADDR  0x2040
+#define HSTS               (BRA_SMB_BASE_ADDR + 0)
+#define HCNT               (BRA_SMB_BASE_ADDR + 2)
+#define HCMD               (BRA_SMB_BASE_ADDR + 3)
+#define XMIT_SLVA          (BRA_SMB_BASE_ADDR + 4)
+#define HDAT0              (BRA_SMB_BASE_ADDR + 5)
+#define HDAT1              (BRA_SMB_BASE_ADDR + 6)
+
+/*
+ * Microcontroller Address
+ */
+
+#define SECOCEC_MICRO_ADDRESS          0x40
+
+/*
+ * STM32 SMBus Registers
+ */
+
+#define SECOCEC_VERSION                        0x00
+#define SECOCEC_ENABLE_REG_1           0x01
+#define SECOCEC_ENABLE_REG_2           0x02
+#define SECOCEC_STATUS_REG_1           0x03
+#define SECOCEC_STATUS_REG_2           0x04
+
+#define SECOCEC_STATUS                 0x28
+#define SECOCEC_DEVICE_LA              0x29
+#define SECOCEC_READ_OPERATION_ID      0x2a
+#define SECOCEC_READ_DATA_LENGTH       0x2b
+#define SECOCEC_READ_DATA_00           0x2c
+#define SECOCEC_READ_DATA_02           0x2d
+#define SECOCEC_READ_DATA_04           0x2e
+#define SECOCEC_READ_DATA_06           0x2f
+#define SECOCEC_READ_DATA_08           0x30
+#define SECOCEC_READ_DATA_10           0x31
+#define SECOCEC_READ_DATA_12           0x32
+#define SECOCEC_READ_BYTE0             0x33
+#define SECOCEC_WRITE_OPERATION_ID     0x34
+#define SECOCEC_WRITE_DATA_LENGTH      0x35
+#define SECOCEC_WRITE_DATA_00          0x36
+#define SECOCEC_WRITE_DATA_02          0x37
+#define SECOCEC_WRITE_DATA_04          0x38
+#define SECOCEC_WRITE_DATA_06          0x39
+#define SECOCEC_WRITE_DATA_08          0x3a
+#define SECOCEC_WRITE_DATA_10          0x3b
+#define SECOCEC_WRITE_DATA_12          0x3c
+#define SECOCEC_WRITE_BYTE0            0x3d
+
+#define SECOCEC_IR_READ_DATA           0x3e
+
+/*
+ * IR
+ */
+
+#define SECOCEC_IR_COMMAND_MASK                0x007F
+#define SECOCEC_IR_COMMAND_SHL         0
+#define SECOCEC_IR_ADDRESS_MASK                0x1F00
+#define SECOCEC_IR_ADDRESS_SHL         7
+#define SECOCEC_IR_TOGGLE_MASK         0x8000
+#define SECOCEC_IR_TOGGLE_SHL          15
+
+/*
+ * Enabling register
+ */
+
+#define SECOCEC_ENABLE_REG_1_CEC               0x1000
+#define SECOCEC_ENABLE_REG_1_IR                        0x2000
+#define SECOCEC_ENABLE_REG_1_IR_PASSTHROUGH    0x4000
+
+/*
+ * Status register
+ */
+
+#define SECOCEC_STATUS_REG_1_CEC       SECOCEC_ENABLE_REG_1_CEC
+#define SECOCEC_STATUS_REG_1_IR                SECOCEC_ENABLE_REG_1_IR
+#define SECOCEC_STATUS_REG_1_IR_PASSTHR        SECOCEC_ENABLE_REG_1_IR_PASSTHR
+
+/*
+ * Status data
+ */
+
+#define SECOCEC_STATUS_MSG_RECEIVED_MASK       BIT(0)
+#define SECOCEC_STATUS_RX_ERROR_MASK           BIT(1)
+#define SECOCEC_STATUS_MSG_SENT_MASK           BIT(2)
+#define SECOCEC_STATUS_TX_ERROR_MASK           BIT(3)
+
+#define SECOCEC_STATUS_TX_NACK_ERROR           BIT(4)
+#define SECOCEC_STATUS_RX_OVERFLOW_MASK                BIT(5)
+
+#endif /* __SECO_CEC_H__ */
index cee58b125548aa6b5f151c760dd7bd17bbbe2599..5799aa4b932318b85ed93cd18e20593840416416 100644 (file)
@@ -1007,7 +1007,7 @@ static int sh_vou_s_selection(struct file *file, void *fh,
 
        /*
         * No down-scaling. According to the API, current call has precedence:
-        * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two.
+        * https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/crop.html#cropping-structures
         */
        vou_adjust_input(&geo, vou_dev->std);
 
index 26d9fa7aeb5f2d8b46167bca20ab06c6c0ad1914..4372abbb5950ff882ccfaa5bfaaf17be1e85631e 100644 (file)
@@ -510,7 +510,7 @@ int bdisp_hw_alloc_filters(struct device *dev)
 
        /* Allocate all the filters within a single memory page */
        size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
-       base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA,
+       base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL,
                               DMA_ATTR_WRITE_COMBINE);
        if (!base)
                return -ENOMEM;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig
new file mode 100644 (file)
index 0000000..018e3ec
--- /dev/null
@@ -0,0 +1,9 @@
+config VIDEO_SUN6I_CSI
+       tristate "Allwinner V3s Camera Sensor Interface driver"
+       depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+       depends on ARCH_SUNXI || COMPILE_TEST
+       select VIDEOBUF2_DMA_CONTIG
+       select REGMAP_MMIO
+       select V4L2_FWNODE
+       help
+          Support for the Allwinner Camera Sensor Interface Controller on V3s.
diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile
new file mode 100644 (file)
index 0000000..213cb6b
--- /dev/null
@@ -0,0 +1,3 @@
+sun6i-csi-y += sun6i_video.o sun6i_csi.o
+
+obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
new file mode 100644 (file)
index 0000000..6950585
--- /dev/null
@@ -0,0 +1,913 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * All rights reserved.
+ * Author: Yong Deng <yong.deng@magewell.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+#include "sun6i_csi.h"
+#include "sun6i_csi_reg.h"
+
+#define MODULE_NAME    "sun6i-csi"
+
+struct sun6i_csi_dev {
+       struct sun6i_csi                csi;
+       struct device                   *dev;
+
+       struct regmap                   *regmap;
+       struct clk                      *clk_mod;
+       struct clk                      *clk_ram;
+       struct reset_control            *rstc_bus;
+
+       int                             planar_offset[3];
+};
+
+static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
+{
+       return container_of(csi, struct sun6i_csi_dev, csi);
+}
+
+/* TODO add 10&12 bit YUV, RGB support */
+bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
+                                  u32 pixformat, u32 mbus_code)
+{
+       struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+
+       /*
+        * Some video receivers have the ability to be compatible with
+        * 8bit and 16bit bus width.
+        * Identify the media bus format from device tree.
+        */
+       if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
+            || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656)
+            && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) {
+               switch (pixformat) {
+               case V4L2_PIX_FMT_HM12:
+               case V4L2_PIX_FMT_NV12:
+               case V4L2_PIX_FMT_NV21:
+               case V4L2_PIX_FMT_NV16:
+               case V4L2_PIX_FMT_NV61:
+               case V4L2_PIX_FMT_YUV420:
+               case V4L2_PIX_FMT_YVU420:
+               case V4L2_PIX_FMT_YUV422P:
+                       switch (mbus_code) {
+                       case MEDIA_BUS_FMT_UYVY8_1X16:
+                       case MEDIA_BUS_FMT_VYUY8_1X16:
+                       case MEDIA_BUS_FMT_YUYV8_1X16:
+                       case MEDIA_BUS_FMT_YVYU8_1X16:
+                               return true;
+                       default:
+                               dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
+                                       mbus_code);
+                               break;
+                       }
+                       break;
+               default:
+                       dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n",
+                               pixformat);
+                       break;
+               }
+               return false;
+       }
+
+       switch (pixformat) {
+       case V4L2_PIX_FMT_SBGGR8:
+               return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8);
+       case V4L2_PIX_FMT_SGBRG8:
+               return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8);
+       case V4L2_PIX_FMT_SGRBG8:
+               return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8);
+       case V4L2_PIX_FMT_SRGGB8:
+               return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8);
+       case V4L2_PIX_FMT_SBGGR10:
+               return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10);
+       case V4L2_PIX_FMT_SGBRG10:
+               return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10);
+       case V4L2_PIX_FMT_SGRBG10:
+               return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10);
+       case V4L2_PIX_FMT_SRGGB10:
+               return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10);
+       case V4L2_PIX_FMT_SBGGR12:
+               return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12);
+       case V4L2_PIX_FMT_SGBRG12:
+               return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12);
+       case V4L2_PIX_FMT_SGRBG12:
+               return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12);
+       case V4L2_PIX_FMT_SRGGB12:
+               return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12);
+
+       case V4L2_PIX_FMT_YUYV:
+               return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8);
+       case V4L2_PIX_FMT_YVYU:
+               return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8);
+       case V4L2_PIX_FMT_UYVY:
+               return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8);
+       case V4L2_PIX_FMT_VYUY:
+               return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8);
+
+       case V4L2_PIX_FMT_HM12:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV422P:
+               switch (mbus_code) {
+               case MEDIA_BUS_FMT_UYVY8_2X8:
+               case MEDIA_BUS_FMT_VYUY8_2X8:
+               case MEDIA_BUS_FMT_YUYV8_2X8:
+               case MEDIA_BUS_FMT_YVYU8_2X8:
+                       return true;
+               default:
+                       dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
+                               mbus_code);
+                       break;
+               }
+               break;
+       default:
+               dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
+               break;
+       }
+
+       return false;
+}
+
+int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
+{
+       struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+       struct regmap *regmap = sdev->regmap;
+       int ret;
+
+       if (!enable) {
+               regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
+
+               clk_disable_unprepare(sdev->clk_ram);
+               clk_disable_unprepare(sdev->clk_mod);
+               reset_control_assert(sdev->rstc_bus);
+               return 0;
+       }
+
+       ret = clk_prepare_enable(sdev->clk_mod);
+       if (ret) {
+               dev_err(sdev->dev, "Enable csi clk err %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sdev->clk_ram);
+       if (ret) {
+               dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret);
+               goto clk_mod_disable;
+       }
+
+       ret = reset_control_deassert(sdev->rstc_bus);
+       if (ret) {
+               dev_err(sdev->dev, "reset err %d\n", ret);
+               goto clk_ram_disable;
+       }
+
+       regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
+
+       return 0;
+
+clk_ram_disable:
+       clk_disable_unprepare(sdev->clk_ram);
+clk_mod_disable:
+       clk_disable_unprepare(sdev->clk_mod);
+       return ret;
+}
+
+static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev,
+                                              u32 mbus_code, u32 pixformat)
+{
+       /* bayer */
+       if ((mbus_code & 0xF000) == 0x3000)
+               return CSI_INPUT_FORMAT_RAW;
+
+       switch (pixformat) {
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+               return CSI_INPUT_FORMAT_RAW;
+       default:
+               break;
+       }
+
+       /* not support YUV420 input format yet */
+       dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n");
+       return CSI_INPUT_FORMAT_YUV422;
+}
+
+static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev,
+                                                u32 pixformat, u32 field)
+{
+       bool buf_interlaced = false;
+
+       if (field == V4L2_FIELD_INTERLACED
+           || field == V4L2_FIELD_INTERLACED_TB
+           || field == V4L2_FIELD_INTERLACED_BT)
+               buf_interlaced = true;
+
+       switch (pixformat) {
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+               return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SRGGB10:
+               return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10;
+       case V4L2_PIX_FMT_SBGGR12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SRGGB12:
+               return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12;
+
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+               return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
+
+       case V4L2_PIX_FMT_HM12:
+               return buf_interlaced ? CSI_FRAME_MB_YUV420 :
+                                       CSI_FIELD_MB_YUV420;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 :
+                                       CSI_FIELD_UV_CB_YUV420;
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 :
+                                       CSI_FIELD_PLANAR_YUV420;
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 :
+                                       CSI_FIELD_UV_CB_YUV422;
+       case V4L2_PIX_FMT_YUV422P:
+               return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 :
+                                       CSI_FIELD_PLANAR_YUV422;
+       default:
+               dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
+               break;
+       }
+
+       return CSI_FIELD_RAW_8;
+}
+
+static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
+                                           u32 mbus_code, u32 pixformat)
+{
+       switch (pixformat) {
+       case V4L2_PIX_FMT_HM12:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YUV422P:
+               switch (mbus_code) {
+               case MEDIA_BUS_FMT_UYVY8_2X8:
+               case MEDIA_BUS_FMT_UYVY8_1X16:
+                       return CSI_INPUT_SEQ_UYVY;
+               case MEDIA_BUS_FMT_VYUY8_2X8:
+               case MEDIA_BUS_FMT_VYUY8_1X16:
+                       return CSI_INPUT_SEQ_VYUY;
+               case MEDIA_BUS_FMT_YUYV8_2X8:
+               case MEDIA_BUS_FMT_YUYV8_1X16:
+                       return CSI_INPUT_SEQ_YUYV;
+               case MEDIA_BUS_FMT_YVYU8_1X16:
+               case MEDIA_BUS_FMT_YVYU8_2X8:
+                       return CSI_INPUT_SEQ_YVYU;
+               default:
+                       dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
+                                mbus_code);
+                       break;
+               }
+               break;
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_YVU420:
+               switch (mbus_code) {
+               case MEDIA_BUS_FMT_UYVY8_2X8:
+               case MEDIA_BUS_FMT_UYVY8_1X16:
+                       return CSI_INPUT_SEQ_VYUY;
+               case MEDIA_BUS_FMT_VYUY8_2X8:
+               case MEDIA_BUS_FMT_VYUY8_1X16:
+                       return CSI_INPUT_SEQ_UYVY;
+               case MEDIA_BUS_FMT_YUYV8_2X8:
+               case MEDIA_BUS_FMT_YUYV8_1X16:
+                       return CSI_INPUT_SEQ_YVYU;
+               case MEDIA_BUS_FMT_YVYU8_1X16:
+               case MEDIA_BUS_FMT_YVYU8_2X8:
+                       return CSI_INPUT_SEQ_YUYV;
+               default:
+                       dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
+                                mbus_code);
+                       break;
+               }
+               break;
+
+       case V4L2_PIX_FMT_YUYV:
+               return CSI_INPUT_SEQ_YUYV;
+
+       default:
+               dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
+                        pixformat);
+               break;
+       }
+
+       return CSI_INPUT_SEQ_YUYV;
+}
+
+static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
+{
+       struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep;
+       struct sun6i_csi *csi = &sdev->csi;
+       unsigned char bus_width;
+       u32 flags;
+       u32 cfg;
+       bool input_interlaced = false;
+
+       if (csi->config.field == V4L2_FIELD_INTERLACED
+           || csi->config.field == V4L2_FIELD_INTERLACED_TB
+           || csi->config.field == V4L2_FIELD_INTERLACED_BT)
+               input_interlaced = true;
+
+       bus_width = endpoint->bus.parallel.bus_width;
+
+       regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg);
+
+       cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
+                CSI_IF_CFG_IF_DATA_WIDTH_MASK |
+                CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK |
+                CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK |
+                CSI_IF_CFG_SRC_TYPE_MASK);
+
+       if (input_interlaced)
+               cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED;
+       else
+               cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED;
+
+       switch (endpoint->bus_type) {
+       case V4L2_MBUS_PARALLEL:
+               cfg |= CSI_IF_CFG_MIPI_IF_CSI;
+
+               flags = endpoint->bus.parallel.flags;
+
+               cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT :
+                                          CSI_IF_CFG_CSI_IF_YUV422_INTLV;
+
+               if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
+                       cfg |= CSI_IF_CFG_FIELD_POSITIVE;
+
+               if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+                       cfg |= CSI_IF_CFG_VREF_POL_POSITIVE;
+               if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+                       cfg |= CSI_IF_CFG_HREF_POL_POSITIVE;
+
+               if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+                       cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
+               break;
+       case V4L2_MBUS_BT656:
+               cfg |= CSI_IF_CFG_MIPI_IF_CSI;
+
+               flags = endpoint->bus.parallel.flags;
+
+               cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 :
+                                          CSI_IF_CFG_CSI_IF_BT656;
+
+               if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
+                       cfg |= CSI_IF_CFG_FIELD_POSITIVE;
+
+               if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+                       cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
+               break;
+       default:
+               dev_warn(sdev->dev, "Unsupported bus type: %d\n",
+                        endpoint->bus_type);
+               break;
+       }
+
+       switch (bus_width) {
+       case 8:
+               cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
+               break;
+       case 10:
+               cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
+               break;
+       case 12:
+               cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
+               break;
+       case 16: /* No need to configure DATA_WIDTH for 16bit */
+               break;
+       default:
+               dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
+               break;
+       }
+
+       regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
+}
+
+static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev)
+{
+       struct sun6i_csi *csi = &sdev->csi;
+       u32 cfg;
+       u32 val;
+
+       regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg);
+
+       cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
+                CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
+                CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
+                CSI_CH_CFG_INPUT_SEQ_MASK);
+
+       val = get_csi_input_format(sdev, csi->config.code,
+                                  csi->config.pixelformat);
+       cfg |= CSI_CH_CFG_INPUT_FMT(val);
+
+       val = get_csi_output_format(sdev, csi->config.pixelformat,
+                                   csi->config.field);
+       cfg |= CSI_CH_CFG_OUTPUT_FMT(val);
+
+       val = get_csi_input_seq(sdev, csi->config.code,
+                               csi->config.pixelformat);
+       cfg |= CSI_CH_CFG_INPUT_SEQ(val);
+
+       if (csi->config.field == V4L2_FIELD_TOP)
+               cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
+       else if (csi->config.field == V4L2_FIELD_BOTTOM)
+               cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
+       else
+               cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;
+
+       regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg);
+}
+
+static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
+{
+       struct sun6i_csi_config *config = &sdev->csi.config;
+       u32 bytesperline_y;
+       u32 bytesperline_c;
+       int *planar_offset = sdev->planar_offset;
+       u32 width = config->width;
+       u32 height = config->height;
+       u32 hor_len = width;
+
+       switch (config->pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+               dev_dbg(sdev->dev,
+                       "Horizontal length should be 2 times of width for packed YUV formats!\n");
+               hor_len = width * 2;
+               break;
+       default:
+               break;
+       }
+
+       regmap_write(sdev->regmap, CSI_CH_HSIZE_REG,
+                    CSI_CH_HSIZE_HOR_LEN(hor_len) |
+                    CSI_CH_HSIZE_HOR_START(0));
+       regmap_write(sdev->regmap, CSI_CH_VSIZE_REG,
+                    CSI_CH_VSIZE_VER_LEN(height) |
+                    CSI_CH_VSIZE_VER_START(0));
+
+       planar_offset[0] = 0;
+       switch (config->pixelformat) {
+       case V4L2_PIX_FMT_HM12:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               bytesperline_y = width;
+               bytesperline_c = width;
+               planar_offset[1] = bytesperline_y * height;
+               planar_offset[2] = -1;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               bytesperline_y = width;
+               bytesperline_c = width / 2;
+               planar_offset[1] = bytesperline_y * height;
+               planar_offset[2] = planar_offset[1] +
+                               bytesperline_c * height / 2;
+               break;
+       case V4L2_PIX_FMT_YUV422P:
+               bytesperline_y = width;
+               bytesperline_c = width / 2;
+               planar_offset[1] = bytesperline_y * height;
+               planar_offset[2] = planar_offset[1] +
+                               bytesperline_c * height;
+               break;
+       default: /* raw */
+               dev_dbg(sdev->dev,
+                       "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n",
+                       config->pixelformat);
+               bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
+                                 config->width) / 8;
+               bytesperline_c = 0;
+               planar_offset[1] = -1;
+               planar_offset[2] = -1;
+               break;
+       }
+
+       regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG,
+                    CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
+                    CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
+}
+
+int sun6i_csi_update_config(struct sun6i_csi *csi,
+                           struct sun6i_csi_config *config)
+{
+       struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+
+       if (!config)
+               return -EINVAL;
+
+       memcpy(&csi->config, config, sizeof(csi->config));
+
+       sun6i_csi_setup_bus(sdev);
+       sun6i_csi_set_format(sdev);
+       sun6i_csi_set_window(sdev);
+
+       return 0;
+}
+
+void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr)
+{
+       struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+
+       regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG,
+                    (addr + sdev->planar_offset[0]) >> 2);
+       if (sdev->planar_offset[1] != -1)
+               regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG,
+                            (addr + sdev->planar_offset[1]) >> 2);
+       if (sdev->planar_offset[2] != -1)
+               regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG,
+                            (addr + sdev->planar_offset[2]) >> 2);
+}
+
+void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
+{
+       struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+       struct regmap *regmap = sdev->regmap;
+
+       if (!enable) {
+               regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
+               regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
+               return;
+       }
+
+       regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
+       regmap_write(regmap, CSI_CH_INT_EN_REG,
+                    CSI_CH_INT_EN_HB_OF_INT_EN |
+                    CSI_CH_INT_EN_FIFO2_OF_INT_EN |
+                    CSI_CH_INT_EN_FIFO1_OF_INT_EN |
+                    CSI_CH_INT_EN_FIFO0_OF_INT_EN |
+                    CSI_CH_INT_EN_FD_INT_EN |
+                    CSI_CH_INT_EN_CD_INT_EN);
+
+       regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
+                          CSI_CAP_CH0_VCAP_ON);
+}
+
+/* -----------------------------------------------------------------------------
+ * Media Controller and V4L2
+ */
+static int sun6i_csi_link_entity(struct sun6i_csi *csi,
+                                struct media_entity *entity,
+                                struct fwnode_handle *fwnode)
+{
+       struct media_entity *sink;
+       struct media_pad *sink_pad;
+       int src_pad_index;
+       int ret;
+
+       ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE);
+       if (ret < 0) {
+               dev_err(csi->dev, "%s: no source pad in external entity %s\n",
+                       __func__, entity->name);
+               return -EINVAL;
+       }
+
+       src_pad_index = ret;
+
+       sink = &csi->video.vdev.entity;
+       sink_pad = &csi->video.pad;
+
+       dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n",
+               entity->name, src_pad_index, sink->name, sink_pad->index);
+       ret = media_create_pad_link(entity, src_pad_index, sink,
+                                   sink_pad->index,
+                                   MEDIA_LNK_FL_ENABLED |
+                                   MEDIA_LNK_FL_IMMUTABLE);
+       if (ret < 0) {
+               dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n",
+                       entity->name, src_pad_index,
+                       sink->name, sink_pad->index);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier)
+{
+       struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi,
+                                            notifier);
+       struct v4l2_device *v4l2_dev = &csi->v4l2_dev;
+       struct v4l2_subdev *sd;
+       int ret;
+
+       dev_dbg(csi->dev, "notify complete, all subdevs registered\n");
+
+       sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list);
+       if (!sd)
+               return -EINVAL;
+
+       ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode);
+       if (ret < 0)
+               return ret;
+
+       ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
+       if (ret < 0)
+               return ret;
+
+       return media_device_register(&csi->media_dev);
+}
+
+static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = {
+       .complete = sun6i_subdev_notify_complete,
+};
+
+static int sun6i_csi_fwnode_parse(struct device *dev,
+                                 struct v4l2_fwnode_endpoint *vep,
+                                 struct v4l2_async_subdev *asd)
+{
+       struct sun6i_csi *csi = dev_get_drvdata(dev);
+
+       if (vep->base.port || vep->base.id) {
+               dev_warn(dev, "Only support a single port with one endpoint\n");
+               return -ENOTCONN;
+       }
+
+       switch (vep->bus_type) {
+       case V4L2_MBUS_PARALLEL:
+       case V4L2_MBUS_BT656:
+               csi->v4l2_ep = *vep;
+               return 0;
+       default:
+               dev_err(dev, "Unsupported media bus type\n");
+               return -ENOTCONN;
+       }
+}
+
+static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi)
+{
+       media_device_unregister(&csi->media_dev);
+       v4l2_async_notifier_unregister(&csi->notifier);
+       v4l2_async_notifier_cleanup(&csi->notifier);
+       sun6i_video_cleanup(&csi->video);
+       v4l2_device_unregister(&csi->v4l2_dev);
+       v4l2_ctrl_handler_free(&csi->ctrl_handler);
+       media_device_cleanup(&csi->media_dev);
+}
+
+static int sun6i_csi_v4l2_init(struct sun6i_csi *csi)
+{
+       int ret;
+
+       csi->media_dev.dev = csi->dev;
+       strscpy(csi->media_dev.model, "Allwinner Video Capture Device",
+               sizeof(csi->media_dev.model));
+       csi->media_dev.hw_revision = 0;
+
+       media_device_init(&csi->media_dev);
+       v4l2_async_notifier_init(&csi->notifier);
+
+       ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0);
+       if (ret) {
+               dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n",
+                       ret);
+               goto clean_media;
+       }
+
+       csi->v4l2_dev.mdev = &csi->media_dev;
+       csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler;
+       ret = v4l2_device_register(csi->dev, &csi->v4l2_dev);
+       if (ret) {
+               dev_err(csi->dev, "V4L2 device registration failed (%d)\n",
+                       ret);
+               goto free_ctrl;
+       }
+
+       ret = sun6i_video_init(&csi->video, csi, "sun6i-csi");
+       if (ret)
+               goto unreg_v4l2;
+
+       ret = v4l2_async_notifier_parse_fwnode_endpoints(csi->dev,
+                                                        &csi->notifier,
+                                                        sizeof(struct v4l2_async_subdev),
+                                                        sun6i_csi_fwnode_parse);
+       if (ret)
+               goto clean_video;
+
+       csi->notifier.ops = &sun6i_csi_async_ops;
+
+       ret = v4l2_async_notifier_register(&csi->v4l2_dev, &csi->notifier);
+       if (ret) {
+               dev_err(csi->dev, "notifier registration failed\n");
+               goto clean_video;
+       }
+
+       return 0;
+
+clean_video:
+       sun6i_video_cleanup(&csi->video);
+unreg_v4l2:
+       v4l2_device_unregister(&csi->v4l2_dev);
+free_ctrl:
+       v4l2_ctrl_handler_free(&csi->ctrl_handler);
+clean_media:
+       v4l2_async_notifier_cleanup(&csi->notifier);
+       media_device_cleanup(&csi->media_dev);
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Resources and IRQ
+ */
+static irqreturn_t sun6i_csi_isr(int irq, void *dev_id)
+{
+       struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id;
+       struct regmap *regmap = sdev->regmap;
+       u32 status;
+
+       regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
+
+       if (!(status & 0xFF))
+               return IRQ_NONE;
+
+       if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) ||
+           (status & CSI_CH_INT_STA_FIFO1_OF_PD) ||
+           (status & CSI_CH_INT_STA_FIFO2_OF_PD) ||
+           (status & CSI_CH_INT_STA_HB_OF_PD)) {
+               regmap_write(regmap, CSI_CH_INT_STA_REG, status);
+               regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
+               regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
+                                  CSI_EN_CSI_EN);
+               return IRQ_HANDLED;
+       }
+
+       if (status & CSI_CH_INT_STA_FD_PD)
+               sun6i_video_frame_done(&sdev->csi.video);
+
+       regmap_write(regmap, CSI_CH_INT_STA_REG, status);
+
+       return IRQ_HANDLED;
+}
+
+static const struct regmap_config sun6i_csi_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = 0x1000,
+};
+
+static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
+                                     struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *io_base;
+       int ret;
+       int irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(io_base))
+               return PTR_ERR(io_base);
+
+       sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base,
+                                                &sun6i_csi_regmap_config);
+       if (IS_ERR(sdev->regmap)) {
+               dev_err(&pdev->dev, "Failed to init register map\n");
+               return PTR_ERR(sdev->regmap);
+       }
+
+       sdev->clk_mod = devm_clk_get(&pdev->dev, "mod");
+       if (IS_ERR(sdev->clk_mod)) {
+               dev_err(&pdev->dev, "Unable to acquire csi clock\n");
+               return PTR_ERR(sdev->clk_mod);
+       }
+
+       sdev->clk_ram = devm_clk_get(&pdev->dev, "ram");
+       if (IS_ERR(sdev->clk_ram)) {
+               dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n");
+               return PTR_ERR(sdev->clk_ram);
+       }
+
+       sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
+       if (IS_ERR(sdev->rstc_bus)) {
+               dev_err(&pdev->dev, "Cannot get reset controller\n");
+               return PTR_ERR(sdev->rstc_bus);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "No csi IRQ specified\n");
+               ret = -ENXIO;
+               return ret;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME,
+                              sdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request csi IRQ\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * PHYS_OFFSET isn't available on all architectures. In order to
+ * accommodate for COMPILE_TEST, let's define it to something dumb.
+ */
+#if defined(CONFIG_COMPILE_TEST) && !defined(PHYS_OFFSET)
+#define PHYS_OFFSET 0
+#endif
+
+static int sun6i_csi_probe(struct platform_device *pdev)
+{
+       struct sun6i_csi_dev *sdev;
+       int ret;
+
+       sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
+       if (!sdev)
+               return -ENOMEM;
+
+       sdev->dev = &pdev->dev;
+       /* The DMA bus has the memory mapped at 0 */
+       sdev->dev->dma_pfn_offset = PHYS_OFFSET >> PAGE_SHIFT;
+
+       ret = sun6i_csi_resource_request(sdev, pdev);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, sdev);
+
+       sdev->csi.dev = &pdev->dev;
+       return sun6i_csi_v4l2_init(&sdev->csi);
+}
+
+static int sun6i_csi_remove(struct platform_device *pdev)
+{
+       struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev);
+
+       sun6i_csi_v4l2_cleanup(&sdev->csi);
+
+       return 0;
+}
+
+static const struct of_device_id sun6i_csi_of_match[] = {
+       { .compatible = "allwinner,sun6i-a31-csi", },
+       { .compatible = "allwinner,sun8i-v3s-csi", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
+
+static struct platform_driver sun6i_csi_platform_driver = {
+       .probe = sun6i_csi_probe,
+       .remove = sun6i_csi_remove,
+       .driver = {
+               .name = MODULE_NAME,
+               .of_match_table = of_match_ptr(sun6i_csi_of_match),
+       },
+};
+module_platform_driver(sun6i_csi_platform_driver);
+
+MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver");
+MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
new file mode 100644 (file)
index 0000000..0bb0007
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * All rights reserved.
+ * Author: Yong Deng <yong.deng@magewell.com>
+ */
+
+#ifndef __SUN6I_CSI_H__
+#define __SUN6I_CSI_H__
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "sun6i_video.h"
+
+struct sun6i_csi;
+
+/**
+ * struct sun6i_csi_config - configs for sun6i csi
+ * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*)
+ * @code:      media bus format code (MEDIA_BUS_FMT_*)
+ * @field:     used interlacing type (enum v4l2_field)
+ * @width:     frame width
+ * @height:    frame height
+ */
+struct sun6i_csi_config {
+       u32             pixelformat;
+       u32             code;
+       u32             field;
+       u32             width;
+       u32             height;
+};
+
+struct sun6i_csi {
+       struct device                   *dev;
+       struct v4l2_ctrl_handler        ctrl_handler;
+       struct v4l2_device              v4l2_dev;
+       struct media_device             media_dev;
+
+       struct v4l2_async_notifier      notifier;
+
+       /* video port settings */
+       struct v4l2_fwnode_endpoint     v4l2_ep;
+
+       struct sun6i_csi_config         config;
+
+       struct sun6i_video              video;
+};
+
+/**
+ * sun6i_csi_is_format_supported() - check if the format supported by csi
+ * @csi:       pointer to the csi
+ * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*)
+ * @mbus_code: media bus format code (MEDIA_BUS_FMT_*)
+ */
+bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat,
+                                  u32 mbus_code);
+
+/**
+ * sun6i_csi_set_power() - power on/off the csi
+ * @csi:       pointer to the csi
+ * @enable:    on/off
+ */
+int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable);
+
+/**
+ * sun6i_csi_update_config() - update the csi register setttings
+ * @csi:       pointer to the csi
+ * @config:    see struct sun6i_csi_config
+ */
+int sun6i_csi_update_config(struct sun6i_csi *csi,
+                           struct sun6i_csi_config *config);
+
+/**
+ * sun6i_csi_update_buf_addr() - update the csi frame buffer address
+ * @csi:       pointer to the csi
+ * @addr:      frame buffer's physical address
+ */
+void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr);
+
+/**
+ * sun6i_csi_set_stream() - start/stop csi streaming
+ * @csi:       pointer to the csi
+ * @enable:    start/stop
+ */
+void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable);
+
+/* get bpp form v4l2 pixformat */
+static inline int sun6i_csi_get_bpp(unsigned int pixformat)
+{
+       switch (pixformat) {
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+               return 8;
+       case V4L2_PIX_FMT_SBGGR10:
+       case V4L2_PIX_FMT_SGBRG10:
+       case V4L2_PIX_FMT_SGRBG10:
+       case V4L2_PIX_FMT_SRGGB10:
+               return 10;
+       case V4L2_PIX_FMT_SBGGR12:
+       case V4L2_PIX_FMT_SGBRG12:
+       case V4L2_PIX_FMT_SGRBG12:
+       case V4L2_PIX_FMT_SRGGB12:
+       case V4L2_PIX_FMT_HM12:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               return 12;
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_YUV422P:
+               return 16;
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+               return 24;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+               return 32;
+       default:
+               WARN(1, "Unsupported pixformat: 0x%x\n", pixformat);
+               break;
+       }
+
+       return 0;
+}
+
+#endif /* __SUN6I_CSI_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h
new file mode 100644 (file)
index 0000000..703fa14
--- /dev/null
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * All rights reserved.
+ * Author: Yong Deng <yong.deng@magewell.com>
+ */
+
+#ifndef __SUN6I_CSI_REG_H__
+#define __SUN6I_CSI_REG_H__
+
+#include <linux/kernel.h>
+
+#define CSI_EN_REG                     0x0
+#define CSI_EN_VER_EN                          BIT(30)
+#define CSI_EN_CSI_EN                          BIT(0)
+
+#define CSI_IF_CFG_REG                 0x4
+#define CSI_IF_CFG_SRC_TYPE_MASK               BIT(21)
+#define CSI_IF_CFG_SRC_TYPE_PROGRESSED         ((0 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
+#define CSI_IF_CFG_SRC_TYPE_INTERLACED         ((1 << 21) & CSI_IF_CFG_SRC_TYPE_MASK)
+#define CSI_IF_CFG_FPS_DS_EN                   BIT(20)
+#define CSI_IF_CFG_FIELD_MASK                  BIT(19)
+#define CSI_IF_CFG_FIELD_NEGATIVE              ((0 << 19) & CSI_IF_CFG_FIELD_MASK)
+#define CSI_IF_CFG_FIELD_POSITIVE              ((1 << 19) & CSI_IF_CFG_FIELD_MASK)
+#define CSI_IF_CFG_VREF_POL_MASK               BIT(18)
+#define CSI_IF_CFG_VREF_POL_NEGATIVE           ((0 << 18) & CSI_IF_CFG_VREF_POL_MASK)
+#define CSI_IF_CFG_VREF_POL_POSITIVE           ((1 << 18) & CSI_IF_CFG_VREF_POL_MASK)
+#define CSI_IF_CFG_HREF_POL_MASK               BIT(17)
+#define CSI_IF_CFG_HREF_POL_NEGATIVE           ((0 << 17) & CSI_IF_CFG_HREF_POL_MASK)
+#define CSI_IF_CFG_HREF_POL_POSITIVE           ((1 << 17) & CSI_IF_CFG_HREF_POL_MASK)
+#define CSI_IF_CFG_CLK_POL_MASK                        BIT(16)
+#define CSI_IF_CFG_CLK_POL_RISING_EDGE         ((0 << 16) & CSI_IF_CFG_CLK_POL_MASK)
+#define CSI_IF_CFG_CLK_POL_FALLING_EDGE                ((1 << 16) & CSI_IF_CFG_CLK_POL_MASK)
+#define CSI_IF_CFG_IF_DATA_WIDTH_MASK          GENMASK(10, 8)
+#define CSI_IF_CFG_IF_DATA_WIDTH_8BIT          ((0 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
+#define CSI_IF_CFG_IF_DATA_WIDTH_10BIT         ((1 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
+#define CSI_IF_CFG_IF_DATA_WIDTH_12BIT         ((2 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK)
+#define CSI_IF_CFG_MIPI_IF_MASK                        BIT(7)
+#define CSI_IF_CFG_MIPI_IF_CSI                 (0 << 7)
+#define CSI_IF_CFG_MIPI_IF_MIPI                        BIT(7)
+#define CSI_IF_CFG_CSI_IF_MASK                 GENMASK(4, 0)
+#define CSI_IF_CFG_CSI_IF_YUV422_INTLV         ((0 << 0) & CSI_IF_CFG_CSI_IF_MASK)
+#define CSI_IF_CFG_CSI_IF_YUV422_16BIT         ((1 << 0) & CSI_IF_CFG_CSI_IF_MASK)
+#define CSI_IF_CFG_CSI_IF_BT656                        ((4 << 0) & CSI_IF_CFG_CSI_IF_MASK)
+#define CSI_IF_CFG_CSI_IF_BT1120               ((5 << 0) & CSI_IF_CFG_CSI_IF_MASK)
+
+#define CSI_CAP_REG                    0x8
+#define CSI_CAP_CH0_CAP_MASK_MASK              GENMASK(5, 2)
+#define CSI_CAP_CH0_CAP_MASK(count)            (((count) << 2) & CSI_CAP_CH0_CAP_MASK_MASK)
+#define CSI_CAP_CH0_VCAP_ON                    BIT(1)
+#define CSI_CAP_CH0_SCAP_ON                    BIT(0)
+
+#define CSI_SYNC_CNT_REG               0xc
+#define CSI_FIFO_THRS_REG              0x10
+#define CSI_BT656_HEAD_CFG_REG         0x14
+#define CSI_PTN_LEN_REG                        0x30
+#define CSI_PTN_ADDR_REG               0x34
+#define CSI_VER_REG                    0x3c
+
+#define CSI_CH_CFG_REG                 0x44
+#define CSI_CH_CFG_INPUT_FMT_MASK              GENMASK(23, 20)
+#define CSI_CH_CFG_INPUT_FMT(fmt)              (((fmt) << 20) & CSI_CH_CFG_INPUT_FMT_MASK)
+#define CSI_CH_CFG_OUTPUT_FMT_MASK             GENMASK(19, 16)
+#define CSI_CH_CFG_OUTPUT_FMT(fmt)             (((fmt) << 16) & CSI_CH_CFG_OUTPUT_FMT_MASK)
+#define CSI_CH_CFG_VFLIP_EN                    BIT(13)
+#define CSI_CH_CFG_HFLIP_EN                    BIT(12)
+#define CSI_CH_CFG_FIELD_SEL_MASK              GENMASK(11, 10)
+#define CSI_CH_CFG_FIELD_SEL_FIELD0            ((0 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
+#define CSI_CH_CFG_FIELD_SEL_FIELD1            ((1 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
+#define CSI_CH_CFG_FIELD_SEL_BOTH              ((2 << 10) & CSI_CH_CFG_FIELD_SEL_MASK)
+#define CSI_CH_CFG_INPUT_SEQ_MASK              GENMASK(9, 8)
+#define CSI_CH_CFG_INPUT_SEQ(seq)              (((seq) << 8) & CSI_CH_CFG_INPUT_SEQ_MASK)
+
+#define CSI_CH_SCALE_REG               0x4c
+#define CSI_CH_SCALE_QUART_EN                  BIT(0)
+
+#define CSI_CH_F0_BUFA_REG             0x50
+
+#define CSI_CH_F1_BUFA_REG             0x58
+
+#define CSI_CH_F2_BUFA_REG             0x60
+
+#define CSI_CH_STA_REG                 0x6c
+#define CSI_CH_STA_FIELD_STA_MASK              BIT(2)
+#define CSI_CH_STA_FIELD_STA_FIELD0            ((0 << 2) & CSI_CH_STA_FIELD_STA_MASK)
+#define CSI_CH_STA_FIELD_STA_FIELD1            ((1 << 2) & CSI_CH_STA_FIELD_STA_MASK)
+#define CSI_CH_STA_VCAP_STA                    BIT(1)
+#define CSI_CH_STA_SCAP_STA                    BIT(0)
+
+#define CSI_CH_INT_EN_REG              0x70
+#define CSI_CH_INT_EN_VS_INT_EN                        BIT(7)
+#define CSI_CH_INT_EN_HB_OF_INT_EN             BIT(6)
+#define CSI_CH_INT_EN_MUL_ERR_INT_EN           BIT(5)
+#define CSI_CH_INT_EN_FIFO2_OF_INT_EN          BIT(4)
+#define CSI_CH_INT_EN_FIFO1_OF_INT_EN          BIT(3)
+#define CSI_CH_INT_EN_FIFO0_OF_INT_EN          BIT(2)
+#define CSI_CH_INT_EN_FD_INT_EN                        BIT(1)
+#define CSI_CH_INT_EN_CD_INT_EN                        BIT(0)
+
+#define CSI_CH_INT_STA_REG             0x74
+#define CSI_CH_INT_STA_VS_PD                   BIT(7)
+#define CSI_CH_INT_STA_HB_OF_PD                        BIT(6)
+#define CSI_CH_INT_STA_MUL_ERR_PD              BIT(5)
+#define CSI_CH_INT_STA_FIFO2_OF_PD             BIT(4)
+#define CSI_CH_INT_STA_FIFO1_OF_PD             BIT(3)
+#define CSI_CH_INT_STA_FIFO0_OF_PD             BIT(2)
+#define CSI_CH_INT_STA_FD_PD                   BIT(1)
+#define CSI_CH_INT_STA_CD_PD                   BIT(0)
+
+#define CSI_CH_FLD1_VSIZE_REG          0x78
+
+#define CSI_CH_HSIZE_REG               0x80
+#define CSI_CH_HSIZE_HOR_LEN_MASK              GENMASK(28, 16)
+#define CSI_CH_HSIZE_HOR_LEN(len)              (((len) << 16) & CSI_CH_HSIZE_HOR_LEN_MASK)
+#define CSI_CH_HSIZE_HOR_START_MASK            GENMASK(12, 0)
+#define CSI_CH_HSIZE_HOR_START(start)          (((start) << 0) & CSI_CH_HSIZE_HOR_START_MASK)
+
+#define CSI_CH_VSIZE_REG               0x84
+#define CSI_CH_VSIZE_VER_LEN_MASK              GENMASK(28, 16)
+#define CSI_CH_VSIZE_VER_LEN(len)              (((len) << 16) & CSI_CH_VSIZE_VER_LEN_MASK)
+#define CSI_CH_VSIZE_VER_START_MASK            GENMASK(12, 0)
+#define CSI_CH_VSIZE_VER_START(start)          (((start) << 0) & CSI_CH_VSIZE_VER_START_MASK)
+
+#define CSI_CH_BUF_LEN_REG             0x88
+#define CSI_CH_BUF_LEN_BUF_LEN_C_MASK          GENMASK(29, 16)
+#define CSI_CH_BUF_LEN_BUF_LEN_C(len)          (((len) << 16) & CSI_CH_BUF_LEN_BUF_LEN_C_MASK)
+#define CSI_CH_BUF_LEN_BUF_LEN_Y_MASK          GENMASK(13, 0)
+#define CSI_CH_BUF_LEN_BUF_LEN_Y(len)          (((len) << 0) & CSI_CH_BUF_LEN_BUF_LEN_Y_MASK)
+
+#define CSI_CH_FLIP_SIZE_REG           0x8c
+#define CSI_CH_FLIP_SIZE_VER_LEN_MASK          GENMASK(28, 16)
+#define CSI_CH_FLIP_SIZE_VER_LEN(len)          (((len) << 16) & CSI_CH_FLIP_SIZE_VER_LEN_MASK)
+#define CSI_CH_FLIP_SIZE_VALID_LEN_MASK                GENMASK(12, 0)
+#define CSI_CH_FLIP_SIZE_VALID_LEN(len)                (((len) << 0) & CSI_CH_FLIP_SIZE_VALID_LEN_MASK)
+
+#define CSI_CH_FRM_CLK_CNT_REG         0x90
+#define CSI_CH_ACC_ITNL_CLK_CNT_REG    0x94
+#define CSI_CH_FIFO_STAT_REG           0x98
+#define CSI_CH_PCLK_STAT_REG           0x9c
+
+/*
+ * csi input data format
+ */
+enum csi_input_fmt {
+       CSI_INPUT_FORMAT_RAW            = 0,
+       CSI_INPUT_FORMAT_YUV422         = 3,
+       CSI_INPUT_FORMAT_YUV420         = 4,
+};
+
+/*
+ * csi output data format
+ */
+enum csi_output_fmt {
+       /* only when input format is RAW */
+       CSI_FIELD_RAW_8                 = 0,
+       CSI_FIELD_RAW_10                = 1,
+       CSI_FIELD_RAW_12                = 2,
+       CSI_FIELD_RGB565                = 4,
+       CSI_FIELD_RGB888                = 5,
+       CSI_FIELD_PRGB888               = 6,
+       CSI_FRAME_RAW_8                 = 8,
+       CSI_FRAME_RAW_10                = 9,
+       CSI_FRAME_RAW_12                = 10,
+       CSI_FRAME_RGB565                = 12,
+       CSI_FRAME_RGB888                = 13,
+       CSI_FRAME_PRGB888               = 14,
+
+       /* only when input format is YUV422 */
+       CSI_FIELD_PLANAR_YUV422         = 0,
+       CSI_FIELD_PLANAR_YUV420         = 1,
+       CSI_FRAME_PLANAR_YUV420         = 2,
+       CSI_FRAME_PLANAR_YUV422         = 3,
+       CSI_FIELD_UV_CB_YUV422          = 4,
+       CSI_FIELD_UV_CB_YUV420          = 5,
+       CSI_FRAME_UV_CB_YUV420          = 6,
+       CSI_FRAME_UV_CB_YUV422          = 7,
+       CSI_FIELD_MB_YUV422             = 8,
+       CSI_FIELD_MB_YUV420             = 9,
+       CSI_FRAME_MB_YUV420             = 10,
+       CSI_FRAME_MB_YUV422             = 11,
+       CSI_FIELD_UV_CB_YUV422_10       = 12,
+       CSI_FIELD_UV_CB_YUV420_10       = 13,
+};
+
+/*
+ * csi YUV input data sequence
+ */
+enum csi_input_seq {
+       /* only when input format is YUV422 */
+       CSI_INPUT_SEQ_YUYV = 0,
+       CSI_INPUT_SEQ_YVYU,
+       CSI_INPUT_SEQ_UYVY,
+       CSI_INPUT_SEQ_VYUY,
+};
+
+#endif /* __SUN6I_CSI_REG_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
new file mode 100644 (file)
index 0000000..b04300c
--- /dev/null
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * All rights reserved.
+ * Author: Yong Deng <yong.deng@magewell.com>
+ */
+
+#include <linux/of.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun6i_csi.h"
+#include "sun6i_video.h"
+
+/* This is got from BSP sources. */
+#define MIN_WIDTH      (32)
+#define MIN_HEIGHT     (32)
+#define MAX_WIDTH      (4800)
+#define MAX_HEIGHT     (4800)
+
+struct sun6i_csi_buffer {
+       struct vb2_v4l2_buffer          vb;
+       struct list_head                list;
+
+       dma_addr_t                      dma_addr;
+       bool                            queued_to_csi;
+};
+
+static const u32 supported_pixformats[] = {
+       V4L2_PIX_FMT_SBGGR8,
+       V4L2_PIX_FMT_SGBRG8,
+       V4L2_PIX_FMT_SGRBG8,
+       V4L2_PIX_FMT_SRGGB8,
+       V4L2_PIX_FMT_SBGGR10,
+       V4L2_PIX_FMT_SGBRG10,
+       V4L2_PIX_FMT_SGRBG10,
+       V4L2_PIX_FMT_SRGGB10,
+       V4L2_PIX_FMT_SBGGR12,
+       V4L2_PIX_FMT_SGBRG12,
+       V4L2_PIX_FMT_SGRBG12,
+       V4L2_PIX_FMT_SRGGB12,
+       V4L2_PIX_FMT_YUYV,
+       V4L2_PIX_FMT_YVYU,
+       V4L2_PIX_FMT_UYVY,
+       V4L2_PIX_FMT_VYUY,
+       V4L2_PIX_FMT_HM12,
+       V4L2_PIX_FMT_NV12,
+       V4L2_PIX_FMT_NV21,
+       V4L2_PIX_FMT_YUV420,
+       V4L2_PIX_FMT_YVU420,
+       V4L2_PIX_FMT_NV16,
+       V4L2_PIX_FMT_NV61,
+       V4L2_PIX_FMT_YUV422P,
+};
+
+static bool is_pixformat_valid(unsigned int pixformat)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++)
+               if (supported_pixformats[i] == pixformat)
+                       return true;
+
+       return false;
+}
+
+static struct v4l2_subdev *
+sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
+{
+       struct media_pad *remote;
+
+       remote = media_entity_remote_pad(&video->pad);
+
+       if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
+               return NULL;
+
+       if (pad)
+               *pad = remote->index;
+
+       return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+static int sun6i_video_queue_setup(struct vb2_queue *vq,
+                                  unsigned int *nbuffers,
+                                  unsigned int *nplanes,
+                                  unsigned int sizes[],
+                                  struct device *alloc_devs[])
+{
+       struct sun6i_video *video = vb2_get_drv_priv(vq);
+       unsigned int size = video->fmt.fmt.pix.sizeimage;
+
+       if (*nplanes)
+               return sizes[0] < size ? -EINVAL : 0;
+
+       *nplanes = 1;
+       sizes[0] = size;
+
+       return 0;
+}
+
+static int sun6i_video_buffer_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct sun6i_csi_buffer *buf =
+                       container_of(vbuf, struct sun6i_csi_buffer, vb);
+       struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size = video->fmt.fmt.pix.sizeimage;
+
+       if (vb2_plane_size(vb, 0) < size) {
+               v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n",
+                        vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, size);
+
+       buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+       vbuf->field = video->fmt.fmt.pix.field;
+
+       return 0;
+}
+
+static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct sun6i_video *video = vb2_get_drv_priv(vq);
+       struct sun6i_csi_buffer *buf;
+       struct sun6i_csi_buffer *next_buf;
+       struct sun6i_csi_config config;
+       struct v4l2_subdev *subdev;
+       unsigned long flags;
+       int ret;
+
+       video->sequence = 0;
+
+       ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe);
+       if (ret < 0)
+               goto clear_dma_queue;
+
+       if (video->mbus_code == 0) {
+               ret = -EINVAL;
+               goto stop_media_pipeline;
+       }
+
+       subdev = sun6i_video_remote_subdev(video, NULL);
+       if (!subdev)
+               goto stop_media_pipeline;
+
+       config.pixelformat = video->fmt.fmt.pix.pixelformat;
+       config.code = video->mbus_code;
+       config.field = video->fmt.fmt.pix.field;
+       config.width = video->fmt.fmt.pix.width;
+       config.height = video->fmt.fmt.pix.height;
+
+       ret = sun6i_csi_update_config(video->csi, &config);
+       if (ret < 0)
+               goto stop_media_pipeline;
+
+       spin_lock_irqsave(&video->dma_queue_lock, flags);
+
+       buf = list_first_entry(&video->dma_queue,
+                              struct sun6i_csi_buffer, list);
+       buf->queued_to_csi = true;
+       sun6i_csi_update_buf_addr(video->csi, buf->dma_addr);
+
+       sun6i_csi_set_stream(video->csi, true);
+
+       /*
+        * CSI will lookup the next dma buffer for next frame before the
+        * the current frame done IRQ triggered. This is not documented
+        * but reported by Ondřej Jirman.
+        * The BSP code has workaround for this too. It skip to mark the
+        * first buffer as frame done for VB2 and pass the second buffer
+        * to CSI in the first frame done ISR call. Then in second frame
+        * done ISR call, it mark the first buffer as frame done for VB2
+        * and pass the third buffer to CSI. And so on. The bad thing is
+        * that the first buffer will be written twice and the first frame
+        * is dropped even the queued buffer is sufficient.
+        * So, I make some improvement here. Pass the next buffer to CSI
+        * just follow starting the CSI. In this case, the first frame
+        * will be stored in first buffer, second frame in second buffer.
+        * This method is used to avoid dropping the first frame, it
+        * would also drop frame when lacking of queued buffer.
+        */
+       next_buf = list_next_entry(buf, list);
+       next_buf->queued_to_csi = true;
+       sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
+
+       spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+
+       ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+       if (ret && ret != -ENOIOCTLCMD)
+               goto stop_csi_stream;
+
+       return 0;
+
+stop_csi_stream:
+       sun6i_csi_set_stream(video->csi, false);
+stop_media_pipeline:
+       media_pipeline_stop(&video->vdev.entity);
+clear_dma_queue:
+       spin_lock_irqsave(&video->dma_queue_lock, flags);
+       list_for_each_entry(buf, &video->dma_queue, list)
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+       INIT_LIST_HEAD(&video->dma_queue);
+       spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+
+       return ret;
+}
+
+static void sun6i_video_stop_streaming(struct vb2_queue *vq)
+{
+       struct sun6i_video *video = vb2_get_drv_priv(vq);
+       struct v4l2_subdev *subdev;
+       unsigned long flags;
+       struct sun6i_csi_buffer *buf;
+
+       subdev = sun6i_video_remote_subdev(video, NULL);
+       if (subdev)
+               v4l2_subdev_call(subdev, video, s_stream, 0);
+
+       sun6i_csi_set_stream(video->csi, false);
+
+       media_pipeline_stop(&video->vdev.entity);
+
+       /* Release all active buffers */
+       spin_lock_irqsave(&video->dma_queue_lock, flags);
+       list_for_each_entry(buf, &video->dma_queue, list)
+               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+       INIT_LIST_HEAD(&video->dma_queue);
+       spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+}
+
+static void sun6i_video_buffer_queue(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct sun6i_csi_buffer *buf =
+                       container_of(vbuf, struct sun6i_csi_buffer, vb);
+       struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long flags;
+
+       spin_lock_irqsave(&video->dma_queue_lock, flags);
+       buf->queued_to_csi = false;
+       list_add_tail(&buf->list, &video->dma_queue);
+       spin_unlock_irqrestore(&video->dma_queue_lock, flags);
+}
+
+void sun6i_video_frame_done(struct sun6i_video *video)
+{
+       struct sun6i_csi_buffer *buf;
+       struct sun6i_csi_buffer *next_buf;
+       struct vb2_v4l2_buffer *vbuf;
+
+       spin_lock(&video->dma_queue_lock);
+
+       buf = list_first_entry(&video->dma_queue,
+                              struct sun6i_csi_buffer, list);
+       if (list_is_last(&buf->list, &video->dma_queue)) {
+               dev_dbg(video->csi->dev, "Frame dropped!\n");
+               goto unlock;
+       }
+
+       next_buf = list_next_entry(buf, list);
+       /* If a new buffer (#next_buf) had not been queued to CSI, the old
+        * buffer (#buf) is still holding by CSI for storing the next
+        * frame. So, we queue a new buffer (#next_buf) to CSI then wait
+        * for next ISR call.
+        */
+       if (!next_buf->queued_to_csi) {
+               next_buf->queued_to_csi = true;
+               sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
+               dev_dbg(video->csi->dev, "Frame dropped!\n");
+               goto unlock;
+       }
+
+       list_del(&buf->list);
+       vbuf = &buf->vb;
+       vbuf->vb2_buf.timestamp = ktime_get_ns();
+       vbuf->sequence = video->sequence;
+       vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
+
+       /* Prepare buffer for next frame but one.  */
+       if (!list_is_last(&next_buf->list, &video->dma_queue)) {
+               next_buf = list_next_entry(next_buf, list);
+               next_buf->queued_to_csi = true;
+               sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
+       } else {
+               dev_dbg(video->csi->dev, "Next frame will be dropped!\n");
+       }
+
+unlock:
+       video->sequence++;
+       spin_unlock(&video->dma_queue_lock);
+}
+
+static const struct vb2_ops sun6i_csi_vb2_ops = {
+       .queue_setup            = sun6i_video_queue_setup,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+       .buf_prepare            = sun6i_video_buffer_prepare,
+       .start_streaming        = sun6i_video_start_streaming,
+       .stop_streaming         = sun6i_video_stop_streaming,
+       .buf_queue              = sun6i_video_buffer_queue,
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct sun6i_video *video = video_drvdata(file);
+
+       strscpy(cap->driver, "sun6i-video", sizeof(cap->driver));
+       strscpy(cap->card, video->vdev.name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                video->csi->dev->of_node->name);
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       u32 index = f->index;
+
+       if (index >= ARRAY_SIZE(supported_pixformats))
+               return -EINVAL;
+
+       f->pixelformat = supported_pixformats[index];
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct sun6i_video *video = video_drvdata(file);
+
+       *fmt = video->fmt;
+
+       return 0;
+}
+
+static int sun6i_video_try_fmt(struct sun6i_video *video,
+                              struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pixfmt = &f->fmt.pix;
+       int bpp;
+
+       if (!is_pixformat_valid(pixfmt->pixelformat))
+               pixfmt->pixelformat = supported_pixformats[0];
+
+       v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1,
+                             &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);
+
+       bpp = sun6i_csi_get_bpp(pixfmt->pixelformat);
+       pixfmt->bytesperline = (pixfmt->width * bpp) >> 3;
+       pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+       if (pixfmt->field == V4L2_FIELD_ANY)
+               pixfmt->field = V4L2_FIELD_NONE;
+
+       pixfmt->colorspace = V4L2_COLORSPACE_RAW;
+       pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+       pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       return 0;
+}
+
+static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f)
+{
+       int ret;
+
+       ret = sun6i_video_try_fmt(video, f);
+       if (ret)
+               return ret;
+
+       video->fmt = *f;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct sun6i_video *video = video_drvdata(file);
+
+       if (vb2_is_busy(&video->vb2_vidq))
+               return -EBUSY;
+
+       return sun6i_video_set_fmt(video, f);
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct sun6i_video *video = video_drvdata(file);
+
+       return sun6i_video_try_fmt(video, f);
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index != 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
+       .vidioc_querycap                = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = vidioc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = vidioc_try_fmt_vid_cap,
+
+       .vidioc_enum_input              = vidioc_enum_input,
+       .vidioc_s_input                 = vidioc_s_input,
+       .vidioc_g_input                 = vidioc_g_input,
+
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_expbuf                  = vb2_ioctl_expbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+static int sun6i_video_open(struct file *file)
+{
+       struct sun6i_video *video = video_drvdata(file);
+       int ret;
+
+       if (mutex_lock_interruptible(&video->lock))
+               return -ERESTARTSYS;
+
+       ret = v4l2_fh_open(file);
+       if (ret < 0)
+               goto unlock;
+
+       ret = v4l2_pipeline_pm_use(&video->vdev.entity, 1);
+       if (ret < 0)
+               goto fh_release;
+
+       /* check if already powered */
+       if (!v4l2_fh_is_singular_file(file))
+               goto unlock;
+
+       ret = sun6i_csi_set_power(video->csi, true);
+       if (ret < 0)
+               goto fh_release;
+
+       mutex_unlock(&video->lock);
+       return 0;
+
+fh_release:
+       v4l2_fh_release(file);
+unlock:
+       mutex_unlock(&video->lock);
+       return ret;
+}
+
+static int sun6i_video_close(struct file *file)
+{
+       struct sun6i_video *video = video_drvdata(file);
+       bool last_fh;
+
+       mutex_lock(&video->lock);
+
+       last_fh = v4l2_fh_is_singular_file(file);
+
+       _vb2_fop_release(file, NULL);
+
+       v4l2_pipeline_pm_use(&video->vdev.entity, 0);
+
+       if (last_fh)
+               sun6i_csi_set_power(video->csi, false);
+
+       mutex_unlock(&video->lock);
+
+       return 0;
+}
+
+static const struct v4l2_file_operations sun6i_video_fops = {
+       .owner          = THIS_MODULE,
+       .open           = sun6i_video_open,
+       .release        = sun6i_video_close,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
+       .poll           = vb2_fop_poll
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+static int sun6i_video_link_validate_get_format(struct media_pad *pad,
+                                               struct v4l2_subdev_format *fmt)
+{
+       if (is_media_entity_v4l2_subdev(pad->entity)) {
+               struct v4l2_subdev *sd =
+                               media_entity_to_v4l2_subdev(pad->entity);
+
+               fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+               fmt->pad = pad->index;
+               return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
+       }
+
+       return -EINVAL;
+}
+
+static int sun6i_video_link_validate(struct media_link *link)
+{
+       struct video_device *vdev = container_of(link->sink->entity,
+                                                struct video_device, entity);
+       struct sun6i_video *video = video_get_drvdata(vdev);
+       struct v4l2_subdev_format source_fmt;
+       int ret;
+
+       video->mbus_code = 0;
+
+       if (!media_entity_remote_pad(link->sink->entity->pads)) {
+               dev_info(video->csi->dev,
+                        "video node %s pad not connected\n", vdev->name);
+               return -ENOLINK;
+       }
+
+       ret = sun6i_video_link_validate_get_format(link->source, &source_fmt);
+       if (ret < 0)
+               return ret;
+
+       if (!sun6i_csi_is_format_supported(video->csi,
+                                          video->fmt.fmt.pix.pixelformat,
+                                          source_fmt.format.code)) {
+               dev_err(video->csi->dev,
+                       "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
+                       video->fmt.fmt.pix.pixelformat,
+                       source_fmt.format.code);
+               return -EPIPE;
+       }
+
+       if (source_fmt.format.width != video->fmt.fmt.pix.width ||
+           source_fmt.format.height != video->fmt.fmt.pix.height) {
+               dev_err(video->csi->dev,
+                       "Wrong width or height %ux%u (%ux%u expected)\n",
+                       video->fmt.fmt.pix.width, video->fmt.fmt.pix.height,
+                       source_fmt.format.width, source_fmt.format.height);
+               return -EPIPE;
+       }
+
+       video->mbus_code = source_fmt.format.code;
+
+       return 0;
+}
+
+static const struct media_entity_operations sun6i_video_media_ops = {
+       .link_validate = sun6i_video_link_validate
+};
+
+int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
+                    const char *name)
+{
+       struct video_device *vdev = &video->vdev;
+       struct vb2_queue *vidq = &video->vb2_vidq;
+       struct v4l2_format fmt = { 0 };
+       int ret;
+
+       video->csi = csi;
+
+       /* Initialize the media entity... */
+       video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+       vdev->entity.ops = &sun6i_video_media_ops;
+       ret = media_entity_pads_init(&vdev->entity, 1, &video->pad);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&video->lock);
+
+       INIT_LIST_HEAD(&video->dma_queue);
+       spin_lock_init(&video->dma_queue_lock);
+
+       video->sequence = 0;
+
+       /* Setup default format */
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix.pixelformat = supported_pixformats[0];
+       fmt.fmt.pix.width = 1280;
+       fmt.fmt.pix.height = 720;
+       fmt.fmt.pix.field = V4L2_FIELD_NONE;
+       sun6i_video_set_fmt(video, &fmt);
+
+       /* Initialize videobuf2 queue */
+       vidq->type                      = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vidq->io_modes                  = VB2_MMAP | VB2_DMABUF;
+       vidq->drv_priv                  = video;
+       vidq->buf_struct_size           = sizeof(struct sun6i_csi_buffer);
+       vidq->ops                       = &sun6i_csi_vb2_ops;
+       vidq->mem_ops                   = &vb2_dma_contig_memops;
+       vidq->timestamp_flags           = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       vidq->lock                      = &video->lock;
+       /* Make sure non-dropped frame */
+       vidq->min_buffers_needed        = 3;
+       vidq->dev                       = csi->dev;
+
+       ret = vb2_queue_init(vidq);
+       if (ret) {
+               v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret);
+               goto clean_entity;
+       }
+
+       /* Register video device */
+       strlcpy(vdev->name, name, sizeof(vdev->name));
+       vdev->release           = video_device_release_empty;
+       vdev->fops              = &sun6i_video_fops;
+       vdev->ioctl_ops         = &sun6i_video_ioctl_ops;
+       vdev->vfl_type          = VFL_TYPE_GRABBER;
+       vdev->vfl_dir           = VFL_DIR_RX;
+       vdev->v4l2_dev          = &csi->v4l2_dev;
+       vdev->queue             = vidq;
+       vdev->lock              = &video->lock;
+       vdev->device_caps       = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+       video_set_drvdata(vdev, video);
+
+       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               v4l2_err(&csi->v4l2_dev,
+                        "video_register_device failed: %d\n", ret);
+               goto release_vb2;
+       }
+
+       return 0;
+
+release_vb2:
+       vb2_queue_release(&video->vb2_vidq);
+clean_entity:
+       media_entity_cleanup(&video->vdev.entity);
+       mutex_destroy(&video->lock);
+       return ret;
+}
+
+void sun6i_video_cleanup(struct sun6i_video *video)
+{
+       video_unregister_device(&video->vdev);
+       media_entity_cleanup(&video->vdev.entity);
+       vb2_queue_release(&video->vb2_vidq);
+       mutex_destroy(&video->lock);
+}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h
new file mode 100644 (file)
index 0000000..b9cd919
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
+ * All rights reserved.
+ * Author: Yong Deng <yong.deng@magewell.com>
+ */
+
+#ifndef __SUN6I_VIDEO_H__
+#define __SUN6I_VIDEO_H__
+
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+
+struct sun6i_csi;
+
+struct sun6i_video {
+       struct video_device             vdev;
+       struct media_pad                pad;
+       struct sun6i_csi                *csi;
+
+       struct mutex                    lock;
+
+       struct vb2_queue                vb2_vidq;
+       spinlock_t                      dma_queue_lock;
+       struct list_head                dma_queue;
+
+       unsigned int                    sequence;
+       struct v4l2_format              fmt;
+       u32                             mbus_code;
+};
+
+int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
+                    const char *name);
+void sun6i_video_cleanup(struct sun6i_video *video);
+
+void sun6i_video_frame_done(struct sun6i_video *video);
+
+#endif /* __SUN6I_VIDEO_H__ */
index 95a093f41905d218f2fe746a637dfc0921d7559f..fc3c212b96e13997da343f27d8f5f1c13eb50c57 100644 (file)
@@ -1615,7 +1615,7 @@ of_get_next_port(const struct device_node *parent,
                                return NULL;
                        }
                        prev = port;
-               } while (of_node_cmp(port->name, "port") != 0);
+               } while (!of_node_name_eq(port, "port"));
        }
 
        return port;
@@ -1635,7 +1635,7 @@ of_get_next_endpoint(const struct device_node *parent,
                if (!ep)
                        return NULL;
                prev = ep;
-       } while (of_node_cmp(ep->name, "endpoint") != 0);
+       } while (!of_node_name_eq(ep, "endpoint"));
 
        return ep;
 }
index 36656031b2956f2a0ab568648b9e3e0fbf065cbb..5630f1dc45e649eaa569ed3ec0fed9f1d22dc2cd 100644 (file)
@@ -753,31 +753,49 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm,
        __be16 *rlco = cf->rlc_data;
        __be16 *rlco_max;
        u32 encoding;
-       u32 chroma_h = frm->height / frm->height_div;
-       u32 chroma_w = frm->width / frm->width_div;
-       unsigned int chroma_size = chroma_h * chroma_w;
 
        rlco_max = rlco + size / 2 - 256;
        encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf,
                                frm->height, frm->width,
-                               frm->luma_step, is_intra, next_is_intra);
+                               frm->luma_alpha_step, is_intra, next_is_intra);
        if (encoding & FWHT_FRAME_UNENCODED)
                encoding |= FWHT_LUMA_UNENCODED;
        encoding &= ~FWHT_FRAME_UNENCODED;
-       rlco_max = rlco + chroma_size / 2 - 256;
-       encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, cf,
-                                chroma_h, chroma_w,
-                                frm->chroma_step, is_intra, next_is_intra);
-       if (encoding & FWHT_FRAME_UNENCODED)
-               encoding |= FWHT_CB_UNENCODED;
-       encoding &= ~FWHT_FRAME_UNENCODED;
-       rlco_max = rlco + chroma_size / 2 - 256;
-       encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, cf,
-                                chroma_h, chroma_w,
-                                frm->chroma_step, is_intra, next_is_intra);
-       if (encoding & FWHT_FRAME_UNENCODED)
-               encoding |= FWHT_CR_UNENCODED;
-       encoding &= ~FWHT_FRAME_UNENCODED;
+
+       if (frm->components_num >= 3) {
+               u32 chroma_h = frm->height / frm->height_div;
+               u32 chroma_w = frm->width / frm->width_div;
+               unsigned int chroma_size = chroma_h * chroma_w;
+
+               rlco_max = rlco + chroma_size / 2 - 256;
+               encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max,
+                                        cf, chroma_h, chroma_w,
+                                        frm->chroma_step,
+                                        is_intra, next_is_intra);
+               if (encoding & FWHT_FRAME_UNENCODED)
+                       encoding |= FWHT_CB_UNENCODED;
+               encoding &= ~FWHT_FRAME_UNENCODED;
+               rlco_max = rlco + chroma_size / 2 - 256;
+               encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max,
+                                        cf, chroma_h, chroma_w,
+                                        frm->chroma_step,
+                                        is_intra, next_is_intra);
+               if (encoding & FWHT_FRAME_UNENCODED)
+                       encoding |= FWHT_CR_UNENCODED;
+               encoding &= ~FWHT_FRAME_UNENCODED;
+       }
+
+       if (frm->components_num == 4) {
+               rlco_max = rlco + size / 2 - 256;
+               encoding = encode_plane(frm->alpha, ref_frm->alpha, &rlco,
+                                       rlco_max, cf, frm->height, frm->width,
+                                       frm->luma_alpha_step,
+                                       is_intra, next_is_intra);
+               if (encoding & FWHT_FRAME_UNENCODED)
+                       encoding |= FWHT_ALPHA_UNENCODED;
+               encoding &= ~FWHT_FRAME_UNENCODED;
+       }
+
        cf->size = (rlco - cf->rlc_data) * sizeof(*rlco);
        return encoding;
 }
@@ -836,20 +854,28 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
 }
 
 void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
-                      u32 hdr_flags)
+                      u32 hdr_flags, unsigned int components_num)
 {
        const __be16 *rlco = cf->rlc_data;
-       u32 h = cf->height / 2;
-       u32 w = cf->width / 2;
 
-       if (hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)
-               h *= 2;
-       if (hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)
-               w *= 2;
        decode_plane(cf, &rlco, ref->luma, cf->height, cf->width,
                     hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED);
-       decode_plane(cf, &rlco, ref->cb, h, w,
-                    hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED);
-       decode_plane(cf, &rlco, ref->cr, h, w,
-                    hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED);
+
+       if (components_num >= 3) {
+               u32 h = cf->height;
+               u32 w = cf->width;
+
+               if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT))
+                       h /= 2;
+               if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH))
+                       w /= 2;
+               decode_plane(cf, &rlco, ref->cb, h, w,
+                            hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED);
+               decode_plane(cf, &rlco, ref->cr, h, w,
+                            hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED);
+       }
+
+       if (components_num == 4)
+               decode_plane(cf, &rlco, ref->alpha, cf->height, cf->width,
+                            hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED);
 }
index 3e9391fec5fe6713b66c59727fa2c686eca426b8..90ff8962fca732e341687c6d08b69923da49cb30 100644 (file)
@@ -56,7 +56,7 @@
 #define FWHT_MAGIC1 0x4f4f4f4f
 #define FWHT_MAGIC2 0xffffffff
 
-#define FWHT_VERSION 1
+#define FWHT_VERSION 2
 
 /* Set if this is an interlaced format */
 #define FWHT_FL_IS_INTERLACED          BIT(0)
 #define FWHT_FL_CR_IS_UNCOMPRESSED     BIT(6)
 #define FWHT_FL_CHROMA_FULL_HEIGHT     BIT(7)
 #define FWHT_FL_CHROMA_FULL_WIDTH      BIT(8)
+#define FWHT_FL_ALPHA_IS_UNCOMPRESSED  BIT(9)
+
+/* A 4-values flag - the number of components - 1 */
+#define FWHT_FL_COMPONENTS_NUM_MSK     GENMASK(17, 16)
+#define FWHT_FL_COMPONENTS_NUM_OFFSET  16
 
 struct fwht_cframe_hdr {
        u32 magic1;
@@ -104,9 +109,10 @@ struct fwht_raw_frame {
        unsigned int width, height;
        unsigned int width_div;
        unsigned int height_div;
-       unsigned int luma_step;
+       unsigned int luma_alpha_step;
        unsigned int chroma_step;
-       u8 *luma, *cb, *cr;
+       unsigned int components_num;
+       u8 *luma, *cb, *cr, *alpha;
 };
 
 #define FWHT_FRAME_PCODED      BIT(0)
@@ -114,12 +120,13 @@ struct fwht_raw_frame {
 #define FWHT_LUMA_UNENCODED    BIT(2)
 #define FWHT_CB_UNENCODED      BIT(3)
 #define FWHT_CR_UNENCODED      BIT(4)
+#define FWHT_ALPHA_UNENCODED   BIT(5)
 
 u32 fwht_encode_frame(struct fwht_raw_frame *frm,
                      struct fwht_raw_frame *ref_frm,
                      struct fwht_cframe *cf,
                      bool is_intra, bool next_is_intra);
 void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
-                      u32 hdr_flags);
+                      u32 hdr_flags, unsigned int components_num);
 
 #endif
index e5b68fb38aacdc9c286552d4a0a371960fdc6b80..8cb0212df67f18daa3e8a0c196118183eefcb7f1 100644 (file)
 #include "codec-v4l2-fwht.h"
 
 static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
-       { V4L2_PIX_FMT_YUV420,  1, 3, 2, 1, 1, 2, 2 },
-       { V4L2_PIX_FMT_YVU420,  1, 3, 2, 1, 1, 2, 2 },
-       { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1 },
-       { V4L2_PIX_FMT_NV12,    1, 3, 2, 1, 2, 2, 2 },
-       { V4L2_PIX_FMT_NV21,    1, 3, 2, 1, 2, 2, 2 },
-       { V4L2_PIX_FMT_NV16,    1, 2, 1, 1, 2, 2, 1 },
-       { V4L2_PIX_FMT_NV61,    1, 2, 1, 1, 2, 2, 1 },
-       { V4L2_PIX_FMT_NV24,    1, 3, 1, 1, 2, 1, 1 },
-       { V4L2_PIX_FMT_NV42,    1, 3, 1, 1, 2, 1, 1 },
-       { V4L2_PIX_FMT_YUYV,    2, 2, 1, 2, 4, 2, 1 },
-       { V4L2_PIX_FMT_YVYU,    2, 2, 1, 2, 4, 2, 1 },
-       { V4L2_PIX_FMT_UYVY,    2, 2, 1, 2, 4, 2, 1 },
-       { V4L2_PIX_FMT_VYUY,    2, 2, 1, 2, 4, 2, 1 },
-       { V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1 },
-       { V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1 },
-       { V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1 },
-       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1 },
-       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1 },
-       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1 },
-       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1 },
-       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1 },
+       { V4L2_PIX_FMT_YUV420,  1, 3, 2, 1, 1, 2, 2, 3},
+       { V4L2_PIX_FMT_YVU420,  1, 3, 2, 1, 1, 2, 2, 3},
+       { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3},
+       { V4L2_PIX_FMT_NV12,    1, 3, 2, 1, 2, 2, 2, 3},
+       { V4L2_PIX_FMT_NV21,    1, 3, 2, 1, 2, 2, 2, 3},
+       { V4L2_PIX_FMT_NV16,    1, 2, 1, 1, 2, 2, 1, 3},
+       { V4L2_PIX_FMT_NV61,    1, 2, 1, 1, 2, 2, 1, 3},
+       { V4L2_PIX_FMT_NV24,    1, 3, 1, 1, 2, 1, 1, 3},
+       { V4L2_PIX_FMT_NV42,    1, 3, 1, 1, 2, 1, 1, 3},
+       { V4L2_PIX_FMT_YUYV,    2, 2, 1, 2, 4, 2, 1, 3},
+       { V4L2_PIX_FMT_YVYU,    2, 2, 1, 2, 4, 2, 1, 3},
+       { V4L2_PIX_FMT_UYVY,    2, 2, 1, 2, 4, 2, 1, 3},
+       { V4L2_PIX_FMT_VYUY,    2, 2, 1, 2, 4, 2, 1, 3},
+       { V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3},
+       { V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3},
+       { V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3},
+       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 3},
+       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 3},
+       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 3},
+       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 3},
+       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 3},
+       { V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4},
+       { V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4},
+       { V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1},
 };
 
 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
@@ -68,10 +71,16 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
        rf.luma = p_in;
        rf.width_div = info->width_div;
        rf.height_div = info->height_div;
-       rf.luma_step = info->luma_step;
+       rf.luma_alpha_step = info->luma_alpha_step;
        rf.chroma_step = info->chroma_step;
+       rf.alpha = NULL;
+       rf.components_num = info->components_num;
 
        switch (info->id) {
+       case V4L2_PIX_FMT_GREY:
+               rf.cb = NULL;
+               rf.cr = NULL;
+               break;
        case V4L2_PIX_FMT_YUV420:
                rf.cb = rf.luma + size;
                rf.cr = rf.cb + size / 4;
@@ -138,6 +147,18 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
                rf.cr = rf.cb + 2;
                rf.luma++;
                break;
+       case V4L2_PIX_FMT_ARGB32:
+               rf.alpha = rf.luma;
+               rf.cr = rf.luma + 1;
+               rf.cb = rf.cr + 2;
+               rf.luma += 2;
+               break;
+       case V4L2_PIX_FMT_ABGR32:
+               rf.cb = rf.luma;
+               rf.cr = rf.cb + 2;
+               rf.luma++;
+               rf.alpha = rf.cr + 1;
+               break;
        default:
                return -EINVAL;
        }
@@ -162,12 +183,15 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
        p_hdr->version = htonl(FWHT_VERSION);
        p_hdr->width = htonl(cf.width);
        p_hdr->height = htonl(cf.height);
+       flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET;
        if (encoding & FWHT_LUMA_UNENCODED)
                flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED;
        if (encoding & FWHT_CB_UNENCODED)
                flags |= FWHT_FL_CB_IS_UNCOMPRESSED;
        if (encoding & FWHT_CR_UNENCODED)
                flags |= FWHT_FL_CR_IS_UNCOMPRESSED;
+       if (encoding & FWHT_ALPHA_UNENCODED)
+               flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED;
        if (rf.height_div == 1)
                flags |= FWHT_FL_CHROMA_FULL_HEIGHT;
        if (rf.width_div == 1)
@@ -192,6 +216,8 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
        struct fwht_cframe_hdr *p_hdr;
        struct fwht_cframe cf;
        u8 *p;
+       unsigned int components_num = 3;
+       unsigned int version;
 
        if (!state->info)
                return -EINVAL;
@@ -199,16 +225,16 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
        p_hdr = (struct fwht_cframe_hdr *)p_in;
        cf.width = ntohl(p_hdr->width);
        cf.height = ntohl(p_hdr->height);
-       flags = ntohl(p_hdr->flags);
-       state->colorspace = ntohl(p_hdr->colorspace);
-       state->xfer_func = ntohl(p_hdr->xfer_func);
-       state->ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
-       state->quantization = ntohl(p_hdr->quantization);
-       cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr));
+
+       version = ntohl(p_hdr->version);
+       if (!version || version > FWHT_VERSION) {
+               pr_err("version %d is not supported, current version is %d\n",
+                      version, FWHT_VERSION);
+               return -EINVAL;
+       }
 
        if (p_hdr->magic1 != FWHT_MAGIC1 ||
            p_hdr->magic2 != FWHT_MAGIC2 ||
-           ntohl(p_hdr->version) != FWHT_VERSION ||
            (cf.width & 7) || (cf.height & 7))
                return -EINVAL;
 
@@ -216,14 +242,34 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
        if (cf.width != state->width || cf.height != state->height)
                return -EINVAL;
 
+       flags = ntohl(p_hdr->flags);
+
+       if (version == FWHT_VERSION) {
+               components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
+                       FWHT_FL_COMPONENTS_NUM_OFFSET);
+       }
+
+       state->colorspace = ntohl(p_hdr->colorspace);
+       state->xfer_func = ntohl(p_hdr->xfer_func);
+       state->ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
+       state->quantization = ntohl(p_hdr->quantization);
+       cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr));
+
        if (!(flags & FWHT_FL_CHROMA_FULL_WIDTH))
                chroma_size /= 2;
        if (!(flags & FWHT_FL_CHROMA_FULL_HEIGHT))
                chroma_size /= 2;
 
-       fwht_decode_frame(&cf, &state->ref_frame, flags);
+       fwht_decode_frame(&cf, &state->ref_frame, flags, components_num);
 
+       /*
+        * TODO - handle the case where the compressed stream encodes a
+        * different format than the requested decoded format.
+        */
        switch (state->info->id) {
+       case V4L2_PIX_FMT_GREY:
+               memcpy(p_out, state->ref_frame.luma, size);
+               break;
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YUV422P:
                memcpy(p_out, state->ref_frame.luma, size);
@@ -325,6 +371,22 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
                        *p++ = 0;
                }
                break;
+       case V4L2_PIX_FMT_ARGB32:
+               for (i = 0, p = p_out; i < size; i++) {
+                       *p++ = state->ref_frame.alpha[i];
+                       *p++ = state->ref_frame.cr[i];
+                       *p++ = state->ref_frame.luma[i];
+                       *p++ = state->ref_frame.cb[i];
+               }
+               break;
+       case V4L2_PIX_FMT_ABGR32:
+               for (i = 0, p = p_out; i < size; i++) {
+                       *p++ = state->ref_frame.cb[i];
+                       *p++ = state->ref_frame.luma[i];
+                       *p++ = state->ref_frame.cr[i];
+                       *p++ = state->ref_frame.alpha[i];
+               }
+               break;
        default:
                return -EINVAL;
        }
index 162465b78067e5adcfa914aecf680959f66ab233..ed53e28d4f9c10c3429fd1bd68f49562dd028f2b 100644 (file)
@@ -13,11 +13,12 @@ struct v4l2_fwht_pixfmt_info {
        unsigned int bytesperline_mult;
        unsigned int sizeimage_mult;
        unsigned int sizeimage_div;
-       unsigned int luma_step;
+       unsigned int luma_alpha_step;
        unsigned int chroma_step;
        /* Chroma plane subsampling */
        unsigned int width_div;
        unsigned int height_div;
+       unsigned int components_num;
 };
 
 struct v4l2_fwht_state {
index 13fb69c58967d0dbf527c4e0f39653410550da5d..0d7876f5acf0dc132443d123cf345ae44dc7274a 100644 (file)
@@ -61,7 +61,7 @@ struct pixfmt_info {
 };
 
 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
-       V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1
+       V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0
 };
 
 static void vicodec_dev_release(struct device *dev)
@@ -151,52 +151,52 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
 }
 
 static int device_process(struct vicodec_ctx *ctx,
-                         struct vb2_v4l2_buffer *in_vb,
-                         struct vb2_v4l2_buffer *out_vb)
+                         struct vb2_v4l2_buffer *src_vb,
+                         struct vb2_v4l2_buffer *dst_vb)
 {
        struct vicodec_dev *dev = ctx->dev;
-       struct vicodec_q_data *q_cap;
+       struct vicodec_q_data *q_dst;
        struct v4l2_fwht_state *state = &ctx->state;
-       u8 *p_in, *p_out;
+       u8 *p_src, *p_dst;
        int ret;
 
-       q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        if (ctx->is_enc)
-               p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
+               p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
        else
-               p_in = state->compressed_frame;
-       p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
-       if (!p_in || !p_out) {
+               p_src = state->compressed_frame;
+       p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
+       if (!p_src || !p_dst) {
                v4l2_err(&dev->v4l2_dev,
                         "Acquiring kernel pointers to buffers failed\n");
                return -EFAULT;
        }
 
        if (ctx->is_enc) {
-               struct vicodec_q_data *q_out;
+               struct vicodec_q_data *q_src;
 
-               q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-               state->info = q_out->info;
-               ret = v4l2_fwht_encode(state, p_in, p_out);
+               q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               state->info = q_src->info;
+               ret = v4l2_fwht_encode(state, p_src, p_dst);
                if (ret < 0)
                        return ret;
-               vb2_set_plane_payload(&out_vb->vb2_buf, 0, ret);
+               vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
        } else {
-               state->info = q_cap->info;
-               ret = v4l2_fwht_decode(state, p_in, p_out);
+               state->info = q_dst->info;
+               ret = v4l2_fwht_decode(state, p_src, p_dst);
                if (ret < 0)
                        return ret;
-               vb2_set_plane_payload(&out_vb->vb2_buf, 0, q_cap->sizeimage);
+               vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
        }
 
-       out_vb->sequence = q_cap->sequence++;
-       out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
+       dst_vb->sequence = q_dst->sequence++;
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
 
-       if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
-               out_vb->timecode = in_vb->timecode;
-       out_vb->field = in_vb->field;
-       out_vb->flags &= ~V4L2_BUF_FLAG_LAST;
-       out_vb->flags |= in_vb->flags &
+       if (src_vb->flags & V4L2_BUF_FLAG_TIMECODE)
+               dst_vb->timecode = src_vb->timecode;
+       dst_vb->field = src_vb->field;
+       dst_vb->flags &= ~V4L2_BUF_FLAG_LAST;
+       dst_vb->flags |= src_vb->flags &
                (V4L2_BUF_FLAG_TIMECODE |
                 V4L2_BUF_FLAG_KEYFRAME |
                 V4L2_BUF_FLAG_PFRAME |
@@ -219,12 +219,12 @@ static void device_run(void *priv)
        struct vicodec_ctx *ctx = priv;
        struct vicodec_dev *dev = ctx->dev;
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       struct vicodec_q_data *q_out;
+       struct vicodec_q_data *q_src;
        u32 state;
 
        src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-       q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 
        state = VB2_BUF_STATE_DONE;
        if (device_process(ctx, src_buf, dst_buf))
@@ -237,11 +237,11 @@ static void device_run(void *priv)
                v4l2_event_queue_fh(&ctx->fh, &eos_event);
        }
        if (ctx->is_enc) {
-               src_buf->sequence = q_out->sequence++;
+               src_buf->sequence = q_src->sequence++;
                src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
                v4l2_m2m_buf_done(src_buf, state);
        } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
-               src_buf->sequence = q_out->sequence++;
+               src_buf->sequence = q_src->sequence++;
                src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
                v4l2_m2m_buf_done(src_buf, state);
                ctx->cur_buf_offset = 0;
@@ -259,15 +259,15 @@ static void device_run(void *priv)
                v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
 }
 
-static void job_remove_out_buf(struct vicodec_ctx *ctx, u32 state)
+static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
 {
        struct vb2_v4l2_buffer *src_buf;
-       struct vicodec_q_data *q_out;
+       struct vicodec_q_data *q_src;
 
-       q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        spin_lock(ctx->lock);
        src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-       src_buf->sequence = q_out->sequence++;
+       src_buf->sequence = q_src->sequence++;
        v4l2_m2m_buf_done(src_buf, state);
        ctx->cur_buf_offset = 0;
        spin_unlock(ctx->lock);
@@ -280,7 +280,7 @@ static int job_ready(void *priv)
        };
        struct vicodec_ctx *ctx = priv;
        struct vb2_v4l2_buffer *src_buf;
-       u8 *p_out;
+       u8 *p_src;
        u8 *p;
        u32 sz;
        u32 state;
@@ -293,26 +293,27 @@ restart:
        src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        if (!src_buf)
                return 0;
-       p_out = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
+       p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
        sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
-       p = p_out + ctx->cur_buf_offset;
+       p = p_src + ctx->cur_buf_offset;
 
        state = VB2_BUF_STATE_DONE;
 
        if (!ctx->comp_size) {
                state = VB2_BUF_STATE_ERROR;
-               for (; p < p_out + sz; p++) {
+               for (; p < p_src + sz; p++) {
                        u32 copy;
 
                        p = memchr(p, magic[ctx->comp_magic_cnt],
-                                  p_out + sz - p);
+                                  p_src + sz - p);
                        if (!p) {
                                ctx->comp_magic_cnt = 0;
                                break;
                        }
                        copy = sizeof(magic) - ctx->comp_magic_cnt;
-                       if (p_out + sz - p < copy)
-                               copy = p_out + sz - p;
+                       if (p_src + sz - p < copy)
+                               copy = p_src + sz - p;
+
                        memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt,
                               p, copy);
                        ctx->comp_magic_cnt += copy;
@@ -325,7 +326,7 @@ restart:
                        ctx->comp_magic_cnt = 0;
                }
                if (ctx->comp_magic_cnt < sizeof(magic)) {
-                       job_remove_out_buf(ctx, state);
+                       job_remove_src_buf(ctx, state);
                        goto restart;
                }
                ctx->comp_size = sizeof(magic);
@@ -335,14 +336,14 @@ restart:
                        (struct fwht_cframe_hdr *)ctx->state.compressed_frame;
                u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size;
 
-               if (copy > p_out + sz - p)
-                       copy = p_out + sz - p;
+               if (copy > p_src + sz - p)
+                       copy = p_src + sz - p;
                memcpy(ctx->state.compressed_frame + ctx->comp_size,
                       p, copy);
                p += copy;
                ctx->comp_size += copy;
                if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
-                       job_remove_out_buf(ctx, state);
+                       job_remove_src_buf(ctx, state);
                        goto restart;
                }
                ctx->comp_frame_size = ntohl(p_hdr->size) + sizeof(*p_hdr);
@@ -352,18 +353,19 @@ restart:
        if (ctx->comp_size < ctx->comp_frame_size) {
                u32 copy = ctx->comp_frame_size - ctx->comp_size;
 
-               if (copy > p_out + sz - p)
-                       copy = p_out + sz - p;
+               if (copy > p_src + sz - p)
+                       copy = p_src + sz - p;
+
                memcpy(ctx->state.compressed_frame + ctx->comp_size,
                       p, copy);
                p += copy;
                ctx->comp_size += copy;
                if (ctx->comp_size < ctx->comp_frame_size) {
-                       job_remove_out_buf(ctx, state);
+                       job_remove_src_buf(ctx, state);
                        goto restart;
                }
        }
-       ctx->cur_buf_offset = p - p_out;
+       ctx->cur_buf_offset = p - p_src;
        ctx->comp_has_frame = true;
        ctx->comp_has_next_frame = false;
        if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) {
@@ -398,11 +400,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                        "platform:%s", VICODEC_NAME);
-       cap->device_caps =  V4L2_CAP_STREAMING |
-                           (multiplanar ?
-                            V4L2_CAP_VIDEO_M2M_MPLANE :
-                            V4L2_CAP_VIDEO_M2M);
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -994,6 +991,18 @@ static int vicodec_start_streaming(struct vb2_queue *q,
        unsigned int size = q_data->width * q_data->height;
        const struct v4l2_fwht_pixfmt_info *info = q_data->info;
        unsigned int chroma_div = info->width_div * info->height_div;
+       unsigned int total_planes_size;
+
+       /*
+        * we don't know ahead how many components are in the encoding type
+        * V4L2_PIX_FMT_FWHT, so we will allocate space for 4 planes.
+        */
+       if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
+               total_planes_size = 2 * size + 2 * (size / chroma_div);
+       else if (info->components_num == 3)
+               total_planes_size = size + 2 * (size / chroma_div);
+       else
+               total_planes_size = size;
 
        q_data->sequence = 0;
 
@@ -1010,10 +1019,8 @@ static int vicodec_start_streaming(struct vb2_queue *q,
                state->height = q_data->height;
        }
        state->ref_frame.width = state->ref_frame.height = 0;
-       state->ref_frame.luma = kvmalloc(size + 2 * size / chroma_div,
-                                        GFP_KERNEL);
-       ctx->comp_max_size = size + 2 * size / chroma_div +
-                            sizeof(struct fwht_cframe_hdr);
+       state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
+       ctx->comp_max_size = total_planes_size + sizeof(struct fwht_cframe_hdr);
        state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
        if (!state->ref_frame.luma || !state->compressed_frame) {
                kvfree(state->ref_frame.luma);
@@ -1021,8 +1028,20 @@ static int vicodec_start_streaming(struct vb2_queue *q,
                vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
                return -ENOMEM;
        }
-       state->ref_frame.cb = state->ref_frame.luma + size;
-       state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
+       if (info->id == V4L2_PIX_FMT_FWHT || info->components_num >= 3) {
+               state->ref_frame.cb = state->ref_frame.luma + size;
+               state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
+       } else {
+               state->ref_frame.cb = NULL;
+               state->ref_frame.cr = NULL;
+       }
+
+       if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
+               state->ref_frame.alpha =
+                       state->ref_frame.cr + size / chroma_div;
+       else
+               state->ref_frame.alpha = NULL;
+
        ctx->last_src_buf = NULL;
        ctx->last_dst_buf = NULL;
        state->gop_cnt = 0;
@@ -1116,7 +1135,7 @@ static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static struct v4l2_ctrl_ops vicodec_ctrl_ops = {
+static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
        .s_ctrl = vicodec_s_ctrl,
 };
 
@@ -1319,6 +1338,8 @@ static int vicodec_probe(struct platform_device *pdev)
        vfd->lock = &dev->enc_mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
        strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
+       vfd->device_caps = V4L2_CAP_STREAMING |
+               (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
        v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
        v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
        video_set_drvdata(vfd, dev);
@@ -1335,6 +1356,8 @@ static int vicodec_probe(struct platform_device *pdev)
        vfd = &dev->dec_vfd;
        vfd->lock = &dev->dec_mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->device_caps = V4L2_CAP_STREAMING |
+               (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
        strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
        v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
        v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
index d82db738f174ef048d663d366b4950cd732c2b43..d01821a6906a778ffb20b810b72ab21d2cb9464a 100644 (file)
@@ -438,8 +438,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                        "platform:%s", MEM2MEM_NAME);
-       cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -805,10 +803,11 @@ static int vim2m_start_streaming(struct vb2_queue *q, unsigned count)
 static void vim2m_stop_streaming(struct vb2_queue *q)
 {
        struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
+       struct vim2m_dev *dev = ctx->dev;
        struct vb2_v4l2_buffer *vbuf;
        unsigned long flags;
 
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&dev->work_run);
        for (;;) {
                if (V4L2_TYPE_IS_OUTPUT(q->type))
                        vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
@@ -999,6 +998,7 @@ static const struct video_device vim2m_videodev = {
        .ioctl_ops      = &vim2m_ioctl_ops,
        .minor          = -1,
        .release        = video_device_release_empty,
+       .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
 };
 
 static const struct v4l2_m2m_ops m2m_ops = {
index dee1b9dfc4f64ba3a274c8775ad9531a3fa332b4..867e24dbd6b585161f5bfad949f159218bbec879 100644 (file)
@@ -276,6 +276,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable)
 
                /* Start the stream in the subdevice direct connected */
                pad = media_entity_remote_pad(&ent->pads[i]);
+               if (!pad)
+                       continue;
 
                if (!is_media_entity_v4l2_subdev(pad->entity))
                        return -EINVAL;
index edf4c85ae63db7875ab8808614bd01f10ba1794e..32ca9c6172b1796a03f48d14951bdac4bb51cf2f 100644 (file)
@@ -286,7 +286,7 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static struct v4l2_subdev_core_ops vimc_sen_core_ops = {
+static const struct v4l2_subdev_core_ops vimc_sen_core_ops = {
        .log_status = v4l2_ctrl_subdev_log_status,
        .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
        .unsubscribe_event = v4l2_event_subdev_unsubscribe,
index 626e2b24a4033e224e09e195760f3cee9373a074..c931f007e5b0e9f53b85b0bc205d256ff970355a 100644 (file)
@@ -324,13 +324,14 @@ static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timin
        return vivid_vid_out_s_dv_timings(file, fh, timings);
 }
 
-static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *fh,
+                               int type, struct v4l2_fract *f)
 {
        struct video_device *vdev = video_devdata(file);
 
        if (vdev->vfl_dir == VFL_DIR_RX)
-               return vivid_vid_cap_cropcap(file, fh, cc);
-       return vivid_vid_out_cropcap(file, fh, cc);
+               return vivid_vid_cap_g_pixelaspect(file, fh, type, f);
+       return vivid_vid_out_g_pixelaspect(file, fh, type, f);
 }
 
 static int vidioc_g_selection(struct file *file, void *fh,
@@ -519,7 +520,7 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
 
        .vidioc_g_selection             = vidioc_g_selection,
        .vidioc_s_selection             = vidioc_s_selection,
-       .vidioc_cropcap                 = vidioc_cropcap,
+       .vidioc_g_pixelaspect           = vidioc_g_pixelaspect,
 
        .vidioc_g_fmt_vbi_cap           = vidioc_g_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap         = vidioc_g_fmt_vbi_cap,
@@ -624,12 +625,24 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev)
        vfree(dev->bitmap_out);
        tpg_free(&dev->tpg);
        kfree(dev->query_dv_timings_qmenu);
+       kfree(dev->query_dv_timings_qmenu_strings);
        kfree(dev);
 }
 
 #ifdef CONFIG_MEDIA_CONTROLLER
+static int vivid_req_validate(struct media_request *req)
+{
+       struct vivid_dev *dev = container_of(req->mdev, struct vivid_dev, mdev);
+
+       if (dev->req_validate_error) {
+               dev->req_validate_error = false;
+               return -EINVAL;
+       }
+       return vb2_request_validate(req);
+}
+
 static const struct media_device_ops vivid_media_ops = {
-       .req_validate = vb2_request_validate,
+       .req_validate = vivid_req_validate,
        .req_queue = vb2_request_queue,
 };
 #endif
@@ -669,6 +682,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
 
        /* Initialize media device */
        strlcpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
+       snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info),
+                "platform:%s-%03d", VIVID_MODULE_NAME, inst);
        dev->mdev.dev = &pdev->dev;
        media_device_init(&dev->mdev);
        dev->mdev.ops = &vivid_media_ops;
@@ -873,20 +888,31 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
        if (!dev->edid)
                goto free_dev;
 
-       /* create a string array containing the names of all the preset timings */
        while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
                dev->query_dv_timings_size++;
+
+       /*
+        * Create a char pointer array that points to the names of all the
+        * preset timings
+        */
        dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size,
-                                                   (sizeof(void *) + 32),
-                                                   GFP_KERNEL);
-       if (dev->query_dv_timings_qmenu == NULL)
+                                                   sizeof(char *), GFP_KERNEL);
+       /*
+        * Create a string array containing the names of all the preset
+        * timings. Each name is max 31 chars long (+ terminating 0).
+        */
+       dev->query_dv_timings_qmenu_strings =
+               kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL);
+
+       if (!dev->query_dv_timings_qmenu ||
+           !dev->query_dv_timings_qmenu_strings)
                goto free_dev;
+
        for (i = 0; i < dev->query_dv_timings_size; i++) {
                const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
-               char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size];
+               char *p = dev->query_dv_timings_qmenu_strings + i * 32;
                u32 htot, vtot;
 
-               p += i * 32;
                dev->query_dv_timings_qmenu[i] = p;
 
                htot = V4L2_DV_BT_FRAME_WIDTH(bt);
index 1891254c8f0b22dee4565a579ad32a4da62c00d7..6697c70096290b0435b82131e9731e670a745f94 100644 (file)
@@ -294,6 +294,7 @@ struct vivid_dev {
        bool                            buf_prepare_error;
        bool                            start_streaming_error;
        bool                            dqbuf_error;
+       bool                            req_validate_error;
        bool                            seq_wrap;
        bool                            time_wrap;
        u64                             time_wrap_offset;
@@ -305,6 +306,7 @@ struct vivid_dev {
 
        enum vivid_signal_mode          dv_timings_signal_mode;
        char                            **query_dv_timings_qmenu;
+       char                            *query_dv_timings_qmenu_strings;
        unsigned                        query_dv_timings_size;
        unsigned                        query_dv_timings_last;
        unsigned                        query_dv_timings;
@@ -392,6 +394,9 @@ struct vivid_dev {
        /* thread for generating video capture stream */
        struct task_struct              *kthread_vid_cap;
        unsigned long                   jiffies_vid_cap;
+       u64                             cap_stream_start;
+       u64                             cap_frame_period;
+       u64                             cap_frame_eof_offset;
        u32                             cap_seq_offset;
        u32                             cap_seq_count;
        bool                            cap_seq_resync;
index bfffeda12f1410455892104cac9911ba4cb50b1e..4cd526ff248b526b15a2650409141d1291c6e21b 100644 (file)
@@ -81,6 +81,7 @@
 #define VIVID_CID_START_STR_ERROR      (VIVID_CID_VIVID_BASE + 69)
 #define VIVID_CID_QUEUE_ERROR          (VIVID_CID_VIVID_BASE + 70)
 #define VIVID_CID_CLEAR_FB             (VIVID_CID_VIVID_BASE + 71)
+#define VIVID_CID_REQ_VALIDATE_ERROR   (VIVID_CID_VIVID_BASE + 72)
 
 #define VIVID_CID_RADIO_SEEK_MODE      (VIVID_CID_VIVID_BASE + 90)
 #define VIVID_CID_RADIO_SEEK_PROG_LIM  (VIVID_CID_VIVID_BASE + 91)
@@ -1002,6 +1003,9 @@ static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
        case VIVID_CID_START_STR_ERROR:
                dev->start_streaming_error = true;
                break;
+       case VIVID_CID_REQ_VALIDATE_ERROR:
+               dev->req_validate_error = true;
+               break;
        case VIVID_CID_QUEUE_ERROR:
                if (vb2_start_streaming_called(&dev->vb_vid_cap_q))
                        vb2_queue_error(&dev->vb_vid_cap_q);
@@ -1087,6 +1091,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_queue_error = {
        .type = V4L2_CTRL_TYPE_BUTTON,
 };
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+static const struct v4l2_ctrl_config vivid_ctrl_req_validate_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_REQ_VALIDATE_ERROR,
+       .name = "Inject req_validate() Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+#endif
+
 static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = {
        .ops = &vivid_streaming_ctrl_ops,
        .id = VIVID_CID_SEQ_WRAP,
@@ -1516,6 +1529,9 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
                v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL);
                v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL);
                v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL);
+#ifdef CONFIG_MEDIA_CONTROLLER
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_req_validate_error, NULL);
+#endif
                v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL);
                v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL);
        }
index eebfff2126be22f0f50664322a722cefa2616a44..f8006a30c12fb7c2234b00ed70d2b02d1f4008aa 100644 (file)
@@ -425,12 +425,6 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
                is_loop = true;
 
        buf->vb.sequence = dev->vid_cap_seq_count;
-       /*
-        * Take the timestamp now if the timestamp source is set to
-        * "Start of Exposure".
-        */
-       if (dev->tstamp_src_is_soe)
-               buf->vb.vb2_buf.timestamp = ktime_get_ns();
        if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
                /*
                 * 60 Hz standards start with the bottom field, 50 Hz standards
@@ -554,14 +548,6 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
                        }
                }
        }
-
-       /*
-        * If "End of Frame" is specified at the timestamp source, then take
-        * the timestamp now.
-        */
-       if (!dev->tstamp_src_is_soe)
-               buf->vb.vb2_buf.timestamp = ktime_get_ns();
-       buf->vb.vb2_buf.timestamp += dev->time_wrap_offset;
 }
 
 /*
@@ -667,10 +653,28 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
        }
 }
 
+static void vivid_cap_update_frame_period(struct vivid_dev *dev)
+{
+       u64 f_period;
+
+       f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000;
+       do_div(f_period, dev->timeperframe_vid_cap.denominator);
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+               f_period >>= 1;
+       /*
+        * If "End of Frame", then offset the exposure time by 0.9
+        * of the frame period.
+        */
+       dev->cap_frame_eof_offset = f_period * 9;
+       do_div(dev->cap_frame_eof_offset, 10);
+       dev->cap_frame_period = f_period;
+}
+
 static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
 {
        struct vivid_buffer *vid_cap_buf = NULL;
        struct vivid_buffer *vbi_cap_buf = NULL;
+       u64 f_time = 0;
 
        dprintk(dev, 1, "Video Capture Thread Tick\n");
 
@@ -702,6 +706,11 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
        if (!vid_cap_buf && !vbi_cap_buf)
                goto update_mv;
 
+       f_time = dev->cap_frame_period * dev->vid_cap_seq_count +
+                dev->cap_stream_start + dev->time_wrap_offset;
+       if (!dev->tstamp_src_is_soe)
+               f_time += dev->cap_frame_eof_offset;
+
        if (vid_cap_buf) {
                v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req,
                                        &dev->ctrl_hdl_vid_cap);
@@ -721,9 +730,13 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
                dprintk(dev, 2, "vid_cap buffer %d done\n",
                                vid_cap_buf->vb.vb2_buf.index);
+
+               vid_cap_buf->vb.vb2_buf.timestamp = f_time;
        }
 
        if (vbi_cap_buf) {
+               u64 vbi_period;
+
                v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req,
                                        &dev->ctrl_hdl_vbi_cap);
                if (dev->stream_sliced_vbi_cap)
@@ -736,6 +749,11 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
                dprintk(dev, 2, "vbi_cap %d done\n",
                                vbi_cap_buf->vb.vb2_buf.index);
+
+               /* If capturing a VBI, offset by 0.05 */
+               vbi_period = dev->cap_frame_period * 5;
+               do_div(vbi_period, 100);
+               vbi_cap_buf->vb.vb2_buf.timestamp = f_time + vbi_period;
        }
        dev->dqbuf_error = false;
 
@@ -767,6 +785,8 @@ static int vivid_thread_vid_cap(void *data)
        dev->cap_seq_count = 0;
        dev->cap_seq_resync = false;
        dev->jiffies_vid_cap = jiffies;
+       dev->cap_stream_start = ktime_get_ns();
+       vivid_cap_update_frame_period(dev);
 
        for (;;) {
                try_to_freeze();
@@ -779,6 +799,9 @@ static int vivid_thread_vid_cap(void *data)
                        dev->jiffies_vid_cap = cur_jiffies;
                        dev->cap_seq_offset = dev->cap_seq_count + 1;
                        dev->cap_seq_count = 0;
+                       dev->cap_stream_start += dev->cap_frame_period *
+                                                dev->cap_seq_offset;
+                       vivid_cap_update_frame_period(dev);
                        dev->cap_seq_resync = false;
                }
                numerator = dev->timeperframe_vid_cap.numerator;
@@ -873,8 +896,11 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
                        "%s-vid-cap", dev->v4l2_dev.name);
 
        if (IS_ERR(dev->kthread_vid_cap)) {
+               int err = PTR_ERR(dev->kthread_vid_cap);
+
+               dev->kthread_vid_cap = NULL;
                v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               return PTR_ERR(dev->kthread_vid_cap);
+               return err;
        }
        *pstreaming = true;
        vivid_grab_controls(dev, true);
index 5a14810eeb6910a6ff6766aae181494ea9fc2e35..ce5bcda2348c97d4ab6b21ad72faaf6deee2e865 100644 (file)
@@ -244,8 +244,11 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
                        "%s-vid-out", dev->v4l2_dev.name);
 
        if (IS_ERR(dev->kthread_vid_out)) {
+               int err = PTR_ERR(dev->kthread_vid_out);
+
+               dev->kthread_vid_out = NULL;
                v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               return PTR_ERR(dev->kthread_vid_out);
+               return err;
        }
        *pstreaming = true;
        vivid_grab_controls(dev, true);
index d666271bdaeddde6c3c712ca761a4e439d33c77c..40ecd7902b5644640864e8295e5f9c9946ef32bf 100644 (file)
@@ -95,8 +95,6 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
 
        if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
                vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
-
-       buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
 }
 
 
@@ -119,8 +117,6 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev,
                for (i = 0; i < 25; i++)
                        vbuf[i] = dev->vbi_gen.data[i];
        }
-
-       buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
 }
 
 static int vbi_cap_queue_setup(struct vb2_queue *vq,
index 673772cd17d61b22a4073af17268dce226ef475a..c059fc12668a8157b684f50c5dd124abbe23db27 100644 (file)
@@ -449,6 +449,8 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
                tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
                break;
        }
+       vfree(dev->bitmap_cap);
+       dev->bitmap_cap = NULL;
        vivid_update_quality(dev);
        tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
        dev->crop_cap = dev->src_rect;
@@ -1014,26 +1016,24 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
        return 0;
 }
 
-int vivid_vid_cap_cropcap(struct file *file, void *priv,
-                             struct v4l2_cropcap *cap)
+int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct vivid_dev *dev = video_drvdata(file);
 
-       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
        switch (vivid_get_pixel_aspect(dev)) {
        case TPG_PIXEL_ASPECT_NTSC:
-               cap->pixelaspect.numerator = 11;
-               cap->pixelaspect.denominator = 10;
+               f->numerator = 11;
+               f->denominator = 10;
                break;
        case TPG_PIXEL_ASPECT_PAL:
-               cap->pixelaspect.numerator = 54;
-               cap->pixelaspect.denominator = 59;
+               f->numerator = 54;
+               f->denominator = 59;
                break;
-       case TPG_PIXEL_ASPECT_SQUARE:
-               cap->pixelaspect.numerator = 1;
-               cap->pixelaspect.denominator = 1;
+       default:
                break;
        }
        return 0;
@@ -1835,9 +1835,6 @@ int vivid_vid_cap_g_parm(struct file *file, void *priv,
        return 0;
 }
 
-#define FRACT_CMP(a, OP, b)    \
-       ((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
-
 int vivid_vid_cap_s_parm(struct file *file, void *priv,
                          struct v4l2_streamparm *parm)
 {
@@ -1858,14 +1855,14 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv,
        if (tpf.denominator == 0)
                tpf = webcam_intervals[ival_sz - 1];
        for (i = 0; i < ival_sz; i++)
-               if (FRACT_CMP(tpf, >=, webcam_intervals[i]))
+               if (V4L2_FRACT_COMPARE(tpf, >=, webcam_intervals[i]))
                        break;
        if (i == ival_sz)
                i = ival_sz - 1;
        dev->webcam_ival_idx = i;
        tpf = webcam_intervals[dev->webcam_ival_idx];
-       tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
-       tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+       tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf;
+       tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf;
 
        /* resync the thread's timings */
        dev->cap_seq_resync = true;
index 47d8b48820dfcbfe09132604f3d8d185bb117f1b..1e422a59eeabf1629f4bea408c5be9fed605f46f 100644 (file)
@@ -28,7 +28,7 @@ int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
 int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
 int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
 int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
-int vivid_vid_cap_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap);
+int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f);
 int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
 int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
 int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
index 9645a91b8782592c1009e863f1aa444aa4f2b5d7..661f4015fba1afc071012440e767a301bbe102c7 100644 (file)
@@ -21,7 +21,7 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
        .type = V4L2_DV_BT_656_1120,
        /* keep this initialization for compatibility with GCC < 4.4.6 */
        .reserved = { 0 },
-       V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000,
+       V4L2_INIT_BT_TIMINGS(16, MAX_WIDTH, 16, MAX_HEIGHT, 14000000, 775000000,
                V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
                V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
                V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
index 628eae154ee709e5cf96128c15f19d73e51442e1..ea250aee2b2e24d61a6e645d2455f5fae546f461 100644 (file)
@@ -793,26 +793,24 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
        return 0;
 }
 
-int vivid_vid_out_cropcap(struct file *file, void *priv,
-                             struct v4l2_cropcap *cap)
+int vivid_vid_out_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct vivid_dev *dev = video_drvdata(file);
 
-       if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+       if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
 
        switch (vivid_get_pixel_aspect(dev)) {
        case TPG_PIXEL_ASPECT_NTSC:
-               cap->pixelaspect.numerator = 11;
-               cap->pixelaspect.denominator = 10;
+               f->numerator = 11;
+               f->denominator = 10;
                break;
        case TPG_PIXEL_ASPECT_PAL:
-               cap->pixelaspect.numerator = 54;
-               cap->pixelaspect.denominator = 59;
+               f->numerator = 54;
+               f->denominator = 59;
                break;
-       case TPG_PIXEL_ASPECT_SQUARE:
-               cap->pixelaspect.numerator = 1;
-               cap->pixelaspect.denominator = 1;
+       default:
                break;
        }
        return 0;
index e87aacf843c5a32b1c0e0c8b54ffac354593d0ee..8d56314f4ea1f83b97e53a1e4926b12ed96b5e99 100644 (file)
@@ -23,7 +23,7 @@ int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f)
 int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
 int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
 int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
-int vivid_vid_out_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cap);
+int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f);
 int vidioc_enum_fmt_vid_out_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
 int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
 int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
index a5d21b7c6e0b222c85c9f75a261a5a69d6fe8cf6..74ec8aaa5ae058f95754f9132b9ddd78d1c363f8 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 config VIDEO_XILINX
        tristate "Xilinx Video IP (EXPERIMENTAL)"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA
index e8a0f2a9f73333a2eaf2aee3f6a3ce8d98fc5cdb..4cdc0b1ec7a5d768e1f8b2da1060488688267c1f 100644 (file)
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o
 
 obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o
index 4ae9d38c94332fa4730fc8309191cc9126815e5a..c9d5fdb2d407ed9f8babd406fc7159f5233cb343 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video DMA
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dma/xilinx_dma.h>
index e95d136c153a8f5f6a04203a50ec14089cedbe0f..5aec4d17eb212ce8c4ba0b7bc62f9c083e687921 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video DMA
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIP_DMA_H__
index 851d20dcd550757a0613d66e9988670ea69496d9..ed01bedb5db69962a67fb149c76363b92e10f7f7 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Test Pattern Generator
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/device.h>
@@ -725,7 +722,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
                const struct xvip_video_format *format;
                struct device_node *endpoint;
 
-               if (!port->name || of_node_cmp(port->name, "port"))
+               if (!of_node_name_eq(port, "port"))
                        continue;
 
                format = xvip_of_get_format(port);
index 3112591295045196a4952a690c08efbfceb6fe96..18f98838111bfe8966f5db0bf1685b5cdfdf8ece 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Core
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/clk.h>
@@ -36,7 +33,7 @@ static const struct xvip_video_format xvip_video_formats[] = {
        { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
          1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" },
        { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
-         1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" },
+         1, V4L2_PIX_FMT_SRGGB8, "Bayer 8-bit RGGB" },
        { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
          1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" },
        { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
index 42fee2026815b78d24886151fbaa914d20cbe7e6..ba939dd52818941bd9bc2bc5073209bfd3bef576 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Core
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIP_H__
index 99e016d35d91d7e7e1b9ad6d7e89653d43ae8b2f..edce0402155dfb007b1b456f7456ecc6ccf218f5 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Composite Device
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/list.h>
index 7e9c4cff33b444e7d0e4454d94e012c82f50f3ee..e65fce9538f9280f81fb05daedf08028e7c06b39 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Composite Device
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIPP_H__
index 01c750edcac55fa4d1380839bcef87bafcd8802e..0ae0208d75296b5d58614a606fc82b0a73f892a1 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video Timing Controller
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/clk.h>
index e1bb2cfcf4288ff8f7a864df7dad8e15a02b569d..90cf442452834fd9ba82dd9715c9d128fb008f72 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video Timing Controller
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VTC_H__
index 1021c08a9ba4c8956742c8d2ef1ddc6fe23450f2..8a216068a35a17ea37d102e9f5fb5479dd9b7f80 100644 (file)
@@ -493,6 +493,18 @@ config IR_TANGO
           The HW decoder supports NEC, RC-5, RC-6 IR protocols.
           When compiled as a module, look for tango-ir.
 
+config RC_XBOX_DVD
+       tristate "Xbox DVD Movie Playback Kit"
+       depends on RC_CORE
+       depends on USB_ARCH_HAS_HCD
+       select USB
+       help
+          Say Y here if you want to use the Xbox DVD Movie Playback Kit.
+          These are IR remotes with USB receivers for the Original Xbox (2001).
+
+          To compile this driver as a module, choose M here: the module will be
+          called xbox_remote.
+
 config IR_ZX
        tristate "ZTE ZX IR remote control"
        depends on RC_CORE
index e0340d043fe85f11881fed8240664156b1d96753..92c163816849d06b08ab521afcc604a16592ed0c 100644 (file)
@@ -48,3 +48,4 @@ obj-$(CONFIG_IR_SIR) += sir_ir.o
 obj-$(CONFIG_IR_MTK) += mtk-cir.o
 obj-$(CONFIG_IR_ZX) += zx-irdec.o
 obj-$(CONFIG_IR_TANGO) += tango-ir.o
+obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o
index 1041c056854d5035d2d6c6072ad37537334c2927..989d2554ec728beab95a204f532a028c812f4975 100644 (file)
@@ -772,9 +772,9 @@ static ssize_t show_associate_remote(struct device *d,
 
        mutex_lock(&ictx->lock);
        if (ictx->rf_isassociating)
-               strcpy(buf, "associating\n");
+               strscpy(buf, "associating\n", PAGE_SIZE);
        else
-               strcpy(buf, "closed\n");
+               strscpy(buf, "closed\n", PAGE_SIZE);
 
        dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n");
        mutex_unlock(&ictx->lock);
index 7796098d9c307a54ed811db1e6c987fadfd2535f..25e56c5b13c02fd6690595e5dfd7cc7e1cb70966 100644 (file)
@@ -14,51 +14,50 @@ struct imon {
        struct device *dev;
        struct urb *ir_urb;
        struct rc_dev *rcdev;
-       u8 ir_buf[8];
+       u8 ir_buf[8] __aligned(__alignof__(u64));
        char phys[64];
 };
 
 /*
- * ffs/find_next_bit() searches in the wrong direction, so open-code our own.
+ * The first 5 bytes of data represent IR pulse or space. Each bit, starting
+ * from highest bit in the first byte, represents 250µs of data. It is 1
+ * for space and 0 for pulse.
+ *
+ * The station sends 10 packets, and the 7th byte will be number 1 to 10, so
+ * when we receive 10 we assume all the data has arrived.
  */
-static inline int is_bit_set(const u8 *buf, int bit)
-{
-       return buf[bit / 8] & (0x80 >> (bit & 7));
-}
-
 static void imon_ir_data(struct imon *imon)
 {
        struct ir_raw_event rawir = {};
-       int offset = 0, size = 5 * 8;
+       u64 d = be64_to_cpup((__be64 *)imon->ir_buf) >> 24;
+       int offset = 40;
        int bit;
 
        dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf);
 
-       while (offset < size) {
-               bit = offset;
-               while (!is_bit_set(imon->ir_buf, bit) && bit < size)
-                       bit++;
-               dev_dbg(imon->dev, "pulse: %d bits", bit - offset);
-               if (bit > offset) {
+       do {
+               bit = fls64(d & (BIT_ULL(offset) - 1));
+               if (bit < offset) {
+                       dev_dbg(imon->dev, "pulse: %d bits", offset - bit);
                        rawir.pulse = true;
-                       rawir.duration = (bit - offset) * BIT_DURATION;
+                       rawir.duration = (offset - bit) * BIT_DURATION;
                        ir_raw_event_store_with_filter(imon->rcdev, &rawir);
-               }
 
-               if (bit >= size)
-                       break;
+                       if (bit == 0)
+                               break;
 
-               offset = bit;
-               while (is_bit_set(imon->ir_buf, bit) && bit < size)
-                       bit++;
-               dev_dbg(imon->dev, "space: %d bits", bit - offset);
+                       offset = bit;
+               }
+
+               bit = fls64(~d & (BIT_ULL(offset) - 1));
+               dev_dbg(imon->dev, "space: %d bits", offset - bit);
 
                rawir.pulse = false;
-               rawir.duration = (bit - offset) * BIT_DURATION;
+               rawir.duration = (offset - bit) * BIT_DURATION;
                ir_raw_event_store_with_filter(imon->rcdev, &rawir);
 
                offset = bit;
-       }
+       } while (offset > 0);
 
        if (imon->ir_buf[7] == 0x0a) {
                ir_raw_event_set_idle(imon->rcdev, true);
index d6b913a3032d8d92b61fce6f05b04d5b5fd0550f..5b1399af6b3a4b4351f4189d7428e689102baecc 100644 (file)
@@ -116,4 +116,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-winfast.o \
                        rc-winfast-usbii-deluxe.o \
                        rc-su3000.o \
+                       rc-xbox-dvd.o \
                        rc-zx-irdec.o
diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c
new file mode 100644 (file)
index 0000000..af38724
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Keytable for Xbox DVD remote
+// Copyright (c) 2018 by Benjamin Valentin <benpicco@googlemail.com>
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/* based on lircd.conf.xbox */
+static struct rc_map_table xbox_dvd[] = {
+       {0xa0b, KEY_OK},
+       {0xaa6, KEY_UP},
+       {0xaa7, KEY_DOWN},
+       {0xaa8, KEY_RIGHT},
+       {0xaa9, KEY_LEFT},
+       {0xac3, KEY_INFO},
+
+       {0xac6, KEY_9},
+       {0xac7, KEY_8},
+       {0xac8, KEY_7},
+       {0xac9, KEY_6},
+       {0xaca, KEY_5},
+       {0xacb, KEY_4},
+       {0xacc, KEY_3},
+       {0xacd, KEY_2},
+       {0xace, KEY_1},
+       {0xacf, KEY_0},
+
+       {0xad5, KEY_ANGLE},
+       {0xad8, KEY_BACK},
+       {0xadd, KEY_PREVIOUSSONG},
+       {0xadf, KEY_NEXTSONG},
+       {0xae0, KEY_STOP},
+       {0xae2, KEY_REWIND},
+       {0xae3, KEY_FASTFORWARD},
+       {0xae5, KEY_TITLE},
+       {0xae6, KEY_PAUSE},
+       {0xaea, KEY_PLAY},
+       {0xaf7, KEY_MENU},
+};
+
+static struct rc_map_list xbox_dvd_map = {
+       .map = {
+               .scan     = xbox_dvd,
+               .size     = ARRAY_SIZE(xbox_dvd),
+               .rc_proto = RC_PROTO_UNKNOWN,
+               .name     = RC_MAP_XBOX_DVD,
+       }
+};
+
+static int __init init_rc_map(void)
+{
+       return rc_map_register(&xbox_dvd_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+       rc_map_unregister(&xbox_dvd_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
index c9293696dc2deee3a7a912f8a50ba73310e2425a..8d7d3ef88862fb431a06bae9241da87567891d04 100644 (file)
@@ -432,6 +432,15 @@ static const struct usb_device_id mceusb_dev_table[] = {
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb139),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       /* Hauppauge WinTV-HVR-935C - based on cx231xx */
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb151),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       /* Hauppauge WinTV-HVR-955Q - based on cx231xx */
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb123),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       /* Hauppauge WinTV-HVR-975 - based on cx231xx */
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb150),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x0259),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x025e),
index 552bbe82a160a80812cbcf456c798d818f7cdece..66a174979b3c98a540ffd1d625a246ddaaea33fb 100644 (file)
@@ -695,7 +695,8 @@ void rc_repeat(struct rc_dev *dev)
                         (dev->last_toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0)
        };
 
-       ir_lirc_scancode_event(dev, &sc);
+       if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
+               ir_lirc_scancode_event(dev, &sc);
 
        spin_lock_irqsave(&dev->keylock, flags);
 
@@ -735,7 +736,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
                .keycode = keycode
        };
 
-       ir_lirc_scancode_event(dev, &sc);
+       if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
+               ir_lirc_scancode_event(dev, &sc);
 
        if (new_event && dev->keypressed)
                ir_do_keyup(dev, false);
@@ -1950,6 +1952,8 @@ void rc_unregister_device(struct rc_dev *dev)
        rc_free_rx_device(dev);
 
        mutex_lock(&dev->lock);
+       if (dev->users && dev->close)
+               dev->close(dev);
        dev->registered = false;
        mutex_unlock(&dev->lock);
 
diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c
new file mode 100644 (file)
index 0000000..f959cbb
--- /dev/null
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Driver for Xbox DVD Movie Playback Kit
+// Copyright (c) 2018 by Benjamin Valentin <benpicco@googlemail.com>
+
+/*
+ *  Xbox DVD Movie Playback Kit USB IR dongle support
+ *
+ *  The driver was derived from the ati_remote driver 2.2.1
+ *          and used information from lirc_xbox.c
+ *
+ *          Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>
+ *          Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *          Copyright (c) 2002 Vladimir Dergachev
+ *          Copyright (c) 2003-2004 Paul Miller <pmiller9@users.sourceforge.net>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+/*
+ * Module and Version Information
+ */
+#define DRIVER_VERSION "1.0.0"
+#define DRIVER_AUTHOR  "Benjamin Valentin <benpicco@googlemail.com>"
+#define DRIVER_DESC            "Xbox DVD USB Remote Control"
+
+#define NAME_BUFSIZE      80    /* size of product name, path buffers */
+#define DATA_BUFSIZE      8     /* size of URB data buffers */
+
+/*
+ * USB vendor ids for XBOX DVD Dongles
+ */
+#define VENDOR_GAMESTER     0x040b
+#define VENDOR_MICROSOFT    0x045e
+
+static const struct usb_device_id xbox_remote_table[] = {
+       /* Gamester Xbox DVD Movie Playback Kit IR */
+       {
+               USB_DEVICE(VENDOR_GAMESTER, 0x6521),
+       },
+       /* Microsoft Xbox DVD Movie Playback Kit IR */
+       {
+               USB_DEVICE(VENDOR_MICROSOFT, 0x0284),
+       },
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, xbox_remote_table);
+
+struct xbox_remote {
+       struct rc_dev *rdev;
+       struct usb_device *udev;
+       struct usb_interface *interface;
+
+       struct urb *irq_urb;
+       unsigned char inbuf[DATA_BUFSIZE] __aligned(sizeof(u16));
+
+       char rc_name[NAME_BUFSIZE];
+       char rc_phys[NAME_BUFSIZE];
+};
+
+static int xbox_remote_rc_open(struct rc_dev *rdev)
+{
+       struct xbox_remote *xbox_remote = rdev->priv;
+
+       /* On first open, submit the read urb which was set up previously. */
+       xbox_remote->irq_urb->dev = xbox_remote->udev;
+       if (usb_submit_urb(xbox_remote->irq_urb, GFP_KERNEL)) {
+               dev_err(&xbox_remote->interface->dev,
+                       "%s: usb_submit_urb failed!\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void xbox_remote_rc_close(struct rc_dev *rdev)
+{
+       struct xbox_remote *xbox_remote = rdev->priv;
+
+       usb_kill_urb(xbox_remote->irq_urb);
+}
+
+/*
+ * xbox_remote_report_input
+ */
+static void xbox_remote_input_report(struct urb *urb)
+{
+       struct xbox_remote *xbox_remote = urb->context;
+       unsigned char *data = xbox_remote->inbuf;
+
+       /*
+        * data[0] = 0x00
+        * data[1] = length - always 0x06
+        * data[2] = the key code
+        * data[3] = high part of key code
+        * data[4] = last_press_ms (low)
+        * data[5] = last_press_ms (high)
+        */
+
+       /* Deal with strange looking inputs */
+       if (urb->actual_length != 6 || urb->actual_length != data[1]) {
+               dev_warn(&urb->dev->dev, "Weird data, len=%d: %*ph\n",
+                        urb->actual_length, urb->actual_length, data);
+               return;
+       }
+
+       rc_keydown(xbox_remote->rdev, RC_PROTO_UNKNOWN,
+                  le16_to_cpup((__le16 *)(data + 2)), 0);
+}
+
+/*
+ * xbox_remote_irq_in
+ */
+static void xbox_remote_irq_in(struct urb *urb)
+{
+       struct xbox_remote *xbox_remote = urb->context;
+       int retval;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               xbox_remote_input_report(urb);
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               dev_dbg(&xbox_remote->interface->dev,
+                       "%s: urb error status, unlink?\n",
+                       __func__);
+               return;
+       default:                /* error */
+               dev_dbg(&xbox_remote->interface->dev,
+                       "%s: Nonzero urb status %d\n",
+                       __func__, urb->status);
+       }
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               dev_err(&xbox_remote->interface->dev,
+                       "%s: usb_submit_urb()=%d\n",
+                       __func__, retval);
+}
+
+static void xbox_remote_rc_init(struct xbox_remote *xbox_remote)
+{
+       struct rc_dev *rdev = xbox_remote->rdev;
+
+       rdev->priv = xbox_remote;
+       rdev->allowed_protocols = RC_PROTO_BIT_UNKNOWN;
+       rdev->driver_name = "xbox_remote";
+
+       rdev->open = xbox_remote_rc_open;
+       rdev->close = xbox_remote_rc_close;
+
+       rdev->device_name = xbox_remote->rc_name;
+       rdev->input_phys = xbox_remote->rc_phys;
+
+       usb_to_input_id(xbox_remote->udev, &rdev->input_id);
+       rdev->dev.parent = &xbox_remote->interface->dev;
+}
+
+static int xbox_remote_initialize(struct xbox_remote *xbox_remote,
+                                 struct usb_endpoint_descriptor *endpoint_in)
+{
+       struct usb_device *udev = xbox_remote->udev;
+       int pipe, maxp;
+
+       /* Set up irq_urb */
+       pipe = usb_rcvintpipe(udev, endpoint_in->bEndpointAddress);
+       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+       usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf,
+                        maxp, xbox_remote_irq_in, xbox_remote,
+                        endpoint_in->bInterval);
+
+       return 0;
+}
+
+/*
+ * xbox_remote_probe
+ */
+static int xbox_remote_probe(struct usb_interface *interface,
+                            const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *iface_host = interface->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint_in;
+       struct xbox_remote *xbox_remote;
+       struct rc_dev *rc_dev;
+       int err = -ENOMEM;
+
+       // why is there also a device with no endpoints?
+       if (iface_host->desc.bNumEndpoints == 0)
+               return -ENODEV;
+
+       if (iface_host->desc.bNumEndpoints != 1) {
+               pr_err("%s: Unexpected desc.bNumEndpoints: %d\n",
+                      __func__, iface_host->desc.bNumEndpoints);
+               return -ENODEV;
+       }
+
+       endpoint_in = &iface_host->endpoint[0].desc;
+
+       if (!usb_endpoint_is_int_in(endpoint_in)) {
+               pr_err("%s: Unexpected endpoint_in\n", __func__);
+               return -ENODEV;
+       }
+       if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
+               pr_err("%s: endpoint_in message size==0?\n", __func__);
+               return -ENODEV;
+       }
+
+       xbox_remote = kzalloc(sizeof(*xbox_remote), GFP_KERNEL);
+       rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
+       if (!xbox_remote || !rc_dev)
+               goto exit_free_dev_rdev;
+
+       /* Allocate URB buffer */
+       xbox_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!xbox_remote->irq_urb)
+               goto exit_free_buffers;
+
+       xbox_remote->udev = udev;
+       xbox_remote->rdev = rc_dev;
+       xbox_remote->interface = interface;
+
+       usb_make_path(udev, xbox_remote->rc_phys, sizeof(xbox_remote->rc_phys));
+
+       strlcat(xbox_remote->rc_phys, "/input0", sizeof(xbox_remote->rc_phys));
+
+       snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name), "%s%s%s",
+                udev->manufacturer ?: "",
+                udev->manufacturer && udev->product ? " " : "",
+                udev->product ?: "");
+
+       if (!strlen(xbox_remote->rc_name))
+               snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name),
+                        DRIVER_DESC "(%04x,%04x)",
+                        le16_to_cpu(xbox_remote->udev->descriptor.idVendor),
+                        le16_to_cpu(xbox_remote->udev->descriptor.idProduct));
+
+       rc_dev->map_name = RC_MAP_XBOX_DVD; /* default map */
+
+       xbox_remote_rc_init(xbox_remote);
+
+       /* Device Hardware Initialization */
+       err = xbox_remote_initialize(xbox_remote, endpoint_in);
+       if (err)
+               goto exit_kill_urbs;
+
+       /* Set up and register rc device */
+       err = rc_register_device(xbox_remote->rdev);
+       if (err)
+               goto exit_kill_urbs;
+
+       usb_set_intfdata(interface, xbox_remote);
+
+       return 0;
+
+exit_kill_urbs:
+       usb_kill_urb(xbox_remote->irq_urb);
+exit_free_buffers:
+       usb_free_urb(xbox_remote->irq_urb);
+exit_free_dev_rdev:
+       rc_free_device(rc_dev);
+       kfree(xbox_remote);
+
+       return err;
+}
+
+/*
+ * xbox_remote_disconnect
+ */
+static void xbox_remote_disconnect(struct usb_interface *interface)
+{
+       struct xbox_remote *xbox_remote;
+
+       xbox_remote = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+       if (!xbox_remote) {
+               dev_warn(&interface->dev, "%s - null device?\n", __func__);
+               return;
+       }
+
+       usb_kill_urb(xbox_remote->irq_urb);
+       rc_unregister_device(xbox_remote->rdev);
+       usb_free_urb(xbox_remote->irq_urb);
+       kfree(xbox_remote);
+}
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver xbox_remote_driver = {
+       .name         = "xbox_remote",
+       .probe        = xbox_remote_probe,
+       .disconnect   = xbox_remote_disconnect,
+       .id_table     = xbox_remote_table,
+};
+
+module_usb_driver(xbox_remote_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
index 11ce5101e19f6b71ed703ea9cd8010e7ae1b6967..d5c433e20d4af30da51f3dff6741c642e4544c47 100644 (file)
@@ -10,6 +10,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
 
 #include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
 #include <linux/ktime.h>
 
 #include <media/dvb_demux.h>
@@ -51,6 +52,7 @@ struct cxd2880_dvb_spi {
        struct mutex spi_mutex; /* For SPI access exclusive control */
        int feed_count;
        int all_pid_feed_count;
+       struct regulator *vcc_supply;
        u8 *ts_buf;
        struct cxd2880_pid_filter_config filter_config;
 };
@@ -518,6 +520,17 @@ cxd2880_spi_probe(struct spi_device *spi)
        if (!dvb_spi)
                return -ENOMEM;
 
+       dvb_spi->vcc_supply = devm_regulator_get_optional(&spi->dev, "vcc");
+       if (IS_ERR(dvb_spi->vcc_supply)) {
+               if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               dvb_spi->vcc_supply = NULL;
+       } else {
+               ret = regulator_enable(dvb_spi->vcc_supply);
+               if (ret)
+                       return ret;
+       }
+
        dvb_spi->spi = spi;
        mutex_init(&dvb_spi->spi_mutex);
        dev_set_drvdata(&spi->dev, dvb_spi);
@@ -536,6 +549,7 @@ cxd2880_spi_probe(struct spi_device *spi)
 
        if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
                pr_err("cxd2880_attach failed\n");
+               ret = -ENODEV;
                goto fail_attach;
        }
 
@@ -630,6 +644,9 @@ cxd2880_spi_remove(struct spi_device *spi)
        dvb_frontend_detach(&dvb_spi->dvb_fe);
        dvb_unregister_adapter(&dvb_spi->adapter);
 
+       if (dvb_spi->vcc_supply)
+               regulator_disable(dvb_spi->vcc_supply);
+
        kfree(dvb_spi);
        pr_info("cxd2880_spi remove ok.\n");
 
index efbf210147c73a289b443cc938c6d2c32798b436..7876c897cc1d60512c4b5350166d065d0baba9ee 100644 (file)
@@ -1616,27 +1616,42 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_cropcap(struct file *file, void *priv,
-                         struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
        dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
-       cc->bounds.left = 0;
-       cc->bounds.top = 0;
-       cc->bounds.width = dev->width;
-       cc->bounds.height = dev->height;
+       f->numerator = 54;
+       f->denominator = 59;
 
-       cc->defrect = cc->bounds;
+       return 0;
+}
+
+static int vidioc_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *s)
+{
+       struct au0828_dev *dev = video_drvdata(file);
 
-       cc->pixelaspect.numerator = 54;
-       cc->pixelaspect.denominator = 59;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = dev->width;
+               s->r.height = dev->height;
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -1762,7 +1777,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_enumaudio           = vidioc_enumaudio,
        .vidioc_g_audio             = vidioc_g_audio,
        .vidioc_s_audio             = vidioc_s_audio,
-       .vidioc_cropcap             = vidioc_cropcap,
+       .vidioc_g_pixelaspect       = vidioc_g_pixelaspect,
+       .vidioc_g_selection         = vidioc_g_selection,
 
        .vidioc_reqbufs             = vb2_ioctl_reqbufs,
        .vidioc_create_bufs         = vb2_ioctl_create_bufs,
index 3f401fbd0ecc675391bd16e6421df43ddd660468..748739c2b8b2cf2ead48ba0d8ee281ac39389d42 100644 (file)
@@ -479,24 +479,25 @@ static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
  *
  *****************************************************************************/
 
-static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
+static int cpia2_g_selection(struct file *file, void *fh,
+                            struct v4l2_selection *s)
 {
        struct camera_data *cam = video_drvdata(file);
 
-       if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-              return -EINVAL;
-
-       c->bounds.left = 0;
-       c->bounds.top = 0;
-       c->bounds.width = cam->width;
-       c->bounds.height = cam->height;
-       c->defrect.left = 0;
-       c->defrect.top = 0;
-       c->defrect.width = cam->width;
-       c->defrect.height = cam->height;
-       c->pixelaspect.numerator = 1;
-       c->pixelaspect.denominator = 1;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = cam->width;
+               s->r.height = cam->height;
+               break;
+       default:
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -1047,7 +1048,7 @@ static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
        .vidioc_try_fmt_vid_cap             = cpia2_try_fmt_vid_cap,
        .vidioc_g_jpegcomp                  = cpia2_g_jpegcomp,
        .vidioc_s_jpegcomp                  = cpia2_s_jpegcomp,
-       .vidioc_cropcap                     = cpia2_cropcap,
+       .vidioc_g_selection                 = cpia2_g_selection,
        .vidioc_reqbufs                     = cpia2_reqbufs,
        .vidioc_querybuf                    = cpia2_querybuf,
        .vidioc_qbuf                        = cpia2_qbuf,
index 2641e23d946b649a0adeeb31cc86c8578722f457..1c48c497bd6a164bc7c785ccaa1d98abc233e9b6 100644 (file)
@@ -1500,27 +1500,45 @@ static const struct videobuf_queue_ops cx231xx_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static int vidioc_cropcap(struct file *file, void *priv,
-                         struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
        bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50;
 
-       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       cc->bounds.left = 0;
-       cc->bounds.top = 0;
-       cc->bounds.width = dev->ts1.width;
-       cc->bounds.height = dev->ts1.height;
-       cc->defrect = cc->bounds;
-       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
-       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+       f->numerator = is_50hz ? 54 : 11;
+       f->denominator = is_50hz ? 59 : 10;
 
        return 0;
 }
 
+static int vidioc_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *s)
+{
+       struct cx231xx_fh *fh = priv;
+       struct cx231xx *dev = fh->dev;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = dev->ts1.width;
+               s->r.height = dev->ts1.height;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
 {
        struct cx231xx_fh  *fh  = file->private_data;
@@ -1865,7 +1883,8 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_g_input          = cx231xx_g_input,
        .vidioc_s_input          = cx231xx_s_input,
        .vidioc_s_ctrl           = vidioc_s_ctrl,
-       .vidioc_cropcap          = vidioc_cropcap,
+       .vidioc_g_pixelaspect    = vidioc_g_pixelaspect,
+       .vidioc_g_selection      = vidioc_g_selection,
        .vidioc_querycap         = cx231xx_querycap,
        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
index c990f70c0ea646453d9b3bf058df201f442a83fe..0d451c4ea3b9aa76ac7632f9bbf8db7d83df4a41 100644 (file)
@@ -1482,27 +1482,45 @@ int cx231xx_s_register(struct file *file, void *priv,
 }
 #endif
 
-static int vidioc_cropcap(struct file *file, void *priv,
-                         struct v4l2_cropcap *cc)
+static int vidioc_g_pixelaspect(struct file *file, void *priv,
+                               int type, struct v4l2_fract *f)
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
        bool is_50hz = dev->norm & V4L2_STD_625_50;
 
-       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       cc->bounds.left = 0;
-       cc->bounds.top = 0;
-       cc->bounds.width = dev->width;
-       cc->bounds.height = dev->height;
-       cc->defrect = cc->bounds;
-       cc->pixelaspect.numerator = is_50hz ? 54 : 11;
-       cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+       f->numerator = is_50hz ? 54 : 11;
+       f->denominator = is_50hz ? 59 : 10;
 
        return 0;
 }
 
+static int vidioc_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *s)
+{
+       struct cx231xx_fh *fh = priv;
+       struct cx231xx *dev = fh->dev;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = dev->width;
+               s->r.height = dev->height;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int vidioc_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type type)
 {
@@ -2093,7 +2111,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vbi_cap          = vidioc_g_fmt_vbi_cap,
        .vidioc_try_fmt_vbi_cap        = vidioc_try_fmt_vbi_cap,
        .vidioc_s_fmt_vbi_cap          = vidioc_s_fmt_vbi_cap,
-       .vidioc_cropcap                = vidioc_cropcap,
+       .vidioc_g_pixelaspect          = vidioc_g_pixelaspect,
+       .vidioc_g_selection            = vidioc_g_selection,
        .vidioc_reqbufs                = vidioc_reqbufs,
        .vidioc_querybuf               = vidioc_querybuf,
        .vidioc_qbuf                   = vidioc_qbuf,
index df4412245a8aeb8214d5d1f8b3760070e781d7ee..511e3f270308852b3f0492e1065a14e1cd8ebe49 100644 (file)
@@ -133,6 +133,7 @@ config DVB_USB_RTL28XXU
        depends on DVB_USB_V2 && I2C_MUX
        select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_MN88473 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT
        select DVB_RTL2830
        select DVB_RTL2832
        select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT)
index 3b8f7931b7306178f5854b5a2ea2608f8faeb25e..d55ef016d4187e604e0e987e32db7603c4e3c028 100644 (file)
@@ -957,9 +957,7 @@ int dvb_usbv2_probe(struct usb_interface *intf,
        if (d->props->identify_state) {
                const char *name = NULL;
                ret = d->props->identify_state(d, &name);
-               if (ret == 0) {
-                       ;
-               } else if (ret == COLD) {
+               if (ret == COLD) {
                        dev_info(&d->udev->dev,
                                        "%s: found a '%s' in cold state\n",
                                        KBUILD_MODNAME, d->name);
@@ -984,7 +982,7 @@ int dvb_usbv2_probe(struct usb_interface *intf,
                        } else {
                                goto err_free_all;
                        }
-               } else {
+               } else if (ret != WARM) {
                        goto err_free_all;
                }
        }
index 0559417c8af48830e614aecb3d206cf1e71cef90..80fed4494736854ff64f34a22ba844a712e0e4ef 100644 (file)
@@ -200,11 +200,10 @@ gl861_i2c_write_ex(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen)
        u8 *buf;
        int ret;
 
-       buf = kmalloc(wlen, GFP_KERNEL);
+       buf = kmemdup(wbuf, wlen, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       memcpy(buf, wbuf, wlen);
        ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
                                 GL861_REQ_I2C_RAW, GL861_WRITE,
                                 addr << (8 + 1), 0x0100, buf, wlen, 2000);
index f109c04f05ae2e879ec00301e8838d263b12edb0..602013cf3e693483c31c0c42e902a62315d3a8f5 100644 (file)
@@ -134,9 +134,9 @@ struct lme2510_state {
        u8 stream_on;
        u8 pid_size;
        u8 pid_off;
-       void *buffer;
+       u8 int_buffer[128];
        struct urb *lme_urb;
-       void *usb_buffer;
+       u8 usb_buffer[64];
        /* Frontend original calls */
        int (*fe_read_status)(struct dvb_frontend *, enum fe_status *);
        int (*fe_read_signal_strength)(struct dvb_frontend *, u16 *);
@@ -147,59 +147,30 @@ struct lme2510_state {
        u8 dvb_usb_lme2510_firmware;
 };
 
-static int lme2510_bulk_write(struct usb_device *dev,
-                               u8 *snd, int len, u8 pipe)
-{
-       int actual_l;
-
-       return usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
-                           snd, len, &actual_l, 100);
-}
-
-static int lme2510_bulk_read(struct usb_device *dev,
-                               u8 *rev, int len, u8 pipe)
-{
-       int actual_l;
-
-       return usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
-                           rev, len, &actual_l, 200);
-}
-
 static int lme2510_usb_talk(struct dvb_usb_device *d,
-               u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+                           u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
        struct lme2510_state *st = d->priv;
-       u8 *buff;
        int ret = 0;
 
-       if (st->usb_buffer == NULL) {
-               st->usb_buffer = kmalloc(64, GFP_KERNEL);
-               if (st->usb_buffer == NULL) {
-                       info("MEM Error no memory");
-                       return -ENOMEM;
-               }
-       }
-       buff = st->usb_buffer;
+       if (max(wlen, rlen) > sizeof(st->usb_buffer))
+               return -EINVAL;
 
        ret = mutex_lock_interruptible(&d->usb_mutex);
-
        if (ret < 0)
                return -EAGAIN;
 
-       /* the read/write capped at 64 */
-       memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
+       memcpy(st->usb_buffer, wbuf, wlen);
 
-       ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+       ret = dvb_usbv2_generic_rw_locked(d, st->usb_buffer, wlen,
+                                         st->usb_buffer, rlen);
 
-       ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
-                       rlen : 64 , 0x01);
-
-       if (rlen > 0)
-               memcpy(rbuf, buff, rlen);
+       if (rlen)
+               memcpy(rbuf, st->usb_buffer, rlen);
 
        mutex_unlock(&d->usb_mutex);
 
-       return (ret < 0) ? -ENODEV : 0;
+       return ret;
 }
 
 static int lme2510_stream_restart(struct dvb_usb_device *d)
@@ -417,20 +388,14 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
        if (lme_int->lme_urb == NULL)
                        return -ENOMEM;
 
-       lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC,
-                                       &lme_int->lme_urb->transfer_dma);
-
-       if (lme_int->buffer == NULL)
-                       return -ENOMEM;
-
        usb_fill_int_urb(lme_int->lme_urb,
-                               d->udev,
-                               usb_rcvintpipe(d->udev, 0xa),
-                               lme_int->buffer,
-                               128,
-                               lme2510_int_response,
-                               adap,
-                               8);
+                        d->udev,
+                        usb_rcvintpipe(d->udev, 0xa),
+                        lme_int->int_buffer,
+                        sizeof(lme_int->int_buffer),
+                        lme2510_int_response,
+                        adap,
+                        8);
 
        /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */
        ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe);
@@ -438,8 +403,6 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
        if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
                lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa),
 
-       lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
        usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
        info("INT Interrupt Service Started");
 
@@ -1245,41 +1208,20 @@ static int lme2510_get_rc_config(struct dvb_usb_device *d,
        return 0;
 }
 
-static void *lme2510_exit_int(struct dvb_usb_device *d)
+static void lme2510_exit(struct dvb_usb_device *d)
 {
        struct lme2510_state *st = d->priv;
        struct dvb_usb_adapter *adap = &d->adapter[0];
-       void *buffer = NULL;
 
        if (adap != NULL) {
                lme2510_kill_urb(&adap->stream);
        }
 
-       if (st->usb_buffer != NULL) {
-               st->i2c_talk_onoff = 1;
-               st->signal_level = 0;
-               st->signal_sn = 0;
-               buffer = st->usb_buffer;
-       }
-
-       if (st->lme_urb != NULL) {
+       if (st->lme_urb) {
                usb_kill_urb(st->lme_urb);
-               usb_free_coherent(d->udev, 128, st->buffer,
-                                 st->lme_urb->transfer_dma);
+               usb_free_urb(st->lme_urb);
                info("Interrupt Service Stopped");
        }
-
-       return buffer;
-}
-
-static void lme2510_exit(struct dvb_usb_device *d)
-{
-       void *usb_buffer;
-
-       if (d != NULL) {
-               usb_buffer = lme2510_exit_int(d);
-               kfree(usb_buffer);
-       }
 }
 
 static struct dvb_usb_device_properties lme2510_props = {
@@ -1288,6 +1230,8 @@ static struct dvb_usb_device_properties lme2510_props = {
        .bInterfaceNumber = 0,
        .adapter_nr = adapter_nr,
        .size_of_priv = sizeof(struct lme2510_state),
+       .generic_bulk_ctrl_endpoint = 0x01,
+       .generic_bulk_ctrl_endpoint_response = 0x01,
 
        .download_firmware = lme2510_download_firmware,
 
index 8a83b10e50e08a87409cce4ca79279c918654836..d0075cb743b2f145378fc888ab65ff30503c7703 100644 (file)
@@ -384,6 +384,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
        struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
        struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf};
        struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf};
+       struct rtl28xxu_req req_cxd2837er = {0xfdd8, CMD_I2C_RD, 1, buf};
        struct rtl28xxu_req req_si2157 = {0x00c0, CMD_I2C_RD, 1, buf};
        struct rtl28xxu_req req_si2168 = {0x00c8, CMD_I2C_RD, 1, buf};
 
@@ -540,7 +541,18 @@ tuner_found:
 
        /* probe slave demod */
        if (dev->tuner == TUNER_RTL2832_R828D) {
-               /* power on MN88472 demod on GPIO0 */
+               /* power off slave demod on GPIO0 to reset CXD2837ER */
+               ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01);
+               if (ret)
+                       goto err;
+
+               ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x00, 0x01);
+               if (ret)
+                       goto err;
+
+               msleep(50);
+
+               /* power on slave demod on GPIO0 */
                ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01);
                if (ret)
                        goto err;
@@ -553,7 +565,7 @@ tuner_found:
                if (ret)
                        goto err;
 
-               /* check MN88472 answers */
+               /* check slave answers */
                ret = rtl28xxu_ctrl_msg(d, &req_mn88472);
                if (ret == 0 && buf[0] == 0x02) {
                        dev_dbg(&d->intf->dev, "MN88472 found\n");
@@ -567,6 +579,13 @@ tuner_found:
                        dev->slave_demod = SLAVE_DEMOD_MN88473;
                        goto demod_found;
                }
+
+               ret = rtl28xxu_ctrl_msg(d, &req_cxd2837er);
+               if (ret == 0 && buf[0] == 0xb1) {
+                       dev_dbg(&d->intf->dev, "CXD2837ER found\n");
+                       dev->slave_demod = SLAVE_DEMOD_CXD2837ER;
+                       goto demod_found;
+               }
        }
        if (dev->tuner == TUNER_RTL2832_SI2157) {
                /* check Si2168 ID register; reg=c8 val=80 */
@@ -989,6 +1008,23 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
                        }
 
                        dev->i2c_client_slave_demod = client;
+               } else if (dev->slave_demod == SLAVE_DEMOD_CXD2837ER) {
+                       struct cxd2841er_config cxd2837er_config = {};
+
+                       cxd2837er_config.i2c_addr = 0xd8;
+                       cxd2837er_config.xtal = SONY_XTAL_20500;
+                       cxd2837er_config.flags = (CXD2841ER_AUTO_IFHZ |
+                               CXD2841ER_NO_AGCNEG | CXD2841ER_TSBITS |
+                               CXD2841ER_EARLY_TUNE | CXD2841ER_TS_SERIAL);
+                       adap->fe[1] = dvb_attach(cxd2841er_attach_t_c,
+                                                &cxd2837er_config,
+                                                &d->i2c_adap);
+                       if (!adap->fe[1]) {
+                               dev->slave_demod = SLAVE_DEMOD_NONE;
+                               goto err_slave_demod_failed;
+                       }
+                       adap->fe[1]->id = 1;
+                       dev->i2c_client_slave_demod = NULL;
                } else {
                        struct si2168_config si2168_config = {};
                        struct i2c_adapter *adapter;
index 138062960a7367737521659acc607983c921a685..197f4e339605da0d1c784590234160d1c3f38f52 100644 (file)
@@ -31,6 +31,7 @@
 #include "rtl2832_sdr.h"
 #include "mn88472.h"
 #include "mn88473.h"
+#include "cxd2841er.h"
 
 #include "qt1010.h"
 #include "mt2060.h"
@@ -87,7 +88,8 @@ struct rtl28xxu_dev {
        #define SLAVE_DEMOD_MN88472        1
        #define SLAVE_DEMOD_MN88473        2
        #define SLAVE_DEMOD_SI2168         3
-       unsigned int slave_demod:2;
+       #define SLAVE_DEMOD_CXD2837ER      4
+       unsigned int slave_demod:3;
        union {
                struct rtl2830_platform_data rtl2830_platform_data;
                struct rtl2832_platform_data rtl2832_platform_data;
index 024c751eb16595e5616f345b3301d59142155dcc..2ad2ddeaff513f36b43c2574ba93c0abcf799173 100644 (file)
@@ -155,7 +155,6 @@ static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
                                stream->props.u.bulk.buffersize,
                                usb_urb_complete, stream);
 
-               stream->urb_list[i]->transfer_flags = URB_FREE_BUFFER;
                stream->urbs_initialized++;
        }
        return 0;
@@ -186,7 +185,7 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
                urb->complete = usb_urb_complete;
                urb->pipe = usb_rcvisocpipe(stream->udev,
                                stream->props.endpoint);
-               urb->transfer_flags = URB_ISO_ASAP | URB_FREE_BUFFER;
+               urb->transfer_flags = URB_ISO_ASAP;
                urb->interval = stream->props.u.isoc.interval;
                urb->number_of_packets = stream->props.u.isoc.framesperurb;
                urb->transfer_buffer_length = stream->props.u.isoc.framesize *
@@ -210,7 +209,7 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream)
        if (stream->state & USB_STATE_URB_BUF) {
                while (stream->buf_num) {
                        stream->buf_num--;
-                       stream->buf_list[stream->buf_num] = NULL;
+                       kfree(stream->buf_list[stream->buf_num]);
                }
        }
 
index 7551dce96f648a3b9e610f51db52ccf7ca020f90..9311f7d4bba51f147506133aa91823e2f37c2c99 100644 (file)
@@ -29,7 +29,7 @@
 
 static int force_lna_activation;
 module_param(force_lna_activation, int, 0644);
-MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), if applicable for the device (default: 0=automatic/off).");
+MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifier(s) (LNA), if applicable for the device (default: 0=automatic/off).");
 
 struct dib0700_adapter_state {
        int (*set_param_save) (struct dvb_frontend *);
diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c
deleted file mode 100644 (file)
index e6bd0ed..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 2.
- *
- * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
- */
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-
-#include "friio.h"
-
-struct jdvbt90502_state {
-       struct i2c_adapter *i2c;
-       struct dvb_frontend frontend;
-       struct jdvbt90502_config config;
-};
-
-/* NOTE: TC90502 has 16bit register-address? */
-/* register 0x0100 is used for reading PLL status, so reg is u16 here */
-static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
-                              const u16 reg, u8 *buf, const size_t count)
-{
-       int ret;
-       u8 wbuf[3];
-       struct i2c_msg msg[2];
-
-       wbuf[0] = reg & 0xFF;
-       wbuf[1] = 0;
-       wbuf[2] = reg >> 8;
-
-       msg[0].addr = state->config.demod_address;
-       msg[0].flags = 0;
-       msg[0].buf = wbuf;
-       msg[0].len = sizeof(wbuf);
-
-       msg[1].addr = msg[0].addr;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = buf;
-       msg[1].len = count;
-
-       ret = i2c_transfer(state->i2c, msg, 2);
-       if (ret != 2) {
-               deb_fe(" reg read failed.\n");
-               return -EREMOTEIO;
-       }
-       return 0;
-}
-
-/* currently 16bit register-address is not used, so reg is u8 here */
-static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
-                                      const u8 reg, const u8 val)
-{
-       struct i2c_msg msg;
-       u8 wbuf[2];
-
-       wbuf[0] = reg;
-       wbuf[1] = val;
-
-       msg.addr = state->config.demod_address;
-       msg.flags = 0;
-       msg.buf = wbuf;
-       msg.len = sizeof(wbuf);
-
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-               deb_fe(" reg write failed.");
-               return -EREMOTEIO;
-       }
-       return 0;
-}
-
-static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
-       struct jdvbt90502_state *state = fe->demodulator_priv;
-       int err, i;
-       for (i = 0; i < len - 1; i++) {
-               err = jdvbt90502_single_reg_write(state,
-                                                 buf[0] + i, buf[i + 1]);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-/* read pll status byte via the demodulator's I2C register */
-/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
-static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
-{
-       int ret;
-
-       /* +1 for reading */
-       u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
-
-       *result = 0;
-
-       ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
-                                         pll_addr_byte);
-       if (ret)
-               goto error;
-
-       ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
-       if (ret)
-               goto error;
-
-       deb_fe("PLL read val:%02x\n", *result);
-       return 0;
-
-error:
-       deb_fe("%s:ret == %d\n", __func__, ret);
-       return -EREMOTEIO;
-}
-
-
-/* set pll frequency via the demodulator's I2C register */
-static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
-{
-       int ret;
-       int retry;
-       u8 res1;
-       u8 res2[9];
-
-       u8 pll_freq_cmd[PLL_CMD_LEN];
-       u8 pll_agc_cmd[PLL_CMD_LEN];
-       struct i2c_msg msg[2];
-       u32 f;
-
-       deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
-              state->frontend.ops.info.frequency_stepsize_hz);
-       /* freq -> oscilator frequency conversion. */
-       /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */
-       f = freq / state->frontend.ops.info.frequency_stepsize_hz;
-       /* add 399[1/7 MHZ] = 57MHz for the IF  */
-       f += 399;
-       /* add center frequency shift if necessary */
-       if (f % 7 == 0)
-               f++;
-       pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
-       pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
-       pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
-       pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
-       pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
-       pll_freq_cmd[BANDSWITCH_BYTE] = 0x08;   /* UHF band */
-
-       msg[0].addr = state->config.demod_address;
-       msg[0].flags = 0;
-       msg[0].buf = pll_freq_cmd;
-       msg[0].len = sizeof(pll_freq_cmd);
-
-       ret = i2c_transfer(state->i2c, &msg[0], 1);
-       if (ret != 1)
-               goto error;
-
-       udelay(50);
-
-       pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
-       pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
-       pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
-       pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
-       pll_agc_cmd[CONTROL_BYTE] = 0x9A; /*  AGC_CTRL instead of BANDSWITCH */
-       pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
-       /* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
-
-       msg[1].addr = msg[0].addr;
-       msg[1].flags = 0;
-       msg[1].buf = pll_agc_cmd;
-       msg[1].len = sizeof(pll_agc_cmd);
-
-       ret = i2c_transfer(state->i2c, &msg[1], 1);
-       if (ret != 1)
-               goto error;
-
-       /* I don't know what these cmds are for,  */
-       /* but the USB log on a windows box contains them */
-       ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
-       ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
-       if (ret)
-               goto error;
-       udelay(100);
-
-       /* wait for the demod to be ready? */
-#define RETRY_COUNT 5
-       for (retry = 0; retry < RETRY_COUNT; retry++) {
-               ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
-               if (ret)
-                       goto error;
-               /* if (res1 != 0x00) goto error; */
-               ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
-               if (ret)
-                       goto error;
-               if (res2[0] >= 0xA7)
-                       break;
-               msleep(100);
-       }
-       if (retry >= RETRY_COUNT) {
-               deb_fe("%s: FE does not get ready after freq setting.\n",
-                      __func__);
-               return -EREMOTEIO;
-       }
-
-       return 0;
-error:
-       deb_fe("%s:ret == %d\n", __func__, ret);
-       return -EREMOTEIO;
-}
-
-static int jdvbt90502_read_status(struct dvb_frontend *fe,
-                                 enum fe_status *state)
-{
-       u8 result;
-       int ret;
-
-       *state = FE_HAS_SIGNAL;
-
-       ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
-       if (ret) {
-               deb_fe("%s:ret == %d\n", __func__, ret);
-               return -EREMOTEIO;
-       }
-
-       *state = FE_HAS_SIGNAL
-               | FE_HAS_CARRIER
-               | FE_HAS_VITERBI
-               | FE_HAS_SYNC;
-
-       if (result & PLL_STATUS_LOCKED)
-               *state |= FE_HAS_LOCK;
-
-       return 0;
-}
-
-static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
-                                          u16 *strength)
-{
-       int ret;
-       u8 rbuf[37];
-
-       *strength = 0;
-
-       /* status register (incl. signal strength) : 0x89  */
-       /* TODO: read just the necessary registers [0x8B..0x8D]? */
-       ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
-                                 rbuf, sizeof(rbuf));
-
-       if (ret) {
-               deb_fe("%s:ret == %d\n", __func__, ret);
-               return -EREMOTEIO;
-       }
-
-       /* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
-       *strength = (rbuf[3] << 8) + rbuf[4];
-       if (rbuf[2])
-               *strength = 0xffff;
-
-       return 0;
-}
-
-static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-
-       /**
-        * NOTE: ignore all the parameters except frequency.
-        *       others should be fixed to the proper value for ISDB-T,
-        *       but don't check here.
-        */
-
-       struct jdvbt90502_state *state = fe->demodulator_priv;
-       int ret;
-
-       deb_fe("%s: Freq:%d\n", __func__, p->frequency);
-
-       /* This driver only works on auto mode */
-       p->inversion = INVERSION_AUTO;
-       p->bandwidth_hz = 6000000;
-       p->code_rate_HP = FEC_AUTO;
-       p->code_rate_LP = FEC_AUTO;
-       p->modulation = QAM_64;
-       p->transmission_mode = TRANSMISSION_MODE_AUTO;
-       p->guard_interval = GUARD_INTERVAL_AUTO;
-       p->hierarchy = HIERARCHY_AUTO;
-       p->delivery_system = SYS_ISDBT;
-
-       ret = jdvbt90502_pll_set_freq(state, p->frequency);
-       if (ret) {
-               deb_fe("%s:ret == %d\n", __func__, ret);
-               return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
-
-/*
- * (reg, val) commad list to initialize this module.
- *  captured on a Windows box.
- */
-static u8 init_code[][2] = {
-       {0x01, 0x40},
-       {0x04, 0x38},
-       {0x05, 0x40},
-       {0x07, 0x40},
-       {0x0F, 0x4F},
-       {0x11, 0x21},
-       {0x12, 0x0B},
-       {0x13, 0x2F},
-       {0x14, 0x31},
-       {0x16, 0x02},
-       {0x21, 0xC4},
-       {0x22, 0x20},
-       {0x2C, 0x79},
-       {0x2D, 0x34},
-       {0x2F, 0x00},
-       {0x30, 0x28},
-       {0x31, 0x31},
-       {0x32, 0xDF},
-       {0x38, 0x01},
-       {0x39, 0x78},
-       {0x3B, 0x33},
-       {0x3C, 0x33},
-       {0x48, 0x90},
-       {0x51, 0x68},
-       {0x5E, 0x38},
-       {0x71, 0x00},
-       {0x72, 0x08},
-       {0x77, 0x00},
-       {0xC0, 0x21},
-       {0xC1, 0x10},
-       {0xE4, 0x1A},
-       {0xEA, 0x1F},
-       {0x77, 0x00},
-       {0x71, 0x00},
-       {0x71, 0x00},
-       {0x76, 0x0C},
-};
-
-static int jdvbt90502_init(struct dvb_frontend *fe)
-{
-       int i = -1;
-       int ret;
-       struct i2c_msg msg;
-
-       struct jdvbt90502_state *state = fe->demodulator_priv;
-
-       deb_fe("%s called.\n", __func__);
-
-       msg.addr = state->config.demod_address;
-       msg.flags = 0;
-       msg.len = 2;
-       for (i = 0; i < ARRAY_SIZE(init_code); i++) {
-               msg.buf = init_code[i];
-               ret = i2c_transfer(state->i2c, &msg, 1);
-               if (ret != 1)
-                       goto error;
-       }
-       fe->dtv_property_cache.delivery_system = SYS_ISDBT;
-       msleep(100);
-
-       return 0;
-
-error:
-       deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
-       return -EREMOTEIO;
-}
-
-
-static void jdvbt90502_release(struct dvb_frontend *fe)
-{
-       struct jdvbt90502_state *state = fe->demodulator_priv;
-       kfree(state);
-}
-
-
-static const struct dvb_frontend_ops jdvbt90502_ops;
-
-struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
-{
-       struct jdvbt90502_state *state = NULL;
-
-       deb_info("%s called.\n", __func__);
-
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
-       if (state == NULL)
-               goto error;
-
-       /* setup the state */
-       state->i2c = &d->i2c_adap;
-       state->config = friio_fe_config;
-
-       /* create dvb_frontend */
-       state->frontend.ops = jdvbt90502_ops;
-       state->frontend.demodulator_priv = state;
-
-       if (jdvbt90502_init(&state->frontend) < 0)
-               goto error;
-
-       return &state->frontend;
-
-error:
-       kfree(state);
-       return NULL;
-}
-
-static const struct dvb_frontend_ops jdvbt90502_ops = {
-       .delsys = { SYS_ISDBT },
-       .info = {
-               .name                   = "Comtech JDVBT90502 ISDB-T",
-               .frequency_min_hz       = 473000000, /* UHF 13ch, center */
-               .frequency_max_hz       = 767142857, /* UHF 62ch, center */
-               .frequency_stepsize_hz  = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
-
-               /* NOTE: this driver ignores all parameters but frequency. */
-               .caps = FE_CAN_INVERSION_AUTO |
-                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO |
-                       FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO,
-       },
-
-       .release = jdvbt90502_release,
-
-       .init = jdvbt90502_init,
-       .write = _jdvbt90502_write,
-
-       .set_frontend = jdvbt90502_set_frontend,
-
-       .read_status = jdvbt90502_read_status,
-       .read_signal_strength = jdvbt90502_read_signal_strength,
-};
diff --git a/drivers/media/usb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c
deleted file mode 100644 (file)
index fe799a7..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 2.
- *
- * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
- */
-#include "friio.h"
-
-/* debug */
-int dvb_usb_friio_debug;
-module_param_named(debug, dvb_usb_friio_debug, int, 0644);
-MODULE_PARM_DESC(debug,
-                "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
-                DVB_USB_DEBUG_STATUS);
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-/*
- * Indirect I2C access to the PLL via FE.
- * whole I2C protocol data to the PLL is sent via the FE's I2C register.
- * This is done by a control msg to the FE with the I2C data accompanied, and
- * a specific USB request number is assigned for that purpose.
- *
- * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
- * TODO: refoctored, smarter i2c functions.
- */
-static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
-                                 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-       u16 index = wbuf[0];    /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
-       u16 value = addr << (8 + 1);
-       int wo = (rbuf == NULL || rlen == 0);   /* write only */
-       u8 req, type;
-
-       deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
-                wbuf[1], wbuf[0], wlen - 1);
-
-       if (wo && wlen >= 2) {
-               req = GL861_REQ_I2C_DATA_CTRL_WRITE;
-               type = GL861_WRITE;
-               udelay(20);
-               return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-                                      req, type, value, index,
-                                      &wbuf[1], wlen - 1, 2000);
-       }
-
-       deb_xfer("not supported ctrl-msg, aborting.");
-       return -EINVAL;
-}
-
-/* normal I2C access (without extra data arguments).
- * write to the register wbuf[0] at I2C address addr with the value wbuf[1],
- *  or read from the register wbuf[0].
- * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
- */
-static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
-                        u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
-       u16 index;
-       u16 value = addr << (8 + 1);
-       int wo = (rbuf == NULL || rlen == 0);   /* write-only */
-       u8 req, type;
-       unsigned int pipe;
-
-       /* special case for the indirect I2C access to the PLL via FE, */
-       if (addr == friio_fe_config.demod_address &&
-           wbuf[0] == JDVBT90502_2ND_I2C_REG)
-               return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
-
-       if (wo) {
-               req = GL861_REQ_I2C_WRITE;
-               type = GL861_WRITE;
-               pipe = usb_sndctrlpipe(d->udev, 0);
-       } else {                /* rw */
-               req = GL861_REQ_I2C_READ;
-               type = GL861_READ;
-               pipe = usb_rcvctrlpipe(d->udev, 0);
-       }
-
-       switch (wlen) {
-       case 1:
-               index = wbuf[0];
-               break;
-       case 2:
-               index = wbuf[0];
-               value = value + wbuf[1];
-               break;
-       case 3:
-               /* special case for 16bit register-address */
-               index = (wbuf[2] << 8) | wbuf[0];
-               value = value + wbuf[1];
-               break;
-       default:
-               deb_xfer("wlen = %x, aborting.", wlen);
-               return -EINVAL;
-       }
-       msleep(1);
-       return usb_control_msg(d->udev, pipe, req, type,
-                              value, index, rbuf, rlen, 2000);
-}
-
-/* I2C */
-static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-                         int num)
-{
-       struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int i;
-
-
-       if (num > 2)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-               return -EAGAIN;
-
-       for (i = 0; i < num; i++) {
-               /* write/read request */
-               if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
-                       if (gl861_i2c_msg(d, msg[i].addr,
-                                         msg[i].buf, msg[i].len,
-                                         msg[i + 1].buf, msg[i + 1].len) < 0)
-                               break;
-                       i++;
-               } else
-                       if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-                                         msg[i].len, NULL, 0) < 0)
-                               break;
-       }
-
-       mutex_unlock(&d->i2c_mutex);
-       return i;
-}
-
-static u32 gl861_i2c_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_I2C;
-}
-
-static int friio_ext_ctl(struct dvb_usb_adapter *adap,
-                        u32 sat_color, int lnb_on)
-{
-       int i;
-       int ret;
-       struct i2c_msg msg;
-       u8 *buf;
-       u32 mask;
-       u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
-
-       buf = kmalloc(2, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       msg.addr = 0x00;
-       msg.flags = 0;
-       msg.len = 2;
-       msg.buf = buf;
-
-       buf[0] = 0x00;
-
-       /* send 2bit header (&B10) */
-       buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
-       ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-       buf[1] |= FRIIO_CTL_CLK;
-       ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-       buf[1] = lnb | FRIIO_CTL_STROBE;
-       ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-       buf[1] |= FRIIO_CTL_CLK;
-       ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-       /* send 32bit(satur, R, G, B) data in serial */
-       mask = 1 << 31;
-       for (i = 0; i < 32; i++) {
-               buf[1] = lnb | FRIIO_CTL_STROBE;
-               if (sat_color & mask)
-                       buf[1] |= FRIIO_CTL_LED;
-               ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-               buf[1] |= FRIIO_CTL_CLK;
-               ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-               mask >>= 1;
-       }
-
-       /* set the strobe off */
-       buf[1] = lnb;
-       ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-       buf[1] |= FRIIO_CTL_CLK;
-       ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
-
-       kfree(buf);
-       return (ret == 70);
-}
-
-
-static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
-
-/* TODO: move these init cmds to the FE's init routine? */
-static u8 streaming_init_cmds[][2] = {
-       {0x33, 0x08},
-       {0x37, 0x40},
-       {0x3A, 0x1F},
-       {0x3B, 0xFF},
-       {0x3C, 0x1F},
-       {0x3D, 0xFF},
-       {0x38, 0x00},
-       {0x35, 0x00},
-       {0x39, 0x00},
-       {0x36, 0x00},
-};
-static int cmdlen = sizeof(streaming_init_cmds) / 2;
-
-/*
- * Command sequence in this init function is a replay
- *  of the captured USB commands from the Windows proprietary driver.
- */
-static int friio_initialize(struct dvb_usb_device *d)
-{
-       int ret;
-       int i;
-       int retry = 0;
-       u8 *rbuf, *wbuf;
-
-       deb_info("%s called.\n", __func__);
-
-       wbuf = kmalloc(3, GFP_KERNEL);
-       if (!wbuf)
-               return -ENOMEM;
-
-       rbuf = kmalloc(2, GFP_KERNEL);
-       if (!rbuf) {
-               kfree(wbuf);
-               return -ENOMEM;
-       }
-
-       /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
-       /* because the i2c device is not set up yet. */
-       wbuf[0] = 0x11;
-       wbuf[1] = 0x02;
-       ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-       msleep(2);
-
-       wbuf[0] = 0x11;
-       wbuf[1] = 0x00;
-       ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-       msleep(1);
-
-       /* following msgs should be in the FE's init code? */
-       /* cmd sequence to identify the device type? (friio black/white) */
-       wbuf[0] = 0x03;
-       wbuf[1] = 0x80;
-       /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
-       ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-                             GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
-                             0x1200, 0x0100, wbuf, 2, 2000);
-       if (ret < 0)
-               goto error;
-
-       msleep(2);
-       wbuf[0] = 0x00;
-       wbuf[2] = 0x01;         /* reg.0x0100 */
-       wbuf[1] = 0x00;
-       ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
-       /* my Friio White returns 0xffff. */
-       if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
-               goto error;
-
-       msleep(2);
-       wbuf[0] = 0x03;
-       wbuf[1] = 0x80;
-       ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
-                             GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
-                             0x9000, 0x0100, wbuf, 2, 2000);
-       if (ret < 0)
-               goto error;
-
-       msleep(2);
-       wbuf[0] = 0x00;
-       wbuf[2] = 0x01;         /* reg.0x0100 */
-       wbuf[1] = 0x00;
-       ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
-       /* my Friio White returns 0xffff again. */
-       if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
-               goto error;
-
-       msleep(1);
-
-restart:
-       /* ============ start DEMOD init cmds ================== */
-       /* read PLL status to clear the POR bit */
-       wbuf[0] = JDVBT90502_2ND_I2C_REG;
-       wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1;    /* +1 for reading */
-       ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-
-       msleep(5);
-       /* note: DEMODULATOR has 16bit register-address. */
-       wbuf[0] = 0x00;
-       wbuf[2] = 0x01;         /* reg addr: 0x0100 */
-       wbuf[1] = 0x00;         /* val: not used */
-       ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
-       if (ret < 0)
-               goto error;
-/*
-       msleep(1);
-       wbuf[0] = 0x80;
-       wbuf[1] = 0x00;
-       ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
-       if (ret < 0)
-               goto error;
- */
-       if (rbuf[0] & 0x80) {   /* still in PowerOnReset state? */
-               if (++retry > 3) {
-                       deb_info("failed to get the correct FE demod status:0x%02x\n",
-                                rbuf[0]);
-                       goto error;
-               }
-               msleep(100);
-               goto restart;
-       }
-
-       /* TODO: check return value in rbuf */
-       /* =========== end DEMOD init cmds ===================== */
-       msleep(1);
-
-       wbuf[0] = 0x30;
-       wbuf[1] = 0x04;
-       ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-
-       msleep(2);
-       /* following 2 cmds unnecessary? */
-       wbuf[0] = 0x00;
-       wbuf[1] = 0x01;
-       ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-
-       wbuf[0] = 0x06;
-       wbuf[1] = 0x0F;
-       ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
-       if (ret < 0)
-               goto error;
-
-       /* some streaming ctl cmds (maybe) */
-       msleep(10);
-       for (i = 0; i < cmdlen; i++) {
-               ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
-                                   NULL, 0);
-               if (ret < 0)
-                       goto error;
-               msleep(1);
-       }
-       msleep(20);
-
-       /* change the LED color etc. */
-       ret = friio_streaming_ctrl(&d->adapter[0], 0);
-       if (ret < 0)
-               goto error;
-
-       return 0;
-
-error:
-       kfree(wbuf);
-       kfree(rbuf);
-       deb_info("%s:ret == %d\n", __func__, ret);
-       return -EIO;
-}
-
-/* Callbacks for DVB USB */
-
-static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       int ret;
-
-       deb_info("%s called.(%d)\n", __func__, onoff);
-
-       /* set the LED color and saturation (and LNB on) */
-       if (onoff)
-               ret = friio_ext_ctl(adap, 0x6400ff64, 1);
-       else
-               ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
-
-       if (ret != 1) {
-               deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
-               return -EREMOTEIO;
-       }
-       return 0;
-}
-
-static int friio_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       if (friio_initialize(adap->dev) < 0)
-               return -EIO;
-
-       adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
-       if (adap->fe_adap[0].fe == NULL)
-               return -EIO;
-
-       return 0;
-}
-
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties friio_properties;
-
-static int friio_probe(struct usb_interface *intf,
-                      const struct usb_device_id *id)
-{
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
-       int ret;
-
-       if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
-               return -ENODEV;
-
-       alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
-       if (alt == NULL) {
-               deb_rc("not alt found!\n");
-               return -ENODEV;
-       }
-       ret = usb_set_interface(interface_to_usbdev(intf),
-                               alt->desc.bInterfaceNumber,
-                               alt->desc.bAlternateSetting);
-       if (ret != 0) {
-               deb_rc("failed to set alt-setting!\n");
-               return ret;
-       }
-
-       ret = dvb_usb_device_init(intf, &friio_properties,
-                                 THIS_MODULE, &d, adapter_nr);
-       if (ret == 0)
-               friio_streaming_ctrl(&d->adapter[0], 1);
-
-       return ret;
-}
-
-
-struct jdvbt90502_config friio_fe_config = {
-       .demod_address = FRIIO_DEMOD_ADDR,
-       .pll_address = FRIIO_PLL_ADDR,
-};
-
-static struct i2c_algorithm gl861_i2c_algo = {
-       .master_xfer   = gl861_i2c_xfer,
-       .functionality = gl861_i2c_func,
-};
-
-static struct usb_device_id friio_table[] = {
-       { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
-       { }             /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, friio_table);
-
-
-static struct dvb_usb_device_properties friio_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .usb_ctrl = DEVICE_SPECIFIC,
-
-       .size_of_priv = 0,
-
-       .num_adapters = 1,
-       .adapter = {
-               /* caps:0 =>  no pid filter, 188B TS packet */
-               /* GL861 has a HW pid filter, but no info available. */
-               {
-               .num_frontends = 1,
-               .fe = {{
-                       .caps  = 0,
-
-                       .frontend_attach  = friio_frontend_attach,
-                       .streaming_ctrl = friio_streaming_ctrl,
-
-                       .stream = {
-                               .type = USB_BULK,
-                               /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
-                               .count = 8,
-                               .endpoint = 0x01,
-                               .u = {
-                                       /* GL861 has 6KB buf inside */
-                                       .bulk = {
-                                               .buffersize = 16384,
-                                       }
-                               }
-                       },
-               }},
-               }
-       },
-       .i2c_algo = &gl861_i2c_algo,
-
-       .num_device_descs = 1,
-       .devices = {
-               {
-                       .name = "774 Friio ISDB-T USB2.0",
-                       .cold_ids = { NULL },
-                       .warm_ids = { &friio_table[0], NULL },
-               },
-       }
-};
-
-static struct usb_driver friio_driver = {
-       .name           = "dvb_usb_friio",
-       .probe          = friio_probe,
-       .disconnect     = dvb_usb_device_exit,
-       .id_table       = friio_table,
-};
-
-module_usb_driver(friio_driver);
-
-MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
-MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
-MODULE_VERSION("0.2");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/friio.h b/drivers/media/usb/dvb-usb/friio.h
deleted file mode 100644 (file)
index a53af56..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
- *
- * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
- *
- * This module is based off the the gl861 and vp702x modules.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 2.
- *
- * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
- */
-#ifndef _DVB_USB_FRIIO_H_
-#define _DVB_USB_FRIIO_H_
-
-/**
- *      Friio Components
- *       USB hub:                                AU4254
- *         USB controller(+ TS dmx & streaming): GL861
- *         Frontend:                             comtech JDVBT-90502
- *             (tuner PLL:                       tua6034, I2C addr:(0xC0 >> 1))
- *             (OFDM demodulator:                TC90502, I2C addr:(0x30 >> 1))
- *         LED x3 (+LNB) control:                PIC 16F676
- *         EEPROM:                               24C08
- *
- *        (USB smart card reader:                AU9522)
- *
- */
-
-#define DVB_USB_LOG_PREFIX "friio"
-#include "dvb-usb.h"
-
-extern int dvb_usb_friio_debug;
-#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_friio_debug, 0x04, args)
-#define deb_fe(args...)   dprintk(dvb_usb_friio_debug, 0x08, args)
-
-/* Vendor requests */
-#define GL861_WRITE            0x40
-#define GL861_READ             0xc0
-
-/* command bytes */
-#define GL861_REQ_I2C_WRITE    0x01
-#define GL861_REQ_I2C_READ     0x02
-/* For control msg with data argument */
-/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
-#define GL861_REQ_I2C_DATA_CTRL_WRITE  0x03
-
-#define GL861_ALTSETTING_COUNT 2
-#define FRIIO_BULK_ALTSETTING  0
-#define FRIIO_ISOC_ALTSETTING  1
-
-/* LED & LNB control via PIC. */
-/* basically, it's serial control with clock and strobe. */
-/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
-/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
-#define FRIIO_CTL_LNB (1 << 0)
-#define FRIIO_CTL_STROBE (1 << 1)
-#define FRIIO_CTL_CLK (1 << 2)
-#define FRIIO_CTL_LED (1 << 3)
-
-/* Front End related */
-
-#define FRIIO_DEMOD_ADDR  (0x30 >> 1)
-#define FRIIO_PLL_ADDR  (0xC0 >> 1)
-
-#define JDVBT90502_PLL_CLK     4000000
-#define JDVBT90502_PLL_DIVIDER 28
-
-#define JDVBT90502_2ND_I2C_REG 0xFE
-
-/* byte index for pll i2c command data structure*/
-/* see datasheet for tua6034 */
-#define DEMOD_REDIRECT_REG 0
-#define ADDRESS_BYTE       1
-#define DIVIDER_BYTE1      2
-#define DIVIDER_BYTE2      3
-#define CONTROL_BYTE       4
-#define BANDSWITCH_BYTE    5
-#define AGC_CTRL_BYTE      5
-#define PLL_CMD_LEN        6
-
-/* bit masks for PLL STATUS response */
-#define PLL_STATUS_POR_MODE   0x80 /* 1: Power on Reset (test) Mode */
-#define PLL_STATUS_LOCKED     0x40 /* 1: locked */
-#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
-#define PLL_STATUS_TESTMODE   0x07 /* digital output level (5 level) */
-  /* 0.15Vcc step   0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
-
-
-struct jdvbt90502_config {
-       u8 demod_address; /* i2c addr for demodulator IC */
-       u8 pll_address;   /* PLL addr on the secondary i2c*/
-};
-extern struct jdvbt90502_config friio_fe_config;
-
-extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
-#endif
index 87b887b7604ef31716faccaa12812897e9b20641..1283c7ca9ad51a4fa399d81a107aeea14703b209 100644 (file)
@@ -1958,7 +1958,7 @@ const struct em28xx_board em28xx_boards[] = {
                } },
        },
        [EM2882_BOARD_TERRATEC_HYBRID_XS] = {
-               .name         = "Terratec Cinnergy Hybrid T USB XS (em2882)",
+               .name         = "Terratec Cinergy Hybrid T USB XS (em2882)",
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
index 365c78b748dd5cb1e5b739a462a7e4df656738b7..b085b14f3f8778747eef3fb4a58c14edc66dc419 100644 (file)
@@ -586,7 +586,7 @@ unlock:
        else
                pulse8->config_pending = true;
        mutex_unlock(&pulse8->config_lock);
-       return err;
+       return log_addr == CEC_LOG_ADDR_INVALID ? 0 : err;
 }
 
 static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
index 7702285c15193f144f5cf9e3305a1685b185ecd4..446a999dd2ce1519656914fb1e79b44225f7017c 100644 (file)
@@ -1698,7 +1698,7 @@ static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
        if (!hdw->flag_tripped) return 0;
        hdw->flag_tripped = 0;
        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                  "Clearing driver error statuss");
+                  "Clearing driver error status");
        return !0;
 }
 
index 97a93ed4bcda74a5923734aacfcbb198597fba85..08d5b7aa3537164c91c866719d741eb21e3749ae 100644 (file)
@@ -703,16 +703,19 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv,
        return 0;
 }
 
-static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap)
+static int pvr2_g_pixelaspect(struct file *file, void *priv,
+                             int type, struct v4l2_fract *f)
 {
        struct pvr2_v4l2_fh *fh = file->private_data;
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       struct v4l2_cropcap cap = { .type = type };
        int ret;
 
-       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       ret = pvr2_hdw_get_cropcap(hdw, cap);
-       cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+       ret = pvr2_hdw_get_cropcap(hdw, &cap);
+       if (!ret)
+               *f = cap.pixelaspect;
        return ret;
 }
 
@@ -815,7 +818,7 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
        .vidioc_g_audio                     = pvr2_g_audio,
        .vidioc_enumaudio                   = pvr2_enumaudio,
        .vidioc_enum_input                  = pvr2_enum_input,
-       .vidioc_cropcap                     = pvr2_cropcap,
+       .vidioc_g_pixelaspect               = pvr2_g_pixelaspect,
        .vidioc_s_selection                 = pvr2_s_selection,
        .vidioc_g_selection                 = pvr2_g_selection,
        .vidioc_g_input                     = pvr2_g_input,
index be3634407f1f361845d12f770dbbef272478c1e4..2ffded08407b8d56a7cb625003176ecdaeebfc79 100644 (file)
@@ -225,10 +225,9 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
                return -ENOENT;
        }
 
-       phdr = kmalloc(size, GFP_KERNEL);
+       phdr = kmemdup(buffer, size, GFP_KERNEL);
        if (!phdr)
                return -ENOMEM;
-       memcpy(phdr, buffer, size);
 
        pr_debug("sending %s(%d) size: %d\n",
                  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
index e11d5d5b7c263e9a00be1e2334b108f2f14111ee..b8ec74d98e8d59bb22d01258114ca15526b43532 100644 (file)
@@ -116,6 +116,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
                }
        },
+       {
+               .ident = "ASUS A6VM",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+               }
+       },
        {}
 };
 
@@ -164,7 +171,11 @@ int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value)
                *value = *buf;
 
        kfree(buf);
-       return ret;
+
+       if (ret < 0)
+               return ret;
+       else
+               return 0;
 }
 
 static int stk_start_stream(struct stk_camera *dev)
index bc369a0934a36258d99b5d6dde0b02dc51fe6d8b..b62cbd8001116e5f5cbf80b57df1b6243205dbbe 100644 (file)
@@ -214,6 +214,11 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_INZI,
                .fcc            = V4L2_PIX_FMT_INZI,
        },
+       {
+               .name           = "4-bit Depth Confidence (Packed)",
+               .guid           = UVC_GUID_FORMAT_CNF4,
+               .fcc            = V4L2_PIX_FMT_CNF4,
+       },
 };
 
 /* ------------------------------------------------------------------------
@@ -390,6 +395,50 @@ static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
        return NULL;
 }
 
+/* ------------------------------------------------------------------------
+ * Streaming Object Management
+ */
+
+static void uvc_stream_delete(struct uvc_streaming *stream)
+{
+       if (stream->async_wq)
+               destroy_workqueue(stream->async_wq);
+
+       mutex_destroy(&stream->mutex);
+
+       usb_put_intf(stream->intf);
+
+       kfree(stream->format);
+       kfree(stream->header.bmaControls);
+       kfree(stream);
+}
+
+static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
+                                           struct usb_interface *intf)
+{
+       struct uvc_streaming *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       mutex_init(&stream->mutex);
+
+       stream->dev = dev;
+       stream->intf = usb_get_intf(intf);
+       stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+       /* Allocate a stream specific work queue for asynchronous tasks. */
+       stream->async_wq = alloc_workqueue("uvcvideo", WQ_UNBOUND | WQ_HIGHPRI,
+                                          0);
+       if (!stream->async_wq) {
+               uvc_stream_delete(stream);
+               return NULL;
+       }
+
+       return stream;
+}
+
 /* ------------------------------------------------------------------------
  * Descriptors parsing
  */
@@ -682,17 +731,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
                return -EINVAL;
        }
 
-       streaming = kzalloc(sizeof(*streaming), GFP_KERNEL);
+       streaming = uvc_stream_new(dev, intf);
        if (streaming == NULL) {
                usb_driver_release_interface(&uvc_driver.driver, intf);
-               return -EINVAL;
+               return -ENOMEM;
        }
 
-       mutex_init(&streaming->mutex);
-       streaming->dev = dev;
-       streaming->intf = usb_get_intf(intf);
-       streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
        /* The Pico iMage webcam has its class-specific interface descriptors
         * after the endpoint descriptors.
         */
@@ -899,10 +943,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
 
 error:
        usb_driver_release_interface(&uvc_driver.driver, intf);
-       usb_put_intf(intf);
-       kfree(streaming->format);
-       kfree(streaming->header.bmaControls);
-       kfree(streaming);
+       uvc_stream_delete(streaming);
        return ret;
 }
 
@@ -1810,7 +1851,7 @@ static int uvc_scan_device(struct uvc_device *dev)
  * is released.
  *
  * As this function is called after or during disconnect(), all URBs have
- * already been canceled by the USB core. There is no need to kill the
+ * already been cancelled by the USB core. There is no need to kill the
  * interrupt URB manually.
  */
 static void uvc_delete(struct kref *kref)
@@ -1824,11 +1865,7 @@ static void uvc_delete(struct kref *kref)
        usb_put_intf(dev->intf);
        usb_put_dev(dev->udev);
 
-       if (dev->vdev.dev)
-               v4l2_device_unregister(&dev->vdev);
 #ifdef CONFIG_MEDIA_CONTROLLER
-       if (media_devnode_is_registered(dev->mdev.devnode))
-               media_device_unregister(&dev->mdev);
        media_device_cleanup(&dev->mdev);
 #endif
 
@@ -1852,10 +1889,7 @@ static void uvc_delete(struct kref *kref)
                streaming = list_entry(p, struct uvc_streaming, list);
                usb_driver_release_interface(&uvc_driver.driver,
                        streaming->intf);
-               usb_put_intf(streaming->intf);
-               kfree(streaming->format);
-               kfree(streaming->header.bmaControls);
-               kfree(streaming);
+               uvc_stream_delete(streaming);
        }
 
        kfree(dev);
@@ -1885,6 +1919,15 @@ static void uvc_unregister_video(struct uvc_device *dev)
 
                uvc_debugfs_cleanup_stream(stream);
        }
+
+       uvc_status_unregister(dev);
+
+       if (dev->vdev.dev)
+               v4l2_device_unregister(&dev->vdev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+       if (media_devnode_is_registered(dev->mdev.devnode))
+               media_device_unregister(&dev->mdev);
+#endif
 }
 
 int uvc_register_video_device(struct uvc_device *dev,
index 81e6f2187bfb032e9537b8267ceac6988852dcaa..39a4e4482b2378e72f02b9fb3f9945bede6d694c 100644 (file)
@@ -99,9 +99,11 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
        return 0;
 }
 
-void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
-                       struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
+void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf,
+                       struct uvc_buffer *meta_buf)
 {
+       struct urb *urb = uvc_urb->urb;
+       struct uvc_streaming *stream = uvc_urb->stream;
        int ret, i;
 
        for (i = 0; i < urb->number_of_packets; ++i) {
index 8964e16f2b22d4ae3388dfaabfdec378c29ad65e..682698ec1118ff6363db5b3c49429b0d54861486 100644 (file)
@@ -142,6 +142,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
 
        spin_lock_irqsave(&queue->irqlock, flags);
        if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+               kref_init(&buf->ref);
                list_add_tail(&buf->queue, &queue->irqqueue);
        } else {
                /* If the device is disconnected return the buffer to userspace
@@ -169,18 +170,19 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
        struct uvc_streaming *stream = uvc_queue_to_stream(queue);
-       unsigned long flags;
        int ret;
 
+       lockdep_assert_irqs_enabled();
+
        queue->buf_used = 0;
 
-       ret = uvc_video_enable(stream, 1);
+       ret = uvc_video_start_streaming(stream);
        if (ret == 0)
                return 0;
 
-       spin_lock_irqsave(&queue->irqlock, flags);
+       spin_lock_irq(&queue->irqlock);
        uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
-       spin_unlock_irqrestore(&queue->irqlock, flags);
+       spin_unlock_irq(&queue->irqlock);
 
        return ret;
 }
@@ -188,14 +190,15 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
 static void uvc_stop_streaming(struct vb2_queue *vq)
 {
        struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
-       unsigned long flags;
+
+       lockdep_assert_irqs_enabled();
 
        if (vq->type != V4L2_BUF_TYPE_META_CAPTURE)
-               uvc_video_enable(uvc_queue_to_stream(queue), 0);
+               uvc_video_stop_streaming(uvc_queue_to_stream(queue));
 
-       spin_lock_irqsave(&queue->irqlock, flags);
+       spin_lock_irq(&queue->irqlock);
        uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
-       spin_unlock_irqrestore(&queue->irqlock, flags);
+       spin_unlock_irq(&queue->irqlock);
 }
 
 static const struct vb2_ops uvc_queue_qops = {
@@ -430,32 +433,93 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
        spin_unlock_irqrestore(&queue->irqlock, flags);
 }
 
-struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
-               struct uvc_buffer *buf)
+/*
+ * uvc_queue_get_current_buffer: Obtain the current working output buffer
+ *
+ * Buffers may span multiple packets, and even URBs, therefore the active buffer
+ * remains on the queue until the EOF marker.
+ */
+static struct uvc_buffer *
+__uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
+{
+       if (list_empty(&queue->irqqueue))
+               return NULL;
+
+       return list_first_entry(&queue->irqqueue, struct uvc_buffer, queue);
+}
+
+struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
 {
        struct uvc_buffer *nextbuf;
        unsigned long flags;
 
+       spin_lock_irqsave(&queue->irqlock, flags);
+       nextbuf = __uvc_queue_get_current_buffer(queue);
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+
+       return nextbuf;
+}
+
+/*
+ * uvc_queue_buffer_requeue: Requeue a buffer on our internal irqqueue
+ *
+ * Reuse a buffer through our internal queue without the need to 'prepare'.
+ * The buffer will be returned to userspace through the uvc_buffer_queue call if
+ * the device has been disconnected.
+ */
+static void uvc_queue_buffer_requeue(struct uvc_video_queue *queue,
+               struct uvc_buffer *buf)
+{
+       buf->error = 0;
+       buf->state = UVC_BUF_STATE_QUEUED;
+       buf->bytesused = 0;
+       vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
+
+       uvc_buffer_queue(&buf->buf.vb2_buf);
+}
+
+static void uvc_queue_buffer_complete(struct kref *ref)
+{
+       struct uvc_buffer *buf = container_of(ref, struct uvc_buffer, ref);
+       struct vb2_buffer *vb = &buf->buf.vb2_buf;
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+
        if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
-               buf->error = 0;
-               buf->state = UVC_BUF_STATE_QUEUED;
-               buf->bytesused = 0;
-               vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
-               return buf;
+               uvc_queue_buffer_requeue(queue, buf);
+               return;
        }
 
+       buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+       vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
+       vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+/*
+ * Release a reference on the buffer. Complete the buffer when the last
+ * reference is released.
+ */
+void uvc_queue_buffer_release(struct uvc_buffer *buf)
+{
+       kref_put(&buf->ref, uvc_queue_buffer_complete);
+}
+
+/*
+ * Remove this buffer from the queue. Lifetime will persist while async actions
+ * are still running (if any), and uvc_queue_buffer_release will give the buffer
+ * back to VB2 when all users have completed.
+ */
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+               struct uvc_buffer *buf)
+{
+       struct uvc_buffer *nextbuf;
+       unsigned long flags;
+
        spin_lock_irqsave(&queue->irqlock, flags);
        list_del(&buf->queue);
-       if (!list_empty(&queue->irqqueue))
-               nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
-                                          queue);
-       else
-               nextbuf = NULL;
+       nextbuf = __uvc_queue_get_current_buffer(queue);
        spin_unlock_irqrestore(&queue->irqlock, flags);
 
-       buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
-       vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
-       vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
+       uvc_queue_buffer_release(buf);
 
        return nextbuf;
 }
index 0722dc684378fd718e30cb7c15a8c9138a25a8ae..883e4cab45e79b1d3e1d0636963acfac73aa420b 100644 (file)
@@ -54,7 +54,7 @@ error:
        return ret;
 }
 
-static void uvc_input_cleanup(struct uvc_device *dev)
+static void uvc_input_unregister(struct uvc_device *dev)
 {
        if (dev->input)
                input_unregister_device(dev->input);
@@ -71,7 +71,7 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
 
 #else
 #define uvc_input_init(dev)
-#define uvc_input_cleanup(dev)
+#define uvc_input_unregister(dev)
 #define uvc_input_report_key(dev, code, value)
 #endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
 
@@ -292,12 +292,16 @@ int uvc_status_init(struct uvc_device *dev)
        return 0;
 }
 
-void uvc_status_cleanup(struct uvc_device *dev)
+void uvc_status_unregister(struct uvc_device *dev)
 {
        usb_kill_urb(dev->int_urb);
+       uvc_input_unregister(dev);
+}
+
+void uvc_status_cleanup(struct uvc_device *dev)
+{
        usb_free_urb(dev->int_urb);
        kfree(dev->status);
-       uvc_input_cleanup(dev);
 }
 
 int uvc_status_start(struct uvc_device *dev, gfp_t flags)
index 86a99f461fd8a7b92aee45641c47ccdc05fe85fb..84525ff0474504688403e7a7146b7025a54af61d 100644 (file)
@@ -1094,21 +1094,54 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
        return data[0];
 }
 
-static void uvc_video_decode_data(struct uvc_streaming *stream,
+/*
+ * uvc_video_decode_data_work: Asynchronous memcpy processing
+ *
+ * Copy URB data to video buffers in process context, releasing buffer
+ * references and requeuing the URB when done.
+ */
+static void uvc_video_copy_data_work(struct work_struct *work)
+{
+       struct uvc_urb *uvc_urb = container_of(work, struct uvc_urb, work);
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < uvc_urb->async_operations; i++) {
+               struct uvc_copy_op *op = &uvc_urb->copy_operations[i];
+
+               memcpy(op->dst, op->src, op->len);
+
+               /* Release reference taken on this buffer. */
+               uvc_queue_buffer_release(op->buf);
+       }
+
+       ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL);
+       if (ret < 0)
+               uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+                          ret);
+}
+
+static void uvc_video_decode_data(struct uvc_urb *uvc_urb,
                struct uvc_buffer *buf, const u8 *data, int len)
 {
-       unsigned int maxlen, nbytes;
-       void *mem;
+       unsigned int active_op = uvc_urb->async_operations;
+       struct uvc_copy_op *op = &uvc_urb->copy_operations[active_op];
+       unsigned int maxlen;
 
        if (len <= 0)
                return;
 
-       /* Copy the video data to the buffer. */
        maxlen = buf->length - buf->bytesused;
-       mem = buf->mem + buf->bytesused;
-       nbytes = min((unsigned int)len, maxlen);
-       memcpy(mem, data, nbytes);
-       buf->bytesused += nbytes;
+
+       /* Take a buffer reference for async work. */
+       kref_get(&buf->ref);
+
+       op->buf = buf;
+       op->src = data;
+       op->dst = buf->mem + buf->bytesused;
+       op->len = min_t(unsigned int, len, maxlen);
+
+       buf->bytesused += op->len;
 
        /* Complete the current frame if the buffer size was exceeded. */
        if (len > maxlen) {
@@ -1116,6 +1149,8 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
                buf->error = 1;
                buf->state = UVC_BUF_STATE_READY;
        }
+
+       uvc_urb->async_operations++;
 }
 
 static void uvc_video_decode_end(struct uvc_streaming *stream,
@@ -1291,9 +1326,11 @@ static void uvc_video_next_buffers(struct uvc_streaming *stream,
        *video_buf = uvc_queue_next_buffer(&stream->queue, *video_buf);
 }
 
-static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
+static void uvc_video_decode_isoc(struct uvc_urb *uvc_urb,
                        struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
 {
+       struct urb *urb = uvc_urb->urb;
+       struct uvc_streaming *stream = uvc_urb->stream;
        u8 *mem;
        int ret, i;
 
@@ -1322,7 +1359,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
                uvc_video_decode_meta(stream, meta_buf, mem, ret);
 
                /* Decode the payload data. */
-               uvc_video_decode_data(stream, buf, mem + ret,
+               uvc_video_decode_data(uvc_urb, buf, mem + ret,
                        urb->iso_frame_desc[i].actual_length - ret);
 
                /* Process the header again. */
@@ -1334,9 +1371,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
        }
 }
 
-static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
+static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb,
                        struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
 {
+       struct urb *urb = uvc_urb->urb;
+       struct uvc_streaming *stream = uvc_urb->stream;
        u8 *mem;
        int len, ret;
 
@@ -1380,9 +1419,9 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
         * sure buf is never dereferenced if NULL.
         */
 
-       /* Process video data. */
+       /* Prepare video data for processing. */
        if (!stream->bulk.skip_payload && buf != NULL)
-               uvc_video_decode_data(stream, buf, mem, len);
+               uvc_video_decode_data(uvc_urb, buf, mem, len);
 
        /* Detect the payload end by a URB smaller than the maximum size (or
         * a payload size equal to the maximum) and process the header again.
@@ -1402,9 +1441,12 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
        }
 }
 
-static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
+static void uvc_video_encode_bulk(struct uvc_urb *uvc_urb,
        struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
 {
+       struct urb *urb = uvc_urb->urb;
+       struct uvc_streaming *stream = uvc_urb->stream;
+
        u8 *mem = urb->transfer_buffer;
        int len = stream->urb_size, ret;
 
@@ -1447,7 +1489,8 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
 
 static void uvc_video_complete(struct urb *urb)
 {
-       struct uvc_streaming *stream = urb->context;
+       struct uvc_urb *uvc_urb = urb->context;
+       struct uvc_streaming *stream = uvc_urb->stream;
        struct uvc_video_queue *queue = &stream->queue;
        struct uvc_video_queue *qmeta = &stream->meta.queue;
        struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue;
@@ -1464,7 +1507,7 @@ static void uvc_video_complete(struct urb *urb)
                uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
                        "completion handler.\n", urb->status);
                /* fall through */
-       case -ENOENT:           /* usb_kill_urb() called. */
+       case -ENOENT:           /* usb_poison_urb() called. */
                if (stream->frozen)
                        return;
                /* fall through */
@@ -1476,11 +1519,7 @@ static void uvc_video_complete(struct urb *urb)
                return;
        }
 
-       spin_lock_irqsave(&queue->irqlock, flags);
-       if (!list_empty(&queue->irqqueue))
-               buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
-                                      queue);
-       spin_unlock_irqrestore(&queue->irqlock, flags);
+       buf = uvc_queue_get_current_buffer(queue);
 
        if (vb2_qmeta) {
                spin_lock_irqsave(&qmeta->irqlock, flags);
@@ -1490,12 +1529,26 @@ static void uvc_video_complete(struct urb *urb)
                spin_unlock_irqrestore(&qmeta->irqlock, flags);
        }
 
-       stream->decode(urb, stream, buf, buf_meta);
+       /* Re-initialise the URB async work. */
+       uvc_urb->async_operations = 0;
 
-       if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-               uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
-                       ret);
+       /*
+        * Process the URB headers, and optionally queue expensive memcpy tasks
+        * to be deferred to a work queue.
+        */
+       stream->decode(uvc_urb, buf, buf_meta);
+
+       /* If no async work is needed, resubmit the URB immediately. */
+       if (!uvc_urb->async_operations) {
+               ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC);
+               if (ret < 0)
+                       uvc_printk(KERN_ERR,
+                                  "Failed to resubmit video URB (%d).\n",
+                                  ret);
+               return;
        }
+
+       queue_work(stream->async_wq, &uvc_urb->work);
 }
 
 /*
@@ -1503,18 +1556,19 @@ static void uvc_video_complete(struct urb *urb)
  */
 static void uvc_free_urb_buffers(struct uvc_streaming *stream)
 {
-       unsigned int i;
+       struct uvc_urb *uvc_urb;
+
+       for_each_uvc_urb(uvc_urb, stream) {
+               if (!uvc_urb->buffer)
+                       continue;
 
-       for (i = 0; i < UVC_URBS; ++i) {
-               if (stream->urb_buffer[i]) {
 #ifndef CONFIG_DMA_NONCOHERENT
-                       usb_free_coherent(stream->dev->udev, stream->urb_size,
-                               stream->urb_buffer[i], stream->urb_dma[i]);
+               usb_free_coherent(stream->dev->udev, stream->urb_size,
+                                 uvc_urb->buffer, uvc_urb->dma);
 #else
-                       kfree(stream->urb_buffer[i]);
+               kfree(uvc_urb->buffer);
 #endif
-                       stream->urb_buffer[i] = NULL;
-               }
+               uvc_urb->buffer = NULL;
        }
 
        stream->urb_size = 0;
@@ -1551,19 +1605,23 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
        /* Retry allocations until one succeed. */
        for (; npackets > 1; npackets /= 2) {
                for (i = 0; i < UVC_URBS; ++i) {
+                       struct uvc_urb *uvc_urb = &stream->uvc_urb[i];
+
                        stream->urb_size = psize * npackets;
 #ifndef CONFIG_DMA_NONCOHERENT
-                       stream->urb_buffer[i] = usb_alloc_coherent(
+                       uvc_urb->buffer = usb_alloc_coherent(
                                stream->dev->udev, stream->urb_size,
-                               gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+                               gfp_flags | __GFP_NOWARN, &uvc_urb->dma);
 #else
-                       stream->urb_buffer[i] =
+                       uvc_urb->buffer =
                            kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
 #endif
-                       if (!stream->urb_buffer[i]) {
+                       if (!uvc_urb->buffer) {
                                uvc_free_urb_buffers(stream);
                                break;
                        }
+
+                       uvc_urb->stream = stream;
                }
 
                if (i == UVC_URBS) {
@@ -1582,21 +1640,26 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
 /*
  * Uninitialize isochronous/bulk URBs and free transfer buffers.
  */
-static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
+static void uvc_video_stop_transfer(struct uvc_streaming *stream,
+                                   int free_buffers)
 {
-       struct urb *urb;
-       unsigned int i;
+       struct uvc_urb *uvc_urb;
 
        uvc_video_stats_stop(stream);
 
-       for (i = 0; i < UVC_URBS; ++i) {
-               urb = stream->urb[i];
-               if (urb == NULL)
-                       continue;
+       /*
+        * We must poison the URBs rather than kill them to ensure that even
+        * after the completion handler returns, any asynchronous workqueues
+        * will be prevented from resubmitting the URBs.
+        */
+       for_each_uvc_urb(uvc_urb, stream)
+               usb_poison_urb(uvc_urb->urb);
 
-               usb_kill_urb(urb);
-               usb_free_urb(urb);
-               stream->urb[i] = NULL;
+       flush_workqueue(stream->async_wq);
+
+       for_each_uvc_urb(uvc_urb, stream) {
+               usb_free_urb(uvc_urb->urb);
+               uvc_urb->urb = NULL;
        }
 
        if (free_buffers)
@@ -1637,7 +1700,8 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
-       unsigned int npackets, i, j;
+       struct uvc_urb *uvc_urb;
+       unsigned int npackets, i;
        u16 psize;
        u32 size;
 
@@ -1650,35 +1714,35 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,
 
        size = npackets * psize;
 
-       for (i = 0; i < UVC_URBS; ++i) {
+       for_each_uvc_urb(uvc_urb, stream) {
                urb = usb_alloc_urb(npackets, gfp_flags);
                if (urb == NULL) {
-                       uvc_uninit_video(stream, 1);
+                       uvc_video_stop_transfer(stream, 1);
                        return -ENOMEM;
                }
 
                urb->dev = stream->dev->udev;
-               urb->context = stream;
+               urb->context = uvc_urb;
                urb->pipe = usb_rcvisocpipe(stream->dev->udev,
                                ep->desc.bEndpointAddress);
 #ifndef CONFIG_DMA_NONCOHERENT
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_dma = stream->urb_dma[i];
+               urb->transfer_dma = uvc_urb->dma;
 #else
                urb->transfer_flags = URB_ISO_ASAP;
 #endif
                urb->interval = ep->desc.bInterval;
-               urb->transfer_buffer = stream->urb_buffer[i];
+               urb->transfer_buffer = uvc_urb->buffer;
                urb->complete = uvc_video_complete;
                urb->number_of_packets = npackets;
                urb->transfer_buffer_length = size;
 
-               for (j = 0; j < npackets; ++j) {
-                       urb->iso_frame_desc[j].offset = j * psize;
-                       urb->iso_frame_desc[j].length = psize;
+               for (i = 0; i < npackets; ++i) {
+                       urb->iso_frame_desc[i].offset = i * psize;
+                       urb->iso_frame_desc[i].length = psize;
                }
 
-               stream->urb[i] = urb;
+               uvc_urb->urb = urb;
        }
 
        return 0;
@@ -1692,7 +1756,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
-       unsigned int npackets, pipe, i;
+       struct uvc_urb *uvc_urb;
+       unsigned int npackets, pipe;
        u16 psize;
        u32 size;
 
@@ -1716,22 +1781,21 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
        if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
                size = 0;
 
-       for (i = 0; i < UVC_URBS; ++i) {
+       for_each_uvc_urb(uvc_urb, stream) {
                urb = usb_alloc_urb(0, gfp_flags);
                if (urb == NULL) {
-                       uvc_uninit_video(stream, 1);
+                       uvc_video_stop_transfer(stream, 1);
                        return -ENOMEM;
                }
 
-               usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
-                       stream->urb_buffer[i], size, uvc_video_complete,
-                       stream);
+               usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer,
+                                 size, uvc_video_complete, uvc_urb);
 #ifndef CONFIG_DMA_NONCOHERENT
                urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_dma = stream->urb_dma[i];
+               urb->transfer_dma = uvc_urb->dma;
 #endif
 
-               stream->urb[i] = urb;
+               uvc_urb->urb = urb;
        }
 
        return 0;
@@ -1740,10 +1804,12 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
 /*
  * Initialize isochronous/bulk URBs and allocate transfer buffers.
  */
-static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
+static int uvc_video_start_transfer(struct uvc_streaming *stream,
+                                   gfp_t gfp_flags)
 {
        struct usb_interface *intf = stream->intf;
        struct usb_host_endpoint *ep;
+       struct uvc_urb *uvc_urb;
        unsigned int i;
        int ret;
 
@@ -1821,12 +1887,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
                return ret;
 
        /* Submit the URBs. */
-       for (i = 0; i < UVC_URBS; ++i) {
-               ret = usb_submit_urb(stream->urb[i], gfp_flags);
+       for_each_uvc_urb(uvc_urb, stream) {
+               ret = usb_submit_urb(uvc_urb->urb, gfp_flags);
                if (ret < 0) {
-                       uvc_printk(KERN_ERR, "Failed to submit URB %u "
-                                       "(%d).\n", i, ret);
-                       uvc_uninit_video(stream, 1);
+                       uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n",
+                                  uvc_urb_index(uvc_urb), ret);
+                       uvc_video_stop_transfer(stream, 1);
                        return ret;
                }
        }
@@ -1857,7 +1923,7 @@ int uvc_video_suspend(struct uvc_streaming *stream)
                return 0;
 
        stream->frozen = 1;
-       uvc_uninit_video(stream, 0);
+       uvc_video_stop_transfer(stream, 0);
        usb_set_interface(stream->dev->udev, stream->intfnum, 0);
        return 0;
 }
@@ -1893,7 +1959,7 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
        if (ret < 0)
                return ret;
 
-       return uvc_init_video(stream, GFP_NOIO);
+       return uvc_video_start_transfer(stream, GFP_NOIO);
 }
 
 /* ------------------------------------------------------------------------
@@ -1915,6 +1981,7 @@ int uvc_video_init(struct uvc_streaming *stream)
        struct uvc_streaming_control *probe = &stream->ctrl;
        struct uvc_format *format = NULL;
        struct uvc_frame *frame = NULL;
+       struct uvc_urb *uvc_urb;
        unsigned int i;
        int ret;
 
@@ -2000,41 +2067,17 @@ int uvc_video_init(struct uvc_streaming *stream)
                }
        }
 
+       /* Prepare asynchronous work items. */
+       for_each_uvc_urb(uvc_urb, stream)
+               INIT_WORK(&uvc_urb->work, uvc_video_copy_data_work);
+
        return 0;
 }
 
-/*
- * Enable or disable the video stream.
- */
-int uvc_video_enable(struct uvc_streaming *stream, int enable)
+int uvc_video_start_streaming(struct uvc_streaming *stream)
 {
        int ret;
 
-       if (!enable) {
-               uvc_uninit_video(stream, 1);
-               if (stream->intf->num_altsetting > 1) {
-                       usb_set_interface(stream->dev->udev,
-                                         stream->intfnum, 0);
-               } else {
-                       /* UVC doesn't specify how to inform a bulk-based device
-                        * when the video stream is stopped. Windows sends a
-                        * CLEAR_FEATURE(HALT) request to the video streaming
-                        * bulk endpoint, mimic the same behaviour.
-                        */
-                       unsigned int epnum = stream->header.bEndpointAddress
-                                          & USB_ENDPOINT_NUMBER_MASK;
-                       unsigned int dir = stream->header.bEndpointAddress
-                                        & USB_ENDPOINT_DIR_MASK;
-                       unsigned int pipe;
-
-                       pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
-                       usb_clear_halt(stream->dev->udev, pipe);
-               }
-
-               uvc_video_clock_cleanup(stream);
-               return 0;
-       }
-
        ret = uvc_video_clock_init(stream);
        if (ret < 0)
                return ret;
@@ -2044,7 +2087,7 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
        if (ret < 0)
                goto error_commit;
 
-       ret = uvc_init_video(stream, GFP_KERNEL);
+       ret = uvc_video_start_transfer(stream, GFP_KERNEL);
        if (ret < 0)
                goto error_video;
 
@@ -2057,3 +2100,28 @@ error_commit:
 
        return ret;
 }
+
+void uvc_video_stop_streaming(struct uvc_streaming *stream)
+{
+       uvc_video_stop_transfer(stream, 1);
+
+       if (stream->intf->num_altsetting > 1) {
+               usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+       } else {
+               /* UVC doesn't specify how to inform a bulk-based device
+                * when the video stream is stopped. Windows sends a
+                * CLEAR_FEATURE(HALT) request to the video streaming
+                * bulk endpoint, mimic the same behaviour.
+                */
+               unsigned int epnum = stream->header.bEndpointAddress
+                                  & USB_ENDPOINT_NUMBER_MASK;
+               unsigned int dir = stream->header.bEndpointAddress
+                                & USB_ENDPOINT_DIR_MASK;
+               unsigned int pipe;
+
+               pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
+               usb_clear_halt(stream->dev->udev, pipe);
+       }
+
+       uvc_video_clock_cleanup(stream);
+}
index c0cbd833d0a4c460954255ba9afd2ba8b285ba62..9b41b14ce076dd28606af1914eda533f9ba648fc 100644 (file)
 #define UVC_GUID_FORMAT_INVI \
        { 'I',  'N',  'V',  'I', 0xdb, 0x57, 0x49, 0x5e, \
         0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f}
+#define UVC_GUID_FORMAT_CNF4 \
+       { 'C',  ' ',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
 #define UVC_GUID_FORMAT_D3DFMT_L8 \
        {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \
@@ -410,6 +413,9 @@ struct uvc_buffer {
        unsigned int bytesused;
 
        u32 pts;
+
+       /* Asynchronous buffer handling. */
+       struct kref ref;
 };
 
 #define UVC_QUEUE_DISCONNECTED         (1 << 0)
@@ -487,6 +493,44 @@ struct uvc_stats_stream {
 
 #define UVC_METATADA_BUF_SIZE 1024
 
+/**
+ * struct uvc_copy_op: Context structure to schedule asynchronous memcpy
+ *
+ * @buf: active buf object for this operation
+ * @dst: copy destination address
+ * @src: copy source address
+ * @len: copy length
+ */
+struct uvc_copy_op {
+       struct uvc_buffer *buf;
+       void *dst;
+       const __u8 *src;
+       size_t len;
+};
+
+/**
+ * struct uvc_urb - URB context management structure
+ *
+ * @urb: the URB described by this context structure
+ * @stream: UVC streaming context
+ * @buffer: memory storage for the URB
+ * @dma: DMA coherent addressing for the urb_buffer
+ * @async_operations: counter to indicate the number of copy operations
+ * @copy_operations: work descriptors for asynchronous copy operations
+ * @work: work queue entry for asynchronous decode
+ */
+struct uvc_urb {
+       struct urb *urb;
+       struct uvc_streaming *stream;
+
+       char *buffer;
+       dma_addr_t dma;
+
+       unsigned int async_operations;
+       struct uvc_copy_op copy_operations[UVC_MAX_PACKETS];
+       struct work_struct work;
+};
+
 struct uvc_streaming {
        struct list_head list;
        struct uvc_device *dev;
@@ -517,8 +561,9 @@ struct uvc_streaming {
        /* Buffers queue. */
        unsigned int frozen : 1;
        struct uvc_video_queue queue;
-       void (*decode) (struct urb *urb, struct uvc_streaming *video,
-                       struct uvc_buffer *buf, struct uvc_buffer *meta_buf);
+       struct workqueue_struct *async_wq;
+       void (*decode)(struct uvc_urb *uvc_urb, struct uvc_buffer *buf,
+                      struct uvc_buffer *meta_buf);
 
        struct {
                struct video_device vdev;
@@ -535,9 +580,7 @@ struct uvc_streaming {
                u32 max_payload_size;
        } bulk;
 
-       struct urb *urb[UVC_URBS];
-       char *urb_buffer[UVC_URBS];
-       dma_addr_t urb_dma[UVC_URBS];
+       struct uvc_urb uvc_urb[UVC_URBS];
        unsigned int urb_size;
 
        u32 sequence;
@@ -572,6 +615,14 @@ struct uvc_streaming {
        } clock;
 };
 
+#define for_each_uvc_urb(uvc_urb, uvc_streaming) \
+       for ((uvc_urb) = &(uvc_streaming)->uvc_urb[0]; \
+            (uvc_urb) < &(uvc_streaming)->uvc_urb[UVC_URBS]; \
+            ++(uvc_urb))
+
+#define uvc_urb_index(uvc_urb) \
+       (unsigned int)((uvc_urb) - (&(uvc_urb)->stream->uvc_urb[0]))
+
 struct uvc_device_info {
        u32     quirks;
        u32     meta_format;
@@ -711,6 +762,8 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type);
 void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
 struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                                         struct uvc_buffer *buf);
+struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue);
+void uvc_queue_buffer_release(struct uvc_buffer *buf);
 int uvc_queue_mmap(struct uvc_video_queue *queue,
                   struct vm_area_struct *vma);
 __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
@@ -737,7 +790,8 @@ void uvc_mc_cleanup_entity(struct uvc_entity *entity);
 int uvc_video_init(struct uvc_streaming *stream);
 int uvc_video_suspend(struct uvc_streaming *stream);
 int uvc_video_resume(struct uvc_streaming *stream, int reset);
-int uvc_video_enable(struct uvc_streaming *stream, int enable);
+int uvc_video_start_streaming(struct uvc_streaming *stream);
+void uvc_video_stop_streaming(struct uvc_streaming *stream);
 int uvc_probe_video(struct uvc_streaming *stream,
                    struct uvc_streaming_control *probe);
 int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
@@ -757,6 +811,7 @@ int uvc_register_video_device(struct uvc_device *dev,
 
 /* Status */
 int uvc_status_init(struct uvc_device *dev);
+void uvc_status_unregister(struct uvc_device *dev);
 void uvc_status_cleanup(struct uvc_device *dev);
 int uvc_status_start(struct uvc_device *dev, gfp_t flags);
 void uvc_status_stop(struct uvc_device *dev);
@@ -806,7 +861,7 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
                                            u8 epaddr);
 
 /* Quirks support */
-void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
+void uvc_video_decode_isight(struct uvc_urb *uvc_urb,
                             struct uvc_buffer *buf,
                             struct uvc_buffer *meta_buf);
 
index b97090e859968c9962261780681efff870708fd3..c0940f5c69b4397fafc109aa7a18e3878ebc4a22 100644 (file)
@@ -30,6 +30,7 @@ config VIDEO_FIXED_MINOR_RANGES
 config VIDEO_PCI_SKELETON
        tristate "Skeleton PCI V4L2 driver"
        depends on PCI
+       depends on SAMPLES
        depends on VIDEO_V4L2 && VIDEOBUF2_CORE
        depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG
        ---help---
index a6d91370838d934295d812051e8d7c55f35adc2d..15b0c44a76e7f6c3a501c8ab4fbf604e3d9e9a31 100644 (file)
@@ -424,11 +424,7 @@ static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
 
 void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
 {
-       mutex_lock(&list_lock);
-
        INIT_LIST_HEAD(&notifier->asd_list);
-
-       mutex_unlock(&list_lock);
 }
 EXPORT_SYMBOL(v4l2_async_notifier_init);
 
index f4325329fbd6f32f558ef1b798da75a2a208199d..fe4577a46869d2070eb3813c9f24d2f14ef554bc 100644 (file)
@@ -323,6 +323,7 @@ static int __get_v4l2_format32(struct v4l2_format __user *p64,
                return copy_in_user(&p64->fmt.sdr, &p32->fmt.sdr,
                                    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_META_CAPTURE:
+       case V4L2_BUF_TYPE_META_OUTPUT:
                return copy_in_user(&p64->fmt.meta, &p32->fmt.meta,
                                    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
        default:
@@ -392,6 +393,7 @@ static int __put_v4l2_format32(struct v4l2_format __user *p64,
                return copy_in_user(&p32->fmt.sdr, &p64->fmt.sdr,
                                    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_META_CAPTURE:
+       case V4L2_BUF_TYPE_META_OUTPUT:
                return copy_in_user(&p32->fmt.meta, &p64->fmt.meta,
                                    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
        default:
index 10b8d94edbef1536c114a7c8b8a2d9110b8a8f31..5e3806feb5d72e9d141ebdfb403ca2ed31b57c75 100644 (file)
@@ -1636,7 +1636,8 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
                switch (p_mpeg2_slice_params->picture.intra_dc_precision) {
                case 0: /* 8 bits */
                case 1: /* 9 bits */
-               case 11: /* 11 bits */
+               case 2: /* 10 bits */
+               case 3: /* 11 bits */
                        break;
                default:
                        return -EINVAL;
index feb749aaaa42f4c801febc1c1db158dce66f09d4..d7528f82a66aa6be5896d48d18a4142fb2ac7e1b 100644 (file)
@@ -597,7 +597,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
                               ops->vidioc_enum_fmt_vid_overlay ||
                               ops->vidioc_enum_fmt_meta_cap)) ||
                    (is_tx && (ops->vidioc_enum_fmt_vid_out ||
-                              ops->vidioc_enum_fmt_vid_out_mplane)))
+                              ops->vidioc_enum_fmt_vid_out_mplane ||
+                              ops->vidioc_enum_fmt_meta_out)))
                        set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
                if ((is_rx && (ops->vidioc_g_fmt_vid_cap ||
                               ops->vidioc_g_fmt_vid_cap_mplane ||
@@ -605,7 +606,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
                               ops->vidioc_g_fmt_meta_cap)) ||
                    (is_tx && (ops->vidioc_g_fmt_vid_out ||
                               ops->vidioc_g_fmt_vid_out_mplane ||
-                              ops->vidioc_g_fmt_vid_out_overlay)))
+                              ops->vidioc_g_fmt_vid_out_overlay ||
+                              ops->vidioc_g_fmt_meta_out)))
                         set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
                if ((is_rx && (ops->vidioc_s_fmt_vid_cap ||
                               ops->vidioc_s_fmt_vid_cap_mplane ||
@@ -613,7 +615,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
                               ops->vidioc_s_fmt_meta_cap)) ||
                    (is_tx && (ops->vidioc_s_fmt_vid_out ||
                               ops->vidioc_s_fmt_vid_out_mplane ||
-                              ops->vidioc_s_fmt_vid_out_overlay)))
+                              ops->vidioc_s_fmt_vid_out_overlay ||
+                              ops->vidioc_s_fmt_meta_out)))
                         set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
                if ((is_rx && (ops->vidioc_try_fmt_vid_cap ||
                               ops->vidioc_try_fmt_vid_cap_mplane ||
@@ -621,7 +624,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
                               ops->vidioc_try_fmt_meta_cap)) ||
                    (is_tx && (ops->vidioc_try_fmt_vid_out ||
                               ops->vidioc_try_fmt_vid_out_mplane ||
-                              ops->vidioc_try_fmt_vid_out_overlay)))
+                              ops->vidioc_try_fmt_vid_out_overlay ||
+                              ops->vidioc_try_fmt_meta_out)))
                         set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
                SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
                SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
@@ -635,14 +639,14 @@ static void determine_valid_ioctls(struct video_device *vdev)
                SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
                SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
                SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
-               if (ops->vidioc_g_crop || ops->vidioc_g_selection)
+               if (ops->vidioc_g_selection) {
                        set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
-               if (ops->vidioc_s_crop || ops->vidioc_s_selection)
+                       set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
+               }
+               if (ops->vidioc_s_selection)
                        set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
                SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
                SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
-               if (ops->vidioc_cropcap || ops->vidioc_g_selection)
-                       set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
        } else if (is_vbi) {
                /* vbi specific ioctls */
                if ((is_rx && (ops->vidioc_g_fmt_vbi_cap ||
index df0ac38c40500fa68999bb93b946878b708da36c..e0ddb9a52bd1f92eba7dbd7c53d64825403a4d42 100644 (file)
@@ -247,6 +247,7 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 
                video_set_drvdata(vdev, sd);
                strscpy(vdev->name, sd->name, sizeof(vdev->name));
+               vdev->dev_parent = sd->dev;
                vdev->v4l2_dev = v4l2_dev;
                vdev->fops = &v4l2_subdev_fops;
                vdev->release = v4l2_device_release_subdev_node;
index 218f0da0ce7690673f797cd5dce0aea2ce0b8f53..9bfedd7596a1a3616368f63902624fb27c603285 100644 (file)
@@ -310,8 +310,8 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
        }
 
        if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
-               flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
-                          V4L2_MBUS_PCLK_SAMPLE_FALLING);
+               flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
+                          V4L2_MBUS_DATA_ACTIVE_LOW);
                flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
                        V4L2_MBUS_DATA_ACTIVE_LOW;
                pr_debug("data-active %s\n", v ? "high" : "low");
@@ -564,8 +564,7 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
        fwnode = fwnode_get_parent(__fwnode);
        fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
        fwnode = fwnode_get_next_parent(fwnode);
-       if (is_of_node(fwnode) &&
-           of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
+       if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
                fwnode = fwnode_get_next_parent(fwnode);
        link->local_node = fwnode;
 
@@ -578,8 +577,7 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
        fwnode = fwnode_get_parent(fwnode);
        fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
        fwnode = fwnode_get_next_parent(fwnode);
-       if (is_of_node(fwnode) &&
-           of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
+       if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
                fwnode = fwnode_get_next_parent(fwnode);
        link->remote_node = fwnode;
 
@@ -613,7 +611,7 @@ v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
        asd->match.fwnode =
                fwnode_graph_get_remote_port_parent(endpoint);
        if (!asd->match.fwnode) {
-               dev_warn(dev, "bad remote port parent\n");
+               dev_dbg(dev, "no remote endpoint found\n");
                ret = -ENOTCONN;
                goto out_err;
        }
index c63746968fa3d714fcd6eaecd2f34d021503f08b..1441a73ce64cf609637c202566756fb98de54c79 100644 (file)
@@ -194,6 +194,7 @@ const char *v4l2_type_names[] = {
        [V4L2_BUF_TYPE_SDR_CAPTURE]        = "sdr-cap",
        [V4L2_BUF_TYPE_SDR_OUTPUT]         = "sdr-out",
        [V4L2_BUF_TYPE_META_CAPTURE]       = "meta-cap",
+       [V4L2_BUF_TYPE_META_OUTPUT]        = "meta-out",
 };
 EXPORT_SYMBOL(v4l2_type_names);
 
@@ -366,6 +367,7 @@ static void v4l_print_format(const void *arg, bool write_only)
                        (sdr->pixelformat >> 24) & 0xff);
                break;
        case V4L2_BUF_TYPE_META_CAPTURE:
+       case V4L2_BUF_TYPE_META_OUTPUT:
                meta = &p->fmt.meta;
                pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n",
                        (meta->dataformat >>  0) & 0xff,
@@ -999,6 +1001,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
                if (is_vid && is_rx && ops->vidioc_g_fmt_meta_cap)
                        return 0;
                break;
+       case V4L2_BUF_TYPE_META_OUTPUT:
+               if (is_vid && is_tx && ops->vidioc_g_fmt_meta_out)
+                       return 0;
+               break;
        default:
                break;
        }
@@ -1189,6 +1195,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
        case V4L2_PIX_FMT_Y12I:         descr = "Interleaved 12-bit Greyscale"; break;
        case V4L2_PIX_FMT_Z16:          descr = "16-bit Depth"; break;
        case V4L2_PIX_FMT_INZI:         descr = "Planar 10:16 Greyscale Depth"; break;
+       case V4L2_PIX_FMT_CNF4:         descr = "4-bit Depth Confidence (Packed)"; break;
        case V4L2_PIX_FMT_PAL8:         descr = "8-bit Palette"; break;
        case V4L2_PIX_FMT_UV8:          descr = "8-bit Chrominance UV 4-4"; break;
        case V4L2_PIX_FMT_YVU410:       descr = "Planar YVU 4:1:0"; break;
@@ -1339,9 +1346,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
                case V4L2_PIX_FMT_MT21C:        descr = "Mediatek Compressed Format"; break;
                case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break;
                default:
-                       WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
                        if (fmt->description[0])
                                return;
+                       WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
                        flags = 0;
                        snprintf(fmt->description, sz, "%c%c%c%c%s",
                                        (char)(fmt->pixelformat & 0x7f),
@@ -1409,6 +1416,11 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
                        break;
                ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg);
                break;
+       case V4L2_BUF_TYPE_META_OUTPUT:
+               if (unlikely(!ops->vidioc_enum_fmt_meta_out))
+                       break;
+               ret = ops->vidioc_enum_fmt_meta_out(file, fh, arg);
+               break;
        }
        if (ret == 0)
                v4l_fill_fmtdesc(p);
@@ -1487,6 +1499,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
                return ops->vidioc_g_fmt_sdr_out(file, fh, arg);
        case V4L2_BUF_TYPE_META_CAPTURE:
                return ops->vidioc_g_fmt_meta_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_META_OUTPUT:
+               return ops->vidioc_g_fmt_meta_out(file, fh, arg);
        }
        return -EINVAL;
 }
@@ -1512,6 +1526,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
        struct v4l2_format *p = arg;
        struct video_device *vfd = video_devdata(file);
        int ret = check_fmt(file, p->type);
+       unsigned int i;
 
        if (ret)
                return ret;
@@ -1536,6 +1551,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
                if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane))
                        break;
                CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
+                       CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline);
                return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
@@ -1564,6 +1581,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
                if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane))
                        break;
                CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
+                       CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline);
                return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
@@ -1595,6 +1614,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
                        break;
                CLEAR_AFTER_FIELD(p, fmt.meta);
                return ops->vidioc_s_fmt_meta_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_META_OUTPUT:
+               if (unlikely(!ops->vidioc_s_fmt_meta_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.meta);
+               return ops->vidioc_s_fmt_meta_out(file, fh, arg);
        }
        return -EINVAL;
 }
@@ -1604,6 +1628,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
 {
        struct v4l2_format *p = arg;
        int ret = check_fmt(file, p->type);
+       unsigned int i;
 
        if (ret)
                return ret;
@@ -1623,6 +1648,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
                if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane))
                        break;
                CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
+                       CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline);
                return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
@@ -1651,6 +1678,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
                if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane))
                        break;
                CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+               for (i = 0; i < p->fmt.pix_mp.num_planes; i++)
+                       CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline);
                return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg);
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
@@ -1682,6 +1711,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
                        break;
                CLEAR_AFTER_FIELD(p, fmt.meta);
                return ops->vidioc_try_fmt_meta_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_META_OUTPUT:
+               if (unlikely(!ops->vidioc_try_fmt_meta_out))
+                       break;
+               CLEAR_AFTER_FIELD(p, fmt.meta);
+               return ops->vidioc_try_fmt_meta_out(file, fh, arg);
        }
        return -EINVAL;
 }
@@ -2202,21 +2236,24 @@ static int v4l_s_selection(const struct v4l2_ioctl_ops *ops,
 static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
+       struct video_device *vfd = video_devdata(file);
        struct v4l2_crop *p = arg;
        struct v4l2_selection s = {
                .type = p->type,
        };
        int ret;
 
-       if (ops->vidioc_g_crop)
-               return ops->vidioc_g_crop(file, fh, p);
        /* simulate capture crop using selection api */
 
        /* crop means compose for output devices */
        if (V4L2_TYPE_IS_OUTPUT(p->type))
-               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+               s.target = V4L2_SEL_TGT_COMPOSE;
        else
-               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+               s.target = V4L2_SEL_TGT_CROP;
+
+       if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags))
+               s.target = s.target == V4L2_SEL_TGT_COMPOSE ?
+                       V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE;
 
        ret = v4l_g_selection(ops, file, fh, &s);
 
@@ -2229,21 +2266,24 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
 static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
+       struct video_device *vfd = video_devdata(file);
        struct v4l2_crop *p = arg;
        struct v4l2_selection s = {
                .type = p->type,
                .r = p->c,
        };
 
-       if (ops->vidioc_s_crop)
-               return ops->vidioc_s_crop(file, fh, p);
        /* simulate capture crop using selection api */
 
        /* crop means compose for output devices */
        if (V4L2_TYPE_IS_OUTPUT(p->type))
-               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+               s.target = V4L2_SEL_TGT_COMPOSE;
        else
-               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+               s.target = V4L2_SEL_TGT_CROP;
+
+       if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags))
+               s.target = s.target == V4L2_SEL_TGT_COMPOSE ?
+                       V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE;
 
        return v4l_s_selection(ops, file, fh, &s);
 }
@@ -2251,6 +2291,7 @@ static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
 static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
+       struct video_device *vfd = video_devdata(file);
        struct v4l2_cropcap *p = arg;
        struct v4l2_selection s = { .type = p->type };
        int ret = 0;
@@ -2259,18 +2300,21 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
        p->pixelaspect.numerator = 1;
        p->pixelaspect.denominator = 1;
 
+       if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               s.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       else if (s.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               s.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
        /*
         * The determine_valid_ioctls() call already should ensure
         * that this can never happen, but just in case...
         */
-       if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_g_selection))
+       if (WARN_ON(!ops->vidioc_g_selection))
                return -ENOTTY;
 
-       if (ops->vidioc_cropcap)
-               ret = ops->vidioc_cropcap(file, fh, p);
-
-       if (!ops->vidioc_g_selection)
-               return ret;
+       if (ops->vidioc_g_pixelaspect)
+               ret = ops->vidioc_g_pixelaspect(file, fh, s.type,
+                                               &p->pixelaspect);
 
        /*
         * Ignore ENOTTY or ENOIOCTLCMD error returns, just use the
@@ -2287,13 +2331,17 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
        else
                s.target = V4L2_SEL_TGT_CROP_BOUNDS;
 
+       if (test_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags))
+               s.target = s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS ?
+                       V4L2_SEL_TGT_CROP_BOUNDS : V4L2_SEL_TGT_COMPOSE_BOUNDS;
+
        ret = v4l_g_selection(ops, file, fh, &s);
        if (ret)
                return ret;
        p->bounds = s.r;
 
        /* obtaining defrect */
-       if (V4L2_TYPE_IS_OUTPUT(p->type))
+       if (s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS)
                s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
        else
                s.target = V4L2_SEL_TGT_CROP_DEFAULT;
@@ -2586,7 +2634,7 @@ DEFINE_V4L_STUB_FUNC(enum_dv_timings)
 DEFINE_V4L_STUB_FUNC(query_dv_timings)
 DEFINE_V4L_STUB_FUNC(dv_timings_cap)
 
-static struct v4l2_ioctl_info v4l2_ioctls[] = {
+static const struct v4l2_ioctl_info v4l2_ioctls[] = {
        IOCTL_INFO(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0),
        IOCTL_INFO(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)),
        IOCTL_INFO(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, 0),
@@ -2679,45 +2727,6 @@ static bool v4l2_is_known_ioctl(unsigned int cmd)
        return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
 }
 
-#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
-static bool v4l2_ioctl_m2m_queue_is_output(unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case VIDIOC_CREATE_BUFS: {
-               struct v4l2_create_buffers *cbufs = arg;
-
-               return V4L2_TYPE_IS_OUTPUT(cbufs->format.type);
-       }
-       case VIDIOC_REQBUFS: {
-               struct v4l2_requestbuffers *rbufs = arg;
-
-               return V4L2_TYPE_IS_OUTPUT(rbufs->type);
-       }
-       case VIDIOC_QBUF:
-       case VIDIOC_DQBUF:
-       case VIDIOC_QUERYBUF:
-       case VIDIOC_PREPARE_BUF: {
-               struct v4l2_buffer *buf = arg;
-
-               return V4L2_TYPE_IS_OUTPUT(buf->type);
-       }
-       case VIDIOC_EXPBUF: {
-               struct v4l2_exportbuffer *expbuf = arg;
-
-               return V4L2_TYPE_IS_OUTPUT(expbuf->type);
-       }
-       case VIDIOC_STREAMON:
-       case VIDIOC_STREAMOFF: {
-               int *type = arg;
-
-               return V4L2_TYPE_IS_OUTPUT(*type);
-       }
-       default:
-               return false;
-       }
-}
-#endif
-
 static struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev,
                                         struct v4l2_fh *vfh, unsigned int cmd,
                                         void *arg)
@@ -2727,12 +2736,8 @@ static struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev,
 #if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
        if (vfh && vfh->m2m_ctx &&
            (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) {
-               bool is_output = v4l2_ioctl_m2m_queue_is_output(cmd, arg);
-               struct v4l2_m2m_queue_ctx *ctx = is_output ?
-                       &vfh->m2m_ctx->out_q_ctx : &vfh->m2m_ctx->cap_q_ctx;
-
-               if (ctx->q.lock)
-                       return ctx->q.lock;
+               if (vfh->m2m_ctx->q_lock)
+                       return vfh->m2m_ctx->q_lock;
        }
 #endif
        if (vdev->queue && vdev->queue->lock &&
index 1ed2465972acab4d0fae6aa4a8d28c966167d224..5bbdec55b7d72dac34da538755af67ce5680c9c0 100644 (file)
@@ -87,6 +87,7 @@ static const char * const m2m_entity_name[] = {
  * @curr_ctx:          currently running instance
  * @job_queue:         instances queued to run
  * @job_spinlock:      protects job_queue
+ * @job_work:          worker to run queued jobs.
  * @m2m_ops:           driver callbacks
  */
 struct v4l2_m2m_dev {
@@ -103,6 +104,7 @@ struct v4l2_m2m_dev {
 
        struct list_head        job_queue;
        spinlock_t              job_spinlock;
+       struct work_struct      job_work;
 
        const struct v4l2_m2m_ops *m2m_ops;
 };
@@ -244,6 +246,9 @@ EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
  * @m2m_dev: per-device context
  *
  * Get next transaction (if present) from the waiting jobs list and run it.
+ *
+ * Note that this function can run on a given v4l2_m2m_ctx context,
+ * but call .device_run for another context.
  */
 static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
 {
@@ -297,51 +302,48 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev,
 
        /* If the context is aborted then don't schedule it */
        if (m2m_ctx->job_flags & TRANS_ABORT) {
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("Aborted context\n");
-               return;
+               goto job_unlock;
        }
 
        if (m2m_ctx->job_flags & TRANS_QUEUED) {
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("On job queue already\n");
-               return;
+               goto job_unlock;
        }
 
        spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
        if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)
            && !m2m_ctx->out_q_ctx.buffered) {
-               spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
-                                       flags_out);
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("No input buffers available\n");
-               return;
+               goto out_unlock;
        }
        spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
        if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)
            && !m2m_ctx->cap_q_ctx.buffered) {
-               spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock,
-                                       flags_cap);
-               spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
-                                       flags_out);
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("No output buffers available\n");
-               return;
+               goto cap_unlock;
        }
        spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
        spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
 
        if (m2m_dev->m2m_ops->job_ready
                && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("Driver not ready\n");
-               return;
+               goto job_unlock;
        }
 
        list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue);
        m2m_ctx->job_flags |= TRANS_QUEUED;
 
        spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+       return;
+
+cap_unlock:
+       spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
+out_unlock:
+       spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
+job_unlock:
+       spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
 }
 
 /**
@@ -365,6 +367,18 @@ void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_try_schedule);
 
+/**
+ * v4l2_m2m_device_run_work() - run pending jobs for the context
+ * @work: Work structure used for scheduling the execution of this function.
+ */
+static void v4l2_m2m_device_run_work(struct work_struct *work)
+{
+       struct v4l2_m2m_dev *m2m_dev =
+               container_of(work, struct v4l2_m2m_dev, job_work);
+
+       v4l2_m2m_try_run(m2m_dev);
+}
+
 /**
  * v4l2_m2m_cancel_job() - cancel pending jobs for the context
  * @m2m_ctx: m2m context with jobs to be canceled
@@ -424,7 +438,12 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
        /* This instance might have more buffers ready, but since we do not
         * allow more than one job on the job_queue per instance, each has
         * to be scheduled separately after the previous one finishes. */
-       v4l2_m2m_try_schedule(m2m_ctx);
+       __v4l2_m2m_try_queue(m2m_dev, m2m_ctx);
+
+       /* We might be running in atomic context,
+        * but the job must be run in non-atomic context.
+        */
+       schedule_work(&m2m_dev->job_work);
 }
 EXPORT_SYMBOL(v4l2_m2m_job_finish);
 
@@ -866,6 +885,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
        m2m_dev->m2m_ops = m2m_ops;
        INIT_LIST_HEAD(&m2m_dev->job_queue);
        spin_lock_init(&m2m_dev->job_spinlock);
+       INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
 
        return m2m_dev;
 }
@@ -908,12 +928,14 @@ struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
        if (ret)
                goto err;
        /*
-        * If both queues use same mutex assign it as the common buffer
-        * queues lock to the m2m context. This lock is used in the
-        * v4l2_m2m_ioctl_* helpers.
+        * Both queues should use same the mutex to lock the m2m context.
+        * This lock is used in some v4l2_m2m_* helpers.
         */
-       if (out_q_ctx->q.lock == cap_q_ctx->q.lock)
-               m2m_ctx->q_lock = out_q_ctx->q.lock;
+       if (WARN_ON(out_q_ctx->q.lock != cap_q_ctx->q.lock)) {
+               ret = -EINVAL;
+               goto err;
+       }
+       m2m_ctx->q_lock = out_q_ctx->q.lock;
 
        return m2m_ctx;
 err:
index 0be511dd93d012b82ff33afae6c779982041895b..e1450a56fc070c42c718843b406270d589a20715 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/err.h>
+#include <linux/acpi.h>
+#include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/mfd/core.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
-#include <linux/mfd/axp20x.h>
-#include <linux/mfd/core.h>
-#include <linux/of_device.h>
-#include <linux/acpi.h>
 
-#define AXP20X_OFF     0x80
+#define AXP20X_OFF     BIT(7)
 
 #define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE   0
 #define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE    BIT(4)
index 22bd6525e09cfb558cd26575c816c9f2a38cfbad..04a177efd24514547b30f77f0a2f0877358f3082 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/mfd/core.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
@@ -306,14 +305,6 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
 
        pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd");
 
-       pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0);
-       if (pdata->ldo[0].enable < 0)
-               pdata->ldo[0].enable = 0;
-
-       pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0);
-       if (pdata->ldo[1].enable < 0)
-               pdata->ldo[1].enable = 0;
-
        return 0;
 }
 #else
index bc1bd2c256132c2f3def2844a7d5ccccb05ef523..55997cf84b39f5dd9c3ced5ea9db6702cb02c65a 100644 (file)
@@ -30,6 +30,7 @@
 #include "pwrseq.h"
 
 #define DEFAULT_CMD6_TIMEOUT_MS        500
+#define MIN_CACHE_EN_TIMEOUT_MS 1600
 
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
@@ -526,8 +527,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        card->cid.year += 16;
 
                /* check whether the eMMC card supports BKOPS */
-               if (!mmc_card_broken_hpi(card) &&
-                   ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+               if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
                        card->ext_csd.bkops = 1;
                        card->ext_csd.man_bkops_en =
                                        (ext_csd[EXT_CSD_BKOPS_EN] &
@@ -1782,20 +1782,26 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                if (err) {
                        pr_warn("%s: Enabling HPI failed\n",
                                mmc_hostname(card->host));
+                       card->ext_csd.hpi_en = 0;
                        err = 0;
-               } else
+               } else {
                        card->ext_csd.hpi_en = 1;
+               }
        }
 
        /*
-        * If cache size is higher than 0, this indicates
-        * the existence of cache and it can be turned on.
+        * If cache size is higher than 0, this indicates the existence of cache
+        * and it can be turned on. Note that some eMMCs from Micron has been
+        * reported to need ~800 ms timeout, while enabling the cache after
+        * sudden power failure tests. Let's extend the timeout to a minimum of
+        * DEFAULT_CACHE_EN_TIMEOUT_MS and do it for all cards.
         */
-       if (!mmc_card_broken_hpi(card) &&
-           card->ext_csd.cache_size > 0) {
+       if (card->ext_csd.cache_size > 0) {
+               unsigned int timeout_ms = MIN_CACHE_EN_TIMEOUT_MS;
+
+               timeout_ms = max(card->ext_csd.generic_cmd6_time, timeout_ms);
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_CACHE_CTRL, 1,
-                               card->ext_csd.generic_cmd6_time);
+                               EXT_CSD_CACHE_CTRL, 1, timeout_ms);
                if (err && err != -EBADMSG)
                        goto free_card;
 
index 467d889a16386c26e273a0157ce25787ea6116ce..3f4ea8f624be5f1e62a109b8e18ade78be7d3954 100644 (file)
@@ -1909,7 +1909,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
        mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-       mmc->max_seg_size = mmc->max_req_size;
 
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
                     MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE | MMC_CAP_CMD23;
@@ -1939,6 +1938,17 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       /*
+        * Limit the maximum segment size to the lower of the request size
+        * and the DMA engine device segment size limits.  In reality, with
+        * 32-bit transfers, the DMA engine can do longer segments than this
+        * but there is no way to represent that in the DMA model - if we
+        * increase this figure here, we get warnings from the DMA API debug.
+        */
+       mmc->max_seg_size = min3(mmc->max_req_size,
+                       dma_get_max_seg_size(host->rx_chan->device->dev),
+                       dma_get_max_seg_size(host->tx_chan->device->dev));
+
        /* Request IRQ for MMC operations */
        ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
                        mmc_hostname(mmc), host);
index 7b95d088fdefd5ff4067c12960b00f3185429440..e6ace31e2a418cc80e0df72eb66f89d1119c26ca 100644 (file)
@@ -510,25 +510,25 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
 
        err = device_property_read_u32(host->mmc->parent,
                        "nvidia,pad-autocal-pull-up-offset-3v3-timeout",
-                       &autocal->pull_up_3v3);
+                       &autocal->pull_up_3v3_timeout);
        if (err)
                autocal->pull_up_3v3_timeout = 0;
 
        err = device_property_read_u32(host->mmc->parent,
                        "nvidia,pad-autocal-pull-down-offset-3v3-timeout",
-                       &autocal->pull_down_3v3);
+                       &autocal->pull_down_3v3_timeout);
        if (err)
                autocal->pull_down_3v3_timeout = 0;
 
        err = device_property_read_u32(host->mmc->parent,
                        "nvidia,pad-autocal-pull-up-offset-1v8-timeout",
-                       &autocal->pull_up_1v8);
+                       &autocal->pull_up_1v8_timeout);
        if (err)
                autocal->pull_up_1v8_timeout = 0;
 
        err = device_property_read_u32(host->mmc->parent,
                        "nvidia,pad-autocal-pull-down-offset-1v8-timeout",
-                       &autocal->pull_down_1v8);
+                       &autocal->pull_down_1v8_timeout);
        if (err)
                autocal->pull_down_1v8_timeout = 0;
 
index 451b08a818a9d60e97e1ac8bb1f807ad89f25e30..df05352b6a4aa5bef6c54092078f7bd75acc455a 100644 (file)
@@ -127,12 +127,12 @@ static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
 {
        u16 ctrl2;
 
-       ctrl2 = sdhci_readb(host, SDHCI_HOST_CONTROL2);
+       ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
        if (ctrl2 & SDHCI_CTRL_V4_MODE)
                return;
 
        ctrl2 |= SDHCI_CTRL_V4_MODE;
-       sdhci_writeb(host, ctrl2, SDHCI_HOST_CONTROL);
+       sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
 }
 
 /*
index c77f537323ecb371d1be527df650bf6fb8ca4713..1e18c9639c3e6d4c32a5c54dd52fc532baaad229 100644 (file)
@@ -22,56 +22,6 @@ config MTD_TESTS
          WARNING: some of the tests will ERASE entire MTD device which they
          test. Do not use these tests unless you really know what you do.
 
-config MTD_REDBOOT_PARTS
-       tristate "RedBoot partition table parsing"
-       help
-         RedBoot is a ROM monitor and bootloader which deals with multiple
-         'images' in flash devices by putting a table one of the erase
-         blocks on the device, similar to a partition table, which gives
-         the offsets, lengths and names of all the images stored in the
-         flash.
-
-         If you need code which can detect and parse this table, and register
-         MTD 'partitions' corresponding to each image in the table, enable
-         this option.
-
-         You will still need the parsing functions to be called by the driver
-         for your particular device. It won't happen automatically. The
-         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
-         example.
-
-if MTD_REDBOOT_PARTS
-
-config MTD_REDBOOT_DIRECTORY_BLOCK
-       int "Location of RedBoot partition table"
-       default "-1"
-       help
-         This option is the Linux counterpart to the
-         CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
-         option.
-
-         The option specifies which Flash sectors holds the RedBoot
-         partition table.  A zero or positive value gives an absolute
-         erase block number. A negative value specifies a number of
-         sectors before the end of the device.
-
-         For example "2" means block number 2, "-1" means the last
-         block and "-2" means the penultimate block.
-
-config MTD_REDBOOT_PARTS_UNALLOCATED
-       bool "Include unallocated flash regions"
-       help
-         If you need to register each unallocated flash region as a MTD
-         'partition', enable this option.
-
-config MTD_REDBOOT_PARTS_READONLY
-       bool "Force read-only for RedBoot system images"
-       help
-         If you need to force read-only for 'RedBoot', 'RedBoot Config' and
-         'FIS directory' images, enable this option.
-
-endif # MTD_REDBOOT_PARTS
-
 config MTD_CMDLINE_PARTS
        tristate "Command line partition table parsing"
        depends on MTD
@@ -144,7 +94,7 @@ config MTD_BCM63XX_PARTS
        depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
        select CRC32
        help
-         This provides partions parsing for BCM63xx devices with CFE
+         This provides partition parsing for BCM63xx devices with CFE
          bootloaders.
 
 config MTD_BCM47XX_PARTS
index 93473d215a38776b0237556fc321f1d436ef5841..58fc327a5276889b9e6875175cd8958a4930dfa7 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_MTD)               += mtd.o
 mtd-y                          := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
 
 obj-$(CONFIG_MTD_OF_PARTS)     += ofpart.o
-obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)    += afs.o
 obj-$(CONFIG_MTD_AR7_PARTS)    += ar7part.o
index 35aa72b720a6246871325250242b99485ed70d7b..e752067526a5c00e1019887ad78af27d0e964e82 100644 (file)
@@ -324,6 +324,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        case FL_JEDEC_QUERY:
                map_write(map, CMD(0x70), cmd_addr);
                chip->state = FL_STATUS;
+               /* Fall through */
 
        case FL_STATUS:
                status = map_read(map, cmd_addr);
@@ -461,6 +462,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip,
 #ifdef DEBUG_CFI_FEATURES
        printk("%s: 1 status[%x]\n", __func__, map_read(map, cmd_adr));
 #endif
+               /* Fall through */
 
        case FL_STATUS:
                status = map_read(map, cmd_adr);
@@ -754,6 +756,7 @@ retry:
        case FL_READY:
                map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
+               /* Fall through */
 
        case FL_STATUS:
                status = map_read(map, adr);
@@ -995,6 +998,7 @@ static void cfi_staa_sync (struct mtd_info *mtd)
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
+                       /* Fall through */
                case FL_SYNCING:
                        mutex_unlock(&chip->mutex);
                        break;
@@ -1050,6 +1054,7 @@ retry:
        case FL_READY:
                map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
+               /* Fall through */
 
        case FL_STATUS:
                status = map_read(map, adr);
@@ -1196,6 +1201,7 @@ retry:
        case FL_READY:
                map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
+               /* Fall through */
 
        case FL_STATUS:
                status = map_read(map, adr);
index c9e424993e37e1c9708e709a476461878553fe06..410a321682e6589405c2fd5f11956e15b44b22e9 100644 (file)
@@ -329,8 +329,10 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
        switch (**endp) {
        case 'G' :
                result *= 1024;
+               /* fall through */
        case 'M':
                result *= 1024;
+               /* fall through */
        case 'K':
        case 'k':
                result *= 1024;
index 512bd4c2eec0b3a31f8dcd5d1a201c780a6fafcf..4c94fc0966964b8c15aefc086cd5ecb8174f7d27 100644 (file)
@@ -1603,7 +1603,7 @@ static void doc_unregister_sysfs(struct platform_device *pdev,
 /*
  * Debug sysfs entries
  */
-static int dbg_flashctrl_show(struct seq_file *s, void *p)
+static int flashcontrol_show(struct seq_file *s, void *p)
 {
        struct docg3 *docg3 = (struct docg3 *)s->private;
 
@@ -1623,9 +1623,9 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
 
        return 0;
 }
-DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show);
+DEFINE_SHOW_ATTRIBUTE(flashcontrol);
 
-static int dbg_asicmode_show(struct seq_file *s, void *p)
+static int asic_mode_show(struct seq_file *s, void *p)
 {
        struct docg3 *docg3 = (struct docg3 *)s->private;
 
@@ -1660,9 +1660,9 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
        seq_puts(s, ")\n");
        return 0;
 }
-DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show);
+DEFINE_SHOW_ATTRIBUTE(asic_mode);
 
-static int dbg_device_id_show(struct seq_file *s, void *p)
+static int device_id_show(struct seq_file *s, void *p)
 {
        struct docg3 *docg3 = (struct docg3 *)s->private;
        int id;
@@ -1674,9 +1674,9 @@ static int dbg_device_id_show(struct seq_file *s, void *p)
        seq_printf(s, "DeviceId = %d\n", id);
        return 0;
 }
-DEBUGFS_RO_ATTR(device_id, dbg_device_id_show);
+DEFINE_SHOW_ATTRIBUTE(device_id);
 
-static int dbg_protection_show(struct seq_file *s, void *p)
+static int protection_show(struct seq_file *s, void *p)
 {
        struct docg3 *docg3 = (struct docg3 *)s->private;
        int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
@@ -1726,7 +1726,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
                   !!(dps1 & DOC_DPS_KEY_OK));
        return 0;
 }
-DEBUGFS_RO_ATTR(protection, dbg_protection_show);
+DEFINE_SHOW_ATTRIBUTE(protection);
 
 static void __init doc_dbg_register(struct mtd_info *floor)
 {
index e99946575398e4798e29af5b4c5cbb3f9498bdf2..e16dca23655b39bdd089782b30c76a93df9c263d 100644 (file)
@@ -317,17 +317,6 @@ struct docg3 {
 #define doc_info(fmt, arg...) dev_info(docg3->dev, (fmt), ## arg)
 #define doc_dbg(fmt, arg...) dev_dbg(docg3->dev, (fmt), ## arg)
 #define doc_vdbg(fmt, arg...) dev_vdbg(docg3->dev, (fmt), ## arg)
-
-#define DEBUGFS_RO_ATTR(name, show_fct) \
-       static int name##_open(struct inode *inode, struct file *file) \
-       { return single_open(file, show_fct, inode->i_private); }      \
-       static const struct file_operations name##_fops = { \
-               .owner = THIS_MODULE, \
-               .open = name##_open, \
-               .llseek = seq_lseek, \
-               .read = seq_read, \
-               .release = single_release \
-       };
 #endif
 
 /*
index afb36bff13a78989b5a8385a0f0da7124558ba90..e0cf869c854439d5b178f2f2361d638ad97c4cb4 100644 (file)
@@ -66,15 +66,15 @@ config MTD_PHYSMAP_BANKWIDTH
          used internally by the CFI drivers.
 
 config MTD_PHYSMAP_OF
-       tristate "Memory device in physical memory map based on OF description"
-       depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM)
+       bool "Memory device in physical memory map based on OF description"
+       depends on OF && MTD_PHYSMAP
        help
          This provides a 'mapping' driver which allows the NOR Flash, ROM
          and RAM driver code to communicate with chips which are mapped
          physically into the CPU's memory. The mapping description here is
          taken from OF device tree.
 
-config MTD_PHYSMAP_OF_VERSATILE
+config MTD_PHYSMAP_VERSATILE
        bool "ARM Versatile OF-based physical memory map handling"
        depends on MTD_PHYSMAP_OF
        depends on MFD_SYSCON
@@ -84,16 +84,26 @@ config MTD_PHYSMAP_OF_VERSATILE
          platforms, basically to add a VPP (write protection) callback so
          the flash can be taken out of write protection.
 
-config MTD_PHYSMAP_OF_GEMINI
+config MTD_PHYSMAP_GEMINI
        bool "Cortina Gemini OF-based physical memory map handling"
        depends on MTD_PHYSMAP_OF
        depends on MFD_SYSCON
+       select MTD_COMPLEX_MAPPINGS
        default ARCH_GEMINI
        help
          This provides some extra DT physmap parsing for the Gemini
          platforms, some detection and setting up parallel mode on the
          external interface.
 
+config MTD_PHYSMAP_GPIO_ADDR
+       bool "GPIO-assisted Flash Chip Support"
+       depends on MTD_PHYSMAP
+       depends on GPIOLIB || COMPILE_TEST
+       depends on MTD_COMPLEX_MAPPINGS
+       help
+         Extend the physmap driver to allow flashes to be partially
+         physically addressed and assisted by GPIOs.
+
 config MTD_PMC_MSP_EVM
        tristate "CFI Flash device mapped on PMC-Sierra MSP"
        depends on PMC_MSP && MTD_CFI
@@ -334,16 +344,6 @@ config MTD_PCMCIA_ANONYMOUS
 
          If unsure, say N.
 
-config MTD_GPIO_ADDR
-       tristate "GPIO-assisted Flash Chip Support"
-       depends on GPIOLIB || COMPILE_TEST
-       depends on MTD_COMPLEX_MAPPINGS
-       help
-         Map driver which allows flashes to be partially physically addressed
-         and assisted by GPIOs.
-
-         If compiled as a module, it will be called gpio-addr-flash.
-
 config MTD_UCLINUX
        bool "Generic uClinux RAM/ROM filesystem support"
        depends on (MTD_RAM=y || MTD_ROM=y) && (!MMU || COLDFIRE)
@@ -400,13 +400,4 @@ config MTD_PISMO
 
          When built as a module, it will be called pismo.ko
 
-config MTD_LATCH_ADDR
-       tristate "Latch-assisted Flash Chip Support"
-       depends on MTD_COMPLEX_MAPPINGS
-       help
-         Map driver which allows flashes to be partially physically addressed
-         and have the upper address lines set by a board specific code.
-
-         If compiled as a module, it will be called latch-addr-flash.
-
 endmenu
index 51acf1fec19b54bce18f66893e901024f1574899..1146009f41df9290e4efabffd12e03f5a30e1811 100644 (file)
@@ -17,12 +17,11 @@ obj-$(CONFIG_MTD_ICHXROM)   += ichxrom.o
 obj-$(CONFIG_MTD_CK804XROM)    += ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
+physmap-objs-y                 += physmap-core.o
+physmap-objs-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o
+physmap-objs-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o
+physmap-objs                   := $(physmap-objs-y)
 obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o
-physmap_of-objs-y              += physmap_of_core.o
-physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_VERSATILE) += physmap_of_versatile.o
-physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_GEMINI) += physmap_of_gemini.o
-physmap_of-objs                        := $(physmap_of-objs-y)
-obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
 obj-$(CONFIG_MTD_PISMO)                += pismo.o
 obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
@@ -44,6 +43,4 @@ obj-$(CONFIG_MTD_PLATRAM)     += plat-ram.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
 obj-$(CONFIG_MTD_RBTX4939)     += rbtx4939-flash.o
 obj-$(CONFIG_MTD_VMU)          += vmu-flash.o
-obj-$(CONFIG_MTD_GPIO_ADDR)    += gpio-addr-flash.o
-obj-$(CONFIG_MTD_LATCH_ADDR)   += latch-addr-flash.o
 obj-$(CONFIG_MTD_LANTIQ)       += lantiq-flash.o
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
deleted file mode 100644 (file)
index a20e85a..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * drivers/mtd/maps/gpio-addr-flash.c
- *
- * Handle the case where a flash device is mostly addressed using physical
- * line and supplemented by GPIOs.  This way you can hook up say a 8MiB flash
- * to a 2MiB memory range and use the GPIOs to select a particular range.
- *
- * Copyright © 2000 Nicolas Pitre <nico@cam.org>
- * Copyright © 2005-2009 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#define win_mask(x) ((BIT(x)) - 1)
-
-#define DRIVER_NAME "gpio-addr-flash"
-
-/**
- * struct async_state - keep GPIO flash state
- *     @mtd:         MTD state for this mapping
- *     @map:         MTD map state for this flash
- *     @gpios:       Struct containing the array of GPIO descriptors
- *     @gpio_values: cached GPIO values
- *     @win_order:   dedicated memory size (if no GPIOs)
- */
-struct async_state {
-       struct mtd_info *mtd;
-       struct map_info map;
-       struct gpio_descs *gpios;
-       unsigned int gpio_values;
-       unsigned int win_order;
-};
-#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
-
-/**
- * gf_set_gpios() - set GPIO address lines to access specified flash offset
- *     @state: GPIO flash state
- *     @ofs:   desired offset to access
- *
- * Rather than call the GPIO framework every time, cache the last-programmed
- * value.  This speeds up sequential accesses (which are by far the most common
- * type).
- */
-static void gf_set_gpios(struct async_state *state, unsigned long ofs)
-{
-       int i;
-
-       ofs >>= state->win_order;
-
-       if (ofs == state->gpio_values)
-               return;
-
-       for (i = 0; i < state->gpios->ndescs; i++) {
-               if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
-                       continue;
-
-               gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
-       }
-
-       state->gpio_values = ofs;
-}
-
-/**
- * gf_read() - read a word at the specified offset
- *     @map: MTD map state
- *     @ofs: desired offset to read
- */
-static map_word gf_read(struct map_info *map, unsigned long ofs)
-{
-       struct async_state *state = gf_map_info_to_state(map);
-       uint16_t word;
-       map_word test;
-
-       gf_set_gpios(state, ofs);
-
-       word = readw(map->virt + (ofs & win_mask(state->win_order)));
-       test.x[0] = word;
-       return test;
-}
-
-/**
- * gf_copy_from() - copy a chunk of data from the flash
- *     @map:  MTD map state
- *     @to:   memory to copy to
- *     @from: flash offset to copy from
- *     @len:  how much to copy
- *
- * The "from" region may straddle more than one window, so toggle the GPIOs for
- * each window region before reading its data.
- */
-static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       struct async_state *state = gf_map_info_to_state(map);
-
-       int this_len;
-
-       while (len) {
-               this_len = from & win_mask(state->win_order);
-               this_len = BIT(state->win_order) - this_len;
-               this_len = min_t(int, len, this_len);
-
-               gf_set_gpios(state, from);
-               memcpy_fromio(to,
-                             map->virt + (from & win_mask(state->win_order)),
-                             this_len);
-               len -= this_len;
-               from += this_len;
-               to += this_len;
-       }
-}
-
-/**
- * gf_write() - write a word at the specified offset
- *     @map: MTD map state
- *     @ofs: desired offset to write
- */
-static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
-{
-       struct async_state *state = gf_map_info_to_state(map);
-       uint16_t d;
-
-       gf_set_gpios(state, ofs);
-
-       d = d1.x[0];
-       writew(d, map->virt + (ofs & win_mask(state->win_order)));
-}
-
-/**
- * gf_copy_to() - copy a chunk of data to the flash
- *     @map:  MTD map state
- *     @to:   flash offset to copy to
- *     @from: memory to copy from
- *     @len:  how much to copy
- *
- * See gf_copy_from() caveat.
- */
-static void gf_copy_to(struct map_info *map, unsigned long to,
-                      const void *from, ssize_t len)
-{
-       struct async_state *state = gf_map_info_to_state(map);
-
-       int this_len;
-
-       while (len) {
-               this_len = to & win_mask(state->win_order);
-               this_len = BIT(state->win_order) - this_len;
-               this_len = min_t(int, len, this_len);
-
-               gf_set_gpios(state, to);
-               memcpy_toio(map->virt + (to & win_mask(state->win_order)),
-                           from, len);
-
-               len -= this_len;
-               to += this_len;
-               from += this_len;
-       }
-}
-
-static const char * const part_probe_types[] = {
-       "cmdlinepart", "RedBoot", NULL };
-
-/**
- * gpio_flash_probe() - setup a mapping for a GPIO assisted flash
- *     @pdev: platform device
- *
- * The platform resource layout expected looks something like:
- * struct mtd_partition partitions[] = { ... };
- * struct physmap_flash_data flash_data = { ... };
- * static struct gpiod_lookup_table addr_flash_gpios = {
- *             .dev_id = "gpio-addr-flash.0",
- *             .table = {
- *             GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
- *             GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
- *             );
- * };
- * gpiod_add_lookup_table(&addr_flash_gpios);
- *
- * struct resource flash_resource[] = {
- *     {
- *             .name  = "cfi_probe",
- *             .start = 0x20000000,
- *             .end   = 0x201fffff,
- *             .flags = IORESOURCE_MEM,
- *     },
- * };
- * struct platform_device flash_device = {
- *     .name          = "gpio-addr-flash",
- *     .dev           = { .platform_data = &flash_data, },
- *     .num_resources = ARRAY_SIZE(flash_resource),
- *     .resource      = flash_resource,
- *     ...
- * };
- */
-static int gpio_flash_probe(struct platform_device *pdev)
-{
-       struct physmap_flash_data *pdata;
-       struct resource *memory;
-       struct async_state *state;
-
-       pdata = dev_get_platdata(&pdev->dev);
-       memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       if (!memory)
-               return -EINVAL;
-
-       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
-       if (!state)
-               return -ENOMEM;
-
-       state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
-       if (IS_ERR(state->gpios))
-               return PTR_ERR(state->gpios);
-
-       state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
-
-       state->map.name       = DRIVER_NAME;
-       state->map.read       = gf_read;
-       state->map.copy_from  = gf_copy_from;
-       state->map.write      = gf_write;
-       state->map.copy_to    = gf_copy_to;
-       state->map.bankwidth  = pdata->width;
-       state->map.size       = BIT(state->win_order + state->gpios->ndescs);
-       state->map.virt       = devm_ioremap_resource(&pdev->dev, memory);
-       if (IS_ERR(state->map.virt))
-               return PTR_ERR(state->map.virt);
-
-       state->map.phys       = NO_XIP;
-       state->map.map_priv_1 = (unsigned long)state;
-
-       platform_set_drvdata(pdev, state);
-
-       dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
-                  state->map.bankwidth * 8);
-       state->mtd = do_map_probe(memory->name, &state->map);
-       if (!state->mtd)
-               return -ENXIO;
-       state->mtd->dev.parent = &pdev->dev;
-
-       mtd_device_parse_register(state->mtd, part_probe_types, NULL,
-                                 pdata->parts, pdata->nr_parts);
-
-       return 0;
-}
-
-static int gpio_flash_remove(struct platform_device *pdev)
-{
-       struct async_state *state = platform_get_drvdata(pdev);
-
-       mtd_device_unregister(state->mtd);
-       map_destroy(state->mtd);
-       return 0;
-}
-
-static struct platform_driver gpio_flash_driver = {
-       .probe          = gpio_flash_probe,
-       .remove         = gpio_flash_remove,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-module_platform_driver(gpio_flash_driver);
-
-MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
-MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c
deleted file mode 100644 (file)
index 51db24b..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Interface for NOR flash driver whose high address lines are latched
- *
- * Copyright © 2000 Nicolas Pitre <nico@cam.org>
- * Copyright © 2005-2008 Analog Devices Inc.
- * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/latch-addr-flash.h>
-#include <linux/slab.h>
-
-#define DRIVER_NAME "latch-addr-flash"
-
-struct latch_addr_flash_info {
-       struct mtd_info         *mtd;
-       struct map_info         map;
-       struct resource         *res;
-
-       void                    (*set_window)(unsigned long offset, void *data);
-       void                    *data;
-
-       /* cache; could be found out of res */
-       unsigned long           win_mask;
-
-       spinlock_t              lock;
-};
-
-static map_word lf_read(struct map_info *map, unsigned long ofs)
-{
-       struct latch_addr_flash_info *info;
-       map_word datum;
-
-       info = (struct latch_addr_flash_info *)map->map_priv_1;
-
-       spin_lock(&info->lock);
-
-       info->set_window(ofs, info->data);
-       datum = inline_map_read(map, info->win_mask & ofs);
-
-       spin_unlock(&info->lock);
-
-       return datum;
-}
-
-static void lf_write(struct map_info *map, map_word datum, unsigned long ofs)
-{
-       struct latch_addr_flash_info *info;
-
-       info = (struct latch_addr_flash_info *)map->map_priv_1;
-
-       spin_lock(&info->lock);
-
-       info->set_window(ofs, info->data);
-       inline_map_write(map, datum, info->win_mask & ofs);
-
-       spin_unlock(&info->lock);
-}
-
-static void lf_copy_from(struct map_info *map, void *to,
-               unsigned long from, ssize_t len)
-{
-       struct latch_addr_flash_info *info =
-               (struct latch_addr_flash_info *) map->map_priv_1;
-       unsigned n;
-
-       while (len > 0) {
-               n = info->win_mask + 1 - (from & info->win_mask);
-               if (n > len)
-                       n = len;
-
-               spin_lock(&info->lock);
-
-               info->set_window(from, info->data);
-               memcpy_fromio(to, map->virt + (from & info->win_mask), n);
-
-               spin_unlock(&info->lock);
-
-               to += n;
-               from += n;
-               len -= n;
-       }
-}
-
-static char *rom_probe_types[] = { "cfi_probe", NULL };
-
-static int latch_addr_flash_remove(struct platform_device *dev)
-{
-       struct latch_addr_flash_info *info;
-       struct latch_addr_flash_data *latch_addr_data;
-
-       info = platform_get_drvdata(dev);
-       if (info == NULL)
-               return 0;
-
-       latch_addr_data = dev_get_platdata(&dev->dev);
-
-       if (info->mtd != NULL) {
-               mtd_device_unregister(info->mtd);
-               map_destroy(info->mtd);
-       }
-
-       if (info->map.virt != NULL)
-               iounmap(info->map.virt);
-
-       if (info->res != NULL)
-               release_mem_region(info->res->start, resource_size(info->res));
-
-       kfree(info);
-
-       if (latch_addr_data->done)
-               latch_addr_data->done(latch_addr_data->data);
-
-       return 0;
-}
-
-static int latch_addr_flash_probe(struct platform_device *dev)
-{
-       struct latch_addr_flash_data *latch_addr_data;
-       struct latch_addr_flash_info *info;
-       resource_size_t win_base = dev->resource->start;
-       resource_size_t win_size = resource_size(dev->resource);
-       char **probe_type;
-       int chipsel;
-       int err;
-
-       latch_addr_data = dev_get_platdata(&dev->dev);
-       if (latch_addr_data == NULL)
-               return -ENODEV;
-
-       pr_notice("latch-addr platform flash device: %#llx byte "
-                 "window at %#.8llx\n",
-                 (unsigned long long)win_size, (unsigned long long)win_base);
-
-       chipsel = dev->id;
-
-       if (latch_addr_data->init) {
-               err = latch_addr_data->init(latch_addr_data->data, chipsel);
-               if (err != 0)
-                       return err;
-       }
-
-       info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL);
-       if (info == NULL) {
-               err = -ENOMEM;
-               goto done;
-       }
-
-       platform_set_drvdata(dev, info);
-
-       info->res = request_mem_region(win_base, win_size, DRIVER_NAME);
-       if (info->res == NULL) {
-               dev_err(&dev->dev, "Could not reserve memory region\n");
-               err = -EBUSY;
-               goto free_info;
-       }
-
-       info->map.name          = DRIVER_NAME;
-       info->map.size          = latch_addr_data->size;
-       info->map.bankwidth     = latch_addr_data->width;
-
-       info->map.phys          = NO_XIP;
-       info->map.virt          = ioremap(win_base, win_size);
-       if (!info->map.virt) {
-               err = -ENOMEM;
-               goto free_res;
-       }
-
-       info->map.map_priv_1    = (unsigned long)info;
-
-       info->map.read          = lf_read;
-       info->map.copy_from     = lf_copy_from;
-       info->map.write         = lf_write;
-       info->set_window        = latch_addr_data->set_window;
-       info->data              = latch_addr_data->data;
-       info->win_mask          = win_size - 1;
-
-       spin_lock_init(&info->lock);
-
-       for (probe_type = rom_probe_types; !info->mtd && *probe_type;
-               probe_type++)
-               info->mtd = do_map_probe(*probe_type, &info->map);
-
-       if (info->mtd == NULL) {
-               dev_err(&dev->dev, "map_probe failed\n");
-               err = -ENODEV;
-               goto iounmap;
-       }
-       info->mtd->dev.parent = &dev->dev;
-
-       mtd_device_register(info->mtd, latch_addr_data->parts,
-                           latch_addr_data->nr_parts);
-       return 0;
-
-iounmap:
-       iounmap(info->map.virt);
-free_res:
-       release_mem_region(info->res->start, resource_size(info->res));
-free_info:
-       kfree(info);
-done:
-       if (latch_addr_data->done)
-               latch_addr_data->done(latch_addr_data->data);
-       return err;
-}
-
-static struct platform_driver latch_addr_flash_driver = {
-       .probe          = latch_addr_flash_probe,
-       .remove         = latch_addr_flash_remove,
-       .driver         = {
-               .name   = DRIVER_NAME,
-       },
-};
-
-module_platform_driver(latch_addr_flash_driver);
-
-MODULE_AUTHOR("David Griego <dgriego@mvista.com>");
-MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper "
-               "address lines being set board specifically");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c
new file mode 100644 (file)
index 0000000..d9a3e4b
--- /dev/null
@@ -0,0 +1,665 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Normal mappings of chips in physical memory
+ *
+ * Copyright (C) 2003 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 031022 - [jsun] add run-time configure and partition setup
+ *
+ * Device tree support:
+ *    Copyright (C) 2006 MontaVista Software Inc.
+ *    Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ *    Revised to handle newer style flash binding by:
+ *    Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * GPIO address extension:
+ *    Handle the case where a flash device is mostly addressed using physical
+ *    line and supplemented by GPIOs.  This way you can hook up say a 8MiB flash
+ *    to a 2MiB memory range and use the GPIOs to select a particular range.
+ *
+ *    Copyright © 2000 Nicolas Pitre <nico@cam.org>
+ *    Copyright © 2005-2009 Analog Devices Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/concat.h>
+#include <linux/mtd/cfi_endian.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/gpio/consumer.h>
+
+#include "physmap-gemini.h"
+#include "physmap-versatile.h"
+
+struct physmap_flash_info {
+       unsigned int            nmaps;
+       struct mtd_info         **mtds;
+       struct mtd_info         *cmtd;
+       struct map_info         *maps;
+       spinlock_t              vpp_lock;
+       int                     vpp_refcnt;
+       const char              *probe_type;
+       const char * const      *part_types;
+       unsigned int            nparts;
+       const struct mtd_partition *parts;
+       struct gpio_descs       *gpios;
+       unsigned int            gpio_values;
+       unsigned int            win_order;
+};
+
+static int physmap_flash_remove(struct platform_device *dev)
+{
+       struct physmap_flash_info *info;
+       struct physmap_flash_data *physmap_data;
+       int i, err;
+
+       info = platform_get_drvdata(dev);
+       if (!info)
+               return 0;
+
+       if (info->cmtd) {
+               err = mtd_device_unregister(info->cmtd);
+               if (err)
+                       return err;
+
+               if (info->cmtd != info->mtds[0])
+                       mtd_concat_destroy(info->cmtd);
+       }
+
+       for (i = 0; i < info->nmaps; i++) {
+               if (info->mtds[i])
+                       map_destroy(info->mtds[i]);
+       }
+
+       physmap_data = dev_get_platdata(&dev->dev);
+       if (physmap_data && physmap_data->exit)
+               physmap_data->exit(dev);
+
+       return 0;
+}
+
+static void physmap_set_vpp(struct map_info *map, int state)
+{
+       struct platform_device *pdev;
+       struct physmap_flash_data *physmap_data;
+       struct physmap_flash_info *info;
+       unsigned long flags;
+
+       pdev = (struct platform_device *)map->map_priv_1;
+       physmap_data = dev_get_platdata(&pdev->dev);
+
+       if (!physmap_data->set_vpp)
+               return;
+
+       info = platform_get_drvdata(pdev);
+
+       spin_lock_irqsave(&info->vpp_lock, flags);
+       if (state) {
+               if (++info->vpp_refcnt == 1)    /* first nested 'on' */
+                       physmap_data->set_vpp(pdev, 1);
+       } else {
+               if (--info->vpp_refcnt == 0)    /* last nested 'off' */
+                       physmap_data->set_vpp(pdev, 0);
+       }
+       spin_unlock_irqrestore(&info->vpp_lock, flags);
+}
+
+#if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
+static void physmap_set_addr_gpios(struct physmap_flash_info *info,
+                                  unsigned long ofs)
+{
+       unsigned int i;
+
+       ofs >>= info->win_order;
+       if (info->gpio_values == ofs)
+               return;
+
+       for (i = 0; i < info->gpios->ndescs; i++) {
+               if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
+                       continue;
+
+               gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
+       }
+}
+
+#define win_mask(order)                (BIT(order) - 1)
+
+static map_word physmap_addr_gpios_read(struct map_info *map,
+                                       unsigned long ofs)
+{
+       struct platform_device *pdev;
+       struct physmap_flash_info *info;
+       map_word mw;
+       u16 word;
+
+       pdev = (struct platform_device *)map->map_priv_1;
+       info = platform_get_drvdata(pdev);
+       physmap_set_addr_gpios(info, ofs);
+
+       word = readw(map->virt + (ofs & win_mask(info->win_order)));
+       mw.x[0] = word;
+       return mw;
+}
+
+static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
+                                        unsigned long ofs, ssize_t len)
+{
+       struct platform_device *pdev;
+       struct physmap_flash_info *info;
+
+       pdev = (struct platform_device *)map->map_priv_1;
+       info = platform_get_drvdata(pdev);
+
+       while (len) {
+               unsigned int winofs = ofs & win_mask(info->win_order);
+               unsigned int chunklen = min_t(unsigned int, len,
+                                             BIT(info->win_order) - winofs);
+
+               physmap_set_addr_gpios(info, ofs);
+               memcpy_fromio(buf, map->virt + winofs, chunklen);
+               len -= chunklen;
+               buf += chunklen;
+               ofs += chunklen;
+       }
+}
+
+static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
+                                    unsigned long ofs)
+{
+       struct platform_device *pdev;
+       struct physmap_flash_info *info;
+       u16 word;
+
+       pdev = (struct platform_device *)map->map_priv_1;
+       info = platform_get_drvdata(pdev);
+       physmap_set_addr_gpios(info, ofs);
+
+       word = mw.x[0];
+       writew(word, map->virt + (ofs & win_mask(info->win_order)));
+}
+
+static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
+                                      const void *buf, ssize_t len)
+{
+       struct platform_device *pdev;
+       struct physmap_flash_info *info;
+
+       pdev = (struct platform_device *)map->map_priv_1;
+       info = platform_get_drvdata(pdev);
+
+       while (len) {
+               unsigned int winofs = ofs & win_mask(info->win_order);
+               unsigned int chunklen = min_t(unsigned int, len,
+                                             BIT(info->win_order) - winofs);
+
+               physmap_set_addr_gpios(info, ofs);
+               memcpy_toio(map->virt + winofs, buf, chunklen);
+               len -= chunklen;
+               buf += chunklen;
+               ofs += chunklen;
+       }
+}
+
+static int physmap_addr_gpios_map_init(struct map_info *map)
+{
+       map->phys = NO_XIP;
+       map->read = physmap_addr_gpios_read;
+       map->copy_from = physmap_addr_gpios_copy_from;
+       map->write = physmap_addr_gpios_write;
+       map->copy_to = physmap_addr_gpios_copy_to;
+
+       return 0;
+}
+#else
+static int physmap_addr_gpios_map_init(struct map_info *map)
+{
+       return -ENOTSUPP;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
+static const struct of_device_id of_flash_match[] = {
+       {
+               .compatible = "cfi-flash",
+               .data = "cfi_probe",
+       },
+       {
+               /*
+                * FIXME: JEDEC chips can't be safely and reliably
+                * probed, although the mtd code gets it right in
+                * practice most of the time.  We should use the
+                * vendor and device ids specified by the binding to
+                * bypass the heuristic probe code, but the mtd layer
+                * provides, at present, no interface for doing so
+                * :(.
+                */
+               .compatible = "jedec-flash",
+               .data = "jedec_probe",
+       },
+       {
+               .compatible = "mtd-ram",
+               .data = "map_ram",
+       },
+       {
+               .compatible = "mtd-rom",
+               .data = "map_rom",
+       },
+       {
+               .type = "rom",
+               .compatible = "direct-mapped"
+       },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, of_flash_match);
+
+static const char * const of_default_part_probes[] = {
+       "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL
+};
+
+static const char * const *of_get_part_probes(struct platform_device *dev)
+{
+       struct device_node *dp = dev->dev.of_node;
+       const char **res;
+       int count;
+
+       count = of_property_count_strings(dp, "linux,part-probe");
+       if (count < 0)
+               return of_default_part_probes;
+
+       res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return NULL;
+
+       count = of_property_read_string_array(dp, "linux,part-probe", res,
+                                             count);
+       if (count < 0)
+               return NULL;
+
+       return res;
+}
+
+static const char *of_select_probe_type(struct platform_device *dev)
+{
+       struct device_node *dp = dev->dev.of_node;
+       const struct of_device_id *match;
+       const char *probe_type;
+
+       match = of_match_device(of_flash_match, &dev->dev);
+       probe_type = match->data;
+       if (probe_type)
+               return probe_type;
+
+       dev_warn(&dev->dev,
+                "Device tree uses obsolete \"direct-mapped\" flash binding\n");
+
+       of_property_read_string(dp, "probe-type", &probe_type);
+       if (!probe_type)
+               return NULL;
+
+       if (!strcmp(probe_type, "CFI")) {
+               probe_type = "cfi_probe";
+       } else if (!strcmp(probe_type, "JEDEC")) {
+               probe_type = "jedec_probe";
+       } else if (!strcmp(probe_type, "ROM")) {
+               probe_type = "map_rom";
+       } else {
+               dev_warn(&dev->dev,
+                        "obsolete_probe: don't know probe type '%s', mapping as rom\n",
+                        probe_type);
+               probe_type = "map_rom";
+       }
+
+       return probe_type;
+}
+
+static int physmap_flash_of_init(struct platform_device *dev)
+{
+       struct physmap_flash_info *info = platform_get_drvdata(dev);
+       struct device_node *dp = dev->dev.of_node;
+       const char *mtd_name = NULL;
+       int err, swap = 0;
+       bool map_indirect;
+       unsigned int i;
+       u32 bankwidth;
+
+       if (!dp)
+               return -EINVAL;
+
+       info->probe_type = of_select_probe_type(dev);
+
+       info->part_types = of_get_part_probes(dev);
+       if (!info->part_types)
+               return -ENOMEM;
+
+       of_property_read_string(dp, "linux,mtd-name", &mtd_name);
+
+       map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
+
+       err = of_property_read_u32(dp, "bank-width", &bankwidth);
+       if (err) {
+               dev_err(&dev->dev, "Can't get bank width from device tree\n");
+               return err;
+       }
+
+       if (of_property_read_bool(dp, "big-endian"))
+               swap = CFI_BIG_ENDIAN;
+       else if (of_property_read_bool(dp, "little-endian"))
+               swap = CFI_LITTLE_ENDIAN;
+
+       for (i = 0; i < info->nmaps; i++) {
+               info->maps[i].name = mtd_name;
+               info->maps[i].swap = swap;
+               info->maps[i].bankwidth = bankwidth;
+               info->maps[i].device_node = dp;
+
+               err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
+               if (err)
+                       return err;
+
+               err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
+               if (err)
+                       return err;
+
+               /*
+                * On some platforms (e.g. MPC5200) a direct 1:1 mapping
+                * may cause problems with JFFS2 usage, as the local bus (LPB)
+                * doesn't support unaligned accesses as implemented in the
+                * JFFS2 code via memcpy(). By setting NO_XIP, the
+                * flash will not be exposed directly to the MTD users
+                * (e.g. JFFS2) any more.
+                */
+               if (map_indirect)
+                       info->maps[i].phys = NO_XIP;
+       }
+
+       return 0;
+}
+#else /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
+#define of_flash_match NULL
+
+static int physmap_flash_of_init(struct platform_device *dev)
+{
+       return -ENOTSUPP;
+}
+#endif /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
+
+static const char * const rom_probe_types[] = {
+       "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom",
+};
+
+static const char * const part_probe_types[] = {
+       "cmdlinepart", "RedBoot", "afs", NULL
+};
+
+static int physmap_flash_pdata_init(struct platform_device *dev)
+{
+       struct physmap_flash_info *info = platform_get_drvdata(dev);
+       struct physmap_flash_data *physmap_data;
+       unsigned int i;
+       int err;
+
+       physmap_data = dev_get_platdata(&dev->dev);
+       if (!physmap_data)
+               return -EINVAL;
+
+       info->probe_type = physmap_data->probe_type;
+       info->part_types = physmap_data->part_probe_types ? : part_probe_types;
+       info->parts = physmap_data->parts;
+       info->nparts = physmap_data->nr_parts;
+
+       if (physmap_data->init) {
+               err = physmap_data->init(dev);
+               if (err)
+                       return err;
+       }
+
+       for (i = 0; i < info->nmaps; i++) {
+               info->maps[i].bankwidth = physmap_data->width;
+               info->maps[i].pfow_base = physmap_data->pfow_base;
+               info->maps[i].set_vpp = physmap_set_vpp;
+       }
+
+       return 0;
+}
+
+static int physmap_flash_probe(struct platform_device *dev)
+{
+       struct physmap_flash_info *info;
+       int err = 0;
+       int i;
+
+       if (!dev->dev.of_node && !dev_get_platdata(&dev->dev))
+               return -EINVAL;
+
+       info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps))
+               info->nmaps++;
+
+       if (!info->nmaps)
+               return -ENODEV;
+
+       info->maps = devm_kzalloc(&dev->dev,
+                                 sizeof(*info->maps) * info->nmaps,
+                                 GFP_KERNEL);
+       if (!info->maps)
+               return -ENOMEM;
+
+       info->mtds = devm_kzalloc(&dev->dev,
+                                 sizeof(*info->mtds) * info->nmaps,
+                                 GFP_KERNEL);
+       if (!info->mtds)
+               return -ENOMEM;
+
+       platform_set_drvdata(dev, info);
+
+       info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
+                                                   GPIOD_OUT_LOW);
+       if (IS_ERR(info->gpios))
+               return PTR_ERR(info->gpios);
+
+       if (info->gpios && info->nmaps > 1) {
+               dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
+               return -EINVAL;
+       }
+
+       if (dev->dev.of_node)
+               err = physmap_flash_of_init(dev);
+       else
+               err = physmap_flash_pdata_init(dev);
+
+       if (err)
+               return err;
+
+       for (i = 0; i < info->nmaps; i++) {
+               struct resource *res;
+
+               res = platform_get_resource(dev, IORESOURCE_MEM, i);
+               info->maps[i].virt = devm_ioremap_resource(&dev->dev, res);
+               if (IS_ERR(info->maps[i].virt)) {
+                       err = PTR_ERR(info->maps[i].virt);
+                       goto err_out;
+               }
+
+               dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
+                          res);
+
+               info->maps[i].name = dev_name(&dev->dev);
+
+               if (!info->maps[i].phys)
+                       info->maps[i].phys = res->start;
+
+               info->win_order = get_bitmask_order(resource_size(res)) - 1;
+               info->maps[i].size = BIT(info->win_order +
+                                        (info->gpios ?
+                                         info->gpios->ndescs : 0));
+
+               info->maps[i].map_priv_1 = (unsigned long)dev;
+
+               if (info->gpios) {
+                       err = physmap_addr_gpios_map_init(&info->maps[i]);
+                       if (err)
+                               goto err_out;
+               }
+
+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
+               /*
+                * Only use the simple_map implementation if map hooks are not
+                * implemented. Since map->read() is mandatory checking for its
+                * presence is enough.
+                */
+               if (!info->maps[i].read)
+                       simple_map_init(&info->maps[i]);
+#else
+               simple_map_init(&info->maps[i]);
+#endif
+
+               if (info->probe_type) {
+                       info->mtds[i] = do_map_probe(info->probe_type,
+                                                    &info->maps[i]);
+               } else {
+                       int j;
+
+                       for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) {
+                               info->mtds[i] = do_map_probe(rom_probe_types[j],
+                                                            &info->maps[i]);
+                               if (info->mtds[i])
+                                       break;
+                       }
+               }
+
+               if (!info->mtds[i]) {
+                       dev_err(&dev->dev, "map_probe failed\n");
+                       err = -ENXIO;
+                       goto err_out;
+               }
+               info->mtds[i]->dev.parent = &dev->dev;
+       }
+
+       if (info->nmaps == 1) {
+               info->cmtd = info->mtds[0];
+       } else {
+               /*
+                * We detected multiple devices. Concatenate them together.
+                */
+               info->cmtd = mtd_concat_create(info->mtds, info->nmaps,
+                                              dev_name(&dev->dev));
+               if (!info->cmtd)
+                       err = -ENXIO;
+       }
+       if (err)
+               goto err_out;
+
+       spin_lock_init(&info->vpp_lock);
+
+       mtd_set_of_node(info->cmtd, dev->dev.of_node);
+       err = mtd_device_parse_register(info->cmtd, info->part_types, NULL,
+                                       info->parts, info->nparts);
+       if (err)
+               goto err_out;
+
+       return 0;
+
+err_out:
+       physmap_flash_remove(dev);
+       return err;
+}
+
+#ifdef CONFIG_PM
+static void physmap_flash_shutdown(struct platform_device *dev)
+{
+       struct physmap_flash_info *info = platform_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < info->nmaps && info->mtds[i]; i++)
+               if (mtd_suspend(info->mtds[i]) == 0)
+                       mtd_resume(info->mtds[i]);
+}
+#else
+#define physmap_flash_shutdown NULL
+#endif
+
+static struct platform_driver physmap_flash_driver = {
+       .probe          = physmap_flash_probe,
+       .remove         = physmap_flash_remove,
+       .shutdown       = physmap_flash_shutdown,
+       .driver         = {
+               .name   = "physmap-flash",
+               .of_match_table = of_flash_match,
+       },
+};
+
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
+static struct physmap_flash_data physmap_flash_data = {
+       .width          = CONFIG_MTD_PHYSMAP_BANKWIDTH,
+};
+
+static struct resource physmap_flash_resource = {
+       .start          = CONFIG_MTD_PHYSMAP_START,
+       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device physmap_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &physmap_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &physmap_flash_resource,
+};
+#endif
+
+static int __init physmap_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&physmap_flash_driver);
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
+       if (err == 0) {
+               err = platform_device_register(&physmap_flash);
+               if (err)
+                       platform_driver_unregister(&physmap_flash_driver);
+       }
+#endif
+
+       return err;
+}
+
+static void __exit physmap_exit(void)
+{
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
+       platform_device_unregister(&physmap_flash);
+#endif
+       platform_driver_unregister(&physmap_flash_driver);
+}
+
+module_init(physmap_init);
+module_exit(physmap_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
+MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
+
+/* legacy platform drivers can't hotplug or coldplg */
+#ifndef CONFIG_MTD_PHYSMAP_COMPAT
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:physmap-flash");
+#endif
diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c
new file mode 100644 (file)
index 0000000..60775b2
--- /dev/null
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cortina Systems Gemini OF physmap add-on
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This SoC has an elaborate flash control register, so we need to
+ * detect and set it up when booting on this platform.
+ */
+#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/xip.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include <linux/pinctrl/consumer.h>
+#include "physmap-gemini.h"
+
+/*
+ * The Flash-relevant parts of the global status register
+ * These would also be relevant for a NAND driver.
+ */
+#define GLOBAL_STATUS                  0x04
+#define FLASH_TYPE_MASK                        (0x3 << 24)
+#define FLASH_TYPE_NAND_2K             (0x3 << 24)
+#define FLASH_TYPE_NAND_512            (0x2 << 24)
+#define FLASH_TYPE_PARALLEL            (0x1 << 24)
+#define FLASH_TYPE_SERIAL              (0x0 << 24)
+/* if parallel */
+#define FLASH_WIDTH_16BIT              (1 << 23)       /* else 8 bit */
+/* if serial */
+#define FLASH_ATMEL                    (1 << 23)       /* else STM */
+
+#define FLASH_SIZE_MASK                        (0x3 << 21)
+#define NAND_256M                      (0x3 << 21)     /* and more */
+#define NAND_128M                      (0x2 << 21)
+#define NAND_64M                       (0x1 << 21)
+#define NAND_32M                       (0x0 << 21)
+#define ATMEL_16M                      (0x3 << 21)     /* and more */
+#define ATMEL_8M                       (0x2 << 21)
+#define ATMEL_4M_2M                    (0x1 << 21)
+#define ATMEL_1M                       (0x0 << 21)     /* and less */
+#define STM_32M                                (1 << 22)       /* and more */
+#define STM_16M                                (0 << 22)       /* and less */
+
+#define FLASH_PARALLEL_HIGH_PIN_CNT    (1 << 20)       /* else low pin cnt */
+
+static const struct of_device_id syscon_match[] = {
+       { .compatible = "cortina,gemini-syscon" },
+       { },
+};
+
+struct gemini_flash {
+       struct device *dev;
+       struct pinctrl *p;
+       struct pinctrl_state *enabled_state;
+       struct pinctrl_state *disabled_state;
+};
+
+/* Static local state */
+static struct gemini_flash *gf;
+
+static void gemini_flash_enable_pins(void)
+{
+       int ret;
+
+       if (IS_ERR(gf->enabled_state))
+               return;
+       ret = pinctrl_select_state(gf->p, gf->enabled_state);
+       if (ret)
+               dev_err(gf->dev, "failed to enable pins\n");
+}
+
+static void gemini_flash_disable_pins(void)
+{
+       int ret;
+
+       if (IS_ERR(gf->disabled_state))
+               return;
+       ret = pinctrl_select_state(gf->p, gf->disabled_state);
+       if (ret)
+               dev_err(gf->dev, "failed to disable pins\n");
+}
+
+static map_word __xipram gemini_flash_map_read(struct map_info *map,
+                                              unsigned long ofs)
+{
+       map_word __xipram ret;
+
+       gemini_flash_enable_pins();
+       ret = inline_map_read(map, ofs);
+       gemini_flash_disable_pins();
+
+       return ret;
+}
+
+static void __xipram gemini_flash_map_write(struct map_info *map,
+                                           const map_word datum,
+                                           unsigned long ofs)
+{
+       gemini_flash_enable_pins();
+       inline_map_write(map, datum, ofs);
+       gemini_flash_disable_pins();
+}
+
+static void __xipram gemini_flash_map_copy_from(struct map_info *map,
+                                               void *to, unsigned long from,
+                                               ssize_t len)
+{
+       gemini_flash_enable_pins();
+       inline_map_copy_from(map, to, from, len);
+       gemini_flash_disable_pins();
+}
+
+static void __xipram gemini_flash_map_copy_to(struct map_info *map,
+                                             unsigned long to,
+                                             const void *from, ssize_t len)
+{
+       gemini_flash_enable_pins();
+       inline_map_copy_to(map, to, from, len);
+       gemini_flash_disable_pins();
+}
+
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map)
+{
+       struct regmap *rmap;
+       struct device *dev = &pdev->dev;
+       u32 val;
+       int ret;
+
+       /* Multiplatform guard */
+       if (!of_device_is_compatible(np, "cortina,gemini-flash"))
+               return 0;
+
+       gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);
+       if (!gf)
+               return -ENOMEM;
+       gf->dev = dev;
+
+       rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+       if (IS_ERR(rmap)) {
+               dev_err(dev, "no syscon\n");
+               return PTR_ERR(rmap);
+       }
+
+       ret = regmap_read(rmap, GLOBAL_STATUS, &val);
+       if (ret) {
+               dev_err(dev, "failed to read global status register\n");
+               return -ENODEV;
+       }
+       dev_dbg(dev, "global status reg: %08x\n", val);
+
+       /*
+        * It would be contradictory if a physmap flash was NOT parallel.
+        */
+       if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {
+               dev_err(dev, "flash is not parallel\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Complain if DT data and hardware definition is different.
+        */
+       if (val & FLASH_WIDTH_16BIT) {
+               if (map->bankwidth != 2)
+                       dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",
+                                map->bankwidth * 8);
+       } else {
+               if (map->bankwidth != 1)
+                       dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",
+                                map->bankwidth * 8);
+       }
+
+       gf->p = devm_pinctrl_get(dev);
+       if (IS_ERR(gf->p)) {
+               dev_err(dev, "no pinctrl handle\n");
+               ret = PTR_ERR(gf->p);
+               return ret;
+       }
+
+       gf->enabled_state = pinctrl_lookup_state(gf->p, "enabled");
+       if (IS_ERR(gf->enabled_state))
+               dev_err(dev, "no enabled pin control state\n");
+
+       gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");
+       if (IS_ERR(gf->enabled_state)) {
+               dev_err(dev, "no disabled pin control state\n");
+       } else {
+               ret = pinctrl_select_state(gf->p, gf->disabled_state);
+               if (ret)
+                       dev_err(gf->dev, "failed to disable pins\n");
+       }
+
+       map->read = gemini_flash_map_read;
+       map->write = gemini_flash_map_write;
+       map->copy_from = gemini_flash_map_copy_from;
+       map->copy_to = gemini_flash_map_copy_to;
+
+       dev_info(dev, "initialized Gemini-specific physmap control\n");
+
+       return 0;
+}
diff --git a/drivers/mtd/maps/physmap-gemini.h b/drivers/mtd/maps/physmap-gemini.h
new file mode 100644 (file)
index 0000000..72bd04c
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/of.h>
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_PHYSMAP_GEMINI
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map);
+#else
+static inline
+int of_flash_probe_gemini(struct platform_device *pdev,
+                         struct device_node *np,
+                         struct map_info *map)
+{
+       return 0;
+}
+#endif
diff --git a/drivers/mtd/maps/physmap-versatile.c b/drivers/mtd/maps/physmap-versatile.c
new file mode 100644 (file)
index 0000000..0179d71
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Versatile OF physmap driver add-on
+ *
+ * Copyright (c) 2016, Linaro Limited
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/mtd/map.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include "physmap-versatile.h"
+
+static struct regmap *syscon_regmap;
+
+enum versatile_flashprot {
+       INTEGRATOR_AP_FLASHPROT,
+       INTEGRATOR_CP_FLASHPROT,
+       VERSATILE_FLASHPROT,
+       REALVIEW_FLASHPROT,
+};
+
+static const struct of_device_id syscon_match[] = {
+       {
+               .compatible = "arm,integrator-ap-syscon",
+               .data = (void *)INTEGRATOR_AP_FLASHPROT,
+       },
+       {
+               .compatible = "arm,integrator-cp-syscon",
+               .data = (void *)INTEGRATOR_CP_FLASHPROT,
+       },
+       {
+               .compatible = "arm,core-module-versatile",
+               .data = (void *)VERSATILE_FLASHPROT,
+       },
+       {
+               .compatible = "arm,realview-eb-syscon",
+               .data = (void *)REALVIEW_FLASHPROT,
+       },
+       {
+               .compatible = "arm,realview-pb1176-syscon",
+               .data = (void *)REALVIEW_FLASHPROT,
+       },
+       {
+               .compatible = "arm,realview-pb11mp-syscon",
+               .data = (void *)REALVIEW_FLASHPROT,
+       },
+       {
+               .compatible = "arm,realview-pba8-syscon",
+               .data = (void *)REALVIEW_FLASHPROT,
+       },
+       {
+               .compatible = "arm,realview-pbx-syscon",
+               .data = (void *)REALVIEW_FLASHPROT,
+       },
+       {},
+};
+
+/*
+ * Flash protection handling for the Integrator/AP
+ */
+#define INTEGRATOR_SC_CTRLS_OFFSET     0x08
+#define INTEGRATOR_SC_CTRLC_OFFSET     0x0C
+#define INTEGRATOR_SC_CTRL_FLVPPEN     BIT(1)
+#define INTEGRATOR_SC_CTRL_FLWP                BIT(2)
+
+#define INTEGRATOR_EBI_CSR1_OFFSET     0x04
+/* The manual says bit 2, the code says bit 3, trust the code */
+#define INTEGRATOR_EBI_WRITE_ENABLE    BIT(3)
+#define INTEGRATOR_EBI_LOCK_OFFSET     0x20
+#define INTEGRATOR_EBI_LOCK_VAL                0xA05F
+
+static const struct of_device_id ebi_match[] = {
+       { .compatible = "arm,external-bus-interface"},
+       { },
+};
+
+static int ap_flash_init(struct platform_device *pdev)
+{
+       struct device_node *ebi;
+       void __iomem *ebi_base;
+       u32 val;
+       int ret;
+
+       /* Look up the EBI */
+       ebi = of_find_matching_node(NULL, ebi_match);
+       if (!ebi) {
+               return -ENODEV;
+       }
+       ebi_base = of_iomap(ebi, 0);
+       if (!ebi_base)
+               return -ENODEV;
+
+       /* Clear VPP and write protection bits */
+       ret = regmap_write(syscon_regmap,
+               INTEGRATOR_SC_CTRLC_OFFSET,
+               INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
+       if (ret)
+               dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
+
+       /* Unlock the EBI */
+       writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
+
+       /* Enable write cycles on the EBI, CSR1 (flash) */
+       val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
+       val |= INTEGRATOR_EBI_WRITE_ENABLE;
+       writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
+
+       /* Lock the EBI again */
+       writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
+       iounmap(ebi_base);
+
+       return 0;
+}
+
+static void ap_flash_set_vpp(struct map_info *map, int on)
+{
+       int ret;
+
+       if (on) {
+               ret = regmap_write(syscon_regmap,
+                       INTEGRATOR_SC_CTRLS_OFFSET,
+                       INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
+               if (ret)
+                       pr_err("error enabling AP VPP\n");
+       } else {
+               ret = regmap_write(syscon_regmap,
+                       INTEGRATOR_SC_CTRLC_OFFSET,
+                       INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
+               if (ret)
+                       pr_err("error disabling AP VPP\n");
+       }
+}
+
+/*
+ * Flash protection handling for the Integrator/CP
+ */
+
+#define INTCP_FLASHPROG_OFFSET         0x04
+#define CINTEGRATOR_FLVPPEN            BIT(0)
+#define CINTEGRATOR_FLWREN             BIT(1)
+#define CINTEGRATOR_FLMASK             BIT(0)|BIT(1)
+
+static void cp_flash_set_vpp(struct map_info *map, int on)
+{
+       int ret;
+
+       if (on) {
+               ret = regmap_update_bits(syscon_regmap,
+                               INTCP_FLASHPROG_OFFSET,
+                               CINTEGRATOR_FLMASK,
+                               CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
+               if (ret)
+                       pr_err("error setting CP VPP\n");
+       } else {
+               ret = regmap_update_bits(syscon_regmap,
+                               INTCP_FLASHPROG_OFFSET,
+                               CINTEGRATOR_FLMASK,
+                               0);
+               if (ret)
+                       pr_err("error setting CP VPP\n");
+       }
+}
+
+/*
+ * Flash protection handling for the Versatiles and RealViews
+ */
+
+#define VERSATILE_SYS_FLASH_OFFSET            0x4C
+
+static void versatile_flash_set_vpp(struct map_info *map, int on)
+{
+       int ret;
+
+       ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
+                                0x01, !!on);
+       if (ret)
+               pr_err("error setting Versatile VPP\n");
+}
+
+int of_flash_probe_versatile(struct platform_device *pdev,
+                            struct device_node *np,
+                            struct map_info *map)
+{
+       struct device_node *sysnp;
+       const struct of_device_id *devid;
+       struct regmap *rmap;
+       static enum versatile_flashprot versatile_flashprot;
+       int ret;
+
+       /* Not all flash chips use this protection line */
+       if (!of_device_is_compatible(np, "arm,versatile-flash"))
+               return 0;
+
+       /* For first chip probed, look up the syscon regmap */
+       if (!syscon_regmap) {
+               sysnp = of_find_matching_node_and_match(NULL,
+                                                       syscon_match,
+                                                       &devid);
+               if (!sysnp)
+                       return -ENODEV;
+
+               versatile_flashprot = (enum versatile_flashprot)devid->data;
+               rmap = syscon_node_to_regmap(sysnp);
+               if (IS_ERR(rmap))
+                       return PTR_ERR(rmap);
+
+               syscon_regmap = rmap;
+       }
+
+       switch (versatile_flashprot) {
+       case INTEGRATOR_AP_FLASHPROT:
+               ret = ap_flash_init(pdev);
+               if (ret)
+                       return ret;
+               map->set_vpp = ap_flash_set_vpp;
+               dev_info(&pdev->dev, "Integrator/AP flash protection\n");
+               break;
+       case INTEGRATOR_CP_FLASHPROT:
+               map->set_vpp = cp_flash_set_vpp;
+               dev_info(&pdev->dev, "Integrator/CP flash protection\n");
+               break;
+       case VERSATILE_FLASHPROT:
+       case REALVIEW_FLASHPROT:
+               map->set_vpp = versatile_flash_set_vpp;
+               dev_info(&pdev->dev, "versatile/realview flash protection\n");
+               break;
+       default:
+               dev_info(&pdev->dev, "device marked as Versatile flash "
+                        "but no system controller was found\n");
+               break;
+       }
+
+       return 0;
+}
diff --git a/drivers/mtd/maps/physmap-versatile.h b/drivers/mtd/maps/physmap-versatile.h
new file mode 100644 (file)
index 0000000..9cf39d0
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/of.h>
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_PHYSMAP_VERSATILE
+int of_flash_probe_versatile(struct platform_device *pdev,
+                            struct device_node *np,
+                            struct map_info *map);
+#else
+static inline
+int of_flash_probe_versatile(struct platform_device *pdev,
+                            struct device_node *np,
+                            struct map_info *map)
+{
+       return 0;
+}
+#endif
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
deleted file mode 100644 (file)
index cc2adbb..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Normal mappings of chips in physical memory
- *
- * Copyright (C) 2003 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * 031022 - [jsun] add run-time configure and partition setup
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/concat.h>
-#include <linux/io.h>
-
-#define MAX_RESOURCES          4
-
-struct physmap_flash_info {
-       struct mtd_info         *mtd[MAX_RESOURCES];
-       struct mtd_info         *cmtd;
-       struct map_info         map[MAX_RESOURCES];
-       spinlock_t              vpp_lock;
-       int                     vpp_refcnt;
-};
-
-static int physmap_flash_remove(struct platform_device *dev)
-{
-       struct physmap_flash_info *info;
-       struct physmap_flash_data *physmap_data;
-       int i;
-
-       info = platform_get_drvdata(dev);
-       if (info == NULL)
-               return 0;
-
-       physmap_data = dev_get_platdata(&dev->dev);
-
-       if (info->cmtd) {
-               mtd_device_unregister(info->cmtd);
-               if (info->cmtd != info->mtd[0])
-                       mtd_concat_destroy(info->cmtd);
-       }
-
-       for (i = 0; i < MAX_RESOURCES; i++) {
-               if (info->mtd[i] != NULL)
-                       map_destroy(info->mtd[i]);
-       }
-
-       if (physmap_data->exit)
-               physmap_data->exit(dev);
-
-       return 0;
-}
-
-static void physmap_set_vpp(struct map_info *map, int state)
-{
-       struct platform_device *pdev;
-       struct physmap_flash_data *physmap_data;
-       struct physmap_flash_info *info;
-       unsigned long flags;
-
-       pdev = (struct platform_device *)map->map_priv_1;
-       physmap_data = dev_get_platdata(&pdev->dev);
-
-       if (!physmap_data->set_vpp)
-               return;
-
-       info = platform_get_drvdata(pdev);
-
-       spin_lock_irqsave(&info->vpp_lock, flags);
-       if (state) {
-               if (++info->vpp_refcnt == 1)    /* first nested 'on' */
-                       physmap_data->set_vpp(pdev, 1);
-       } else {
-               if (--info->vpp_refcnt == 0)    /* last nested 'off' */
-                       physmap_data->set_vpp(pdev, 0);
-       }
-       spin_unlock_irqrestore(&info->vpp_lock, flags);
-}
-
-static const char * const rom_probe_types[] = {
-       "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom", NULL };
-
-static const char * const part_probe_types[] = {
-       "cmdlinepart", "RedBoot", "afs", NULL };
-
-static int physmap_flash_probe(struct platform_device *dev)
-{
-       struct physmap_flash_data *physmap_data;
-       struct physmap_flash_info *info;
-       const char * const *probe_type;
-       const char * const *part_types;
-       int err = 0;
-       int i;
-       int devices_found = 0;
-
-       physmap_data = dev_get_platdata(&dev->dev);
-       if (physmap_data == NULL)
-               return -ENODEV;
-
-       info = devm_kzalloc(&dev->dev, sizeof(struct physmap_flash_info),
-                           GFP_KERNEL);
-       if (info == NULL) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       if (physmap_data->init) {
-               err = physmap_data->init(dev);
-               if (err)
-                       goto err_out;
-       }
-
-       platform_set_drvdata(dev, info);
-
-       for (i = 0; i < dev->num_resources; i++) {
-               printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
-                      (unsigned long long)resource_size(&dev->resource[i]),
-                      (unsigned long long)dev->resource[i].start);
-
-               if (!devm_request_mem_region(&dev->dev,
-                       dev->resource[i].start,
-                       resource_size(&dev->resource[i]),
-                       dev_name(&dev->dev))) {
-                       dev_err(&dev->dev, "Could not reserve memory region\n");
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-
-               info->map[i].name = dev_name(&dev->dev);
-               info->map[i].phys = dev->resource[i].start;
-               info->map[i].size = resource_size(&dev->resource[i]);
-               info->map[i].bankwidth = physmap_data->width;
-               info->map[i].set_vpp = physmap_set_vpp;
-               info->map[i].pfow_base = physmap_data->pfow_base;
-               info->map[i].map_priv_1 = (unsigned long)dev;
-
-               info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
-                                                info->map[i].size);
-               if (info->map[i].virt == NULL) {
-                       dev_err(&dev->dev, "Failed to ioremap flash region\n");
-                       err = -EIO;
-                       goto err_out;
-               }
-
-               simple_map_init(&info->map[i]);
-
-               probe_type = rom_probe_types;
-               if (physmap_data->probe_type == NULL) {
-                       for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
-                               info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
-               } else
-                       info->mtd[i] = do_map_probe(physmap_data->probe_type, &info->map[i]);
-
-               if (info->mtd[i] == NULL) {
-                       dev_err(&dev->dev, "map_probe failed\n");
-                       err = -ENXIO;
-                       goto err_out;
-               } else {
-                       devices_found++;
-               }
-               info->mtd[i]->dev.parent = &dev->dev;
-       }
-
-       if (devices_found == 1) {
-               info->cmtd = info->mtd[0];
-       } else if (devices_found > 1) {
-               /*
-                * We detected multiple devices. Concatenate them together.
-                */
-               info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev));
-               if (info->cmtd == NULL)
-                       err = -ENXIO;
-       }
-       if (err)
-               goto err_out;
-
-       spin_lock_init(&info->vpp_lock);
-
-       part_types = physmap_data->part_probe_types ? : part_probe_types;
-
-       mtd_device_parse_register(info->cmtd, part_types, NULL,
-                                 physmap_data->parts, physmap_data->nr_parts);
-       return 0;
-
-err_out:
-       physmap_flash_remove(dev);
-       return err;
-}
-
-#ifdef CONFIG_PM
-static void physmap_flash_shutdown(struct platform_device *dev)
-{
-       struct physmap_flash_info *info = platform_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++)
-               if (mtd_suspend(info->mtd[i]) == 0)
-                       mtd_resume(info->mtd[i]);
-}
-#else
-#define physmap_flash_shutdown NULL
-#endif
-
-static struct platform_driver physmap_flash_driver = {
-       .probe          = physmap_flash_probe,
-       .remove         = physmap_flash_remove,
-       .shutdown       = physmap_flash_shutdown,
-       .driver         = {
-               .name   = "physmap-flash",
-       },
-};
-
-
-#ifdef CONFIG_MTD_PHYSMAP_COMPAT
-static struct physmap_flash_data physmap_flash_data = {
-       .width          = CONFIG_MTD_PHYSMAP_BANKWIDTH,
-};
-
-static struct resource physmap_flash_resource = {
-       .start          = CONFIG_MTD_PHYSMAP_START,
-       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device physmap_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &physmap_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &physmap_flash_resource,
-};
-#endif
-
-static int __init physmap_init(void)
-{
-       int err;
-
-       err = platform_driver_register(&physmap_flash_driver);
-#ifdef CONFIG_MTD_PHYSMAP_COMPAT
-       if (err == 0) {
-               err = platform_device_register(&physmap_flash);
-               if (err)
-                       platform_driver_unregister(&physmap_flash_driver);
-       }
-#endif
-
-       return err;
-}
-
-static void __exit physmap_exit(void)
-{
-#ifdef CONFIG_MTD_PHYSMAP_COMPAT
-       platform_device_unregister(&physmap_flash);
-#endif
-       platform_driver_unregister(&physmap_flash_driver);
-}
-
-module_init(physmap_init);
-module_exit(physmap_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("Generic configurable MTD map driver");
-
-/* legacy platform drivers can't hotplug or coldplg */
-#ifndef CONFIG_MTD_PHYSMAP_COMPAT
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:physmap-flash");
-#endif
diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c
deleted file mode 100644 (file)
index ece605d..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Flash mappings described by the OF (or flattened) device tree
- *
- * Copyright (C) 2006 MontaVista Software Inc.
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- *
- * Revised to handle newer style flash binding by:
- *   Copyright (C) 2007 David Gibson, IBM Corporation.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/concat.h>
-#include <linux/mtd/cfi_endian.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/slab.h>
-#include "physmap_of_gemini.h"
-#include "physmap_of_versatile.h"
-
-struct of_flash_list {
-       struct mtd_info *mtd;
-       struct map_info map;
-};
-
-struct of_flash {
-       struct mtd_info         *cmtd;
-       int list_size; /* number of elements in of_flash_list */
-       struct of_flash_list    list[0];
-};
-
-static int of_flash_remove(struct platform_device *dev)
-{
-       struct of_flash *info;
-       int i;
-
-       info = dev_get_drvdata(&dev->dev);
-       if (!info)
-               return 0;
-       dev_set_drvdata(&dev->dev, NULL);
-
-       if (info->cmtd) {
-               mtd_device_unregister(info->cmtd);
-               if (info->cmtd != info->list[0].mtd)
-                       mtd_concat_destroy(info->cmtd);
-       }
-
-       for (i = 0; i < info->list_size; i++)
-               if (info->list[i].mtd)
-                       map_destroy(info->list[i].mtd);
-
-       return 0;
-}
-
-static const char * const rom_probe_types[] = {
-       "cfi_probe", "jedec_probe", "map_rom" };
-
-/* Helper function to handle probing of the obsolete "direct-mapped"
- * compatible binding, which has an extra "probe-type" property
- * describing the type of flash probe necessary. */
-static struct mtd_info *obsolete_probe(struct platform_device *dev,
-                                      struct map_info *map)
-{
-       struct device_node *dp = dev->dev.of_node;
-       const char *of_probe;
-       struct mtd_info *mtd;
-       int i;
-
-       dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
-                "flash binding\n");
-
-       of_probe = of_get_property(dp, "probe-type", NULL);
-       if (!of_probe) {
-               for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
-                       mtd = do_map_probe(rom_probe_types[i], map);
-                       if (mtd)
-                               return mtd;
-               }
-               return NULL;
-       } else if (strcmp(of_probe, "CFI") == 0) {
-               return do_map_probe("cfi_probe", map);
-       } else if (strcmp(of_probe, "JEDEC") == 0) {
-               return do_map_probe("jedec_probe", map);
-       } else {
-               if (strcmp(of_probe, "ROM") != 0)
-                       dev_warn(&dev->dev, "obsolete_probe: don't know probe "
-                                "type '%s', mapping as rom\n", of_probe);
-               return do_map_probe("map_rom", map);
-       }
-}
-
-/* When partitions are set we look for a linux,part-probe property which
-   specifies the list of partition probers to use. If none is given then the
-   default is use. These take precedence over other device tree
-   information. */
-static const char * const part_probe_types_def[] = {
-       "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
-
-static const char * const *of_get_probes(struct device_node *dp)
-{
-       const char **res;
-       int count;
-
-       count = of_property_count_strings(dp, "linux,part-probe");
-       if (count < 0)
-               return part_probe_types_def;
-
-       res = kcalloc(count + 1, sizeof(*res), GFP_KERNEL);
-       if (!res)
-               return NULL;
-
-       count = of_property_read_string_array(dp, "linux,part-probe", res,
-                                             count);
-       if (count < 0)
-               return NULL;
-
-       return res;
-}
-
-static void of_free_probes(const char * const *probes)
-{
-       if (probes != part_probe_types_def)
-               kfree(probes);
-}
-
-static const struct of_device_id of_flash_match[];
-static int of_flash_probe(struct platform_device *dev)
-{
-       const char * const *part_probe_types;
-       const struct of_device_id *match;
-       struct device_node *dp = dev->dev.of_node;
-       struct resource res;
-       struct of_flash *info;
-       const char *probe_type;
-       const __be32 *width;
-       int err;
-       int i;
-       int count;
-       const __be32 *p;
-       int reg_tuple_size;
-       struct mtd_info **mtd_list = NULL;
-       resource_size_t res_size;
-       bool map_indirect;
-       const char *mtd_name = NULL;
-
-       match = of_match_device(of_flash_match, &dev->dev);
-       if (!match)
-               return -EINVAL;
-       probe_type = match->data;
-
-       reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
-
-       of_property_read_string(dp, "linux,mtd-name", &mtd_name);
-
-       /*
-        * Get number of "reg" tuples. Scan for MTD devices on area's
-        * described by each "reg" region. This makes it possible (including
-        * the concat support) to support the Intel P30 48F4400 chips which
-        * consists internally of 2 non-identical NOR chips on one die.
-        */
-       p = of_get_property(dp, "reg", &count);
-       if (!p || count % reg_tuple_size != 0) {
-               dev_err(&dev->dev, "Malformed reg property on %pOF\n",
-                               dev->dev.of_node);
-               err = -EINVAL;
-               goto err_flash_remove;
-       }
-       count /= reg_tuple_size;
-
-       map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
-
-       err = -ENOMEM;
-       info = devm_kzalloc(&dev->dev,
-                           sizeof(struct of_flash) +
-                           sizeof(struct of_flash_list) * count, GFP_KERNEL);
-       if (!info)
-               goto err_flash_remove;
-
-       dev_set_drvdata(&dev->dev, info);
-
-       mtd_list = kcalloc(count, sizeof(*mtd_list), GFP_KERNEL);
-       if (!mtd_list)
-               goto err_flash_remove;
-
-       for (i = 0; i < count; i++) {
-               err = -ENXIO;
-               if (of_address_to_resource(dp, i, &res)) {
-                       /*
-                        * Continue with next register tuple if this
-                        * one is not mappable
-                        */
-                       continue;
-               }
-
-               dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
-
-               err = -EBUSY;
-               res_size = resource_size(&res);
-               info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
-               if (IS_ERR(info->list[i].map.virt)) {
-                       err = PTR_ERR(info->list[i].map.virt);
-                       goto err_out;
-               }
-
-               err = -ENXIO;
-               width = of_get_property(dp, "bank-width", NULL);
-               if (!width) {
-                       dev_err(&dev->dev, "Can't get bank width from device"
-                               " tree\n");
-                       goto err_out;
-               }
-
-               info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
-               info->list[i].map.phys = res.start;
-               info->list[i].map.size = res_size;
-               info->list[i].map.bankwidth = be32_to_cpup(width);
-               info->list[i].map.device_node = dp;
-
-               if (of_property_read_bool(dp, "big-endian"))
-                       info->list[i].map.swap = CFI_BIG_ENDIAN;
-               else if (of_property_read_bool(dp, "little-endian"))
-                       info->list[i].map.swap = CFI_LITTLE_ENDIAN;
-
-               err = of_flash_probe_gemini(dev, dp, &info->list[i].map);
-               if (err)
-                       goto err_out;
-               err = of_flash_probe_versatile(dev, dp, &info->list[i].map);
-               if (err)
-                       goto err_out;
-
-               simple_map_init(&info->list[i].map);
-
-               /*
-                * On some platforms (e.g. MPC5200) a direct 1:1 mapping
-                * may cause problems with JFFS2 usage, as the local bus (LPB)
-                * doesn't support unaligned accesses as implemented in the
-                * JFFS2 code via memcpy(). By setting NO_XIP, the
-                * flash will not be exposed directly to the MTD users
-                * (e.g. JFFS2) any more.
-                */
-               if (map_indirect)
-                       info->list[i].map.phys = NO_XIP;
-
-               if (probe_type) {
-                       info->list[i].mtd = do_map_probe(probe_type,
-                                                        &info->list[i].map);
-               } else {
-                       info->list[i].mtd = obsolete_probe(dev,
-                                                          &info->list[i].map);
-               }
-
-               /* Fall back to mapping region as ROM */
-               if (!info->list[i].mtd) {
-                       dev_warn(&dev->dev,
-                               "do_map_probe() failed for type %s\n",
-                                probe_type);
-
-                       info->list[i].mtd = do_map_probe("map_rom",
-                                                        &info->list[i].map);
-               }
-               mtd_list[i] = info->list[i].mtd;
-
-               err = -ENXIO;
-               if (!info->list[i].mtd) {
-                       dev_err(&dev->dev, "do_map_probe() failed\n");
-                       goto err_out;
-               } else {
-                       info->list_size++;
-               }
-               info->list[i].mtd->dev.parent = &dev->dev;
-       }
-
-       err = 0;
-       info->cmtd = NULL;
-       if (info->list_size == 1) {
-               info->cmtd = info->list[0].mtd;
-       } else if (info->list_size > 1) {
-               /*
-                * We detected multiple devices. Concatenate them together.
-                */
-               info->cmtd = mtd_concat_create(mtd_list, info->list_size,
-                                              dev_name(&dev->dev));
-       }
-       if (info->cmtd == NULL)
-               err = -ENXIO;
-
-       if (err)
-               goto err_out;
-
-       info->cmtd->dev.parent = &dev->dev;
-       mtd_set_of_node(info->cmtd, dp);
-       part_probe_types = of_get_probes(dp);
-       if (!part_probe_types) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
-                       NULL, 0);
-       of_free_probes(part_probe_types);
-
-       kfree(mtd_list);
-
-       return 0;
-
-err_out:
-       kfree(mtd_list);
-err_flash_remove:
-       of_flash_remove(dev);
-
-       return err;
-}
-
-static const struct of_device_id of_flash_match[] = {
-       {
-               .compatible     = "cfi-flash",
-               .data           = (void *)"cfi_probe",
-       },
-       {
-               /* FIXME: JEDEC chips can't be safely and reliably
-                * probed, although the mtd code gets it right in
-                * practice most of the time.  We should use the
-                * vendor and device ids specified by the binding to
-                * bypass the heuristic probe code, but the mtd layer
-                * provides, at present, no interface for doing so
-                * :(. */
-               .compatible     = "jedec-flash",
-               .data           = (void *)"jedec_probe",
-       },
-       {
-               .compatible     = "mtd-ram",
-               .data           = (void *)"map_ram",
-       },
-       {
-               .compatible     = "mtd-rom",
-               .data           = (void *)"map_rom",
-       },
-       {
-               .type           = "rom",
-               .compatible     = "direct-mapped"
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, of_flash_match);
-
-static struct platform_driver of_flash_driver = {
-       .driver = {
-               .name = "of-flash",
-               .of_match_table = of_flash_match,
-       },
-       .probe          = of_flash_probe,
-       .remove         = of_flash_remove,
-};
-
-module_platform_driver(of_flash_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
-MODULE_DESCRIPTION("Device tree based MTD map driver");
diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c
deleted file mode 100644 (file)
index 9df62ca..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Cortina Systems Gemini OF physmap add-on
- * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
- *
- * This SoC has an elaborate flash control register, so we need to
- * detect and set it up when booting on this platform.
- */
-#include <linux/export.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/mtd/map.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/bitops.h>
-#include "physmap_of_gemini.h"
-
-/*
- * The Flash-relevant parts of the global status register
- * These would also be relevant for a NAND driver.
- */
-#define GLOBAL_STATUS                  0x04
-#define FLASH_TYPE_MASK                        (0x3 << 24)
-#define FLASH_TYPE_NAND_2K             (0x3 << 24)
-#define FLASH_TYPE_NAND_512            (0x2 << 24)
-#define FLASH_TYPE_PARALLEL            (0x1 << 24)
-#define FLASH_TYPE_SERIAL              (0x0 << 24)
-/* if parallel */
-#define FLASH_WIDTH_16BIT              (1 << 23)       /* else 8 bit */
-/* if serial */
-#define FLASH_ATMEL                    (1 << 23)       /* else STM */
-
-#define FLASH_SIZE_MASK                        (0x3 << 21)
-#define NAND_256M                      (0x3 << 21)     /* and more */
-#define NAND_128M                      (0x2 << 21)
-#define NAND_64M                       (0x1 << 21)
-#define NAND_32M                       (0x0 << 21)
-#define ATMEL_16M                      (0x3 << 21)     /* and more */
-#define ATMEL_8M                       (0x2 << 21)
-#define ATMEL_4M_2M                    (0x1 << 21)
-#define ATMEL_1M                       (0x0 << 21)     /* and less */
-#define STM_32M                                (1 << 22)       /* and more */
-#define STM_16M                                (0 << 22)       /* and less */
-
-#define FLASH_PARALLEL_HIGH_PIN_CNT    (1 << 20)       /* else low pin cnt */
-
-int of_flash_probe_gemini(struct platform_device *pdev,
-                         struct device_node *np,
-                         struct map_info *map)
-{
-       struct regmap *rmap;
-       struct device *dev = &pdev->dev;
-       u32 val;
-       int ret;
-
-       /* Multiplatform guard */
-       if (!of_device_is_compatible(np, "cortina,gemini-flash"))
-               return 0;
-
-       rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
-       if (IS_ERR(rmap)) {
-               dev_err(dev, "no syscon\n");
-               return PTR_ERR(rmap);
-       }
-
-       ret = regmap_read(rmap, GLOBAL_STATUS, &val);
-       if (ret) {
-               dev_err(dev, "failed to read global status register\n");
-               return -ENODEV;
-       }
-       dev_dbg(dev, "global status reg: %08x\n", val);
-
-       /*
-        * It would be contradictory if a physmap flash was NOT parallel.
-        */
-       if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {
-               dev_err(dev, "flash is not parallel\n");
-               return -ENODEV;
-       }
-
-       /*
-        * Complain if DT data and hardware definition is different.
-        */
-       if (val & FLASH_WIDTH_16BIT) {
-               if (map->bankwidth != 2)
-                       dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",
-                                map->bankwidth * 8);
-       } else {
-               if (map->bankwidth != 1)
-                       dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",
-                                map->bankwidth * 8);
-       }
-
-       dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n");
-
-       return 0;
-}
diff --git a/drivers/mtd/maps/physmap_of_gemini.h b/drivers/mtd/maps/physmap_of_gemini.h
deleted file mode 100644 (file)
index 60e13a6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/of.h>
-#include <linux/mtd/map.h>
-
-#ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI
-int of_flash_probe_gemini(struct platform_device *pdev,
-                         struct device_node *np,
-                         struct map_info *map);
-#else
-static inline
-int of_flash_probe_gemini(struct platform_device *pdev,
-                         struct device_node *np,
-                         struct map_info *map)
-{
-       return 0;
-}
-#endif
diff --git a/drivers/mtd/maps/physmap_of_versatile.c b/drivers/mtd/maps/physmap_of_versatile.c
deleted file mode 100644 (file)
index 03f2b6e..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Versatile OF physmap driver add-on
- *
- * Copyright (c) 2016, Linaro Limited
- * Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <linux/export.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/mtd/map.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/bitops.h>
-#include "physmap_of_versatile.h"
-
-static struct regmap *syscon_regmap;
-
-enum versatile_flashprot {
-       INTEGRATOR_AP_FLASHPROT,
-       INTEGRATOR_CP_FLASHPROT,
-       VERSATILE_FLASHPROT,
-       REALVIEW_FLASHPROT,
-};
-
-static const struct of_device_id syscon_match[] = {
-       {
-               .compatible = "arm,integrator-ap-syscon",
-               .data = (void *)INTEGRATOR_AP_FLASHPROT,
-       },
-       {
-               .compatible = "arm,integrator-cp-syscon",
-               .data = (void *)INTEGRATOR_CP_FLASHPROT,
-       },
-       {
-               .compatible = "arm,core-module-versatile",
-               .data = (void *)VERSATILE_FLASHPROT,
-       },
-       {
-               .compatible = "arm,realview-eb-syscon",
-               .data = (void *)REALVIEW_FLASHPROT,
-       },
-       {
-               .compatible = "arm,realview-pb1176-syscon",
-               .data = (void *)REALVIEW_FLASHPROT,
-       },
-       {
-               .compatible = "arm,realview-pb11mp-syscon",
-               .data = (void *)REALVIEW_FLASHPROT,
-       },
-       {
-               .compatible = "arm,realview-pba8-syscon",
-               .data = (void *)REALVIEW_FLASHPROT,
-       },
-       {
-               .compatible = "arm,realview-pbx-syscon",
-               .data = (void *)REALVIEW_FLASHPROT,
-       },
-       {},
-};
-
-/*
- * Flash protection handling for the Integrator/AP
- */
-#define INTEGRATOR_SC_CTRLS_OFFSET     0x08
-#define INTEGRATOR_SC_CTRLC_OFFSET     0x0C
-#define INTEGRATOR_SC_CTRL_FLVPPEN     BIT(1)
-#define INTEGRATOR_SC_CTRL_FLWP                BIT(2)
-
-#define INTEGRATOR_EBI_CSR1_OFFSET     0x04
-/* The manual says bit 2, the code says bit 3, trust the code */
-#define INTEGRATOR_EBI_WRITE_ENABLE    BIT(3)
-#define INTEGRATOR_EBI_LOCK_OFFSET     0x20
-#define INTEGRATOR_EBI_LOCK_VAL                0xA05F
-
-static const struct of_device_id ebi_match[] = {
-       { .compatible = "arm,external-bus-interface"},
-       { },
-};
-
-static int ap_flash_init(struct platform_device *pdev)
-{
-       struct device_node *ebi;
-       void __iomem *ebi_base;
-       u32 val;
-       int ret;
-
-       /* Look up the EBI */
-       ebi = of_find_matching_node(NULL, ebi_match);
-       if (!ebi) {
-               return -ENODEV;
-       }
-       ebi_base = of_iomap(ebi, 0);
-       if (!ebi_base)
-               return -ENODEV;
-
-       /* Clear VPP and write protection bits */
-       ret = regmap_write(syscon_regmap,
-               INTEGRATOR_SC_CTRLC_OFFSET,
-               INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
-       if (ret)
-               dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
-
-       /* Unlock the EBI */
-       writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
-
-       /* Enable write cycles on the EBI, CSR1 (flash) */
-       val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
-       val |= INTEGRATOR_EBI_WRITE_ENABLE;
-       writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
-
-       /* Lock the EBI again */
-       writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
-       iounmap(ebi_base);
-
-       return 0;
-}
-
-static void ap_flash_set_vpp(struct map_info *map, int on)
-{
-       int ret;
-
-       if (on) {
-               ret = regmap_write(syscon_regmap,
-                       INTEGRATOR_SC_CTRLS_OFFSET,
-                       INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
-               if (ret)
-                       pr_err("error enabling AP VPP\n");
-       } else {
-               ret = regmap_write(syscon_regmap,
-                       INTEGRATOR_SC_CTRLC_OFFSET,
-                       INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
-               if (ret)
-                       pr_err("error disabling AP VPP\n");
-       }
-}
-
-/*
- * Flash protection handling for the Integrator/CP
- */
-
-#define INTCP_FLASHPROG_OFFSET         0x04
-#define CINTEGRATOR_FLVPPEN            BIT(0)
-#define CINTEGRATOR_FLWREN             BIT(1)
-#define CINTEGRATOR_FLMASK             BIT(0)|BIT(1)
-
-static void cp_flash_set_vpp(struct map_info *map, int on)
-{
-       int ret;
-
-       if (on) {
-               ret = regmap_update_bits(syscon_regmap,
-                               INTCP_FLASHPROG_OFFSET,
-                               CINTEGRATOR_FLMASK,
-                               CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
-               if (ret)
-                       pr_err("error setting CP VPP\n");
-       } else {
-               ret = regmap_update_bits(syscon_regmap,
-                               INTCP_FLASHPROG_OFFSET,
-                               CINTEGRATOR_FLMASK,
-                               0);
-               if (ret)
-                       pr_err("error setting CP VPP\n");
-       }
-}
-
-/*
- * Flash protection handling for the Versatiles and RealViews
- */
-
-#define VERSATILE_SYS_FLASH_OFFSET            0x4C
-
-static void versatile_flash_set_vpp(struct map_info *map, int on)
-{
-       int ret;
-
-       ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
-                                0x01, !!on);
-       if (ret)
-               pr_err("error setting Versatile VPP\n");
-}
-
-int of_flash_probe_versatile(struct platform_device *pdev,
-                            struct device_node *np,
-                            struct map_info *map)
-{
-       struct device_node *sysnp;
-       const struct of_device_id *devid;
-       struct regmap *rmap;
-       static enum versatile_flashprot versatile_flashprot;
-       int ret;
-
-       /* Not all flash chips use this protection line */
-       if (!of_device_is_compatible(np, "arm,versatile-flash"))
-               return 0;
-
-       /* For first chip probed, look up the syscon regmap */
-       if (!syscon_regmap) {
-               sysnp = of_find_matching_node_and_match(NULL,
-                                                       syscon_match,
-                                                       &devid);
-               if (!sysnp)
-                       return -ENODEV;
-
-               versatile_flashprot = (enum versatile_flashprot)devid->data;
-               rmap = syscon_node_to_regmap(sysnp);
-               if (IS_ERR(rmap))
-                       return PTR_ERR(rmap);
-
-               syscon_regmap = rmap;
-       }
-
-       switch (versatile_flashprot) {
-       case INTEGRATOR_AP_FLASHPROT:
-               ret = ap_flash_init(pdev);
-               if (ret)
-                       return ret;
-               map->set_vpp = ap_flash_set_vpp;
-               dev_info(&pdev->dev, "Integrator/AP flash protection\n");
-               break;
-       case INTEGRATOR_CP_FLASHPROT:
-               map->set_vpp = cp_flash_set_vpp;
-               dev_info(&pdev->dev, "Integrator/CP flash protection\n");
-               break;
-       case VERSATILE_FLASHPROT:
-       case REALVIEW_FLASHPROT:
-               map->set_vpp = versatile_flash_set_vpp;
-               dev_info(&pdev->dev, "versatile/realview flash protection\n");
-               break;
-       default:
-               dev_info(&pdev->dev, "device marked as Versatile flash "
-                        "but no system controller was found\n");
-               break;
-       }
-
-       return 0;
-}
diff --git a/drivers/mtd/maps/physmap_of_versatile.h b/drivers/mtd/maps/physmap_of_versatile.h
deleted file mode 100644 (file)
index 0302502..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/of.h>
-#include <linux/mtd/map.h>
-
-#ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE
-int of_flash_probe_versatile(struct platform_device *pdev,
-                            struct device_node *np,
-                            struct map_info *map);
-#else
-static inline
-int of_flash_probe_versatile(struct platform_device *pdev,
-                            struct device_node *np,
-                            struct map_info *map)
-{
-       return 0;
-}
-#endif
index a5b1933c0490946d3c328f13074865af10718f19..b2d5ed1cbc94a670bff86f3e9a78d131002d8014 100644 (file)
@@ -56,7 +56,7 @@ struct mtdblk_dev {
  */
 
 static int erase_write (struct mtd_info *mtd, unsigned long pos,
-                       int len, const char *buf)
+                       unsigned int len, const char *buf)
 {
        struct erase_info erase;
        size_t retlen;
index 97ac219c082e7ef78993084ffcc8c9e98abaaac4..b6b93291aba9b13c89ceff0795403c8a6fd41126 100644 (file)
@@ -665,6 +665,8 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd)
        } else {
                pr_debug("mtd device won't show a device symlink in sysfs\n");
        }
+
+       mtd->orig_flags = mtd->flags;
 }
 
 /**
@@ -1136,13 +1138,13 @@ static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
                return -EINVAL;
 
        if (ops->ooblen) {
-               u64 maxooblen;
+               size_t maxooblen;
 
                if (ops->ooboffs >= mtd_oobavail(mtd, ops))
                        return -EINVAL;
 
-               maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
-                             mtd_div_by_ws(offs, mtd)) *
+               maxooblen = ((size_t)(mtd_div_by_ws(mtd->size, mtd) -
+                                     mtd_div_by_ws(offs, mtd)) *
                             mtd_oobavail(mtd, ops)) - ops->ooboffs;
                if (ops->ooblen > maxooblen)
                        return -EINVAL;
index 99c460facd5e97702896aae893d4df258320c0f2..b6af41b046223426fa86d98f66843da43cbc5d5b 100644 (file)
@@ -61,6 +61,15 @@ static inline struct mtd_part *mtd_to_part(const struct mtd_info *mtd)
        return container_of(mtd, struct mtd_part, mtd);
 }
 
+static u64 part_absolute_offset(struct mtd_info *mtd)
+{
+       struct mtd_part *part = mtd_to_part(mtd);
+
+       if (!mtd_is_partition(mtd))
+               return 0;
+
+       return part_absolute_offset(part->parent) + part->offset;
+}
 
 /*
  * MTD methods which simply translate the effective address and pass through
@@ -346,7 +355,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
 
        /* set up the MTD object for this partition */
        slave->mtd.type = parent->type;
-       slave->mtd.flags = parent->flags & ~part->mask_flags;
+       slave->mtd.flags = parent->orig_flags & ~part->mask_flags;
+       slave->mtd.orig_flags = slave->mtd.flags;
        slave->mtd.size = part->size;
        slave->mtd.writesize = parent->writesize;
        slave->mtd.writebufsize = parent->writebufsize;
@@ -513,7 +523,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
        if (!(slave->mtd.flags & MTD_NO_ERASE))
                wr_alignment = slave->mtd.erasesize;
 
-       tmp = slave->offset;
+       tmp = part_absolute_offset(parent) + slave->offset;
        remainder = do_div(tmp, wr_alignment);
        if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
                /* Doesn't start on a boundary of major erase size */
@@ -524,7 +534,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
                        part->name);
        }
 
-       tmp = slave->mtd.size;
+       tmp = part_absolute_offset(parent) + slave->mtd.size;
        remainder = do_div(tmp, wr_alignment);
        if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
                slave->mtd.flags &= ~MTD_WRITEABLE;
index d9dcb2d051b4b0393f7a1c0a68769dfc29c52dda..d162d1717fad4603d96f3e712163227461186384 100644 (file)
@@ -1265,18 +1265,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
 
        return 0;
 }
-
-static int mtdswap_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mtdswap_show, inode->i_private);
-}
-
-static const struct file_operations mtdswap_fops = {
-       .open           = mtdswap_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mtdswap);
 
 static int mtdswap_add_debugfs(struct mtdswap_dev *d)
 {
index c7efc31384d52726199a63869cc3dd1b547128e4..1a55d3e3d4c5d6f4aee59f92a5446105151caf69 100644 (file)
@@ -70,7 +70,7 @@ config MTD_NAND_GPIO
 
 config MTD_NAND_AMS_DELTA
        tristate "NAND Flash device on Amstrad E3"
-       depends on MACH_AMS_DELTA
+       depends on MACH_AMS_DELTA || COMPILE_TEST
        default y
        help
          Support for NAND flash on Amstrad E3 (Delta).
index 5ba180a291eb2986004b76af286e9582146e2d62..8312182088c1dee9cc4117e08a4e5219308349a6 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
  *
@@ -8,10 +9,6 @@
  *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
  *  Partially stolen from plat_nand.c
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  *  Overview:
  *   This is a device driver for the NAND flash device found on the
  *   Amstrad E3 (Delta).
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
-#include <linux/platform_data/gpio-omap.h>
-
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#include <mach/hardware.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
 
 /*
  * MTD structure for E3 (Delta)
  */
-
 struct ams_delta_nand {
+       struct nand_controller  base;
        struct nand_chip        nand_chip;
        struct gpio_desc        *gpiod_rdy;
        struct gpio_desc        *gpiod_nce;
@@ -44,7 +37,7 @@ struct ams_delta_nand {
        struct gpio_desc        *gpiod_nwe;
        struct gpio_desc        *gpiod_ale;
        struct gpio_desc        *gpiod_cle;
-       void __iomem            *io_base;
+       struct gpio_descs       *data_gpiods;
        bool                    data_in;
 };
 
@@ -73,99 +66,154 @@ static const struct mtd_partition partition_info[] = {
          .size         =  3 * SZ_256K },
 };
 
-static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)
+static void ams_delta_write_commit(struct ams_delta_nand *priv)
 {
-       writew(byte, priv->nand_chip.legacy.IO_ADDR_W);
        gpiod_set_value(priv->gpiod_nwe, 0);
        ndelay(40);
        gpiod_set_value(priv->gpiod_nwe, 1);
 }
 
-static u_char ams_delta_io_read(struct ams_delta_nand *priv)
+static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte)
+{
+       struct gpio_descs *data_gpiods = priv->data_gpiods;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };
+
+       gpiod_set_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,
+                                 data_gpiods->info, values);
+
+       ams_delta_write_commit(priv);
+}
+
+static void ams_delta_dir_output(struct ams_delta_nand *priv, u8 byte)
+{
+       struct gpio_descs *data_gpiods = priv->data_gpiods;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };
+       int i;
+
+       for (i = 0; i < data_gpiods->ndescs; i++)
+               gpiod_direction_output_raw(data_gpiods->desc[i],
+                                          test_bit(i, values));
+
+       ams_delta_write_commit(priv);
+
+       priv->data_in = false;
+}
+
+static u8 ams_delta_io_read(struct ams_delta_nand *priv)
 {
-       u_char res;
+       u8 res;
+       struct gpio_descs *data_gpiods = priv->data_gpiods;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(res)) = { 0, };
 
        gpiod_set_value(priv->gpiod_nre, 0);
        ndelay(40);
-       res = readw(priv->nand_chip.legacy.IO_ADDR_R);
+
+       gpiod_get_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,
+                                 data_gpiods->info, values);
+
        gpiod_set_value(priv->gpiod_nre, 1);
 
+       res = values[0];
        return res;
 }
 
-static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
+static void ams_delta_dir_input(struct ams_delta_nand *priv)
 {
-       writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
-       priv->data_in = in;
+       struct gpio_descs *data_gpiods = priv->data_gpiods;
+       int i;
+
+       for (i = 0; i < data_gpiods->ndescs; i++)
+               gpiod_direction_input(data_gpiods->desc[i]);
+
+       priv->data_in = true;
 }
 
-static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,
+static void ams_delta_write_buf(struct ams_delta_nand *priv, const u8 *buf,
                                int len)
 {
-       struct ams_delta_nand *priv = nand_get_controller_data(this);
-       int i;
+       int i = 0;
 
-       if (priv->data_in)
-               ams_delta_dir_input(priv, false);
+       if (len > 0 && priv->data_in)
+               ams_delta_dir_output(priv, buf[i++]);
 
-       for (i = 0; i < len; i++)
-               ams_delta_io_write(priv, buf[i]);
+       while (i < len)
+               ams_delta_io_write(priv, buf[i++]);
 }
 
-static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)
+static void ams_delta_read_buf(struct ams_delta_nand *priv, u8 *buf, int len)
 {
-       struct ams_delta_nand *priv = nand_get_controller_data(this);
        int i;
 
        if (!priv->data_in)
-               ams_delta_dir_input(priv, true);
+               ams_delta_dir_input(priv);
 
        for (i = 0; i < len; i++)
                buf[i] = ams_delta_io_read(priv);
 }
 
-static u_char ams_delta_read_byte(struct nand_chip *this)
+static void ams_delta_ctrl_cs(struct ams_delta_nand *priv, bool assert)
 {
-       u_char res;
-
-       ams_delta_read_buf(this, &res, 1);
-
-       return res;
+       gpiod_set_value(priv->gpiod_nce, assert ? 0 : 1);
 }
 
-/*
- * Command control function
- *
- * ctrl:
- * NAND_NCE: bit 0 -> bit 2
- * NAND_CLE: bit 1 -> bit 7
- * NAND_ALE: bit 2 -> bit 6
- */
-static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,
-                               unsigned int ctrl)
+static int ams_delta_exec_op(struct nand_chip *this,
+                            const struct nand_operation *op, bool check_only)
 {
        struct ams_delta_nand *priv = nand_get_controller_data(this);
-
-       if (ctrl & NAND_CTRL_CHANGE) {
-               gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE));
-               gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE));
-               gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));
+       const struct nand_op_instr *instr;
+       int ret = 0;
+
+       if (check_only)
+               return 0;
+
+       ams_delta_ctrl_cs(priv, 1);
+
+       for (instr = op->instrs; instr < op->instrs + op->ninstrs; instr++) {
+               switch (instr->type) {
+               case NAND_OP_CMD_INSTR:
+                       gpiod_set_value(priv->gpiod_cle, 1);
+                       ams_delta_write_buf(priv, &instr->ctx.cmd.opcode, 1);
+                       gpiod_set_value(priv->gpiod_cle, 0);
+                       break;
+
+               case NAND_OP_ADDR_INSTR:
+                       gpiod_set_value(priv->gpiod_ale, 1);
+                       ams_delta_write_buf(priv, instr->ctx.addr.addrs,
+                                           instr->ctx.addr.naddrs);
+                       gpiod_set_value(priv->gpiod_ale, 0);
+                       break;
+
+               case NAND_OP_DATA_IN_INSTR:
+                       ams_delta_read_buf(priv, instr->ctx.data.buf.in,
+                                          instr->ctx.data.len);
+                       break;
+
+               case NAND_OP_DATA_OUT_INSTR:
+                       ams_delta_write_buf(priv, instr->ctx.data.buf.out,
+                                           instr->ctx.data.len);
+                       break;
+
+               case NAND_OP_WAITRDY_INSTR:
+                       ret = priv->gpiod_rdy ?
+                             nand_gpio_waitrdy(this, priv->gpiod_rdy,
+                                               instr->ctx.waitrdy.timeout_ms) :
+                             nand_soft_waitrdy(this,
+                                               instr->ctx.waitrdy.timeout_ms);
+                       break;
+               }
+
+               if (ret)
+                       break;
        }
 
-       if (cmd != NAND_CMD_NONE) {
-               u_char byte = cmd;
+       ams_delta_ctrl_cs(priv, 0);
 
-               ams_delta_write_buf(this, &byte, 1);
-       }
-}
-
-static int ams_delta_nand_ready(struct nand_chip *this)
-{
-       struct ams_delta_nand *priv = nand_get_controller_data(this);
-
-       return gpiod_get_value(priv->gpiod_rdy);
+       return ret;
 }
 
+static const struct nand_controller_ops ams_delta_ops = {
+       .exec_op = ams_delta_exec_op,
+};
 
 /*
  * Main initialization routine
@@ -175,61 +223,29 @@ static int ams_delta_init(struct platform_device *pdev)
        struct ams_delta_nand *priv;
        struct nand_chip *this;
        struct mtd_info *mtd;
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       void __iomem *io_base;
+       struct gpio_descs *data_gpiods;
        int err = 0;
 
-       if (!res)
-               return -ENXIO;
-
        /* Allocate memory for MTD device structure and private data */
        priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
                            GFP_KERNEL);
-       if (!priv) {
-               pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
+       if (!priv)
                return -ENOMEM;
-       }
+
        this = &priv->nand_chip;
 
        mtd = nand_to_mtd(this);
        mtd->dev.parent = &pdev->dev;
 
-       /*
-        * Don't try to request the memory region from here,
-        * it should have been already requested from the
-        * gpio-omap driver and requesting it again would fail.
-        */
-
-       io_base = ioremap(res->start, resource_size(res));
-       if (io_base == NULL) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               err = -EIO;
-               goto out_free;
-       }
-
-       priv->io_base = io_base;
        nand_set_controller_data(this, priv);
 
-       /* Set address of NAND IO lines */
-       this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
-       this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
-       this->legacy.read_byte = ams_delta_read_byte;
-       this->legacy.write_buf = ams_delta_write_buf;
-       this->legacy.read_buf = ams_delta_read_buf;
-       this->legacy.cmd_ctrl = ams_delta_hwcontrol;
-
        priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
        if (IS_ERR(priv->gpiod_rdy)) {
                err = PTR_ERR(priv->gpiod_rdy);
                dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
-       if (priv->gpiod_rdy)
-               this->legacy.dev_ready = ams_delta_nand_ready;
-
-       /* 25 us command delay time */
-       this->legacy.chip_delay = 30;
        this->ecc.mode = NAND_ECC_SOFT;
        this->ecc.algo = NAND_ECC_HAMMING;
 
@@ -240,61 +256,75 @@ static int ams_delta_init(struct platform_device *pdev)
        if (IS_ERR(priv->gpiod_nwp)) {
                err = PTR_ERR(priv->gpiod_nwp);
                dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
        priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH);
        if (IS_ERR(priv->gpiod_nce)) {
                err = PTR_ERR(priv->gpiod_nce);
                dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
        priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH);
        if (IS_ERR(priv->gpiod_nre)) {
                err = PTR_ERR(priv->gpiod_nre);
                dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
        priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH);
        if (IS_ERR(priv->gpiod_nwe)) {
                err = PTR_ERR(priv->gpiod_nwe);
                dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
        priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);
        if (IS_ERR(priv->gpiod_ale)) {
                err = PTR_ERR(priv->gpiod_ale);
                dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
        priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);
        if (IS_ERR(priv->gpiod_cle)) {
                err = PTR_ERR(priv->gpiod_cle);
                dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);
-               goto out_mtd;
+               return err;
        }
 
-       /* Initialize data port direction to a known state */
-       ams_delta_dir_input(priv, true);
+       /* Request array of data pins, initialize them as input */
+       data_gpiods = devm_gpiod_get_array(&pdev->dev, "data", GPIOD_IN);
+       if (IS_ERR(data_gpiods)) {
+               err = PTR_ERR(data_gpiods);
+               dev_err(&pdev->dev, "data GPIO request failed: %d\n", err);
+               return err;
+       }
+       priv->data_gpiods = data_gpiods;
+       priv->data_in = true;
+
+       /* Initialize the NAND controller object embedded in ams_delta_nand. */
+       priv->base.ops = &ams_delta_ops;
+       nand_controller_init(&priv->base);
+       this->controller = &priv->base;
 
        /* Scan to find existence of the device */
        err = nand_scan(this, 1);
        if (err)
-               goto out_mtd;
+               return err;
 
        /* Register the partitions */
-       mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));
+       err = mtd_device_register(mtd, partition_info,
+                                 ARRAY_SIZE(partition_info));
+       if (err)
+               goto err_nand_cleanup;
 
-       goto out;
+       return 0;
+
+err_nand_cleanup:
+       nand_cleanup(this);
 
- out_mtd:
-       iounmap(io_base);
-out_free:
- out:
        return err;
 }
 
@@ -305,13 +335,10 @@ static int ams_delta_cleanup(struct platform_device *pdev)
 {
        struct ams_delta_nand *priv = platform_get_drvdata(pdev);
        struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
-       void __iomem *io_base = priv->io_base;
 
-       /* Release resources, unregister device */
+       /* Unregister device */
        nand_release(mtd_to_nand(mtd));
 
-       iounmap(io_base);
-
        return 0;
 }
 
@@ -325,6 +352,6 @@ static struct platform_driver ams_delta_nand_driver = {
 
 module_platform_driver(ams_delta_nand_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
 MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
index ad720494e8f78dfd74995ba067a8ea973f555980..5781fcf6b76c604906e55b792ccf9f9693c6016e 100644 (file)
@@ -1477,10 +1477,10 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
        chip->legacy.write_byte = atmel_nand_write_byte;
        chip->legacy.read_buf = atmel_nand_read_buf;
        chip->legacy.write_buf = atmel_nand_write_buf;
-       chip->select_chip = atmel_nand_select_chip;
+       chip->legacy.select_chip = atmel_nand_select_chip;
 
-       if (nc->mck && nc->caps->ops->setup_data_interface)
-               chip->setup_data_interface = atmel_nand_setup_data_interface;
+       if (!nc->mck || !nc->caps->ops->setup_data_interface)
+               chip->options |= NAND_KEEP_TIMINGS;
 
        /* Some NANDs require a longer delay than the default one (20us). */
        chip->legacy.chip_delay = 40;
@@ -1525,7 +1525,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
 
        /* Overload some methods for the HSMC controller. */
        chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
-       chip->select_chip = atmel_hsmc_nand_select_chip;
+       chip->legacy.select_chip = atmel_hsmc_nand_select_chip;
 }
 
 static int atmel_nand_controller_remove_nand(struct atmel_nand *nand)
@@ -1908,6 +1908,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops atmel_nand_controller_ops = {
        .attach_chip = atmel_nand_attach_chip,
+       .setup_data_interface = atmel_nand_setup_data_interface,
 };
 
 static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
index 9731c1c487f6e723d54d8cad1af98e043c68291d..a963002663ed1d186dc8dae567d779e0d8b631df 100644 (file)
@@ -430,7 +430,7 @@ static int au1550nd_probe(struct platform_device *pdev)
        ctx->cs = cs;
 
        this->legacy.dev_ready = au1550_device_ready;
-       this->select_chip = au1550_select_chip;
+       this->legacy.select_chip = au1550_select_chip;
        this->legacy.cmdfunc = au1550_command;
 
        /* 30 us command delay time */
index 9095a79ebc7db4f3d3273958cff7551ea99ba10f..a37cbfe565677cf2d4bf6fe6e7ac5f2976dbb25e 100644 (file)
@@ -383,7 +383,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
        u8 tbits, col_bits, col_size, row_bits, row_bsize;
        u32 val;
 
-       b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
+       nand_chip->legacy.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
        nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
        nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
        b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
index c1a745940d12936123433878b5c63b4a81c39002..b1c0cd6b49da6344b16b8c97084ef060c162b858 100644 (file)
@@ -708,7 +708,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe->nand.legacy.read_byte = cafe_read_byte;
        cafe->nand.legacy.read_buf = cafe_read_buf;
        cafe->nand.legacy.write_buf = cafe_write_buf;
-       cafe->nand.select_chip = cafe_select_chip;
+       cafe->nand.legacy.select_chip = cafe_select_chip;
        cafe->nand.legacy.set_features = nand_get_set_features_notsupp;
        cafe->nand.legacy.get_features = nand_get_set_features_notsupp;
 
@@ -780,7 +780,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe->usedma = 0;
 
        /* Scan to find existence of the device */
-       cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
+       cafe->nand.legacy.dummy_controller.ops = &cafe_nand_controller_ops;
        err = nand_scan(&cafe->nand, 2);
        if (err)
                goto out_irq;
index 80f228d23cd26da3c118e595edd4e5406ef0610f..27bafa5e1ca178672c7692ece9121d5ffce72f49 100644 (file)
@@ -762,7 +762,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
        info->chip.legacy.IO_ADDR_R     = vaddr;
        info->chip.legacy.IO_ADDR_W     = vaddr;
        info->chip.legacy.chip_delay    = 0;
-       info->chip.select_chip  = nand_davinci_select_chip;
+       info->chip.legacy.select_chip   = nand_davinci_select_chip;
 
        /* options such as NAND_BBT_USE_FLASH */
        info->chip.bbt_options  = pdata->bbt_options;
@@ -801,7 +801,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
        spin_unlock_irq(&davinci_nand_lock);
 
        /* Scan to find existence of the device(s) */
-       info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
+       info->chip.legacy.dummy_controller.ops = &davinci_nand_controller_ops;
        ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
index 830ea247277b1cac529e4814834eb20c05212e7f..eebac35304c6f2be99b7f551e5be2dc9b8789480 100644 (file)
@@ -204,18 +204,6 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
        return denali->irq_status;
 }
 
-static uint32_t denali_check_irq(struct denali_nand_info *denali)
-{
-       unsigned long flags;
-       uint32_t irq_status;
-
-       spin_lock_irqsave(&denali->irq_lock, flags);
-       irq_status = denali->irq_status;
-       spin_unlock_irqrestore(&denali->irq_lock, flags);
-
-       return irq_status;
-}
-
 static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
@@ -288,8 +276,7 @@ static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
                return;
 
        /*
-        * Some commands are followed by chip->legacy.dev_ready or
-        * chip->legacy.waitfunc.
+        * Some commands are followed by chip->legacy.waitfunc.
         * irq_status must be cleared here to catch the R/B# interrupt later.
         */
        if (ctrl & NAND_CTRL_CHANGE)
@@ -298,13 +285,6 @@ static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
        denali->host_write(denali, DENALI_BANK(denali) | type, dat);
 }
 
-static int denali_dev_ready(struct nand_chip *chip)
-{
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-
-       return !!(denali_check_irq(denali) & INTR__INT_ACT);
-}
-
 static int denali_check_erased_page(struct mtd_info *mtd,
                                    struct nand_chip *chip, uint8_t *buf,
                                    unsigned long uncor_ecc_flags,
@@ -1065,29 +1045,6 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        return 0;
 }
 
-static void denali_reset_banks(struct denali_nand_info *denali)
-{
-       u32 irq_status;
-       int i;
-
-       for (i = 0; i < denali->max_banks; i++) {
-               denali->active_bank = i;
-
-               denali_reset_irq(denali);
-
-               iowrite32(DEVICE_RESET__BANK(i),
-                         denali->reg + DEVICE_RESET);
-
-               irq_status = denali_wait_for_irq(denali,
-                       INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
-               if (!(irq_status & INTR__INT_ACT))
-                       break;
-       }
-
-       dev_dbg(denali->dev, "%d chips connected\n", i);
-       denali->max_banks = i;
-}
-
 static void denali_hw_init(struct denali_nand_info *denali)
 {
        /*
@@ -1316,6 +1273,7 @@ static void denali_detach_chip(struct nand_chip *chip)
 static const struct nand_controller_ops denali_controller_ops = {
        .attach_chip = denali_attach_chip,
        .detach_chip = denali_detach_chip,
+       .setup_data_interface = denali_setup_data_interface,
 };
 
 int denali_init(struct denali_nand_info *denali)
@@ -1341,12 +1299,6 @@ int denali_init(struct denali_nand_info *denali)
        }
 
        denali_enable_irq(denali);
-       denali_reset_banks(denali);
-       if (!denali->max_banks) {
-               /* Error out earlier if no chip is found for some reasons. */
-               ret = -ENODEV;
-               goto disable_irq;
-       }
 
        denali->active_bank = DENALI_INVALID_BANK;
 
@@ -1355,11 +1307,10 @@ int denali_init(struct denali_nand_info *denali)
        if (!mtd->name)
                mtd->name = "denali-nand";
 
-       chip->select_chip = denali_select_chip;
+       chip->legacy.select_chip = denali_select_chip;
        chip->legacy.read_byte = denali_read_byte;
        chip->legacy.write_byte = denali_write_byte;
        chip->legacy.cmd_ctrl = denali_cmd_ctrl;
-       chip->legacy.dev_ready = denali_dev_ready;
        chip->legacy.waitfunc = denali_waitfunc;
 
        if (features & FEATURES__INDEX_ADDR) {
@@ -1372,9 +1323,9 @@ int denali_init(struct denali_nand_info *denali)
 
        /* clk rate info is needed for setup_data_interface */
        if (denali->clk_rate && denali->clk_x_rate)
-               chip->setup_data_interface = denali_setup_data_interface;
+               chip->options |= NAND_KEEP_TIMINGS;
 
-       chip->dummy_controller.ops = &denali_controller_ops;
+       chip->legacy.dummy_controller.ops = &denali_controller_ops;
        ret = nand_scan(chip, denali->max_banks);
        if (ret)
                goto disable_irq;
index 57a5498f58bbb493dc8379c0341e45ea33e6a2ac..25c00601b8b34fdc0c9d45689781384979100da2 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef __DENALI_H__
 #define __DENALI_H__
 
-#include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/completion.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/spinlock_types.h>
index 3a4c373affab3048866b40cda681c2a1335c3029..53f57e0f007e25654c773b73b1c0f56b35699b14 100644 (file)
@@ -1390,7 +1390,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
        this->legacy.read_buf = doc2001plus_readbuf;
        doc->late_init = inftl_scan_bbt;
        this->legacy.cmd_ctrl = NULL;
-       this->select_chip = doc2001plus_select_chip;
+       this->legacy.select_chip = doc2001plus_select_chip;
        this->legacy.cmdfunc = doc2001plus_command;
        this->ecc.hwctl = doc2001plus_enable_hwecc;
 
@@ -1568,7 +1568,7 @@ static int __init doc_probe(unsigned long physadr)
        mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
 
        nand_set_controller_data(nand, doc);
-       nand->select_chip       = doc200x_select_chip;
+       nand->legacy.select_chip        = doc200x_select_chip;
        nand->legacy.cmd_ctrl           = doc200x_hwcontrol;
        nand->legacy.dev_ready  = doc200x_dev_ready;
        nand->legacy.waitfunc   = doc200x_wait;
index d6ed697fcfe6e6e4ddd8b4ddc97fca7000918502..70f0d2b450ea1fd21a16cec5c19b1ac61e553d02 100644 (file)
@@ -779,7 +779,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
        chip->legacy.read_byte = fsl_elbc_read_byte;
        chip->legacy.write_buf = fsl_elbc_write_buf;
        chip->legacy.read_buf = fsl_elbc_read_buf;
-       chip->select_chip = fsl_elbc_select_chip;
+       chip->legacy.select_chip = fsl_elbc_select_chip;
        chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
        chip->legacy.waitfunc = fsl_elbc_wait;
        chip->legacy.set_features = nand_get_set_features_notsupp;
index 6f4afc44381a3e05affc9bfbe14d2069e876a398..e65d274399f91d213e5141c55291a1fbd094bc2e 100644 (file)
@@ -864,7 +864,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        chip->legacy.write_buf = fsl_ifc_write_buf;
        chip->legacy.read_buf = fsl_ifc_read_buf;
-       chip->select_chip = fsl_ifc_select_chip;
+       chip->legacy.select_chip = fsl_ifc_select_chip;
        chip->legacy.cmdfunc = fsl_ifc_cmdfunc;
        chip->legacy.waitfunc = fsl_ifc_wait;
        chip->legacy.set_features = nand_get_set_features_notsupp;
index 673c5a0c9345691160bb76a2415f2a8791d44ec9..5ccc28ec0985651cea6d12e5b94eab69966358f9 100644 (file)
@@ -170,7 +170,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
        fun->chip.ecc.mode = NAND_ECC_SOFT;
        fun->chip.ecc.algo = NAND_ECC_HAMMING;
        if (fun->mchip_count > 1)
-               fun->chip.select_chip = fun_select_chip;
+               fun->chip.legacy.select_chip = fun_select_chip;
 
        if (fun->rnb_gpio[0] >= 0)
                fun->chip.legacy.dev_ready = fun_chip_ready;
index 70ac8d875218e5010a30ad020f944586eee8241c..325b4414dcccdaae2064dfe4416a6e5b39fb812e 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * ST Microelectronics
  * Flexible Static Memory Controller (FSMC)
  * Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8)
  *  Copyright © 2007 STMicroelectronics Pvt. Ltd.
  *  Copyright © 2009 Alessandro Rubini
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/clk.h>
 /* fsmc controller registers for NOR flash */
 #define CTRL                   0x0
        /* ctrl register definitions */
-       #define BANK_ENABLE             (1 << 0)
-       #define MUXED                   (1 << 1)
+       #define BANK_ENABLE             BIT(0)
+       #define MUXED                   BIT(1)
        #define NOR_DEV                 (2 << 2)
-       #define WIDTH_8                 (0 << 4)
-       #define WIDTH_16                (1 << 4)
-       #define RSTPWRDWN               (1 << 6)
-       #define WPROT                   (1 << 7)
-       #define WRT_ENABLE              (1 << 12)
-       #define WAIT_ENB                (1 << 13)
+       #define WIDTH_16                BIT(4)
+       #define RSTPWRDWN               BIT(6)
+       #define WPROT                   BIT(7)
+       #define WRT_ENABLE              BIT(12)
+       #define WAIT_ENB                BIT(13)
 
 #define CTRL_TIM               0x4
        /* ctrl_tim register definitions */
 #define FSMC_NOR_BANK_SZ       0x8
 #define FSMC_NOR_REG_SIZE      0x40
 
-#define FSMC_NOR_REG(base, bank, reg)          (base + \
-                                               FSMC_NOR_BANK_SZ * (bank) + \
-                                               reg)
+#define FSMC_NOR_REG(base, bank, reg)  ((base) +                       \
+                                        (FSMC_NOR_BANK_SZ * (bank)) +  \
+                                        (reg))
 
 /* fsmc controller registers for NAND flash */
 #define FSMC_PC                        0x00
        /* pc register definitions */
-       #define FSMC_RESET              (1 << 0)
-       #define FSMC_WAITON             (1 << 1)
-       #define FSMC_ENABLE             (1 << 2)
-       #define FSMC_DEVTYPE_NAND       (1 << 3)
-       #define FSMC_DEVWID_8           (0 << 4)
-       #define FSMC_DEVWID_16          (1 << 4)
-       #define FSMC_ECCEN              (1 << 6)
-       #define FSMC_ECCPLEN_512        (0 << 7)
-       #define FSMC_ECCPLEN_256        (1 << 7)
-       #define FSMC_TCLR_1             (1)
+       #define FSMC_RESET              BIT(0)
+       #define FSMC_WAITON             BIT(1)
+       #define FSMC_ENABLE             BIT(2)
+       #define FSMC_DEVTYPE_NAND       BIT(3)
+       #define FSMC_DEVWID_16          BIT(4)
+       #define FSMC_ECCEN              BIT(6)
+       #define FSMC_ECCPLEN_256        BIT(7)
        #define FSMC_TCLR_SHIFT         (9)
        #define FSMC_TCLR_MASK          (0xF)
-       #define FSMC_TAR_1              (1)
        #define FSMC_TAR_SHIFT          (13)
        #define FSMC_TAR_MASK           (0xF)
 #define STS                    0x04
        /* sts register definitions */
-       #define FSMC_CODE_RDY           (1 << 15)
+       #define FSMC_CODE_RDY           BIT(15)
 #define COMM                   0x08
        /* comm register definitions */
-       #define FSMC_TSET_0             0
        #define FSMC_TSET_SHIFT         0
        #define FSMC_TSET_MASK          0xFF
-       #define FSMC_TWAIT_6            6
        #define FSMC_TWAIT_SHIFT        8
        #define FSMC_TWAIT_MASK         0xFF
-       #define FSMC_THOLD_4            4
        #define FSMC_THOLD_SHIFT        16
        #define FSMC_THOLD_MASK         0xFF
-       #define FSMC_THIZ_1             1
        #define FSMC_THIZ_SHIFT         24
        #define FSMC_THIZ_MASK          0xFF
 #define ATTRIB                 0x0C
 #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
 
 struct fsmc_nand_timings {
-       uint8_t tclr;
-       uint8_t tar;
-       uint8_t thiz;
-       uint8_t thold;
-       uint8_t twait;
-       uint8_t tset;
+       u8 tclr;
+       u8 tar;
+       u8 thiz;
+       u8 thold;
+       u8 twait;
+       u8 tset;
 };
 
 enum access_mode {
@@ -122,19 +110,21 @@ enum access_mode {
 /**
  * struct fsmc_nand_data - structure for FSMC NAND device state
  *
+ * @base:              Inherit from the nand_controller struct
  * @pid:               Part ID on the AMBA PrimeCell format
- * @mtd:               MTD info for a NAND flash.
  * @nand:              Chip related info for a NAND flash.
- * @partitions:                Partition info for a NAND Flash.
- * @nr_partitions:     Total number of partition of a NAND flash.
  *
  * @bank:              Bank number for probed device.
+ * @dev:               Parent device
+ * @mode:              Access mode
  * @clk:               Clock structure for FSMC.
  *
  * @read_dma_chan:     DMA channel for read access
  * @write_dma_chan:    DMA channel for write access to NAND
  * @dma_access_complete: Completion structure
  *
+ * @dev_timings:       NAND timings
+ *
  * @data_pa:           NAND Physical port for Data.
  * @data_va:           NAND port for Data.
  * @cmd_va:            NAND port for Command.
@@ -142,6 +132,7 @@ enum access_mode {
  * @regs_va:           Registers base address for a given bank.
  */
 struct fsmc_nand_data {
+       struct nand_controller  base;
        u32                     pid;
        struct nand_chip        nand;
 
@@ -248,9 +239,9 @@ static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
        .free = fsmc_ecc4_ooblayout_free,
 };
 
-static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
+static inline struct fsmc_nand_data *nand_to_fsmc(struct nand_chip *chip)
 {
-       return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
+       return container_of(chip, struct fsmc_nand_data, nand);
 }
 
 /*
@@ -262,8 +253,8 @@ static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
 static void fsmc_nand_setup(struct fsmc_nand_data *host,
                            struct fsmc_nand_timings *tims)
 {
-       uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
-       uint32_t tclr, tar, thiz, thold, twait, tset;
+       u32 value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
+       u32 tclr, tar, thiz, thold, twait, tset;
 
        tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
        tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
@@ -273,13 +264,9 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
        tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
        if (host->nand.options & NAND_BUSWIDTH_16)
-               writel_relaxed(value | FSMC_DEVWID_16,
-                              host->regs_va + FSMC_PC);
-       else
-               writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + FSMC_PC);
+               value |= FSMC_DEVWID_16;
 
-       writel_relaxed(readl(host->regs_va + FSMC_PC) | tclr | tar,
-                      host->regs_va + FSMC_PC);
+       writel_relaxed(value | tclr | tar, host->regs_va + FSMC_PC);
        writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
        writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
 }
@@ -290,7 +277,7 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
 {
        unsigned long hclk = clk_get_rate(host->clk);
        unsigned long hclkn = NSEC_PER_SEC / hclk;
-       uint32_t thiz, thold, twait, tset;
+       u32 thiz, thold, twait, tset;
 
        if (sdrt->tRC_min < 30000)
                return -EOPNOTSUPP;
@@ -343,7 +330,7 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
 static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
                                     const struct nand_data_interface *conf)
 {
-       struct fsmc_nand_data *host = nand_get_controller_data(nand);
+       struct fsmc_nand_data *host = nand_to_fsmc(nand);
        struct fsmc_nand_timings tims;
        const struct nand_sdr_timings *sdrt;
        int ret;
@@ -369,7 +356,7 @@ static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
  */
 static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
+       struct fsmc_nand_data *host = nand_to_fsmc(chip);
 
        writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
                       host->regs_va + FSMC_PC);
@@ -384,18 +371,18 @@ static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
  * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
  * max of 8-bits)
  */
-static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
-                               uint8_t *ecc)
+static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const u8 *data,
+                               u8 *ecc)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
-       uint32_t ecc_tmp;
+       struct fsmc_nand_data *host = nand_to_fsmc(chip);
+       u32 ecc_tmp;
        unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
 
        do {
                if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY)
                        break;
-               else
-                       cond_resched();
+
+               cond_resched();
        } while (!time_after_eq(jiffies, deadline));
 
        if (time_after_eq(jiffies, deadline)) {
@@ -404,25 +391,25 @@ static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
        }
 
        ecc_tmp = readl_relaxed(host->regs_va + ECC1);
-       ecc[0] = (uint8_t) (ecc_tmp >> 0);
-       ecc[1] = (uint8_t) (ecc_tmp >> 8);
-       ecc[2] = (uint8_t) (ecc_tmp >> 16);
-       ecc[3] = (uint8_t) (ecc_tmp >> 24);
+       ecc[0] = ecc_tmp;
+       ecc[1] = ecc_tmp >> 8;
+       ecc[2] = ecc_tmp >> 16;
+       ecc[3] = ecc_tmp >> 24;
 
        ecc_tmp = readl_relaxed(host->regs_va + ECC2);
-       ecc[4] = (uint8_t) (ecc_tmp >> 0);
-       ecc[5] = (uint8_t) (ecc_tmp >> 8);
-       ecc[6] = (uint8_t) (ecc_tmp >> 16);
-       ecc[7] = (uint8_t) (ecc_tmp >> 24);
+       ecc[4] = ecc_tmp;
+       ecc[5] = ecc_tmp >> 8;
+       ecc[6] = ecc_tmp >> 16;
+       ecc[7] = ecc_tmp >> 24;
 
        ecc_tmp = readl_relaxed(host->regs_va + ECC3);
-       ecc[8] = (uint8_t) (ecc_tmp >> 0);
-       ecc[9] = (uint8_t) (ecc_tmp >> 8);
-       ecc[10] = (uint8_t) (ecc_tmp >> 16);
-       ecc[11] = (uint8_t) (ecc_tmp >> 24);
+       ecc[8] = ecc_tmp;
+       ecc[9] = ecc_tmp >> 8;
+       ecc[10] = ecc_tmp >> 16;
+       ecc[11] = ecc_tmp >> 24;
 
        ecc_tmp = readl_relaxed(host->regs_va + STS);
-       ecc[12] = (uint8_t) (ecc_tmp >> 16);
+       ecc[12] = ecc_tmp >> 16;
 
        return 0;
 }
@@ -432,22 +419,22 @@ static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
  * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
  * max of 1-bit)
  */
-static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data,
-                               uint8_t *ecc)
+static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const u8 *data,
+                               u8 *ecc)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
-       uint32_t ecc_tmp;
+       struct fsmc_nand_data *host = nand_to_fsmc(chip);
+       u32 ecc_tmp;
 
        ecc_tmp = readl_relaxed(host->regs_va + ECC1);
-       ecc[0] = (uint8_t) (ecc_tmp >> 0);
-       ecc[1] = (uint8_t) (ecc_tmp >> 8);
-       ecc[2] = (uint8_t) (ecc_tmp >> 16);
+       ecc[0] = ecc_tmp;
+       ecc[1] = ecc_tmp >> 8;
+       ecc[2] = ecc_tmp >> 16;
 
        return 0;
 }
 
 /* Count the number of 0's in buff upto a max of max_bits */
-static int count_written_bits(uint8_t *buff, int size, int max_bits)
+static int count_written_bits(u8 *buff, int size, int max_bits)
 {
        int k, written_bits = 0;
 
@@ -468,7 +455,7 @@ static void dma_complete(void *param)
 }
 
 static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
-               enum dma_data_direction direction)
+                   enum dma_data_direction direction)
 {
        struct dma_chan *chan;
        struct dma_device *dma_dev;
@@ -519,7 +506,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
 
        time_left =
        wait_for_completion_timeout(&host->dma_access_complete,
-                               msecs_to_jiffies(3000));
+                                   msecs_to_jiffies(3000));
        if (time_left == 0) {
                dmaengine_terminate_all(chan);
                dev_err(host->dev, "wait_for_completion_timeout\n");
@@ -537,18 +524,19 @@ unmap_dma:
 
 /*
  * fsmc_write_buf - write buffer to chip
- * @mtd:       MTD device structure
+ * @host:      FSMC NAND controller
  * @buf:       data buffer
  * @len:       number of bytes to write
  */
-static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void fsmc_write_buf(struct fsmc_nand_data *host, const u8 *buf,
+                          int len)
 {
-       struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
        int i;
 
-       if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
-                       IS_ALIGNED(len, sizeof(uint32_t))) {
-               uint32_t *p = (uint32_t *)buf;
+       if (IS_ALIGNED((uintptr_t)buf, sizeof(u32)) &&
+           IS_ALIGNED(len, sizeof(u32))) {
+               u32 *p = (u32 *)buf;
+
                len = len >> 2;
                for (i = 0; i < len; i++)
                        writel_relaxed(p[i], host->data_va);
@@ -560,18 +548,18 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 /*
  * fsmc_read_buf - read chip data into buffer
- * @mtd:       MTD device structure
+ * @host:      FSMC NAND controller
  * @buf:       buffer to store date
  * @len:       number of bytes to read
  */
-static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void fsmc_read_buf(struct fsmc_nand_data *host, u8 *buf, int len)
 {
-       struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
        int i;
 
-       if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
-                       IS_ALIGNED(len, sizeof(uint32_t))) {
-               uint32_t *p = (uint32_t *)buf;
+       if (IS_ALIGNED((uintptr_t)buf, sizeof(u32)) &&
+           IS_ALIGNED(len, sizeof(u32))) {
+               u32 *p = (u32 *)buf;
+
                len = len >> 2;
                for (i = 0; i < len; i++)
                        p[i] = readl_relaxed(host->data_va);
@@ -583,48 +571,42 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 /*
  * fsmc_read_buf_dma - read chip data into buffer
- * @mtd:       MTD device structure
+ * @host:      FSMC NAND controller
  * @buf:       buffer to store date
  * @len:       number of bytes to read
  */
-static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
+static void fsmc_read_buf_dma(struct fsmc_nand_data *host, u8 *buf,
+                             int len)
 {
-       struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
-
        dma_xfer(host, buf, len, DMA_FROM_DEVICE);
 }
 
 /*
  * fsmc_write_buf_dma - write buffer to chip
- * @mtd:       MTD device structure
+ * @host:      FSMC NAND controller
  * @buf:       data buffer
  * @len:       number of bytes to write
  */
-static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
-               int len)
+static void fsmc_write_buf_dma(struct fsmc_nand_data *host, const u8 *buf,
+                              int len)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-
        dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
 }
 
 /* fsmc_select_chip - assert or deassert nCE */
-static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
+static void fsmc_ce_ctrl(struct fsmc_nand_data *host, bool assert)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
-       u32 pc;
-
-       /* Support only one CS */
-       if (chipnr > 0)
-               return;
+       u32 pc = readl(host->regs_va + FSMC_PC);
 
-       pc = readl(host->regs_va + FSMC_PC);
-       if (chipnr < 0)
+       if (!assert)
                writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC);
        else
                writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC);
 
-       /* nCE line must be asserted before starting any operation */
+       /*
+        * nCE line changes must be applied before returning from this
+        * function.
+        */
        mb();
 }
 
@@ -637,14 +619,16 @@ static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
 static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                        bool check_only)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = nand_to_fsmc(chip);
        const struct nand_op_instr *instr = NULL;
        int ret = 0;
        unsigned int op_id;
        int i;
 
        pr_debug("Executing operation [%d instructions]:\n", op->ninstrs);
+
+       fsmc_ce_ctrl(host, true);
+
        for (op_id = 0; op_id < op->ninstrs; op_id++) {
                instr = &op->instrs[op_id];
 
@@ -671,10 +655,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                                 ", force 8-bit" : "");
 
                        if (host->mode == USE_DMA_ACCESS)
-                               fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in,
+                               fsmc_read_buf_dma(host, instr->ctx.data.buf.in,
                                                  instr->ctx.data.len);
                        else
-                               fsmc_read_buf(mtd, instr->ctx.data.buf.in,
+                               fsmc_read_buf(host, instr->ctx.data.buf.in,
                                              instr->ctx.data.len);
                        break;
 
@@ -684,10 +668,11 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                                 ", force 8-bit" : "");
 
                        if (host->mode == USE_DMA_ACCESS)
-                               fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out,
+                               fsmc_write_buf_dma(host,
+                                                  instr->ctx.data.buf.out,
                                                   instr->ctx.data.len);
                        else
-                               fsmc_write_buf(mtd, instr->ctx.data.buf.out,
+                               fsmc_write_buf(host, instr->ctx.data.buf.out,
                                               instr->ctx.data.len);
                        break;
 
@@ -701,6 +686,8 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                }
        }
 
+       fsmc_ce_ctrl(host, false);
+
        return ret;
 }
 
@@ -717,34 +704,35 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
  * After this read, fsmc hardware generates and reports error data bits(up to a
  * max of 8 bits)
  */
-static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+static int fsmc_read_page_hwecc(struct nand_chip *chip, u8 *buf,
                                int oob_required, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        int i, j, s, stat, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
-       uint8_t *p = buf;
-       uint8_t *ecc_calc = chip->ecc.calc_buf;
-       uint8_t *ecc_code = chip->ecc.code_buf;
-       int off, len, group = 0;
+       u8 *p = buf;
+       u8 *ecc_calc = chip->ecc.calc_buf;
+       u8 *ecc_code = chip->ecc.code_buf;
+       int off, len, ret, group = 0;
        /*
-        * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
+        * ecc_oob is intentionally taken as u16. In 16bit devices, we
         * end up reading 14 bytes (7 words) from oob. The local array is
         * to maintain word alignment
         */
-       uint16_t ecc_oob[7];
-       uint8_t *oob = (uint8_t *)&ecc_oob[0];
+       u16 ecc_oob[7];
+       u8 *oob = (u8 *)&ecc_oob[0];
        unsigned int max_bitflips = 0;
 
        for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
                nand_read_page_op(chip, page, s * eccsize, NULL, 0);
                chip->ecc.hwctl(chip, NAND_ECC_READ);
-               nand_read_data_op(chip, p, eccsize, false);
+               ret = nand_read_data_op(chip, p, eccsize, false);
+               if (ret)
+                       return ret;
 
                for (j = 0; j < eccbytes;) {
                        struct mtd_oob_region oobregion;
-                       int ret;
 
                        ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
                        if (ret)
@@ -788,15 +776,15 @@ static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
  * @calc_ecc:  ecc calculated from read data
  *
  * calc_ecc is a 104 bit information containing maximum of 8 error
- * offset informations of 13 bits each in 512 bytes of read data.
+ * offset information of 13 bits each in 512 bytes of read data.
  */
-static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
-                                 uint8_t *read_ecc, uint8_t *calc_ecc)
+static int fsmc_bch8_correct_data(struct nand_chip *chip, u8 *dat,
+                                 u8 *read_ecc, u8 *calc_ecc)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
-       uint32_t err_idx[8];
-       uint32_t num_err, i;
-       uint32_t ecc1, ecc2, ecc3, ecc4;
+       struct fsmc_nand_data *host = nand_to_fsmc(chip);
+       u32 err_idx[8];
+       u32 num_err, i;
+       u32 ecc1, ecc2, ecc3, ecc4;
 
        num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF;
 
@@ -837,8 +825,8 @@ static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
         * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--|
         *
         * calc_ecc is a 104 bit information containing maximum of 8 error
-        * offset informations of 13 bits each. calc_ecc is copied into a
-        * uint64_t array and error offset indexes are populated in err_idx
+        * offset information of 13 bits each. calc_ecc is copied into a
+        * u64 array and error offset indexes are populated in err_idx
         * array
         */
        ecc1 = readl_relaxed(host->regs_va + ECC1);
@@ -897,11 +885,13 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
                nand->options |= NAND_SKIP_BBTSCAN;
 
        host->dev_timings = devm_kzalloc(&pdev->dev,
-                               sizeof(*host->dev_timings), GFP_KERNEL);
+                                        sizeof(*host->dev_timings),
+                                        GFP_KERNEL);
        if (!host->dev_timings)
                return -ENOMEM;
+
        ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
-                                               sizeof(*host->dev_timings));
+                                       sizeof(*host->dev_timings));
        if (ret)
                host->dev_timings = NULL;
 
@@ -920,7 +910,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
 static int fsmc_nand_attach_chip(struct nand_chip *nand)
 {
        struct mtd_info *mtd = nand_to_mtd(nand);
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = nand_to_fsmc(nand);
 
        if (AMBA_REV_BITS(host->pid) >= 8) {
                switch (mtd->oobsize) {
@@ -992,6 +982,8 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
 
 static const struct nand_controller_ops fsmc_nand_controller_ops = {
        .attach_chip = fsmc_nand_attach_chip,
+       .exec_op = fsmc_exec_op,
+       .setup_data_interface = fsmc_setup_data_interface,
 };
 
 /*
@@ -1061,10 +1053,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
         * AMBA PrimeCell bus. However it is not a PrimeCell.
         */
        for (pid = 0, i = 0; i < 4; i++)
-               pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
+               pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) &
+                       255) << (i * 8);
+
        host->pid = pid;
-       dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
-                "revision %02x, config %02x\n",
+
+       dev_info(&pdev->dev,
+                "FSMC device partno %03x, manufacturer %02x, revision %02x, config %02x\n",
                 AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
                 AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
 
@@ -1075,12 +1070,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 
        /* Link all private pointers */
        mtd = nand_to_mtd(&host->nand);
-       nand_set_controller_data(nand, host);
        nand_set_flash_node(nand, pdev->dev.of_node);
 
        mtd->dev.parent = &pdev->dev;
-       nand->exec_op = fsmc_exec_op;
-       nand->select_chip = fsmc_select_chip;
 
        /*
         * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
@@ -1106,10 +1098,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                }
        }
 
-       if (host->dev_timings)
+       if (host->dev_timings) {
                fsmc_nand_setup(host, host->dev_timings);
-       else
-               nand->setup_data_interface = fsmc_setup_data_interface;
+               nand->options |= NAND_KEEP_TIMINGS;
+       }
 
        if (AMBA_REV_BITS(host->pid) >= 8) {
                nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -1119,10 +1111,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                nand->ecc.strength = 8;
        }
 
+       nand_controller_init(&host->base);
+       host->base.ops = &fsmc_nand_controller_ops;
+       nand->controller = &host->base;
+
        /*
         * Scan to find existence of the device
         */
-       nand->dummy_controller.ops = &fsmc_nand_controller_ops;
        ret = nand_scan(nand, 1);
        if (ret)
                goto release_dma_write_chan;
@@ -1175,19 +1170,23 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 static int fsmc_nand_suspend(struct device *dev)
 {
        struct fsmc_nand_data *host = dev_get_drvdata(dev);
+
        if (host)
                clk_disable_unprepare(host->clk);
+
        return 0;
 }
 
 static int fsmc_nand_resume(struct device *dev)
 {
        struct fsmc_nand_data *host = dev_get_drvdata(dev);
+
        if (host) {
                clk_prepare_enable(host->clk);
                if (host->dev_timings)
                        fsmc_nand_setup(host, host->dev_timings);
        }
+
        return 0;
 }
 #endif
@@ -1212,6 +1211,6 @@ static struct platform_driver fsmc_nand_driver = {
 
 module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");
 MODULE_DESCRIPTION("NAND driver for SPEAr Platforms");
index 94c2b7525c85e5942ad2ed26fe7e16bde3c21852..ed405c9434fe531a4e961119388dafeb4922b59d 100644 (file)
@@ -1549,7 +1549,7 @@ static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
        int column, page, chipnr;
 
        chipnr = (int)(ofs >> chip->chip_shift);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
 
@@ -1562,7 +1562,7 @@ static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
 
        ret = nand_prog_page_op(chip, page, column, block_mark, 1);
 
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
 
        return ret;
 }
@@ -1610,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
        search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
 
        saved_chip_number = this->current_chip;
-       chip->select_chip(chip, 0);
+       nand_select_target(chip, 0);
 
        /*
         * Loop through the first search area, looking for the NCB fingerprint.
@@ -1638,7 +1638,10 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
 
        }
 
-       chip->select_chip(chip, saved_chip_number);
+       if (saved_chip_number >= 0)
+               nand_select_target(chip, saved_chip_number);
+       else
+               nand_deselect_target(chip);
 
        if (found_an_ncb_fingerprint)
                dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1681,7 +1684,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
 
        /* Select chip 0. */
        saved_chip_number = this->current_chip;
-       chip->select_chip(chip, 0);
+       nand_select_target(chip, 0);
 
        /* Loop over blocks in the first search area, erasing them. */
        dev_dbg(dev, "Erasing the search area...\n");
@@ -1713,7 +1716,11 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
        }
 
        /* Deselect chip 0. */
-       chip->select_chip(chip, saved_chip_number);
+       if (saved_chip_number >= 0)
+               nand_select_target(chip, saved_chip_number);
+       else
+               nand_deselect_target(chip);
+
        return 0;
 }
 
@@ -1762,10 +1769,10 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
                byte = block <<  chip->phys_erase_shift;
 
                /* Send the command to read the conventional block mark. */
-               chip->select_chip(chip, chipnr);
+               nand_select_target(chip, chipnr);
                nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
                block_mark = chip->legacy.read_byte(chip);
-               chip->select_chip(chip, -1);
+               nand_deselect_target(chip);
 
                /*
                 * Check if the block is marked bad. If so, we need to mark it
@@ -1882,6 +1889,7 @@ static int gpmi_nand_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops gpmi_nand_controller_ops = {
        .attach_chip = gpmi_nand_attach_chip,
+       .setup_data_interface = gpmi_setup_data_interface,
 };
 
 static int gpmi_nand_init(struct gpmi_nand_data *this)
@@ -1900,8 +1908,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
        nand_set_controller_data(chip, this);
        nand_set_flash_node(chip, this->pdev->dev.of_node);
-       chip->select_chip       = gpmi_select_chip;
-       chip->setup_data_interface = gpmi_setup_data_interface;
+       chip->legacy.select_chip        = gpmi_select_chip;
        chip->legacy.cmd_ctrl   = gpmi_cmd_ctrl;
        chip->legacy.dev_ready  = gpmi_dev_ready;
        chip->legacy.read_byte  = gpmi_read_byte;
@@ -1924,7 +1931,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
-       chip->dummy_controller.ops = &gpmi_nand_controller_ops;
+       chip->legacy.dummy_controller.ops = &gpmi_nand_controller_ops;
        ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
        if (ret)
                goto err_out;
index f043938ee36b7fb5848fa505d8edd9c3f5e0e477..f3f9aa160cffefecf7d93a2f18f136014596220a 100644 (file)
@@ -783,7 +783,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        nand_set_controller_data(chip, host);
        nand_set_flash_node(chip, np);
        chip->legacy.cmdfunc    = hisi_nfc_cmdfunc;
-       chip->select_chip       = hisi_nfc_select_chip;
+       chip->legacy.select_chip        = hisi_nfc_select_chip;
        chip->legacy.read_byte  = hisi_nfc_read_byte;
        chip->legacy.write_buf  = hisi_nfc_write_buf;
        chip->legacy.read_buf   = hisi_nfc_read_buf;
@@ -799,7 +799,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       chip->dummy_controller.ops = &hisi_nfc_controller_ops;
+       chip->legacy.dummy_controller.ops = &hisi_nfc_controller_ops;
        ret = nand_scan(chip, max_chips);
        if (ret)
                return ret;
index 04c2cf74eff3e397779874d82d4155d456b5009b..fbf6ca015cd7e9c73cc07e9c9f771d17da569ce8 100644 (file)
@@ -95,6 +95,39 @@ void nand_decode_ext_id(struct nand_chip *chip);
 void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
 void sanitize_string(uint8_t *s, size_t len);
 
+static inline bool nand_has_exec_op(struct nand_chip *chip)
+{
+       if (!chip->controller || !chip->controller->ops ||
+           !chip->controller->ops->exec_op)
+               return false;
+
+       return true;
+}
+
+static inline int nand_exec_op(struct nand_chip *chip,
+                              const struct nand_operation *op)
+{
+       if (!nand_has_exec_op(chip))
+               return -ENOTSUPP;
+
+       if (WARN_ON(op->cs >= chip->numchips))
+               return -EINVAL;
+
+       return chip->controller->ops->exec_op(chip, op, false);
+}
+
+static inline bool nand_has_setup_data_iface(struct nand_chip *chip)
+{
+       if (!chip->controller || !chip->controller->ops ||
+           !chip->controller->ops->setup_data_interface)
+               return false;
+
+       if (chip->options & NAND_KEEP_TIMINGS)
+               return false;
+
+       return true;
+}
+
 /* BBT functions */
 int nand_markbad_bbt(struct nand_chip *chip, loff_t offs);
 int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs);
index fb59cfca11a7c109513ecf5aeca511bc698e41de..f92ae5aa2a548939eb5636d12a774158f16ddc16 100644 (file)
@@ -335,14 +335,14 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
                        goto notfound_id;
 
                /* Retrieve the IDs from the first chip. */
-               chip->select_chip(chip, 0);
+               nand_select_target(chip, 0);
                nand_reset_op(chip);
                nand_readid_op(chip, 0, id, sizeof(id));
                *nand_maf_id = id[0];
                *nand_dev_id = id[1];
        } else {
                /* Detect additional chip. */
-               chip->select_chip(chip, chipnr);
+               nand_select_target(chip, chipnr);
                nand_reset_op(chip);
                nand_readid_op(chip, 0, id, sizeof(id));
                if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
@@ -427,8 +427,8 @@ static int jz_nand_probe(struct platform_device *pdev)
 
        chip->legacy.chip_delay = 50;
        chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
-       chip->select_chip = jz_nand_select_chip;
-       chip->dummy_controller.ops = &jz_nand_controller_ops;
+       chip->legacy.select_chip = jz_nand_select_chip;
+       chip->legacy.dummy_controller.ops = &jz_nand_controller_ops;
 
        if (nand->busy_gpio)
                chip->legacy.dev_ready = jz_nand_dev_ready;
index 731c6051d91e0fcc49f69ac74c8f6ccdfddad2f8..7201827809e9aa461b5662a17f0e297c7379997d 100644 (file)
@@ -136,8 +136,10 @@ static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
        switch (size8) {
        case 3:
                dest8[2] = (val >> 16) & 0xff;
+               /* fall through */
        case 2:
                dest8[1] = (val >> 8) & 0xff;
+               /* fall through */
        case 1:
                dest8[0] = val & 0xff;
                break;
index cdf22100ab7719841c63851cd5c6702ed3facdcc..22e58975f0d5e4487c1993db95e13fd5fc88e159 100644 (file)
@@ -279,7 +279,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
        chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
        chip->legacy.chip_delay = RB_DELAY_US;
        chip->options = NAND_NO_SUBPAGE_WRITE;
-       chip->select_chip = jz4780_nand_select_chip;
+       chip->legacy.select_chip = jz4780_nand_select_chip;
        chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
        chip->ecc.mode = NAND_ECC_HW;
        chip->controller = &nfc->controller;
index abbb655fe154dfc834ea42488d2fba5fd500b073..086964f8d4240e1a3a7d138307678660415a7bf4 100644 (file)
@@ -799,7 +799,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * Scan to find existence of the device and get the type of NAND device:
         * SMALL block or LARGE block.
         */
-       nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+       nand_chip->legacy.dummy_controller.ops = &lpc32xx_nand_controller_ops;
        res = nand_scan(nand_chip, 1);
        if (res)
                goto free_irq;
index f2f2cdbb9d04c6ea72ad30c8ea375f2dcff7492a..a2c5fdc875bdecaab413f86b2d5fe80b2fb3a460 100644 (file)
@@ -924,7 +924,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        /* Find NAND device */
-       chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+       chip->legacy.dummy_controller.ops = &lpc32xx_nand_controller_ops;
        res = nand_scan(chip, 1);
        if (res)
                goto release_dma;
index 650f2b490a054c16c8c20f882f0c72134fadd7b1..84283c6bb0ff9dc12a99857e3c6dc9c0ad5e855b 100644 (file)
@@ -378,7 +378,7 @@ struct marvell_nfc_caps {
  * @dev:               Parent device (used to print error messages)
  * @regs:              NAND controller registers
  * @core_clk:          Core clock
- * @reg_clk:           Regiters clock
+ * @reg_clk:           Registers clock
  * @complete:          Completion object to wait for NAND controller events
  * @assigned_cs:       Bitmask describing already assigned CS lines
  * @chips:             List containing all the NAND chips attached to
@@ -514,9 +514,14 @@ static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
        writel_relaxed(reg & ~int_mask, nfc->regs + NDCR);
 }
 
-static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
+static u32 marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
 {
+       u32 reg;
+
+       reg = readl_relaxed(nfc->regs + NDSR);
        writel_relaxed(int_mask, nfc->regs + NDSR);
+
+       return reg & int_mask;
 }
 
 static void marvell_nfc_force_byte_access(struct nand_chip *chip,
@@ -683,6 +688,7 @@ static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
 static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
 {
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+       u32 pending;
        int ret;
 
        /* Timeout is expressed in ms */
@@ -695,8 +701,13 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
        ret = wait_for_completion_timeout(&nfc->complete,
                                          msecs_to_jiffies(timeout_ms));
        marvell_nfc_disable_int(nfc, NDCR_RDYM);
-       marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
-       if (!ret) {
+       pending = marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
+
+       /*
+        * In case the interrupt was not served in the required time frame,
+        * check if the ISR was not served or if something went actually wrong.
+        */
+       if (ret && !pending) {
                dev_err(nfc->dev, "Timeout waiting for RB signal\n");
                return -ETIMEDOUT;
        }
@@ -704,7 +715,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
        return 0;
 }
 
-static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
+static void marvell_nfc_select_target(struct nand_chip *chip,
+                                     unsigned int die_nr)
 {
        struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
@@ -713,12 +725,6 @@ static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
        if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die)
                return;
 
-       if (die_nr < 0 || die_nr >= marvell_nand->nsels) {
-               nfc->selected_chip = NULL;
-               marvell_nand->selected_die = -1;
-               return;
-       }
-
        writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
        writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
 
@@ -1024,13 +1030,13 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
        }
 
        ret = marvell_nfc_wait_cmdd(chip);
-
        return ret;
 }
 
 static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
                                                int oob_required, int page)
 {
+       marvell_nfc_select_target(chip, chip->cur_cs);
        return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
                                                   true, page);
 }
@@ -1043,6 +1049,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
        int max_bitflips = 0, ret;
        u8 *raw_buf;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
        marvell_nfc_enable_hw_ecc(chip);
        marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, false,
                                            page);
@@ -1079,6 +1086,7 @@ static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
        return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf,
                                                   chip->oob_poi, true, page);
 }
@@ -1142,6 +1150,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
                                                 const u8 *buf,
                                                 int oob_required, int page)
 {
+       marvell_nfc_select_target(chip, chip->cur_cs);
        return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
                                                    true, page);
 }
@@ -1152,6 +1161,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
 {
        int ret;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
        marvell_nfc_enable_hw_ecc(chip);
        ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
                                                   false, page);
@@ -1175,6 +1185,7 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
 
        memset(chip->data_buf, 0xFF, mtd->writesize);
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
        return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf,
                                                    chip->oob_poi, true, page);
 }
@@ -1194,6 +1205,8 @@ static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
        int ecc_len = lt->ecc_bytes;
        int chunk;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
+
        if (oob_required)
                memset(chip->oob_poi, 0xFF, mtd->oobsize);
 
@@ -1304,6 +1317,8 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
        u32 failure_mask = 0;
        int chunk, ret;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
+
        /*
         * With BCH, OOB is not fully used (and thus not read entirely), not
         * expected bytes could show up at the end of the OOB buffer if not
@@ -1448,6 +1463,8 @@ static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
                lt->last_spare_bytes;
        int chunk;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
+
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
 
        for (chunk = 0; chunk < lt->nchunks; chunk++) {
@@ -1559,6 +1576,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
        int spare_len = lt->spare_bytes;
        int chunk, ret;
 
+       marvell_nfc_select_target(chip, chip->cur_cs);
+
        /* Spare data will be written anyway, so clear it to avoid garbage */
        if (!oob_required)
                memset(chip->oob_poi, 0xFF, mtd->oobsize);
@@ -2097,6 +2116,8 @@ static int marvell_nfc_exec_op(struct nand_chip *chip,
 {
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
 
+       marvell_nfc_select_target(chip, op->cs);
+
        if (nfc->caps->is_nfcv2)
                return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser,
                                              op, check_only);
@@ -2495,6 +2516,8 @@ static int marvell_nand_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops marvell_nand_controller_ops = {
        .attach_chip = marvell_nand_attach_chip,
+       .exec_op = marvell_nfc_exec_op,
+       .setup_data_interface = marvell_nfc_setup_data_interface,
 };
 
 static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
@@ -2617,10 +2640,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
        chip->controller = &nfc->controller;
        nand_set_flash_node(chip, np);
 
-       chip->exec_op = marvell_nfc_exec_op;
-       chip->select_chip = marvell_nfc_select_chip;
        if (!of_property_read_bool(np, "marvell,nand-keep-config"))
-               chip->setup_data_interface = marvell_nfc_setup_data_interface;
+               chip->options |= NAND_KEEP_TIMINGS;
 
        mtd = nand_to_mtd(chip);
        mtd->dev.parent = dev;
index 86a0aabe08df941bd6931a40d1f72918ec6fa3e6..062cd1eb28616275dd8080755e23041c082e680e 100644 (file)
@@ -697,7 +697,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip->legacy.read_byte = mpc5121_nfc_read_byte;
        chip->legacy.read_buf = mpc5121_nfc_read_buf;
        chip->legacy.write_buf = mpc5121_nfc_write_buf;
-       chip->select_chip = mpc5121_nfc_select_chip;
+       chip->legacy.select_chip = mpc5121_nfc_select_chip;
        chip->legacy.set_features = nand_get_set_features_notsupp;
        chip->legacy.get_features = nand_get_set_features_notsupp;
        chip->bbt_options = NAND_BBT_USE_FLASH;
@@ -712,7 +712,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
                        return retval;
                }
 
-               chip->select_chip = ads5121_select_chip;
+               chip->legacy.select_chip = ads5121_select_chip;
        }
 
        /* Enable NFC clock */
index 2bb0df1b7244795658e2620ace4c6bc4b45d4359..b6b4602f5132ebc7b9b3fe30daabd3094bd06ccf 100644 (file)
@@ -1288,6 +1288,7 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops mtk_nfc_controller_ops = {
        .attach_chip = mtk_nfc_attach_chip,
+       .setup_data_interface = mtk_nfc_setup_data_interface,
 };
 
 static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
@@ -1333,13 +1334,12 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
        nand->legacy.dev_ready = mtk_nfc_dev_ready;
-       nand->select_chip = mtk_nfc_select_chip;
+       nand->legacy.select_chip = mtk_nfc_select_chip;
        nand->legacy.write_byte = mtk_nfc_write_byte;
        nand->legacy.write_buf = mtk_nfc_write_buf;
        nand->legacy.read_byte = mtk_nfc_read_byte;
        nand->legacy.read_buf = mtk_nfc_read_buf;
        nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
-       nand->setup_data_interface = mtk_nfc_setup_data_interface;
 
        /* set default mode in case dt entry is missing */
        nand->ecc.mode = NAND_ECC_HW;
index 88bd3f6a499c02a213ba84341084ae11ffd23a67..59554c187e01a99e3302497dd86631dcaccb0560 100644 (file)
@@ -1738,8 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
        return 0;
 }
 
+static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr,
+                                     const struct nand_data_interface *conf)
+{
+       struct mxc_nand_host *host = nand_get_controller_data(chip);
+
+       return host->devtype_data->setup_data_interface(chip, chipnr, conf);
+}
+
 static const struct nand_controller_ops mxcnd_controller_ops = {
        .attach_chip = mxcnd_attach_chip,
+       .setup_data_interface = mxcnd_setup_data_interface,
 };
 
 static int mxcnd_probe(struct platform_device *pdev)
@@ -1800,7 +1809,8 @@ static int mxcnd_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       this->setup_data_interface = host->devtype_data->setup_data_interface;
+       if (!host->devtype_data->setup_data_interface)
+               this->options |= NAND_KEEP_TIMINGS;
 
        if (host->devtype_data->needs_ip) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1828,7 +1838,7 @@ static int mxcnd_probe(struct platform_device *pdev)
        this->ecc.bytes = host->devtype_data->eccbytes;
        host->eccsize = host->devtype_data->eccsize;
 
-       this->select_chip = host->devtype_data->select_chip;
+       this->legacy.select_chip = host->devtype_data->select_chip;
        this->ecc.size = 512;
        mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
 
@@ -1881,7 +1891,7 @@ static int mxcnd_probe(struct platform_device *pdev)
        }
 
        /* Scan the NAND device */
-       this->dummy_controller.ops = &mxcnd_controller_ops;
+       this->legacy.dummy_controller.ops = &mxcnd_controller_ops;
        err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
        if (err)
                goto escan;
index 71050a0b31dfe3b6bf273ff4c240e7cfe307080f..cca4b24d2ffa8e13151b61721053101f2a55644e 100644 (file)
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
+#include <linux/gpio/consumer.h>
 
 #include "internals.h"
 
-static int nand_get_device(struct mtd_info *mtd, int new_state);
-
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
-                            struct mtd_oob_ops *ops);
-
 /* Define default oob placement schemes for large and small page devices */
 static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
                                 struct mtd_oob_region *oobregion)
@@ -213,10 +209,8 @@ static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
        .free = nand_ooblayout_free_lp_hamming,
 };
 
-static int check_offs_len(struct mtd_info *mtd,
-                                       loff_t ofs, uint64_t len)
+static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        int ret = 0;
 
        /* Start address must align on block boundary */
@@ -234,16 +228,55 @@ static int check_offs_len(struct mtd_info *mtd,
        return ret;
 }
 
+/**
+ * nand_select_target() - Select a NAND target (A.K.A. die)
+ * @chip: NAND chip object
+ * @cs: the CS line to select. Note that this CS id is always from the chip
+ *     PoV, not the controller one
+ *
+ * Select a NAND target so that further operations executed on @chip go to the
+ * selected NAND target.
+ */
+void nand_select_target(struct nand_chip *chip, unsigned int cs)
+{
+       /*
+        * cs should always lie between 0 and chip->numchips, when that's not
+        * the case it's a bug and the caller should be fixed.
+        */
+       if (WARN_ON(cs > chip->numchips))
+               return;
+
+       chip->cur_cs = cs;
+
+       if (chip->legacy.select_chip)
+               chip->legacy.select_chip(chip, cs);
+}
+EXPORT_SYMBOL_GPL(nand_select_target);
+
+/**
+ * nand_deselect_target() - Deselect the currently selected target
+ * @chip: NAND chip object
+ *
+ * Deselect the currently selected NAND target. The result of operations
+ * executed on @chip after the target has been deselected is undefined.
+ */
+void nand_deselect_target(struct nand_chip *chip)
+{
+       if (chip->legacy.select_chip)
+               chip->legacy.select_chip(chip, -1);
+
+       chip->cur_cs = -1;
+}
+EXPORT_SYMBOL_GPL(nand_deselect_target);
+
 /**
  * nand_release_device - [GENERIC] release chip
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  *
  * Release chip lock and wake up anyone waiting on the device.
  */
-static void nand_release_device(struct mtd_info *mtd)
+static void nand_release_device(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        /* Release the controller and the chip */
        spin_lock(&chip->controller->lock);
        chip->controller->active = NULL;
@@ -289,6 +322,197 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
        return 0;
 }
 
+static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+       if (chip->legacy.block_bad)
+               return chip->legacy.block_bad(chip, ofs);
+
+       return nand_block_bad(chip, ofs);
+}
+
+/**
+ * panic_nand_get_device - [GENERIC] Get chip for selected access
+ * @chip: the nand chip descriptor
+ * @new_state: the state which is requested
+ *
+ * Used when in panic, no locks are taken.
+ */
+static void panic_nand_get_device(struct nand_chip *chip, int new_state)
+{
+       /* Hardware controller shared among independent devices */
+       chip->controller->active = chip;
+       chip->state = new_state;
+}
+
+/**
+ * nand_get_device - [GENERIC] Get chip for selected access
+ * @chip: NAND chip structure
+ * @new_state: the state which is requested
+ *
+ * Get the device and lock it for exclusive access
+ */
+static int
+nand_get_device(struct nand_chip *chip, int new_state)
+{
+       spinlock_t *lock = &chip->controller->lock;
+       wait_queue_head_t *wq = &chip->controller->wq;
+       DECLARE_WAITQUEUE(wait, current);
+retry:
+       spin_lock(lock);
+
+       /* Hardware controller shared among independent devices */
+       if (!chip->controller->active)
+               chip->controller->active = chip;
+
+       if (chip->controller->active == chip && chip->state == FL_READY) {
+               chip->state = new_state;
+               spin_unlock(lock);
+               return 0;
+       }
+       if (new_state == FL_PM_SUSPENDED) {
+               if (chip->controller->active->state == FL_PM_SUSPENDED) {
+                       chip->state = FL_PM_SUSPENDED;
+                       spin_unlock(lock);
+                       return 0;
+               }
+       }
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(wq, &wait);
+       spin_unlock(lock);
+       schedule();
+       remove_wait_queue(wq, &wait);
+       goto retry;
+}
+
+/**
+ * nand_check_wp - [GENERIC] check if the chip is write protected
+ * @chip: NAND chip object
+ *
+ * Check, if the device is write protected. The function expects, that the
+ * device is already selected.
+ */
+static int nand_check_wp(struct nand_chip *chip)
+{
+       u8 status;
+       int ret;
+
+       /* Broken xD cards report WP despite being writable */
+       if (chip->options & NAND_BROKEN_XD)
+               return 0;
+
+       /* Check the WP bit */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               return ret;
+
+       return status & NAND_STATUS_WP ? 0 : 1;
+}
+
+/**
+ * nand_fill_oob - [INTERN] Transfer client buffer to oob
+ * @oob: oob data buffer
+ * @len: oob data write length
+ * @ops: oob ops structure
+ */
+static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
+                             struct mtd_oob_ops *ops)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+
+       /*
+        * Initialise to all 0xFF, to avoid the possibility of left over OOB
+        * data from a previous OOB read.
+        */
+       memset(chip->oob_poi, 0xff, mtd->oobsize);
+
+       switch (ops->mode) {
+
+       case MTD_OPS_PLACE_OOB:
+       case MTD_OPS_RAW:
+               memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+               return oob + len;
+
+       case MTD_OPS_AUTO_OOB:
+               ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
+                                                 ops->ooboffs, len);
+               BUG_ON(ret);
+               return oob + len;
+
+       default:
+               BUG();
+       }
+       return NULL;
+}
+
+/**
+ * nand_do_write_oob - [MTD Interface] NAND write out-of-band
+ * @chip: NAND chip object
+ * @to: offset to write to
+ * @ops: oob operation description structure
+ *
+ * NAND write out-of-band.
+ */
+static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
+                            struct mtd_oob_ops *ops)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int chipnr, page, status, len;
+
+       pr_debug("%s: to = 0x%08x, len = %i\n",
+                        __func__, (unsigned int)to, (int)ops->ooblen);
+
+       len = mtd_oobavail(mtd, ops);
+
+       /* Do not allow write past end of page */
+       if ((ops->ooboffs + ops->ooblen) > len) {
+               pr_debug("%s: attempt to write past end of page\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       chipnr = (int)(to >> chip->chip_shift);
+
+       /*
+        * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
+        * of my DiskOnChip 2000 test units) will clear the whole data page too
+        * if we don't do this. I have no clue why, but I seem to have 'fixed'
+        * it in the doc2000 driver in August 1999.  dwmw2.
+        */
+       nand_reset(chip, chipnr);
+
+       nand_select_target(chip, chipnr);
+
+       /* Shift to get page */
+       page = (int)(to >> chip->page_shift);
+
+       /* Check, if it is write protected */
+       if (nand_check_wp(chip)) {
+               nand_deselect_target(chip);
+               return -EROFS;
+       }
+
+       /* Invalidate the page cache, if we write to the cached page */
+       if (page == chip->pagebuf)
+               chip->pagebuf = -1;
+
+       nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
+
+       if (ops->mode == MTD_OPS_RAW)
+               status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
+       else
+               status = chip->ecc.write_oob(chip, page & chip->pagemask);
+
+       nand_deselect_target(chip);
+
+       if (status)
+               return status;
+
+       ops->oobretlen = ops->ooblen;
+
+       return 0;
+}
+
 /**
  * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
  * @chip: NAND chip object
@@ -320,7 +544,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
        if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
                ofs += mtd->erasesize - mtd->writesize;
        do {
-               res = nand_do_write_oob(mtd, ofs, &ops);
+               res = nand_do_write_oob(chip, ofs, &ops);
                if (!ret)
                        ret = res;
 
@@ -344,17 +568,9 @@ int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)
        return nand_default_block_markbad(chip, ofs);
 }
 
-static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
-{
-       if (chip->legacy.block_bad)
-               return chip->legacy.block_bad(chip, ofs);
-
-       return nand_block_bad(chip, ofs);
-}
-
 /**
  * nand_block_markbad_lowlevel - mark a block bad
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @ofs: offset from device start
  *
  * This function performs the generic NAND bad block marking steps (i.e., bad
@@ -371,9 +587,9 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
  * Note that we retain the first error encountered in (2) or (3), finish the
  * procedures, and dump the error in the end.
 */
-static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int res, ret = 0;
 
        if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
@@ -386,9 +602,9 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
                nand_erase_nand(chip, &einfo, 0);
 
                /* Write bad block marker to OOB */
-               nand_get_device(mtd, FL_WRITING);
+               nand_get_device(chip, FL_WRITING);
                ret = nand_markbad_bbm(chip, ofs);
-               nand_release_device(mtd);
+               nand_release_device(chip);
        }
 
        /* Mark block bad in BBT */
@@ -404,31 +620,6 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
        return ret;
 }
 
-/**
- * nand_check_wp - [GENERIC] check if the chip is write protected
- * @mtd: MTD device structure
- *
- * Check, if the device is write protected. The function expects, that the
- * device is already selected.
- */
-static int nand_check_wp(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       u8 status;
-       int ret;
-
-       /* Broken xD cards report WP despite being writable */
-       if (chip->options & NAND_BROKEN_XD)
-               return 0;
-
-       /* Check the WP bit */
-       ret = nand_status_op(chip, &status);
-       if (ret)
-               return ret;
-
-       return status & NAND_STATUS_WP ? 0 : 1;
-}
-
 /**
  * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
  * @mtd: MTD device structure
@@ -448,17 +639,15 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
 
 /**
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @ofs: offset from device start
  * @allowbbt: 1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+static int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        /* Return info from the table */
        if (chip->bbt)
                return nand_isbad_bbt(chip, ofs, allowbbt);
@@ -489,7 +678,7 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
        u8 status = 0;
        int ret;
 
-       if (!chip->exec_op)
+       if (!nand_has_exec_op(chip))
                return -ENOTSUPP;
 
        /* Wait tWB before polling the STATUS reg. */
@@ -532,61 +721,34 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
 EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
 
 /**
- * panic_nand_get_device - [GENERIC] Get chip for selected access
- * @chip: the nand chip descriptor
- * @mtd: MTD device structure
- * @new_state: the state which is requested
+ * nand_gpio_waitrdy - Poll R/B GPIO pin until ready
+ * @chip: NAND chip structure
+ * @gpiod: GPIO descriptor of R/B pin
+ * @timeout_ms: Timeout in ms
  *
- * Used when in panic, no locks are taken.
- */
-static void panic_nand_get_device(struct nand_chip *chip,
-                     struct mtd_info *mtd, int new_state)
-{
-       /* Hardware controller shared among independent devices */
-       chip->controller->active = chip;
-       chip->state = new_state;
-}
-
-/**
- * nand_get_device - [GENERIC] Get chip for selected access
- * @mtd: MTD device structure
- * @new_state: the state which is requested
+ * Poll the R/B GPIO pin until it becomes ready. If that does not happen
+ * whitin the specified timeout, -ETIMEDOUT is returned.
  *
- * Get the device and lock it for exclusive access
+ * This helper is intended to be used when the controller has access to the
+ * NAND R/B pin over GPIO.
+ *
+ * Return 0 if the R/B pin indicates chip is ready, a negative error otherwise.
  */
-static int
-nand_get_device(struct mtd_info *mtd, int new_state)
+int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
+                     unsigned long timeout_ms)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       spinlock_t *lock = &chip->controller->lock;
-       wait_queue_head_t *wq = &chip->controller->wq;
-       DECLARE_WAITQUEUE(wait, current);
-retry:
-       spin_lock(lock);
+       /* Wait until R/B pin indicates chip is ready or timeout occurs */
+       timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
+       do {
+               if (gpiod_get_value_cansleep(gpiod))
+                       return 0;
 
-       /* Hardware controller shared among independent devices */
-       if (!chip->controller->active)
-               chip->controller->active = chip;
+               cond_resched();
+       } while (time_before(jiffies, timeout_ms));
 
-       if (chip->controller->active == chip && chip->state == FL_READY) {
-               chip->state = new_state;
-               spin_unlock(lock);
-               return 0;
-       }
-       if (new_state == FL_PM_SUSPENDED) {
-               if (chip->controller->active->state == FL_PM_SUSPENDED) {
-                       chip->state = FL_PM_SUSPENDED;
-                       spin_unlock(lock);
-                       return 0;
-               }
-       }
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       add_wait_queue(wq, &wait);
-       spin_unlock(lock);
-       schedule();
-       remove_wait_queue(wq, &wait);
-       goto retry;
-}
+       return gpiod_get_value_cansleep(gpiod) ? 0 : -ETIMEDOUT;
+};
+EXPORT_SYMBOL_GPL(nand_gpio_waitrdy);
 
 /**
  * panic_nand_wait - [GENERIC] wait until the command is done
@@ -645,7 +807,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
 {
        int ret;
 
-       if (!chip->setup_data_interface)
+       if (!nand_has_setup_data_iface(chip))
                return 0;
 
        /*
@@ -663,7 +825,8 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
         */
 
        onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
-       ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
+       ret = chip->controller->ops->setup_data_interface(chip, chipnr,
+                                                       &chip->data_interface);
        if (ret)
                pr_err("Failed to configure data interface to SDR timing mode 0\n");
 
@@ -690,21 +853,22 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
        };
        int ret;
 
-       if (!chip->setup_data_interface)
+       if (!nand_has_setup_data_iface(chip))
                return 0;
 
        /* Change the mode on the chip side (if supported by the NAND chip) */
        if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
-               chip->select_chip(chip, chipnr);
+               nand_select_target(chip, chipnr);
                ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
                                        tmode_param);
-               chip->select_chip(chip, -1);
+               nand_deselect_target(chip);
                if (ret)
                        return ret;
        }
 
        /* Change the mode on the controller side */
-       ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
+       ret = chip->controller->ops->setup_data_interface(chip, chipnr,
+                                                       &chip->data_interface);
        if (ret)
                return ret;
 
@@ -713,10 +877,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
                return 0;
 
        memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
        ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
                                tmode_param);
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
        if (ret)
                goto err_reset_chip;
 
@@ -734,9 +898,9 @@ err_reset_chip:
         * timing mode.
         */
        nand_reset_data_interface(chip, chipnr);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
        nand_reset_op(chip);
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
 
        return ret;
 }
@@ -759,7 +923,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
 {
        int modes, mode, ret;
 
-       if (!chip->setup_data_interface)
+       if (!nand_has_setup_data_iface(chip))
                return 0;
 
        /*
@@ -785,7 +949,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
                 * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
                 * controller supports the requested timings.
                 */
-               ret = chip->setup_data_interface(chip,
+               ret = chip->controller->ops->setup_data_interface(chip,
                                                 NAND_DATA_IFACE_CHECK_ONLY,
                                                 &chip->data_interface);
                if (!ret) {
@@ -866,7 +1030,7 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
                                 PSEC_TO_NSEC(sdr->tRR_min)),
                NAND_OP_DATA_IN(len, buf, 0),
        };
-       struct nand_operation op = NAND_OPERATION(instrs);
+       struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
        int ret;
 
        /* Drop the DATA_IN instruction if len is set to 0. */
@@ -909,7 +1073,7 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
                                 PSEC_TO_NSEC(sdr->tRR_min)),
                NAND_OP_DATA_IN(len, buf, 0),
        };
-       struct nand_operation op = NAND_OPERATION(instrs);
+       struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
        int ret;
 
        /* Drop the DATA_IN instruction if len is set to 0. */
@@ -955,7 +1119,7 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
        if (offset_in_page + len > mtd->writesize + mtd->oobsize)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                if (mtd->writesize > 512)
                        return nand_lp_exec_read_page_op(chip, page,
                                                         offset_in_page, buf,
@@ -994,7 +1158,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
        if (len && !buf)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1004,7 +1168,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
                                         PSEC_TO_NSEC(sdr->tRR_min)),
                        NAND_OP_8BIT_DATA_IN(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                /* Drop the DATA_IN instruction if len is set to 0. */
                if (!len)
@@ -1049,7 +1213,7 @@ int nand_change_read_column_op(struct nand_chip *chip,
        if (mtd->writesize <= 512)
                return -ENOTSUPP;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                u8 addrs[2] = {};
@@ -1060,7 +1224,7 @@ int nand_change_read_column_op(struct nand_chip *chip,
                                    PSEC_TO_NSEC(sdr->tCCS_min)),
                        NAND_OP_DATA_IN(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
                int ret;
 
                ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
@@ -1108,7 +1272,7 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
        if (offset_in_oob + len > mtd->oobsize)
                return -EINVAL;
 
-       if (chip->exec_op)
+       if (nand_has_exec_op(chip))
                return nand_read_page_op(chip, page,
                                         mtd->writesize + offset_in_oob,
                                         buf, len);
@@ -1142,7 +1306,7 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
                NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)),
                NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
        };
-       struct nand_operation op = NAND_OPERATION(instrs);
+       struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
        int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
        int ret;
        u8 status;
@@ -1221,7 +1385,7 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
        if (offset_in_page + len > mtd->writesize + mtd->oobsize)
                return -EINVAL;
 
-       if (chip->exec_op)
+       if (nand_has_exec_op(chip))
                return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
                                              len, false);
 
@@ -1248,7 +1412,7 @@ int nand_prog_page_end_op(struct nand_chip *chip)
        int ret;
        u8 status;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1256,7 +1420,7 @@ int nand_prog_page_end_op(struct nand_chip *chip)
                                    PSEC_TO_NSEC(sdr->tWB_max)),
                        NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                ret = nand_exec_op(chip, &op);
                if (ret)
@@ -1307,7 +1471,7 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
        if (offset_in_page + len > mtd->writesize + mtd->oobsize)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
                                                len, true);
        } else {
@@ -1355,7 +1519,7 @@ int nand_change_write_column_op(struct nand_chip *chip,
        if (mtd->writesize <= 512)
                return -ENOTSUPP;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                u8 addrs[2];
@@ -1364,7 +1528,7 @@ int nand_change_write_column_op(struct nand_chip *chip,
                        NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)),
                        NAND_OP_DATA_OUT(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
                int ret;
 
                ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
@@ -1410,7 +1574,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
        if (len && !buf)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1418,7 +1582,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
                        NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
                        NAND_OP_8BIT_DATA_IN(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                /* Drop the DATA_IN instruction if len is set to 0. */
                if (!len)
@@ -1449,7 +1613,7 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
  */
 int nand_status_op(struct nand_chip *chip, u8 *status)
 {
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1457,7 +1621,7 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
                                    PSEC_TO_NSEC(sdr->tADL_min)),
                        NAND_OP_8BIT_DATA_IN(1, status, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                if (!status)
                        op.ninstrs--;
@@ -1486,11 +1650,11 @@ EXPORT_SYMBOL_GPL(nand_status_op);
  */
 int nand_exit_status_op(struct nand_chip *chip)
 {
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_CMD(NAND_CMD_READ0, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -1518,7 +1682,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
        int ret;
        u8 status;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                u8 addrs[3] = { page, page >> 8, page >> 16 };
@@ -1529,7 +1693,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
                                    PSEC_TO_MSEC(sdr->tWB_max)),
                        NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                if (chip->options & NAND_ROW_ADDR_3)
                        instrs[1].ctx.addr.naddrs++;
@@ -1577,7 +1741,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
        const u8 *params = data;
        int i, ret;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1587,7 +1751,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
                                              PSEC_TO_NSEC(sdr->tWB_max)),
                        NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -1624,7 +1788,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
        u8 *params = data;
        int i;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
@@ -1635,7 +1799,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
                        NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN,
                                             data, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -1650,12 +1814,12 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
 static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
                            unsigned int delay_ns)
 {
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms),
                                         PSEC_TO_NSEC(delay_ns)),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -1681,14 +1845,14 @@ static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
  */
 int nand_reset_op(struct nand_chip *chip)
 {
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
                struct nand_op_instr instrs[] = {
                        NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
                        NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -1718,11 +1882,11 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
        if (!len || !buf)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_DATA_IN(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                instrs[0].ctx.data.force_8bit = force_8bit;
 
@@ -1762,11 +1926,11 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf,
        if (!len || !buf)
                return -EINVAL;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_DATA_OUT(len, buf, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                instrs[0].ctx.data.force_8bit = force_8bit;
 
@@ -2224,11 +2388,12 @@ int nand_reset(struct nand_chip *chip, int chipnr)
 
        /*
         * The CS line has to be released before we can apply the new NAND
-        * interface settings, hence this weird ->select_chip() dance.
+        * interface settings, hence this weird nand_select_target()
+        * nand_deselect_target() dance.
         */
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
        ret = nand_reset_op(chip);
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
        if (ret)
                return ret;
 
@@ -2924,15 +3089,15 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
 
 /**
  * nand_transfer_oob - [INTERN] Transfer oob to client buffer
- * @mtd: mtd info structure
+ * @chip: NAND chip object
  * @oob: oob destination address
  * @ops: oob ops structure
  * @len: size of oob to transfer
  */
-static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
+static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
                                  struct mtd_oob_ops *ops, size_t len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        switch (ops->mode) {
@@ -2989,17 +3154,17 @@ static void nand_wait_readrdy(struct nand_chip *chip)
 
 /**
  * nand_do_read_ops - [INTERN] Read data with ECC
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @from: offset to read from
  * @ops: oob ops structure
  *
  * Internal function. Called with chip held.
  */
-static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
                            struct mtd_oob_ops *ops)
 {
        int chipnr, page, realpage, col, bytes, aligned, oob_required;
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret = 0;
        uint32_t readlen = ops->len;
        uint32_t oobreadlen = ops->ooblen;
@@ -3012,7 +3177,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        bool ecc_fail = false;
 
        chipnr = (int)(from >> chip->chip_shift);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        realpage = (int)(from >> chip->page_shift);
        page = realpage & chip->pagemask;
@@ -3087,8 +3252,8 @@ read_retry:
                                int toread = min(oobreadlen, max_oobsize);
 
                                if (toread) {
-                                       oob = nand_transfer_oob(mtd,
-                                               oob, ops, toread);
+                                       oob = nand_transfer_oob(chip, oob, ops,
+                                                               toread);
                                        oobreadlen -= toread;
                                }
                        }
@@ -3143,11 +3308,11 @@ read_retry:
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(chip, -1);
-                       chip->select_chip(chip, chipnr);
+                       nand_deselect_target(chip);
+                       nand_select_target(chip, chipnr);
                }
        }
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
 
        ops->retlen = ops->len - (size_t) readlen;
        if (oob)
@@ -3318,18 +3483,18 @@ static int nand_write_oob_syndrome(struct nand_chip *chip, int page)
 
 /**
  * nand_do_read_oob - [INTERN] NAND read out-of-band
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @from: offset to read from
  * @ops: oob operations description structure
  *
  * NAND read out-of-band data from the spare area.
  */
-static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+static int nand_do_read_oob(struct nand_chip *chip, loff_t from,
                            struct mtd_oob_ops *ops)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int max_bitflips = 0;
        int page, realpage, chipnr;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct mtd_ecc_stats stats;
        int readlen = ops->ooblen;
        int len;
@@ -3344,7 +3509,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        len = mtd_oobavail(mtd, ops);
 
        chipnr = (int)(from >> chip->chip_shift);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        /* Shift to get page */
        realpage = (int)(from >> chip->page_shift);
@@ -3360,7 +3525,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                        break;
 
                len = min(len, readlen);
-               buf = nand_transfer_oob(mtd, buf, ops, len);
+               buf = nand_transfer_oob(chip, buf, ops, len);
 
                nand_wait_readrdy(chip);
 
@@ -3377,11 +3542,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(chip, -1);
-                       chip->select_chip(chip, chipnr);
+                       nand_deselect_target(chip);
+                       nand_select_target(chip, chipnr);
                }
        }
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
 
        ops->oobretlen = ops->ooblen - readlen;
 
@@ -3405,6 +3570,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
 {
+       struct nand_chip *chip = mtd_to_nand(mtd);
        int ret;
 
        ops->retlen = 0;
@@ -3414,14 +3580,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
            ops->mode != MTD_OPS_RAW)
                return -ENOTSUPP;
 
-       nand_get_device(mtd, FL_READING);
+       nand_get_device(chip, FL_READING);
 
        if (!ops->datbuf)
-               ret = nand_do_read_oob(mtd, from, ops);
+               ret = nand_do_read_oob(chip, from, ops);
        else
-               ret = nand_do_read_ops(mtd, from, ops);
+               ret = nand_do_read_ops(chip, from, ops);
 
-       nand_release_device(mtd);
+       nand_release_device(chip);
        return ret;
 }
 
@@ -3749,7 +3915,6 @@ static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf,
 
 /**
  * nand_write_page - write one page
- * @mtd: MTD device structure
  * @chip: NAND chip descriptor
  * @offset: address offset within the page
  * @data_len: length of actual data to be written
@@ -3758,10 +3923,11 @@ static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf,
  * @page: page number to write
  * @raw: use _raw version of write_page
  */
-static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-               uint32_t offset, int data_len, const uint8_t *buf,
-               int oob_required, int page, int raw)
+static int nand_write_page(struct nand_chip *chip, uint32_t offset,
+                          int data_len, const uint8_t *buf, int oob_required,
+                          int page, int raw)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int status, subpage;
 
        if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
@@ -3785,59 +3951,21 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-/**
- * nand_fill_oob - [INTERN] Transfer client buffer to oob
- * @mtd: MTD device structure
- * @oob: oob data buffer
- * @len: oob data write length
- * @ops: oob ops structure
- */
-static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
-                             struct mtd_oob_ops *ops)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       int ret;
-
-       /*
-        * Initialise to all 0xFF, to avoid the possibility of left over OOB
-        * data from a previous OOB read.
-        */
-       memset(chip->oob_poi, 0xff, mtd->oobsize);
-
-       switch (ops->mode) {
-
-       case MTD_OPS_PLACE_OOB:
-       case MTD_OPS_RAW:
-               memcpy(chip->oob_poi + ops->ooboffs, oob, len);
-               return oob + len;
-
-       case MTD_OPS_AUTO_OOB:
-               ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
-                                                 ops->ooboffs, len);
-               BUG_ON(ret);
-               return oob + len;
-
-       default:
-               BUG();
-       }
-       return NULL;
-}
-
 #define NOTALIGNED(x)  ((x & (chip->subpagesize - 1)) != 0)
 
 /**
  * nand_do_write_ops - [INTERN] NAND write with ECC
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @to: offset to write to
  * @ops: oob operations description structure
  *
  * NAND write with ECC.
  */
-static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+static int nand_do_write_ops(struct nand_chip *chip, loff_t to,
                             struct mtd_oob_ops *ops)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int chipnr, realpage, page, column;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        uint32_t writelen = ops->len;
 
        uint32_t oobwritelen = ops->ooblen;
@@ -3862,10 +3990,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        column = to & (mtd->writesize - 1);
 
        chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd)) {
+       if (nand_check_wp(chip)) {
                ret = -EIO;
                goto err_out;
        }
@@ -3913,14 +4041,14 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
                if (unlikely(oob)) {
                        size_t len = min(oobwritelen, oobmaxlen);
-                       oob = nand_fill_oob(mtd, oob, len, ops);
+                       oob = nand_fill_oob(chip, oob, len, ops);
                        oobwritelen -= len;
                } else {
                        /* We still need to erase leftover OOB data */
                        memset(chip->oob_poi, 0xff, mtd->oobsize);
                }
 
-               ret = nand_write_page(mtd, chip, column, bytes, wbuf,
+               ret = nand_write_page(chip, column, bytes, wbuf,
                                      oob_required, page,
                                      (ops->mode == MTD_OPS_RAW));
                if (ret)
@@ -3938,8 +4066,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(chip, -1);
-                       chip->select_chip(chip, chipnr);
+                       nand_deselect_target(chip);
+                       nand_select_target(chip, chipnr);
                }
        }
 
@@ -3948,7 +4076,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                ops->oobretlen = ops->ooblen;
 
 err_out:
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
        return ret;
 }
 
@@ -3972,9 +4100,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        int ret;
 
        /* Grab the device */
-       panic_nand_get_device(chip, mtd, FL_WRITING);
+       panic_nand_get_device(chip, FL_WRITING);
 
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        /* Wait for the device to get ready */
        panic_nand_wait(chip, 400);
@@ -3984,80 +4112,12 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        ops.datbuf = (uint8_t *)buf;
        ops.mode = MTD_OPS_PLACE_OOB;
 
-       ret = nand_do_write_ops(mtd, to, &ops);
+       ret = nand_do_write_ops(chip, to, &ops);
 
        *retlen = ops.retlen;
        return ret;
 }
 
-/**
- * nand_do_write_oob - [MTD Interface] NAND write out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operation description structure
- *
- * NAND write out-of-band.
- */
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
-                            struct mtd_oob_ops *ops)
-{
-       int chipnr, page, status, len;
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       pr_debug("%s: to = 0x%08x, len = %i\n",
-                        __func__, (unsigned int)to, (int)ops->ooblen);
-
-       len = mtd_oobavail(mtd, ops);
-
-       /* Do not allow write past end of page */
-       if ((ops->ooboffs + ops->ooblen) > len) {
-               pr_debug("%s: attempt to write past end of page\n",
-                               __func__);
-               return -EINVAL;
-       }
-
-       chipnr = (int)(to >> chip->chip_shift);
-
-       /*
-        * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
-        * of my DiskOnChip 2000 test units) will clear the whole data page too
-        * if we don't do this. I have no clue why, but I seem to have 'fixed'
-        * it in the doc2000 driver in August 1999.  dwmw2.
-        */
-       nand_reset(chip, chipnr);
-
-       chip->select_chip(chip, chipnr);
-
-       /* Shift to get page */
-       page = (int)(to >> chip->page_shift);
-
-       /* Check, if it is write protected */
-       if (nand_check_wp(mtd)) {
-               chip->select_chip(chip, -1);
-               return -EROFS;
-       }
-
-       /* Invalidate the page cache, if we write to the cached page */
-       if (page == chip->pagebuf)
-               chip->pagebuf = -1;
-
-       nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
-
-       if (ops->mode == MTD_OPS_RAW)
-               status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
-       else
-               status = chip->ecc.write_oob(chip, page & chip->pagemask);
-
-       chip->select_chip(chip, -1);
-
-       if (status)
-               return status;
-
-       ops->oobretlen = ops->ooblen;
-
-       return 0;
-}
-
 /**
  * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
  * @mtd: MTD device structure
@@ -4067,11 +4127,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                          struct mtd_oob_ops *ops)
 {
+       struct nand_chip *chip = mtd_to_nand(mtd);
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
 
-       nand_get_device(mtd, FL_WRITING);
+       nand_get_device(chip, FL_WRITING);
 
        switch (ops->mode) {
        case MTD_OPS_PLACE_OOB:
@@ -4084,12 +4145,12 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
        }
 
        if (!ops->datbuf)
-               ret = nand_do_write_oob(mtd, to, ops);
+               ret = nand_do_write_oob(chip, to, ops);
        else
-               ret = nand_do_write_ops(mtd, to, ops);
+               ret = nand_do_write_ops(chip, to, ops);
 
 out:
-       nand_release_device(mtd);
+       nand_release_device(chip);
        return ret;
 }
 
@@ -4133,7 +4194,6 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                    int allowbbt)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        int page, status, pages_per_block, ret, chipnr;
        loff_t len;
 
@@ -4141,11 +4201,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                        __func__, (unsigned long long)instr->addr,
                        (unsigned long long)instr->len);
 
-       if (check_offs_len(mtd, instr->addr, instr->len))
+       if (check_offs_len(chip, instr->addr, instr->len))
                return -EINVAL;
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(mtd, FL_ERASING);
+       nand_get_device(chip, FL_ERASING);
 
        /* Shift to get first page */
        page = (int)(instr->addr >> chip->page_shift);
@@ -4155,10 +4215,10 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
        pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
 
        /* Select the NAND device */
-       chip->select_chip(chip, chipnr);
+       nand_select_target(chip, chipnr);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd)) {
+       if (nand_check_wp(chip)) {
                pr_debug("%s: device is write protected!\n",
                                __func__);
                ret = -EIO;
@@ -4170,7 +4230,7 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
 
        while (len) {
                /* Check if we have a bad block, we do not erase bad blocks! */
-               if (nand_block_checkbad(mtd, ((loff_t) page) <<
+               if (nand_block_checkbad(chip, ((loff_t) page) <<
                                        chip->page_shift, allowbbt)) {
                        pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
                                    __func__, page);
@@ -4209,8 +4269,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                /* Check, if we cross a chip boundary */
                if (len && !(page & chip->pagemask)) {
                        chipnr++;
-                       chip->select_chip(chip, -1);
-                       chip->select_chip(chip, chipnr);
+                       nand_deselect_target(chip);
+                       nand_select_target(chip, chipnr);
                }
        }
 
@@ -4218,8 +4278,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
 erase_exit:
 
        /* Deselect and wake up anyone waiting on the device */
-       chip->select_chip(chip, -1);
-       nand_release_device(mtd);
+       nand_deselect_target(chip);
+       nand_release_device(chip);
 
        /* Return more or less happy */
        return ret;
@@ -4233,12 +4293,14 @@ erase_exit:
  */
 static void nand_sync(struct mtd_info *mtd)
 {
+       struct nand_chip *chip = mtd_to_nand(mtd);
+
        pr_debug("%s: called\n", __func__);
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(mtd, FL_SYNCING);
+       nand_get_device(chip, FL_SYNCING);
        /* Release it and go back */
-       nand_release_device(mtd);
+       nand_release_device(chip);
 }
 
 /**
@@ -4253,13 +4315,13 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
        int ret;
 
        /* Select the NAND device */
-       nand_get_device(mtd, FL_READING);
-       chip->select_chip(chip, chipnr);
+       nand_get_device(chip, FL_READING);
+       nand_select_target(chip, chipnr);
 
-       ret = nand_block_checkbad(mtd, offs, 0);
+       ret = nand_block_checkbad(chip, offs, 0);
 
-       chip->select_chip(chip, -1);
-       nand_release_device(mtd);
+       nand_deselect_target(chip);
+       nand_release_device(chip);
 
        return ret;
 }
@@ -4281,7 +4343,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       return nand_block_markbad_lowlevel(mtd, ofs);
+       return nand_block_markbad_lowlevel(mtd_to_nand(mtd), ofs);
 }
 
 /**
@@ -4326,7 +4388,7 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
  */
 static int nand_suspend(struct mtd_info *mtd)
 {
-       return nand_get_device(mtd, FL_PM_SUSPENDED);
+       return nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED);
 }
 
 /**
@@ -4338,7 +4400,7 @@ static void nand_resume(struct mtd_info *mtd)
        struct nand_chip *chip = mtd_to_nand(mtd);
 
        if (chip->state == FL_PM_SUSPENDED)
-               nand_release_device(mtd);
+               nand_release_device(chip);
        else
                pr_err("%s called for a chip which is not in suspended state\n",
                        __func__);
@@ -4351,19 +4413,20 @@ static void nand_resume(struct mtd_info *mtd)
  */
 static void nand_shutdown(struct mtd_info *mtd)
 {
-       nand_get_device(mtd, FL_PM_SUSPENDED);
+       nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED);
 }
 
 /* Set default functions */
 static void nand_set_defaults(struct nand_chip *chip)
 {
-       nand_legacy_set_defaults(chip);
-
+       /* If no controller is provided, use the dummy, legacy one. */
        if (!chip->controller) {
-               chip->controller = &chip->dummy_controller;
+               chip->controller = &chip->legacy.dummy_controller;
                nand_controller_init(chip->controller);
        }
 
+       nand_legacy_set_defaults(chip);
+
        if (!chip->buf_align)
                chip->buf_align = 1;
 }
@@ -4627,7 +4690,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
                return ret;
 
        /* Select the device */
-       chip->select_chip(chip, 0);
+       nand_select_target(chip, 0);
 
        /* Send the command for reading device ID */
        ret = nand_readid_op(chip, 0, id_data, 2);
@@ -4952,6 +5015,9 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        unsigned int i;
        int ret;
 
+       /* Assume all dies are deselected when we enter nand_scan_ident(). */
+       chip->cur_cs = -1;
+
        /* Enforce the right timings for reset/detection */
        onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
 
@@ -4962,31 +5028,32 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        if (!mtd->name && mtd->dev.parent)
                mtd->name = dev_name(mtd->dev.parent);
 
-       if (chip->exec_op && !chip->select_chip) {
-               pr_err("->select_chip() is mandatory when implementing ->exec_op()\n");
-               return -EINVAL;
-       }
+       /*
+        * Start with chips->numchips = maxchips to let nand_select_target() do
+        * its job. chip->numchips will be adjusted after.
+        */
+       chip->numchips = maxchips;
+
+       /* Set the default functions */
+       nand_set_defaults(chip);
 
        ret = nand_legacy_check_hooks(chip);
        if (ret)
                return ret;
 
-       /* Set the default functions */
-       nand_set_defaults(chip);
-
        /* Read the flash type */
        ret = nand_detect(chip, table);
        if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
-               chip->select_chip(chip, -1);
+               nand_deselect_target(chip);
                return ret;
        }
 
        nand_maf_id = chip->id.data[0];
        nand_dev_id = chip->id.data[1];
 
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
 
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
@@ -4995,15 +5062,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
                /* See comment in nand_get_flash_type for reset */
                nand_reset(chip, i);
 
-               chip->select_chip(chip, i);
+               nand_select_target(chip, i);
                /* Send the command for reading device ID */
                nand_readid_op(chip, 0, id, sizeof(id));
                /* Read manufacturer and device IDs */
                if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
-                       chip->select_chip(chip, -1);
+                       nand_deselect_target(chip);
                        break;
                }
-               chip->select_chip(chip, -1);
+               nand_deselect_target(chip);
        }
        if (i > 1)
                pr_info("%d chips detected\n", i);
@@ -5021,9 +5088,9 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
        kfree(chip->parameters.onfi);
 }
 
-static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
+static int nand_set_ecc_soft_ops(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
 
        if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
@@ -5379,9 +5446,9 @@ EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
  * Requirement (2) ensures we can correct even when all bitflips are clumped
  * in the same sector.
  */
-static bool nand_ecc_strength_good(struct mtd_info *mtd)
+static bool nand_ecc_strength_good(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int corr, ds_corr;
 
@@ -5429,9 +5496,9 @@ static int nand_scan_tail(struct nand_chip *chip)
         * to explictly select the relevant die when interacting with the NAND
         * chip.
         */
-       chip->select_chip(chip, 0);
+       nand_select_target(chip, 0);
        ret = nand_manufacturer_init(chip);
-       chip->select_chip(chip, -1);
+       nand_deselect_target(chip);
        if (ret)
                goto err_free_buf;
 
@@ -5546,7 +5613,7 @@ static int nand_scan_tail(struct nand_chip *chip)
                ecc->algo = NAND_ECC_HAMMING;
 
        case NAND_ECC_SOFT:
-               ret = nand_set_ecc_soft_ops(mtd);
+               ret = nand_set_ecc_soft_ops(chip);
                if (ret) {
                        ret = -EINVAL;
                        goto err_nand_manuf_cleanup;
@@ -5631,7 +5698,7 @@ static int nand_scan_tail(struct nand_chip *chip)
        mtd->oobavail = ret;
 
        /* ECC sanity check: warn if it's too weak */
-       if (!nand_ecc_strength_good(mtd))
+       if (!nand_ecc_strength_good(chip))
                pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
                        mtd->name);
 
index 98a826838b609c0912cbacb1fb9997ca302727a4..1b722fe9213c31ca56fedd21736eb1e7b678c9f2 100644 (file)
@@ -77,8 +77,6 @@
 #define BBT_ENTRY_MASK         0x03
 #define BBT_ENTRY_SHIFT                2
 
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
-
 static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
 {
        uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
@@ -160,7 +158,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: temporary buffer
  * @page: the starting page
  * @num: the number of bbt descriptors to read
@@ -169,11 +167,11 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
  *
  * Read the bad block table starting from page.
  */
-static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
-               struct nand_bbt_descr *td, int offs)
+static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num,
+                   struct nand_bbt_descr *td, int offs)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        int res, ret = 0, i, j, act = 0;
-       struct nand_chip *this = mtd_to_nand(mtd);
        size_t retlen, len, totlen;
        loff_t from;
        int bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -253,7 +251,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 
 /**
  * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @chip: read the table for a specific chip, -1 read all chips; applies only if
@@ -262,16 +260,17 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
  * Read the bad block table for all chips starting at a given page. We assume
  * that the bbt bits are in consecutive order.
  */
-static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+static int read_abs_bbt(struct nand_chip *this, uint8_t *buf,
+                       struct nand_bbt_descr *td, int chip)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int res = 0, i;
 
        if (td->options & NAND_BBT_PERCHIP) {
                int offs = 0;
                for (i = 0; i < this->numchips; i++) {
                        if (chip == -1 || chip == i)
-                               res = read_bbt(mtd, buf, td->pages[i],
+                               res = read_bbt(this, buf, td->pages[i],
                                        this->chipsize >> this->bbt_erase_shift,
                                        td, offs);
                        if (res)
@@ -279,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                        offs += this->chipsize >> this->bbt_erase_shift;
                }
        } else {
-               res = read_bbt(mtd, buf, td->pages[0],
+               res = read_bbt(this, buf, td->pages[0],
                                mtd->size >> this->bbt_erase_shift, td, 0);
                if (res)
                        return res;
@@ -288,9 +287,10 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 }
 
 /* BBT marker is in the first page, no OOB */
-static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-                        struct nand_bbt_descr *td)
+static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs,
+                         struct nand_bbt_descr *td)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        size_t retlen;
        size_t len;
 
@@ -303,7 +303,7 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
 
 /**
  * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @offs: offset at which to scan
  * @len: length of data region to read
@@ -312,9 +312,10 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
  * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
  * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
  */
-static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs,
                         size_t len)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct mtd_oob_ops ops;
        int res, ret = 0;
 
@@ -342,19 +343,20 @@ static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
        return ret;
 }
 
-static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-                        size_t len, struct nand_bbt_descr *td)
+static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs,
+                    size_t len, struct nand_bbt_descr *td)
 {
        if (td->options & NAND_BBT_NO_OOB)
-               return scan_read_data(mtd, buf, offs, td);
+               return scan_read_data(this, buf, offs, td);
        else
-               return scan_read_oob(mtd, buf, offs, len);
+               return scan_read_oob(this, buf, offs, len);
 }
 
 /* Scan write data with oob to flash */
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len,
                          uint8_t *buf, uint8_t *oob)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct mtd_oob_ops ops;
 
        ops.mode = MTD_OPS_PLACE_OOB;
@@ -367,8 +369,9 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
        return mtd_write_oob(mtd, offs, &ops);
 }
 
-static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        u32 ver_offs = td->veroffs;
 
        if (!(td->options & NAND_BBT_NO_OOB))
@@ -378,7 +381,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
 
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md:        descriptor for the bad block table mirror
@@ -386,34 +389,35 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
  * Read the bad block table(s) for all chips starting at a given page. We
  * assume that the bbt bits are in consecutive order.
  */
-static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void read_abs_bbts(struct nand_chip *this, uint8_t *buf,
                          struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
 
        /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
-                             mtd->writesize, td);
-               td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
+               scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift,
+                         mtd->writesize, td);
+               td->version[0] = buf[bbt_get_ver_offs(this, td)];
                pr_info("Bad block table at page %d, version 0x%02X\n",
                         td->pages[0], td->version[0]);
        }
 
        /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-                             mtd->writesize, md);
-               md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
+               scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift,
+                         mtd->writesize, md);
+               md->version[0] = buf[bbt_get_ver_offs(this, md)];
                pr_info("Bad block table at page %d, version 0x%02X\n",
                         md->pages[0], md->version[0]);
        }
 }
 
 /* Scan a given block partially */
-static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
                           loff_t offs, uint8_t *buf, int numpages)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct mtd_oob_ops ops;
        int j, ret;
 
@@ -443,7 +447,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 
 /**
  * create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @bd: descriptor for the good/bad block search pattern
  * @chip: create the table for a specific chip, -1 read all chips; applies only
@@ -452,10 +456,10 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
  * Create a bad block table by scanning the device for the given good/bad block
  * identify pattern.
  */
-static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
-       struct nand_bbt_descr *bd, int chip)
+static int create_bbt(struct nand_chip *this, uint8_t *buf,
+                     struct nand_bbt_descr *bd, int chip)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int i, numblocks, numpages;
        int startblock;
        loff_t from;
@@ -491,7 +495,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
                BUG_ON(bd->options & NAND_BBT_NO_OOB);
 
-               ret = scan_block_fast(mtd, bd, from, buf, numpages);
+               ret = scan_block_fast(this, bd, from, buf, numpages);
                if (ret < 0)
                        return ret;
 
@@ -509,7 +513,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 /**
  * search_bbt - [GENERIC] scan the device for a specific bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  *
@@ -522,9 +526,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
  *
  * The bbt ident pattern resides in the oob area of the first page in a block.
  */
-static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+static int search_bbt(struct nand_chip *this, uint8_t *buf,
+                     struct nand_bbt_descr *td)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int i, chips;
        int startblock, block, dir;
        int scanlen = mtd->writesize + mtd->oobsize;
@@ -561,11 +566,11 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                        loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
 
                        /* Read first page */
-                       scan_read(mtd, buf, offs, mtd->writesize, td);
+                       scan_read(this, buf, offs, mtd->writesize, td);
                        if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
                                td->pages[i] = actblock << blocktopage;
                                if (td->options & NAND_BBT_VERSION) {
-                                       offs = bbt_get_ver_offs(mtd, td);
+                                       offs = bbt_get_ver_offs(this, td);
                                        td->version[i] = buf[offs];
                                }
                                break;
@@ -586,23 +591,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
 /**
  * search_read_bbts - [GENERIC] scan the device for bad block table(s)
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md: descriptor for the bad block table mirror
  *
  * Search and read the bad block table(s).
  */
-static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+static void search_read_bbts(struct nand_chip *this, uint8_t *buf,
                             struct nand_bbt_descr *td,
                             struct nand_bbt_descr *md)
 {
        /* Search the primary table */
-       search_bbt(mtd, buf, td);
+       search_bbt(this, buf, td);
 
        /* Search the mirror table */
        if (md)
-               search_bbt(mtd, buf, md);
+               search_bbt(this, buf, md);
 }
 
 /**
@@ -700,7 +705,7 @@ static void mark_bbt_block_bad(struct nand_chip *this,
 
 /**
  * write_bbt - [GENERIC] (Re)write the bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
  * @md: descriptor for the bad block table mirror
@@ -708,11 +713,11 @@ static void mark_bbt_block_bad(struct nand_chip *this,
  *
  * (Re)write the bad block table.
  */
-static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+static int write_bbt(struct nand_chip *this, uint8_t *buf,
                     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
                     int chipsel)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct erase_info einfo;
        int i, res, chip = 0;
        int bits, page, offs, numblocks, sft, sftmsk;
@@ -862,9 +867,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        continue;
                }
 
-               res = scan_write_bbt(mtd, to, len, buf,
-                               td->options & NAND_BBT_NO_OOB ? NULL :
-                               &buf[len]);
+               res = scan_write_bbt(this, to, len, buf,
+                                    td->options & NAND_BBT_NO_OOB ?
+                                    NULL : &buf[len]);
                if (res < 0) {
                        pr_warn("nand_bbt: error while writing BBT block %d\n",
                                res);
@@ -887,22 +892,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 /**
  * nand_memory_bbt - [GENERIC] create a memory based bad block table
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @bd: descriptor for the good/bad block search pattern
  *
  * The function creates a memory based bbt by scanning the device for
  * manufacturer / software marked good / bad blocks.
  */
-static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt(struct nand_chip *this,
+                                 struct nand_bbt_descr *bd)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-
-       return create_bbt(mtd, this->data_buf, bd, -1);
+       return create_bbt(this, this->data_buf, bd, -1);
 }
 
 /**
  * check_create - [GENERIC] create and write bbt(s) if necessary
- * @mtd: MTD device structure
+ * @this: the NAND device
  * @buf: temporary buffer
  * @bd: descriptor for the good/bad block search pattern
  *
@@ -911,10 +915,10 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  * for the chip/device. Update is necessary if one of the tables is missing or
  * the version nr. of one table is less than the other.
  */
-static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+static int check_create(struct nand_chip *this, uint8_t *buf,
+                       struct nand_bbt_descr *bd)
 {
        int i, chips, writeops, create, chipsel, res, res2;
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct nand_bbt_descr *td = this->bbt_td;
        struct nand_bbt_descr *md = this->bbt_md;
        struct nand_bbt_descr *rd, *rd2;
@@ -971,7 +975,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
                        /* Create the table in memory by scanning the chip(s) */
                        if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
-                               create_bbt(mtd, buf, bd, chipsel);
+                               create_bbt(this, buf, bd, chipsel);
 
                        td->version[i] = 1;
                        if (md)
@@ -980,7 +984,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
                /* Read back first? */
                if (rd) {
-                       res = read_abs_bbt(mtd, buf, rd, chipsel);
+                       res = read_abs_bbt(this, buf, rd, chipsel);
                        if (mtd_is_eccerr(res)) {
                                /* Mark table as invalid */
                                rd->pages[i] = -1;
@@ -991,7 +995,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                }
                /* If they weren't versioned, read both */
                if (rd2) {
-                       res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+                       res2 = read_abs_bbt(this, buf, rd2, chipsel);
                        if (mtd_is_eccerr(res2)) {
                                /* Mark table as invalid */
                                rd2->pages[i] = -1;
@@ -1013,14 +1017,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
                /* Write the bad block table to the device? */
                if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-                       res = write_bbt(mtd, buf, td, md, chipsel);
+                       res = write_bbt(this, buf, td, md, chipsel);
                        if (res < 0)
                                return res;
                }
 
                /* Write the mirror bad block table to the device? */
                if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-                       res = write_bbt(mtd, buf, md, td, chipsel);
+                       res = write_bbt(this, buf, md, td, chipsel);
                        if (res < 0)
                                return res;
                }
@@ -1028,17 +1032,72 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
        return 0;
 }
 
+/**
+ * nand_update_bbt - update bad block table(s)
+ * @this: the NAND device
+ * @offs: the offset of the newly marked block
+ *
+ * The function updates the bad block table(s).
+ */
+static int nand_update_bbt(struct nand_chip *this, loff_t offs)
+{
+       struct mtd_info *mtd = nand_to_mtd(this);
+       int len, res = 0;
+       int chip, chipsel;
+       uint8_t *buf;
+       struct nand_bbt_descr *td = this->bbt_td;
+       struct nand_bbt_descr *md = this->bbt_md;
+
+       if (!this->bbt || !td)
+               return -EINVAL;
+
+       /* Allocate a temporary buffer for one eraseblock incl. oob */
+       len = (1 << this->bbt_erase_shift);
+       len += (len >> this->page_shift) * mtd->oobsize;
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* Do we have a bbt per chip? */
+       if (td->options & NAND_BBT_PERCHIP) {
+               chip = (int)(offs >> this->chip_shift);
+               chipsel = chip;
+       } else {
+               chip = 0;
+               chipsel = -1;
+       }
+
+       td->version[chip]++;
+       if (md)
+               md->version[chip]++;
+
+       /* Write the bad block table to the device? */
+       if (td->options & NAND_BBT_WRITE) {
+               res = write_bbt(this, buf, td, md, chipsel);
+               if (res < 0)
+                       goto out;
+       }
+       /* Write the mirror bad block table to the device? */
+       if (md && (md->options & NAND_BBT_WRITE)) {
+               res = write_bbt(this, buf, md, td, chipsel);
+       }
+
+ out:
+       kfree(buf);
+       return res;
+}
+
 /**
  * mark_bbt_regions - [GENERIC] mark the bad block table regions
- * @mtd: MTD device structure
+ * @this: the NAND device
  * @td: bad block table descriptor
  *
  * The bad block table regions are marked as "bad" to prevent accidental
  * erasures / writes. The regions are identified by the mark 0x02.
  */
-static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
+static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int i, j, chips, block, nrblocks, update;
        uint8_t oldval;
 
@@ -1061,7 +1120,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                        bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
                        if ((oldval != BBT_BLOCK_RESERVED) &&
                                        td->reserved_block_code)
-                               nand_update_bbt(mtd, (loff_t)block <<
+                               nand_update_bbt(this, (loff_t)block <<
                                                this->bbt_erase_shift);
                        continue;
                }
@@ -1083,22 +1142,22 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                 * bbts.  This should only happen once.
                 */
                if (update && td->reserved_block_code)
-                       nand_update_bbt(mtd, (loff_t)(block - 1) <<
+                       nand_update_bbt(this, (loff_t)(block - 1) <<
                                        this->bbt_erase_shift);
        }
 }
 
 /**
  * verify_bbt_descr - verify the bad block description
- * @mtd: MTD device structure
+ * @this: the NAND device
  * @bd: the table to verify
  *
  * This functions performs a few sanity checks on the bad block description
  * table.
  */
-static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        u32 pattern_len;
        u32 bits;
        u32 table_size;
@@ -1138,7 +1197,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
- * @mtd: MTD device structure
+ * @this: the NAND device
  * @bd: descriptor for the good/bad block search pattern
  *
  * The function checks, if a bad block table(s) is/are already available. If
@@ -1148,9 +1207,9 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
  * The bad block table memory is allocated here. It must be freed by calling
  * the nand_free_bbt function.
  */
-static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int len, res;
        uint8_t *buf;
        struct nand_bbt_descr *td = this->bbt_td;
@@ -1170,14 +1229,14 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
         * memory based bad block table.
         */
        if (!td) {
-               if ((res = nand_memory_bbt(mtd, bd))) {
+               if ((res = nand_memory_bbt(this, bd))) {
                        pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
                        goto err;
                }
                return 0;
        }
-       verify_bbt_descr(mtd, td);
-       verify_bbt_descr(mtd, md);
+       verify_bbt_descr(this, td);
+       verify_bbt_descr(this, md);
 
        /* Allocate a temporary buffer for one eraseblock incl. oob */
        len = (1 << this->bbt_erase_shift);
@@ -1190,20 +1249,20 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
        /* Is the bbt at a given page? */
        if (td->options & NAND_BBT_ABSPAGE) {
-               read_abs_bbts(mtd, buf, td, md);
+               read_abs_bbts(this, buf, td, md);
        } else {
                /* Search the bad block table using a pattern in oob */
-               search_read_bbts(mtd, buf, td, md);
+               search_read_bbts(this, buf, td, md);
        }
 
-       res = check_create(mtd, buf, bd);
+       res = check_create(this, buf, bd);
        if (res)
                goto err;
 
        /* Prevent the bbt regions from erasing / writing */
-       mark_bbt_region(mtd, td);
+       mark_bbt_region(this, td);
        if (md)
-               mark_bbt_region(mtd, md);
+               mark_bbt_region(this, md);
 
        vfree(buf);
        return 0;
@@ -1214,61 +1273,6 @@ err:
        return res;
 }
 
-/**
- * nand_update_bbt - update bad block table(s)
- * @mtd: MTD device structure
- * @offs: the offset of the newly marked block
- *
- * The function updates the bad block table(s).
- */
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
-{
-       struct nand_chip *this = mtd_to_nand(mtd);
-       int len, res = 0;
-       int chip, chipsel;
-       uint8_t *buf;
-       struct nand_bbt_descr *td = this->bbt_td;
-       struct nand_bbt_descr *md = this->bbt_md;
-
-       if (!this->bbt || !td)
-               return -EINVAL;
-
-       /* Allocate a temporary buffer for one eraseblock incl. oob */
-       len = (1 << this->bbt_erase_shift);
-       len += (len >> this->page_shift) * mtd->oobsize;
-       buf = kmalloc(len, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /* Do we have a bbt per chip? */
-       if (td->options & NAND_BBT_PERCHIP) {
-               chip = (int)(offs >> this->chip_shift);
-               chipsel = chip;
-       } else {
-               chip = 0;
-               chipsel = -1;
-       }
-
-       td->version[chip]++;
-       if (md)
-               md->version[chip]++;
-
-       /* Write the bad block table to the device? */
-       if (td->options & NAND_BBT_WRITE) {
-               res = write_bbt(mtd, buf, td, md, chipsel);
-               if (res < 0)
-                       goto out;
-       }
-       /* Write the mirror bad block table to the device? */
-       if (md && (md->options & NAND_BBT_WRITE)) {
-               res = write_bbt(mtd, buf, md, td, chipsel);
-       }
-
- out:
-       kfree(buf);
-       return res;
-}
-
 /*
  * Define some generic bad / good block scan pattern which are used
  * while scanning a device for factory marked good / bad blocks.
@@ -1382,7 +1386,7 @@ int nand_create_bbt(struct nand_chip *this)
                        return ret;
        }
 
-       return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern);
+       return nand_scan_bbt(this, this->badblock_pattern);
 }
 EXPORT_SYMBOL(nand_create_bbt);
 
@@ -1433,7 +1437,6 @@ int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
  */
 int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
 {
-       struct mtd_info *mtd = nand_to_mtd(this);
        int block, ret = 0;
 
        block = (int)(offs >> this->bbt_erase_shift);
@@ -1443,7 +1446,7 @@ int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
 
        /* Update flash-based bad block table */
        if (this->bbt_options & NAND_BBT_USE_FLASH)
-               ret = nand_update_bbt(mtd, offs);
+               ret = nand_update_bbt(this, offs);
 
        return ret;
 }
index ac1b5c1039684f56d1a23cdeec00c022fd61ba7c..343f477362d1d03e8c607c4f4507854875e4c48f 100644 (file)
@@ -80,11 +80,11 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
 
 static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
 {
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_CMD(cmd, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
@@ -98,12 +98,12 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
 {
        u16 column = ((u16)addr << 8) | addr;
 
-       if (chip->exec_op) {
+       if (nand_has_exec_op(chip)) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_ADDR(1, &addr, 0),
                        NAND_OP_8BIT_DATA_OUT(1, &val, 0),
                };
-               struct nand_operation op = NAND_OPERATION(instrs);
+               struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
 
                return nand_exec_op(chip, &op);
        }
index 5c26492c841dd2ab21c1f7ad526d0a66ac622f89..38b5dc22cb30a6c56dec29ba71fe2b93b1362555 100644 (file)
@@ -107,6 +107,8 @@ int nand_jedec_detect(struct nand_chip *chip)
                pr_warn("Invalid codeword size\n");
        }
 
+       ret = 1;
+
 free_jedec_param_page:
        kfree(p);
        return ret;
index c5ddc86cd98c183addcccf1f9bc64b3f9af99374..43575943f13bde45a3ff5889af83e0506e82e758 100644 (file)
@@ -165,15 +165,14 @@ static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
 
 /**
  * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @timeo: Timeout
  *
  * Helper function for nand_wait_ready used when needing to wait in interrupt
  * context.
  */
-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+static void panic_nand_wait_ready(struct nand_chip *chip, unsigned long timeo)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        int i;
 
        /* Wait for the device to get ready */
@@ -193,11 +192,10 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
  */
 void nand_wait_ready(struct nand_chip *chip)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned long timeo = 400;
 
        if (in_interrupt() || oops_in_progress)
-               return panic_nand_wait_ready(mtd, timeo);
+               return panic_nand_wait_ready(chip, timeo);
 
        /* Wait until command is processed or timeout occurs */
        timeo = jiffies + msecs_to_jiffies(timeo);
@@ -214,14 +212,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
 
 /**
  * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @timeo: Timeout in ms
  *
  * Wait for status ready (i.e. command done) or timeout.
  */
-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+static void nand_wait_status_ready(struct nand_chip *chip, unsigned long timeo)
 {
-       register struct nand_chip *chip = mtd_to_nand(mtd);
        int ret;
 
        timeo = jiffies + msecs_to_jiffies(timeo);
@@ -321,7 +318,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
                chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
                                      NAND_NCE | NAND_CTRL_CHANGE);
                /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-               nand_wait_status_ready(mtd, 250);
+               nand_wait_status_ready(chip, 250);
                return;
 
                /* This applies to read commands */
@@ -367,7 +364,7 @@ static void nand_ccs_delay(struct nand_chip *chip)
         * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
         * (which should be safe for all NANDs).
         */
-       if (chip->setup_data_interface)
+       if (nand_has_setup_data_iface(chip))
                ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
        else
                ndelay(500);
@@ -458,7 +455,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command,
                chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
                                      NAND_NCE | NAND_CTRL_CHANGE);
                /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-               nand_wait_status_ready(mtd, 250);
+               nand_wait_status_ready(chip, 250);
                return;
 
        case NAND_CMD_RNDOUT:
@@ -525,7 +522,6 @@ EXPORT_SYMBOL(nand_get_set_features_notsupp);
 
 /**
  * nand_wait - [DEFAULT] wait until the command is done
- * @mtd: MTD device structure
  * @chip: NAND chip structure
  *
  * Wait for command done. This applies to erase and program only.
@@ -581,7 +577,7 @@ void nand_legacy_set_defaults(struct nand_chip *chip)
 {
        unsigned int busw = chip->options & NAND_BUSWIDTH_16;
 
-       if (chip->exec_op)
+       if (nand_has_exec_op(chip))
                return;
 
        /* check for proper chip_delay setup, set 20us if not */
@@ -589,15 +585,15 @@ void nand_legacy_set_defaults(struct nand_chip *chip)
                chip->legacy.chip_delay = 20;
 
        /* check, if a user supplied command function given */
-       if (!chip->legacy.cmdfunc && !chip->exec_op)
+       if (!chip->legacy.cmdfunc)
                chip->legacy.cmdfunc = nand_command;
 
        /* check, if a user supplied wait function given */
        if (chip->legacy.waitfunc == NULL)
                chip->legacy.waitfunc = nand_wait;
 
-       if (!chip->select_chip)
-               chip->select_chip = nand_select_chip;
+       if (!chip->legacy.select_chip)
+               chip->legacy.select_chip = nand_select_chip;
 
        /* If called twice, pointers that depend on busw may need to be reset */
        if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte)
@@ -625,14 +621,15 @@ int nand_legacy_check_hooks(struct nand_chip *chip)
         * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is
         * not populated.
         */
-       if (chip->exec_op)
+       if (nand_has_exec_op(chip))
                return 0;
 
        /*
         * Default functions assigned for ->legacy.cmdfunc() and
-        * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated.
+        * ->legacy.select_chip() both expect ->legacy.cmd_ctrl() to be
+        *  populated.
         */
-       if ((!chip->legacy.cmdfunc || !chip->select_chip) &&
+       if ((!chip->legacy.cmdfunc || !chip->legacy.select_chip) &&
            !chip->legacy.cmd_ctrl) {
                pr_err("->legacy.cmd_ctrl() should be provided\n");
                return -EINVAL;
index 358dcc957bb20c1d1600f2819661f9f35ccbb706..47d8cda547cfe10c87852f5d855ab9157bc6fe73 100644 (file)
@@ -33,6 +33,13 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
                "MX30LF4G18AC",
                "MX30LF4G28AC",
                "MX60LF8G18AC",
+               "MX30UF1G18AC",
+               "MX30UF1G16AC",
+               "MX30UF2G18AC",
+               "MX30UF2G16AC",
+               "MX30UF4G18AC",
+               "MX30UF4G16AC",
+               "MX30UF4G28AC",
        };
 
        if (!chip->parameters.supports_set_get_features)
index c452819f612372d56ca5b4316d6afe8cbcb73e1d..933d1a629c519874d3a0f35771b620cf5e5c20f7 100644 (file)
@@ -443,7 +443,7 @@ static unsigned long total_wear = 0;
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
-static int nandsim_debugfs_show(struct seq_file *m, void *private)
+static int nandsim_show(struct seq_file *m, void *private)
 {
        unsigned long wmin = -1, wmax = 0, avg;
        unsigned long deciles[10], decile_max[10], tot = 0;
@@ -494,18 +494,7 @@ static int nandsim_debugfs_show(struct seq_file *m, void *private)
 
        return 0;
 }
-
-static int nandsim_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, nandsim_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations dfs_fops = {
-       .open           = nandsim_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(nandsim);
 
 /**
  * nandsim_debugfs_create - initialize debugfs
@@ -531,7 +520,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
        }
 
        dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
-                                  root, dev, &dfs_fops);
+                                  root, dev, &nandsim_fops);
        if (IS_ERR_OR_NULL(dent)) {
                NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
                return -1;
@@ -2304,7 +2293,7 @@ static int __init ns_init_module(void)
        if ((retval = parse_gravepages()) != 0)
                goto error;
 
-       chip->dummy_controller.ops = &ns_controller_ops;
+       chip->legacy.dummy_controller.ops = &ns_controller_ops;
        retval = nand_scan(chip, 1);
        if (retval) {
                NS_ERR("Could not scan NAND Simulator device\n");
index d49a7a17146c84e17f917eae0db3da4bb3dad564..9857e0e5acd48cec6ad07b1f4a14af6426b21786 100644 (file)
@@ -146,7 +146,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
        chip->legacy.cmd_ctrl = ndfc_hwcontrol;
        chip->legacy.dev_ready = ndfc_ready;
-       chip->select_chip = ndfc_select_chip;
+       chip->legacy.select_chip = ndfc_select_chip;
        chip->legacy.chip_delay = 50;
        chip->controller = &ndfc->ndfc_control;
        chip->legacy.read_buf = ndfc_read_buf;
index 886d05c391efe20b08b78bdb2fb145f3f859b752..68e8b9f7f372a71618837e6a39e88d373c59ed3b 100644 (file)
@@ -1944,7 +1944,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
        case NAND_OMAP_PREFETCH_DMA:
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
-               info->dma = dma_request_chan(dev, "rxtx");
+               info->dma = dma_request_chan(dev->parent, "rxtx");
 
                if (IS_ERR(info->dma)) {
                        dev_err(dev, "DMA engine request failed\n");
index 86c536ddaf248d5a99105f89af2d5dd01871a64d..a994b76daa50572930e9f55e40c1eccf3ad2990a 100644 (file)
@@ -63,7 +63,7 @@ static int plat_nand_probe(struct platform_device *pdev)
        data->chip.legacy.IO_ADDR_W = data->io_base;
        data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
        data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
-       data->chip.select_chip = pdata->ctrl.select_chip;
+       data->chip.legacy.select_chip = pdata->ctrl.select_chip;
        data->chip.legacy.write_buf = pdata->ctrl.write_buf;
        data->chip.legacy.read_buf = pdata->ctrl.read_buf;
        data->chip.legacy.chip_delay = pdata->chip.chip_delay;
index 699d3cf49c6da04b49180cda81d3b5d05fc66563..46c62a31fa46f6364e87ea97172898cfeef092bf 100644 (file)
@@ -2804,7 +2804,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
        mtd->dev.parent = dev;
 
        chip->legacy.cmdfunc    = qcom_nandc_command;
-       chip->select_chip       = qcom_nandc_select_chip;
+       chip->legacy.select_chip        = qcom_nandc_select_chip;
        chip->legacy.read_byte  = qcom_nandc_read_byte;
        chip->legacy.read_buf   = qcom_nandc_read_buf;
        chip->legacy.write_buf  = qcom_nandc_write_buf;
index 39be65b35ac251dde3e0f4d500b703fabc2ef3c9..c01422d953dd80487f3a21839bccf6859d818951 100644 (file)
@@ -151,8 +151,9 @@ static void r852_dma_done(struct r852_device *dev, int error)
        dev->dma_stage = 0;
 
        if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
-               pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
-                       dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+               dma_unmap_single(&dev->pci_dev->dev, dev->phys_dma_addr,
+                       R852_DMA_LEN,
+                       dev->dma_dir ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /*
@@ -197,11 +198,10 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
                bounce = 1;
 
        if (!bounce) {
-               dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf,
+               dev->phys_dma_addr = dma_map_single(&dev->pci_dev->dev, buf,
                        R852_DMA_LEN,
-                       (do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
-
-               if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr))
+                       do_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (dma_mapping_error(&dev->pci_dev->dev, dev->phys_dma_addr))
                        bounce = 1;
        }
 
@@ -835,7 +835,7 @@ static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 
        pci_set_master(pci_dev);
 
-       error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+       error = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
        if (error)
                goto error2;
 
@@ -885,8 +885,8 @@ static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        dev->pci_dev = pci_dev;
        pci_set_drvdata(pci_dev, dev);
 
-       dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN,
-               &dev->phys_bounce_buffer);
+       dev->bounce_buffer = dma_alloc_coherent(&pci_dev->dev, R852_DMA_LEN,
+               &dev->phys_bounce_buffer, GFP_KERNEL);
 
        if (!dev->bounce_buffer)
                goto error6;
@@ -946,8 +946,8 @@ error9:
 error8:
        pci_iounmap(pci_dev, dev->mmio);
 error7:
-       pci_free_consistent(pci_dev, R852_DMA_LEN,
-               dev->bounce_buffer, dev->phys_bounce_buffer);
+       dma_free_coherent(&pci_dev->dev, R852_DMA_LEN, dev->bounce_buffer,
+                         dev->phys_bounce_buffer);
 error6:
        kfree(dev);
 error5:
@@ -980,8 +980,8 @@ static void r852_remove(struct pci_dev *pci_dev)
        /* Cleanup */
        kfree(dev->tmp_buffer);
        pci_iounmap(pci_dev, dev->mmio);
-       pci_free_consistent(pci_dev, R852_DMA_LEN,
-               dev->bounce_buffer, dev->phys_bounce_buffer);
+       dma_free_coherent(&pci_dev->dev, R852_DMA_LEN, dev->bounce_buffer,
+                         dev->phys_bounce_buffer);
 
        kfree(dev->chip);
        kfree(dev);
@@ -1045,9 +1045,9 @@ static int r852_resume(struct device *device)
        /* Otherwise, initialize the card */
        if (dev->card_registered) {
                r852_engine_enable(dev);
-               dev->chip->select_chip(dev->chip, 0);
+               nand_select_target(dev->chip, 0);
                nand_reset_op(dev->chip);
-               dev->chip->select_chip(dev->chip, -1);
+               nand_deselect_target(dev->chip);
        }
 
        /* Program card detection IRQ */
index d2e42e9d0e8c15cfca6b235bb8ea5a96e733545b..adc7a196e3836d8ee700624a5d83b1d1e83e8b8c 100644 (file)
@@ -866,7 +866,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 
        chip->legacy.write_buf    = s3c2410_nand_write_buf;
        chip->legacy.read_buf     = s3c2410_nand_read_buf;
-       chip->select_chip  = s3c2410_nand_select_chip;
+       chip->legacy.select_chip  = s3c2410_nand_select_chip;
        chip->legacy.chip_delay   = 50;
        nand_set_controller_data(chip, nmtd);
        chip->options      = set->options;
@@ -876,8 +876,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
         * let's keep behavior unchanged for legacy boards booting via pdata and
         * auto-detect timings only when booting with a device tree.
         */
-       if (np)
-               chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+       if (!np)
+               chip->options |= NAND_KEEP_TIMINGS;
 
        switch (info->cpu_type) {
        case TYPE_S3C2410:
@@ -1011,6 +1011,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
        .attach_chip = s3c2410_nand_attach_chip,
+       .setup_data_interface = s3c2410_nand_setup_data_interface,
 };
 
 static const struct of_device_id s3c24xx_nand_dt_ids[] = {
index 4d20d033de7b32559f1f9606b4693b1067601a11..cf6b1be1cf9c2a95d99699f4ae1633642835e7f4 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SuperH FLCTL nand controller
  *
@@ -5,20 +6,6 @@
  * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
  *
  * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/module.h>
@@ -1183,7 +1170,7 @@ static int flctl_probe(struct platform_device *pdev)
        nand->legacy.read_byte = flctl_read_byte;
        nand->legacy.write_buf = flctl_write_buf;
        nand->legacy.read_buf = flctl_read_buf;
-       nand->select_chip = flctl_select_chip;
+       nand->legacy.select_chip = flctl_select_chip;
        nand->legacy.cmdfunc = flctl_cmdfunc;
        nand->legacy.set_features = nand_get_set_features_notsupp;
        nand->legacy.get_features = nand_get_set_features_notsupp;
@@ -1196,7 +1183,7 @@ static int flctl_probe(struct platform_device *pdev)
 
        flctl_setup_dma(flctl);
 
-       nand->dummy_controller.ops = &flctl_nand_controller_ops;
+       nand->legacy.dummy_controller.ops = &flctl_nand_controller_ops;
        ret = nand_scan(nand, 1);
        if (ret)
                goto err_chip;
@@ -1236,7 +1223,7 @@ static struct platform_driver flctl_driver = {
 
 module_platform_driver_probe(flctl_driver, flctl_probe);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 MODULE_DESCRIPTION("SuperH FLCTL driver");
 MODULE_ALIAS("platform:sh_flctl");
index 6f063ef576405f089622be656fba11ea3ca86745..409d036858dc0e606ab8dc66807505f78ae952b8 100644 (file)
@@ -194,7 +194,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
        chip->options |= NAND_SKIP_BBTSCAN;
 
        /* Scan for card properties */
-       chip->dummy_controller.ops = &sm_controller_ops;
+       chip->legacy.dummy_controller.ops = &sm_controller_ops;
        flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
        ret = nand_scan_with_ids(chip, 1, flash_ids);
        if (ret)
index 51b1a548064b60bc263396efde767786550fac00..e828ee50a201885632f015b81e98b5b21d66f937 100644 (file)
@@ -1393,7 +1393,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
        sunxi_nfc_randomizer_enable(mtd);
 
        writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
-              nfc->regs + NFC_REG_RCMD_SET);
+              nfc->regs + NFC_REG_WCMD_SET);
 
        dma_async_issue_pending(nfc->dmac);
 
@@ -1847,6 +1847,7 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
 
 static const struct nand_controller_ops sunxi_nand_controller_ops = {
        .attach_chip = sunxi_nand_attach_chip,
+       .setup_data_interface = sunxi_nfc_setup_data_interface,
 };
 
 static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
@@ -1922,12 +1923,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
         */
        nand->ecc.mode = NAND_ECC_HW;
        nand_set_flash_node(nand, np);
-       nand->select_chip = sunxi_nfc_select_chip;
+       nand->legacy.select_chip = sunxi_nfc_select_chip;
        nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
        nand->legacy.read_buf = sunxi_nfc_read_buf;
        nand->legacy.write_buf = sunxi_nfc_write_buf;
        nand->legacy.read_byte = sunxi_nfc_read_byte;
-       nand->setup_data_interface = sunxi_nfc_setup_data_interface;
 
        mtd = nand_to_mtd(nand);
        mtd->dev.parent = dev;
index 8818f893f300f1ca26939beb5aff8c5ba00d34ff..cb3beda88789a77844a15175d0cd4834572a5f96 100644 (file)
@@ -530,6 +530,7 @@ static int tango_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops tango_controller_ops = {
        .attach_chip = tango_attach_chip,
+       .setup_data_interface = tango_set_timings,
 };
 
 static int chip_init(struct device *dev, struct device_node *np)
@@ -567,10 +568,9 @@ static int chip_init(struct device *dev, struct device_node *np)
        chip->legacy.read_byte = tango_read_byte;
        chip->legacy.write_buf = tango_write_buf;
        chip->legacy.read_buf = tango_read_buf;
-       chip->select_chip = tango_select_chip;
+       chip->legacy.select_chip = tango_select_chip;
        chip->legacy.cmd_ctrl = tango_cmd_ctrl;
        chip->legacy.dev_ready = tango_dev_ready;
-       chip->setup_data_interface = tango_set_timings;
        chip->options = NAND_USE_BOUNCE_BUFFER |
                        NAND_NO_SUBPAGE_WRITE |
                        NAND_WAIT_TCCS;
index 9767e29d74e2924b46e18fc5625ccfbce075f920..13be32c381948f1e621368cbd26f1e2e2ee8aa9f 100644 (file)
@@ -454,29 +454,24 @@ static const struct nand_op_parser tegra_nand_op_parser = NAND_OP_PARSER(
                NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 4)),
        );
 
+static void tegra_nand_select_target(struct nand_chip *chip,
+                                    unsigned int die_nr)
+{
+       struct tegra_nand_chip *nand = to_tegra_chip(chip);
+       struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
+
+       ctrl->cur_cs = nand->cs[die_nr];
+}
+
 static int tegra_nand_exec_op(struct nand_chip *chip,
                              const struct nand_operation *op,
                              bool check_only)
 {
+       tegra_nand_select_target(chip, op->cs);
        return nand_op_parser_exec_op(chip, &tegra_nand_op_parser, op,
                                      check_only);
 }
 
-static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr)
-{
-       struct tegra_nand_chip *nand = to_tegra_chip(chip);
-       struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
-
-       WARN_ON(die_nr >= (int)ARRAY_SIZE(nand->cs));
-
-       if (die_nr < 0 || die_nr > 0) {
-               ctrl->cur_cs = -1;
-               return;
-       }
-
-       ctrl->cur_cs = nand->cs[die_nr];
-}
-
 static void tegra_nand_hw_ecc(struct tegra_nand_controller *ctrl,
                              struct nand_chip *chip, bool enable)
 {
@@ -503,6 +498,8 @@ static int tegra_nand_page_xfer(struct mtd_info *mtd, struct nand_chip *chip,
        u32 addr1, cmd, dma_ctrl;
        int ret;
 
+       tegra_nand_select_target(chip, chip->cur_cs);
+
        if (read) {
                writel_relaxed(NAND_CMD_READ0, ctrl->regs + CMD_REG1);
                writel_relaxed(NAND_CMD_READSTART, ctrl->regs + CMD_REG2);
@@ -1053,6 +1050,8 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops tegra_nand_controller_ops = {
        .attach_chip = &tegra_nand_attach_chip,
+       .exec_op = tegra_nand_exec_op,
+       .setup_data_interface = tegra_nand_setup_data_interface,
 };
 
 static int tegra_nand_chips_init(struct device *dev,
@@ -1115,9 +1114,6 @@ static int tegra_nand_chips_init(struct device *dev,
                mtd->name = "tegra_nand";
 
        chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
-       chip->exec_op = tegra_nand_exec_op;
-       chip->select_chip = tegra_nand_select_chip;
-       chip->setup_data_interface = tegra_nand_setup_data_interface;
 
        ret = nand_scan(chip, 1);
        if (ret)
index 9814fd4a84cfd59bac00e04c50e3b48b4d0e75b2..a662ca1970e587d8f8460c879d9c774772a823dc 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
  *
  *
  * Based on original driver mpc5121_nfc.c.
  *
- * This 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.
- *
  * Limitations:
  * - Untested on MPC5125 and M54418.
  * - DMA and pipelining not used.
@@ -152,6 +148,7 @@ enum vf610_nfc_variant {
 };
 
 struct vf610_nfc {
+       struct nand_controller base;
        struct nand_chip chip;
        struct device *dev;
        void __iomem *regs;
@@ -168,11 +165,6 @@ struct vf610_nfc {
        u32 ecc_mode;
 };
 
-static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
-{
-       return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
-}
-
 static inline struct vf610_nfc *chip_to_nfc(struct nand_chip *chip)
 {
        return container_of(chip, struct vf610_nfc, chip);
@@ -316,8 +308,7 @@ static void vf610_nfc_done(struct vf610_nfc *nfc)
 
 static irqreturn_t vf610_nfc_irq(int irq, void *data)
 {
-       struct mtd_info *mtd = data;
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = data;
 
        vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
        complete(&nfc->cmd_done);
@@ -487,40 +478,40 @@ static const struct nand_op_parser vf610_nfc_op_parser = NAND_OP_PARSER(
                NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, PAGE_2K + OOB_MAX)),
        );
 
-static int vf610_nfc_exec_op(struct nand_chip *chip,
-                            const struct nand_operation *op,
-                            bool check_only)
-{
-       return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op,
-                                     check_only);
-}
-
 /*
  * This function supports Vybrid only (MPC5125 would have full RB and four CS)
  */
-static void vf610_nfc_select_chip(struct nand_chip *chip, int cs)
+static void vf610_nfc_select_target(struct nand_chip *chip, unsigned int cs)
 {
-       struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
-       u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
+       u32 tmp;
 
        /* Vybrid only (MPC5125 would have full RB and four CS) */
        if (nfc->variant != NFC_VFC610)
                return;
 
+       tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
        tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
-
-       if (cs >= 0) {
-               tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
-               tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT;
-       }
+       tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
+       tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT;
 
        vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
 }
 
-static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+static int vf610_nfc_exec_op(struct nand_chip *chip,
+                            const struct nand_operation *op,
+                            bool check_only)
+{
+       vf610_nfc_select_target(chip, op->cs);
+       return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op,
+                                     check_only);
+}
+
+static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat,
                                         uint8_t *oob, int page)
 {
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
        u8 ecc_status;
        u8 ecc_count;
@@ -560,12 +551,14 @@ static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code,
 static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
                               int oob_required, int page)
 {
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int trfr_sz = mtd->writesize + mtd->oobsize;
        u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
        int stat;
 
+       vf610_nfc_select_target(chip, chip->cur_cs);
+
        cmd2 |= NAND_CMD_READ0 << CMD_BYTE1_SHIFT;
        code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2;
 
@@ -592,7 +585,7 @@ static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
                                                   mtd->writesize,
                                       mtd->oobsize, false);
 
-       stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
+       stat = vf610_nfc_correct_data(chip, buf, chip->oob_poi, page);
 
        if (stat < 0) {
                mtd->ecc_stats.failed++;
@@ -606,13 +599,15 @@ static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
 static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf,
                                int oob_required, int page)
 {
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int trfr_sz = mtd->writesize + mtd->oobsize;
        u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
        u8 status;
        int ret;
 
+       vf610_nfc_select_target(chip, chip->cur_cs);
+
        cmd2 |= NAND_CMD_SEQIN << CMD_BYTE1_SHIFT;
        code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2;
 
@@ -648,8 +643,7 @@ static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf,
 static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf,
                                   int oob_required, int page)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        int ret;
 
        nfc->data_access = true;
@@ -662,8 +656,8 @@ static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf,
 static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
                                    int oob_required, int page)
 {
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int ret;
 
        nfc->data_access = true;
@@ -681,7 +675,7 @@ static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
 
 static int vf610_nfc_read_oob(struct nand_chip *chip, int page)
 {
-       struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        int ret;
 
        nfc->data_access = true;
@@ -694,7 +688,7 @@ static int vf610_nfc_read_oob(struct nand_chip *chip, int page)
 static int vf610_nfc_write_oob(struct nand_chip *chip, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
        int ret;
 
        nfc->data_access = true;
@@ -751,7 +745,7 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
 static int vf610_nfc_attach_chip(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = chip_to_nfc(chip);
 
        vf610_nfc_init_controller(nfc);
 
@@ -809,6 +803,8 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops vf610_nfc_controller_ops = {
        .attach_chip = vf610_nfc_attach_chip,
+       .exec_op = vf610_nfc_exec_op,
+
 };
 
 static int vf610_nfc_probe(struct platform_device *pdev)
@@ -876,14 +872,11 @@ static int vf610_nfc_probe(struct platform_device *pdev)
                goto err_disable_clk;
        }
 
-       chip->exec_op = vf610_nfc_exec_op;
-       chip->select_chip = vf610_nfc_select_chip;
-
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
        init_completion(&nfc->cmd_done);
 
-       err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
+       err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, nfc);
        if (err) {
                dev_err(nfc->dev, "Error requesting IRQ!\n");
                goto err_disable_clk;
@@ -891,13 +884,16 @@ static int vf610_nfc_probe(struct platform_device *pdev)
 
        vf610_nfc_preinit_controller(nfc);
 
+       nand_controller_init(&nfc->base);
+       nfc->base.ops = &vf610_nfc_controller_ops;
+       chip->controller = &nfc->base;
+
        /* Scan the NAND chip */
-       chip->dummy_controller.ops = &vf610_nfc_controller_ops;
        err = nand_scan(chip, 1);
        if (err)
                goto err_disable_clk;
 
-       platform_set_drvdata(pdev, mtd);
+       platform_set_drvdata(pdev, nfc);
 
        /* Register device in MTD */
        err = mtd_device_register(mtd, NULL, 0);
@@ -914,10 +910,9 @@ err_disable_clk:
 
 static int vf610_nfc_remove(struct platform_device *pdev)
 {
-       struct mtd_info *mtd = platform_get_drvdata(pdev);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = platform_get_drvdata(pdev);
 
-       nand_release(mtd_to_nand(mtd));
+       nand_release(&nfc->chip);
        clk_disable_unprepare(nfc->clk);
        return 0;
 }
@@ -925,8 +920,7 @@ static int vf610_nfc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int vf610_nfc_suspend(struct device *dev)
 {
-       struct mtd_info *mtd = dev_get_drvdata(dev);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = dev_get_drvdata(dev);
 
        clk_disable_unprepare(nfc->clk);
        return 0;
@@ -934,11 +928,9 @@ static int vf610_nfc_suspend(struct device *dev)
 
 static int vf610_nfc_resume(struct device *dev)
 {
+       struct vf610_nfc *nfc = dev_get_drvdata(dev);
        int err;
 
-       struct mtd_info *mtd = dev_get_drvdata(dev);
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
        err = clk_prepare_enable(nfc->clk);
        if (err)
                return err;
index a234a5cb486885bb21c606ff84713b751f1bfc89..4cb78106af14cd159dfd2976dd767903b5ae1d8c 100644 (file)
@@ -176,7 +176,7 @@ static int xway_nand_probe(struct platform_device *pdev)
 
        data->chip.legacy.cmd_ctrl = xway_cmd_ctrl;
        data->chip.legacy.dev_ready = xway_dev_ready;
-       data->chip.select_chip = xway_select_chip;
+       data->chip.legacy.select_chip = xway_select_chip;
        data->chip.legacy.write_buf = xway_write_buf;
        data->chip.legacy.read_buf = xway_read_buf;
        data->chip.legacy.read_byte = xway_read_byte;
index b74e074b363a27ff92ca5a7a3b079e109e2926ac..753125082640c6b684b4cc165653707af7a83bb1 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o macronix.o micron.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
index 30f83649c48140e63d7f8871851a7f4ee3320ab6..479c2f2cf17f91ee44978b221391f91a928c0b95 100644 (file)
@@ -764,8 +764,10 @@ static const struct nand_ops spinand_ops = {
 };
 
 static const struct spinand_manufacturer *spinand_manufacturers[] = {
+       &gigadevice_spinand_manufacturer,
        &macronix_spinand_manufacturer,
        &micron_spinand_manufacturer,
+       &toshiba_spinand_manufacturer,
        &winbond_spinand_manufacturer,
 };
 
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
new file mode 100644 (file)
index 0000000..e4141c2
--- /dev/null
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author:
+ *     Chuanhong Guo <gch981213@gmail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_GIGADEVICE                 0xC8
+#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS     (1 << 4)
+#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS       (3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       region->offset = (16 * section) + 8;
+       region->length = 8;
+
+       return 0;
+}
+
+static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
+                                  struct mtd_oob_region *region)
+{
+       if (section > 3)
+               return -ERANGE;
+
+       if (section) {
+               region->offset = 16 * section;
+               region->length = 8;
+       } else {
+               /* section 0 has one byte reserved for bad block mark */
+               region->offset = 1;
+               region->length = 7;
+       }
+       return 0;
+}
+
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+                                        u8 status)
+{
+       switch (status & STATUS_ECC_MASK) {
+       case STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+               /* 1-7 bits are flipped. return the maximum. */
+               return 7;
+
+       case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
+               return 8;
+
+       case STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+       .ecc = gd5fxgq4xa_ooblayout_ecc,
+       .free = gd5fxgq4xa_ooblayout_free,
+};
+
+static const struct spinand_info gigadevice_spinand_table[] = {
+       SPINAND_INFO("GD5F1GQ4xA", 0xF1,
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F2GQ4xA", 0xF2,
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4xA", 0xF4,
+                    NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
+};
+
+static int gigadevice_spinand_detect(struct spinand_device *spinand)
+{
+       u8 *id = spinand->id.data;
+       int ret;
+
+       /*
+        * For GD NANDs, There is an address byte needed to shift in before IDs
+        * are read out, so the first byte in raw_id is dummy.
+        */
+       if (id[1] != SPINAND_MFR_GIGADEVICE)
+               return 0;
+
+       ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
+                                    ARRAY_SIZE(gigadevice_spinand_table),
+                                    id[2]);
+       if (ret)
+               return ret;
+
+       return 1;
+}
+
+static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
+       .detect = gigadevice_spinand_detect,
+};
+
+const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
+       .id = SPINAND_MFR_GIGADEVICE,
+       .name = "GigaDevice",
+       .ops = &gigadevice_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
new file mode 100644 (file)
index 0000000..0812655
--- /dev/null
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 exceet electronics GmbH
+ * Copyright (c) 2018 Kontron Electronics GmbH
+ *
+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_TOSHIBA            0x98
+#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                    struct mtd_oob_region *region)
+{
+       if (section > 7)
+               return -ERANGE;
+
+       region->offset = 128 + 16 * section;
+       region->length = 16;
+
+       return 0;
+}
+
+static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
+                                     struct mtd_oob_region *region)
+{
+       if (section > 0)
+               return -ERANGE;
+
+       /* 2 bytes reserved for BBM */
+       region->offset = 2;
+       region->length = 126;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
+       .ecc = tc58cvg2s0h_ooblayout_ecc,
+       .free = tc58cvg2s0h_ooblayout_free,
+};
+
+static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
+                                     u8 status)
+{
+       struct nand_device *nand = spinand_to_nand(spinand);
+       u8 mbf = 0;
+       struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+
+       switch (status & STATUS_ECC_MASK) {
+       case STATUS_ECC_NO_BITFLIPS:
+               return 0;
+
+       case STATUS_ECC_UNCOR_ERROR:
+               return -EBADMSG;
+
+       case STATUS_ECC_HAS_BITFLIPS:
+       case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
+               /*
+                * Let's try to retrieve the real maximum number of bitflips
+                * in order to avoid forcing the wear-leveling layer to move
+                * data around if it's not necessary.
+                */
+               if (spi_mem_exec_op(spinand->spimem, &op))
+                       return nand->eccreq.strength;
+
+               mbf >>= 4;
+
+               if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
+                       return nand->eccreq.strength;
+
+               return mbf;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct spinand_info toshiba_spinand_table[] = {
+       SPINAND_INFO("TC58CVG2S0H", 0xCD,
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
+                                    tc58cvg2s0h_ecc_get_status)),
+};
+
+static int toshiba_spinand_detect(struct spinand_device *spinand)
+{
+       u8 *id = spinand->id.data;
+       int ret;
+
+       /*
+        * Toshiba SPI NAND read ID needs a dummy byte,
+        * so the first byte in id is garbage.
+        */
+       if (id[1] != SPINAND_MFR_TOSHIBA)
+               return 0;
+
+       ret = spinand_match_and_init(spinand, toshiba_spinand_table,
+                                    ARRAY_SIZE(toshiba_spinand_table),
+                                    id[2]);
+       if (ret)
+               return ret;
+
+       return 1;
+}
+
+static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
+       .detect = toshiba_spinand_detect,
+};
+
+const struct spinand_manufacturer toshiba_spinand_manufacturer = {
+       .id = SPINAND_MFR_TOSHIBA,
+       .name = "Toshiba",
+       .ops = &toshiba_spinand_manuf_ops,
+};
index 67baa1b32c00c2ee5ce8e131e7b3cf1be2223dca..5d944580b8981c22d583d375bbe314945d1b2aa0 100644 (file)
@@ -84,6 +84,14 @@ static const struct spinand_info winbond_spinand_table[] = {
                     0,
                     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
                     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
+       SPINAND_INFO("W25N01GV", 0xAA,
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(1, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
 };
 
 /**
index 91b7fb326f9ab627697b1e8426cfcca4e314a838..334aa5b3a655eabbed9d7bae6503f01b6657db87 100644 (file)
@@ -346,25 +346,26 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
                goto fail;
        }
 
-               /* increase and write Wear-Leveling info */
-               nb_erases = le32_to_cpu(uci.WearInfo);
-               nb_erases++;
-
-               /* wrap (almost impossible with current flash) or free block */
-               if (nb_erases == 0)
-                       nb_erases = 1;
-
-               /* check the "freeness" of Erase Unit before updating metadata
-                * FixMe:  is this check really necessary ? since we have check the
-                *         return code after the erase operation. */
-               if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
-                       goto fail;
-
-               uci.WearInfo = le32_to_cpu(nb_erases);
-               if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
-                                  8, 8, &retlen, (char *)&uci) < 0)
-                       goto fail;
-               return 0;
+       /* increase and write Wear-Leveling info */
+       nb_erases = le32_to_cpu(uci.WearInfo);
+       nb_erases++;
+
+       /* wrap (almost impossible with current flash) or free block */
+       if (nb_erases == 0)
+               nb_erases = 1;
+
+       /* check the "freeness" of Erase Unit before updating metadata
+        * FixMe:  is this check really necessary ? since we have check the
+        *         return code after the erase operation.
+        */
+       if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
+               goto fail;
+
+       uci.WearInfo = le32_to_cpu(nb_erases);
+       if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
+                          8, 8, &retlen, (char *)&uci) < 0)
+               goto fail;
+       return 0;
 fail:
        /* could not format, update the bad block table (caller is responsible
           for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
index ee5ab994132fdc5d15e9c4dbcc43e0669a470fbd..fccf1950e92de1b6ac2baabd74daddc14c75acd0 100644 (file)
@@ -14,3 +14,53 @@ config MTD_SHARPSL_PARTS
          This provides the read-only FTL logic necessary to read the partition
          table from the NAND flash of Sharp SL Series (Zaurus) and the MTD
          partition parser using this code.
+
+config MTD_REDBOOT_PARTS
+       tristate "RedBoot partition table parsing"
+       help
+         RedBoot is a ROM monitor and bootloader which deals with multiple
+         'images' in flash devices by putting a table one of the erase
+         blocks on the device, similar to a partition table, which gives
+         the offsets, lengths and names of all the images stored in the
+         flash.
+
+         If you need code which can detect and parse this table, and register
+         MTD 'partitions' corresponding to each image in the table, enable
+         this option.
+
+         You will still need the parsing functions to be called by the driver
+         for your particular device. It won't happen automatically. The
+         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
+         example.
+
+if MTD_REDBOOT_PARTS
+
+config MTD_REDBOOT_DIRECTORY_BLOCK
+       int "Location of RedBoot partition table"
+       default "-1"
+       help
+         This option is the Linux counterpart to the
+         CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
+         option.
+
+         The option specifies which Flash sectors holds the RedBoot
+         partition table.  A zero or positive value gives an absolute
+         erase block number. A negative value specifies a number of
+         sectors before the end of the device.
+
+         For example "2" means block number 2, "-1" means the last
+         block and "-2" means the penultimate block.
+
+config MTD_REDBOOT_PARTS_UNALLOCATED
+       bool "Include unallocated flash regions"
+       help
+         If you need to register each unallocated flash region as a MTD
+         'partition', enable this option.
+
+config MTD_REDBOOT_PARTS_READONLY
+       bool "Force read-only for RedBoot system images"
+       help
+         If you need to force read-only for 'RedBoot', 'RedBoot Config' and
+         'FIS directory' images, enable this option.
+
+endif # MTD_REDBOOT_PARTS
index 5b1bcc3d90d96b387723ba804e274f27dea13165..d8418bf6804a118884db8634721aa28fd10e7fcc 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MTD_PARSER_TRX)           += parser_trx.o
 obj-$(CONFIG_MTD_SHARPSL_PARTS)                += sharpslpart.o
+obj-$(CONFIG_MTD_REDBOOT_PARTS)                += redboot.o
diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c
new file mode 100644 (file)
index 0000000..957538d
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Parse RedBoot-style Flash Image System (FIS) tables and
+ * produce a Linux partition array to match.
+ *
+ * Copyright © 2001      Red Hat UK Limited
+ * Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/module.h>
+
+struct fis_image_desc {
+    unsigned char name[16];      // Null terminated name
+    uint32_t     flash_base;    // Address within FLASH of image
+    uint32_t     mem_base;      // Address in memory where it executes
+    uint32_t     size;          // Length of image
+    uint32_t     entry_point;   // Execution entry point
+    uint32_t     data_length;   // Length of actual data
+    unsigned char _pad[256-(16+7*sizeof(uint32_t))];
+    uint32_t     desc_cksum;    // Checksum over image descriptor
+    uint32_t     file_cksum;    // Checksum over image data
+};
+
+struct fis_list {
+       struct fis_image_desc *img;
+       struct fis_list *next;
+};
+
+static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
+module_param(directory, int, 0);
+
+static inline int redboot_checksum(struct fis_image_desc *img)
+{
+       /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
+       return 1;
+}
+
+static void parse_redboot_of(struct mtd_info *master)
+{
+       struct device_node *np;
+       u32 dirblock;
+       int ret;
+
+       np = mtd_get_of_node(master);
+       if (!np)
+               return;
+
+       ret = of_property_read_u32(np, "fis-index-block", &dirblock);
+       if (ret)
+               return;
+
+       /*
+        * Assign the block found in the device tree to the local
+        * directory block pointer.
+        */
+       directory = dirblock;
+}
+
+static int parse_redboot_partitions(struct mtd_info *master,
+                                   const struct mtd_partition **pparts,
+                                   struct mtd_part_parser_data *data)
+{
+       int nrparts = 0;
+       struct fis_image_desc *buf;
+       struct mtd_partition *parts;
+       struct fis_list *fl = NULL, *tmp_fl;
+       int ret, i;
+       size_t retlen;
+       char *names;
+       char *nullname;
+       int namelen = 0;
+       int nulllen = 0;
+       int numslots;
+       unsigned long offset;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       static char nullstring[] = "unallocated";
+#endif
+
+       parse_redboot_of(master);
+
+       if ( directory < 0 ) {
+               offset = master->size + directory * master->erasesize;
+               while (mtd_block_isbad(master, offset)) {
+                       if (!offset) {
+                       nogood:
+                               printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
+                               return -EIO;
+                       }
+                       offset -= master->erasesize;
+               }
+       } else {
+               offset = directory * master->erasesize;
+               while (mtd_block_isbad(master, offset)) {
+                       offset += master->erasesize;
+                       if (offset == master->size)
+                               goto nogood;
+               }
+       }
+       buf = vmalloc(master->erasesize);
+
+       if (!buf)
+               return -ENOMEM;
+
+       printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+              master->name, offset);
+
+       ret = mtd_read(master, offset, master->erasesize, &retlen,
+                      (void *)buf);
+
+       if (ret)
+               goto out;
+
+       if (retlen != master->erasesize) {
+               ret = -EIO;
+               goto out;
+       }
+
+       numslots = (master->erasesize / sizeof(struct fis_image_desc));
+       for (i = 0; i < numslots; i++) {
+               if (!memcmp(buf[i].name, "FIS directory", 14)) {
+                       /* This is apparently the FIS directory entry for the
+                        * FIS directory itself.  The FIS directory size is
+                        * one erase block; if the buf[i].size field is
+                        * swab32(erasesize) then we know we are looking at
+                        * a byte swapped FIS directory - swap all the entries!
+                        * (NOTE: this is 'size' not 'data_length'; size is
+                        * the full size of the entry.)
+                        */
+
+                       /* RedBoot can combine the FIS directory and
+                          config partitions into a single eraseblock;
+                          we assume wrong-endian if either the swapped
+                          'size' matches the eraseblock size precisely,
+                          or if the swapped size actually fits in an
+                          eraseblock while the unswapped size doesn't. */
+                       if (swab32(buf[i].size) == master->erasesize ||
+                           (buf[i].size > master->erasesize
+                            && swab32(buf[i].size) < master->erasesize)) {
+                               int j;
+                               /* Update numslots based on actual FIS directory size */
+                               numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
+                               for (j = 0; j < numslots; ++j) {
+
+                                       /* A single 0xff denotes a deleted entry.
+                                        * Two of them in a row is the end of the table.
+                                        */
+                                       if (buf[j].name[0] == 0xff) {
+                                               if (buf[j].name[1] == 0xff) {
+                                                       break;
+                                               } else {
+                                                       continue;
+                                               }
+                                       }
+
+                                       /* The unsigned long fields were written with the
+                                        * wrong byte sex, name and pad have no byte sex.
+                                        */
+                                       swab32s(&buf[j].flash_base);
+                                       swab32s(&buf[j].mem_base);
+                                       swab32s(&buf[j].size);
+                                       swab32s(&buf[j].entry_point);
+                                       swab32s(&buf[j].data_length);
+                                       swab32s(&buf[j].desc_cksum);
+                                       swab32s(&buf[j].file_cksum);
+                               }
+                       } else if (buf[i].size < master->erasesize) {
+                               /* Update numslots based on actual FIS directory size */
+                               numslots = buf[i].size / sizeof(struct fis_image_desc);
+                       }
+                       break;
+               }
+       }
+       if (i == numslots) {
+               /* Didn't find it */
+               printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
+                      master->name);
+               ret = 0;
+               goto out;
+       }
+
+       for (i = 0; i < numslots; i++) {
+               struct fis_list *new_fl, **prev;
+
+               if (buf[i].name[0] == 0xff) {
+                       if (buf[i].name[1] == 0xff) {
+                               break;
+                       } else {
+                               continue;
+                       }
+               }
+               if (!redboot_checksum(&buf[i]))
+                       break;
+
+               new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
+               namelen += strlen(buf[i].name)+1;
+               if (!new_fl) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               new_fl->img = &buf[i];
+               if (data && data->origin)
+                       buf[i].flash_base -= data->origin;
+               else
+                       buf[i].flash_base &= master->size-1;
+
+               /* I'm sure the JFFS2 code has done me permanent damage.
+                * I now think the following is _normal_
+                */
+               prev = &fl;
+               while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
+                       prev = &(*prev)->next;
+               new_fl->next = *prev;
+               *prev = new_fl;
+
+               nrparts++;
+       }
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (fl->img->flash_base) {
+               nrparts++;
+               nulllen = sizeof(nullstring);
+       }
+
+       for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
+               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
+                       nrparts++;
+                       nulllen = sizeof(nullstring);
+               }
+       }
+#endif
+       parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+
+       if (!parts) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       nullname = (char *)&parts[nrparts];
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (nulllen > 0) {
+               strcpy(nullname, nullstring);
+       }
+#endif
+       names = nullname + nulllen;
+
+       i=0;
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (fl->img->flash_base) {
+              parts[0].name = nullname;
+              parts[0].size = fl->img->flash_base;
+              parts[0].offset = 0;
+               i++;
+       }
+#endif
+       for ( ; i<nrparts; i++) {
+               parts[i].size = fl->img->size;
+               parts[i].offset = fl->img->flash_base;
+               parts[i].name = names;
+
+               strcpy(names, fl->img->name);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
+               if (!memcmp(names, "RedBoot", 8) ||
+                               !memcmp(names, "RedBoot config", 15) ||
+                               !memcmp(names, "FIS directory", 14)) {
+                       parts[i].mask_flags = MTD_WRITEABLE;
+               }
+#endif
+               names += strlen(names)+1;
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+                       i++;
+                       parts[i].offset = parts[i-1].size + parts[i-1].offset;
+                       parts[i].size = fl->next->img->flash_base - parts[i].offset;
+                       parts[i].name = nullname;
+               }
+#endif
+               tmp_fl = fl;
+               fl = fl->next;
+               kfree(tmp_fl);
+       }
+       ret = nrparts;
+       *pparts = parts;
+ out:
+       while (fl) {
+               struct fis_list *old = fl;
+               fl = fl->next;
+               kfree(old);
+       }
+       vfree(buf);
+       return ret;
+}
+
+static const struct of_device_id mtd_parser_redboot_of_match_table[] = {
+       { .compatible = "redboot-fis" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtd_parser_redboot_of_match_table);
+
+static struct mtd_part_parser redboot_parser = {
+       .parse_fn = parse_redboot_partitions,
+       .name = "RedBoot",
+       .of_match_table = mtd_parser_redboot_of_match_table,
+};
+module_mtd_part_parser(redboot_parser);
+
+/* mtd parsers will request the module by parser name */
+MODULE_ALIAS("RedBoot");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Parsing code for RedBoot Flash Image System (FIS) tables");
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
deleted file mode 100644 (file)
index 7623ac5..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Parse RedBoot-style Flash Image System (FIS) tables and
- * produce a Linux partition array to match.
- *
- * Copyright © 2001      Red Hat UK Limited
- * Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/module.h>
-
-struct fis_image_desc {
-    unsigned char name[16];      // Null terminated name
-    uint32_t     flash_base;    // Address within FLASH of image
-    uint32_t     mem_base;      // Address in memory where it executes
-    uint32_t     size;          // Length of image
-    uint32_t     entry_point;   // Execution entry point
-    uint32_t     data_length;   // Length of actual data
-    unsigned char _pad[256-(16+7*sizeof(uint32_t))];
-    uint32_t     desc_cksum;    // Checksum over image descriptor
-    uint32_t     file_cksum;    // Checksum over image data
-};
-
-struct fis_list {
-       struct fis_image_desc *img;
-       struct fis_list *next;
-};
-
-static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
-module_param(directory, int, 0);
-
-static inline int redboot_checksum(struct fis_image_desc *img)
-{
-       /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
-       return 1;
-}
-
-static int parse_redboot_partitions(struct mtd_info *master,
-                                   const struct mtd_partition **pparts,
-                                   struct mtd_part_parser_data *data)
-{
-       int nrparts = 0;
-       struct fis_image_desc *buf;
-       struct mtd_partition *parts;
-       struct fis_list *fl = NULL, *tmp_fl;
-       int ret, i;
-       size_t retlen;
-       char *names;
-       char *nullname;
-       int namelen = 0;
-       int nulllen = 0;
-       int numslots;
-       unsigned long offset;
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-       static char nullstring[] = "unallocated";
-#endif
-
-       if ( directory < 0 ) {
-               offset = master->size + directory * master->erasesize;
-               while (mtd_block_isbad(master, offset)) {
-                       if (!offset) {
-                       nogood:
-                               printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
-                               return -EIO;
-                       }
-                       offset -= master->erasesize;
-               }
-       } else {
-               offset = directory * master->erasesize;
-               while (mtd_block_isbad(master, offset)) {
-                       offset += master->erasesize;
-                       if (offset == master->size)
-                               goto nogood;
-               }
-       }
-       buf = vmalloc(master->erasesize);
-
-       if (!buf)
-               return -ENOMEM;
-
-       printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
-              master->name, offset);
-
-       ret = mtd_read(master, offset, master->erasesize, &retlen,
-                      (void *)buf);
-
-       if (ret)
-               goto out;
-
-       if (retlen != master->erasesize) {
-               ret = -EIO;
-               goto out;
-       }
-
-       numslots = (master->erasesize / sizeof(struct fis_image_desc));
-       for (i = 0; i < numslots; i++) {
-               if (!memcmp(buf[i].name, "FIS directory", 14)) {
-                       /* This is apparently the FIS directory entry for the
-                        * FIS directory itself.  The FIS directory size is
-                        * one erase block; if the buf[i].size field is
-                        * swab32(erasesize) then we know we are looking at
-                        * a byte swapped FIS directory - swap all the entries!
-                        * (NOTE: this is 'size' not 'data_length'; size is
-                        * the full size of the entry.)
-                        */
-
-                       /* RedBoot can combine the FIS directory and
-                          config partitions into a single eraseblock;
-                          we assume wrong-endian if either the swapped
-                          'size' matches the eraseblock size precisely,
-                          or if the swapped size actually fits in an
-                          eraseblock while the unswapped size doesn't. */
-                       if (swab32(buf[i].size) == master->erasesize ||
-                           (buf[i].size > master->erasesize
-                            && swab32(buf[i].size) < master->erasesize)) {
-                               int j;
-                               /* Update numslots based on actual FIS directory size */
-                               numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
-                               for (j = 0; j < numslots; ++j) {
-
-                                       /* A single 0xff denotes a deleted entry.
-                                        * Two of them in a row is the end of the table.
-                                        */
-                                       if (buf[j].name[0] == 0xff) {
-                                               if (buf[j].name[1] == 0xff) {
-                                                       break;
-                                               } else {
-                                                       continue;
-                                               }
-                                       }
-
-                                       /* The unsigned long fields were written with the
-                                        * wrong byte sex, name and pad have no byte sex.
-                                        */
-                                       swab32s(&buf[j].flash_base);
-                                       swab32s(&buf[j].mem_base);
-                                       swab32s(&buf[j].size);
-                                       swab32s(&buf[j].entry_point);
-                                       swab32s(&buf[j].data_length);
-                                       swab32s(&buf[j].desc_cksum);
-                                       swab32s(&buf[j].file_cksum);
-                               }
-                       } else if (buf[i].size < master->erasesize) {
-                               /* Update numslots based on actual FIS directory size */
-                               numslots = buf[i].size / sizeof(struct fis_image_desc);
-                       }
-                       break;
-               }
-       }
-       if (i == numslots) {
-               /* Didn't find it */
-               printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
-                      master->name);
-               ret = 0;
-               goto out;
-       }
-
-       for (i = 0; i < numslots; i++) {
-               struct fis_list *new_fl, **prev;
-
-               if (buf[i].name[0] == 0xff) {
-                       if (buf[i].name[1] == 0xff) {
-                               break;
-                       } else {
-                               continue;
-                       }
-               }
-               if (!redboot_checksum(&buf[i]))
-                       break;
-
-               new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
-               namelen += strlen(buf[i].name)+1;
-               if (!new_fl) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               new_fl->img = &buf[i];
-               if (data && data->origin)
-                       buf[i].flash_base -= data->origin;
-               else
-                       buf[i].flash_base &= master->size-1;
-
-               /* I'm sure the JFFS2 code has done me permanent damage.
-                * I now think the following is _normal_
-                */
-               prev = &fl;
-               while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
-                       prev = &(*prev)->next;
-               new_fl->next = *prev;
-               *prev = new_fl;
-
-               nrparts++;
-       }
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-       if (fl->img->flash_base) {
-               nrparts++;
-               nulllen = sizeof(nullstring);
-       }
-
-       for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
-               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
-                       nrparts++;
-                       nulllen = sizeof(nullstring);
-               }
-       }
-#endif
-       parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
-
-       if (!parts) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       nullname = (char *)&parts[nrparts];
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-       if (nulllen > 0) {
-               strcpy(nullname, nullstring);
-       }
-#endif
-       names = nullname + nulllen;
-
-       i=0;
-
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-       if (fl->img->flash_base) {
-              parts[0].name = nullname;
-              parts[0].size = fl->img->flash_base;
-              parts[0].offset = 0;
-               i++;
-       }
-#endif
-       for ( ; i<nrparts; i++) {
-               parts[i].size = fl->img->size;
-               parts[i].offset = fl->img->flash_base;
-               parts[i].name = names;
-
-               strcpy(names, fl->img->name);
-#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
-               if (!memcmp(names, "RedBoot", 8) ||
-                               !memcmp(names, "RedBoot config", 15) ||
-                               !memcmp(names, "FIS directory", 14)) {
-                       parts[i].mask_flags = MTD_WRITEABLE;
-               }
-#endif
-               names += strlen(names)+1;
-
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
-               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
-                       i++;
-                       parts[i].offset = parts[i-1].size + parts[i-1].offset;
-                       parts[i].size = fl->next->img->flash_base - parts[i].offset;
-                       parts[i].name = nullname;
-               }
-#endif
-               tmp_fl = fl;
-               fl = fl->next;
-               kfree(tmp_fl);
-       }
-       ret = nrparts;
-       *pparts = parts;
- out:
-       while (fl) {
-               struct fis_list *old = fl;
-               fl = fl->next;
-               kfree(old);
-       }
-       vfree(buf);
-       return ret;
-}
-
-static struct mtd_part_parser redboot_parser = {
-       .parse_fn = parse_redboot_partitions,
-       .name = "RedBoot",
-};
-module_mtd_part_parser(redboot_parser);
-
-/* mtd parsers will request the module by parser name */
-MODULE_ALIAS("RedBoot");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("Parsing code for RedBoot Flash Image System (FIS) tables");
index 6cc9c929ff571616abb601dc7c494cdfe3d34b61..44fe8018733c283e91ae30994bdf2dd21183c558 100644 (file)
@@ -39,15 +39,6 @@ config SPI_ASPEED_SMC
          and support for the SPI flash memory controller (SPI) for
          the host firmware. The implementation only supports SPI NOR.
 
-config SPI_ATMEL_QUADSPI
-       tristate "Atmel Quad SPI Controller"
-       depends on ARCH_AT91 || (ARM && COMPILE_TEST)
-       depends on OF && HAS_IOMEM
-       help
-         This enables support for the Quad SPI controller in master mode.
-         This driver does not support generic SPI. The implementation only
-         supports SPI NOR.
-
 config SPI_CADENCE_QUADSPI
        tristate "Cadence Quad SPI controller"
        depends on OF && (ARM || ARM64 || COMPILE_TEST)
index f4c61d282abd5c29538d3e208615f799fcaad251..a552efd22958238125cc1bc8d2136e790ccb1cf5 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor.o
 obj-$(CONFIG_SPI_ASPEED_SMC)   += aspeed-smc.o
-obj-$(CONFIG_SPI_ATMEL_QUADSPI)        += atmel-quadspi.o
 obj-$(CONFIG_SPI_CADENCE_QUADSPI)      += cadence-quadspi.o
 obj-$(CONFIG_SPI_FSL_QUADSPI)  += fsl-quadspi.o
 obj-$(CONFIG_SPI_HISI_SFC)     += hisi-sfc.o
diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c
deleted file mode 100644 (file)
index 8200487..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Driver for Atmel QSPI Controller
- *
- * Copyright (C) 2015 Atmel Corporation
- *
- * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/spi-nor.h>
-#include <linux/platform_data/atmel.h>
-#include <linux/of.h>
-
-#include <linux/io.h>
-#include <linux/gpio/consumer.h>
-
-/* QSPI register offsets */
-#define QSPI_CR      0x0000  /* Control Register */
-#define QSPI_MR      0x0004  /* Mode Register */
-#define QSPI_RD      0x0008  /* Receive Data Register */
-#define QSPI_TD      0x000c  /* Transmit Data Register */
-#define QSPI_SR      0x0010  /* Status Register */
-#define QSPI_IER     0x0014  /* Interrupt Enable Register */
-#define QSPI_IDR     0x0018  /* Interrupt Disable Register */
-#define QSPI_IMR     0x001c  /* Interrupt Mask Register */
-#define QSPI_SCR     0x0020  /* Serial Clock Register */
-
-#define QSPI_IAR     0x0030  /* Instruction Address Register */
-#define QSPI_ICR     0x0034  /* Instruction Code Register */
-#define QSPI_IFR     0x0038  /* Instruction Frame Register */
-
-#define QSPI_SMR     0x0040  /* Scrambling Mode Register */
-#define QSPI_SKR     0x0044  /* Scrambling Key Register */
-
-#define QSPI_WPMR    0x00E4  /* Write Protection Mode Register */
-#define QSPI_WPSR    0x00E8  /* Write Protection Status Register */
-
-#define QSPI_VERSION 0x00FC  /* Version Register */
-
-
-/* Bitfields in QSPI_CR (Control Register) */
-#define QSPI_CR_QSPIEN                  BIT(0)
-#define QSPI_CR_QSPIDIS                 BIT(1)
-#define QSPI_CR_SWRST                   BIT(7)
-#define QSPI_CR_LASTXFER                BIT(24)
-
-/* Bitfields in QSPI_MR (Mode Register) */
-#define QSPI_MR_SSM                     BIT(0)
-#define QSPI_MR_LLB                     BIT(1)
-#define QSPI_MR_WDRBT                   BIT(2)
-#define QSPI_MR_SMRM                    BIT(3)
-#define QSPI_MR_CSMODE_MASK             GENMASK(5, 4)
-#define QSPI_MR_CSMODE_NOT_RELOADED     (0 << 4)
-#define QSPI_MR_CSMODE_LASTXFER         (1 << 4)
-#define QSPI_MR_CSMODE_SYSTEMATICALLY   (2 << 4)
-#define QSPI_MR_NBBITS_MASK             GENMASK(11, 8)
-#define QSPI_MR_NBBITS(n)               ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
-#define QSPI_MR_DLYBCT_MASK             GENMASK(23, 16)
-#define QSPI_MR_DLYBCT(n)               (((n) << 16) & QSPI_MR_DLYBCT_MASK)
-#define QSPI_MR_DLYCS_MASK              GENMASK(31, 24)
-#define QSPI_MR_DLYCS(n)                (((n) << 24) & QSPI_MR_DLYCS_MASK)
-
-/* Bitfields in QSPI_SR/QSPI_IER/QSPI_IDR/QSPI_IMR  */
-#define QSPI_SR_RDRF                    BIT(0)
-#define QSPI_SR_TDRE                    BIT(1)
-#define QSPI_SR_TXEMPTY                 BIT(2)
-#define QSPI_SR_OVRES                   BIT(3)
-#define QSPI_SR_CSR                     BIT(8)
-#define QSPI_SR_CSS                     BIT(9)
-#define QSPI_SR_INSTRE                  BIT(10)
-#define QSPI_SR_QSPIENS                 BIT(24)
-
-#define QSPI_SR_CMD_COMPLETED  (QSPI_SR_INSTRE | QSPI_SR_CSR)
-
-/* Bitfields in QSPI_SCR (Serial Clock Register) */
-#define QSPI_SCR_CPOL                   BIT(0)
-#define QSPI_SCR_CPHA                   BIT(1)
-#define QSPI_SCR_SCBR_MASK              GENMASK(15, 8)
-#define QSPI_SCR_SCBR(n)                (((n) << 8) & QSPI_SCR_SCBR_MASK)
-#define QSPI_SCR_DLYBS_MASK             GENMASK(23, 16)
-#define QSPI_SCR_DLYBS(n)               (((n) << 16) & QSPI_SCR_DLYBS_MASK)
-
-/* Bitfields in QSPI_ICR (Instruction Code Register) */
-#define QSPI_ICR_INST_MASK              GENMASK(7, 0)
-#define QSPI_ICR_INST(inst)             (((inst) << 0) & QSPI_ICR_INST_MASK)
-#define QSPI_ICR_OPT_MASK               GENMASK(23, 16)
-#define QSPI_ICR_OPT(opt)               (((opt) << 16) & QSPI_ICR_OPT_MASK)
-
-/* Bitfields in QSPI_IFR (Instruction Frame Register) */
-#define QSPI_IFR_WIDTH_MASK             GENMASK(2, 0)
-#define QSPI_IFR_WIDTH_SINGLE_BIT_SPI   (0 << 0)
-#define QSPI_IFR_WIDTH_DUAL_OUTPUT      (1 << 0)
-#define QSPI_IFR_WIDTH_QUAD_OUTPUT      (2 << 0)
-#define QSPI_IFR_WIDTH_DUAL_IO          (3 << 0)
-#define QSPI_IFR_WIDTH_QUAD_IO          (4 << 0)
-#define QSPI_IFR_WIDTH_DUAL_CMD         (5 << 0)
-#define QSPI_IFR_WIDTH_QUAD_CMD         (6 << 0)
-#define QSPI_IFR_INSTEN                 BIT(4)
-#define QSPI_IFR_ADDREN                 BIT(5)
-#define QSPI_IFR_OPTEN                  BIT(6)
-#define QSPI_IFR_DATAEN                 BIT(7)
-#define QSPI_IFR_OPTL_MASK              GENMASK(9, 8)
-#define QSPI_IFR_OPTL_1BIT              (0 << 8)
-#define QSPI_IFR_OPTL_2BIT              (1 << 8)
-#define QSPI_IFR_OPTL_4BIT              (2 << 8)
-#define QSPI_IFR_OPTL_8BIT              (3 << 8)
-#define QSPI_IFR_ADDRL                  BIT(10)
-#define QSPI_IFR_TFRTYP_MASK            GENMASK(13, 12)
-#define QSPI_IFR_TFRTYP_TRSFR_READ      (0 << 12)
-#define QSPI_IFR_TFRTYP_TRSFR_READ_MEM  (1 << 12)
-#define QSPI_IFR_TFRTYP_TRSFR_WRITE     (2 << 12)
-#define QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM (3 << 13)
-#define QSPI_IFR_CRM                    BIT(14)
-#define QSPI_IFR_NBDUM_MASK             GENMASK(20, 16)
-#define QSPI_IFR_NBDUM(n)               (((n) << 16) & QSPI_IFR_NBDUM_MASK)
-
-/* Bitfields in QSPI_SMR (Scrambling Mode Register) */
-#define QSPI_SMR_SCREN                  BIT(0)
-#define QSPI_SMR_RVDIS                  BIT(1)
-
-/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
-#define QSPI_WPMR_WPEN                  BIT(0)
-#define QSPI_WPMR_WPKEY_MASK            GENMASK(31, 8)
-#define QSPI_WPMR_WPKEY(wpkey)          (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
-
-/* Bitfields in QSPI_WPSR (Write Protection Status Register) */
-#define QSPI_WPSR_WPVS                  BIT(0)
-#define QSPI_WPSR_WPVSRC_MASK           GENMASK(15, 8)
-#define QSPI_WPSR_WPVSRC(src)           (((src) << 8) & QSPI_WPSR_WPVSRC)
-
-
-struct atmel_qspi {
-       void __iomem            *regs;
-       void __iomem            *mem;
-       struct clk              *clk;
-       struct platform_device  *pdev;
-       u32                     pending;
-
-       struct spi_nor          nor;
-       u32                     clk_rate;
-       struct completion       cmd_completion;
-};
-
-struct atmel_qspi_command {
-       union {
-               struct {
-                       u32     instruction:1;
-                       u32     address:3;
-                       u32     mode:1;
-                       u32     dummy:1;
-                       u32     data:1;
-                       u32     reserved:25;
-               }               bits;
-               u32     word;
-       }       enable;
-       u8      instruction;
-       u8      mode;
-       u8      num_mode_cycles;
-       u8      num_dummy_cycles;
-       u32     address;
-
-       size_t          buf_len;
-       const void      *tx_buf;
-       void            *rx_buf;
-};
-
-/* Register access functions */
-static inline u32 qspi_readl(struct atmel_qspi *aq, u32 reg)
-{
-       return readl_relaxed(aq->regs + reg);
-}
-
-static inline void qspi_writel(struct atmel_qspi *aq, u32 reg, u32 value)
-{
-       writel_relaxed(value, aq->regs + reg);
-}
-
-static int atmel_qspi_run_transfer(struct atmel_qspi *aq,
-                                  const struct atmel_qspi_command *cmd)
-{
-       void __iomem *ahb_mem;
-
-       /* Then fallback to a PIO transfer (memcpy() DOES NOT work!) */
-       ahb_mem = aq->mem;
-       if (cmd->enable.bits.address)
-               ahb_mem += cmd->address;
-       if (cmd->tx_buf)
-               _memcpy_toio(ahb_mem, cmd->tx_buf, cmd->buf_len);
-       else
-               _memcpy_fromio(cmd->rx_buf, ahb_mem, cmd->buf_len);
-
-       return 0;
-}
-
-#ifdef DEBUG
-static void atmel_qspi_debug_command(struct atmel_qspi *aq,
-                                    const struct atmel_qspi_command *cmd,
-                                    u32 ifr)
-{
-       u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
-       size_t len = 0;
-       int i;
-
-       if (cmd->enable.bits.instruction)
-               cmd_buf[len++] = cmd->instruction;
-
-       for (i = cmd->enable.bits.address-1; i >= 0; --i)
-               cmd_buf[len++] = (cmd->address >> (i << 3)) & 0xff;
-
-       if (cmd->enable.bits.mode)
-               cmd_buf[len++] = cmd->mode;
-
-       if (cmd->enable.bits.dummy) {
-               int num = cmd->num_dummy_cycles;
-
-               switch (ifr & QSPI_IFR_WIDTH_MASK) {
-               case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
-               case QSPI_IFR_WIDTH_DUAL_OUTPUT:
-               case QSPI_IFR_WIDTH_QUAD_OUTPUT:
-                       num >>= 3;
-                       break;
-               case QSPI_IFR_WIDTH_DUAL_IO:
-               case QSPI_IFR_WIDTH_DUAL_CMD:
-                       num >>= 2;
-                       break;
-               case QSPI_IFR_WIDTH_QUAD_IO:
-               case QSPI_IFR_WIDTH_QUAD_CMD:
-                       num >>= 1;
-                       break;
-               default:
-                       return;
-               }
-
-               for (i = 0; i < num; ++i)
-                       cmd_buf[len++] = 0;
-       }
-
-       /* Dump the SPI command */
-       print_hex_dump(KERN_DEBUG, "qspi cmd: ", DUMP_PREFIX_NONE,
-                      32, 1, cmd_buf, len, false);
-
-#ifdef VERBOSE_DEBUG
-       /* If verbose debug is enabled, also dump the TX data */
-       if (cmd->enable.bits.data && cmd->tx_buf)
-               print_hex_dump(KERN_DEBUG, "qspi tx : ", DUMP_PREFIX_NONE,
-                              32, 1, cmd->tx_buf, cmd->buf_len, false);
-#endif
-}
-#else
-#define atmel_qspi_debug_command(aq, cmd, ifr)
-#endif
-
-static int atmel_qspi_run_command(struct atmel_qspi *aq,
-                                 const struct atmel_qspi_command *cmd,
-                                 u32 ifr_tfrtyp, enum spi_nor_protocol proto)
-{
-       u32 iar, icr, ifr, sr;
-       int err = 0;
-
-       iar = 0;
-       icr = 0;
-       ifr = ifr_tfrtyp;
-
-       /* Set the SPI protocol */
-       switch (proto) {
-       case SNOR_PROTO_1_1_1:
-               ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
-               break;
-
-       case SNOR_PROTO_1_1_2:
-               ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
-               break;
-
-       case SNOR_PROTO_1_1_4:
-               ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
-               break;
-
-       case SNOR_PROTO_1_2_2:
-               ifr |= QSPI_IFR_WIDTH_DUAL_IO;
-               break;
-
-       case SNOR_PROTO_1_4_4:
-               ifr |= QSPI_IFR_WIDTH_QUAD_IO;
-               break;
-
-       case SNOR_PROTO_2_2_2:
-               ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
-               break;
-
-       case SNOR_PROTO_4_4_4:
-               ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       /* Compute instruction parameters */
-       if (cmd->enable.bits.instruction) {
-               icr |= QSPI_ICR_INST(cmd->instruction);
-               ifr |= QSPI_IFR_INSTEN;
-       }
-
-       /* Compute address parameters */
-       switch (cmd->enable.bits.address) {
-       case 4:
-               ifr |= QSPI_IFR_ADDRL;
-               /* fall through to the 24bit (3 byte) address case. */
-       case 3:
-               iar = (cmd->enable.bits.data) ? 0 : cmd->address;
-               ifr |= QSPI_IFR_ADDREN;
-               break;
-       case 0:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Compute option parameters */
-       if (cmd->enable.bits.mode && cmd->num_mode_cycles) {
-               u32 mode_cycle_bits, mode_bits;
-
-               icr |= QSPI_ICR_OPT(cmd->mode);
-               ifr |= QSPI_IFR_OPTEN;
-
-               switch (ifr & QSPI_IFR_WIDTH_MASK) {
-               case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
-               case QSPI_IFR_WIDTH_DUAL_OUTPUT:
-               case QSPI_IFR_WIDTH_QUAD_OUTPUT:
-                       mode_cycle_bits = 1;
-                       break;
-               case QSPI_IFR_WIDTH_DUAL_IO:
-               case QSPI_IFR_WIDTH_DUAL_CMD:
-                       mode_cycle_bits = 2;
-                       break;
-               case QSPI_IFR_WIDTH_QUAD_IO:
-               case QSPI_IFR_WIDTH_QUAD_CMD:
-                       mode_cycle_bits = 4;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
-               switch (mode_bits) {
-               case 1:
-                       ifr |= QSPI_IFR_OPTL_1BIT;
-                       break;
-
-               case 2:
-                       ifr |= QSPI_IFR_OPTL_2BIT;
-                       break;
-
-               case 4:
-                       ifr |= QSPI_IFR_OPTL_4BIT;
-                       break;
-
-               case 8:
-                       ifr |= QSPI_IFR_OPTL_8BIT;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-       }
-
-       /* Set number of dummy cycles */
-       if (cmd->enable.bits.dummy)
-               ifr |= QSPI_IFR_NBDUM(cmd->num_dummy_cycles);
-
-       /* Set data enable */
-       if (cmd->enable.bits.data) {
-               ifr |= QSPI_IFR_DATAEN;
-
-               /* Special case for Continuous Read Mode */
-               if (!cmd->tx_buf && !cmd->rx_buf)
-                       ifr |= QSPI_IFR_CRM;
-       }
-
-       /* Clear pending interrupts */
-       (void)qspi_readl(aq, QSPI_SR);
-
-       /* Set QSPI Instruction Frame registers */
-       atmel_qspi_debug_command(aq, cmd, ifr);
-       qspi_writel(aq, QSPI_IAR, iar);
-       qspi_writel(aq, QSPI_ICR, icr);
-       qspi_writel(aq, QSPI_IFR, ifr);
-
-       /* Skip to the final steps if there is no data */
-       if (!cmd->enable.bits.data)
-               goto no_data;
-
-       /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
-       (void)qspi_readl(aq, QSPI_IFR);
-
-       /* Stop here for continuous read */
-       if (!cmd->tx_buf && !cmd->rx_buf)
-               return 0;
-       /* Send/Receive data */
-       err = atmel_qspi_run_transfer(aq, cmd);
-
-       /* Release the chip-select */
-       qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
-
-       if (err)
-               return err;
-
-#if defined(DEBUG) && defined(VERBOSE_DEBUG)
-       /*
-        * If verbose debug is enabled, also dump the RX data in addition to
-        * the SPI command previously dumped by atmel_qspi_debug_command()
-        */
-       if (cmd->rx_buf)
-               print_hex_dump(KERN_DEBUG, "qspi rx : ", DUMP_PREFIX_NONE,
-                              32, 1, cmd->rx_buf, cmd->buf_len, false);
-#endif
-no_data:
-       /* Poll INSTRuction End status */
-       sr = qspi_readl(aq, QSPI_SR);
-       if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
-               return err;
-
-       /* Wait for INSTRuction End interrupt */
-       reinit_completion(&aq->cmd_completion);
-       aq->pending = sr & QSPI_SR_CMD_COMPLETED;
-       qspi_writel(aq, QSPI_IER, QSPI_SR_CMD_COMPLETED);
-       if (!wait_for_completion_timeout(&aq->cmd_completion,
-                                        msecs_to_jiffies(1000)))
-               err = -ETIMEDOUT;
-       qspi_writel(aq, QSPI_IDR, QSPI_SR_CMD_COMPLETED);
-
-       return err;
-}
-
-static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
-                              u8 *buf, int len)
-{
-       struct atmel_qspi *aq = nor->priv;
-       struct atmel_qspi_command cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.enable.bits.instruction = 1;
-       cmd.enable.bits.data = 1;
-       cmd.instruction = opcode;
-       cmd.rx_buf = buf;
-       cmd.buf_len = len;
-       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
-                                     nor->reg_proto);
-}
-
-static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
-                               u8 *buf, int len)
-{
-       struct atmel_qspi *aq = nor->priv;
-       struct atmel_qspi_command cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.enable.bits.instruction = 1;
-       cmd.enable.bits.data = (buf != NULL && len > 0);
-       cmd.instruction = opcode;
-       cmd.tx_buf = buf;
-       cmd.buf_len = len;
-       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-                                     nor->reg_proto);
-}
-
-static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
-                               const u_char *write_buf)
-{
-       struct atmel_qspi *aq = nor->priv;
-       struct atmel_qspi_command cmd;
-       ssize_t ret;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.enable.bits.instruction = 1;
-       cmd.enable.bits.address = nor->addr_width;
-       cmd.enable.bits.data = 1;
-       cmd.instruction = nor->program_opcode;
-       cmd.address = (u32)to;
-       cmd.tx_buf = write_buf;
-       cmd.buf_len = len;
-       ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
-                                    nor->write_proto);
-       return (ret < 0) ? ret : len;
-}
-
-static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
-{
-       struct atmel_qspi *aq = nor->priv;
-       struct atmel_qspi_command cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.enable.bits.instruction = 1;
-       cmd.enable.bits.address = nor->addr_width;
-       cmd.instruction = nor->erase_opcode;
-       cmd.address = (u32)offs;
-       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
-                                     nor->reg_proto);
-}
-
-static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
-                              u_char *read_buf)
-{
-       struct atmel_qspi *aq = nor->priv;
-       struct atmel_qspi_command cmd;
-       u8 num_mode_cycles, num_dummy_cycles;
-       ssize_t ret;
-
-       if (nor->read_dummy >= 2) {
-               num_mode_cycles = 2;
-               num_dummy_cycles = nor->read_dummy - 2;
-       } else {
-               num_mode_cycles = nor->read_dummy;
-               num_dummy_cycles = 0;
-       }
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.enable.bits.instruction = 1;
-       cmd.enable.bits.address = nor->addr_width;
-       cmd.enable.bits.mode = (num_mode_cycles > 0);
-       cmd.enable.bits.dummy = (num_dummy_cycles > 0);
-       cmd.enable.bits.data = 1;
-       cmd.instruction = nor->read_opcode;
-       cmd.address = (u32)from;
-       cmd.mode = 0xff; /* This value prevents from entering the 0-4-4 mode */
-       cmd.num_mode_cycles = num_mode_cycles;
-       cmd.num_dummy_cycles = num_dummy_cycles;
-       cmd.rx_buf = read_buf;
-       cmd.buf_len = len;
-       ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
-                                    nor->read_proto);
-       return (ret < 0) ? ret : len;
-}
-
-static int atmel_qspi_init(struct atmel_qspi *aq)
-{
-       unsigned long src_rate;
-       u32 mr, scr, scbr;
-
-       /* Reset the QSPI controller */
-       qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
-
-       /* Set the QSPI controller in Serial Memory Mode */
-       mr = QSPI_MR_NBBITS(8) | QSPI_MR_SSM;
-       qspi_writel(aq, QSPI_MR, mr);
-
-       src_rate = clk_get_rate(aq->clk);
-       if (!src_rate)
-               return -EINVAL;
-
-       /* Compute the QSPI baudrate */
-       scbr = DIV_ROUND_UP(src_rate, aq->clk_rate);
-       if (scbr > 0)
-               scbr--;
-       scr = QSPI_SCR_SCBR(scbr);
-       qspi_writel(aq, QSPI_SCR, scr);
-
-       /* Enable the QSPI controller */
-       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
-
-       return 0;
-}
-
-static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
-{
-       struct atmel_qspi *aq = (struct atmel_qspi *)dev_id;
-       u32 status, mask, pending;
-
-       status = qspi_readl(aq, QSPI_SR);
-       mask = qspi_readl(aq, QSPI_IMR);
-       pending = status & mask;
-
-       if (!pending)
-               return IRQ_NONE;
-
-       aq->pending |= pending;
-       if ((aq->pending & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
-               complete(&aq->cmd_completion);
-
-       return IRQ_HANDLED;
-}
-
-static int atmel_qspi_probe(struct platform_device *pdev)
-{
-       const struct spi_nor_hwcaps hwcaps = {
-               .mask = SNOR_HWCAPS_READ |
-                       SNOR_HWCAPS_READ_FAST |
-                       SNOR_HWCAPS_READ_1_1_2 |
-                       SNOR_HWCAPS_READ_1_2_2 |
-                       SNOR_HWCAPS_READ_2_2_2 |
-                       SNOR_HWCAPS_READ_1_1_4 |
-                       SNOR_HWCAPS_READ_1_4_4 |
-                       SNOR_HWCAPS_READ_4_4_4 |
-                       SNOR_HWCAPS_PP |
-                       SNOR_HWCAPS_PP_1_1_4 |
-                       SNOR_HWCAPS_PP_1_4_4 |
-                       SNOR_HWCAPS_PP_4_4_4,
-       };
-       struct device_node *child, *np = pdev->dev.of_node;
-       struct atmel_qspi *aq;
-       struct resource *res;
-       struct spi_nor *nor;
-       struct mtd_info *mtd;
-       int irq, err = 0;
-
-       if (of_get_child_count(np) != 1)
-               return -ENODEV;
-       child = of_get_next_child(np, NULL);
-
-       aq = devm_kzalloc(&pdev->dev, sizeof(*aq), GFP_KERNEL);
-       if (!aq) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       platform_set_drvdata(pdev, aq);
-       init_completion(&aq->cmd_completion);
-       aq->pdev = pdev;
-
-       /* Map the registers */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
-       aq->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(aq->regs)) {
-               dev_err(&pdev->dev, "missing registers\n");
-               err = PTR_ERR(aq->regs);
-               goto exit;
-       }
-
-       /* Map the AHB memory */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap");
-       aq->mem = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(aq->mem)) {
-               dev_err(&pdev->dev, "missing AHB memory\n");
-               err = PTR_ERR(aq->mem);
-               goto exit;
-       }
-
-       /* Get the peripheral clock */
-       aq->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(aq->clk)) {
-               dev_err(&pdev->dev, "missing peripheral clock\n");
-               err = PTR_ERR(aq->clk);
-               goto exit;
-       }
-
-       /* Enable the peripheral clock */
-       err = clk_prepare_enable(aq->clk);
-       if (err) {
-               dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
-               goto exit;
-       }
-
-       /* Request the IRQ */
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ\n");
-               err = irq;
-               goto disable_clk;
-       }
-       err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
-                              0, dev_name(&pdev->dev), aq);
-       if (err)
-               goto disable_clk;
-
-       /* Setup the spi-nor */
-       nor = &aq->nor;
-       mtd = &nor->mtd;
-
-       nor->dev = &pdev->dev;
-       spi_nor_set_flash_node(nor, child);
-       nor->priv = aq;
-       mtd->priv = nor;
-
-       nor->read_reg = atmel_qspi_read_reg;
-       nor->write_reg = atmel_qspi_write_reg;
-       nor->read = atmel_qspi_read;
-       nor->write = atmel_qspi_write;
-       nor->erase = atmel_qspi_erase;
-
-       err = of_property_read_u32(child, "spi-max-frequency", &aq->clk_rate);
-       if (err < 0)
-               goto disable_clk;
-
-       err = atmel_qspi_init(aq);
-       if (err)
-               goto disable_clk;
-
-       err = spi_nor_scan(nor, NULL, &hwcaps);
-       if (err)
-               goto disable_clk;
-
-       err = mtd_device_register(mtd, NULL, 0);
-       if (err)
-               goto disable_clk;
-
-       of_node_put(child);
-
-       return 0;
-
-disable_clk:
-       clk_disable_unprepare(aq->clk);
-exit:
-       of_node_put(child);
-
-       return err;
-}
-
-static int atmel_qspi_remove(struct platform_device *pdev)
-{
-       struct atmel_qspi *aq = platform_get_drvdata(pdev);
-
-       mtd_device_unregister(&aq->nor.mtd);
-       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIDIS);
-       clk_disable_unprepare(aq->clk);
-       return 0;
-}
-
-static int __maybe_unused atmel_qspi_suspend(struct device *dev)
-{
-       struct atmel_qspi *aq = dev_get_drvdata(dev);
-
-       clk_disable_unprepare(aq->clk);
-
-       return 0;
-}
-
-static int __maybe_unused atmel_qspi_resume(struct device *dev)
-{
-       struct atmel_qspi *aq = dev_get_drvdata(dev);
-
-       clk_prepare_enable(aq->clk);
-
-       return atmel_qspi_init(aq);
-}
-
-static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend,
-                        atmel_qspi_resume);
-
-static const struct of_device_id atmel_qspi_dt_ids[] = {
-       { .compatible = "atmel,sama5d2-qspi" },
-       { /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, atmel_qspi_dt_ids);
-
-static struct platform_driver atmel_qspi_driver = {
-       .driver = {
-               .name   = "atmel_qspi",
-               .of_match_table = atmel_qspi_dt_ids,
-               .pm     = &atmel_qspi_pm_ops,
-       },
-       .probe          = atmel_qspi_probe,
-       .remove         = atmel_qspi_remove,
-};
-module_platform_driver(atmel_qspi_driver);
-
-MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
-MODULE_DESCRIPTION("Atmel QSPI Controller driver");
-MODULE_LICENSE("GPL v2");
index 1fdd2834fbcb164c48fb580e51cfa53fdfaddf96..6e13bbd1aaa508308790c07e914dedb011b8d591 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
  * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
  *
  * Copyright (C) 2005, Intec Automation Inc.
  * Copyright (C) 2014, Freescale Semiconductor, Inc.
- *
- * This code is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/err.h>
 #define SPI_NOR_MAX_ID_LEN     6
 #define SPI_NOR_MAX_ADDR_WIDTH 4
 
+struct spi_nor_read_command {
+       u8                      num_mode_clocks;
+       u8                      num_wait_states;
+       u8                      opcode;
+       enum spi_nor_protocol   proto;
+};
+
+struct spi_nor_pp_command {
+       u8                      opcode;
+       enum spi_nor_protocol   proto;
+};
+
+enum spi_nor_read_command_index {
+       SNOR_CMD_READ,
+       SNOR_CMD_READ_FAST,
+       SNOR_CMD_READ_1_1_1_DTR,
+
+       /* Dual SPI */
+       SNOR_CMD_READ_1_1_2,
+       SNOR_CMD_READ_1_2_2,
+       SNOR_CMD_READ_2_2_2,
+       SNOR_CMD_READ_1_2_2_DTR,
+
+       /* Quad SPI */
+       SNOR_CMD_READ_1_1_4,
+       SNOR_CMD_READ_1_4_4,
+       SNOR_CMD_READ_4_4_4,
+       SNOR_CMD_READ_1_4_4_DTR,
+
+       /* Octo SPI */
+       SNOR_CMD_READ_1_1_8,
+       SNOR_CMD_READ_1_8_8,
+       SNOR_CMD_READ_8_8_8,
+       SNOR_CMD_READ_1_8_8_DTR,
+
+       SNOR_CMD_READ_MAX
+};
+
+enum spi_nor_pp_command_index {
+       SNOR_CMD_PP,
+
+       /* Quad SPI */
+       SNOR_CMD_PP_1_1_4,
+       SNOR_CMD_PP_1_4_4,
+       SNOR_CMD_PP_4_4_4,
+
+       /* Octo SPI */
+       SNOR_CMD_PP_1_1_8,
+       SNOR_CMD_PP_1_8_8,
+       SNOR_CMD_PP_8_8_8,
+
+       SNOR_CMD_PP_MAX
+};
+
+struct spi_nor_flash_parameter {
+       u64                             size;
+       u32                             page_size;
+
+       struct spi_nor_hwcaps           hwcaps;
+       struct spi_nor_read_command     reads[SNOR_CMD_READ_MAX];
+       struct spi_nor_pp_command       page_programs[SNOR_CMD_PP_MAX];
+
+       int (*quad_enable)(struct spi_nor *nor);
+};
+
+struct sfdp_parameter_header {
+       u8              id_lsb;
+       u8              minor;
+       u8              major;
+       u8              length; /* in double words */
+       u8              parameter_table_pointer[3]; /* byte address */
+       u8              id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)        (((p)->id_msb << 8) | (p)->id_lsb)
+#define SFDP_PARAM_HEADER_PTP(p) \
+       (((p)->parameter_table_pointer[2] << 16) | \
+        ((p)->parameter_table_pointer[1] <<  8) | \
+        ((p)->parameter_table_pointer[0] <<  0))
+
+#define SFDP_BFPT_ID           0xff00  /* Basic Flash Parameter Table */
+#define SFDP_SECTOR_MAP_ID     0xff81  /* Sector Map Table */
+#define SFDP_4BAIT_ID          0xff84  /* 4-byte Address Instruction Table */
+
+#define SFDP_SIGNATURE         0x50444653U
+#define SFDP_JESD216_MAJOR     1
+#define SFDP_JESD216_MINOR     0
+#define SFDP_JESD216A_MINOR    5
+#define SFDP_JESD216B_MINOR    6
+
+struct sfdp_header {
+       u32             signature; /* Ox50444653U <=> "SFDP" */
+       u8              minor;
+       u8              major;
+       u8              nph; /* 0-base number of parameter headers */
+       u8              unused;
+
+       /* Basic Flash Parameter Table. */
+       struct sfdp_parameter_header    bfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/*
+ * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
+ * They are indexed from 1 but C arrays are indexed from 0.
+ */
+#define BFPT_DWORD(i)          ((i) - 1)
+#define BFPT_DWORD_MAX         16
+
+/* The first version of JESB216 defined only 9 DWORDs. */
+#define BFPT_DWORD_MAX_JESD216                 9
+
+/* 1st DWORD. */
+#define BFPT_DWORD1_FAST_READ_1_1_2            BIT(16)
+#define BFPT_DWORD1_ADDRESS_BYTES_MASK         GENMASK(18, 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY       (0x0UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4       (0x1UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY       (0x2UL << 17)
+#define BFPT_DWORD1_DTR                                BIT(19)
+#define BFPT_DWORD1_FAST_READ_1_2_2            BIT(20)
+#define BFPT_DWORD1_FAST_READ_1_4_4            BIT(21)
+#define BFPT_DWORD1_FAST_READ_1_1_4            BIT(22)
+
+/* 5th DWORD. */
+#define BFPT_DWORD5_FAST_READ_2_2_2            BIT(0)
+#define BFPT_DWORD5_FAST_READ_4_4_4            BIT(4)
+
+/* 11th DWORD. */
+#define BFPT_DWORD11_PAGE_SIZE_SHIFT           4
+#define BFPT_DWORD11_PAGE_SIZE_MASK            GENMASK(7, 4)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216 rev B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ *         reads based on instruction. DQ3/HOLD# functions are hold during
+ *         instruction phase.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         Writing only one byte to the status register has the side-effect of
+ *         clearing status register 2, including the QE bit. The 100b code is
+ *         used if writing one byte to the status register does not modify
+ *         status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ *         one data byte where bit 6 is one.
+ *         [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ *         register 2 instruction 3Eh with one data byte where bit 7 is one.
+ *         [...]
+ *         The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         In contrast to the 001b code, writing one byte to the status
+ *         register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ *         Read Status instruction 05h. Status register2 is read using
+ *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ */
+#define BFPT_DWORD15_QER_MASK                  GENMASK(22, 20)
+#define BFPT_DWORD15_QER_NONE                  (0x0UL << 20) /* Micron */
+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY                (0x1UL << 20)
+#define BFPT_DWORD15_QER_SR1_BIT6              (0x2UL << 20) /* Macronix */
+#define BFPT_DWORD15_QER_SR2_BIT7              (0x3UL << 20)
+#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD                (0x4UL << 20)
+#define BFPT_DWORD15_QER_SR2_BIT1              (0x5UL << 20) /* Spansion */
+
+struct sfdp_bfpt {
+       u32     dwords[BFPT_DWORD_MAX];
+};
+
+/**
+ * struct spi_nor_fixups - SPI NOR fixup hooks
+ * @post_bfpt: called after the BFPT table has been parsed
+ *
+ * Those hooks can be used to tweak the SPI NOR configuration when the SFDP
+ * table is broken or not available.
+ */
+struct spi_nor_fixups {
+       int (*post_bfpt)(struct spi_nor *nor,
+                        const struct sfdp_parameter_header *bfpt_header,
+                        const struct sfdp_bfpt *bfpt,
+                        struct spi_nor_flash_parameter *params);
+};
+
 struct flash_info {
        char            *name;
 
@@ -91,13 +279,14 @@ struct flash_info {
 #define SPI_NOR_SKIP_SFDP      BIT(13) /* Skip parsing of SFDP tables */
 #define USE_CLSR               BIT(14) /* use CLSR command */
 
+       /* Part specific fixup hooks. */
+       const struct spi_nor_fixups *fixups;
+
        int     (*quad_enable)(struct spi_nor *nor);
 };
 
 #define JEDEC_MFR(info)        ((info)->id[0])
 
-static const struct flash_info *spi_nor_match_id(const char *name);
-
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -159,7 +348,7 @@ static int read_cr(struct spi_nor *nor)
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
-static inline int write_sr(struct spi_nor *nor, u8 val)
+static int write_sr(struct spi_nor *nor, u8 val)
 {
        nor->cmd_buf[0] = val;
        return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
@@ -169,7 +358,7 @@ static inline int write_sr(struct spi_nor *nor, u8 val)
  * Set write enable latch with Write Enable command.
  * Returns negative if error occurred.
  */
-static inline int write_enable(struct spi_nor *nor)
+static int write_enable(struct spi_nor *nor)
 {
        return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
 }
@@ -177,12 +366,12 @@ static inline int write_enable(struct spi_nor *nor)
 /*
  * Send write disable instruction to the chip.
  */
-static inline int write_disable(struct spi_nor *nor)
+static int write_disable(struct spi_nor *nor)
 {
        return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
 }
 
-static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
 {
        return mtd->priv;
 }
@@ -200,7 +389,7 @@ static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
        return opcode;
 }
 
-static inline u8 spi_nor_convert_3to4_read(u8 opcode)
+static u8 spi_nor_convert_3to4_read(u8 opcode)
 {
        static const u8 spi_nor_3to4_read[][2] = {
                { SPINOR_OP_READ,       SPINOR_OP_READ_4B },
@@ -219,7 +408,7 @@ static inline u8 spi_nor_convert_3to4_read(u8 opcode)
                                      ARRAY_SIZE(spi_nor_3to4_read));
 }
 
-static inline u8 spi_nor_convert_3to4_program(u8 opcode)
+static u8 spi_nor_convert_3to4_program(u8 opcode)
 {
        static const u8 spi_nor_3to4_program[][2] = {
                { SPINOR_OP_PP,         SPINOR_OP_PP_4B },
@@ -231,7 +420,7 @@ static inline u8 spi_nor_convert_3to4_program(u8 opcode)
                                      ARRAY_SIZE(spi_nor_3to4_program));
 }
 
-static inline u8 spi_nor_convert_3to4_erase(u8 opcode)
+static u8 spi_nor_convert_3to4_erase(u8 opcode)
 {
        static const u8 spi_nor_3to4_erase[][2] = {
                { SPINOR_OP_BE_4K,      SPINOR_OP_BE_4K_4B },
@@ -243,15 +432,14 @@ static inline u8 spi_nor_convert_3to4_erase(u8 opcode)
                                      ARRAY_SIZE(spi_nor_3to4_erase));
 }
 
-static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
-                                     const struct flash_info *info)
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
 {
        /* Do some manufacturer fixups first */
-       switch (JEDEC_MFR(info)) {
+       switch (JEDEC_MFR(nor->info)) {
        case SNOR_MFR_SPANSION:
                /* No small sector erase for 4-byte command set */
                nor->erase_opcode = SPINOR_OP_SE;
-               nor->mtd.erasesize = info->sector_size;
+               nor->mtd.erasesize = nor->info->sector_size;
                break;
 
        default:
@@ -276,17 +464,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
 }
 
 /* Enable/disable 4-byte addressing mode. */
-static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
-                           int enable)
+static int set_4byte(struct spi_nor *nor, bool enable)
 {
        int status;
        bool need_wren = false;
        u8 cmd;
 
-       switch (JEDEC_MFR(info)) {
+       switch (JEDEC_MFR(nor->info)) {
+       case SNOR_MFR_ST:
        case SNOR_MFR_MICRON:
                /* Some Micron need WREN command; all will accept it */
                need_wren = true;
+               /* fall through */
        case SNOR_MFR_MACRONIX:
        case SNOR_MFR_WINBOND:
                if (need_wren)
@@ -298,7 +487,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
                        write_disable(nor);
 
                if (!status && !enable &&
-                   JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+                   JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) {
                        /*
                         * On Winbond W25Q256FV, leaving 4byte mode causes
                         * the Extended Address Register to be set to 1, so all
@@ -333,7 +522,7 @@ static int s3an_sr_ready(struct spi_nor *nor)
        return !!(val & XSR_RDY);
 }
 
-static inline int spi_nor_sr_ready(struct spi_nor *nor)
+static int spi_nor_sr_ready(struct spi_nor *nor)
 {
        int sr = read_sr(nor);
        if (sr < 0)
@@ -352,7 +541,7 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor)
        return !(sr & SR_WIP);
 }
 
-static inline int spi_nor_fsr_ready(struct spi_nor *nor)
+static int spi_nor_fsr_ready(struct spi_nor *nor)
 {
        int fsr = read_fsr(nor);
        if (fsr < 0)
@@ -1200,59 +1389,324 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return ret;
 }
 
-static int macronix_quad_enable(struct spi_nor *nor);
+/*
+ * Write status Register and configuration register with 2 bytes
+ * The first byte will be written to the status register, while the
+ * second byte will be written to the configuration register.
+ * Return negative if error occurred.
+ */
+static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
+{
+       int ret;
 
-/* Used when the "_ext_id" is two bytes at most */
-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
-               .id = {                                                 \
-                       ((_jedec_id) >> 16) & 0xff,                     \
-                       ((_jedec_id) >> 8) & 0xff,                      \
-                       (_jedec_id) & 0xff,                             \
-                       ((_ext_id) >> 8) & 0xff,                        \
-                       (_ext_id) & 0xff,                               \
-                       },                                              \
-               .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),       \
-               .sector_size = (_sector_size),                          \
-               .n_sectors = (_n_sectors),                              \
-               .page_size = 256,                                       \
-               .flags = (_flags),
+       write_enable(nor);
 
-#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)    \
-               .id = {                                                 \
-                       ((_jedec_id) >> 16) & 0xff,                     \
-                       ((_jedec_id) >> 8) & 0xff,                      \
-                       (_jedec_id) & 0xff,                             \
-                       ((_ext_id) >> 16) & 0xff,                       \
-                       ((_ext_id) >> 8) & 0xff,                        \
-                       (_ext_id) & 0xff,                               \
-                       },                                              \
-               .id_len = 6,                                            \
-               .sector_size = (_sector_size),                          \
-               .n_sectors = (_n_sectors),                              \
-               .page_size = 256,                                       \
-               .flags = (_flags),
+       ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
+       if (ret < 0) {
+               dev_err(nor->dev,
+                       "error while writing configuration register\n");
+               return -EINVAL;
+       }
 
-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)  \
-               .sector_size = (_sector_size),                          \
-               .n_sectors = (_n_sectors),                              \
-               .page_size = (_page_size),                              \
-               .addr_width = (_addr_width),                            \
-               .flags = (_flags),
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret) {
+               dev_err(nor->dev,
+                       "timeout while writing configuration register\n");
+               return ret;
+       }
 
-#define S3AN_INFO(_jedec_id, _n_sectors, _page_size)                   \
-               .id = {                                                 \
-                       ((_jedec_id) >> 16) & 0xff,                     \
-                       ((_jedec_id) >> 8) & 0xff,                      \
-                       (_jedec_id) & 0xff                              \
-                       },                                              \
-               .id_len = 3,                                            \
-               .sector_size = (8*_page_size),                          \
-               .n_sectors = (_n_sectors),                              \
-               .page_size = _page_size,                                \
-               .addr_width = 3,                                        \
-               .flags = SPI_NOR_NO_FR | SPI_S3AN,
+       return 0;
+}
 
-/* NOTE: double check command sets and memory organization when you add
+/**
+ * macronix_quad_enable() - set QE bit in Status Register.
+ * @nor:       pointer to a 'struct spi_nor'
+ *
+ * Set the Quad Enable (QE) bit in the Status Register.
+ *
+ * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int macronix_quad_enable(struct spi_nor *nor)
+{
+       int ret, val;
+
+       val = read_sr(nor);
+       if (val < 0)
+               return val;
+       if (val & SR_QUAD_EN_MX)
+               return 0;
+
+       write_enable(nor);
+
+       write_sr(nor, val | SR_QUAD_EN_MX);
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               return ret;
+
+       ret = read_sr(nor);
+       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
+               dev_err(nor->dev, "Macronix Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * spansion_quad_enable() - set QE bit in Configuraiton Register.
+ * @nor:       pointer to a 'struct spi_nor'
+ *
+ * Set the Quad Enable (QE) bit in the Configuration Register.
+ * This function is kept for legacy purpose because it has been used for a
+ * long time without anybody complaining but it should be considered as
+ * deprecated and maybe buggy.
+ * First, this function doesn't care about the previous values of the Status
+ * and Configuration Registers when it sets the QE bit (bit 1) in the
+ * Configuration Register: all other bits are cleared, which may have unwanted
+ * side effects like removing some block protections.
+ * Secondly, it uses the Read Configuration Register (35h) instruction though
+ * some very old and few memories don't support this instruction. If a pull-up
+ * resistor is present on the MISO/IO1 line, we might still be able to pass the
+ * "read back" test because the QSPI memory doesn't recognize the command,
+ * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF.
+ *
+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
+ * memories.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_quad_enable(struct spi_nor *nor)
+{
+       u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN};
+       int ret;
+
+       ret = write_sr_cr(nor, sr_cr);
+       if (ret)
+               return ret;
+
+       /* read back and check it */
+       ret = read_cr(nor);
+       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+               dev_err(nor->dev, "Spansion Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register.
+ * @nor:       pointer to a 'struct spi_nor'
+ *
+ * Set the Quad Enable (QE) bit in the Configuration Register.
+ * This function should be used with QSPI memories not supporting the Read
+ * Configuration Register (35h) instruction.
+ *
+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
+ * memories.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
+{
+       u8 sr_cr[2];
+       int ret;
+
+       /* Keep the current value of the Status Register. */
+       ret = read_sr(nor);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while reading status register\n");
+               return -EINVAL;
+       }
+       sr_cr[0] = ret;
+       sr_cr[1] = CR_QUAD_EN_SPAN;
+
+       return write_sr_cr(nor, sr_cr);
+}
+
+/**
+ * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
+ * @nor:       pointer to a 'struct spi_nor'
+ *
+ * Set the Quad Enable (QE) bit in the Configuration Register.
+ * This function should be used with QSPI memories supporting the Read
+ * Configuration Register (35h) instruction.
+ *
+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
+ * memories.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_read_cr_quad_enable(struct spi_nor *nor)
+{
+       struct device *dev = nor->dev;
+       u8 sr_cr[2];
+       int ret;
+
+       /* Check current Quad Enable bit value. */
+       ret = read_cr(nor);
+       if (ret < 0) {
+               dev_err(dev, "error while reading configuration register\n");
+               return -EINVAL;
+       }
+
+       if (ret & CR_QUAD_EN_SPAN)
+               return 0;
+
+       sr_cr[1] = ret | CR_QUAD_EN_SPAN;
+
+       /* Keep the current value of the Status Register. */
+       ret = read_sr(nor);
+       if (ret < 0) {
+               dev_err(dev, "error while reading status register\n");
+               return -EINVAL;
+       }
+       sr_cr[0] = ret;
+
+       ret = write_sr_cr(nor, sr_cr);
+       if (ret)
+               return ret;
+
+       /* Read back and check it. */
+       ret = read_cr(nor);
+       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+               dev_err(nor->dev, "Spansion Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * sr2_bit7_quad_enable() - set QE bit in Status Register 2.
+ * @nor:       pointer to a 'struct spi_nor'
+ *
+ * Set the Quad Enable (QE) bit in the Status Register 2.
+ *
+ * This is one of the procedures to set the QE bit described in the SFDP
+ * (JESD216 rev B) specification but no manufacturer using this procedure has
+ * been identified yet, hence the name of the function.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int sr2_bit7_quad_enable(struct spi_nor *nor)
+{
+       u8 sr2;
+       int ret;
+
+       /* Check current Quad Enable bit value. */
+       ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+       if (ret)
+               return ret;
+       if (sr2 & SR2_QUAD_EN_BIT7)
+               return 0;
+
+       /* Update the Quad Enable bit. */
+       sr2 |= SR2_QUAD_EN_BIT7;
+
+       write_enable(nor);
+
+       ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while writing status register 2\n");
+               return -EINVAL;
+       }
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret < 0) {
+               dev_err(nor->dev, "timeout while writing status register 2\n");
+               return ret;
+       }
+
+       /* Read back and check it. */
+       ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+       if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) {
+               dev_err(nor->dev, "SR2 Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Used when the "_ext_id" is two bytes at most */
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
+               .id = {                                                 \
+                       ((_jedec_id) >> 16) & 0xff,                     \
+                       ((_jedec_id) >> 8) & 0xff,                      \
+                       (_jedec_id) & 0xff,                             \
+                       ((_ext_id) >> 8) & 0xff,                        \
+                       (_ext_id) & 0xff,                               \
+                       },                                              \
+               .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),       \
+               .sector_size = (_sector_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = 256,                                       \
+               .flags = (_flags),
+
+#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)    \
+               .id = {                                                 \
+                       ((_jedec_id) >> 16) & 0xff,                     \
+                       ((_jedec_id) >> 8) & 0xff,                      \
+                       (_jedec_id) & 0xff,                             \
+                       ((_ext_id) >> 16) & 0xff,                       \
+                       ((_ext_id) >> 8) & 0xff,                        \
+                       (_ext_id) & 0xff,                               \
+                       },                                              \
+               .id_len = 6,                                            \
+               .sector_size = (_sector_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = 256,                                       \
+               .flags = (_flags),
+
+#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)  \
+               .sector_size = (_sector_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = (_page_size),                              \
+               .addr_width = (_addr_width),                            \
+               .flags = (_flags),
+
+#define S3AN_INFO(_jedec_id, _n_sectors, _page_size)                   \
+               .id = {                                                 \
+                       ((_jedec_id) >> 16) & 0xff,                     \
+                       ((_jedec_id) >> 8) & 0xff,                      \
+                       (_jedec_id) & 0xff                              \
+                       },                                              \
+               .id_len = 3,                                            \
+               .sector_size = (8*_page_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = _page_size,                                \
+               .addr_width = 3,                                        \
+               .flags = SPI_NOR_NO_FR | SPI_S3AN,
+
+static int
+mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
+                           const struct sfdp_parameter_header *bfpt_header,
+                           const struct sfdp_bfpt *bfpt,
+                           struct spi_nor_flash_parameter *params)
+{
+       /*
+        * MX25L25635F supports 4B opcodes but MX25L25635E does not.
+        * Unfortunately, Macronix has re-used the same JEDEC ID for both
+        * variants which prevents us from defining a new entry in the parts
+        * table.
+        * We need a way to differentiate MX25L25635E and MX25L25635F, and it
+        * seems that the F version advertises support for Fast Read 4-4-4 in
+        * its BFPT table.
+        */
+       if (bfpt->dwords[BFPT_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
+               nor->flags |= SNOR_F_4B_OPCODES;
+
+       return 0;
+}
+
+static struct spi_nor_fixups mx25l25635_fixups = {
+       .post_bfpt = mx25l25635_post_bfpt_fixups,
+};
+
+/* NOTE: double check command sets and memory organization when you add
  * more nor chips.  This current list focusses on newer chips, which
  * have been converging on command sets which including JEDEC ID.
  *
@@ -1352,12 +1806,19 @@ static const struct flash_info spi_nor_ids[] = {
        { "is25cd512",  INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
        { "is25lq040b", INFO(0x9d4013, 0, 64 * 1024,   8,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "is25lp016d", INFO(0x9d6015, 0, 64 * 1024,  32,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "is25lp080d", INFO(0x9d6014, 0, 64 * 1024,  16,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "is25lp032",  INFO(0x9d6016, 0, 64 * 1024,  64,
+                       SECT_4K | SPI_NOR_DUAL_READ) },
+       { "is25lp064",  INFO(0x9d6017, 0, 64 * 1024, 128,
+                       SECT_4K | SPI_NOR_DUAL_READ) },
        { "is25lp128",  INFO(0x9d6018, 0, 64 * 1024, 256,
                        SECT_4K | SPI_NOR_DUAL_READ) },
        { "is25lp256",  INFO(0x9d6019, 0, 64 * 1024, 512,
-                       SECT_4K | SPI_NOR_DUAL_READ) },
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_4B_OPCODES) },
        { "is25wp032",  INFO(0x9d7016, 0, 64 * 1024,  64,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "is25wp064",  INFO(0x9d7017, 0, 64 * 1024, 128,
@@ -1380,7 +1841,11 @@ static const struct flash_info spi_nor_ids[] = {
        { "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
        { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
        { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
-       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
+                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512,
+                        SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+                        .fixups = &mx25l25635_fixups },
        { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
        { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
@@ -1388,7 +1853,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 
-       /* Micron */
+       /* Micron <--> ST Micro */
        { "n25q016a",    INFO(0x20bb15, 0, 64 * 1024,   32, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q032",     INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
        { "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
@@ -1404,6 +1869,12 @@ static const struct flash_info spi_nor_ids[] = {
        { "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
        { "mt25qu02g",   INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 
+       /* Micron */
+       {
+               "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512,
+                       SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES)
+       },
+
        /* PMC */
        { "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
        { "pm25lv010",   INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
@@ -1531,6 +2002,11 @@ static const struct flash_info spi_nor_ids[] = {
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
                        SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
        },
+       {
+               "w25q128jv", INFO(0xef7018, 0, 64 * 1024, 256,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -1559,450 +2035,208 @@ static const struct flash_info spi_nor_ids[] = {
 };
 
 static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
-{
-       int                     tmp;
-       u8                      id[SPI_NOR_MAX_ID_LEN];
-       const struct flash_info *info;
-
-       tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
-       if (tmp < 0) {
-               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
-               return ERR_PTR(tmp);
-       }
-
-       for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
-               info = &spi_nor_ids[tmp];
-               if (info->id_len) {
-                       if (!memcmp(info->id, id, info->id_len))
-                               return &spi_nor_ids[tmp];
-               }
-       }
-       dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
-               id[0], id[1], id[2]);
-       return ERR_PTR(-ENODEV);
-}
-
-static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf)
-{
-       struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       int ret;
-
-       dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
-
-       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
-       if (ret)
-               return ret;
-
-       while (len) {
-               loff_t addr = from;
-
-               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
-                       addr = spi_nor_s3an_addr_convert(nor, addr);
-
-               ret = nor->read(nor, addr, len, buf);
-               if (ret == 0) {
-                       /* We shouldn't see 0-length reads */
-                       ret = -EIO;
-                       goto read_err;
-               }
-               if (ret < 0)
-                       goto read_err;
-
-               WARN_ON(ret > len);
-               *retlen += ret;
-               buf += ret;
-               from += ret;
-               len -= ret;
-       }
-       ret = 0;
-
-read_err:
-       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
-       return ret;
-}
-
-static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
-               size_t *retlen, const u_char *buf)
-{
-       struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       size_t actual;
-       int ret;
-
-       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
-
-       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
-       if (ret)
-               return ret;
-
-       write_enable(nor);
-
-       nor->sst_write_second = false;
-
-       actual = to % 2;
-       /* Start write from odd address. */
-       if (actual) {
-               nor->program_opcode = SPINOR_OP_BP;
-
-               /* write one byte. */
-               ret = nor->write(nor, to, 1, buf);
-               if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
-                    (int)ret);
-               ret = spi_nor_wait_till_ready(nor);
-               if (ret)
-                       goto sst_write_err;
-       }
-       to += actual;
-
-       /* Write out most of the data here. */
-       for (; actual < len - 1; actual += 2) {
-               nor->program_opcode = SPINOR_OP_AAI_WP;
-
-               /* write two bytes. */
-               ret = nor->write(nor, to, 2, buf + actual);
-               if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
-                    (int)ret);
-               ret = spi_nor_wait_till_ready(nor);
-               if (ret)
-                       goto sst_write_err;
-               to += 2;
-               nor->sst_write_second = true;
-       }
-       nor->sst_write_second = false;
-
-       write_disable(nor);
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               goto sst_write_err;
-
-       /* Write out trailing byte if it exists. */
-       if (actual != len) {
-               write_enable(nor);
-
-               nor->program_opcode = SPINOR_OP_BP;
-               ret = nor->write(nor, to, 1, buf + actual);
-               if (ret < 0)
-                       goto sst_write_err;
-               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
-                    (int)ret);
-               ret = spi_nor_wait_till_ready(nor);
-               if (ret)
-                       goto sst_write_err;
-               write_disable(nor);
-               actual += 1;
-       }
-sst_write_err:
-       *retlen += actual;
-       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
-       return ret;
-}
-
-/*
- * Write an address range to the nor chip.  Data must be written in
- * FLASH_PAGESIZE chunks.  The address range may be any size provided
- * it is within the physical boundaries.
- */
-static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
-{
-       struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       size_t page_offset, page_remain, i;
-       ssize_t ret;
-
-       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
-
-       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < len; ) {
-               ssize_t written;
-               loff_t addr = to + i;
-
-               /*
-                * If page_size is a power of two, the offset can be quickly
-                * calculated with an AND operation. On the other cases we
-                * need to do a modulus operation (more expensive).
-                * Power of two numbers have only one bit set and we can use
-                * the instruction hweight32 to detect if we need to do a
-                * modulus (do_div()) or not.
-                */
-               if (hweight32(nor->page_size) == 1) {
-                       page_offset = addr & (nor->page_size - 1);
-               } else {
-                       uint64_t aux = addr;
-
-                       page_offset = do_div(aux, nor->page_size);
-               }
-               /* the size of data remaining on the first page */
-               page_remain = min_t(size_t,
-                                   nor->page_size - page_offset, len - i);
-
-               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
-                       addr = spi_nor_s3an_addr_convert(nor, addr);
-
-               write_enable(nor);
-               ret = nor->write(nor, addr, page_remain, buf + i);
-               if (ret < 0)
-                       goto write_err;
-               written = ret;
-
-               ret = spi_nor_wait_till_ready(nor);
-               if (ret)
-                       goto write_err;
-               *retlen += written;
-               i += written;
-       }
-
-write_err:
-       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
-       return ret;
-}
-
-/**
- * macronix_quad_enable() - set QE bit in Status Register.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Status Register.
- *
- * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int macronix_quad_enable(struct spi_nor *nor)
-{
-       int ret, val;
-
-       val = read_sr(nor);
-       if (val < 0)
-               return val;
-       if (val & SR_QUAD_EN_MX)
-               return 0;
-
-       write_enable(nor);
-
-       write_sr(nor, val | SR_QUAD_EN_MX);
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               return ret;
-
-       ret = read_sr(nor);
-       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-               dev_err(nor->dev, "Macronix Quad bit not set\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
- * Write status Register and configuration register with 2 bytes
- * The first byte will be written to the status register, while the
- * second byte will be written to the configuration register.
- * Return negative if error occurred.
- */
-static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
-{
-       int ret;
-
-       write_enable(nor);
+{
+       int                     tmp;
+       u8                      id[SPI_NOR_MAX_ID_LEN];
+       const struct flash_info *info;
 
-       ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
-       if (ret < 0) {
-               dev_err(nor->dev,
-                       "error while writing configuration register\n");
-               return -EINVAL;
+       tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+       if (tmp < 0) {
+               dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+               return ERR_PTR(tmp);
        }
 
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret) {
-               dev_err(nor->dev,
-                       "timeout while writing configuration register\n");
-               return ret;
+       for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+               info = &spi_nor_ids[tmp];
+               if (info->id_len) {
+                       if (!memcmp(info->id, id, info->id_len))
+                               return &spi_nor_ids[tmp];
+               }
        }
-
-       return 0;
+       dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+               id[0], id[1], id[2]);
+       return ERR_PTR(-ENODEV);
 }
 
-/**
- * spansion_quad_enable() - set QE bit in Configuraiton Register.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Configuration Register.
- * This function is kept for legacy purpose because it has been used for a
- * long time without anybody complaining but it should be considered as
- * deprecated and maybe buggy.
- * First, this function doesn't care about the previous values of the Status
- * and Configuration Registers when it sets the QE bit (bit 1) in the
- * Configuration Register: all other bits are cleared, which may have unwanted
- * side effects like removing some block protections.
- * Secondly, it uses the Read Configuration Register (35h) instruction though
- * some very old and few memories don't support this instruction. If a pull-up
- * resistor is present on the MISO/IO1 line, we might still be able to pass the
- * "read back" test because the QSPI memory doesn't recognize the command,
- * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF.
- *
- * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
- * memories.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spansion_quad_enable(struct spi_nor *nor)
+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
 {
-       u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN};
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
        int ret;
 
-       ret = write_sr_cr(nor, sr_cr);
+       dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
        if (ret)
                return ret;
 
-       /* read back and check it */
-       ret = read_cr(nor);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
-       }
+       while (len) {
+               loff_t addr = from;
 
-       return 0;
-}
+               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
+                       addr = spi_nor_s3an_addr_convert(nor, addr);
 
-/**
- * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Configuration Register.
- * This function should be used with QSPI memories not supporting the Read
- * Configuration Register (35h) instruction.
- *
- * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
- * memories.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
-{
-       u8 sr_cr[2];
-       int ret;
+               ret = nor->read(nor, addr, len, buf);
+               if (ret == 0) {
+                       /* We shouldn't see 0-length reads */
+                       ret = -EIO;
+                       goto read_err;
+               }
+               if (ret < 0)
+                       goto read_err;
 
-       /* Keep the current value of the Status Register. */
-       ret = read_sr(nor);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while reading status register\n");
-               return -EINVAL;
+               WARN_ON(ret > len);
+               *retlen += ret;
+               buf += ret;
+               from += ret;
+               len -= ret;
        }
-       sr_cr[0] = ret;
-       sr_cr[1] = CR_QUAD_EN_SPAN;
+       ret = 0;
 
-       return write_sr_cr(nor, sr_cr);
+read_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+       return ret;
 }
 
-/**
- * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Configuration Register.
- * This function should be used with QSPI memories supporting the Read
- * Configuration Register (35h) instruction.
- *
- * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
- * memories.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spansion_read_cr_quad_enable(struct spi_nor *nor)
+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+               size_t *retlen, const u_char *buf)
 {
-       struct device *dev = nor->dev;
-       u8 sr_cr[2];
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       size_t actual;
        int ret;
 
-       /* Check current Quad Enable bit value. */
-       ret = read_cr(nor);
-       if (ret < 0) {
-               dev_err(dev, "error while reading configuration register\n");
-               return -EINVAL;
-       }
+       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
 
-       if (ret & CR_QUAD_EN_SPAN)
-               return 0;
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+       if (ret)
+               return ret;
 
-       sr_cr[1] = ret | CR_QUAD_EN_SPAN;
+       write_enable(nor);
 
-       /* Keep the current value of the Status Register. */
-       ret = read_sr(nor);
-       if (ret < 0) {
-               dev_err(dev, "error while reading status register\n");
-               return -EINVAL;
+       nor->sst_write_second = false;
+
+       actual = to % 2;
+       /* Start write from odd address. */
+       if (actual) {
+               nor->program_opcode = SPINOR_OP_BP;
+
+               /* write one byte. */
+               ret = nor->write(nor, to, 1, buf);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+                    (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+                       goto sst_write_err;
        }
-       sr_cr[0] = ret;
+       to += actual;
 
-       ret = write_sr_cr(nor, sr_cr);
-       if (ret)
-               return ret;
+       /* Write out most of the data here. */
+       for (; actual < len - 1; actual += 2) {
+               nor->program_opcode = SPINOR_OP_AAI_WP;
 
-       /* Read back and check it. */
-       ret = read_cr(nor);
-       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-               dev_err(nor->dev, "Spansion Quad bit not set\n");
-               return -EINVAL;
+               /* write two bytes. */
+               ret = nor->write(nor, to, 2, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
+                    (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+                       goto sst_write_err;
+               to += 2;
+               nor->sst_write_second = true;
        }
+       nor->sst_write_second = false;
 
-       return 0;
+       write_disable(nor);
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               goto sst_write_err;
+
+       /* Write out trailing byte if it exists. */
+       if (actual != len) {
+               write_enable(nor);
+
+               nor->program_opcode = SPINOR_OP_BP;
+               ret = nor->write(nor, to, 1, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+                    (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+                       goto sst_write_err;
+               write_disable(nor);
+               actual += 1;
+       }
+sst_write_err:
+       *retlen += actual;
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
 }
 
-/**
- * sr2_bit7_quad_enable() - set QE bit in Status Register 2.
- * @nor:       pointer to a 'struct spi_nor'
- *
- * Set the Quad Enable (QE) bit in the Status Register 2.
- *
- * This is one of the procedures to set the QE bit described in the SFDP
- * (JESD216 rev B) specification but no manufacturer using this procedure has
- * been identified yet, hence the name of the function.
- *
- * Return: 0 on success, -errno otherwise.
+/*
+ * Write an address range to the nor chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
  */
-static int sr2_bit7_quad_enable(struct spi_nor *nor)
+static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
 {
-       u8 sr2;
-       int ret;
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       size_t page_offset, page_remain, i;
+       ssize_t ret;
 
-       /* Check current Quad Enable bit value. */
-       ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
+       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
        if (ret)
                return ret;
-       if (sr2 & SR2_QUAD_EN_BIT7)
-               return 0;
 
-       /* Update the Quad Enable bit. */
-       sr2 |= SR2_QUAD_EN_BIT7;
+       for (i = 0; i < len; ) {
+               ssize_t written;
+               loff_t addr = to + i;
 
-       write_enable(nor);
+               /*
+                * If page_size is a power of two, the offset can be quickly
+                * calculated with an AND operation. On the other cases we
+                * need to do a modulus operation (more expensive).
+                * Power of two numbers have only one bit set and we can use
+                * the instruction hweight32 to detect if we need to do a
+                * modulus (do_div()) or not.
+                */
+               if (hweight32(nor->page_size) == 1) {
+                       page_offset = addr & (nor->page_size - 1);
+               } else {
+                       uint64_t aux = addr;
 
-       ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while writing status register 2\n");
-               return -EINVAL;
-       }
+                       page_offset = do_div(aux, nor->page_size);
+               }
+               /* the size of data remaining on the first page */
+               page_remain = min_t(size_t,
+                                   nor->page_size - page_offset, len - i);
 
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret < 0) {
-               dev_err(nor->dev, "timeout while writing status register 2\n");
-               return ret;
-       }
+               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
+                       addr = spi_nor_s3an_addr_convert(nor, addr);
 
-       /* Read back and check it. */
-       ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
-       if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) {
-               dev_err(nor->dev, "SR2 Quad bit not set\n");
-               return -EINVAL;
+               write_enable(nor);
+               ret = nor->write(nor, addr, page_remain, buf + i);
+               if (ret < 0)
+                       goto write_err;
+               written = ret;
+
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+                       goto write_err;
+               *retlen += written;
+               i += written;
        }
 
-       return 0;
+write_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
 }
 
 static int spi_nor_check(struct spi_nor *nor)
@@ -2016,7 +2250,7 @@ static int spi_nor_check(struct spi_nor *nor)
        return 0;
 }
 
-static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
+static int s3an_nor_scan(struct spi_nor *nor)
 {
        int ret;
        u8 val;
@@ -2047,7 +2281,7 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
                /* Flash in Power of 2 mode */
                nor->page_size = (nor->page_size == 264) ? 256 : 512;
                nor->mtd.writebufsize = nor->page_size;
-               nor->mtd.size = 8 * nor->page_size * info->n_sectors;
+               nor->mtd.size = 8 * nor->page_size * nor->info->n_sectors;
                nor->mtd.erasesize = 8 * nor->page_size;
        } else {
                /* Flash in Default addressing mode */
@@ -2057,71 +2291,6 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
        return 0;
 }
 
-struct spi_nor_read_command {
-       u8                      num_mode_clocks;
-       u8                      num_wait_states;
-       u8                      opcode;
-       enum spi_nor_protocol   proto;
-};
-
-struct spi_nor_pp_command {
-       u8                      opcode;
-       enum spi_nor_protocol   proto;
-};
-
-enum spi_nor_read_command_index {
-       SNOR_CMD_READ,
-       SNOR_CMD_READ_FAST,
-       SNOR_CMD_READ_1_1_1_DTR,
-
-       /* Dual SPI */
-       SNOR_CMD_READ_1_1_2,
-       SNOR_CMD_READ_1_2_2,
-       SNOR_CMD_READ_2_2_2,
-       SNOR_CMD_READ_1_2_2_DTR,
-
-       /* Quad SPI */
-       SNOR_CMD_READ_1_1_4,
-       SNOR_CMD_READ_1_4_4,
-       SNOR_CMD_READ_4_4_4,
-       SNOR_CMD_READ_1_4_4_DTR,
-
-       /* Octo SPI */
-       SNOR_CMD_READ_1_1_8,
-       SNOR_CMD_READ_1_8_8,
-       SNOR_CMD_READ_8_8_8,
-       SNOR_CMD_READ_1_8_8_DTR,
-
-       SNOR_CMD_READ_MAX
-};
-
-enum spi_nor_pp_command_index {
-       SNOR_CMD_PP,
-
-       /* Quad SPI */
-       SNOR_CMD_PP_1_1_4,
-       SNOR_CMD_PP_1_4_4,
-       SNOR_CMD_PP_4_4_4,
-
-       /* Octo SPI */
-       SNOR_CMD_PP_1_1_8,
-       SNOR_CMD_PP_1_8_8,
-       SNOR_CMD_PP_8_8_8,
-
-       SNOR_CMD_PP_MAX
-};
-
-struct spi_nor_flash_parameter {
-       u64                             size;
-       u32                             page_size;
-
-       struct spi_nor_hwcaps           hwcaps;
-       struct spi_nor_read_command     reads[SNOR_CMD_READ_MAX];
-       struct spi_nor_pp_command       page_programs[SNOR_CMD_PP_MAX];
-
-       int (*quad_enable)(struct spi_nor *nor);
-};
-
 static void
 spi_nor_set_read_settings(struct spi_nor_read_command *read,
                          u8 num_mode_clocks,
@@ -2144,6 +2313,57 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
        pp->proto = proto;
 }
 
+static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               if (table[i][0] == (int)hwcaps)
+                       return table[i][1];
+
+       return -EINVAL;
+}
+
+static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
+{
+       static const int hwcaps_read2cmd[][2] = {
+               { SNOR_HWCAPS_READ,             SNOR_CMD_READ },
+               { SNOR_HWCAPS_READ_FAST,        SNOR_CMD_READ_FAST },
+               { SNOR_HWCAPS_READ_1_1_1_DTR,   SNOR_CMD_READ_1_1_1_DTR },
+               { SNOR_HWCAPS_READ_1_1_2,       SNOR_CMD_READ_1_1_2 },
+               { SNOR_HWCAPS_READ_1_2_2,       SNOR_CMD_READ_1_2_2 },
+               { SNOR_HWCAPS_READ_2_2_2,       SNOR_CMD_READ_2_2_2 },
+               { SNOR_HWCAPS_READ_1_2_2_DTR,   SNOR_CMD_READ_1_2_2_DTR },
+               { SNOR_HWCAPS_READ_1_1_4,       SNOR_CMD_READ_1_1_4 },
+               { SNOR_HWCAPS_READ_1_4_4,       SNOR_CMD_READ_1_4_4 },
+               { SNOR_HWCAPS_READ_4_4_4,       SNOR_CMD_READ_4_4_4 },
+               { SNOR_HWCAPS_READ_1_4_4_DTR,   SNOR_CMD_READ_1_4_4_DTR },
+               { SNOR_HWCAPS_READ_1_1_8,       SNOR_CMD_READ_1_1_8 },
+               { SNOR_HWCAPS_READ_1_8_8,       SNOR_CMD_READ_1_8_8 },
+               { SNOR_HWCAPS_READ_8_8_8,       SNOR_CMD_READ_8_8_8 },
+               { SNOR_HWCAPS_READ_1_8_8_DTR,   SNOR_CMD_READ_1_8_8_DTR },
+       };
+
+       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
+                                 ARRAY_SIZE(hwcaps_read2cmd));
+}
+
+static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
+{
+       static const int hwcaps_pp2cmd[][2] = {
+               { SNOR_HWCAPS_PP,               SNOR_CMD_PP },
+               { SNOR_HWCAPS_PP_1_1_4,         SNOR_CMD_PP_1_1_4 },
+               { SNOR_HWCAPS_PP_1_4_4,         SNOR_CMD_PP_1_4_4 },
+               { SNOR_HWCAPS_PP_4_4_4,         SNOR_CMD_PP_4_4_4 },
+               { SNOR_HWCAPS_PP_1_1_8,         SNOR_CMD_PP_1_1_8 },
+               { SNOR_HWCAPS_PP_1_8_8,         SNOR_CMD_PP_1_8_8 },
+               { SNOR_HWCAPS_PP_8_8_8,         SNOR_CMD_PP_8_8_8 },
+       };
+
+       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
+                                 ARRAY_SIZE(hwcaps_pp2cmd));
+}
+
 /*
  * Serial Flash Discoverable Parameters (SFDP) parsing.
  */
@@ -2201,163 +2421,52 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
        addr_width = nor->addr_width;
        read_dummy = nor->read_dummy;
 
-       nor->read_opcode = SPINOR_OP_RDSFDP;
-       nor->addr_width = 3;
-       nor->read_dummy = 8;
-
-       ret = spi_nor_read_raw(nor, addr, len, buf);
-
-       nor->read_opcode = read_opcode;
-       nor->addr_width = addr_width;
-       nor->read_dummy = read_dummy;
-
-       return ret;
-}
-
-/**
- * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters.
- * @nor:       pointer to a 'struct spi_nor'
- * @addr:      offset in the SFDP area to start reading data from
- * @len:       number of bytes to read
- * @buf:       buffer where the SFDP data are copied into
- *
- * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not
- * guaranteed to be dma-safe.
- *
- * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp()
- *          otherwise.
- */
-static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr,
-                                       size_t len, void *buf)
-{
-       void *dma_safe_buf;
-       int ret;
-
-       dma_safe_buf = kmalloc(len, GFP_KERNEL);
-       if (!dma_safe_buf)
-               return -ENOMEM;
-
-       ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf);
-       memcpy(buf, dma_safe_buf, len);
-       kfree(dma_safe_buf);
-
-       return ret;
-}
-
-struct sfdp_parameter_header {
-       u8              id_lsb;
-       u8              minor;
-       u8              major;
-       u8              length; /* in double words */
-       u8              parameter_table_pointer[3]; /* byte address */
-       u8              id_msb;
-};
-
-#define SFDP_PARAM_HEADER_ID(p)        (((p)->id_msb << 8) | (p)->id_lsb)
-#define SFDP_PARAM_HEADER_PTP(p) \
-       (((p)->parameter_table_pointer[2] << 16) | \
-        ((p)->parameter_table_pointer[1] <<  8) | \
-        ((p)->parameter_table_pointer[0] <<  0))
-
-#define SFDP_BFPT_ID           0xff00  /* Basic Flash Parameter Table */
-#define SFDP_SECTOR_MAP_ID     0xff81  /* Sector Map Table */
-
-#define SFDP_SIGNATURE         0x50444653U
-#define SFDP_JESD216_MAJOR     1
-#define SFDP_JESD216_MINOR     0
-#define SFDP_JESD216A_MINOR    5
-#define SFDP_JESD216B_MINOR    6
-
-struct sfdp_header {
-       u32             signature; /* Ox50444653U <=> "SFDP" */
-       u8              minor;
-       u8              major;
-       u8              nph; /* 0-base number of parameter headers */
-       u8              unused;
-
-       /* Basic Flash Parameter Table. */
-       struct sfdp_parameter_header    bfpt_header;
-};
-
-/* Basic Flash Parameter Table */
-
-/*
- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
- * They are indexed from 1 but C arrays are indexed from 0.
- */
-#define BFPT_DWORD(i)          ((i) - 1)
-#define BFPT_DWORD_MAX         16
-
-/* The first version of JESB216 defined only 9 DWORDs. */
-#define BFPT_DWORD_MAX_JESD216                 9
-
-/* 1st DWORD. */
-#define BFPT_DWORD1_FAST_READ_1_1_2            BIT(16)
-#define BFPT_DWORD1_ADDRESS_BYTES_MASK         GENMASK(18, 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY       (0x0UL << 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4       (0x1UL << 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY       (0x2UL << 17)
-#define BFPT_DWORD1_DTR                                BIT(19)
-#define BFPT_DWORD1_FAST_READ_1_2_2            BIT(20)
-#define BFPT_DWORD1_FAST_READ_1_4_4            BIT(21)
-#define BFPT_DWORD1_FAST_READ_1_1_4            BIT(22)
+       nor->read_opcode = SPINOR_OP_RDSFDP;
+       nor->addr_width = 3;
+       nor->read_dummy = 8;
 
-/* 5th DWORD. */
-#define BFPT_DWORD5_FAST_READ_2_2_2            BIT(0)
-#define BFPT_DWORD5_FAST_READ_4_4_4            BIT(4)
+       ret = spi_nor_read_raw(nor, addr, len, buf);
 
-/* 11th DWORD. */
-#define BFPT_DWORD11_PAGE_SIZE_SHIFT           4
-#define BFPT_DWORD11_PAGE_SIZE_MASK            GENMASK(7, 4)
+       nor->read_opcode = read_opcode;
+       nor->addr_width = addr_width;
+       nor->read_dummy = read_dummy;
 
-/* 15th DWORD. */
+       return ret;
+}
 
-/*
- * (from JESD216 rev B)
- * Quad Enable Requirements (QER):
- * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
- *         reads based on instruction. DQ3/HOLD# functions are hold during
- *         instruction phase.
- * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
- *         Writing only one byte to the status register has the side-effect of
- *         clearing status register 2, including the QE bit. The 100b code is
- *         used if writing one byte to the status register does not modify
- *         status register 2.
- * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
- *         one data byte where bit 6 is one.
- *         [...]
- * - 011b: QE is bit 7 of status register 2. It is set via Write status
- *         register 2 instruction 3Eh with one data byte where bit 7 is one.
- *         [...]
- *         The status register 2 is read using instruction 3Fh.
- * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
- *         In contrast to the 001b code, writing one byte to the status
- *         register does not modify status register 2.
- * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
- *         Read Status instruction 05h. Status register2 is read using
- *         instruction 35h. QE is set via Writ Status instruction 01h with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
+/**
+ * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters.
+ * @nor:       pointer to a 'struct spi_nor'
+ * @addr:      offset in the SFDP area to start reading data from
+ * @len:       number of bytes to read
+ * @buf:       buffer where the SFDP data are copied into
+ *
+ * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not
+ * guaranteed to be dma-safe.
+ *
+ * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp()
+ *          otherwise.
  */
-#define BFPT_DWORD15_QER_MASK                  GENMASK(22, 20)
-#define BFPT_DWORD15_QER_NONE                  (0x0UL << 20) /* Micron */
-#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY                (0x1UL << 20)
-#define BFPT_DWORD15_QER_SR1_BIT6              (0x2UL << 20) /* Macronix */
-#define BFPT_DWORD15_QER_SR2_BIT7              (0x3UL << 20)
-#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD                (0x4UL << 20)
-#define BFPT_DWORD15_QER_SR2_BIT1              (0x5UL << 20) /* Spansion */
+static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr,
+                                       size_t len, void *buf)
+{
+       void *dma_safe_buf;
+       int ret;
 
-struct sfdp_bfpt {
-       u32     dwords[BFPT_DWORD_MAX];
-};
+       dma_safe_buf = kmalloc(len, GFP_KERNEL);
+       if (!dma_safe_buf)
+               return -ENOMEM;
+
+       ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf);
+       memcpy(buf, dma_safe_buf, len);
+       kfree(dma_safe_buf);
+
+       return ret;
+}
 
 /* Fast Read settings. */
 
-static inline void
+static void
 spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read,
                                    u16 half,
                                    enum spi_nor_protocol proto)
@@ -2464,8 +2573,6 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
        {BFPT_DWORD(9), 16},
 };
 
-static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
-
 /**
  * spi_nor_set_erase_type() - set a SPI NOR erase type
  * @erase:     pointer to a structure that describes a SPI NOR erase type
@@ -2598,6 +2705,19 @@ static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
        map->uniform_erase_type = erase_mask;
 }
 
+static int
+spi_nor_post_bfpt_fixups(struct spi_nor *nor,
+                        const struct sfdp_parameter_header *bfpt_header,
+                        const struct sfdp_bfpt *bfpt,
+                        struct spi_nor_flash_parameter *params)
+{
+       if (nor->info->fixups && nor->info->fixups->post_bfpt)
+               return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt,
+                                                   params);
+
+       return 0;
+}
+
 /**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:               pointer to a 'struct spi_nor'
@@ -2750,7 +2870,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 
        /* Stop here if not JESD216 rev A or later. */
        if (bfpt_header->length < BFPT_DWORD_MAX)
-               return 0;
+               return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
+                                               params);
 
        /* Page size: this field specifies 'N' so the page size = 2^N bytes. */
        params->page_size = bfpt.dwords[BFPT_DWORD(11)];
@@ -2785,7 +2906,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
                return -EINVAL;
        }
 
-       return 0;
+       return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
 }
 
 #define SMPT_CMD_ADDRESS_LEN_MASK              GENMASK(23, 22)
@@ -3091,7 +3212,7 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
 
        /* Read the Sector Map Parameter Table. */
        len = smpt_header->length * sizeof(*smpt);
-       smpt = kzalloc(len, GFP_KERNEL);
+       smpt = kmalloc(len, GFP_KERNEL);
        if (!smpt)
                return -ENOMEM;
 
@@ -3121,6 +3242,191 @@ out:
        return ret;
 }
 
+#define SFDP_4BAIT_DWORD_MAX   2
+
+struct sfdp_4bait {
+       /* The hardware capability. */
+       u32             hwcaps;
+
+       /*
+        * The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
+        * the associated 4-byte address op code is supported.
+        */
+       u32             supported_bit;
+};
+
+/**
+ * spi_nor_parse_4bait() - parse the 4-Byte Address Instruction Table
+ * @nor:               pointer to a 'struct spi_nor'.
+ * @param_header:      pointer to the 'struct sfdp_parameter_header' describing
+ *                     the 4-Byte Address Instruction Table length and version.
+ * @params:            pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+                              const struct sfdp_parameter_header *param_header,
+                              struct spi_nor_flash_parameter *params)
+{
+       static const struct sfdp_4bait reads[] = {
+               { SNOR_HWCAPS_READ,             BIT(0) },
+               { SNOR_HWCAPS_READ_FAST,        BIT(1) },
+               { SNOR_HWCAPS_READ_1_1_2,       BIT(2) },
+               { SNOR_HWCAPS_READ_1_2_2,       BIT(3) },
+               { SNOR_HWCAPS_READ_1_1_4,       BIT(4) },
+               { SNOR_HWCAPS_READ_1_4_4,       BIT(5) },
+               { SNOR_HWCAPS_READ_1_1_1_DTR,   BIT(13) },
+               { SNOR_HWCAPS_READ_1_2_2_DTR,   BIT(14) },
+               { SNOR_HWCAPS_READ_1_4_4_DTR,   BIT(15) },
+       };
+       static const struct sfdp_4bait programs[] = {
+               { SNOR_HWCAPS_PP,               BIT(6) },
+               { SNOR_HWCAPS_PP_1_1_4,         BIT(7) },
+               { SNOR_HWCAPS_PP_1_4_4,         BIT(8) },
+       };
+       static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
+               { 0u /* not used */,            BIT(9) },
+               { 0u /* not used */,            BIT(10) },
+               { 0u /* not used */,            BIT(11) },
+               { 0u /* not used */,            BIT(12) },
+       };
+       struct spi_nor_pp_command *params_pp = params->page_programs;
+       struct spi_nor_erase_map *map = &nor->erase_map;
+       struct spi_nor_erase_type *erase_type = map->erase_type;
+       u32 *dwords;
+       size_t len;
+       u32 addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
+       int i, ret;
+
+       if (param_header->major != SFDP_JESD216_MAJOR ||
+           param_header->length < SFDP_4BAIT_DWORD_MAX)
+               return -EINVAL;
+
+       /* Read the 4-byte Address Instruction Table. */
+       len = sizeof(*dwords) * SFDP_4BAIT_DWORD_MAX;
+
+       /* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
+       dwords = kmalloc(len, GFP_KERNEL);
+       if (!dwords)
+               return -ENOMEM;
+
+       addr = SFDP_PARAM_HEADER_PTP(param_header);
+       ret = spi_nor_read_sfdp(nor, addr, len, dwords);
+       if (ret)
+               return ret;
+
+       /* Fix endianness of the 4BAIT DWORDs. */
+       for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++)
+               dwords[i] = le32_to_cpu(dwords[i]);
+
+       /*
+        * Compute the subset of (Fast) Read commands for which the 4-byte
+        * version is supported.
+        */
+       discard_hwcaps = 0;
+       read_hwcaps = 0;
+       for (i = 0; i < ARRAY_SIZE(reads); i++) {
+               const struct sfdp_4bait *read = &reads[i];
+
+               discard_hwcaps |= read->hwcaps;
+               if ((params->hwcaps.mask & read->hwcaps) &&
+                   (dwords[0] & read->supported_bit))
+                       read_hwcaps |= read->hwcaps;
+       }
+
+       /*
+        * Compute the subset of Page Program commands for which the 4-byte
+        * version is supported.
+        */
+       pp_hwcaps = 0;
+       for (i = 0; i < ARRAY_SIZE(programs); i++) {
+               const struct sfdp_4bait *program = &programs[i];
+
+               /*
+                * The 4 Byte Address Instruction (Optional) Table is the only
+                * SFDP table that indicates support for Page Program Commands.
+                * Bypass the params->hwcaps.mask and consider 4BAIT the biggest
+                * authority for specifying Page Program support.
+                */
+               discard_hwcaps |= program->hwcaps;
+               if (dwords[0] & program->supported_bit)
+                       pp_hwcaps |= program->hwcaps;
+       }
+
+       /*
+        * Compute the subset of Sector Erase commands for which the 4-byte
+        * version is supported.
+        */
+       erase_mask = 0;
+       for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+               const struct sfdp_4bait *erase = &erases[i];
+
+               if (dwords[0] & erase->supported_bit)
+                       erase_mask |= BIT(i);
+       }
+
+       /* Replicate the sort done for the map's erase types in BFPT. */
+       erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
+
+       /*
+        * We need at least one 4-byte op code per read, program and erase
+        * operation; the .read(), .write() and .erase() hooks share the
+        * nor->addr_width value.
+        */
+       if (!read_hwcaps || !pp_hwcaps || !erase_mask)
+               goto out;
+
+       /*
+        * Discard all operations from the 4-byte instruction set which are
+        * not supported by this memory.
+        */
+       params->hwcaps.mask &= ~discard_hwcaps;
+       params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
+
+       /* Use the 4-byte address instruction set. */
+       for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
+               struct spi_nor_read_command *read_cmd = &params->reads[i];
+
+               read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
+       }
+
+       /* 4BAIT is the only SFDP table that indicates page program support. */
+       if (pp_hwcaps & SNOR_HWCAPS_PP)
+               spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP],
+                                       SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+       if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
+               spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_1_1_4],
+                                       SPINOR_OP_PP_1_1_4_4B,
+                                       SNOR_PROTO_1_1_4);
+       if (pp_hwcaps & SNOR_HWCAPS_PP_1_4_4)
+               spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_1_4_4],
+                                       SPINOR_OP_PP_1_4_4_4B,
+                                       SNOR_PROTO_1_4_4);
+
+       for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+               if (erase_mask & BIT(i))
+                       erase_type[i].opcode = (dwords[1] >>
+                                               erase_type[i].idx * 8) & 0xFF;
+               else
+                       spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
+       }
+
+       /*
+        * We set SNOR_F_HAS_4BAIT in order to skip spi_nor_set_4byte_opcodes()
+        * later because we already did the conversion to 4byte opcodes. Also,
+        * this latest function implements a legacy quirk for the erase size of
+        * Spansion memory. However this quirk is no longer needed with new
+        * SFDP compliant memories.
+        */
+       nor->addr_width = 4;
+       nor->flags |= SNOR_F_4B_OPCODES | SNOR_F_HAS_4BAIT;
+
+       /* fall through */
+out:
+       kfree(dwords);
+       return ret;
+}
+
 /**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:               pointer to a 'struct spi_nor'
@@ -3218,6 +3524,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
                        err = spi_nor_parse_smpt(nor, param_header);
                        break;
 
+               case SFDP_4BAIT_ID:
+                       err = spi_nor_parse_4bait(nor, param_header, params);
+                       break;
+
                default:
                        break;
                }
@@ -3241,17 +3551,17 @@ exit:
 }
 
 static int spi_nor_init_params(struct spi_nor *nor,
-                              const struct flash_info *info,
                               struct spi_nor_flash_parameter *params)
 {
        struct spi_nor_erase_map *map = &nor->erase_map;
+       const struct flash_info *info = nor->info;
        u8 i, erase_mask;
 
        /* Set legacy flash parameters as default. */
        memset(params, 0, sizeof(*params));
 
        /* Set SPI NOR sizes. */
-       params->size = info->sector_size * info->n_sectors;
+       params->size = (u64)info->sector_size * info->n_sectors;
        params->page_size = info->page_size;
 
        /* (Fast) Read settings. */
@@ -3316,6 +3626,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
                        params->quad_enable = macronix_quad_enable;
                        break;
 
+               case SNOR_MFR_ST:
                case SNOR_MFR_MICRON:
                        break;
 
@@ -3345,6 +3656,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
 
                if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
                        nor->addr_width = 0;
+                       nor->flags &= ~SNOR_F_4B_OPCODES;
                        /* restore previous erase map */
                        memcpy(&nor->erase_map, &prev_map,
                               sizeof(nor->erase_map));
@@ -3356,57 +3668,6 @@ static int spi_nor_init_params(struct spi_nor *nor,
        return 0;
 }
 
-static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
-{
-       size_t i;
-
-       for (i = 0; i < size; i++)
-               if (table[i][0] == (int)hwcaps)
-                       return table[i][1];
-
-       return -EINVAL;
-}
-
-static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
-{
-       static const int hwcaps_read2cmd[][2] = {
-               { SNOR_HWCAPS_READ,             SNOR_CMD_READ },
-               { SNOR_HWCAPS_READ_FAST,        SNOR_CMD_READ_FAST },
-               { SNOR_HWCAPS_READ_1_1_1_DTR,   SNOR_CMD_READ_1_1_1_DTR },
-               { SNOR_HWCAPS_READ_1_1_2,       SNOR_CMD_READ_1_1_2 },
-               { SNOR_HWCAPS_READ_1_2_2,       SNOR_CMD_READ_1_2_2 },
-               { SNOR_HWCAPS_READ_2_2_2,       SNOR_CMD_READ_2_2_2 },
-               { SNOR_HWCAPS_READ_1_2_2_DTR,   SNOR_CMD_READ_1_2_2_DTR },
-               { SNOR_HWCAPS_READ_1_1_4,       SNOR_CMD_READ_1_1_4 },
-               { SNOR_HWCAPS_READ_1_4_4,       SNOR_CMD_READ_1_4_4 },
-               { SNOR_HWCAPS_READ_4_4_4,       SNOR_CMD_READ_4_4_4 },
-               { SNOR_HWCAPS_READ_1_4_4_DTR,   SNOR_CMD_READ_1_4_4_DTR },
-               { SNOR_HWCAPS_READ_1_1_8,       SNOR_CMD_READ_1_1_8 },
-               { SNOR_HWCAPS_READ_1_8_8,       SNOR_CMD_READ_1_8_8 },
-               { SNOR_HWCAPS_READ_8_8_8,       SNOR_CMD_READ_8_8_8 },
-               { SNOR_HWCAPS_READ_1_8_8_DTR,   SNOR_CMD_READ_1_8_8_DTR },
-       };
-
-       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
-                                 ARRAY_SIZE(hwcaps_read2cmd));
-}
-
-static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
-{
-       static const int hwcaps_pp2cmd[][2] = {
-               { SNOR_HWCAPS_PP,               SNOR_CMD_PP },
-               { SNOR_HWCAPS_PP_1_1_4,         SNOR_CMD_PP_1_1_4 },
-               { SNOR_HWCAPS_PP_1_4_4,         SNOR_CMD_PP_1_4_4 },
-               { SNOR_HWCAPS_PP_4_4_4,         SNOR_CMD_PP_4_4_4 },
-               { SNOR_HWCAPS_PP_1_1_8,         SNOR_CMD_PP_1_1_8 },
-               { SNOR_HWCAPS_PP_1_8_8,         SNOR_CMD_PP_1_8_8 },
-               { SNOR_HWCAPS_PP_8_8_8,         SNOR_CMD_PP_8_8_8 },
-       };
-
-       return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
-                                 ARRAY_SIZE(hwcaps_pp2cmd));
-}
-
 static int spi_nor_select_read(struct spi_nor *nor,
                               const struct spi_nor_flash_parameter *params,
                               u32 shared_hwcaps)
@@ -3559,7 +3820,7 @@ static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size)
        return 0;
 }
 
-static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+static int spi_nor_setup(struct spi_nor *nor,
                         const struct spi_nor_flash_parameter *params,
                         const struct spi_nor_hwcaps *hwcaps)
 {
@@ -3602,7 +3863,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
        }
 
        /* Select the Sector Erase command. */
-       err = spi_nor_select_erase(nor, info->sector_size);
+       err = spi_nor_select_erase(nor, nor->info->sector_size);
        if (err) {
                dev_err(nor->dev,
                        "can't select erase settings supported by both the SPI controller and memory.\n");
@@ -3645,9 +3906,7 @@ static int spi_nor_init(struct spi_nor *nor)
                }
        }
 
-       if ((nor->addr_width == 4) &&
-           (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
-           !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
+       if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) {
                /*
                 * If the RESET# pin isn't hooked up properly, or the system
                 * otherwise doesn't perform a reset command in the boot
@@ -3657,7 +3916,7 @@ static int spi_nor_init(struct spi_nor *nor)
                 */
                WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
                          "enabling reset hack; may not recover from unexpected reboots\n");
-               set_4byte(nor, nor->info, 1);
+               set_4byte(nor, true);
        }
 
        return 0;
@@ -3679,14 +3938,24 @@ static void spi_nor_resume(struct mtd_info *mtd)
 void spi_nor_restore(struct spi_nor *nor)
 {
        /* restore the addressing mode */
-       if ((nor->addr_width == 4) &&
-           (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
-           !(nor->info->flags & SPI_NOR_4B_OPCODES) &&
-           (nor->flags & SNOR_F_BROKEN_RESET))
-               set_4byte(nor, nor->info, 0);
+       if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
+           nor->flags & SNOR_F_BROKEN_RESET)
+               set_4byte(nor, false);
 }
 EXPORT_SYMBOL_GPL(spi_nor_restore);
 
+static const struct flash_info *spi_nor_match_id(const char *name)
+{
+       const struct flash_info *id = spi_nor_ids;
+
+       while (id->name) {
+               if (!strcmp(name, id->name))
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+
 int spi_nor_scan(struct spi_nor *nor, const char *name,
                 const struct spi_nor_hwcaps *hwcaps)
 {
@@ -3739,6 +4008,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
                }
        }
 
+       nor->info = info;
+
        mutex_init(&nor->lock);
 
        /*
@@ -3750,7 +4021,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
                nor->flags |=  SNOR_F_READY_XSR_RDY;
 
        /* Parse the Serial Flash Discoverable Parameters table. */
-       ret = spi_nor_init_params(nor, info, &params);
+       ret = spi_nor_init_params(nor, &params);
        if (ret)
                return ret;
 
@@ -3766,8 +4037,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        mtd->_resume = spi_nor_resume;
 
        /* NOR protection support for STmicro/Micron chips and similar */
-       if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
-                       info->flags & SPI_NOR_HAS_LOCK) {
+       if (JEDEC_MFR(info) == SNOR_MFR_ST ||
+           JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+           info->flags & SPI_NOR_HAS_LOCK) {
                nor->flash_lock = stm_lock;
                nor->flash_unlock = stm_unlock;
                nor->flash_is_locked = stm_is_locked;
@@ -3826,7 +4098,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
         * - set the SPI protocols for register and memory accesses.
         * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
         */
-       ret = spi_nor_setup(nor, info, &params, hwcaps);
+       ret = spi_nor_setup(nor, &params, hwcaps);
        if (ret)
                return ret;
 
@@ -3837,13 +4109,18 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        } else if (mtd->size > 0x1000000) {
                /* enable 4-byte addressing if the device exceeds 16MiB */
                nor->addr_width = 4;
-               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
-                   info->flags & SPI_NOR_4B_OPCODES)
-                       spi_nor_set_4byte_opcodes(nor, info);
        } else {
                nor->addr_width = 3;
        }
 
+       if (info->flags & SPI_NOR_4B_OPCODES ||
+           (JEDEC_MFR(info) == SNOR_MFR_SPANSION && mtd->size > SZ_16M))
+               nor->flags |= SNOR_F_4B_OPCODES;
+
+       if (nor->addr_width == 4 && nor->flags & SNOR_F_4B_OPCODES &&
+           !(nor->flags & SNOR_F_HAS_4BAIT))
+               spi_nor_set_4byte_opcodes(nor);
+
        if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
                dev_err(dev, "address width is too large: %u\n",
                        nor->addr_width);
@@ -3851,13 +4128,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        }
 
        if (info->flags & SPI_S3AN) {
-               ret = s3an_nor_scan(info, nor);
+               ret = s3an_nor_scan(nor);
                if (ret)
                        return ret;
        }
 
        /* Send all the required SPI flash commands to initialize device */
-       nor->info = info;
        ret = spi_nor_init(nor);
        if (ret)
                return ret;
@@ -3885,19 +4161,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
 }
 EXPORT_SYMBOL_GPL(spi_nor_scan);
 
-static const struct flash_info *spi_nor_match_id(const char *name)
-{
-       const struct flash_info *id = spi_nor_ids;
-
-       while (id->name) {
-               if (!strcmp(name, id->name))
-                       return id;
-               id++;
-       }
-       return NULL;
-}
-
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>");
 MODULE_AUTHOR("Mike Lavender");
 MODULE_DESCRIPTION("framework for SPI NOR");
index a4e3454133a47eacdcc61034c11b6c98d831e9c8..09170b707339e57be9833cbc9b25fca6d738c424 100644 (file)
@@ -1101,10 +1101,10 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
        ubi_wl_close(ubi);
        ubi_free_internal_volumes(ubi);
        vfree(ubi->vtbl);
-       put_mtd_device(ubi->mtd);
        vfree(ubi->peb_buf);
        vfree(ubi->fm_buf);
        ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
+       put_mtd_device(ubi->mtd);
        put_device(&ubi->dev);
        return 0;
 }
index e9e9ecbcedcc384aee39a7b3e08f9d23cffd39aa..0b8f0c46268dae932896b7438e15fe8205b9016f 100644 (file)
@@ -227,9 +227,9 @@ out_unlock:
 out_free:
        kfree(desc);
 out_put_ubi:
-       ubi_put_device(ubi);
        ubi_err(ubi, "cannot open device %d, volume %d, error %d",
                ubi_num, vol_id, err);
+       ubi_put_device(ubi);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume);
index e05d4eddc9351d9c582cc51cae07a49ae2055e4f..24fb6a68503966a4ae049ef6b6fafa7d2bce7edf 100644 (file)
@@ -1124,7 +1124,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
        u16 *p = _p;
        int i;
 
-       regs->version = 0;
+       regs->version = chip->info->prod_num;
 
        memset(p, 0xff, 32 * sizeof(u16));
 
index 3b889efddf789643803b371420c321e90b0e5481..50dd6bf176d034721590bf15c2abfab88dd5285a 100644 (file)
@@ -29,9 +29,6 @@
 #define RES_RING_CSR   1
 #define RES_RING_CMD   2
 
-static const struct of_device_id xgene_enet_of_match[];
-static const struct acpi_device_id xgene_enet_acpi_match[];
-
 static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
 {
        struct xgene_enet_raw_desc16 *raw_desc;
index 0de487a8f0eb22d7b033c4f9751b68cf2454286e..5cd3135dfe302331b30e6bb1105add2a95189c6c 100644 (file)
@@ -1282,6 +1282,7 @@ enum sp_rtnl_flag {
        BNX2X_SP_RTNL_TX_STOP,
        BNX2X_SP_RTNL_GET_DRV_VERSION,
        BNX2X_SP_RTNL_CHANGE_UDP_PORT,
+       BNX2X_SP_RTNL_UPDATE_SVID,
 };
 
 enum bnx2x_iov_flag {
@@ -2520,6 +2521,7 @@ void bnx2x_update_mfw_dump(struct bnx2x *bp);
 void bnx2x_init_ptp(struct bnx2x *bp);
 int bnx2x_configure_ptp_filters(struct bnx2x *bp);
 void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb);
+void bnx2x_register_phc(struct bnx2x *bp);
 
 #define BNX2X_MAX_PHC_DRIFT 31000000
 #define BNX2X_PTP_TX_TIMEOUT
index 686899d7e555e84a4c78459e1780765b9794b913..ecb1bd7eb5080d1d47725e0c98f3153437fb5a42 100644 (file)
@@ -2842,6 +2842,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        bnx2x_set_rx_mode_inner(bp);
 
        if (bp->flags & PTP_SUPPORTED) {
+               bnx2x_register_phc(bp);
                bnx2x_init_ptp(bp);
                bnx2x_configure_ptp_filters(bp);
        }
index 95309b27c7d19cca8261ede60d3a32a04ebbab39..b164f705709d083576e92fb4e2fd007cd3dbe9bb 100644 (file)
@@ -2925,6 +2925,10 @@ static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp)
        func_params.f_obj = &bp->func_obj;
        func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE;
 
+       /* Prepare parameters for function state transitions */
+       __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+       __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
        if (IS_MF_UFP(bp) || IS_MF_BD(bp)) {
                int func = BP_ABS_FUNC(bp);
                u32 val;
@@ -4311,7 +4315,8 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
                                bnx2x_handle_eee_event(bp);
 
                        if (val & DRV_STATUS_OEM_UPDATE_SVID)
-                               bnx2x_handle_update_svid_cmd(bp);
+                               bnx2x_schedule_sp_rtnl(bp,
+                                       BNX2X_SP_RTNL_UPDATE_SVID, 0);
 
                        if (bp->link_vars.periodic_flags &
                            PERIODIC_FLAGS_LINK_EVENT) {
@@ -7723,6 +7728,9 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
                REG_WR(bp, reg_addr, val);
        }
 
+       if (CHIP_IS_E3B0(bp))
+               bp->flags |= PTP_SUPPORTED;
+
        return 0;
 }
 
@@ -8472,6 +8480,7 @@ int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
        /* Fill a user request section if needed */
        if (!test_bit(RAMROD_CONT, ramrod_flags)) {
                ramrod_param.user_req.u.vlan.vlan = vlan;
+               __set_bit(BNX2X_VLAN, &ramrod_param.user_req.vlan_mac_flags);
                /* Set the command: ADD or DEL */
                if (set)
                        ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
@@ -8492,6 +8501,27 @@ int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
        return rc;
 }
 
+static int bnx2x_del_all_vlans(struct bnx2x *bp)
+{
+       struct bnx2x_vlan_mac_obj *vlan_obj = &bp->sp_objs[0].vlan_obj;
+       unsigned long ramrod_flags = 0, vlan_flags = 0;
+       struct bnx2x_vlan_entry *vlan;
+       int rc;
+
+       __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+       __set_bit(BNX2X_VLAN, &vlan_flags);
+       rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_flags, &ramrod_flags);
+       if (rc)
+               return rc;
+
+       /* Mark that hw forgot all entries */
+       list_for_each_entry(vlan, &bp->vlan_reg, link)
+               vlan->hw = false;
+       bp->vlan_cnt = 0;
+
+       return 0;
+}
+
 int bnx2x_del_all_macs(struct bnx2x *bp,
                       struct bnx2x_vlan_mac_obj *mac_obj,
                       int mac_type, bool wait_for_comp)
@@ -9330,6 +9360,11 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
                BNX2X_ERR("Failed to schedule DEL commands for UC MACs list: %d\n",
                          rc);
 
+       /* Remove all currently configured VLANs */
+       rc = bnx2x_del_all_vlans(bp);
+       if (rc < 0)
+               BNX2X_ERR("Failed to delete all VLANs\n");
+
        /* Disable LLH */
        if (!CHIP_IS_E1(bp))
                REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
@@ -9417,8 +9452,13 @@ unload_error:
         * function stop ramrod is sent, since as part of this ramrod FW access
         * PTP registers.
         */
-       if (bp->flags & PTP_SUPPORTED)
+       if (bp->flags & PTP_SUPPORTED) {
                bnx2x_stop_ptp(bp);
+               if (bp->ptp_clock) {
+                       ptp_clock_unregister(bp->ptp_clock);
+                       bp->ptp_clock = NULL;
+               }
+       }
 
        /* Disable HW interrupts, NAPI */
        bnx2x_netif_stop(bp, 1);
@@ -10359,6 +10399,9 @@ sp_rtnl_not_reset:
                               &bp->sp_rtnl_state))
                bnx2x_update_mng_version(bp);
 
+       if (test_and_clear_bit(BNX2X_SP_RTNL_UPDATE_SVID, &bp->sp_rtnl_state))
+               bnx2x_handle_update_svid_cmd(bp);
+
        if (test_and_clear_bit(BNX2X_SP_RTNL_CHANGE_UDP_PORT,
                               &bp->sp_rtnl_state)) {
                if (bnx2x_udp_port_update(bp)) {
@@ -11750,8 +11793,10 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
         * If maximum allowed number of connections is zero -
         * disable the feature.
         */
-       if (!bp->cnic_eth_dev.max_fcoe_conn)
+       if (!bp->cnic_eth_dev.max_fcoe_conn) {
                bp->flags |= NO_FCOE_FLAG;
+               eth_zero_addr(bp->fip_mac);
+       }
 }
 
 static void bnx2x_get_cnic_info(struct bnx2x *bp)
@@ -12494,9 +12539,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        bp->dump_preset_idx = 1;
 
-       if (CHIP_IS_E3B0(bp))
-               bp->flags |= PTP_SUPPORTED;
-
        return rc;
 }
 
@@ -13024,13 +13066,6 @@ static void bnx2x_vlan_configure(struct bnx2x *bp, bool set_rx_mode)
 
 int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp)
 {
-       struct bnx2x_vlan_entry *vlan;
-
-       /* The hw forgot all entries after reload */
-       list_for_each_entry(vlan, &bp->vlan_reg, link)
-               vlan->hw = false;
-       bp->vlan_cnt = 0;
-
        /* Don't set rx mode here. Our caller will do it. */
        bnx2x_vlan_configure(bp, false);
 
@@ -13895,7 +13930,7 @@ static int bnx2x_ptp_enable(struct ptp_clock_info *ptp,
        return -ENOTSUPP;
 }
 
-static void bnx2x_register_phc(struct bnx2x *bp)
+void bnx2x_register_phc(struct bnx2x *bp)
 {
        /* Fill the ptp_clock_info struct and register PTP clock*/
        bp->ptp_clock_info.owner = THIS_MODULE;
@@ -14097,8 +14132,6 @@ static int bnx2x_init_one(struct pci_dev *pdev,
               dev->base_addr, bp->pdev->irq, dev->dev_addr);
        pcie_print_link_status(bp->pdev);
 
-       bnx2x_register_phc(bp);
-
        if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp))
                bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED);
 
@@ -14131,11 +14164,6 @@ static void __bnx2x_remove(struct pci_dev *pdev,
                           struct bnx2x *bp,
                           bool remove_netdev)
 {
-       if (bp->ptp_clock) {
-               ptp_clock_unregister(bp->ptp_clock);
-               bp->ptp_clock = NULL;
-       }
-
        /* Delete storage MAC address */
        if (!NO_FCOE(bp)) {
                rtnl_lock();
index 0bf2fd470819e64d2d7788b57caee6569b9b3828..7a6e82db423123585574c88765fb00f14ab3b603 100644 (file)
@@ -265,6 +265,7 @@ enum {
        BNX2X_ETH_MAC,
        BNX2X_ISCSI_ETH_MAC,
        BNX2X_NETQ_ETH_MAC,
+       BNX2X_VLAN,
        BNX2X_DONT_CONSUME_CAM_CREDIT,
        BNX2X_DONT_CONSUME_CAM_CREDIT_DEST,
 };
@@ -272,7 +273,8 @@ enum {
 #define BNX2X_VLAN_MAC_CMP_MASK        (1 << BNX2X_UC_LIST_MAC | \
                                 1 << BNX2X_ETH_MAC | \
                                 1 << BNX2X_ISCSI_ETH_MAC | \
-                                1 << BNX2X_NETQ_ETH_MAC)
+                                1 << BNX2X_NETQ_ETH_MAC | \
+                                1 << BNX2X_VLAN)
 #define BNX2X_VLAN_MAC_CMP_FLAGS(flags) \
        ((flags) & BNX2X_VLAN_MAC_CMP_MASK)
 
index 6cc69a58478a5ffaad8b7a0511d68e36a93657f3..6b51f4de601743a6d24fb54ea3e3159b39af9acc 100644 (file)
@@ -2572,6 +2572,7 @@ static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
 static int bnxt_run_loopback(struct bnxt *bp)
 {
        struct bnxt_tx_ring_info *txr = &bp->tx_ring[0];
+       struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
        struct bnxt_cp_ring_info *cpr;
        int pkt_size, i = 0;
        struct sk_buff *skb;
@@ -2579,7 +2580,9 @@ static int bnxt_run_loopback(struct bnxt *bp)
        u8 *data;
        int rc;
 
-       cpr = &txr->bnapi->cp_ring;
+       cpr = &rxr->bnapi->cp_ring;
+       if (bp->flags & BNXT_FLAG_CHIP_P5)
+               cpr = cpr->cp_ring_arr[BNXT_RX_HDL];
        pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
        skb = netdev_alloc_skb(bp->dev, pkt_size);
        if (!skb)
index 1d86b4d5645ad884b34103a45eb42c7af95f0745..4c816e5a841fa3c976114c93ad86b08f4d8f2195 100644 (file)
@@ -61,7 +61,8 @@
 #define MACB_TX_ERR_FLAGS      (MACB_BIT(ISR_TUND)                     \
                                        | MACB_BIT(ISR_RLE)             \
                                        | MACB_BIT(TXERR))
-#define MACB_TX_INT_FLAGS      (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP))
+#define MACB_TX_INT_FLAGS      (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)    \
+                                       | MACB_BIT(TXUBR))
 
 /* Max length of transmit frame must be a multiple of 8 bytes */
 #define MACB_TX_LEN_ALIGN      8
@@ -680,6 +681,11 @@ static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_
        if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
                desc_64 = macb_64b_desc(bp, desc);
                desc_64->addrh = upper_32_bits(addr);
+               /* The low bits of RX address contain the RX_USED bit, clearing
+                * of which allows packet RX. Make sure the high bits are also
+                * visible to HW at that point.
+                */
+               dma_wmb();
        }
 #endif
        desc->addr = lower_32_bits(addr);
@@ -928,14 +934,19 @@ static void gem_rx_refill(struct macb_queue *queue)
 
                        if (entry == bp->rx_ring_size - 1)
                                paddr |= MACB_BIT(RX_WRAP);
-                       macb_set_addr(bp, desc, paddr);
                        desc->ctrl = 0;
+                       /* Setting addr clears RX_USED and allows reception,
+                        * make sure ctrl is cleared first to avoid a race.
+                        */
+                       dma_wmb();
+                       macb_set_addr(bp, desc, paddr);
 
                        /* properly align Ethernet header */
                        skb_reserve(skb, NET_IP_ALIGN);
                } else {
-                       desc->addr &= ~MACB_BIT(RX_USED);
                        desc->ctrl = 0;
+                       dma_wmb();
+                       desc->addr &= ~MACB_BIT(RX_USED);
                }
        }
 
@@ -989,11 +1000,15 @@ static int gem_rx(struct macb_queue *queue, int budget)
 
                rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
                addr = macb_get_addr(bp, desc);
-               ctrl = desc->ctrl;
 
                if (!rxused)
                        break;
 
+               /* Ensure ctrl is at least as up-to-date as rxused */
+               dma_rmb();
+
+               ctrl = desc->ctrl;
+
                queue->rx_tail++;
                count++;
 
@@ -1168,11 +1183,14 @@ static int macb_rx(struct macb_queue *queue, int budget)
                /* Make hw descriptor updates visible to CPU */
                rmb();
 
-               ctrl = desc->ctrl;
-
                if (!(desc->addr & MACB_BIT(RX_USED)))
                        break;
 
+               /* Ensure ctrl is at least as up-to-date as addr */
+               dma_rmb();
+
+               ctrl = desc->ctrl;
+
                if (ctrl & MACB_BIT(RX_SOF)) {
                        if (first_frag != -1)
                                discard_partial_frame(queue, first_frag, tail);
@@ -1312,6 +1330,21 @@ static void macb_hresp_error_task(unsigned long data)
        netif_tx_start_all_queues(dev);
 }
 
+static void macb_tx_restart(struct macb_queue *queue)
+{
+       unsigned int head = queue->tx_head;
+       unsigned int tail = queue->tx_tail;
+       struct macb *bp = queue->bp;
+
+       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+               queue_writel(queue, ISR, MACB_BIT(TXUBR));
+
+       if (head == tail)
+               return;
+
+       macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+}
+
 static irqreturn_t macb_interrupt(int irq, void *dev_id)
 {
        struct macb_queue *queue = dev_id;
@@ -1369,6 +1402,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                if (status & MACB_BIT(TCOMP))
                        macb_tx_interrupt(queue);
 
+               if (status & MACB_BIT(TXUBR))
+                       macb_tx_restart(queue);
+
                /* Link change detection isn't possible with RMII, so we'll
                 * add that if/when we get our hands on a full-blown MII PHY.
                 */
index cd5296b842290302a5904b4c590e51fdea741bbd..a6dc47edc4cf6431066850770928640670e20bb1 100644 (file)
@@ -319,6 +319,8 @@ int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb,
        desc_ptp = macb_ptp_desc(queue->bp, desc);
        tx_timestamp = &queue->tx_timestamps[head];
        tx_timestamp->skb = skb;
+       /* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */
+       dma_rmb();
        tx_timestamp->desc_ptp.ts_1 = desc_ptp->ts_1;
        tx_timestamp->desc_ptp.ts_2 = desc_ptp->ts_2;
        /* move head */
index f152da1ce0464c5c065010813213e5f60eb111af..c62a0c830705cc71681890bbcf17223de16bdbac 100644 (file)
@@ -1453,6 +1453,9 @@ struct cpl_tx_data {
 #define T6_TX_FORCE_V(x)       ((x) << T6_TX_FORCE_S)
 #define T6_TX_FORCE_F          T6_TX_FORCE_V(1U)
 
+#define TX_URG_S    16
+#define TX_URG_V(x) ((x) << TX_URG_S)
+
 #define TX_SHOVE_S    14
 #define TX_SHOVE_V(x) ((x) << TX_SHOVE_S)
 
index b52029e26d15323b98811c5180a3d78ac288bf52..ad1779fc410e64b668bf9bdf5dc037eb46a737fa 100644 (file)
@@ -379,6 +379,9 @@ static void hns_ae_stop(struct hnae_handle *handle)
 
        hns_ae_ring_enable_all(handle, 0);
 
+       /* clean rx fbd. */
+       hns_rcb_wait_fbd_clean(handle->qs, handle->q_num, RCB_INT_FLAG_RX);
+
        (void)hns_mac_vm_config_bc_en(mac_cb, 0, false);
 }
 
index aaf72c055711ce2051d982c3f91b4fb674117a29..1790cdafd9b823ec32e10e7a301c3e259a4d467a 100644 (file)
@@ -67,11 +67,14 @@ static void hns_gmac_enable(void *mac_drv, enum mac_commom_mode mode)
        struct mac_driver *drv = (struct mac_driver *)mac_drv;
 
        /*enable GE rX/tX */
-       if ((mode == MAC_COMM_MODE_TX) || (mode == MAC_COMM_MODE_RX_AND_TX))
+       if (mode == MAC_COMM_MODE_TX || mode == MAC_COMM_MODE_RX_AND_TX)
                dsaf_set_dev_bit(drv, GMAC_PORT_EN_REG, GMAC_PORT_TX_EN_B, 1);
 
-       if ((mode == MAC_COMM_MODE_RX) || (mode == MAC_COMM_MODE_RX_AND_TX))
+       if (mode == MAC_COMM_MODE_RX || mode == MAC_COMM_MODE_RX_AND_TX) {
+               /* enable rx pcs */
+               dsaf_set_dev_bit(drv, GMAC_PCS_RX_EN_REG, 0, 0);
                dsaf_set_dev_bit(drv, GMAC_PORT_EN_REG, GMAC_PORT_RX_EN_B, 1);
+       }
 }
 
 static void hns_gmac_disable(void *mac_drv, enum mac_commom_mode mode)
@@ -79,11 +82,14 @@ static void hns_gmac_disable(void *mac_drv, enum mac_commom_mode mode)
        struct mac_driver *drv = (struct mac_driver *)mac_drv;
 
        /*disable GE rX/tX */
-       if ((mode == MAC_COMM_MODE_TX) || (mode == MAC_COMM_MODE_RX_AND_TX))
+       if (mode == MAC_COMM_MODE_TX || mode == MAC_COMM_MODE_RX_AND_TX)
                dsaf_set_dev_bit(drv, GMAC_PORT_EN_REG, GMAC_PORT_TX_EN_B, 0);
 
-       if ((mode == MAC_COMM_MODE_RX) || (mode == MAC_COMM_MODE_RX_AND_TX))
+       if (mode == MAC_COMM_MODE_RX || mode == MAC_COMM_MODE_RX_AND_TX) {
+               /* disable rx pcs */
+               dsaf_set_dev_bit(drv, GMAC_PCS_RX_EN_REG, 0, 1);
                dsaf_set_dev_bit(drv, GMAC_PORT_EN_REG, GMAC_PORT_RX_EN_B, 0);
+       }
 }
 
 /* hns_gmac_get_en - get port enable
index 3613e400e816d9fd6478f5328e11a13a7e08e802..a97228c93831d69fe2211317486f14a25197e740 100644 (file)
@@ -778,6 +778,17 @@ static int hns_mac_register_phy(struct hns_mac_cb *mac_cb)
        return rc;
 }
 
+static void hns_mac_remove_phydev(struct hns_mac_cb *mac_cb)
+{
+       if (!to_acpi_device_node(mac_cb->fw_port) || !mac_cb->phy_dev)
+               return;
+
+       phy_device_remove(mac_cb->phy_dev);
+       phy_device_free(mac_cb->phy_dev);
+
+       mac_cb->phy_dev = NULL;
+}
+
 #define MAC_MEDIA_TYPE_MAX_LEN         16
 
 static const struct {
@@ -1117,7 +1128,11 @@ void hns_mac_uninit(struct dsaf_device *dsaf_dev)
        int max_port_num = hns_mac_get_max_port_num(dsaf_dev);
 
        for (i = 0; i < max_port_num; i++) {
+               if (!dsaf_dev->mac_cb[i])
+                       continue;
+
                dsaf_dev->misc_op->cpld_reset_led(dsaf_dev->mac_cb[i]);
+               hns_mac_remove_phydev(dsaf_dev->mac_cb[i]);
                dsaf_dev->mac_cb[i] = NULL;
        }
 }
index e557a4ef5996c6772804ca746830af633a4adca9..3b9e74be5fbd27309fb00e1d36195f619c6a8ac6 100644 (file)
@@ -934,6 +934,62 @@ static void hns_dsaf_tcam_mc_cfg(
        spin_unlock_bh(&dsaf_dev->tcam_lock);
 }
 
+/**
+ * hns_dsaf_tcam_uc_cfg_vague - INT
+ * @dsaf_dev: dsa fabric device struct pointer
+ * @address,
+ * @ptbl_tcam_data,
+ */
+static void hns_dsaf_tcam_uc_cfg_vague(struct dsaf_device *dsaf_dev,
+                                      u32 address,
+                                      struct dsaf_tbl_tcam_data *tcam_data,
+                                      struct dsaf_tbl_tcam_data *tcam_mask,
+                                      struct dsaf_tbl_tcam_ucast_cfg *tcam_uc)
+{
+       spin_lock_bh(&dsaf_dev->tcam_lock);
+       hns_dsaf_tbl_tcam_addr_cfg(dsaf_dev, address);
+       hns_dsaf_tbl_tcam_data_cfg(dsaf_dev, tcam_data);
+       hns_dsaf_tbl_tcam_ucast_cfg(dsaf_dev, tcam_uc);
+       hns_dsaf_tbl_tcam_match_cfg(dsaf_dev, tcam_mask);
+       hns_dsaf_tbl_tcam_data_ucast_pul(dsaf_dev);
+
+       /*Restore Match Data*/
+       tcam_mask->tbl_tcam_data_high = 0xffffffff;
+       tcam_mask->tbl_tcam_data_low = 0xffffffff;
+       hns_dsaf_tbl_tcam_match_cfg(dsaf_dev, tcam_mask);
+
+       spin_unlock_bh(&dsaf_dev->tcam_lock);
+}
+
+/**
+ * hns_dsaf_tcam_mc_cfg_vague - INT
+ * @dsaf_dev: dsa fabric device struct pointer
+ * @address,
+ * @ptbl_tcam_data,
+ * @ptbl_tcam_mask
+ * @ptbl_tcam_mcast
+ */
+static void hns_dsaf_tcam_mc_cfg_vague(struct dsaf_device *dsaf_dev,
+                                      u32 address,
+                                      struct dsaf_tbl_tcam_data *tcam_data,
+                                      struct dsaf_tbl_tcam_data *tcam_mask,
+                                      struct dsaf_tbl_tcam_mcast_cfg *tcam_mc)
+{
+       spin_lock_bh(&dsaf_dev->tcam_lock);
+       hns_dsaf_tbl_tcam_addr_cfg(dsaf_dev, address);
+       hns_dsaf_tbl_tcam_data_cfg(dsaf_dev, tcam_data);
+       hns_dsaf_tbl_tcam_mcast_cfg(dsaf_dev, tcam_mc);
+       hns_dsaf_tbl_tcam_match_cfg(dsaf_dev, tcam_mask);
+       hns_dsaf_tbl_tcam_data_mcast_pul(dsaf_dev);
+
+       /*Restore Match Data*/
+       tcam_mask->tbl_tcam_data_high = 0xffffffff;
+       tcam_mask->tbl_tcam_data_low = 0xffffffff;
+       hns_dsaf_tbl_tcam_match_cfg(dsaf_dev, tcam_mask);
+
+       spin_unlock_bh(&dsaf_dev->tcam_lock);
+}
+
 /**
  * hns_dsaf_tcam_mc_invld - INT
  * @dsaf_id: dsa fabric id
@@ -1492,6 +1548,27 @@ static u16 hns_dsaf_find_empty_mac_entry(struct dsaf_device *dsaf_dev)
        return DSAF_INVALID_ENTRY_IDX;
 }
 
+/**
+ * hns_dsaf_find_empty_mac_entry_reverse
+ * search dsa fabric soft empty-entry from the end
+ * @dsaf_dev: dsa fabric device struct pointer
+ */
+static u16 hns_dsaf_find_empty_mac_entry_reverse(struct dsaf_device *dsaf_dev)
+{
+       struct dsaf_drv_priv *priv = hns_dsaf_dev_priv(dsaf_dev);
+       struct dsaf_drv_soft_mac_tbl *soft_mac_entry;
+       int i;
+
+       soft_mac_entry = priv->soft_mac_tbl + (DSAF_TCAM_SUM - 1);
+       for (i = (DSAF_TCAM_SUM - 1); i > 0; i--) {
+               /* search all entry from end to start.*/
+               if (soft_mac_entry->index == DSAF_INVALID_ENTRY_IDX)
+                       return i;
+               soft_mac_entry--;
+       }
+       return DSAF_INVALID_ENTRY_IDX;
+}
+
 /**
  * hns_dsaf_set_mac_key - set mac key
  * @dsaf_dev: dsa fabric device struct pointer
@@ -2166,9 +2243,9 @@ void hns_dsaf_update_stats(struct dsaf_device *dsaf_dev, u32 node_num)
                DSAF_INODE_LOCAL_ADDR_FALSE_NUM_0_REG + 0x80 * (u64)node_num);
 
        hw_stats->vlan_drop += dsaf_read_dev(dsaf_dev,
-               DSAF_INODE_SW_VLAN_TAG_DISC_0_REG + 0x80 * (u64)node_num);
+               DSAF_INODE_SW_VLAN_TAG_DISC_0_REG + 4 * (u64)node_num);
        hw_stats->stp_drop += dsaf_read_dev(dsaf_dev,
-               DSAF_INODE_IN_DATA_STP_DISC_0_REG + 0x80 * (u64)node_num);
+               DSAF_INODE_IN_DATA_STP_DISC_0_REG + 4 * (u64)node_num);
 
        /* pfc pause frame statistics stored in dsaf inode*/
        if ((node_num < DSAF_SERVICE_NW_NUM) && !is_ver1) {
@@ -2285,237 +2362,237 @@ void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data)
                                DSAF_INODE_BD_ORDER_STATUS_0_REG + j * 4);
                p[223 + i] = dsaf_read_dev(ddev,
                                DSAF_INODE_SW_VLAN_TAG_DISC_0_REG + j * 4);
-               p[224 + i] = dsaf_read_dev(ddev,
+               p[226 + i] = dsaf_read_dev(ddev,
                                DSAF_INODE_IN_DATA_STP_DISC_0_REG + j * 4);
        }
 
-       p[227] = dsaf_read_dev(ddev, DSAF_INODE_GE_FC_EN_0_REG + port * 4);
+       p[229] = dsaf_read_dev(ddev, DSAF_INODE_GE_FC_EN_0_REG + port * 4);
 
        for (i = 0; i < DSAF_INODE_NUM / DSAF_COMM_CHN; i++) {
                j = i * DSAF_COMM_CHN + port;
-               p[228 + i] = dsaf_read_dev(ddev,
+               p[230 + i] = dsaf_read_dev(ddev,
                                DSAF_INODE_VC0_IN_PKT_NUM_0_REG + j * 4);
        }
 
-       p[231] = dsaf_read_dev(ddev,
-               DSAF_INODE_VC1_IN_PKT_NUM_0_REG + port * 4);
+       p[233] = dsaf_read_dev(ddev,
+               DSAF_INODE_VC1_IN_PKT_NUM_0_REG + port * 0x80);
 
        /* dsaf inode registers */
        for (i = 0; i < HNS_DSAF_SBM_NUM(ddev) / DSAF_COMM_CHN; i++) {
                j = i * DSAF_COMM_CHN + port;
-               p[232 + i] = dsaf_read_dev(ddev,
+               p[234 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_CFG_REG_0_REG + j * 0x80);
-               p[235 + i] = dsaf_read_dev(ddev,
+               p[237 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CFG_0_XGE_REG_0_REG + j * 0x80);
-               p[238 + i] = dsaf_read_dev(ddev,
+               p[240 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CFG_1_REG_0_REG + j * 0x80);
-               p[241 + i] = dsaf_read_dev(ddev,
+               p[243 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CFG_2_XGE_REG_0_REG + j * 0x80);
-               p[244 + i] = dsaf_read_dev(ddev,
+               p[246 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_FREE_CNT_0_0_REG + j * 0x80);
-               p[245 + i] = dsaf_read_dev(ddev,
+               p[249 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_FREE_CNT_1_0_REG + j * 0x80);
-               p[248 + i] = dsaf_read_dev(ddev,
+               p[252 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CNT_0_0_REG + j * 0x80);
-               p[251 + i] = dsaf_read_dev(ddev,
+               p[255 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CNT_1_0_REG + j * 0x80);
-               p[254 + i] = dsaf_read_dev(ddev,
+               p[258 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CNT_2_0_REG + j * 0x80);
-               p[257 + i] = dsaf_read_dev(ddev,
+               p[261 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CNT_3_0_REG + j * 0x80);
-               p[260 + i] = dsaf_read_dev(ddev,
+               p[264 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_INER_ST_0_REG + j * 0x80);
-               p[263 + i] = dsaf_read_dev(ddev,
+               p[267 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_MIB_REQ_FAILED_TC_0_REG + j * 0x80);
-               p[266 + i] = dsaf_read_dev(ddev,
+               p[270 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_CNT_0_REG + j * 0x80);
-               p[269 + i] = dsaf_read_dev(ddev,
+               p[273 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_DROP_CNT_0_REG + j * 0x80);
-               p[272 + i] = dsaf_read_dev(ddev,
+               p[276 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_INF_OUTPORT_CNT_0_REG + j * 0x80);
-               p[275 + i] = dsaf_read_dev(ddev,
+               p[279 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC0_CNT_0_REG + j * 0x80);
-               p[278 + i] = dsaf_read_dev(ddev,
+               p[282 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC1_CNT_0_REG + j * 0x80);
-               p[281 + i] = dsaf_read_dev(ddev,
+               p[285 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC2_CNT_0_REG + j * 0x80);
-               p[284 + i] = dsaf_read_dev(ddev,
+               p[288 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC3_CNT_0_REG + j * 0x80);
-               p[287 + i] = dsaf_read_dev(ddev,
+               p[291 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC4_CNT_0_REG + j * 0x80);
-               p[290 + i] = dsaf_read_dev(ddev,
+               p[294 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC5_CNT_0_REG + j * 0x80);
-               p[293 + i] = dsaf_read_dev(ddev,
+               p[297 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC6_CNT_0_REG + j * 0x80);
-               p[296 + i] = dsaf_read_dev(ddev,
+               p[300 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_INPORT_TC7_CNT_0_REG + j * 0x80);
-               p[299 + i] = dsaf_read_dev(ddev,
+               p[303 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_REQ_CNT_0_REG + j * 0x80);
-               p[302 + i] = dsaf_read_dev(ddev,
+               p[306 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_LNK_RELS_CNT_0_REG + j * 0x80);
-               p[305 + i] = dsaf_read_dev(ddev,
+               p[309 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CFG_3_REG_0_REG + j * 0x80);
-               p[308 + i] = dsaf_read_dev(ddev,
+               p[312 + i] = dsaf_read_dev(ddev,
                                DSAF_SBM_BP_CFG_4_REG_0_REG + j * 0x80);
        }
 
        /* dsaf onode registers */
        for (i = 0; i < DSAF_XOD_NUM; i++) {
-               p[311 + i] = dsaf_read_dev(ddev,
+               p[315 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_TSA_TC0_TC3_CFG_0_REG + i * 0x90);
-               p[319 + i] = dsaf_read_dev(ddev,
+               p[323 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_TSA_TC4_TC7_CFG_0_REG + i * 0x90);
-               p[327 + i] = dsaf_read_dev(ddev,
+               p[331 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_BW_TC0_TC3_CFG_0_REG + i * 0x90);
-               p[335 + i] = dsaf_read_dev(ddev,
+               p[339 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_BW_TC4_TC7_CFG_0_REG + i * 0x90);
-               p[343 + i] = dsaf_read_dev(ddev,
+               p[347 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_BW_OFFSET_CFG_0_REG + i * 0x90);
-               p[351 + i] = dsaf_read_dev(ddev,
+               p[355 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_ETS_TOKEN_CFG_0_REG + i * 0x90);
        }
 
-       p[359] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_0_0_REG + port * 0x90);
-       p[360] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_1_0_REG + port * 0x90);
-       p[361] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_2_0_REG + port * 0x90);
+       p[363] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_0_0_REG + port * 0x90);
+       p[364] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_1_0_REG + port * 0x90);
+       p[365] = dsaf_read_dev(ddev, DSAF_XOD_PFS_CFG_2_0_REG + port * 0x90);
 
        for (i = 0; i < DSAF_XOD_BIG_NUM / DSAF_COMM_CHN; i++) {
                j = i * DSAF_COMM_CHN + port;
-               p[362 + i] = dsaf_read_dev(ddev,
+               p[366 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_GNT_L_0_REG + j * 0x90);
-               p[365 + i] = dsaf_read_dev(ddev,
+               p[369 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_GNT_H_0_REG + j * 0x90);
-               p[368 + i] = dsaf_read_dev(ddev,
+               p[372 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_CONNECT_STATE_0_REG + j * 0x90);
-               p[371 + i] = dsaf_read_dev(ddev,
+               p[375 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVPKT_CNT_0_REG + j * 0x90);
-               p[374 + i] = dsaf_read_dev(ddev,
+               p[378 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVTC0_CNT_0_REG + j * 0x90);
-               p[377 + i] = dsaf_read_dev(ddev,
+               p[381 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVTC1_CNT_0_REG + j * 0x90);
-               p[380 + i] = dsaf_read_dev(ddev,
+               p[384 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVTC2_CNT_0_REG + j * 0x90);
-               p[383 + i] = dsaf_read_dev(ddev,
+               p[387 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVTC3_CNT_0_REG + j * 0x90);
-               p[386 + i] = dsaf_read_dev(ddev,
+               p[390 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVVC0_CNT_0_REG + j * 0x90);
-               p[389 + i] = dsaf_read_dev(ddev,
+               p[393 + i] = dsaf_read_dev(ddev,
                                DSAF_XOD_RCVVC1_CNT_0_REG + j * 0x90);
        }
 
-       p[392] = dsaf_read_dev(ddev,
+       p[396] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN0_CNT_0_REG + port * 0x90);
-       p[393] = dsaf_read_dev(ddev,
+       p[397] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN1_CNT_0_REG + port * 0x90);
-       p[394] = dsaf_read_dev(ddev,
+       p[398] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN2_CNT_0_REG + port * 0x90);
-       p[395] = dsaf_read_dev(ddev,
+       p[399] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN3_CNT_0_REG + port * 0x90);
-       p[396] = dsaf_read_dev(ddev,
+       p[400] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN4_CNT_0_REG + port * 0x90);
-       p[397] = dsaf_read_dev(ddev,
+       p[401] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN5_CNT_0_REG + port * 0x90);
-       p[398] = dsaf_read_dev(ddev,
+       p[402] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN6_CNT_0_REG + port * 0x90);
-       p[399] = dsaf_read_dev(ddev,
+       p[403] = dsaf_read_dev(ddev,
                DSAF_XOD_XGE_RCVIN7_CNT_0_REG + port * 0x90);
-       p[400] = dsaf_read_dev(ddev,
+       p[404] = dsaf_read_dev(ddev,
                DSAF_XOD_PPE_RCVIN0_CNT_0_REG + port * 0x90);
-       p[401] = dsaf_read_dev(ddev,
+       p[405] = dsaf_read_dev(ddev,
                DSAF_XOD_PPE_RCVIN1_CNT_0_REG + port * 0x90);
-       p[402] = dsaf_read_dev(ddev,
+       p[406] = dsaf_read_dev(ddev,
                DSAF_XOD_ROCEE_RCVIN0_CNT_0_REG + port * 0x90);
-       p[403] = dsaf_read_dev(ddev,
+       p[407] = dsaf_read_dev(ddev,
                DSAF_XOD_ROCEE_RCVIN1_CNT_0_REG + port * 0x90);
-       p[404] = dsaf_read_dev(ddev,
+       p[408] = dsaf_read_dev(ddev,
                DSAF_XOD_FIFO_STATUS_0_REG + port * 0x90);
 
        /* dsaf voq registers */
        for (i = 0; i < DSAF_VOQ_NUM / DSAF_COMM_CHN; i++) {
                j = (i * DSAF_COMM_CHN + port) * 0x90;
-               p[405 + i] = dsaf_read_dev(ddev,
+               p[409 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_ECC_INVERT_EN_0_REG + j);
-               p[408 + i] = dsaf_read_dev(ddev,
+               p[412 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_SRAM_PKT_NUM_0_REG + j);
-               p[411 + i] = dsaf_read_dev(ddev, DSAF_VOQ_IN_PKT_NUM_0_REG + j);
-               p[414 + i] = dsaf_read_dev(ddev,
+               p[415 + i] = dsaf_read_dev(ddev, DSAF_VOQ_IN_PKT_NUM_0_REG + j);
+               p[418 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_OUT_PKT_NUM_0_REG + j);
-               p[417 + i] = dsaf_read_dev(ddev,
+               p[421 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_ECC_ERR_ADDR_0_REG + j);
-               p[420 + i] = dsaf_read_dev(ddev, DSAF_VOQ_BP_STATUS_0_REG + j);
-               p[423 + i] = dsaf_read_dev(ddev, DSAF_VOQ_SPUP_IDLE_0_REG + j);
-               p[426 + i] = dsaf_read_dev(ddev,
+               p[424 + i] = dsaf_read_dev(ddev, DSAF_VOQ_BP_STATUS_0_REG + j);
+               p[427 + i] = dsaf_read_dev(ddev, DSAF_VOQ_SPUP_IDLE_0_REG + j);
+               p[430 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_XGE_XOD_REQ_0_0_REG + j);
-               p[429 + i] = dsaf_read_dev(ddev,
+               p[433 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_XGE_XOD_REQ_1_0_REG + j);
-               p[432 + i] = dsaf_read_dev(ddev,
+               p[436 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_PPE_XOD_REQ_0_REG + j);
-               p[435 + i] = dsaf_read_dev(ddev,
+               p[439 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_ROCEE_XOD_REQ_0_REG + j);
-               p[438 + i] = dsaf_read_dev(ddev,
+               p[442 + i] = dsaf_read_dev(ddev,
                        DSAF_VOQ_BP_ALL_THRD_0_REG + j);
        }
 
        /* dsaf tbl registers */
-       p[441] = dsaf_read_dev(ddev, DSAF_TBL_CTRL_0_REG);
-       p[442] = dsaf_read_dev(ddev, DSAF_TBL_INT_MSK_0_REG);
-       p[443] = dsaf_read_dev(ddev, DSAF_TBL_INT_SRC_0_REG);
-       p[444] = dsaf_read_dev(ddev, DSAF_TBL_INT_STS_0_REG);
-       p[445] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_ADDR_0_REG);
-       p[446] = dsaf_read_dev(ddev, DSAF_TBL_LINE_ADDR_0_REG);
-       p[447] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_HIGH_0_REG);
-       p[448] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_LOW_0_REG);
-       p[449] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_4_0_REG);
-       p[450] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_3_0_REG);
-       p[451] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_2_0_REG);
-       p[452] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_1_0_REG);
-       p[453] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_0_0_REG);
-       p[454] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_UCAST_CFG_0_REG);
-       p[455] = dsaf_read_dev(ddev, DSAF_TBL_LIN_CFG_0_REG);
-       p[456] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RDATA_HIGH_0_REG);
-       p[457] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RDATA_LOW_0_REG);
-       p[458] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA4_0_REG);
-       p[459] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA3_0_REG);
-       p[460] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA2_0_REG);
-       p[461] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA1_0_REG);
-       p[462] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA0_0_REG);
-       p[463] = dsaf_read_dev(ddev, DSAF_TBL_LIN_RDATA_0_REG);
+       p[445] = dsaf_read_dev(ddev, DSAF_TBL_CTRL_0_REG);
+       p[446] = dsaf_read_dev(ddev, DSAF_TBL_INT_MSK_0_REG);
+       p[447] = dsaf_read_dev(ddev, DSAF_TBL_INT_SRC_0_REG);
+       p[448] = dsaf_read_dev(ddev, DSAF_TBL_INT_STS_0_REG);
+       p[449] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_ADDR_0_REG);
+       p[450] = dsaf_read_dev(ddev, DSAF_TBL_LINE_ADDR_0_REG);
+       p[451] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_HIGH_0_REG);
+       p[452] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_LOW_0_REG);
+       p[453] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_4_0_REG);
+       p[454] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_3_0_REG);
+       p[455] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_2_0_REG);
+       p[456] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_1_0_REG);
+       p[457] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_MCAST_CFG_0_0_REG);
+       p[458] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_UCAST_CFG_0_REG);
+       p[459] = dsaf_read_dev(ddev, DSAF_TBL_LIN_CFG_0_REG);
+       p[460] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RDATA_HIGH_0_REG);
+       p[461] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RDATA_LOW_0_REG);
+       p[462] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA4_0_REG);
+       p[463] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA3_0_REG);
+       p[464] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA2_0_REG);
+       p[465] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA1_0_REG);
+       p[466] = dsaf_read_dev(ddev, DSAF_TBL_TCAM_RAM_RDATA0_0_REG);
+       p[467] = dsaf_read_dev(ddev, DSAF_TBL_LIN_RDATA_0_REG);
 
        for (i = 0; i < DSAF_SW_PORT_NUM; i++) {
                j = i * 0x8;
-               p[464 + 2 * i] = dsaf_read_dev(ddev,
+               p[468 + 2 * i] = dsaf_read_dev(ddev,
                        DSAF_TBL_DA0_MIS_INFO1_0_REG + j);
-               p[465 + 2 * i] = dsaf_read_dev(ddev,
+               p[469 + 2 * i] = dsaf_read_dev(ddev,
                        DSAF_TBL_DA0_MIS_INFO0_0_REG + j);
        }
 
-       p[480] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO2_0_REG);
-       p[481] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO1_0_REG);
-       p[482] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO0_0_REG);
-       p[483] = dsaf_read_dev(ddev, DSAF_TBL_PUL_0_REG);
-       p[484] = dsaf_read_dev(ddev, DSAF_TBL_OLD_RSLT_0_REG);
-       p[485] = dsaf_read_dev(ddev, DSAF_TBL_OLD_SCAN_VAL_0_REG);
-       p[486] = dsaf_read_dev(ddev, DSAF_TBL_DFX_CTRL_0_REG);
-       p[487] = dsaf_read_dev(ddev, DSAF_TBL_DFX_STAT_0_REG);
-       p[488] = dsaf_read_dev(ddev, DSAF_TBL_DFX_STAT_2_0_REG);
-       p[489] = dsaf_read_dev(ddev, DSAF_TBL_LKUP_NUM_I_0_REG);
-       p[490] = dsaf_read_dev(ddev, DSAF_TBL_LKUP_NUM_O_0_REG);
-       p[491] = dsaf_read_dev(ddev, DSAF_TBL_UCAST_BCAST_MIS_INFO_0_0_REG);
+       p[484] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO2_0_REG);
+       p[485] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO1_0_REG);
+       p[486] = dsaf_read_dev(ddev, DSAF_TBL_SA_MIS_INFO0_0_REG);
+       p[487] = dsaf_read_dev(ddev, DSAF_TBL_PUL_0_REG);
+       p[488] = dsaf_read_dev(ddev, DSAF_TBL_OLD_RSLT_0_REG);
+       p[489] = dsaf_read_dev(ddev, DSAF_TBL_OLD_SCAN_VAL_0_REG);
+       p[490] = dsaf_read_dev(ddev, DSAF_TBL_DFX_CTRL_0_REG);
+       p[491] = dsaf_read_dev(ddev, DSAF_TBL_DFX_STAT_0_REG);
+       p[492] = dsaf_read_dev(ddev, DSAF_TBL_DFX_STAT_2_0_REG);
+       p[493] = dsaf_read_dev(ddev, DSAF_TBL_LKUP_NUM_I_0_REG);
+       p[494] = dsaf_read_dev(ddev, DSAF_TBL_LKUP_NUM_O_0_REG);
+       p[495] = dsaf_read_dev(ddev, DSAF_TBL_UCAST_BCAST_MIS_INFO_0_0_REG);
 
        /* dsaf other registers */
-       p[492] = dsaf_read_dev(ddev, DSAF_INODE_FIFO_WL_0_REG + port * 0x4);
-       p[493] = dsaf_read_dev(ddev, DSAF_ONODE_FIFO_WL_0_REG + port * 0x4);
-       p[494] = dsaf_read_dev(ddev, DSAF_XGE_GE_WORK_MODE_0_REG + port * 0x4);
-       p[495] = dsaf_read_dev(ddev,
+       p[496] = dsaf_read_dev(ddev, DSAF_INODE_FIFO_WL_0_REG + port * 0x4);
+       p[497] = dsaf_read_dev(ddev, DSAF_ONODE_FIFO_WL_0_REG + port * 0x4);
+       p[498] = dsaf_read_dev(ddev, DSAF_XGE_GE_WORK_MODE_0_REG + port * 0x4);
+       p[499] = dsaf_read_dev(ddev,
                DSAF_XGE_APP_RX_LINK_UP_0_REG + port * 0x4);
-       p[496] = dsaf_read_dev(ddev, DSAF_NETPORT_CTRL_SIG_0_REG + port * 0x4);
-       p[497] = dsaf_read_dev(ddev, DSAF_XGE_CTRL_SIG_CFG_0_REG + port * 0x4);
+       p[500] = dsaf_read_dev(ddev, DSAF_NETPORT_CTRL_SIG_0_REG + port * 0x4);
+       p[501] = dsaf_read_dev(ddev, DSAF_XGE_CTRL_SIG_CFG_0_REG + port * 0x4);
 
        if (!is_ver1)
-               p[498] = dsaf_read_dev(ddev, DSAF_PAUSE_CFG_REG + port * 0x4);
+               p[502] = dsaf_read_dev(ddev, DSAF_PAUSE_CFG_REG + port * 0x4);
 
        /* mark end of dsaf regs */
-       for (i = 499; i < 504; i++)
+       for (i = 503; i < 504; i++)
                p[i] = 0xdddddddd;
 }
 
@@ -2673,58 +2750,156 @@ int hns_dsaf_get_regs_count(void)
        return DSAF_DUMP_REGS_NUM;
 }
 
-/* Reserve the last TCAM entry for promisc support */
-#define dsaf_promisc_tcam_entry(port) \
-       (DSAF_TCAM_SUM - DSAFV2_MAC_FUZZY_TCAM_NUM + (port))
-void hns_dsaf_set_promisc_tcam(struct dsaf_device *dsaf_dev,
-                              u32 port, bool enable)
+static void set_promisc_tcam_enable(struct dsaf_device *dsaf_dev, u32 port)
 {
+       struct dsaf_tbl_tcam_ucast_cfg tbl_tcam_ucast = {0, 1, 0, 0, 0x80};
+       struct dsaf_tbl_tcam_data tbl_tcam_data_mc = {0x01000000, port};
+       struct dsaf_tbl_tcam_data tbl_tcam_mask_uc = {0x01000000, 0xf};
+       struct dsaf_tbl_tcam_mcast_cfg tbl_tcam_mcast = {0, 0, {0} };
        struct dsaf_drv_priv *priv = hns_dsaf_dev_priv(dsaf_dev);
-       struct dsaf_drv_soft_mac_tbl *soft_mac_entry = priv->soft_mac_tbl;
-       u16 entry_index;
-       struct dsaf_drv_tbl_tcam_key tbl_tcam_data, tbl_tcam_mask;
-       struct dsaf_tbl_tcam_mcast_cfg mac_data = {0};
+       struct dsaf_tbl_tcam_data tbl_tcam_data_uc = {0, port};
+       struct dsaf_drv_mac_single_dest_entry mask_entry;
+       struct dsaf_drv_tbl_tcam_key temp_key, mask_key;
+       struct dsaf_drv_soft_mac_tbl *soft_mac_entry;
+       u16 entry_index = DSAF_INVALID_ENTRY_IDX;
+       struct dsaf_drv_tbl_tcam_key mac_key;
+       struct hns_mac_cb *mac_cb;
+       u8 addr[ETH_ALEN] = {0};
+       u8 port_num;
+       u16 mskid;
+
+       /* promisc use vague table match with vlanid = 0 & macaddr = 0 */
+       hns_dsaf_set_mac_key(dsaf_dev, &mac_key, 0x00, port, addr);
+       entry_index = hns_dsaf_find_soft_mac_entry(dsaf_dev, &mac_key);
+       if (entry_index != DSAF_INVALID_ENTRY_IDX)
+               return;
+
+       /* put promisc tcam entry in the end. */
+       /* 1. set promisc unicast vague tcam entry. */
+       entry_index = hns_dsaf_find_empty_mac_entry_reverse(dsaf_dev);
+       if (entry_index == DSAF_INVALID_ENTRY_IDX) {
+               dev_err(dsaf_dev->dev,
+                       "enable uc promisc failed (port:%#x)\n",
+                       port);
+               return;
+       }
+
+       mac_cb = dsaf_dev->mac_cb[port];
+       (void)hns_mac_get_inner_port_num(mac_cb, 0, &port_num);
+       tbl_tcam_ucast.tbl_ucast_out_port = port_num;
 
-       if ((AE_IS_VER1(dsaf_dev->dsaf_ver)) || HNS_DSAF_IS_DEBUG(dsaf_dev))
+       /* config uc vague table */
+       hns_dsaf_tcam_uc_cfg_vague(dsaf_dev, entry_index, &tbl_tcam_data_uc,
+                                  &tbl_tcam_mask_uc, &tbl_tcam_ucast);
+
+       /* update software entry */
+       soft_mac_entry = priv->soft_mac_tbl;
+       soft_mac_entry += entry_index;
+       soft_mac_entry->index = entry_index;
+       soft_mac_entry->tcam_key.high.val = mac_key.high.val;
+       soft_mac_entry->tcam_key.low.val = mac_key.low.val;
+       /* step back to the START for mc. */
+       soft_mac_entry = priv->soft_mac_tbl;
+
+       /* 2. set promisc multicast vague tcam entry. */
+       entry_index = hns_dsaf_find_empty_mac_entry_reverse(dsaf_dev);
+       if (entry_index == DSAF_INVALID_ENTRY_IDX) {
+               dev_err(dsaf_dev->dev,
+                       "enable mc promisc failed (port:%#x)\n",
+                       port);
                return;
+       }
+
+       memset(&mask_entry, 0x0, sizeof(mask_entry));
+       memset(&mask_key, 0x0, sizeof(mask_key));
+       memset(&temp_key, 0x0, sizeof(temp_key));
+       mask_entry.addr[0] = 0x01;
+       hns_dsaf_set_mac_key(dsaf_dev, &mask_key, mask_entry.in_vlan_id,
+                            port, mask_entry.addr);
+       tbl_tcam_mcast.tbl_mcast_item_vld = 1;
+       tbl_tcam_mcast.tbl_mcast_old_en = 0;
 
-       /* find the tcam entry index for promisc */
-       entry_index = dsaf_promisc_tcam_entry(port);
-
-       memset(&tbl_tcam_data, 0, sizeof(tbl_tcam_data));
-       memset(&tbl_tcam_mask, 0, sizeof(tbl_tcam_mask));
-
-       /* config key mask */
-       if (enable) {
-               dsaf_set_field(tbl_tcam_data.low.bits.port_vlan,
-                              DSAF_TBL_TCAM_KEY_PORT_M,
-                              DSAF_TBL_TCAM_KEY_PORT_S, port);
-               dsaf_set_field(tbl_tcam_mask.low.bits.port_vlan,
-                              DSAF_TBL_TCAM_KEY_PORT_M,
-                              DSAF_TBL_TCAM_KEY_PORT_S, 0xf);
-
-               /* SUB_QID */
-               dsaf_set_bit(mac_data.tbl_mcast_port_msk[0],
-                            DSAF_SERVICE_NW_NUM, true);
-               mac_data.tbl_mcast_item_vld = true;     /* item_vld bit */
+       if (port < DSAF_SERVICE_NW_NUM) {
+               mskid = port;
+       } else if (port >= DSAF_BASE_INNER_PORT_NUM) {
+               mskid = port - DSAF_BASE_INNER_PORT_NUM + DSAF_SERVICE_NW_NUM;
        } else {
-               mac_data.tbl_mcast_item_vld = false;    /* item_vld bit */
+               dev_err(dsaf_dev->dev, "%s,pnum(%d)error,key(%#x:%#x)\n",
+                       dsaf_dev->ae_dev.name, port,
+                       mask_key.high.val, mask_key.low.val);
+               return;
        }
 
-       dev_dbg(dsaf_dev->dev,
-               "set_promisc_entry, %s Mac key(%#x:%#x) entry_index%d\n",
-               dsaf_dev->ae_dev.name, tbl_tcam_data.high.val,
-               tbl_tcam_data.low.val, entry_index);
+       dsaf_set_bit(tbl_tcam_mcast.tbl_mcast_port_msk[mskid / 32],
+                    mskid % 32, 1);
+       memcpy(&temp_key, &mask_key, sizeof(mask_key));
+       hns_dsaf_tcam_mc_cfg_vague(dsaf_dev, entry_index, &tbl_tcam_data_mc,
+                                  (struct dsaf_tbl_tcam_data *)(&mask_key),
+                                  &tbl_tcam_mcast);
+
+       /* update software entry */
+       soft_mac_entry += entry_index;
+       soft_mac_entry->index = entry_index;
+       soft_mac_entry->tcam_key.high.val = temp_key.high.val;
+       soft_mac_entry->tcam_key.low.val = temp_key.low.val;
+}
 
-       /* config promisc entry with mask */
-       hns_dsaf_tcam_mc_cfg(dsaf_dev, entry_index,
-                            (struct dsaf_tbl_tcam_data *)&tbl_tcam_data,
-                            (struct dsaf_tbl_tcam_data *)&tbl_tcam_mask,
-                            &mac_data);
+static void set_promisc_tcam_disable(struct dsaf_device *dsaf_dev, u32 port)
+{
+       struct dsaf_tbl_tcam_data tbl_tcam_data_mc = {0x01000000, port};
+       struct dsaf_tbl_tcam_ucast_cfg tbl_tcam_ucast = {0, 0, 0, 0, 0};
+       struct dsaf_tbl_tcam_mcast_cfg tbl_tcam_mcast = {0, 0, {0} };
+       struct dsaf_drv_priv *priv = hns_dsaf_dev_priv(dsaf_dev);
+       struct dsaf_tbl_tcam_data tbl_tcam_data_uc = {0, 0};
+       struct dsaf_tbl_tcam_data tbl_tcam_mask = {0, 0};
+       struct dsaf_drv_soft_mac_tbl *soft_mac_entry;
+       u16 entry_index = DSAF_INVALID_ENTRY_IDX;
+       struct dsaf_drv_tbl_tcam_key mac_key;
+       u8 addr[ETH_ALEN] = {0};
 
-       /* config software entry */
+       /* 1. delete uc vague tcam entry. */
+       /* promisc use vague table match with vlanid = 0 & macaddr = 0 */
+       hns_dsaf_set_mac_key(dsaf_dev, &mac_key, 0x00, port, addr);
+       entry_index = hns_dsaf_find_soft_mac_entry(dsaf_dev, &mac_key);
+
+       if (entry_index == DSAF_INVALID_ENTRY_IDX)
+               return;
+
+       /* config uc vague table */
+       hns_dsaf_tcam_uc_cfg_vague(dsaf_dev, entry_index, &tbl_tcam_data_uc,
+                                  &tbl_tcam_mask, &tbl_tcam_ucast);
+       /* update soft management table. */
+       soft_mac_entry = priv->soft_mac_tbl;
+       soft_mac_entry += entry_index;
+       soft_mac_entry->index = DSAF_INVALID_ENTRY_IDX;
+       /* step back to the START for mc. */
+       soft_mac_entry = priv->soft_mac_tbl;
+
+       /* 2. delete mc vague tcam entry. */
+       addr[0] = 0x01;
+       memset(&mac_key, 0x0, sizeof(mac_key));
+       hns_dsaf_set_mac_key(dsaf_dev, &mac_key, 0x00, port, addr);
+       entry_index = hns_dsaf_find_soft_mac_entry(dsaf_dev, &mac_key);
+
+       if (entry_index == DSAF_INVALID_ENTRY_IDX)
+               return;
+
+       /* config mc vague table */
+       hns_dsaf_tcam_mc_cfg_vague(dsaf_dev, entry_index, &tbl_tcam_data_mc,
+                                  &tbl_tcam_mask, &tbl_tcam_mcast);
+       /* update soft management table. */
        soft_mac_entry += entry_index;
-       soft_mac_entry->index = enable ? entry_index : DSAF_INVALID_ENTRY_IDX;
+       soft_mac_entry->index = DSAF_INVALID_ENTRY_IDX;
+}
+
+/* Reserve the last TCAM entry for promisc support */
+void hns_dsaf_set_promisc_tcam(struct dsaf_device *dsaf_dev,
+                              u32 port, bool enable)
+{
+       if (enable)
+               set_promisc_tcam_enable(dsaf_dev, port);
+       else
+               set_promisc_tcam_disable(dsaf_dev, port);
 }
 
 int hns_dsaf_wait_pkt_clean(struct dsaf_device *dsaf_dev, int port)
index 74d935d82cbc6050a287a07532024675ce75254e..b9733b0b848263bc9a25ccf42f3d8b433a7b9e5e 100644 (file)
 #define DSAF_INODE_IN_DATA_STP_DISC_0_REG      0x1A50
 #define DSAF_INODE_GE_FC_EN_0_REG              0x1B00
 #define DSAF_INODE_VC0_IN_PKT_NUM_0_REG                0x1B50
-#define DSAF_INODE_VC1_IN_PKT_NUM_0_REG                0x1C00
+#define DSAF_INODE_VC1_IN_PKT_NUM_0_REG                0x103C
 #define DSAF_INODE_IN_PRIO_PAUSE_BASE_REG      0x1C00
 #define DSAF_INODE_IN_PRIO_PAUSE_BASE_OFFSET   0x100
 #define DSAF_INODE_IN_PRIO_PAUSE_OFFSET                0x50
 #define RCB_ECC_ERR_ADDR4_REG                  0x460
 #define RCB_ECC_ERR_ADDR5_REG                  0x464
 
-#define RCB_COM_SF_CFG_INTMASK_RING            0x480
-#define RCB_COM_SF_CFG_RING_STS                        0x484
-#define RCB_COM_SF_CFG_RING                    0x488
-#define RCB_COM_SF_CFG_INTMASK_BD              0x48C
-#define RCB_COM_SF_CFG_BD_RINT_STS             0x470
+#define RCB_COM_SF_CFG_INTMASK_RING            0x470
+#define RCB_COM_SF_CFG_RING_STS                        0x474
+#define RCB_COM_SF_CFG_RING                    0x478
+#define RCB_COM_SF_CFG_INTMASK_BD              0x47C
+#define RCB_COM_SF_CFG_BD_RINT_STS             0x480
 #define RCB_COM_RCB_RD_BD_BUSY                 0x490
 #define RCB_COM_RCB_FBD_CRT_EN                 0x494
 #define RCB_COM_AXI_WR_ERR_INTMASK             0x498
 #define GMAC_LD_LINK_COUNTER_REG               0x01D0UL
 #define GMAC_LOOP_REG                          0x01DCUL
 #define GMAC_RECV_CONTROL_REG                  0x01E0UL
+#define GMAC_PCS_RX_EN_REG                     0x01E4UL
 #define GMAC_VLAN_CODE_REG                     0x01E8UL
 #define GMAC_RX_OVERRUN_CNT_REG                        0x01ECUL
 #define GMAC_RX_LENGTHFIELD_ERR_CNT_REG                0x01F4UL
index 28e907831b0eddbf760e0edb579ae7ae708520e0..6242249c9f4c544450d17808939e9f4868efee84 100644 (file)
@@ -1186,6 +1186,9 @@ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h)
        if (h->phy_if == PHY_INTERFACE_MODE_XGMII)
                phy_dev->autoneg = false;
 
+       if (h->phy_if == PHY_INTERFACE_MODE_SGMII)
+               phy_stop(phy_dev);
+
        return 0;
 }
 
@@ -1281,6 +1284,22 @@ static int hns_nic_init_affinity_mask(int q_num, int ring_idx,
        return cpu;
 }
 
+static void hns_nic_free_irq(int q_num, struct hns_nic_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < q_num * 2; i++) {
+               if (priv->ring_data[i].ring->irq_init_flag == RCB_IRQ_INITED) {
+                       irq_set_affinity_hint(priv->ring_data[i].ring->irq,
+                                             NULL);
+                       free_irq(priv->ring_data[i].ring->irq,
+                                &priv->ring_data[i]);
+                       priv->ring_data[i].ring->irq_init_flag =
+                               RCB_IRQ_NOT_INITED;
+               }
+       }
+}
+
 static int hns_nic_init_irq(struct hns_nic_priv *priv)
 {
        struct hnae_handle *h = priv->ae_handle;
@@ -1306,7 +1325,7 @@ static int hns_nic_init_irq(struct hns_nic_priv *priv)
                if (ret) {
                        netdev_err(priv->netdev, "request irq(%d) fail\n",
                                   rd->ring->irq);
-                       return ret;
+                       goto out_free_irq;
                }
                disable_irq(rd->ring->irq);
 
@@ -1321,6 +1340,10 @@ static int hns_nic_init_irq(struct hns_nic_priv *priv)
        }
 
        return 0;
+
+out_free_irq:
+       hns_nic_free_irq(h->q_num, priv);
+       return ret;
 }
 
 static int hns_nic_net_up(struct net_device *ndev)
@@ -1330,6 +1353,9 @@ static int hns_nic_net_up(struct net_device *ndev)
        int i, j;
        int ret;
 
+       if (!test_bit(NIC_STATE_DOWN, &priv->state))
+               return 0;
+
        ret = hns_nic_init_irq(priv);
        if (ret != 0) {
                netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
@@ -1365,6 +1391,7 @@ out_has_some_queues:
        for (j = i - 1; j >= 0; j--)
                hns_nic_ring_close(ndev, j);
 
+       hns_nic_free_irq(h->q_num, priv);
        set_bit(NIC_STATE_DOWN, &priv->state);
 
        return ret;
@@ -1482,11 +1509,19 @@ static int hns_nic_net_stop(struct net_device *ndev)
 }
 
 static void hns_tx_timeout_reset(struct hns_nic_priv *priv);
+#define HNS_TX_TIMEO_LIMIT (40 * HZ)
 static void hns_nic_net_timeout(struct net_device *ndev)
 {
        struct hns_nic_priv *priv = netdev_priv(ndev);
 
-       hns_tx_timeout_reset(priv);
+       if (ndev->watchdog_timeo < HNS_TX_TIMEO_LIMIT) {
+               ndev->watchdog_timeo *= 2;
+               netdev_info(ndev, "watchdog_timo changed to %d.\n",
+                           ndev->watchdog_timeo);
+       } else {
+               ndev->watchdog_timeo = HNS_NIC_TX_TIMEOUT;
+               hns_tx_timeout_reset(priv);
+       }
 }
 
 static int hns_nic_do_ioctl(struct net_device *netdev, struct ifreq *ifr,
@@ -2049,11 +2084,11 @@ static void hns_nic_service_task(struct work_struct *work)
                = container_of(work, struct hns_nic_priv, service_task);
        struct hnae_handle *h = priv->ae_handle;
 
+       hns_nic_reset_subtask(priv);
        hns_nic_update_link_status(priv->netdev);
        h->dev->ops->update_led_status(h);
        hns_nic_update_stats(priv->netdev);
 
-       hns_nic_reset_subtask(priv);
        hns_nic_service_event_complete(priv);
 }
 
@@ -2339,7 +2374,7 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
        ndev->min_mtu = MAC_MIN_MTU;
        switch (priv->enet_ver) {
        case AE_VERSION_2:
-               ndev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+               ndev->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_NTUPLE;
                ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                        NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
                        NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6;
index ed50b8dee44f3a8699ca0a226d81f482cdd0f3c0..67cc6d9c8fd7257af3e3c592fd96a636cc8be326 100644 (file)
@@ -1939,8 +1939,9 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
 static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
 {
        struct ibmvnic_rwi *rwi;
+       unsigned long flags;
 
-       mutex_lock(&adapter->rwi_lock);
+       spin_lock_irqsave(&adapter->rwi_lock, flags);
 
        if (!list_empty(&adapter->rwi_list)) {
                rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
@@ -1950,7 +1951,7 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
                rwi = NULL;
        }
 
-       mutex_unlock(&adapter->rwi_lock);
+       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
        return rwi;
 }
 
@@ -2025,6 +2026,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        struct list_head *entry, *tmp_entry;
        struct ibmvnic_rwi *rwi, *tmp;
        struct net_device *netdev = adapter->netdev;
+       unsigned long flags;
        int ret;
 
        if (adapter->state == VNIC_REMOVING ||
@@ -2041,21 +2043,21 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
                goto err;
        }
 
-       mutex_lock(&adapter->rwi_lock);
+       spin_lock_irqsave(&adapter->rwi_lock, flags);
 
        list_for_each(entry, &adapter->rwi_list) {
                tmp = list_entry(entry, struct ibmvnic_rwi, list);
                if (tmp->reset_reason == reason) {
                        netdev_dbg(netdev, "Skipping matching reset\n");
-                       mutex_unlock(&adapter->rwi_lock);
+                       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
                        ret = EBUSY;
                        goto err;
                }
        }
 
-       rwi = kzalloc(sizeof(*rwi), GFP_KERNEL);
+       rwi = kzalloc(sizeof(*rwi), GFP_ATOMIC);
        if (!rwi) {
-               mutex_unlock(&adapter->rwi_lock);
+               spin_unlock_irqrestore(&adapter->rwi_lock, flags);
                ibmvnic_close(netdev);
                ret = ENOMEM;
                goto err;
@@ -2069,7 +2071,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        }
        rwi->reset_reason = reason;
        list_add_tail(&rwi->list, &adapter->rwi_list);
-       mutex_unlock(&adapter->rwi_lock);
+       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
        adapter->resetting = true;
        netdev_dbg(adapter->netdev, "Scheduling reset (reason %d)\n", reason);
        schedule_work(&adapter->ibmvnic_reset);
@@ -4759,7 +4761,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
        INIT_LIST_HEAD(&adapter->rwi_list);
-       mutex_init(&adapter->rwi_lock);
+       spin_lock_init(&adapter->rwi_lock);
        adapter->resetting = false;
 
        adapter->mac_change_pending = false;
index 99c4f8d331ce7c489c4b3badb1d5fbbe57ff8dea..f2018dbebfa527684a2dd8f91aeedfd1413d7fa1 100644 (file)
@@ -1075,7 +1075,7 @@ struct ibmvnic_adapter {
        struct tasklet_struct tasklet;
        enum vnic_state state;
        enum ibmvnic_reset_reason reset_reason;
-       struct mutex rwi_lock;
+       spinlock_t rwi_lock;
        struct list_head rwi_list;
        struct work_struct ibmvnic_reset;
        bool resetting;
index a3f45335437c3cecde089e44c3a13a3932001960..0e5dc74b4ef229cc6874e9fefce4a6d9f3ffff94 100644 (file)
@@ -1543,17 +1543,17 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
 
        /* Copy the address first, so that we avoid a possible race with
-        * .set_rx_mode(). If we copy after changing the address in the filter
-        * list, we might open ourselves to a narrow race window where
-        * .set_rx_mode could delete our dev_addr filter and prevent traffic
-        * from passing.
+        * .set_rx_mode().
+        * - Remove old address from MAC filter
+        * - Copy new address
+        * - Add new address to MAC filter
         */
-       ether_addr_copy(netdev->dev_addr, addr->sa_data);
-
        spin_lock_bh(&vsi->mac_filter_hash_lock);
        i40e_del_mac_filter(vsi, netdev->dev_addr);
-       i40e_add_mac_filter(vsi, addr->sa_data);
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
+       i40e_add_mac_filter(vsi, netdev->dev_addr);
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
        if (vsi->type == I40E_VSI_MAIN) {
                i40e_status ret;
 
index aef3c89ee79c4e7384e0713c55b12090c1c36f60..d0a95424ce58eee4cd1510d7815258bc774ae03e 100644 (file)
@@ -1558,24 +1558,6 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
        return true;
 }
 
-/**
- * i40e_receive_skb - Send a completed packet up the stack
- * @rx_ring:  rx ring in play
- * @skb: packet to send up
- * @vlan_tag: vlan tag for packet
- **/
-void i40e_receive_skb(struct i40e_ring *rx_ring,
-                     struct sk_buff *skb, u16 vlan_tag)
-{
-       struct i40e_q_vector *q_vector = rx_ring->q_vector;
-
-       if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-           (vlan_tag & VLAN_VID_MASK))
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
-
-       napi_gro_receive(&q_vector->napi, skb);
-}
-
 /**
  * i40e_alloc_rx_buffers - Replace used receive buffers
  * @rx_ring: ring to place buffers on
@@ -1793,8 +1775,7 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
  * other fields within the skb.
  **/
 void i40e_process_skb_fields(struct i40e_ring *rx_ring,
-                            union i40e_rx_desc *rx_desc, struct sk_buff *skb,
-                            u8 rx_ptype)
+                            union i40e_rx_desc *rx_desc, struct sk_buff *skb)
 {
        u64 qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
        u32 rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
@@ -1802,6 +1783,8 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
        u32 tsynvalid = rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK;
        u32 tsyn = (rx_status & I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
                   I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT;
+       u8 rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
+                     I40E_RXD_QW1_PTYPE_SHIFT;
 
        if (unlikely(tsynvalid))
                i40e_ptp_rx_hwtstamp(rx_ring->vsi->back, skb, tsyn);
@@ -1812,6 +1795,13 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
 
        skb_record_rx_queue(skb, rx_ring->queue_index);
 
+       if (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) {
+               u16 vlan_tag = rx_desc->wb.qword0.lo_dword.l2tag1;
+
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                      le16_to_cpu(vlan_tag));
+       }
+
        /* modifies the skb - consumes the enet header */
        skb->protocol = eth_type_trans(skb, rx_ring->netdev);
 }
@@ -2350,8 +2340,6 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                struct i40e_rx_buffer *rx_buffer;
                union i40e_rx_desc *rx_desc;
                unsigned int size;
-               u16 vlan_tag;
-               u8 rx_ptype;
                u64 qword;
 
                /* return some buffers to hardware, one at a time is too slow */
@@ -2444,18 +2432,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
 
-               qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
-               rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
-                          I40E_RXD_QW1_PTYPE_SHIFT;
-
                /* populate checksum, VLAN, and protocol */
-               i40e_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
-
-               vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
-                          le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
+               i40e_process_skb_fields(rx_ring, rx_desc, skb);
 
                i40e_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb);
-               i40e_receive_skb(rx_ring, skb, vlan_tag);
+               napi_gro_receive(&rx_ring->q_vector->napi, skb);
                skb = NULL;
 
                /* update budget accounting */
index 09809dffe39931a843b11204d3480c30e1f68554..8af0e99c6c0d89b9e9aa7f59b3c6eaaa8ccdb7fb 100644 (file)
@@ -12,10 +12,7 @@ struct i40e_rx_buffer *i40e_clean_programming_status(
        union i40e_rx_desc *rx_desc,
        u64 qw);
 void i40e_process_skb_fields(struct i40e_ring *rx_ring,
-                            union i40e_rx_desc *rx_desc, struct sk_buff *skb,
-                            u8 rx_ptype);
-void i40e_receive_skb(struct i40e_ring *rx_ring,
-                     struct sk_buff *skb, u16 vlan_tag);
+                            union i40e_rx_desc *rx_desc, struct sk_buff *skb);
 void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring);
 void i40e_update_rx_stats(struct i40e_ring *rx_ring,
                          unsigned int total_rx_bytes,
index 433c8e688c78d5623e65fe5edefeae4cc22d67a8..870cf654e4364480e41887ec0e0d054a05f4e25a 100644 (file)
@@ -634,8 +634,6 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
                struct i40e_rx_buffer *bi;
                union i40e_rx_desc *rx_desc;
                unsigned int size;
-               u16 vlan_tag;
-               u8 rx_ptype;
                u64 qword;
 
                if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
@@ -713,14 +711,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
                total_rx_bytes += skb->len;
                total_rx_packets++;
 
-               qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
-               rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
-                          I40E_RXD_QW1_PTYPE_SHIFT;
-               i40e_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
-
-               vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
-                          le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
-               i40e_receive_skb(rx_ring, skb, vlan_tag);
+               i40e_process_skb_fields(rx_ring, rx_desc, skb);
+               napi_gro_receive(&rx_ring->q_vector->napi, skb);
        }
 
        i40e_finalize_xdp_rx(rx_ring, xdp_xmit);
index 5dacfc870259881f8746a72546f5c410f4bf06f6..345701af7749c2e983813b76589baf7e79202fc5 100644 (file)
@@ -700,7 +700,6 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
        u8 num_tcs = adapter->hw_tcs;
        u32 reg_val;
        u32 queue;
-       u32 word;
 
        /* remove VLAN filters beloning to this VF */
        ixgbe_clear_vf_vlans(adapter, vf);
@@ -758,6 +757,14 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
                }
        }
 
+       IXGBE_WRITE_FLUSH(hw);
+}
+
+static void ixgbe_vf_clear_mbx(struct ixgbe_adapter *adapter, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 word;
+
        /* Clear VF's mailbox memory */
        for (word = 0; word < IXGBE_VFMAILBOX_SIZE; word++)
                IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf), word, 0);
@@ -831,6 +838,8 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
        /* reset the filters for the device */
        ixgbe_vf_reset_event(adapter, vf);
 
+       ixgbe_vf_clear_mbx(adapter, vf);
+
        /* set vf mac address */
        if (!is_zero_ether_addr(vf_mac))
                ixgbe_set_vf_mac(adapter, vf, vf_mac);
index e5397c8197b9c3713c48e925dad0dfcee732c0b9..61b23497f83692fc164dd6ace1e0948b6eece467 100644 (file)
@@ -408,7 +408,6 @@ struct mvneta_port {
        struct mvneta_pcpu_stats __percpu       *stats;
 
        int pkt_size;
-       unsigned int frag_size;
        void __iomem *base;
        struct mvneta_rx_queue *rxqs;
        struct mvneta_tx_queue *txqs;
@@ -2905,7 +2904,9 @@ static void mvneta_rxq_hw_init(struct mvneta_port *pp,
        if (!pp->bm_priv) {
                /* Set Offset */
                mvneta_rxq_offset_set(pp, rxq, 0);
-               mvneta_rxq_buf_size_set(pp, rxq, pp->frag_size);
+               mvneta_rxq_buf_size_set(pp, rxq, PAGE_SIZE < SZ_64K ?
+                                       PAGE_SIZE :
+                                       MVNETA_RX_BUF_SIZE(pp->pkt_size));
                mvneta_rxq_bm_disable(pp, rxq);
                mvneta_rxq_fill(pp, rxq, rxq->size);
        } else {
@@ -3760,7 +3761,6 @@ static int mvneta_open(struct net_device *dev)
        int ret;
 
        pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);
-       pp->frag_size = PAGE_SIZE;
 
        ret = mvneta_setup_rxqs(pp);
        if (ret)
index 125ea99418df6915da4c5ad9427802e0aeb738f9..f1dab0b55769974a193684182e12a499fee9706e 100644 (file)
@@ -4405,12 +4405,15 @@ static void mvpp2_phylink_validate(struct net_device *dev,
        case PHY_INTERFACE_MODE_10GKR:
        case PHY_INTERFACE_MODE_XAUI:
        case PHY_INTERFACE_MODE_NA:
-               phylink_set(mask, 10000baseCR_Full);
-               phylink_set(mask, 10000baseSR_Full);
-               phylink_set(mask, 10000baseLR_Full);
-               phylink_set(mask, 10000baseLRM_Full);
-               phylink_set(mask, 10000baseER_Full);
-               phylink_set(mask, 10000baseKR_Full);
+               if (port->gop_id == 0) {
+                       phylink_set(mask, 10000baseT_Full);
+                       phylink_set(mask, 10000baseCR_Full);
+                       phylink_set(mask, 10000baseSR_Full);
+                       phylink_set(mask, 10000baseLR_Full);
+                       phylink_set(mask, 10000baseLRM_Full);
+                       phylink_set(mask, 10000baseER_Full);
+                       phylink_set(mask, 10000baseKR_Full);
+               }
                /* Fall-through */
        case PHY_INTERFACE_MODE_RGMII:
        case PHY_INTERFACE_MODE_RGMII_ID:
@@ -4421,7 +4424,6 @@ static void mvpp2_phylink_validate(struct net_device *dev,
                phylink_set(mask, 10baseT_Full);
                phylink_set(mask, 100baseT_Half);
                phylink_set(mask, 100baseT_Full);
-               phylink_set(mask, 10000baseT_Full);
                /* Fall-through */
        case PHY_INTERFACE_MODE_1000BASEX:
        case PHY_INTERFACE_MODE_2500BASEX:
index 25c1c4f96841244336c3257abbd213707655ad51..f480763dcd0db1f16d0fcb1da7f61172dd8a5bf7 100644 (file)
@@ -1190,11 +1190,6 @@ int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
                              struct ethtool_ts_info *info)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
-       int ret;
-
-       ret = ethtool_op_get_ts_info(priv->netdev, info);
-       if (ret)
-               return ret;
 
        info->phc_index = mlx5_clock_get_ptp_index(mdev);
 
@@ -1202,9 +1197,9 @@ int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
            info->phc_index == -1)
                return 0;
 
-       info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
-                                SOF_TIMESTAMPING_RX_HARDWARE |
-                                SOF_TIMESTAMPING_RAW_HARDWARE;
+       info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+                               SOF_TIMESTAMPING_RX_HARDWARE |
+                               SOF_TIMESTAMPING_RAW_HARDWARE;
 
        info->tx_types = BIT(HWTSTAMP_TX_OFF) |
                         BIT(HWTSTAMP_TX_ON);
index 871313d6b34d1b315e6ef1a9c07cba396de14186..b70cb6fd164c4fb23f93653e17b08c3fb0d8204d 100644 (file)
@@ -128,6 +128,8 @@ static bool mlx5e_rx_is_linear_skb(struct mlx5_core_dev *mdev,
        return !params->lro_en && frag_sz <= PAGE_SIZE;
 }
 
+#define MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ ((BIT(__mlx5_bit_sz(wq, log_wqe_stride_size)) - 1) + \
+                                         MLX5_MPWQE_LOG_STRIDE_SZ_BASE)
 static bool mlx5e_rx_mpwqe_is_linear_skb(struct mlx5_core_dev *mdev,
                                         struct mlx5e_params *params)
 {
@@ -138,6 +140,9 @@ static bool mlx5e_rx_mpwqe_is_linear_skb(struct mlx5_core_dev *mdev,
        if (!mlx5e_rx_is_linear_skb(mdev, params))
                return false;
 
+       if (order_base_2(frag_sz) > MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ)
+               return false;
+
        if (MLX5_CAP_GEN(mdev, ext_stride_num_range))
                return true;
 
@@ -1396,6 +1401,7 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
        struct mlx5_core_dev *mdev = c->mdev;
        struct mlx5_rate_limit rl = {0};
 
+       cancel_work_sync(&sq->dim.work);
        mlx5e_destroy_sq(mdev, sq->sqn);
        if (sq->rate_limit) {
                rl.rate = sq->rate_limit;
index c3c657548824117f1732f3c7d14158c9a2a8e2a0..820fe85100b08dffd406a863f2e1f50f7879cfda 100644 (file)
@@ -46,6 +46,7 @@
 
 #define MLX5E_REP_PARAMS_LOG_SQ_SIZE \
        max(0x6, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
+#define MLX5E_REP_PARAMS_DEF_NUM_CHANNELS 1
 
 static const char mlx5e_rep_driver_name[] = "mlx5e_rep";
 
@@ -466,8 +467,8 @@ static void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
 
        ASSERT_RTNL();
 
-       if ((!neigh_connected && (e->flags & MLX5_ENCAP_ENTRY_VALID)) ||
-           !ether_addr_equal(e->h_dest, ha))
+       if ((e->flags & MLX5_ENCAP_ENTRY_VALID) &&
+           (!neigh_connected || !ether_addr_equal(e->h_dest, ha)))
                mlx5e_tc_encap_flows_del(priv, e);
 
        if (neigh_connected && !(e->flags & MLX5_ENCAP_ENTRY_VALID)) {
@@ -1083,9 +1084,7 @@ static int mlx5e_init_rep(struct mlx5_core_dev *mdev,
        if (err)
                return err;
 
-
-       priv->channels.params.num_channels =
-                               mlx5e_get_netdev_max_channels(netdev);
+       priv->channels.params.num_channels = MLX5E_REP_PARAMS_DEF_NUM_CHANNELS;
 
        mlx5e_build_rep_params(mdev, &priv->channels.params, netdev->mtu);
        mlx5e_build_rep_netdev(netdev);
index 624eed345b5d2b19fa5ed54935667b41090383f8..0b5ef6d4e81586fab515de64843a44465ec757fa 100644 (file)
@@ -1190,7 +1190,7 @@ mpwrq_cqe_out:
 int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
 {
        struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq);
-       struct mlx5e_xdpsq *xdpsq;
+       struct mlx5e_xdpsq *xdpsq = &rq->xdpsq;
        struct mlx5_cqe64 *cqe;
        int work_done = 0;
 
@@ -1201,10 +1201,11 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
                work_done += mlx5e_decompress_cqes_cont(rq, cq, 0, budget);
 
        cqe = mlx5_cqwq_get_cqe(&cq->wq);
-       if (!cqe)
+       if (!cqe) {
+               if (unlikely(work_done))
+                       goto out;
                return 0;
-
-       xdpsq = &rq->xdpsq;
+       }
 
        do {
                if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED) {
@@ -1219,6 +1220,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
                rq->handle_rx_cqe(rq, cqe);
        } while ((++work_done < budget) && (cqe = mlx5_cqwq_get_cqe(&cq->wq)));
 
+out:
        if (xdpsq->doorbell) {
                mlx5e_xmit_xdp_doorbell(xdpsq);
                xdpsq->doorbell = false;
index 3e99d0728b2f2c5366a13f01400d4354d3c80b2c..4337afd610d78daba92068b16669a586aea65942 100644 (file)
@@ -74,7 +74,6 @@ static const struct counter_desc sw_stats_desc[] = {
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_recover) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_cqes) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_wake) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_udp_seg_rem) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_cqe_err) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_xmit) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_full) },
@@ -198,7 +197,6 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
                        s->tx_nop               += sq_stats->nop;
                        s->tx_queue_stopped     += sq_stats->stopped;
                        s->tx_queue_wake        += sq_stats->wake;
-                       s->tx_udp_seg_rem       += sq_stats->udp_seg_rem;
                        s->tx_queue_dropped     += sq_stats->dropped;
                        s->tx_cqe_err           += sq_stats->cqe_err;
                        s->tx_recover           += sq_stats->recover;
index 3f8e870ef4c903bbca01e894bc2608bbb8ead182..3ff69ddae2d3172fd7872bbbce681b9179a3c9f7 100644 (file)
@@ -87,7 +87,6 @@ struct mlx5e_sw_stats {
        u64 tx_recover;
        u64 tx_cqes;
        u64 tx_queue_wake;
-       u64 tx_udp_seg_rem;
        u64 tx_cqe_err;
        u64 tx_xdp_xmit;
        u64 tx_xdp_full;
@@ -221,7 +220,6 @@ struct mlx5e_sq_stats {
        u64 csum_partial_inner;
        u64 added_vlan_packets;
        u64 nop;
-       u64 udp_seg_rem;
 #ifdef CONFIG_MLX5_EN_TLS
        u64 tls_ooo;
        u64 tls_resync_bytes;
index fca6f4132c91a51ac2a03eaaf64b0bbc5b6ff2c3..9dabe9d4b2798bc0b41f77761b8fb1126279ea39 100644 (file)
@@ -870,9 +870,9 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw,
        struct mlx5_flow_handle *rule;
 
        memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr));
-       slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
-       slow_attr->mirror_count = 0,
-       slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN,
+       slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       slow_attr->mirror_count = 0;
+       slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN;
 
        rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr);
        if (!IS_ERR(rule))
@@ -887,6 +887,9 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
                                  struct mlx5_esw_flow_attr *slow_attr)
 {
        memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr));
+       slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       slow_attr->mirror_count = 0;
+       slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN;
        mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr);
        flow->flags &= ~MLX5E_TC_FLOW_SLOW;
 }
@@ -907,11 +910,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        struct mlx5e_priv *out_priv;
        int err = 0, encap_err = 0;
 
-       /* if prios are not supported, keep the old behaviour of using same prio
-        * for all offloaded rules.
-        */
-       if (!mlx5_eswitch_prios_supported(esw))
-               attr->prio = 1;
+       if (!mlx5_eswitch_prios_supported(esw) && attr->prio != 1) {
+               NL_SET_ERR_MSG(extack, "E-switch priorities unsupported, upgrade FW");
+               return -EOPNOTSUPP;
+       }
 
        if (attr->chain > max_chain) {
                NL_SET_ERR_MSG(extack, "Requested chain is out of supported range");
@@ -1094,10 +1096,9 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
                flow->rule[0] = rule;
        }
 
-       if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
-               e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
-               mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id);
-       }
+       /* we know that the encap is valid */
+       e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
+       mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id);
 }
 
 static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
@@ -2966,8 +2967,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                NL_SET_ERR_MSG(extack, "Requested destination chain is out of supported range");
                                return -EOPNOTSUPP;
                        }
-                       action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
-                                 MLX5_FLOW_CONTEXT_ACTION_COUNT;
+                       action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
                        attr->dest_chain = dest_chain;
 
                        continue;
@@ -2980,6 +2980,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
        if (!actions_match_supported(priv, exts, parse_attr, flow, extack))
                return -EOPNOTSUPP;
 
+       if (attr->dest_chain) {
+               if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
+                       NL_SET_ERR_MSG(extack, "Mirroring goto chain rules isn't supported");
+                       return -EOPNOTSUPP;
+               }
+               attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       }
+
        if (attr->mirror_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "current firmware doesn't support split rule for port mirroring");
index 9d73eb955f75e0c4e19047aae6cf52d9457e6c64..08233cf44871b877679e8ac9273fd1f6d10c587b 100644 (file)
@@ -452,7 +452,7 @@ static void del_sw_hw_rule(struct fs_node *node)
 
        if ((fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
            --fte->dests_size) {
-               modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST),
+               modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
                update_fte = true;
        }
 out:
index 30f751e696980d727a86200e1748adda13bb8a22..f7154f358f2766b450cd81bd5c431f1dcd1c9f8d 100644 (file)
@@ -81,6 +81,7 @@ struct mlxsw_core {
        struct mlxsw_core_port *ports;
        unsigned int max_ports;
        bool reload_fail;
+       bool fw_flash_in_progress;
        unsigned long driver_priv[0];
        /* driver_priv has to be always the last item */
 };
@@ -428,12 +429,16 @@ struct mlxsw_reg_trans {
        struct rcu_head rcu;
 };
 
-#define MLXSW_EMAD_TIMEOUT_MS 200
+#define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS  3000
+#define MLXSW_EMAD_TIMEOUT_MS                  200
 
 static void mlxsw_emad_trans_timeout_schedule(struct mlxsw_reg_trans *trans)
 {
        unsigned long timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS);
 
+       if (trans->core->fw_flash_in_progress)
+               timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS);
+
        queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, timeout);
 }
 
@@ -1854,6 +1859,18 @@ int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
 }
 EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);
 
+void mlxsw_core_fw_flash_start(struct mlxsw_core *mlxsw_core)
+{
+       mlxsw_core->fw_flash_in_progress = true;
+}
+EXPORT_SYMBOL(mlxsw_core_fw_flash_start);
+
+void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core)
+{
+       mlxsw_core->fw_flash_in_progress = false;
+}
+EXPORT_SYMBOL(mlxsw_core_fw_flash_end);
+
 static int __init mlxsw_core_module_init(void)
 {
        int err;
index c35be477856f18d6493c4a8c1c6d14e0ef2f2d1b..c4e4971764e54efc101130c87af817f16c7b6106 100644 (file)
@@ -292,6 +292,9 @@ int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
                             u64 *p_single_size, u64 *p_double_size,
                             u64 *p_linear_size);
 
+void mlxsw_core_fw_flash_start(struct mlxsw_core *mlxsw_core);
+void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core);
+
 bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
                          enum mlxsw_res_id res_id);
 
index 9bec940330a450856d2dba23ed7274321cf82059..f84b9c02fcc5eea8a0a1806831c4b559b31ea4d8 100644 (file)
@@ -309,8 +309,13 @@ static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp,
                },
                .mlxsw_sp = mlxsw_sp
        };
+       int err;
+
+       mlxsw_core_fw_flash_start(mlxsw_sp->core);
+       err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware);
+       mlxsw_core_fw_flash_end(mlxsw_sp->core);
 
-       return mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware);
+       return err;
 }
 
 static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)
@@ -3521,6 +3526,7 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
        MLXSW_SP_RXL_MR_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),
        /* NVE traps */
        MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false),
+       MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, TRAP_TO_CPU, ARP, false),
 };
 
 static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
index 5c13674439f1f0751a369a3112d19bea46a2464c..b5b54b41349a865ae699a80ef1d2c04774633244 100644 (file)
@@ -977,6 +977,6 @@ void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
 {
        WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
        rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
-       mlxsw_sp->nve = NULL;
        kfree(mlxsw_sp->nve);
+       mlxsw_sp->nve = NULL;
 }
index 6f18f4d3322a6f28f14bf774a269fe8c52411680..451216dd7f6bbc1025ff26b71f426fd76c40d4f8 100644 (file)
@@ -60,6 +60,7 @@ enum {
        MLXSW_TRAP_ID_IPV6_MC_LINK_LOCAL_DEST = 0x91,
        MLXSW_TRAP_ID_HOST_MISS_IPV6 = 0x92,
        MLXSW_TRAP_ID_IPIP_DECAP_ERROR = 0xB1,
+       MLXSW_TRAP_ID_NVE_DECAP_ARP = 0xB8,
        MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD,
        MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6,
        MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7,
index e8ca98c070f68443c6460ecb10d3eb4b3ee9a2f2..20c9377e99cb227f863c3a113014496450b4f1cb 100644 (file)
@@ -802,14 +802,8 @@ static int lan743x_mac_init(struct lan743x_adapter *adapter)
        u32 mac_addr_hi = 0;
        u32 mac_addr_lo = 0;
        u32 data;
-       int ret;
 
        netdev = adapter->netdev;
-       lan743x_csr_write(adapter, MAC_CR, MAC_CR_RST_);
-       ret = lan743x_csr_wait_for_bit(adapter, MAC_CR, MAC_CR_RST_,
-                                      0, 1000, 20000, 100);
-       if (ret)
-               return ret;
 
        /* setup auto duplex, and speed detection */
        data = lan743x_csr_read(adapter, MAC_CR);
@@ -2719,8 +2713,9 @@ static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
        snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE,
                 "pci-%s", pci_name(adapter->pdev));
 
-       /* set to internal PHY id */
-       adapter->mdiobus->phy_mask = ~(u32)BIT(1);
+       if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == ID_REV_ID_LAN7430_)
+               /* LAN7430 uses internal phy at address 1 */
+               adapter->mdiobus->phy_mask = ~(u32)BIT(1);
 
        /* register mdiobus */
        ret = mdiobus_register(adapter->mdiobus);
index 3238b9ee42f3fe467ba4532de67b1fc2fe5c0ef3..c84074fa4c954e781393df510ad6c9e6b4759d99 100644 (file)
@@ -747,7 +747,7 @@ static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        }
 
        return ocelot_mact_learn(ocelot, port->chip_port, addr, vid,
-                                ENTRYTYPE_NORMAL);
+                                ENTRYTYPE_LOCKED);
 }
 
 static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
index 4c1fb7e578889ac5ea755890e7ff4662259a157d..7cde387e5ec62a0c36f070a163a6e5b9c38a6a4b 100644 (file)
@@ -808,7 +808,7 @@ __vxge_hw_vpath_fw_ver_get(struct __vxge_hw_virtualpath *vpath,
        struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
        struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
        struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
-       u64 data0, data1 = 0, steer_ctrl = 0;
+       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
        enum vxge_hw_status status;
 
        status = vxge_hw_vpath_fw_api(vpath,
index 2f49eb75f3cce3245b7162a2ee3cf664bc0ab7f1..67e576fe7fc0f1ad9ecfc043383780b31250022a 100644 (file)
@@ -345,13 +345,29 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
                    !(tcp_flags & (TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST)))
                        return -EOPNOTSUPP;
 
-               /* We need to store TCP flags in the IPv4 key space, thus
-                * we need to ensure we include a IPv4 key layer if we have
-                * not done so already.
+               /* We need to store TCP flags in the either the IPv4 or IPv6 key
+                * space, thus we need to ensure we include a IPv4/IPv6 key
+                * layer if we have not done so already.
                 */
-               if (!(key_layer & NFP_FLOWER_LAYER_IPV4)) {
-                       key_layer |= NFP_FLOWER_LAYER_IPV4;
-                       key_size += sizeof(struct nfp_flower_ipv4);
+               if (!key_basic)
+                       return -EOPNOTSUPP;
+
+               if (!(key_layer & NFP_FLOWER_LAYER_IPV4) &&
+                   !(key_layer & NFP_FLOWER_LAYER_IPV6)) {
+                       switch (key_basic->n_proto) {
+                       case cpu_to_be16(ETH_P_IP):
+                               key_layer |= NFP_FLOWER_LAYER_IPV4;
+                               key_size += sizeof(struct nfp_flower_ipv4);
+                               break;
+
+                       case cpu_to_be16(ETH_P_IPV6):
+                               key_layer |= NFP_FLOWER_LAYER_IPV6;
+                               key_size += sizeof(struct nfp_flower_ipv6);
+                               break;
+
+                       default:
+                               return -EOPNOTSUPP;
+                       }
                }
        }
 
index 052b3d2c07a1222b7f902477f30d8eef5a75ab22..c662c6f5bee340f4a0b73e09ae36c7eb4bc878d3 100644 (file)
@@ -912,7 +912,7 @@ static const struct net_device_ops w90p910_ether_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-static void __init get_mac_address(struct net_device *dev)
+static void get_mac_address(struct net_device *dev)
 {
        struct w90p910_ether *ether = netdev_priv(dev);
        struct platform_device *pdev;
index 0ea141ece19ea14c02e79300d8aefe249b0db3ee..6547a9dd59355459251e92cd724f8f879fcf8bc7 100644 (file)
@@ -1125,7 +1125,8 @@ netxen_validate_firmware(struct netxen_adapter *adapter)
                return -EINVAL;
        }
        val = nx_get_bios_version(adapter);
-       netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
+       if (netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios))
+               return -EIO;
        if ((__force u32)val != bios) {
                dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
                                fw_name[fw_type]);
index 5c221ebaa7b34fa863f6f424d22c82cf4d54514d..b38e12c9de9d3a883ef79b30c5d9fb912503e786 100644 (file)
@@ -12831,8 +12831,9 @@ enum MFW_DRV_MSG_TYPE {
        MFW_DRV_MSG_BW_UPDATE10,
        MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE,
        MFW_DRV_MSG_BW_UPDATE11,
-       MFW_DRV_MSG_OEM_CFG_UPDATE,
+       MFW_DRV_MSG_RESERVED,
        MFW_DRV_MSG_GET_TLV_REQ,
+       MFW_DRV_MSG_OEM_CFG_UPDATE,
        MFW_DRV_MSG_MAX
 };
 
index aa633381aa47ea3bc13de4829bde316448ee0d6b..c6f4bab67a5fc30e28e22c2f4b0bcb391667730b 100644 (file)
@@ -2496,6 +2496,7 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb,
                if (unlikely(dma_mapping_error(&cdev->pdev->dev, mapping))) {
                        DP_NOTICE(cdev,
                                  "Unable to map frag - dropping packet\n");
+                       rc = -ENOMEM;
                        goto err;
                }
 
index 1fd01688d37bdd9c7e09e2444034c0ccb286ea19..209566f8097baa29d2b2b21129219c49c51242b0 100644 (file)
@@ -6469,7 +6469,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                goto out;
        }
 
-       if (status & LinkChg)
+       if (status & LinkChg && tp->dev->phydev)
                phy_mac_interrupt(tp->dev->phydev);
 
        if (unlikely(status & RxFIFOOver &&
index 5551fead8f6646f327dcfc7d5b98d8f3483f3eeb..c4a35e932f05216a6a579d6e7a62bcf81a98ae79 100644 (file)
@@ -4250,6 +4250,7 @@ int stmmac_dvr_probe(struct device *device,
        priv->wq = create_singlethread_workqueue("stmmac_wq");
        if (!priv->wq) {
                dev_err(priv->device, "failed to create workqueue\n");
+               ret = -ENOMEM;
                goto error_wq;
        }
 
index 0ff5a403a8dc356a359fb085be26379ca011b67b..b2ff903a9cb6e56a47814be2559589b73325302a 100644 (file)
@@ -721,7 +721,7 @@ static void ca8210_mlme_reset_worker(struct work_struct *work)
 static void ca8210_rx_done(struct cas_control *cas_ctl)
 {
        u8 *buf;
-       u8 len;
+       unsigned int len;
        struct work_priv_container *mlme_reset_wpc;
        struct ca8210_priv *priv = cas_ctl->priv;
 
@@ -730,7 +730,7 @@ static void ca8210_rx_done(struct cas_control *cas_ctl)
        if (len > CA8210_SPI_BUF_SIZE) {
                dev_crit(
                        &priv->spi->dev,
-                       "Received packet len (%d) erroneously long\n",
+                       "Received packet len (%u) erroneously long\n",
                        len
                );
                goto finish;
index 51b5198d5943422bc61e2201e830176d733d006b..b6743f03dce000578b65bf9a8afddd3c2613d628 100644 (file)
@@ -492,7 +492,7 @@ static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
            !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
                return -EINVAL;
 
-       if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX + 1,
+       if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX,
                             info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE],
                             hwsim_edge_policy, NULL))
                return -EINVAL;
@@ -542,7 +542,7 @@ static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
            !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
                return -EINVAL;
 
-       if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX + 1,
+       if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX,
                             info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE],
                             hwsim_edge_policy, NULL))
                return -EINVAL;
index 18e92c19c5ab8716f6a87e905689a2b0c16b56d4..26c41ede54a4f4fde7a0b009d458bd145fb49f4d 100644 (file)
@@ -308,11 +308,8 @@ static int mdio_bus_phy_restore(struct device *dev)
        if (ret < 0)
                return ret;
 
-       /* The PHY needs to renegotiate. */
-       phydev->link = 0;
-       phydev->state = PHY_UP;
-
-       phy_start_machine(phydev);
+       if (phydev->attached_dev && phydev->adjust_link)
+               phy_start_machine(phydev);
 
        return 0;
 }
index 184c24baca1527333d92ec927c48e958ad6c95f0..d6916f787fce98ae2ce4d51d0619eb5094738543 100644 (file)
@@ -2807,6 +2807,12 @@ static int hso_get_config_data(struct usb_interface *interface)
                return -EIO;
        }
 
+       /* check if we have a valid interface */
+       if (if_num > 16) {
+               kfree(config_data);
+               return -EINVAL;
+       }
+
        switch (config_data[if_num]) {
        case 0x0:
                result = 0;
@@ -2877,10 +2883,18 @@ static int hso_probe(struct usb_interface *interface,
 
        /* Get the interface/port specification from either driver_info or from
         * the device itself */
-       if (id->driver_info)
+       if (id->driver_info) {
+               /* if_num is controlled by the device, driver_info is a 0 terminated
+                * array. Make sure, the access is in bounds! */
+               for (i = 0; i <= if_num; ++i)
+                       if (((u32 *)(id->driver_info))[i] == 0)
+                               goto exit;
                port_spec = ((u32 *)(id->driver_info))[if_num];
-       else
+       } else {
                port_spec = hso_get_config_data(interface);
+               if (port_spec < 0)
+                       goto exit;
+       }
 
        /* Check if we need to switch to alt interfaces prior to port
         * configuration */
index be1917be28f2d457c561a117ea92dd49c7f62d50..77d3c85febf18f801a1dc234bf5c1063c264f472 100644 (file)
@@ -2320,6 +2320,10 @@ static int lan78xx_set_mac_addr(struct net_device *netdev, void *p)
        ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
        ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
 
+       /* Added to support MAC address changes */
+       ret = lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
+       ret = lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_);
+
        return 0;
 }
 
index 72a55b6b421184c4fb69411ba3d0150e6c337a88..774e1ff01c9a9e3e3297360cc46d199ee9c90f40 100644 (file)
@@ -151,17 +151,18 @@ static bool qmimux_has_slaves(struct usbnet *dev)
 
 static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
-       unsigned int len, offset = sizeof(struct qmimux_hdr);
+       unsigned int len, offset = 0;
        struct qmimux_hdr *hdr;
        struct net_device *net;
        struct sk_buff *skbn;
+       u8 qmimux_hdr_sz = sizeof(*hdr);
 
-       while (offset < skb->len) {
-               hdr = (struct qmimux_hdr *)skb->data;
+       while (offset + qmimux_hdr_sz < skb->len) {
+               hdr = (struct qmimux_hdr *)(skb->data + offset);
                len = be16_to_cpu(hdr->pkt_len);
 
                /* drop the packet, bogus length */
-               if (offset + len > skb->len)
+               if (offset + len + qmimux_hdr_sz > skb->len)
                        return 0;
 
                /* control packet, we do not know what to do */
@@ -176,7 +177,7 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                        return 0;
                skbn->dev = net;
 
-               switch (skb->data[offset] & 0xf0) {
+               switch (skb->data[offset + qmimux_hdr_sz] & 0xf0) {
                case 0x40:
                        skbn->protocol = htons(ETH_P_IP);
                        break;
@@ -188,12 +189,12 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                        goto skip;
                }
 
-               skb_put_data(skbn, skb->data + offset, len);
+               skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, len);
                if (netif_rx(skbn) != NET_RX_SUCCESS)
                        return 0;
 
 skip:
-               offset += len + sizeof(struct qmimux_hdr);
+               offset += len + qmimux_hdr_sz;
        }
        return 1;
 }
@@ -1117,6 +1118,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1435, 0xd181, 4)},    /* Wistron NeWeb D18Q1 */
        {QMI_FIXED_INTF(0x1435, 0xd181, 5)},    /* Wistron NeWeb D18Q1 */
        {QMI_FIXED_INTF(0x1435, 0xd191, 4)},    /* Wistron NeWeb D19Q1 */
+       {QMI_QUIRK_SET_DTR(0x1508, 0x1001, 4)}, /* Fibocom NL668 series */
        {QMI_FIXED_INTF(0x16d8, 0x6003, 0)},    /* CMOTech 6003 */
        {QMI_FIXED_INTF(0x16d8, 0x6007, 0)},    /* CMOTech CHE-628S */
        {QMI_FIXED_INTF(0x16d8, 0x6008, 0)},    /* CMOTech CMU-301 */
@@ -1229,6 +1231,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)},    /* Telit ME910 dual modem */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
        {QMI_QUIRK_SET_DTR(0x1bc7, 0x1201, 2)}, /* Telit LE920, LE920A4 */
+       {QMI_QUIRK_SET_DTR(0x1bc7, 0x1900, 1)}, /* Telit LN940 series */
        {QMI_FIXED_INTF(0x1c9e, 0x9801, 3)},    /* Telewell TW-3G HSPA+ */
        {QMI_FIXED_INTF(0x1c9e, 0x9803, 4)},    /* Telewell TW-3G HSPA+ */
        {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)},    /* XS Stick W100-2 from 4G Systems */
@@ -1263,6 +1266,7 @@ static const struct usb_device_id products[] = {
        {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */
        {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */
        {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},    /* Quectel BG96 */
+       {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index f1b5201cc32075da27cf14d94b781c9f58c16189..60dd1ec1665f992ea9b50551672d4a85a5b6b670 100644 (file)
 #define USB_UPS_CTRL           0xd800
 #define USB_POWER_CUT          0xd80a
 #define USB_MISC_0             0xd81a
+#define USB_MISC_1             0xd81f
 #define USB_AFE_CTRL2          0xd824
 #define USB_UPS_CFG            0xd842
 #define USB_UPS_FLAGS          0xd848
@@ -555,6 +556,7 @@ enum spd_duplex {
 
 /* MAC PASSTHRU */
 #define AD_MASK                        0xfee0
+#define BND_MASK               0x0004
 #define EFUSE                  0xcfdb
 #define PASS_THRU_MASK         0x1
 
@@ -1150,7 +1152,7 @@ out1:
        return ret;
 }
 
-/* Devices containing RTL8153-AD can support a persistent
+/* Devices containing proper chips can support a persistent
  * host system provided MAC address.
  * Examples of this are Dell TB15 and Dell WD15 docks
  */
@@ -1165,13 +1167,23 @@ static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa)
 
        /* test for -AD variant of RTL8153 */
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
-       if ((ocp_data & AD_MASK) != 0x1000)
-               return -ENODEV;
-
-       /* test for MAC address pass-through bit */
-       ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
-       if ((ocp_data & PASS_THRU_MASK) != 1)
-               return -ENODEV;
+       if ((ocp_data & AD_MASK) == 0x1000) {
+               /* test for MAC address pass-through bit */
+               ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
+               if ((ocp_data & PASS_THRU_MASK) != 1) {
+                       netif_dbg(tp, probe, tp->netdev,
+                                 "No efuse for RTL8153-AD MAC pass through\n");
+                       return -ENODEV;
+               }
+       } else {
+               /* test for RTL8153-BND */
+               ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1);
+               if ((ocp_data & BND_MASK) == 0) {
+                       netif_dbg(tp, probe, tp->netdev,
+                                 "Invalid variant for MAC pass through\n");
+                       return -ENODEV;
+               }
+       }
 
        /* returns _AUXMAC_#AABBCCDDEEFF# */
        status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer);
@@ -1217,9 +1229,8 @@ static int set_ethernet_addr(struct r8152 *tp)
        if (tp->version == RTL_VER_01) {
                ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
        } else {
-               /* if this is not an RTL8153-AD, no eFuse mac pass thru set,
-                * or system doesn't provide valid _SB.AMAC this will be
-                * be expected to non-zero
+               /* if device doesn't support MAC pass through this will
+                * be expected to be non-zero
                 */
                ret = vendor_mac_passthru_addr_read(tp, &sa);
                if (ret < 0)
index 297cdeaef4796501279f826154191eb6e0e0d298..0565f8880199d217ad63c574f058bf1b724524f5 100644 (file)
@@ -568,6 +568,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
        rd->remote_port = port;
        rd->remote_vni = vni;
        rd->remote_ifindex = ifindex;
+       rd->offloaded = false;
        return 1;
 }
 
@@ -3258,6 +3259,7 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_fdb *f = NULL;
+       bool unregister = false;
        int err;
 
        err = vxlan_dev_configure(net, dev, conf, false, extack);
@@ -3283,12 +3285,11 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
        err = register_netdevice(dev);
        if (err)
                goto errout;
+       unregister = true;
 
        err = rtnl_configure_link(dev, NULL);
-       if (err) {
-               unregister_netdevice(dev);
+       if (err)
                goto errout;
-       }
 
        /* notify default fdb entry */
        if (f)
@@ -3296,9 +3297,16 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
 
        list_add(&vxlan->next, &vn->vxlan_list);
        return 0;
+
 errout:
+       /* unregister_netdevice() destroys the default FDB entry with deletion
+        * notification. But the addition notification was not sent yet, so
+        * destroy the entry by hand here.
+        */
        if (f)
                vxlan_fdb_destroy(vxlan, f, false);
+       if (unregister)
+               unregister_netdevice(dev);
        return err;
 }
 
@@ -3534,7 +3542,6 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
        struct vxlan_rdst *dst = &vxlan->default_dst;
        struct vxlan_rdst old_dst;
        struct vxlan_config conf;
-       struct vxlan_fdb *f = NULL;
        int err;
 
        err = vxlan_nl2conf(tb, data,
@@ -3560,19 +3567,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
                                           old_dst.remote_ifindex, 0);
 
                if (!vxlan_addr_any(&dst->remote_ip)) {
-                       err = vxlan_fdb_create(vxlan, all_zeros_mac,
+                       err = vxlan_fdb_update(vxlan, all_zeros_mac,
                                               &dst->remote_ip,
                                               NUD_REACHABLE | NUD_PERMANENT,
+                                              NLM_F_APPEND | NLM_F_CREATE,
                                               vxlan->cfg.dst_port,
                                               dst->remote_vni,
                                               dst->remote_vni,
                                               dst->remote_ifindex,
-                                              NTF_SELF, &f);
+                                              NTF_SELF);
                        if (err) {
                                spin_unlock_bh(&vxlan->hash_lock);
                                return err;
                        }
-                       vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH);
                }
                spin_unlock_bh(&vxlan->hash_lock);
        }
index da607febfd8200fffbdd5cfa575866a7f99cd04b..d210b0ed59beb606bdef977ae0bec7babd00f212 100644 (file)
@@ -2418,6 +2418,28 @@ static int ath10k_core_reset_rx_filter(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_core_compat_services(struct ath10k *ar)
+{
+       struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
+
+       /* all 10.x firmware versions support thermal throttling but don't
+        * advertise the support via service flags so we have to hardcode
+        * it here
+        */
+       switch (fw_file->wmi_op_version) {
+       case ATH10K_FW_WMI_OP_VERSION_10_1:
+       case ATH10K_FW_WMI_OP_VERSION_10_2:
+       case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+       case ATH10K_FW_WMI_OP_VERSION_10_4:
+               set_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
                      const struct ath10k_fw_components *fw)
 {
@@ -2617,6 +2639,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
                goto err_hif_stop;
        }
 
+       status = ath10k_core_compat_services(ar);
+       if (status) {
+               ath10k_err(ar, "compat services failed: %d\n", status);
+               goto err_hif_stop;
+       }
+
        /* Some firmware revisions do not properly set up hardware rx filter
         * registers.
         *
index 15964b374f68da69636e256d6a3911cc3eee773b..02988fc378a1581844645661349bdfdfcf3d3993 100644 (file)
@@ -2578,8 +2578,9 @@ int ath10k_debug_register(struct ath10k *ar)
        debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar,
                            &fops_pktlog_filter);
 
-       debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,
-                           &fops_quiet_period);
+       if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
+               debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,
+                                   &fops_quiet_period);
 
        debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar,
                            &fops_tpc_stats);
index aa8978a8d7514aa5f827ff6de9d4465ffee9a334..fe35edcd3ec8104005310f5c831218493d990754 100644 (file)
@@ -140,6 +140,9 @@ void ath10k_thermal_set_throttling(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
+               return;
+
        if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
                return;
 
@@ -165,6 +168,9 @@ int ath10k_thermal_register(struct ath10k *ar)
        struct device *hwmon_dev;
        int ret;
 
+       if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
+               return 0;
+
        cdev = thermal_cooling_device_register("ath10k_thermal", ar,
                                               &ath10k_thermal_ops);
 
@@ -216,6 +222,9 @@ err_cooling_destroy:
 
 void ath10k_thermal_unregister(struct ath10k *ar)
 {
+       if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
+               return;
+
        sysfs_remove_link(&ar->dev->kobj, "cooling_device");
        thermal_cooling_device_unregister(ar->thermal.cdev);
 }
index 92c25f51bf868fd8daa4d93b0d7e4b888125ffc2..c2cb413392eeb350fd146ab585178b38768eeecf 100644 (file)
@@ -1564,6 +1564,9 @@ wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, size_t len)
        SVCMAP(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT,
               WMI_SERVICE_SPOOF_MAC_SUPPORT,
               WMI_TLV_MAX_SERVICE);
+       SVCMAP(WMI_TLV_SERVICE_THERM_THROT,
+              WMI_SERVICE_THERM_THROT,
+              WMI_TLV_MAX_SERVICE);
 }
 
 #undef SVCMAP
index f7badd079051d35601ca1fa6400601d4109604ad..c5a343c93013132d613acae897a5511339c1b94a 100644 (file)
@@ -205,6 +205,7 @@ enum wmi_service {
        WMI_SERVICE_SPOOF_MAC_SUPPORT,
        WMI_SERVICE_TX_DATA_ACK_RSSI,
        WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT,
+       WMI_SERVICE_THERM_THROT,
 
        /* keep last */
        WMI_SERVICE_MAX,
index 2ba890445c356502502a5d948bb2fdb0a21042bf..1689bead1b4fd3f872f41ff073653d1d896740dd 100644 (file)
@@ -881,6 +881,15 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
        int ret, i, j;
        u16 cmd_wide_id =  WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT);
 
+       /*
+        * This command is not supported on earlier firmware versions.
+        * Unfortunately, we don't have a TLV API flag to rely on, so
+        * rely on the major version which is in the first byte of
+        * ucode_ver.
+        */
+       if (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) < 41)
+               return 0;
+
        ret = iwl_mvm_sar_get_wgds_table(mvm);
        if (ret < 0) {
                IWL_DEBUG_RADIO(mvm,
index e2addd8b878b290bbcb6656f6baeedb258400964..5d75c971004b4e480737aa0fe13627afb1e58cb7 100644 (file)
@@ -696,11 +696,10 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
                                "Send delba to tid=%d, %pM\n",
                                tid, rx_reor_tbl_ptr->ta);
                        mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
-                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
-                                              flags);
-                       return;
+                       goto exit;
                }
        }
+exit:
        spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 }
 
index 8e63d14c1e1c57b4a93d430f5174c245f6a69b08..5380fba652cc49ff2a2aef2528b35e674b8f1a4a 100644 (file)
@@ -103,8 +103,6 @@ static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
  * There could be holes in the buffer, which are skipped by the function.
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
- *
- * The caller must hold rx_reorder_tbl_lock spinlock.
  */
 static void
 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
@@ -113,21 +111,25 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
 {
        int pkt_to_send, i;
        void *rx_tmp_ptr;
+       unsigned long flags;
 
        pkt_to_send = (start_win > tbl->start_win) ?
                      min((start_win - tbl->start_win), tbl->win_size) :
                      tbl->win_size;
 
        for (i = 0; i < pkt_to_send; ++i) {
+               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
                rx_tmp_ptr = NULL;
                if (tbl->rx_reorder_ptr[i]) {
                        rx_tmp_ptr = tbl->rx_reorder_ptr[i];
                        tbl->rx_reorder_ptr[i] = NULL;
                }
+               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                if (rx_tmp_ptr)
                        mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
        }
 
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        /*
         * We don't have a circular buffer, hence use rotation to simulate
         * circular buffer
@@ -138,6 +140,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
        }
 
        tbl->start_win = start_win;
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 }
 
 /*
@@ -147,8 +150,6 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
  * The start window is adjusted automatically when a hole is located.
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
- *
- * The caller must hold rx_reorder_tbl_lock spinlock.
  */
 static void
 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
@@ -156,15 +157,22 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
 {
        int i, j, xchg;
        void *rx_tmp_ptr;
+       unsigned long flags;
 
        for (i = 0; i < tbl->win_size; ++i) {
-               if (!tbl->rx_reorder_ptr[i])
+               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+               if (!tbl->rx_reorder_ptr[i]) {
+                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+                                              flags);
                        break;
+               }
                rx_tmp_ptr = tbl->rx_reorder_ptr[i];
                tbl->rx_reorder_ptr[i] = NULL;
+               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
        }
 
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        /*
         * We don't have a circular buffer, hence use rotation to simulate
         * circular buffer
@@ -177,6 +185,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                }
        }
        tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 }
 
 /*
@@ -184,8 +193,6 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
  *
  * The function stops the associated timer and dispatches all the
  * pending packets in the Rx reorder table before deletion.
- *
- * The caller must hold rx_reorder_tbl_lock spinlock.
  */
 static void
 mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
@@ -211,7 +218,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
 
        del_timer_sync(&tbl->timer_context.timer);
        tbl->timer_context.timer_is_set = false;
+
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        list_del(&tbl->list);
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
        kfree(tbl->rx_reorder_ptr);
        kfree(tbl);
 
@@ -224,17 +235,22 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
 /*
  * This function returns the pointer to an entry in Rx reordering
  * table which matches the given TA/TID pair.
- *
- * The caller must hold rx_reorder_tbl_lock spinlock.
  */
 struct mwifiex_rx_reorder_tbl *
 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
 {
        struct mwifiex_rx_reorder_tbl *tbl;
+       unsigned long flags;
 
-       list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
-               if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid)
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+       list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
+               if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
+                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+                                              flags);
                        return tbl;
+               }
+       }
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        return NULL;
 }
@@ -251,9 +267,14 @@ void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
                return;
 
        spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
-       list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list)
-               if (!memcmp(tbl->ta, ta, ETH_ALEN))
+       list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
+               if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
+                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+                                              flags);
                        mwifiex_del_rx_reorder_entry(priv, tbl);
+                       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+               }
+       }
        spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        return;
@@ -262,18 +283,24 @@ void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
 /*
  * This function finds the last sequence number used in the packets
  * buffered in Rx reordering table.
- *
- * The caller must hold rx_reorder_tbl_lock spinlock.
  */
 static int
 mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
 {
        struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
+       struct mwifiex_private *priv = ctx->priv;
+       unsigned long flags;
        int i;
 
-       for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i)
-               if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+       for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
+               if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
+                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+                                              flags);
                        return i;
+               }
+       }
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        return -1;
 }
@@ -291,22 +318,17 @@ mwifiex_flush_data(struct timer_list *t)
        struct reorder_tmr_cnxt *ctx =
                from_timer(ctx, t, timer);
        int start_win, seq_num;
-       unsigned long flags;
 
        ctx->timer_is_set = false;
-       spin_lock_irqsave(&ctx->priv->rx_reorder_tbl_lock, flags);
        seq_num = mwifiex_11n_find_last_seq_num(ctx);
 
-       if (seq_num < 0) {
-               spin_unlock_irqrestore(&ctx->priv->rx_reorder_tbl_lock, flags);
+       if (seq_num < 0)
                return;
-       }
 
        mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
        start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
        mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
                                                 start_win);
-       spin_unlock_irqrestore(&ctx->priv->rx_reorder_tbl_lock, flags);
 }
 
 /*
@@ -333,14 +355,11 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
         * If we get a TID, ta pair which is already present dispatch all the
         * the packets and move the window size until the ssn
         */
-       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
        if (tbl) {
                mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num);
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                return;
        }
-       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
        /* if !tbl then create one */
        new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
        if (!new_node)
@@ -551,20 +570,16 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
        int prev_start_win, start_win, end_win, win_size;
        u16 pkt_index;
        bool init_window_shift = false;
-       unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
        if (!tbl) {
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                if (pkt_type != PKT_TYPE_BAR)
                        mwifiex_11n_dispatch_pkt(priv, payload);
                return ret;
        }
 
        if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                mwifiex_11n_dispatch_pkt(priv, payload);
                return ret;
        }
@@ -651,8 +666,6 @@ done:
        if (!tbl->timer_context.timer_is_set ||
            prev_start_win != tbl->start_win)
                mwifiex_11n_rxreorder_timer_restart(tbl);
-
-       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
        return ret;
 }
 
@@ -681,18 +694,14 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
                    peer_mac, tid, initiator);
 
        if (cleanup_rx_reorder_tbl) {
-               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
                tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
                                                                 peer_mac);
                if (!tbl) {
-                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
-                                              flags);
                        mwifiex_dbg(priv->adapter, EVENT,
                                    "event: TID, TA not found in table\n");
                        return;
                }
                mwifiex_del_rx_reorder_entry(priv, tbl);
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
        } else {
                ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
                if (!ptx_tbl) {
@@ -726,7 +735,6 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
        int tid, win_size;
        struct mwifiex_rx_reorder_tbl *tbl;
        uint16_t block_ack_param_set;
-       unsigned long flags;
 
        block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
 
@@ -740,20 +748,17 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
                mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
                            add_ba_rsp->peer_mac_addr, tid);
 
-               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
                tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
                                                     add_ba_rsp->peer_mac_addr);
                if (tbl)
                        mwifiex_del_rx_reorder_entry(priv, tbl);
 
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                return 0;
        }
 
        win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
                    >> BLOCKACKPARAM_WINSIZE_POS;
 
-       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
                                             add_ba_rsp->peer_mac_addr);
        if (tbl) {
@@ -764,7 +769,6 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
                else
                        tbl->amsdu = false;
        }
-       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        mwifiex_dbg(priv->adapter, CMD,
                    "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
@@ -804,8 +808,11 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
 
        spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        list_for_each_entry_safe(del_tbl_ptr, tmp_node,
-                                &priv->rx_reorder_tbl_ptr, list)
+                                &priv->rx_reorder_tbl_ptr, list) {
+               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
+               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+       }
        INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
        spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
@@ -929,7 +936,6 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
        int tlv_buf_left = len;
        int ret;
        u8 *tmp;
-       unsigned long flags;
 
        mwifiex_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:",
                         event_buf, len);
@@ -949,18 +955,14 @@ void mwifiex_11n_rxba_sync_event(struct mwifiex_private *priv,
                            tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num,
                            tlv_bitmap_len);
 
-               spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
                rx_reor_tbl_ptr =
                        mwifiex_11n_get_rx_reorder_tbl(priv, tlv_rxba->tid,
                                                       tlv_rxba->mac);
                if (!rx_reor_tbl_ptr) {
-                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
-                                              flags);
                        mwifiex_dbg(priv->adapter, ERROR,
                                    "Can not find rx_reorder_tbl!");
                        return;
                }
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
                for (i = 0; i < tlv_bitmap_len; i++) {
                        for (j = 0 ; j < 8; j++) {
index a83c5afc256abcb9f3eca164dd84ce323e3b0eaf..5ce85d5727e4b882ebc37372f03bb49003d1a0c9 100644 (file)
@@ -421,15 +421,12 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
                spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
        }
 
-       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        if (!priv->ap_11n_enabled ||
            (!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
            (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
                ret = mwifiex_handle_uap_rx_forward(priv, skb);
-               spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
                return ret;
        }
-       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        /* Reorder and send to kernel */
        pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
index 7cbce03aa65b96c3eee1cfbf75a92879005dcb64..aa426b838ffafeae66aedfbe76f9099a80490310 100644 (file)
@@ -400,7 +400,12 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
 
        for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
                struct ieee80211_txq *txq = sta->txq[i];
-               struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv;
+               struct mt76_txq *mtxq;
+
+               if (!txq)
+                       continue;
+
+               mtxq = (struct mt76_txq *)txq->drv_priv;
 
                spin_lock_bh(&mtxq->hwq->lock);
                mtxq->send_bar = mtxq->aggr && send_bar;
index f4122c8fdd9777e852ac1bc0f01d9cedcde6c84a..ef9b502ce576b04bbcc562313957bd3619f14451 100644 (file)
@@ -2289,6 +2289,7 @@ void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        if (rtl_c2h_fast_cmd(hw, skb)) {
                rtl_c2h_content_parsing(hw, skb);
+               kfree_skb(skb);
                return;
        }
 
index f17f602e6171203acd39ee448c305cba719ff1de..5b97cc946d70a695cb68e1f3e2f93328c29d8bc2 100644 (file)
@@ -905,7 +905,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
                if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) {
                        unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
 
-                       BUG_ON(pull_to <= skb_headlen(skb));
+                       BUG_ON(pull_to < skb_headlen(skb));
                        __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
                }
                if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
index 2c2df4e4fc14db27e6d2f5f938ff6300e43e9412..e5507add8f04f75b2bbd88cdc5de0ea7e8d714b4 100644 (file)
@@ -196,12 +196,12 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
        if (IS_ERR(opp_table))
                return 0;
 
-       count = opp_table->regulator_count;
-
        /* Regulator may not be required for the device */
-       if (!count)
+       if (!opp_table->regulators)
                goto put_opp_table;
 
+       count = opp_table->regulator_count;
+
        uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
        if (!uV)
                goto put_opp_table;
@@ -548,44 +548,6 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
        return ret;
 }
 
-static inline int
-_generic_set_opp_domain(struct device *dev, struct clk *clk,
-                       unsigned long old_freq, unsigned long freq,
-                       unsigned int old_pstate, unsigned int new_pstate)
-{
-       int ret;
-
-       /* Scaling up? Scale domain performance state before frequency */
-       if (freq > old_freq) {
-               ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
-               if (ret)
-                       return ret;
-       }
-
-       ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
-       if (ret)
-               goto restore_domain_state;
-
-       /* Scaling down? Scale domain performance state after frequency */
-       if (freq < old_freq) {
-               ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
-               if (ret)
-                       goto restore_freq;
-       }
-
-       return 0;
-
-restore_freq:
-       if (_generic_set_opp_clk_only(dev, clk, freq, old_freq))
-               dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
-                       __func__, old_freq);
-restore_domain_state:
-       if (freq > old_freq)
-               dev_pm_genpd_set_performance_state(dev, old_pstate);
-
-       return ret;
-}
-
 static int _generic_set_opp_regulator(const struct opp_table *opp_table,
                                      struct device *dev,
                                      unsigned long old_freq,
@@ -635,6 +597,84 @@ restore_voltage:
        return ret;
 }
 
+static int _set_opp_custom(const struct opp_table *opp_table,
+                          struct device *dev, unsigned long old_freq,
+                          unsigned long freq,
+                          struct dev_pm_opp_supply *old_supply,
+                          struct dev_pm_opp_supply *new_supply)
+{
+       struct dev_pm_set_opp_data *data;
+       int size;
+
+       data = opp_table->set_opp_data;
+       data->regulators = opp_table->regulators;
+       data->regulator_count = opp_table->regulator_count;
+       data->clk = opp_table->clk;
+       data->dev = dev;
+
+       data->old_opp.rate = old_freq;
+       size = sizeof(*old_supply) * opp_table->regulator_count;
+       if (IS_ERR(old_supply))
+               memset(data->old_opp.supplies, 0, size);
+       else
+               memcpy(data->old_opp.supplies, old_supply, size);
+
+       data->new_opp.rate = freq;
+       memcpy(data->new_opp.supplies, new_supply, size);
+
+       return opp_table->set_opp(data);
+}
+
+/* This is only called for PM domain for now */
+static int _set_required_opps(struct device *dev,
+                             struct opp_table *opp_table,
+                             struct dev_pm_opp *opp)
+{
+       struct opp_table **required_opp_tables = opp_table->required_opp_tables;
+       struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
+       unsigned int pstate;
+       int i, ret = 0;
+
+       if (!required_opp_tables)
+               return 0;
+
+       /* Single genpd case */
+       if (!genpd_virt_devs) {
+               pstate = opp->required_opps[0]->pstate;
+               ret = dev_pm_genpd_set_performance_state(dev, pstate);
+               if (ret) {
+                       dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
+                               dev_name(dev), pstate, ret);
+               }
+               return ret;
+       }
+
+       /* Multiple genpd case */
+
+       /*
+        * Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev
+        * after it is freed from another thread.
+        */
+       mutex_lock(&opp_table->genpd_virt_dev_lock);
+
+       for (i = 0; i < opp_table->required_opp_count; i++) {
+               pstate = opp->required_opps[i]->pstate;
+
+               if (!genpd_virt_devs[i])
+                       continue;
+
+               ret = dev_pm_genpd_set_performance_state(genpd_virt_devs[i], pstate);
+               if (ret) {
+                       dev_err(dev, "Failed to set performance rate of %s: %d (%d)\n",
+                               dev_name(genpd_virt_devs[i]), pstate, ret);
+                       break;
+               }
+       }
+       mutex_unlock(&opp_table->genpd_virt_dev_lock);
+
+       return ret;
+}
+
 /**
  * dev_pm_opp_set_rate() - Configure new OPP based on frequency
  * @dev:        device for which we do this operation
@@ -649,7 +689,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
        unsigned long freq, old_freq;
        struct dev_pm_opp *old_opp, *opp;
        struct clk *clk;
-       int ret, size;
+       int ret;
 
        if (unlikely(!target_freq)) {
                dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
@@ -702,44 +742,34 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
        dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
                old_freq, freq);
 
-       /* Only frequency scaling */
-       if (!opp_table->regulators) {
-               /*
-                * We don't support devices with both regulator and
-                * domain performance-state for now.
-                */
-               if (opp_table->genpd_performance_state)
-                       ret = _generic_set_opp_domain(dev, clk, old_freq, freq,
-                                                     IS_ERR(old_opp) ? 0 : old_opp->pstate,
-                                                     opp->pstate);
-               else
-                       ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
-       } else if (!opp_table->set_opp) {
+       /* Scaling up? Configure required OPPs before frequency */
+       if (freq > old_freq) {
+               ret = _set_required_opps(dev, opp_table, opp);
+               if (ret)
+                       goto put_opp;
+       }
+
+       if (opp_table->set_opp) {
+               ret = _set_opp_custom(opp_table, dev, old_freq, freq,
+                                     IS_ERR(old_opp) ? NULL : old_opp->supplies,
+                                     opp->supplies);
+       } else if (opp_table->regulators) {
                ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq,
                                                 IS_ERR(old_opp) ? NULL : old_opp->supplies,
                                                 opp->supplies);
        } else {
-               struct dev_pm_set_opp_data *data;
-
-               data = opp_table->set_opp_data;
-               data->regulators = opp_table->regulators;
-               data->regulator_count = opp_table->regulator_count;
-               data->clk = clk;
-               data->dev = dev;
-
-               data->old_opp.rate = old_freq;
-               size = sizeof(*opp->supplies) * opp_table->regulator_count;
-               if (IS_ERR(old_opp))
-                       memset(data->old_opp.supplies, 0, size);
-               else
-                       memcpy(data->old_opp.supplies, old_opp->supplies, size);
-
-               data->new_opp.rate = freq;
-               memcpy(data->new_opp.supplies, opp->supplies, size);
+               /* Only frequency scaling */
+               ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+       }
 
-               ret = opp_table->set_opp(data);
+       /* Scaling down? Configure required OPPs after frequency */
+       if (!ret && freq < old_freq) {
+               ret = _set_required_opps(dev, opp_table, opp);
+               if (ret)
+                       dev_err(dev, "Failed to set required opps: %d\n", ret);
        }
 
+put_opp:
        dev_pm_opp_put(opp);
 put_old_opp:
        if (!IS_ERR(old_opp))
@@ -810,8 +840,12 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
                return NULL;
 
        mutex_init(&opp_table->lock);
+       mutex_init(&opp_table->genpd_virt_dev_lock);
        INIT_LIST_HEAD(&opp_table->dev_list);
 
+       /* Mark regulator count uninitialized */
+       opp_table->regulator_count = -1;
+
        opp_dev = _add_opp_dev(dev, opp_table);
        if (!opp_dev) {
                kfree(opp_table);
@@ -888,6 +922,8 @@ static void _opp_table_kref_release(struct kref *kref)
        struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
        struct opp_device *opp_dev, *temp;
 
+       _of_clear_opp_table(opp_table);
+
        /* Release clk */
        if (!IS_ERR(opp_table->clk))
                clk_put(opp_table->clk);
@@ -905,6 +941,7 @@ static void _opp_table_kref_release(struct kref *kref)
                _remove_opp_dev(opp_dev, opp_table);
        }
 
+       mutex_destroy(&opp_table->genpd_virt_dev_lock);
        mutex_destroy(&opp_table->lock);
        list_del(&opp_table->node);
        kfree(opp_table);
@@ -961,6 +998,7 @@ static void _opp_kref_release(struct kref *kref)
         * frequency/voltage list.
         */
        blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
+       _of_opp_free_required_opps(opp_table, opp);
        opp_debug_remove_one(opp);
        list_del(&opp->node);
        kfree(opp);
@@ -1028,7 +1066,7 @@ struct dev_pm_opp *_opp_allocate(struct opp_table *table)
        int count, supply_size;
 
        /* Allocate space for at least one supply */
-       count = table->regulator_count ? table->regulator_count : 1;
+       count = table->regulator_count > 0 ? table->regulator_count : 1;
        supply_size = sizeof(*opp->supplies) * count;
 
        /* allocate new OPP node and supplies structures */
@@ -1049,6 +1087,9 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
        struct regulator *reg;
        int i;
 
+       if (!opp_table->regulators)
+               return true;
+
        for (i = 0; i < opp_table->regulator_count; i++) {
                reg = opp_table->regulators[i];
 
@@ -1333,7 +1374,7 @@ static int _allocate_set_opp_data(struct opp_table *opp_table)
        struct dev_pm_set_opp_data *data;
        int len, count = opp_table->regulator_count;
 
-       if (WARN_ON(!count))
+       if (WARN_ON(!opp_table->regulators))
                return -EINVAL;
 
        /* space for set_opp_data */
@@ -1430,7 +1471,7 @@ free_regulators:
 
        kfree(opp_table->regulators);
        opp_table->regulators = NULL;
-       opp_table->regulator_count = 0;
+       opp_table->regulator_count = -1;
 err:
        dev_pm_opp_put_opp_table(opp_table);
 
@@ -1459,7 +1500,7 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
 
        kfree(opp_table->regulators);
        opp_table->regulators = NULL;
-       opp_table->regulator_count = 0;
+       opp_table->regulator_count = -1;
 
 put_opp_table:
        dev_pm_opp_put_opp_table(opp_table);
@@ -1586,6 +1627,155 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
 
+/**
+ * dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index
+ * @dev: Consumer device for which the genpd device is getting set.
+ * @virt_dev: virtual genpd device.
+ * @index: index.
+ *
+ * Multiple generic power domains for a device are supported with the help of
+ * virtual genpd devices, which are created for each consumer device - genpd
+ * pair. These are the device structures which are attached to the power domain
+ * and are required by the OPP core to set the performance state of the genpd.
+ *
+ * This helper will normally be called by the consumer driver of the device
+ * "dev", as only that has details of the genpd devices.
+ *
+ * This helper needs to be called once for each of those virtual devices, but
+ * only if multiple domains are available for a device. Otherwise the original
+ * device structure will be used instead by the OPP core.
+ */
+struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev,
+                                               struct device *virt_dev,
+                                               int index)
+{
+       struct opp_table *opp_table;
+
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_lock(&opp_table->genpd_virt_dev_lock);
+
+       if (unlikely(!opp_table->genpd_virt_devs ||
+                    index >= opp_table->required_opp_count ||
+                    opp_table->genpd_virt_devs[index])) {
+
+               dev_err(dev, "Invalid request to set required device\n");
+               dev_pm_opp_put_opp_table(opp_table);
+               mutex_unlock(&opp_table->genpd_virt_dev_lock);
+
+               return ERR_PTR(-EINVAL);
+       }
+
+       opp_table->genpd_virt_devs[index] = virt_dev;
+       mutex_unlock(&opp_table->genpd_virt_dev_lock);
+
+       return opp_table;
+}
+
+/**
+ * dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device.
+ * @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev().
+ * @virt_dev: virtual genpd device.
+ *
+ * This releases the resource previously acquired with a call to
+ * dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper
+ * if it doesn't want OPP core to update performance state of a power domain
+ * anymore.
+ */
+void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table,
+                                  struct device *virt_dev)
+{
+       int i;
+
+       /*
+        * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
+        * used in parallel.
+        */
+       mutex_lock(&opp_table->genpd_virt_dev_lock);
+
+       for (i = 0; i < opp_table->required_opp_count; i++) {
+               if (opp_table->genpd_virt_devs[i] != virt_dev)
+                       continue;
+
+               opp_table->genpd_virt_devs[i] = NULL;
+               dev_pm_opp_put_opp_table(opp_table);
+
+               /* Drop the vote */
+               dev_pm_genpd_set_performance_state(virt_dev, 0);
+               break;
+       }
+
+       mutex_unlock(&opp_table->genpd_virt_dev_lock);
+
+       if (unlikely(i == opp_table->required_opp_count))
+               dev_err(virt_dev, "Failed to find required device entry\n");
+}
+
+/**
+ * dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
+ * @src_table: OPP table which has dst_table as one of its required OPP table.
+ * @dst_table: Required OPP table of the src_table.
+ * @pstate: Current performance state of the src_table.
+ *
+ * This Returns pstate of the OPP (present in @dst_table) pointed out by the
+ * "required-opps" property of the OPP (present in @src_table) which has
+ * performance state set to @pstate.
+ *
+ * Return: Zero or positive performance state on success, otherwise negative
+ * value on errors.
+ */
+int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
+                                      struct opp_table *dst_table,
+                                      unsigned int pstate)
+{
+       struct dev_pm_opp *opp;
+       int dest_pstate = -EINVAL;
+       int i;
+
+       if (!pstate)
+               return 0;
+
+       /*
+        * Normally the src_table will have the "required_opps" property set to
+        * point to one of the OPPs in the dst_table, but in some cases the
+        * genpd and its master have one to one mapping of performance states
+        * and so none of them have the "required-opps" property set. Return the
+        * pstate of the src_table as it is in such cases.
+        */
+       if (!src_table->required_opp_count)
+               return pstate;
+
+       for (i = 0; i < src_table->required_opp_count; i++) {
+               if (src_table->required_opp_tables[i]->np == dst_table->np)
+                       break;
+       }
+
+       if (unlikely(i == src_table->required_opp_count)) {
+               pr_err("%s: Couldn't find matching OPP table (%p: %p)\n",
+                      __func__, src_table, dst_table);
+               return -EINVAL;
+       }
+
+       mutex_lock(&src_table->lock);
+
+       list_for_each_entry(opp, &src_table->opp_list, node) {
+               if (opp->pstate == pstate) {
+                       dest_pstate = opp->required_opps[i]->pstate;
+                       goto unlock;
+               }
+       }
+
+       pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__, src_table,
+              dst_table);
+
+unlock:
+       mutex_unlock(&src_table->lock);
+
+       return dest_pstate;
+}
+
 /**
  * dev_pm_opp_add()  - Add an OPP table from a table definitions
  * @dev:       device for which we do this operation
@@ -1612,6 +1802,9 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
        if (!opp_table)
                return -ENOMEM;
 
+       /* Fix regulator count for dynamic OPPs */
+       opp_table->regulator_count = 1;
+
        ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
        if (ret)
                dev_pm_opp_put_opp_table(opp_table);
index 38a08805a30c64bba10519550474cac0fc83cdad..06f0f632ec4771aa84874221900e07c1b8b924ef 100644 (file)
@@ -73,6 +73,167 @@ struct opp_table *_managed_opp(struct device *dev, int index)
        return managed_table;
 }
 
+/* The caller must call dev_pm_opp_put() after the OPP is used */
+static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
+                                         struct device_node *opp_np)
+{
+       struct dev_pm_opp *opp;
+
+       lockdep_assert_held(&opp_table_lock);
+
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(opp, &opp_table->opp_list, node) {
+               if (opp->np == opp_np) {
+                       dev_pm_opp_get(opp);
+                       mutex_unlock(&opp_table->lock);
+                       return opp;
+               }
+       }
+
+       mutex_unlock(&opp_table->lock);
+
+       return NULL;
+}
+
+static struct device_node *of_parse_required_opp(struct device_node *np,
+                                                int index)
+{
+       struct device_node *required_np;
+
+       required_np = of_parse_phandle(np, "required-opps", index);
+       if (unlikely(!required_np)) {
+               pr_err("%s: Unable to parse required-opps: %pOF, index: %d\n",
+                      __func__, np, index);
+       }
+
+       return required_np;
+}
+
+/* The caller must call dev_pm_opp_put_opp_table() after the table is used */
+static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
+{
+       struct opp_table *opp_table;
+       struct device_node *opp_table_np;
+
+       lockdep_assert_held(&opp_table_lock);
+
+       opp_table_np = of_get_parent(opp_np);
+       if (!opp_table_np)
+               goto err;
+
+       /* It is safe to put the node now as all we need now is its address */
+       of_node_put(opp_table_np);
+
+       list_for_each_entry(opp_table, &opp_tables, node) {
+               if (opp_table_np == opp_table->np) {
+                       _get_opp_table_kref(opp_table);
+                       return opp_table;
+               }
+       }
+
+err:
+       return ERR_PTR(-ENODEV);
+}
+
+/* Free resources previously acquired by _opp_table_alloc_required_tables() */
+static void _opp_table_free_required_tables(struct opp_table *opp_table)
+{
+       struct opp_table **required_opp_tables = opp_table->required_opp_tables;
+       struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
+       int i;
+
+       if (!required_opp_tables)
+               return;
+
+       for (i = 0; i < opp_table->required_opp_count; i++) {
+               if (IS_ERR_OR_NULL(required_opp_tables[i]))
+                       break;
+
+               dev_pm_opp_put_opp_table(required_opp_tables[i]);
+       }
+
+       kfree(required_opp_tables);
+       kfree(genpd_virt_devs);
+
+       opp_table->required_opp_count = 0;
+       opp_table->genpd_virt_devs = NULL;
+       opp_table->required_opp_tables = NULL;
+}
+
+/*
+ * Populate all devices and opp tables which are part of "required-opps" list.
+ * Checking only the first OPP node should be enough.
+ */
+static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
+                                            struct device *dev,
+                                            struct device_node *opp_np)
+{
+       struct opp_table **required_opp_tables;
+       struct device **genpd_virt_devs = NULL;
+       struct device_node *required_np, *np;
+       int count, i;
+
+       /* Traversing the first OPP node is all we need */
+       np = of_get_next_available_child(opp_np, NULL);
+       if (!np) {
+               dev_err(dev, "Empty OPP table\n");
+               return;
+       }
+
+       count = of_count_phandle_with_args(np, "required-opps", NULL);
+       if (!count)
+               goto put_np;
+
+       if (count > 1) {
+               genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs),
+                                       GFP_KERNEL);
+               if (!genpd_virt_devs)
+                       goto put_np;
+       }
+
+       required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
+                                     GFP_KERNEL);
+       if (!required_opp_tables) {
+               kfree(genpd_virt_devs);
+               goto put_np;
+       }
+
+       opp_table->genpd_virt_devs = genpd_virt_devs;
+       opp_table->required_opp_tables = required_opp_tables;
+       opp_table->required_opp_count = count;
+
+       for (i = 0; i < count; i++) {
+               required_np = of_parse_required_opp(np, i);
+               if (!required_np)
+                       goto free_required_tables;
+
+               required_opp_tables[i] = _find_table_of_opp_np(required_np);
+               of_node_put(required_np);
+
+               if (IS_ERR(required_opp_tables[i]))
+                       goto free_required_tables;
+
+               /*
+                * We only support genpd's OPPs in the "required-opps" for now,
+                * as we don't know how much about other cases. Error out if the
+                * required OPP doesn't belong to a genpd.
+                */
+               if (!required_opp_tables[i]->is_genpd) {
+                       dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
+                               required_np);
+                       goto free_required_tables;
+               }
+       }
+
+       goto put_np;
+
+free_required_tables:
+       _opp_table_free_required_tables(opp_table);
+put_np:
+       of_node_put(np);
+}
+
 void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
                        int index)
 {
@@ -92,6 +253,9 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
        of_property_read_u32(np, "voltage-tolerance",
                             &opp_table->voltage_tolerance_v1);
 
+       if (of_find_property(np, "#power-domain-cells", NULL))
+               opp_table->is_genpd = true;
+
        /* Get OPP table node */
        opp_np = _opp_of_get_opp_desc_node(np, index);
        of_node_put(np);
@@ -106,9 +270,86 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
 
        opp_table->np = opp_np;
 
+       _opp_table_alloc_required_tables(opp_table, dev, opp_np);
        of_node_put(opp_np);
 }
 
+void _of_clear_opp_table(struct opp_table *opp_table)
+{
+       _opp_table_free_required_tables(opp_table);
+}
+
+/*
+ * Release all resources previously acquired with a call to
+ * _of_opp_alloc_required_opps().
+ */
+void _of_opp_free_required_opps(struct opp_table *opp_table,
+                               struct dev_pm_opp *opp)
+{
+       struct dev_pm_opp **required_opps = opp->required_opps;
+       int i;
+
+       if (!required_opps)
+               return;
+
+       for (i = 0; i < opp_table->required_opp_count; i++) {
+               if (!required_opps[i])
+                       break;
+
+               /* Put the reference back */
+               dev_pm_opp_put(required_opps[i]);
+       }
+
+       kfree(required_opps);
+       opp->required_opps = NULL;
+}
+
+/* Populate all required OPPs which are part of "required-opps" list */
+static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
+                                      struct dev_pm_opp *opp)
+{
+       struct dev_pm_opp **required_opps;
+       struct opp_table *required_table;
+       struct device_node *np;
+       int i, ret, count = opp_table->required_opp_count;
+
+       if (!count)
+               return 0;
+
+       required_opps = kcalloc(count, sizeof(*required_opps), GFP_KERNEL);
+       if (!required_opps)
+               return -ENOMEM;
+
+       opp->required_opps = required_opps;
+
+       for (i = 0; i < count; i++) {
+               required_table = opp_table->required_opp_tables[i];
+
+               np = of_parse_required_opp(opp->np, i);
+               if (unlikely(!np)) {
+                       ret = -ENODEV;
+                       goto free_required_opps;
+               }
+
+               required_opps[i] = _find_opp_of_np(required_table, np);
+               of_node_put(np);
+
+               if (!required_opps[i]) {
+                       pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
+                              __func__, opp->np, i);
+                       ret = -ENODEV;
+                       goto free_required_opps;
+               }
+       }
+
+       return 0;
+
+free_required_opps:
+       _of_opp_free_required_opps(opp_table, opp);
+
+       return ret;
+}
+
 static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
                              struct device_node *np)
 {
@@ -150,12 +391,10 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
                              struct opp_table *opp_table)
 {
        u32 *microvolt, *microamp = NULL;
-       int supplies, vcount, icount, ret, i, j;
+       int supplies = opp_table->regulator_count, vcount, icount, ret, i, j;
        struct property *prop = NULL;
        char name[NAME_MAX];
 
-       supplies = opp_table->regulator_count ? opp_table->regulator_count : 1;
-
        /* Search for "opp-microvolt-<name>" */
        if (opp_table->prop_name) {
                snprintf(name, sizeof(name), "opp-microvolt-%s",
@@ -170,7 +409,13 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
 
                /* Missing property isn't a problem, but an invalid entry is */
                if (!prop) {
-                       if (!opp_table->regulator_count)
+                       if (unlikely(supplies == -1)) {
+                               /* Initialize regulator_count */
+                               opp_table->regulator_count = 0;
+                               return 0;
+                       }
+
+                       if (!supplies)
                                return 0;
 
                        dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
@@ -179,6 +424,14 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
                }
        }
 
+       if (unlikely(supplies == -1)) {
+               /* Initialize regulator_count */
+               supplies = opp_table->regulator_count = 1;
+       } else if (unlikely(!supplies)) {
+               dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
+               return -EINVAL;
+       }
+
        vcount = of_property_count_u32_elems(opp->np, name);
        if (vcount < 0) {
                dev_err(dev, "%s: Invalid %s property (%d)\n",
@@ -326,8 +579,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        ret = of_property_read_u64(np, "opp-hz", &rate);
        if (ret < 0) {
                /* "opp-hz" is optional for devices like power domains. */
-               if (!of_find_property(dev->of_node, "#power-domain-cells",
-                                     NULL)) {
+               if (!opp_table->is_genpd) {
                        dev_err(dev, "%s: opp-hz not found\n", __func__);
                        goto free_opp;
                }
@@ -354,21 +606,26 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        new_opp->dynamic = false;
        new_opp->available = true;
 
+       ret = _of_opp_alloc_required_opps(opp_table, new_opp);
+       if (ret)
+               goto free_opp;
+
        if (!of_property_read_u32(np, "clock-latency-ns", &val))
                new_opp->clock_latency_ns = val;
 
-       new_opp->pstate = of_genpd_opp_to_performance_state(dev, np);
-
        ret = opp_parse_supplies(new_opp, dev, opp_table);
        if (ret)
-               goto free_opp;
+               goto free_required_opps;
+
+       if (opp_table->is_genpd)
+               new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
 
        ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
        if (ret) {
                /* Don't return error for duplicate OPPs */
                if (ret == -EBUSY)
                        ret = 0;
-               goto free_opp;
+               goto free_required_opps;
        }
 
        /* OPP to select on device suspend */
@@ -398,6 +655,8 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
        blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
        return new_opp;
 
+free_required_opps:
+       _of_opp_free_required_opps(opp_table, new_opp);
 free_opp:
        _opp_free(new_opp);
 
@@ -727,58 +986,48 @@ put_cpu_node:
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
 
 /**
- * of_dev_pm_opp_find_required_opp() - Search for required OPP.
- * @dev: The device whose OPP node is referenced by the 'np' DT node.
+ * of_get_required_opp_performance_state() - Search for required OPP and return its performance state.
  * @np: Node that contains the "required-opps" property.
+ * @index: Index of the phandle to parse.
  *
- * Returns the OPP of the device 'dev', whose phandle is present in the "np"
- * node. Although the "required-opps" property supports having multiple
- * phandles, this helper routine only parses the very first phandle in the list.
- *
- * Return: Matching opp, else returns ERR_PTR in case of error and should be
- * handled using IS_ERR.
+ * Returns the performance state of the OPP pointed out by the "required-opps"
+ * property at @index in @np.
  *
- * The callers are required to call dev_pm_opp_put() for the returned OPP after
- * use.
+ * Return: Zero or positive performance state on success, otherwise negative
+ * value on errors.
  */
-struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev,
-                                                  struct device_node *np)
+int of_get_required_opp_performance_state(struct device_node *np, int index)
 {
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+       struct dev_pm_opp *opp;
        struct device_node *required_np;
        struct opp_table *opp_table;
+       int pstate = -EINVAL;
 
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table);
+       required_np = of_parse_required_opp(np, index);
+       if (!required_np)
+               return -EINVAL;
 
-       required_np = of_parse_phandle(np, "required-opps", 0);
-       if (unlikely(!required_np)) {
-               dev_err(dev, "Unable to parse required-opps\n");
-               goto put_opp_table;
+       opp_table = _find_table_of_opp_np(required_np);
+       if (IS_ERR(opp_table)) {
+               pr_err("%s: Failed to find required OPP table %pOF: %ld\n",
+                      __func__, np, PTR_ERR(opp_table));
+               goto put_required_np;
        }
 
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->np == required_np) {
-                       opp = temp_opp;
-
-                       /* Increment the reference count of OPP */
-                       dev_pm_opp_get(opp);
-                       break;
-               }
+       opp = _find_opp_of_np(opp_table, required_np);
+       if (opp) {
+               pstate = opp->pstate;
+               dev_pm_opp_put(opp);
        }
 
-       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
 
+put_required_np:
        of_node_put(required_np);
-put_opp_table:
-       dev_pm_opp_put_opp_table(opp_table);
 
-       return opp;
+       return pstate;
 }
-EXPORT_SYMBOL_GPL(of_dev_pm_opp_find_required_opp);
+EXPORT_SYMBOL_GPL(of_get_required_opp_performance_state);
 
 /**
  * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp
index 9c6544b4f4f901027c645c1d3bfdb223f6610826..e24d81497375dc2f3283426848dab05574e10001 100644 (file)
@@ -63,6 +63,7 @@ extern struct list_head opp_tables;
  * @supplies:  Power supplies voltage/current values
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
  *             frequency from any other OPP's frequency.
+ * @required_opps: List of OPPs that are required by this OPP.
  * @opp_table: points back to the opp_table struct this opp belongs to
  * @np:                OPP's device node.
  * @dentry:    debugfs dentry pointer (per opp)
@@ -84,6 +85,7 @@ struct dev_pm_opp {
 
        unsigned long clock_latency_ns;
 
+       struct dev_pm_opp **required_opps;
        struct opp_table *opp_table;
 
        struct device_node *np;
@@ -133,13 +135,21 @@ enum opp_table_access {
  * @parsed_static_opps: True if OPPs are initialized from DT.
  * @shared_opp: OPP is shared between multiple devices.
  * @suspend_opp: Pointer to OPP to be used during device suspend.
+ * @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
+ * @genpd_virt_devs: List of virtual devices for multiple genpd support.
+ * @required_opp_tables: List of device OPP tables that are required by OPPs in
+ *             this table.
+ * @required_opp_count: Number of required devices.
  * @supported_hw: Array of version number to support.
  * @supported_hw_count: Number of elements in supported_hw array.
  * @prop_name: A name to postfix to many DT properties, while parsing them.
  * @clk: Device's clock handle
  * @regulators: Supply regulators
- * @regulator_count: Number of power supply regulators
+ * @regulator_count: Number of power supply regulators. Its value can be -1
+ * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt
+ * property).
  * @genpd_performance_state: Device's power domain support performance state.
+ * @is_genpd: Marks if the OPP table belongs to a genpd.
  * @set_opp: Platform specific set_opp callback
  * @set_opp_data: Data to be passed to set_opp callback
  * @dentry:    debugfs dentry pointer of the real device directory (not links).
@@ -171,13 +181,19 @@ struct opp_table {
        enum opp_table_access shared_opp;
        struct dev_pm_opp *suspend_opp;
 
+       struct mutex genpd_virt_dev_lock;
+       struct device **genpd_virt_devs;
+       struct opp_table **required_opp_tables;
+       unsigned int required_opp_count;
+
        unsigned int *supported_hw;
        unsigned int supported_hw_count;
        const char *prop_name;
        struct clk *clk;
        struct regulator **regulators;
-       unsigned int regulator_count;
+       int regulator_count;
        bool genpd_performance_state;
+       bool is_genpd;
 
        int (*set_opp)(struct dev_pm_set_opp_data *data);
        struct dev_pm_set_opp_data *set_opp_data;
@@ -206,10 +222,16 @@ void _put_opp_list_kref(struct opp_table *opp_table);
 
 #ifdef CONFIG_OF
 void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
+void _of_clear_opp_table(struct opp_table *opp_table);
 struct opp_table *_managed_opp(struct device *dev, int index);
+void _of_opp_free_required_opps(struct opp_table *opp_table,
+                               struct dev_pm_opp *opp);
 #else
 static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
+static inline void _of_clear_opp_table(struct opp_table *opp_table) {}
 static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
+static inline void _of_opp_free_required_opps(struct opp_table *opp_table,
+                                             struct dev_pm_opp *opp) {}
 #endif
 
 #ifdef CONFIG_DEBUG_FS
index f2bda77a2df1f98b8abd68fb1127c687c272ee60..657d642fcc67a8a99a4fb3548550eae758c60c45 100644 (file)
@@ -11,6 +11,7 @@ ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)          += proc.o
 obj-$(CONFIG_SYSFS)            += slot.o
 obj-$(CONFIG_OF)               += of.o
+obj-$(CONFIG_ACPI)             += pci-acpi.o
 endif
 
 obj-$(CONFIG_PCI_QUIRKS)       += quirks.o
@@ -20,7 +21,6 @@ obj-$(CONFIG_PCI_MSI)         += msi.o
 obj-$(CONFIG_PCI_ATS)          += ats.o
 obj-$(CONFIG_PCI_IOV)          += iov.o
 obj-$(CONFIG_PCI_BRIDGE_EMUL)  += pci-bridge-emul.o
-obj-$(CONFIG_ACPI)             += pci-acpi.o
 obj-$(CONFIG_PCI_LABEL)                += pci-label.o
 obj-$(CONFIG_X86_INTEL_MID)    += pci-mid.o
 obj-$(CONFIG_PCI_SYSCALL)      += syscall.o
index a90a9194ac4a8304df3076cb40dc32d8bc0605c7..fed29de783e00ff554e2e0c8e0e0849bf70d6c35 100644 (file)
@@ -1064,7 +1064,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
                .regs           = aer_regs,
        };
 
-       if (kfifo_in_spinlocked(&aer_recover_ring, &entry, sizeof(entry),
+       if (kfifo_in_spinlocked(&aer_recover_ring, &entry, 1,
                                 &aer_recover_ring_lock))
                schedule_work(&aer_recover_work);
        else
index 54f6a40c75c69c667ac3d4591dde89fd99bac3be..45ef4d22f14c5ed68fee9f625d7ed91e3fe69796 100644 (file)
@@ -177,6 +177,8 @@ config DELL_LAPTOP
        select POWER_SUPPLY
        select LEDS_CLASS
        select NEW_LEDS
+       select LEDS_TRIGGERS
+       select LEDS_TRIGGER_AUDIO
        ---help---
        This driver adds support for rfkill and backlight control to Dell
        laptops (except for some models covered by the Compal driver).
@@ -493,6 +495,8 @@ config THINKPAD_ACPI
        select NVRAM
        select NEW_LEDS
        select LEDS_CLASS
+       select LEDS_TRIGGERS
+       select LEDS_TRIGGER_AUDIO
        ---help---
          This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
          support for Fn-Fx key combinations, Bluetooth control, video
@@ -1288,6 +1292,23 @@ config INTEL_ATOMISP2_PM
          To compile this driver as a module, choose M here: the module
          will be called intel_atomisp2_pm.
 
+config HUAWEI_WMI
+       tristate "Huawei WMI hotkeys driver"
+       depends on ACPI_WMI
+       depends on INPUT
+       select INPUT_SPARSEKMAP
+       select LEDS_CLASS
+       select LEDS_TRIGGERS
+       select LEDS_TRIGGER_AUDIO
+       select NEW_LEDS
+       help
+         This driver provides support for Huawei WMI hotkeys.
+         It enables the missing keys and adds support to the micmute
+         LED found on some of these laptops.
+
+         To compile this driver as a module, choose M here: the module
+         will be called huawei-wmi.
+
 endif # X86_PLATFORM_DEVICES
 
 config PMC_ATOM
index 39ae94135406b69bb7cef9bcb8d24242382afe35..d841c550e3cc6cb05ea9cbd5000f30663ba787b8 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_ACERHDF)         += acerhdf.o
 obj-$(CONFIG_HP_ACCEL)         += hp_accel.o
 obj-$(CONFIG_HP_WIRELESS)      += hp-wireless.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
+obj-$(CONFIG_HUAWEI_WMI)               += huawei-wmi.o
 obj-$(CONFIG_AMILO_RFKILL)     += amilo-rfkill.o
 obj-$(CONFIG_GPD_POCKET_FAN)   += gpd-pocket-fan.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
index db2af09067dbcb4d57da168ebffed7ede9c5fa94..b6f2ff95c3ed9eaf237b80e3415a5c28032ec9b1 100644 (file)
@@ -442,8 +442,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
-       { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
-       { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
+       { KE_KEY, 0x35, { KEY_SCREENLOCK } },
        { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
        { KE_KEY, 0x41, { KEY_NEXTSONG } },
        { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
index c285a16675ee7d912280028bf5f94c552fad6371..37b5de54127043441e7cb373d032ef8981b67ca7 100644 (file)
@@ -2131,7 +2131,8 @@ static int asus_wmi_add(struct platform_device *pdev)
                err = asus_wmi_backlight_init(asus);
                if (err && err != -ENODEV)
                        goto fail_backlight;
-       }
+       } else
+               err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
 
        status = wmi_install_notify_handler(asus->driver->event_guid,
                                            asus_wmi_notify, asus);
index 06978c14c83b23c5e35c4cb721863903a736486d..95e6ca116e00e2932e8dbcce678ca3489c31b5dc 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/mm.h>
 #include <linux/i8042.h>
 #include <linux/debugfs.h>
-#include <linux/dell-led.h>
 #include <linux/seq_file.h>
 #include <acpi/video.h>
 #include "dell-rbtn.h"
@@ -1565,8 +1564,10 @@ static ssize_t kbd_led_timeout_store(struct device *dev,
                switch (unit) {
                case KBD_TIMEOUT_DAYS:
                        value *= 24;
+                       /* fall through */
                case KBD_TIMEOUT_HOURS:
                        value *= 60;
+                       /* fall through */
                case KBD_TIMEOUT_MINUTES:
                        value *= 60;
                        unit = KBD_TIMEOUT_SECONDS;
@@ -2109,17 +2110,17 @@ static struct notifier_block dell_laptop_notifier = {
        .notifier_call = dell_laptop_notifier_call,
 };
 
-int dell_micmute_led_set(int state)
+static int micmute_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness brightness)
 {
        struct calling_interface_buffer buffer;
        struct calling_interface_token *token;
+       int state = brightness != LED_OFF;
 
        if (state == 0)
                token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
-       else if (state == 1)
-               token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
        else
-               return -EINVAL;
+               token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
 
        if (!token)
                return -ENODEV;
@@ -2127,9 +2128,15 @@ int dell_micmute_led_set(int state)
        dell_fill_request(&buffer, token->location, token->value, 0, 0);
        dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
 
-       return state;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(dell_micmute_led_set);
+
+static struct led_classdev micmute_led_cdev = {
+       .name = "platform::micmute",
+       .max_brightness = 1,
+       .brightness_set_blocking = micmute_led_set,
+       .default_trigger = "audio-micmute",
+};
 
 static int __init dell_init(void)
 {
@@ -2175,6 +2182,11 @@ static int __init dell_init(void)
 
        dell_laptop_register_notifier(&dell_laptop_notifier);
 
+       micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+       ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev);
+       if (ret < 0)
+               goto fail_led;
+
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
 
@@ -2220,6 +2232,8 @@ static int __init dell_init(void)
 fail_get_brightness:
        backlight_device_unregister(dell_backlight_device);
 fail_backlight:
+       led_classdev_unregister(&micmute_led_cdev);
+fail_led:
        dell_cleanup_rfkill();
 fail_rfkill:
        platform_device_del(platform_device);
@@ -2239,6 +2253,7 @@ static void __exit dell_exit(void)
                touchpad_led_exit();
        kbd_led_exit();
        backlight_device_unregister(dell_backlight_device);
+       led_classdev_unregister(&micmute_led_cdev);
        dell_cleanup_rfkill();
        if (platform_device) {
                platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
new file mode 100644 (file)
index 0000000..59872f8
--- /dev/null
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Huawei WMI hotkeys
+ *
+ *  Copyright (C) 2018       Ayman Bagabas <ayman.bagabas@gmail.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+/*
+ * Huawei WMI GUIDs
+ */
+#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+
+#define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
+
+struct huawei_wmi_priv {
+       struct input_dev *idev;
+       struct led_classdev cdev;
+       acpi_handle handle;
+       char *acpi_method;
+};
+
+static const struct key_entry huawei_wmi_keymap[] = {
+       { KE_KEY,    0x281, { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY,    0x282, { KEY_BRIGHTNESSUP } },
+       { KE_KEY,    0x284, { KEY_MUTE } },
+       { KE_KEY,    0x285, { KEY_VOLUMEDOWN } },
+       { KE_KEY,    0x286, { KEY_VOLUMEUP } },
+       { KE_KEY,    0x287, { KEY_MICMUTE } },
+       { KE_KEY,    0x289, { KEY_WLAN } },
+       // Huawei |M| key
+       { KE_KEY,    0x28a, { KEY_CONFIG } },
+       // Keyboard backlight
+       { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
+       { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
+       { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
+       { KE_END,        0 }
+};
+
+static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
+               enum led_brightness brightness)
+{
+       struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
+       acpi_status status;
+       union acpi_object args[3];
+       struct acpi_object_list arg_list = {
+               .pointer = args,
+               .count = ARRAY_SIZE(args),
+       };
+
+       args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
+       args[1].integer.value = 0x04;
+
+       if (strcmp(priv->acpi_method, "SPIN") == 0) {
+               args[0].integer.value = 0;
+               args[2].integer.value = brightness ? 1 : 0;
+       } else if (strcmp(priv->acpi_method, "WPIN") == 0) {
+               args[0].integer.value = 1;
+               args[2].integer.value = brightness ? 0 : 1;
+       } else {
+               return -EINVAL;
+       }
+
+       status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENXIO;
+
+       return 0;
+}
+
+static int huawei_wmi_leds_setup(struct wmi_device *wdev)
+{
+       struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+
+       priv->handle = ec_get_handle();
+       if (!priv->handle)
+               return 0;
+
+       if (acpi_has_method(priv->handle, "SPIN"))
+               priv->acpi_method = "SPIN";
+       else if (acpi_has_method(priv->handle, "WPIN"))
+               priv->acpi_method = "WPIN";
+       else
+               return 0;
+
+       priv->cdev.name = "platform::micmute";
+       priv->cdev.max_brightness = 1;
+       priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
+       priv->cdev.default_trigger = "audio-micmute";
+       priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+       priv->cdev.dev = &wdev->dev;
+       priv->cdev.flags = LED_CORE_SUSPENDRESUME;
+
+       return devm_led_classdev_register(&wdev->dev, &priv->cdev);
+}
+
+static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
+{
+       struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+       const struct key_entry *key;
+
+       /*
+        * WMI0 uses code 0x80 to indicate a hotkey event.
+        * The actual key is fetched from the method WQ00
+        * using WMI0_EXPENSIVE_GUID.
+        */
+       if (code == 0x80) {
+               struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+               union acpi_object *obj;
+               acpi_status status;
+
+               status = wmi_query_block(WMI0_EXPENSIVE_GUID, 0, &response);
+               if (ACPI_FAILURE(status))
+                       return;
+
+               obj = (union acpi_object *)response.pointer;
+               if (obj && obj->type == ACPI_TYPE_INTEGER)
+                       code = obj->integer.value;
+
+               kfree(response.pointer);
+       }
+
+       key = sparse_keymap_entry_from_scancode(priv->idev, code);
+       if (!key) {
+               dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
+               return;
+       }
+
+       sparse_keymap_report_entry(priv->idev, key, 1, true);
+}
+
+static void huawei_wmi_notify(struct wmi_device *wdev,
+               union acpi_object *obj)
+{
+       if (obj->type == ACPI_TYPE_INTEGER)
+               huawei_wmi_process_key(wdev, obj->integer.value);
+       else
+               dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
+}
+
+static int huawei_wmi_input_setup(struct wmi_device *wdev)
+{
+       struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+       int err;
+
+       priv->idev = devm_input_allocate_device(&wdev->dev);
+       if (!priv->idev)
+               return -ENOMEM;
+
+       priv->idev->name = "Huawei WMI hotkeys";
+       priv->idev->phys = "wmi/input0";
+       priv->idev->id.bustype = BUS_HOST;
+       priv->idev->dev.parent = &wdev->dev;
+
+       err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
+       if (err)
+               return err;
+
+       return input_register_device(priv->idev);
+}
+
+static int huawei_wmi_probe(struct wmi_device *wdev)
+{
+       struct huawei_wmi_priv *priv;
+       int err;
+
+       priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dev_set_drvdata(&wdev->dev, priv);
+
+       err = huawei_wmi_input_setup(wdev);
+       if (err)
+               return err;
+
+       return huawei_wmi_leds_setup(wdev);
+}
+
+static const struct wmi_device_id huawei_wmi_id_table[] = {
+       { .guid_string = WMI0_EVENT_GUID },
+       { .guid_string = AMW0_EVENT_GUID },
+       {  }
+};
+
+static struct wmi_driver huawei_wmi_driver = {
+       .driver = {
+               .name = "huawei-wmi",
+       },
+       .id_table = huawei_wmi_id_table,
+       .probe = huawei_wmi_probe,
+       .notify = huawei_wmi_notify,
+};
+
+module_wmi_driver(huawei_wmi_driver);
+
+MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
+MODULE_ALIAS("wmi:"AMW0_EVENT_GUID);
+MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
+MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_LICENSE("GPL v2");
index 5456581b473c9f417e07198799371033bb560159..3d893e0ac2505eea63532cc7b98a4b161773b04a 100644 (file)
@@ -7,15 +7,23 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/bits.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define IRQ_RESOURCE_TYPE      GENMASK(1, 0)
+#define IRQ_RESOURCE_NONE      0
+#define IRQ_RESOURCE_GPIO      1
+#define IRQ_RESOURCE_APIC      2
 
 struct i2c_inst_data {
        const char *type;
-       int gpio_irq_idx;
+       unsigned int flags;
+       int irq_idx;
 };
 
 struct i2c_multi_inst_data {
@@ -23,6 +31,31 @@ struct i2c_multi_inst_data {
        struct i2c_client *clients[0];
 };
 
+static int i2c_multi_inst_count(struct acpi_resource *ares, void *data)
+{
+       struct acpi_resource_i2c_serialbus *sb;
+       int *count = data;
+
+       if (i2c_acpi_get_i2c_resource(ares, &sb))
+               *count = *count + 1;
+
+       return 1;
+}
+
+static int i2c_multi_inst_count_resources(struct acpi_device *adev)
+{
+       LIST_HEAD(r);
+       int count = 0;
+       int ret;
+
+       ret = acpi_dev_get_resources(adev, &r, i2c_multi_inst_count, &count);
+       if (ret < 0)
+               return ret;
+
+       acpi_dev_free_resource_list(&r);
+       return count;
+}
+
 static int i2c_multi_inst_probe(struct platform_device *pdev)
 {
        struct i2c_multi_inst_data *multi;
@@ -44,40 +77,59 @@ static int i2c_multi_inst_probe(struct platform_device *pdev)
        adev = ACPI_COMPANION(dev);
 
        /* Count number of clients to instantiate */
-       for (i = 0; inst_data[i].type; i++) {}
+       ret = i2c_multi_inst_count_resources(adev);
+       if (ret < 0)
+               return ret;
 
        multi = devm_kmalloc(dev,
-                       offsetof(struct i2c_multi_inst_data, clients[i]),
+                       offsetof(struct i2c_multi_inst_data, clients[ret]),
                        GFP_KERNEL);
        if (!multi)
                return -ENOMEM;
 
-       multi->num_clients = i;
+       multi->num_clients = ret;
 
-       for (i = 0; i < multi->num_clients; i++) {
+       for (i = 0; i < multi->num_clients && inst_data[i].type; i++) {
                memset(&board_info, 0, sizeof(board_info));
                strlcpy(board_info.type, inst_data[i].type, I2C_NAME_SIZE);
-               snprintf(name, sizeof(name), "%s-%s", match->id,
-                        inst_data[i].type);
+               snprintf(name, sizeof(name), "%s-%s.%d", match->id,
+                        inst_data[i].type, i);
                board_info.dev_name = name;
-               board_info.irq = 0;
-               if (inst_data[i].gpio_irq_idx != -1) {
-                       ret = acpi_dev_gpio_irq_get(adev,
-                                                   inst_data[i].gpio_irq_idx);
+               switch (inst_data[i].flags & IRQ_RESOURCE_TYPE) {
+               case IRQ_RESOURCE_GPIO:
+                       ret = acpi_dev_gpio_irq_get(adev, inst_data[i].irq_idx);
                        if (ret < 0) {
                                dev_err(dev, "Error requesting irq at index %d: %d\n",
-                                       inst_data[i].gpio_irq_idx, ret);
+                                       inst_data[i].irq_idx, ret);
                                goto error;
                        }
                        board_info.irq = ret;
+                       break;
+               case IRQ_RESOURCE_APIC:
+                       ret = platform_get_irq(pdev, inst_data[i].irq_idx);
+                       if (ret < 0) {
+                               dev_dbg(dev, "Error requesting irq at index %d: %d\n",
+                                       inst_data[i].irq_idx, ret);
+                       }
+                       board_info.irq = ret;
+                       break;
+               default:
+                       board_info.irq = 0;
+                       break;
                }
                multi->clients[i] = i2c_acpi_new_device(dev, i, &board_info);
-               if (!multi->clients[i]) {
-                       dev_err(dev, "Error creating i2c-client, idx %d\n", i);
-                       ret = -ENODEV;
+               if (IS_ERR(multi->clients[i])) {
+                       ret = PTR_ERR(multi->clients[i]);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "Error creating i2c-client, idx %d\n", i);
                        goto error;
                }
        }
+       if (i < multi->num_clients) {
+               dev_err(dev, "Error finding driver, idx %d\n", i);
+               ret = -ENODEV;
+               goto error;
+       }
 
        platform_set_drvdata(pdev, multi);
        return 0;
@@ -101,9 +153,17 @@ static int i2c_multi_inst_remove(struct platform_device *pdev)
 }
 
 static const struct i2c_inst_data bsg1160_data[]  = {
-       { "bmc150_accel", 0 },
-       { "bmc150_magn", -1 },
-       { "bmg160", -1 },
+       { "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
+       { "bmc150_magn" },
+       { "bmg160" },
+       {}
+};
+
+static const struct i2c_inst_data int3515_data[]  = {
+       { "tps6598x", IRQ_RESOURCE_APIC, 0 },
+       { "tps6598x", IRQ_RESOURCE_APIC, 1 },
+       { "tps6598x", IRQ_RESOURCE_APIC, 2 },
+       { "tps6598x", IRQ_RESOURCE_APIC, 3 },
        {}
 };
 
@@ -113,6 +173,7 @@ static const struct i2c_inst_data bsg1160_data[]  = {
  */
 static const struct acpi_device_id i2c_multi_inst_acpi_ids[] = {
        { "BSG1160", (unsigned long)bsg1160_data },
+       { "INT3515", (unsigned long)int3515_data },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, i2c_multi_inst_acpi_ids);
index b6489cba29853e1919cd21c36e7fd19f3c720748..1589dffab9faf1359cf7eaa9f075d8d3e75d6f42 100644 (file)
@@ -1188,6 +1188,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
                },
        },
+       {
+               .ident = "Lenovo Yoga 2 13",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Yoga 2 13"),
+               },
+       },
        {
                .ident = "Lenovo Yoga 3 1170 / 1470",
                .matches = {
index 9371603a0ac90ca5f206e86f356f9e33b74814c2..b0f421fea2a58ed61d0063625c1855d61e575108 100644 (file)
 #define ISPSSPM0_IUNIT_POWER_ON                0x0
 #define ISPSSPM0_IUNIT_POWER_OFF       0x3
 
-static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int isp_set_power(struct pci_dev *dev, bool enable)
 {
        unsigned long timeout;
-       u32 val;
-
-       pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, 0);
-
-       /*
-        * MRFLD IUNIT DPHY is located in an always-power-on island
-        * MRFLD HW design need all CSI ports are disabled before
-        * powering down the IUNIT.
-        */
-       pci_read_config_dword(dev, PCI_CSI_CONTROL, &val);
-       val |= PCI_CSI_CONTROL_PORTS_OFF_MASK;
-       pci_write_config_dword(dev, PCI_CSI_CONTROL, val);
+       u32 val = enable ? ISPSSPM0_IUNIT_POWER_ON :
+               ISPSSPM0_IUNIT_POWER_OFF;
 
-       /* Write 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */
+       /* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */
        iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0,
-                       ISPSSPM0_IUNIT_POWER_OFF, ISPSSPM0_ISPSSC_MASK);
+                       val, ISPSSPM0_ISPSSC_MASK);
 
        /*
         * There should be no IUNIT access while power-down is
         * in progress HW sighting: 4567865
         * Wait up to 50 ms for the IUNIT to shut down.
+        * And we do the same for power on.
         */
        timeout = jiffies + msecs_to_jiffies(50);
        while (1) {
-               /* Wait until ISPSSPM0 bit[25:24] shows 0x3 */
-               iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &val);
-               val = (val & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET;
-               if (val == ISPSSPM0_IUNIT_POWER_OFF)
+               u32 tmp;
+
+               /* Wait until ISPSSPM0 bit[25:24] shows the right value */
+               iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &tmp);
+               tmp = (tmp & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET;
+               if (tmp == val)
                        break;
 
                if (time_after(jiffies, timeout)) {
-                       dev_err(&dev->dev, "IUNIT power-off timeout.\n");
+                       dev_err(&dev->dev, "IUNIT power-%s timeout.\n",
+                               enable ? "on" : "off");
                        return -EBUSY;
                }
                usleep_range(1000, 2000);
        }
 
+       return 0;
+}
+
+static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
        pm_runtime_allow(&dev->dev);
        pm_runtime_put_sync_suspend(&dev->dev);
 
@@ -87,11 +86,40 @@ static void isp_remove(struct pci_dev *dev)
 
 static int isp_pci_suspend(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
+       u32 val;
+
+       pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, 0);
+
+       /*
+        * MRFLD IUNIT DPHY is located in an always-power-on island
+        * MRFLD HW design need all CSI ports are disabled before
+        * powering down the IUNIT.
+        */
+       pci_read_config_dword(pdev, PCI_CSI_CONTROL, &val);
+       val |= PCI_CSI_CONTROL_PORTS_OFF_MASK;
+       pci_write_config_dword(pdev, PCI_CSI_CONTROL, val);
+
+       /*
+        * We lose config space access when punit power gates
+        * the ISP. Can't use pci_set_power_state() because
+        * pmcsr won't actually change when we write to it.
+        */
+       pci_save_state(pdev);
+       pdev->current_state = PCI_D3cold;
+       isp_set_power(pdev, false);
+
        return 0;
 }
 
 static int isp_pci_resume(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       isp_set_power(pdev, true);
+       pdev->current_state = PCI_D0;
+       pci_restore_state(pdev);
+
        return 0;
 }
 
@@ -99,6 +127,7 @@ static UNIVERSAL_DEV_PM_OPS(isp_pm_ops, isp_pci_suspend,
                            isp_pci_resume, NULL);
 
 static const struct pci_device_id isp_id_table[] = {
+       { PCI_VDEVICE(INTEL, 0x0f38), },
        { PCI_VDEVICE(INTEL, 0x22b8), },
        { 0, }
 };
index 464fe93657b53e03268eabb2f41f5cdd0583d96e..616b8853a91f8f8be7fa2d97f7fe9fc3b8106257 100644 (file)
@@ -168,8 +168,8 @@ static int cht_int33fe_probe(struct platform_device *pdev)
                board_info.dev_name = "max17047";
                board_info.properties = max17047_props;
                data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
-               if (!data->max17047)
-                       return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
+               if (IS_ERR(data->max17047))
+                       return PTR_ERR(data->max17047);
        }
 
        data->connections[0].endpoint[0] = "port0";
@@ -194,16 +194,20 @@ static int cht_int33fe_probe(struct platform_device *pdev)
        board_info.irq = fusb302_irq;
 
        data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
-       if (!data->fusb302)
+       if (IS_ERR(data->fusb302)) {
+               ret = PTR_ERR(data->fusb302);
                goto out_unregister_max17047;
+       }
 
        memset(&board_info, 0, sizeof(board_info));
        board_info.dev_name = "pi3usb30532";
        strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
 
        data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
-       if (!data->pi3usb30532)
+       if (IS_ERR(data->pi3usb30532)) {
+               ret = PTR_ERR(data->pi3usb30532);
                goto out_unregister_fusb302;
+       }
 
        platform_set_drvdata(pdev, data);
 
@@ -213,12 +217,11 @@ out_unregister_fusb302:
        i2c_unregister_device(data->fusb302);
 
 out_unregister_max17047:
-       if (data->max17047)
-               i2c_unregister_device(data->max17047);
+       i2c_unregister_device(data->max17047);
 
        device_connections_remove(data->connections);
 
-       return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
+       return ret;
 }
 
 static int cht_int33fe_remove(struct platform_device *pdev)
@@ -227,8 +230,7 @@ static int cht_int33fe_remove(struct platform_device *pdev)
 
        i2c_unregister_device(data->pi3usb30532);
        i2c_unregister_device(data->fusb302);
-       if (data->max17047)
-               i2c_unregister_device(data->max17047);
+       i2c_unregister_device(data->max17047);
 
        device_connections_remove(data->connections);
 
index 225638a1b09e45d762668615cc9de93a0db100ba..bffe548187eed329e5028b8eeaf20adb8e608507 100644 (file)
@@ -1210,13 +1210,7 @@ static void ips_debugfs_cleanup(struct ips_driver *ips) { return; }
 
 /* Expose current state and limits in debugfs if possible */
 
-struct ips_debugfs_node {
-       struct ips_driver *ips;
-       char *name;
-       int (*show)(struct seq_file *m, void *data);
-};
-
-static int show_cpu_temp(struct seq_file *m, void *data)
+static int cpu_temp_show(struct seq_file *m, void *data)
 {
        struct ips_driver *ips = m->private;
 
@@ -1225,8 +1219,9 @@ static int show_cpu_temp(struct seq_file *m, void *data)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(cpu_temp);
 
-static int show_cpu_power(struct seq_file *m, void *data)
+static int cpu_power_show(struct seq_file *m, void *data)
 {
        struct ips_driver *ips = m->private;
 
@@ -1234,8 +1229,9 @@ static int show_cpu_power(struct seq_file *m, void *data)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(cpu_power);
 
-static int show_cpu_clamp(struct seq_file *m, void *data)
+static int cpu_clamp_show(struct seq_file *m, void *data)
 {
        u64 turbo_override;
        int tdp, tdc;
@@ -1255,8 +1251,9 @@ static int show_cpu_clamp(struct seq_file *m, void *data)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(cpu_clamp);
 
-static int show_mch_temp(struct seq_file *m, void *data)
+static int mch_temp_show(struct seq_file *m, void *data)
 {
        struct ips_driver *ips = m->private;
 
@@ -1265,8 +1262,9 @@ static int show_mch_temp(struct seq_file *m, void *data)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(mch_temp);
 
-static int show_mch_power(struct seq_file *m, void *data)
+static int mch_power_show(struct seq_file *m, void *data)
 {
        struct ips_driver *ips = m->private;
 
@@ -1274,68 +1272,22 @@ static int show_mch_power(struct seq_file *m, void *data)
 
        return 0;
 }
-
-static struct ips_debugfs_node ips_debug_files[] = {
-       { NULL, "cpu_temp", show_cpu_temp },
-       { NULL, "cpu_power", show_cpu_power },
-       { NULL, "cpu_clamp", show_cpu_clamp },
-       { NULL, "mch_temp", show_mch_temp },
-       { NULL, "mch_power", show_mch_power },
-};
-
-static int ips_debugfs_open(struct inode *inode, struct file *file)
-{
-       struct ips_debugfs_node *node = inode->i_private;
-
-       return single_open(file, node->show, node->ips);
-}
-
-static const struct file_operations ips_debugfs_ops = {
-       .owner = THIS_MODULE,
-       .open = ips_debugfs_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mch_power);
 
 static void ips_debugfs_cleanup(struct ips_driver *ips)
 {
-       if (ips->debug_root)
-               debugfs_remove_recursive(ips->debug_root);
-       return;
+       debugfs_remove_recursive(ips->debug_root);
 }
 
 static void ips_debugfs_init(struct ips_driver *ips)
 {
-       int i;
-
        ips->debug_root = debugfs_create_dir("ips", NULL);
-       if (!ips->debug_root) {
-               dev_err(ips->dev, "failed to create debugfs entries: %ld\n",
-                       PTR_ERR(ips->debug_root));
-               return;
-       }
 
-       for (i = 0; i < ARRAY_SIZE(ips_debug_files); i++) {
-               struct dentry *ent;
-               struct ips_debugfs_node *node = &ips_debug_files[i];
-
-               node->ips = ips;
-               ent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
-                                         ips->debug_root, node,
-                                         &ips_debugfs_ops);
-               if (!ent) {
-                       dev_err(ips->dev, "failed to create debug file: %ld\n",
-                               PTR_ERR(ent));
-                       goto err_cleanup;
-               }
-       }
-
-       return;
-
-err_cleanup:
-       ips_debugfs_cleanup(ips);
-       return;
+       debugfs_create_file("cpu_temp", 0444, ips->debug_root, ips, &cpu_temp_fops);
+       debugfs_create_file("cpu_power", 0444, ips->debug_root, ips, &cpu_power_fops);
+       debugfs_create_file("cpu_clamp", 0444, ips->debug_root, ips, &cpu_clamp_fops);
+       debugfs_create_file("mch_temp", 0444, ips->debug_root, ips, &mch_temp_fops);
+       debugfs_create_file("mch_power", 0444, ips->debug_root, ips, &mch_power_fops);
 }
 #endif /* CONFIG_DEBUG_FS */
 
@@ -1646,9 +1598,6 @@ static void ips_remove(struct pci_dev *dev)
        struct ips_driver *ips = pci_get_drvdata(dev);
        u64 turbo_override;
 
-       if (!ips)
-               return;
-
        ips_debugfs_cleanup(ips);
 
        /* Release i915 driver */
index 6b31d410cb09abeb57aec266a7896c4dbbec1dc3..22dbf115782e312f3958b1567c0cb01c7062354d 100644 (file)
@@ -12,6 +12,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/acpi.h>
+#include <linux/bitfield.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -101,10 +102,35 @@ static const struct pmc_bit_map spt_pfear_map[] = {
        {},
 };
 
+static const struct pmc_bit_map spt_ltr_show_map[] = {
+       {"SOUTHPORT_A",         SPT_PMC_LTR_SPA},
+       {"SOUTHPORT_B",         SPT_PMC_LTR_SPB},
+       {"SATA",                SPT_PMC_LTR_SATA},
+       {"GIGABIT_ETHERNET",    SPT_PMC_LTR_GBE},
+       {"XHCI",                SPT_PMC_LTR_XHCI},
+       {"ME",                  SPT_PMC_LTR_ME},
+       /* EVA is Enterprise Value Add, doesn't really exist on PCH */
+       {"EVA",                 SPT_PMC_LTR_EVA},
+       {"SOUTHPORT_C",         SPT_PMC_LTR_SPC},
+       {"HD_AUDIO",            SPT_PMC_LTR_AZ},
+       {"LPSS",                SPT_PMC_LTR_LPSS},
+       {"SOUTHPORT_D",         SPT_PMC_LTR_SPD},
+       {"SOUTHPORT_E",         SPT_PMC_LTR_SPE},
+       {"CAMERA",              SPT_PMC_LTR_CAM},
+       {"ESPI",                SPT_PMC_LTR_ESPI},
+       {"SCC",                 SPT_PMC_LTR_SCC},
+       {"ISH",                 SPT_PMC_LTR_ISH},
+       /* Below two cannot be used for LTR_IGNORE */
+       {"CURRENT_PLATFORM",    SPT_PMC_LTR_CUR_PLT},
+       {"AGGREGATED_SYSTEM",   SPT_PMC_LTR_CUR_ASLT},
+       {}
+};
+
 static const struct pmc_reg_map spt_reg_map = {
        .pfear_sts = spt_pfear_map,
        .mphy_sts = spt_mphy_map,
        .pll_sts = spt_pll_map,
+       .ltr_show_sts = spt_ltr_show_map,
        .slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET,
        .ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET,
        .regmap_length = SPT_PMC_MMIO_REG_LEN,
@@ -112,6 +138,7 @@ static const struct pmc_reg_map spt_reg_map = {
        .ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES,
        .pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET,
        .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
+       .ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED,
 };
 
 /* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */
@@ -243,10 +270,38 @@ static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
        NULL,
 };
 
+static const struct pmc_bit_map cnp_ltr_show_map[] = {
+       {"SOUTHPORT_A",         CNP_PMC_LTR_SPA},
+       {"SOUTHPORT_B",         CNP_PMC_LTR_SPB},
+       {"SATA",                CNP_PMC_LTR_SATA},
+       {"GIGABIT_ETHERNET",    CNP_PMC_LTR_GBE},
+       {"XHCI",                CNP_PMC_LTR_XHCI},
+       {"ME",                  CNP_PMC_LTR_ME},
+       /* EVA is Enterprise Value Add, doesn't really exist on PCH */
+       {"EVA",                 CNP_PMC_LTR_EVA},
+       {"SOUTHPORT_C",         CNP_PMC_LTR_SPC},
+       {"HD_AUDIO",            CNP_PMC_LTR_AZ},
+       {"CNV",                 CNP_PMC_LTR_CNV},
+       {"LPSS",                CNP_PMC_LTR_LPSS},
+       {"SOUTHPORT_D",         CNP_PMC_LTR_SPD},
+       {"SOUTHPORT_E",         CNP_PMC_LTR_SPE},
+       {"CAMERA",              CNP_PMC_LTR_CAM},
+       {"ESPI",                CNP_PMC_LTR_ESPI},
+       {"SCC",                 CNP_PMC_LTR_SCC},
+       {"ISH",                 CNP_PMC_LTR_ISH},
+       {"UFSX2",               CNP_PMC_LTR_UFSX2},
+       {"EMMC",                CNP_PMC_LTR_EMMC},
+       /* Below two cannot be used for LTR_IGNORE */
+       {"CURRENT_PLATFORM",    CNP_PMC_LTR_CUR_PLT},
+       {"AGGREGATED_SYSTEM",   CNP_PMC_LTR_CUR_ASLT},
+       {}
+};
+
 static const struct pmc_reg_map cnp_reg_map = {
        .pfear_sts = cnp_pfear_map,
        .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
        .slps0_dbg_maps = cnp_slps0_dbg_maps,
+       .ltr_show_sts = cnp_ltr_show_map,
        .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
        .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
        .regmap_length = CNP_PMC_MMIO_REG_LEN,
@@ -254,6 +309,7 @@ static const struct pmc_reg_map cnp_reg_map = {
        .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
        .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
        .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+       .ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
 };
 
 static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
@@ -311,7 +367,7 @@ static void pmc_core_display_map(struct seq_file *s, int index,
                   pf_map[index].bit_mask & pf_reg ? "Off" : "On");
 }
 
-static int pmc_core_ppfear_sts_show(struct seq_file *s, void *unused)
+static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
 {
        struct pmc_dev *pmcdev = s->private;
        const struct pmc_bit_map *map = pmcdev->map->pfear_sts;
@@ -329,18 +385,7 @@ static int pmc_core_ppfear_sts_show(struct seq_file *s, void *unused)
 
        return 0;
 }
-
-static int pmc_core_ppfear_sts_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pmc_core_ppfear_sts_show, inode->i_private);
-}
-
-static const struct file_operations pmc_core_ppfear_ops = {
-       .open           = pmc_core_ppfear_sts_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_core_ppfear);
 
 /* This function should return link status, 0 means ready */
 static int pmc_core_mtpmc_link_status(void)
@@ -372,7 +417,7 @@ static int pmc_core_send_msg(u32 *addr_xram)
        return 0;
 }
 
-static int pmc_core_mphy_pg_sts_show(struct seq_file *s, void *unused)
+static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused)
 {
        struct pmc_dev *pmcdev = s->private;
        const struct pmc_bit_map *map = pmcdev->map->mphy_sts;
@@ -424,18 +469,7 @@ out_unlock:
        mutex_unlock(&pmcdev->lock);
        return err;
 }
-
-static int pmc_core_mphy_pg_sts_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pmc_core_mphy_pg_sts_show, inode->i_private);
-}
-
-static const struct file_operations pmc_core_mphy_pg_ops = {
-       .open           = pmc_core_mphy_pg_sts_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_core_mphy_pg);
 
 static int pmc_core_pll_show(struct seq_file *s, void *unused)
 {
@@ -471,18 +505,7 @@ out_unlock:
        mutex_unlock(&pmcdev->lock);
        return err;
 }
-
-static int pmc_core_pll_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pmc_core_pll_show, inode->i_private);
-}
-
-static const struct file_operations pmc_core_pll_ops = {
-       .open           = pmc_core_pll_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);
 
 static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user
 *userbuf, size_t count, loff_t *ppos)
@@ -500,7 +523,7 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user
                goto out_unlock;
        }
 
-       if (val > NUM_IP_IGN_ALLOWED) {
+       if (val > map->ltr_ignore_max) {
                err = -EINVAL;
                goto out_unlock;
        }
@@ -583,6 +606,77 @@ static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused)
 }
 DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg);
 
+static u32 convert_ltr_scale(u32 val)
+{
+       /*
+        * As per PCIE specification supporting document
+        * ECN_LatencyTolnReporting_14Aug08.pdf the Latency
+        * Tolerance Reporting data payload is encoded in a
+        * 3 bit scale and 10 bit value fields. Values are
+        * multiplied by the indicated scale to yield an absolute time
+        * value, expressible in a range from 1 nanosecond to
+        * 2^25*(2^10-1) = 34,326,183,936 nanoseconds.
+        *
+        * scale encoding is as follows:
+        *
+        * ----------------------------------------------
+        * |scale factor        |       Multiplier (ns) |
+        * ----------------------------------------------
+        * |    0               |       1               |
+        * |    1               |       32              |
+        * |    2               |       1024            |
+        * |    3               |       32768           |
+        * |    4               |       1048576         |
+        * |    5               |       33554432        |
+        * |    6               |       Invalid         |
+        * |    7               |       Invalid         |
+        * ----------------------------------------------
+        */
+       if (val > 5) {
+               pr_warn("Invalid LTR scale factor.\n");
+               return 0;
+       }
+
+       return 1U << (5 * val);
+}
+
+static int pmc_core_ltr_show(struct seq_file *s, void *unused)
+{
+       struct pmc_dev *pmcdev = s->private;
+       const struct pmc_bit_map *map = pmcdev->map->ltr_show_sts;
+       u64 decoded_snoop_ltr, decoded_non_snoop_ltr;
+       u32 ltr_raw_data, scale, val;
+       u16 snoop_ltr, nonsnoop_ltr;
+       int index;
+
+       for (index = 0; map[index].name ; index++) {
+               decoded_snoop_ltr = decoded_non_snoop_ltr = 0;
+               ltr_raw_data = pmc_core_reg_read(pmcdev,
+                                                map[index].bit_mask);
+               snoop_ltr = ltr_raw_data & ~MTPMC_MASK;
+               nonsnoop_ltr = (ltr_raw_data >> 0x10) & ~MTPMC_MASK;
+
+               if (FIELD_GET(LTR_REQ_NONSNOOP, ltr_raw_data)) {
+                       scale = FIELD_GET(LTR_DECODED_SCALE, nonsnoop_ltr);
+                       val = FIELD_GET(LTR_DECODED_VAL, nonsnoop_ltr);
+                       decoded_non_snoop_ltr = val * convert_ltr_scale(scale);
+               }
+
+               if (FIELD_GET(LTR_REQ_SNOOP, ltr_raw_data)) {
+                       scale = FIELD_GET(LTR_DECODED_SCALE, snoop_ltr);
+                       val = FIELD_GET(LTR_DECODED_VAL, snoop_ltr);
+                       decoded_snoop_ltr = val * convert_ltr_scale(scale);
+               }
+
+               seq_printf(s, "%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n",
+                          map[index].name, ltr_raw_data,
+                          decoded_non_snoop_ltr,
+                          decoded_snoop_ltr);
+       }
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr);
+
 static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
 {
        debugfs_remove_recursive(pmcdev->dbgfs_dir);
@@ -602,19 +696,21 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
                            &pmc_core_dev_state);
 
        debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
-                           &pmc_core_ppfear_ops);
+                           &pmc_core_ppfear_fops);
 
        debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
                            &pmc_core_ltr_ignore_ops);
 
+       debugfs_create_file("ltr_show", 0644, dir, pmcdev, &pmc_core_ltr_fops);
+
        if (pmcdev->map->pll_sts)
                debugfs_create_file("pll_status", 0444, dir, pmcdev,
-                                   &pmc_core_pll_ops);
+                                   &pmc_core_pll_fops);
 
        if (pmcdev->map->mphy_sts)
                debugfs_create_file("mphy_core_lanes_power_gating_status",
                                    0444, dir, pmcdev,
-                                   &pmc_core_mphy_pg_ops);
+                                   &pmc_core_mphy_pg_fops);
 
        if (pmcdev->map->slps0_dbg_maps) {
                debugfs_create_file("slp_s0_debug_status", 0444,
index be045348ad86b2674c3b08b3c1af54b3844ea339..89554cba575816f90fdfeda6a5cc8415911458cb 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef PMC_CORE_H
 #define PMC_CORE_H
 
+#include <linux/bits.h>
+
 #define PMC_BASE_ADDR_DEFAULT                  0xFE000000
 
 /* Sunrise Point Power Management Controller PCI Device ID */
 #define SPT_PMC_READ_DISABLE_BIT               0x16
 #define SPT_PMC_MSG_FULL_STS_BIT               0x18
 #define NUM_RETRIES                            100
-#define NUM_IP_IGN_ALLOWED                     17
+#define SPT_NUM_IP_IGN_ALLOWED                 17
+
+#define SPT_PMC_LTR_CUR_PLT                    0x350
+#define SPT_PMC_LTR_CUR_ASLT                   0x354
+#define SPT_PMC_LTR_SPA                                0x360
+#define SPT_PMC_LTR_SPB                                0x364
+#define SPT_PMC_LTR_SATA                       0x368
+#define SPT_PMC_LTR_GBE                                0x36C
+#define SPT_PMC_LTR_XHCI                       0x370
+#define SPT_PMC_LTR_ME                         0x378
+#define SPT_PMC_LTR_EVA                                0x37C
+#define SPT_PMC_LTR_SPC                                0x380
+#define SPT_PMC_LTR_AZ                         0x384
+#define SPT_PMC_LTR_LPSS                       0x38C
+#define SPT_PMC_LTR_CAM                                0x390
+#define SPT_PMC_LTR_SPD                                0x394
+#define SPT_PMC_LTR_SPE                                0x398
+#define SPT_PMC_LTR_ESPI                       0x39C
+#define SPT_PMC_LTR_SCC                                0x3A0
+#define SPT_PMC_LTR_ISH                                0x3A4
 
 /* Sunrise Point: PGD PFET Enable Ack Status Registers */
 enum ppfear_regs {
@@ -115,18 +136,46 @@ enum ppfear_regs {
 #define SPT_PMC_BIT_MPHY_CMN_LANE3             BIT(3)
 
 /* Cannonlake Power Management Controller register offsets */
-#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET      0x193C
-#define CNP_PMC_LTR_IGNORE_OFFSET              0x1B0C
-#define CNP_PMC_PM_CFG_OFFSET                  0x1818
 #define CNP_PMC_SLPS0_DBG_OFFSET               0x10B4
+#define CNP_PMC_PM_CFG_OFFSET                  0x1818
+#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET      0x193C
+#define CNP_PMC_LTR_IGNORE_OFFSET              0x1B0C
 /* Cannonlake: PGD PFET Enable Ack Status Register(s) start */
-#define CNP_PMC_HOST_PPFEAR0A                  0x1D90
+#define CNP_PMC_HOST_PPFEAR0A                  0x1D90
 
-#define CNP_PMC_MMIO_REG_LEN                   0x2000
-#define CNP_PPFEAR_NUM_ENTRIES                 8
-#define CNP_PMC_READ_DISABLE_BIT               22
 #define CNP_PMC_LATCH_SLPS0_EVENTS             BIT(31)
 
+#define CNP_PMC_MMIO_REG_LEN                   0x2000
+#define CNP_PPFEAR_NUM_ENTRIES                 8
+#define CNP_PMC_READ_DISABLE_BIT               22
+#define CNP_NUM_IP_IGN_ALLOWED                 19
+#define CNP_PMC_LTR_CUR_PLT                    0x1B50
+#define CNP_PMC_LTR_CUR_ASLT                   0x1B54
+#define CNP_PMC_LTR_SPA                                0x1B60
+#define CNP_PMC_LTR_SPB                                0x1B64
+#define CNP_PMC_LTR_SATA                       0x1B68
+#define CNP_PMC_LTR_GBE                                0x1B6C
+#define CNP_PMC_LTR_XHCI                       0x1B70
+#define CNP_PMC_LTR_ME                         0x1B78
+#define CNP_PMC_LTR_EVA                                0x1B7C
+#define CNP_PMC_LTR_SPC                                0x1B80
+#define CNP_PMC_LTR_AZ                         0x1B84
+#define CNP_PMC_LTR_LPSS                       0x1B8C
+#define CNP_PMC_LTR_CAM                                0x1B90
+#define CNP_PMC_LTR_SPD                                0x1B94
+#define CNP_PMC_LTR_SPE                                0x1B98
+#define CNP_PMC_LTR_ESPI                       0x1B9C
+#define CNP_PMC_LTR_SCC                                0x1BA0
+#define CNP_PMC_LTR_ISH                                0x1BA4
+#define CNP_PMC_LTR_CNV                                0x1BF0
+#define CNP_PMC_LTR_EMMC                       0x1BF4
+#define CNP_PMC_LTR_UFSX2                      0x1BF8
+
+#define LTR_DECODED_VAL                                GENMASK(9, 0)
+#define LTR_DECODED_SCALE                      GENMASK(12, 10)
+#define LTR_REQ_SNOOP                          BIT(15)
+#define LTR_REQ_NONSNOOP                       BIT(31)
+
 struct pmc_bit_map {
        const char *name;
        u32 bit_mask;
@@ -139,6 +188,7 @@ struct pmc_bit_map {
  * @mphy_sts:          Maps name of MPHY lane to MPHY status lane status bit
  * @pll_sts:           Maps name of PLL to corresponding bit status
  * @slps0_dbg_maps:    Array of SLP_S0_DBG* registers containing debug info
+ * @ltr_show_sts:      Maps PCH IP Names to their MMIO register offsets
  * @slp_s0_offset:     PWRMBASE offset to read SLP_S0 residency
  * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
  * @regmap_length:     Length of memory to map from PWRMBASE address to access
@@ -157,6 +207,7 @@ struct pmc_reg_map {
        const struct pmc_bit_map *mphy_sts;
        const struct pmc_bit_map *pll_sts;
        const struct pmc_bit_map **slps0_dbg_maps;
+       const struct pmc_bit_map *ltr_show_sts;
        const u32 slp_s0_offset;
        const u32 ltr_ignore_offset;
        const int regmap_length;
@@ -165,6 +216,7 @@ struct pmc_reg_map {
        const u32 pm_cfg_offset;
        const int pm_read_disable_bit;
        const u32 slps0_dbg_offset;
+       const u32 ltr_ignore_max;
 };
 
 /**
index 40bce560eb30d9cf2ca1a348d7b1eece30d00616..98ba9185a27b7c44d61b8e7b18f5a1ae387a0350 100644 (file)
@@ -466,17 +466,7 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int telem_pss_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, telem_pss_states_show, inode->i_private);
-}
-
-static const struct file_operations telem_pss_ops = {
-       .open           = telem_pss_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(telem_pss_states);
 
 static int telem_ioss_states_show(struct seq_file *s, void *unused)
 {
@@ -505,17 +495,7 @@ static int telem_ioss_states_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int telem_ioss_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, telem_ioss_states_show, inode->i_private);
-}
-
-static const struct file_operations telem_ioss_ops = {
-       .open           = telem_ioss_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(telem_ioss_states);
 
 static int telem_soc_states_show(struct seq_file *s, void *unused)
 {
@@ -664,17 +644,7 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int telem_soc_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, telem_soc_states_show, inode->i_private);
-}
-
-static const struct file_operations telem_socstate_ops = {
-       .open           = telem_soc_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(telem_soc_states);
 
 static int telem_s0ix_res_get(void *data, u64 *val)
 {
@@ -960,7 +930,7 @@ static int __init telemetry_debugfs_init(void)
 
        f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO,
                                debugfs_conf->telemetry_dbg_dir, NULL,
-                               &telem_pss_ops);
+                               &telem_pss_states_fops);
        if (!f) {
                pr_err("pss_sample_info debugfs register failed\n");
                goto out;
@@ -968,7 +938,7 @@ static int __init telemetry_debugfs_init(void)
 
        f = debugfs_create_file("ioss_info", S_IFREG | S_IRUGO,
                                debugfs_conf->telemetry_dbg_dir, NULL,
-                               &telem_ioss_ops);
+                               &telem_ioss_states_fops);
        if (!f) {
                pr_err("ioss_sample_info debugfs register failed\n");
                goto out;
@@ -976,7 +946,7 @@ static int __init telemetry_debugfs_init(void)
 
        f = debugfs_create_file("soc_states", S_IFREG | S_IRUGO,
                                debugfs_conf->telemetry_dbg_dir,
-                               NULL, &telem_socstate_ops);
+                               NULL, &telem_soc_states_fops);
        if (!f) {
                pr_err("ioss_sample_info debugfs register failed\n");
                goto out;
index c2c3a1a19879596bd905952a9e028e96ea7cba01..df3fcd36776a99a4f5ed929060fdfba00cfa6f42 100644 (file)
@@ -1,34 +1,9 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
 /*
- * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
+ * Mellanox platform driver
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * Copyright (C) 2016-2018 Mellanox Technologies
+ * Copyright (C) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
  */
 
 #include <linux/device.h>
 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
 #define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET  0x00
 #define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET  0x01
+#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET  0x02
 #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET        0x1d
+#define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e
+#define MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET 0x1f
 #define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET       0x20
 #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET       0x21
 #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET       0x22
 #define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET     0xe7
 #define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET     0xe8
 #define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET     0xe9
-#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET     0xea
-#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET     0xeb
-#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET     0xec
-#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET    0xed
-#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET    0xee
-#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET    0xef
+#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET     0xeb
+#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET     0xec
+#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET     0xed
+#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET    0xee
+#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET    0xef
+#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET    0xf0
 #define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
@@ -1101,6 +1079,118 @@ static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = {
                .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data),
 };
 
+/* Platform register access for next generation systems families data */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
+       {
+               .label = "cpld1_version",
+               .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET,
+               .bit = GENMASK(7, 0),
+               .mode = 0444,
+       },
+       {
+               .label = "cpld2_version",
+               .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET,
+               .bit = GENMASK(7, 0),
+               .mode = 0444,
+       },
+       {
+               .label = "cpld3_version",
+               .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET,
+               .bit = GENMASK(7, 0),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_long_pb",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(0),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_short_pb",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(1),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_aux_pwr_or_ref",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(2),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_from_comex",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(4),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_asic_thermal",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(7),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_comex_pwr_fail",
+               .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(3),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_voltmon_upgrade_fail",
+               .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(0),
+               .mode = 0444,
+       },
+       {
+               .label = "reset_system",
+               .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(1),
+               .mode = 0444,
+       },
+       {
+               .label = "psu1_on",
+               .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(0),
+               .mode = 0200,
+       },
+       {
+               .label = "psu2_on",
+               .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(1),
+               .mode = 0200,
+       },
+       {
+               .label = "pwr_cycle",
+               .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(2),
+               .mode = 0200,
+       },
+       {
+               .label = "pwr_down",
+               .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(3),
+               .mode = 0200,
+       },
+       {
+               .label = "jtag_enable",
+               .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(4),
+               .mode = 0644,
+       },
+       {
+               .label = "asic_health",
+               .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
+               .mask = MLXPLAT_CPLD_ASIC_MASK,
+               .bit = 1,
+               .mode = 0444,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = {
+               .data = mlxplat_mlxcpld_default_ng_regs_io_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_regs_io_data),
+};
+
 /* Platform FAN default */
 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
        {
@@ -1208,7 +1298,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
        switch (reg) {
        case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
@@ -1258,7 +1351,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
        switch (reg) {
        case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
@@ -1421,7 +1517,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
-       mlxplat_led = &mlxplat_default_ng_led_data;
+       mlxplat_led = &mlxplat_msn21xx_led_data;
        mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
 
        return 1;
@@ -1439,7 +1535,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
-       mlxplat_led = &mlxplat_msn21xx_led_data;
+       mlxplat_led = &mlxplat_default_ng_led_data;
+       mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
        mlxplat_fan = &mlxplat_default_fan_data;
 
        return 1;
@@ -1499,21 +1596,21 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
                .callback = mlxplat_dmi_qmb7xx_matched,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MQM87"),
                },
        },
        {
                .callback = mlxplat_dmi_qmb7xx_matched,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"),
                },
        },
        {
                .callback = mlxplat_dmi_qmb7xx_matched,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN34"),
                },
        },
        {
index fde08a997557fed3aeef16b3729ef1b8c85efe75..726341f2b638636c4672c4a9ff9be7cb0003cc5d 100644 (file)
@@ -81,7 +81,6 @@
 #include <linux/acpi.h>
 #include <linux/pci_ids.h>
 #include <linux/power_supply.h>
-#include <linux/thinkpad_acpi.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
@@ -478,6 +477,12 @@ do {                                                                       \
          .ec = TPACPI_MATCH_ANY,               \
          .quirks = (__quirk) }
 
+#define TPACPI_QEC_IBM(__id1, __id2, __quirk)  \
+       { .vendor = PCI_VENDOR_ID_IBM,          \
+         .bios = TPACPI_MATCH_ANY,             \
+         .ec = TPID(__id1, __id2),             \
+         .quirks = (__quirk) }
+
 #define TPACPI_QEC_LNV(__id1, __id2, __quirk)  \
        { .vendor = PCI_VENDOR_ID_LENOVO,       \
          .bios = TPACPI_MATCH_ANY,             \
@@ -3457,7 +3462,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN,
 
-               KEY_FAVORITES,       /* Favorite app, 0x311 */
+               KEY_BOOKMARKS,       /* Favorite app, 0x311 */
                KEY_RESERVED,        /* Clipping tool */
                KEY_CALC,            /* Calculator (above numpad, P52) */
                KEY_BLUETOOTH,       /* Bluetooth */
@@ -5973,9 +5978,6 @@ static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
        },
 };
 
-#undef TPACPI_LEDQ_IBM
-#undef TPACPI_LEDQ_LNV
-
 static enum led_access_mode __init led_init_detect_mode(void)
 {
        acpi_status status;
@@ -8710,40 +8712,18 @@ static const struct attribute_group fan_attr_group = {
        .attrs = fan_attributes,
 };
 
-#define        TPACPI_FAN_Q1   0x0001          /* Unitialized HFSP */
+#define TPACPI_FAN_Q1  0x0001          /* Unitialized HFSP */
 #define TPACPI_FAN_2FAN        0x0002          /* EC 0x31 bit 0 selects fan2 */
 
-#define TPACPI_FAN_QI(__id1, __id2, __quirks)  \
-       { .vendor = PCI_VENDOR_ID_IBM,          \
-         .bios = TPACPI_MATCH_ANY,             \
-         .ec = TPID(__id1, __id2),             \
-         .quirks = __quirks }
-
-#define TPACPI_FAN_QL(__id1, __id2, __quirks)  \
-       { .vendor = PCI_VENDOR_ID_LENOVO,       \
-         .bios = TPACPI_MATCH_ANY,             \
-         .ec = TPID(__id1, __id2),             \
-         .quirks = __quirks }
-
-#define TPACPI_FAN_QB(__id1, __id2, __quirks)  \
-       { .vendor = PCI_VENDOR_ID_LENOVO,       \
-         .bios = TPID(__id1, __id2),           \
-         .ec = TPACPI_MATCH_ANY,               \
-         .quirks = __quirks }
-
 static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
-       TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1),
-       TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1),
-       TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1),
-       TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1),
-       TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN),
-       TPACPI_FAN_QB('N', '1', TPACPI_FAN_2FAN),
+       TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
+       TPACPI_QEC_IBM('7', '8', TPACPI_FAN_Q1),
+       TPACPI_QEC_IBM('7', '6', TPACPI_FAN_Q1),
+       TPACPI_QEC_IBM('7', '0', TPACPI_FAN_Q1),
+       TPACPI_QEC_LNV('7', 'M', TPACPI_FAN_2FAN),
+       TPACPI_Q_LNV('N', '1', TPACPI_FAN_2FAN),
 };
 
-#undef TPACPI_FAN_QL
-#undef TPACPI_FAN_QI
-#undef TPACPI_FAN_QB
-
 static int __init fan_init(struct ibm_init_struct *iibm)
 {
        int rc;
@@ -9150,6 +9130,7 @@ static struct ibm_struct fan_driver_data = {
  * Mute LED subdriver
  */
 
+#define TPACPI_LED_MAX         2
 
 struct tp_led_table {
        acpi_string name;
@@ -9158,13 +9139,13 @@ struct tp_led_table {
        int state;
 };
 
-static struct tp_led_table led_tables[] = {
-       [TPACPI_LED_MUTE] = {
+static struct tp_led_table led_tables[TPACPI_LED_MAX] = {
+       [LED_AUDIO_MUTE] = {
                .name = "SSMS",
                .on_value = 1,
                .off_value = 0,
        },
-       [TPACPI_LED_MICMUTE] = {
+       [LED_AUDIO_MICMUTE] = {
                .name = "MMTS",
                .on_value = 2,
                .off_value = 0,
@@ -9189,31 +9170,64 @@ static int mute_led_on_off(struct tp_led_table *t, bool state)
        return state;
 }
 
-int tpacpi_led_set(int whichled, bool on)
+static int tpacpi_led_set(int whichled, bool on)
 {
        struct tp_led_table *t;
 
-       if (whichled < 0 || whichled >= TPACPI_LED_MAX)
-               return -EINVAL;
-
        t = &led_tables[whichled];
        if (t->state < 0 || t->state == on)
                return t->state;
        return mute_led_on_off(t, on);
 }
-EXPORT_SYMBOL_GPL(tpacpi_led_set);
+
+static int tpacpi_led_mute_set(struct led_classdev *led_cdev,
+                              enum led_brightness brightness)
+{
+       return tpacpi_led_set(LED_AUDIO_MUTE, brightness != LED_OFF);
+}
+
+static int tpacpi_led_micmute_set(struct led_classdev *led_cdev,
+                                 enum led_brightness brightness)
+{
+       return tpacpi_led_set(LED_AUDIO_MICMUTE, brightness != LED_OFF);
+}
+
+static struct led_classdev mute_led_cdev[TPACPI_LED_MAX] = {
+       [LED_AUDIO_MUTE] = {
+               .name           = "platform::mute",
+               .max_brightness = 1,
+               .brightness_set_blocking = tpacpi_led_mute_set,
+               .default_trigger = "audio-mute",
+       },
+       [LED_AUDIO_MICMUTE] = {
+               .name           = "platform::micmute",
+               .max_brightness = 1,
+               .brightness_set_blocking = tpacpi_led_micmute_set,
+               .default_trigger = "audio-micmute",
+       },
+};
 
 static int mute_led_init(struct ibm_init_struct *iibm)
 {
        acpi_handle temp;
-       int i;
+       int i, err;
 
        for (i = 0; i < TPACPI_LED_MAX; i++) {
                struct tp_led_table *t = &led_tables[i];
-               if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp)))
-                       mute_led_on_off(t, false);
-               else
+               if (ACPI_FAILURE(acpi_get_handle(hkey_handle, t->name, &temp))) {
                        t->state = -ENODEV;
+                       continue;
+               }
+
+               mute_led_cdev[i].brightness = ledtrig_audio_get(i);
+               err = led_classdev_register(&tpacpi_pdev->dev, &mute_led_cdev[i]);
+               if (err < 0) {
+                       while (i--) {
+                               if (led_tables[i].state >= 0)
+                                       led_classdev_unregister(&mute_led_cdev[i]);
+                       }
+                       return err;
+               }
        }
        return 0;
 }
@@ -9222,8 +9236,12 @@ static void mute_led_exit(void)
 {
        int i;
 
-       for (i = 0; i < TPACPI_LED_MAX; i++)
-               tpacpi_led_set(i, false);
+       for (i = 0; i < TPACPI_LED_MAX; i++) {
+               if (led_tables[i].state >= 0) {
+                       led_classdev_unregister(&mute_led_cdev[i]);
+                       tpacpi_led_set(i, false);
+               }
+       }
 }
 
 static void mute_led_resume(void)
index 5f2d7ea912b56e89beb0fa75f8d502e1ef3e9f99..8c5d47c0aea6521a0164d599e351ee1b0fcbe21e 100644 (file)
@@ -614,6 +614,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
                },
        },
+       {
+               /* Mediacom Flexbook Edge 11 (same hw as TS Primebook C11) */
+               .driver_data = (void *)&trekstor_primebook_c11_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
+               },
+       },
        {
                /* Onda oBook 20 Plus */
                .driver_data = (void *)&onda_obook_20_plus_data,
index 1360a7fa542c5dca0a79c4b611f2518e5af556f4..c96c01e097407da55c3a7981dfbefe1462c85366 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * OMAP SmartReflex Voltage Control
  *
  *
  * Copyright (C) 2007 Texas Instruments, Inc.
  * Lesly A M <x0080970@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/module.h>
@@ -37,7 +34,6 @@
 static LIST_HEAD(sr_list);
 
 static struct omap_sr_class_data *sr_class;
-static struct omap_sr_pmic_data *sr_pmic_data;
 static struct dentry           *sr_dbg_dir;
 
 static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
@@ -780,25 +776,6 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
        sr_class->disable(sr, 1);
 }
 
-/**
- * omap_sr_register_pmic() - API to register pmic specific info.
- * @pmic_data: The structure containing pmic specific data.
- *
- * This API is to be called from the PMIC specific code to register with
- * smartreflex driver pmic specific info. Currently the only info required
- * is the smartreflex init on the PMIC side.
- */
-void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
-{
-       if (!pmic_data) {
-               pr_warn("%s: Trying to register NULL PMIC data structure with smartreflex\n",
-                       __func__);
-               return;
-       }
-
-       sr_pmic_data = pmic_data;
-}
-
 /* PM Debug FS entries to enable and disable smartreflex. */
 static int omap_sr_autocomp_show(void *data, u64 *val)
 {
@@ -1010,8 +987,7 @@ static int omap_sr_remove(struct platform_device *pdev)
 
        if (sr_info->autocomp_active)
                sr_stop_vddautocomp(sr_info);
-       if (sr_info->dbg_dir)
-               debugfs_remove_recursive(sr_info->dbg_dir);
+       debugfs_remove_recursive(sr_info->dbg_dir);
 
        pm_runtime_disable(&pdev->dev);
        list_del(&sr_info->node);
@@ -1065,17 +1041,6 @@ static int __init sr_init(void)
 {
        int ret = 0;
 
-       /*
-        * sr_init is a late init. If by then a pmic specific API is not
-        * registered either there is no need for anything to be done on
-        * the PMIC side or somebody has forgotten to register a PMIC
-        * handler. Warn for the second condition.
-        */
-       if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
-               sr_pmic_data->sr_pmic_init();
-       else
-               pr_warn("%s: No PMIC hook to init smartreflex\n", __func__);
-
        ret = platform_driver_register(&smartreflex_driver);
        if (ret) {
                pr_err("%s: platform driver register failed for SR\n",
index 27e5dd47a01f9564fdff4c172be76b9694223e7e..a8f47df0655a6f1a7112aba36b375fd18ccbe6b6 100644 (file)
@@ -88,7 +88,9 @@ config PWM_BCM_IPROC
 
 config PWM_BCM_KONA
        tristate "Kona PWM support"
-       depends on ARCH_BCM_MOBILE
+       depends on ARCH_BCM_MOBILE || ARCH_BCM_CYGNUS || COMPILE_TEST
+       depends on HAVE_CLK && HAS_IOMEM
+       default ARCH_BCM_MOBILE || ARCH_BCM_CYGNUS
        help
          Generic PWM framework driver for Broadcom Kona PWM block.
 
index db001cba937fd8617fc81720e21c30601f2bfec5..5652f461d9941f9f69b096c59ce368eb5a4f560f 100644 (file)
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright 2014 Bart Tanghe <bart.tanghe@thomasmore.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2.
  */
 
 #include <linux/clk.h>
index 26ec24e457b12414cb9ca3a7cbe049f8a49f70e9..924d39a797cf762f33586fa114c7310e78e01a3d 100644 (file)
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Cirrus Logic CLPS711X PWM driver
- *
- * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
+ * Author: Alexander Shiyan <shc_work@mail.ru>
  */
 
 #include <linux/clk.h>
@@ -48,7 +43,7 @@ static void clps711x_pwm_update_val(struct clps711x_chip *priv, u32 n, u32 v)
 static unsigned int clps711x_get_duty(struct pwm_device *pwm, unsigned int v)
 {
        /* Duty cycle 0..15 max */
-       return DIV_ROUND_CLOSEST(v * 0xf, pwm_get_period(pwm));
+       return DIV_ROUND_CLOSEST(v * 0xf, pwm->args.period);
 }
 
 static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -71,7 +66,7 @@ static int clps711x_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        struct clps711x_chip *priv = to_clps711x_chip(chip);
        unsigned int duty;
 
-       if (period_ns != pwm_get_period(pwm))
+       if (period_ns != pwm->args.period)
                return -EINVAL;
 
        duty = clps711x_get_duty(pwm, duty_ns);
index 1d5242c9cde084a29a393154158ef9629cdd7499..55a3a363d5be94708b48bbc08ce792d1a81a62f0 100644 (file)
@@ -5,17 +5,19 @@
  * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/io.h>
-#include <linux/pwm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
 
 /* i.MX1 and i.MX21 share the same PWM function block: */
 
@@ -23,7 +25,7 @@
 #define MX1_PWMS                       0x04   /* PWM Sample Register */
 #define MX1_PWMP                       0x08   /* PWM Period Register */
 
-#define MX1_PWMC_EN                    (1 << 4)
+#define MX1_PWMC_EN                    BIT(4)
 
 /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
 
 #define MX3_PWMSR                      0x04    /* PWM Status Register */
 #define MX3_PWMSAR                     0x0C    /* PWM Sample Register */
 #define MX3_PWMPR                      0x10    /* PWM Period Register */
-#define MX3_PWMCR_PRESCALER(x)         ((((x) - 1) & 0xFFF) << 4)
-#define MX3_PWMCR_STOPEN               (1 << 25)
-#define MX3_PWMCR_DOZEEN               (1 << 24)
-#define MX3_PWMCR_WAITEN               (1 << 23)
-#define MX3_PWMCR_DBGEN                        (1 << 22)
-#define MX3_PWMCR_POUTC                        (1 << 18)
-#define MX3_PWMCR_CLKSRC_IPG_HIGH      (2 << 16)
-#define MX3_PWMCR_CLKSRC_IPG           (1 << 16)
-#define MX3_PWMCR_SWR                  (1 << 3)
-#define MX3_PWMCR_EN                   (1 << 0)
-#define MX3_PWMSR_FIFOAV_4WORDS                0x4
-#define MX3_PWMSR_FIFOAV_MASK          0x7
+
+#define MX3_PWMCR_FWM                  GENMASK(27, 26)
+#define MX3_PWMCR_STOPEN               BIT(25)
+#define MX3_PWMCR_DOZEN                        BIT(24)
+#define MX3_PWMCR_WAITEN               BIT(23)
+#define MX3_PWMCR_DBGEN                        BIT(22)
+#define MX3_PWMCR_BCTR                 BIT(21)
+#define MX3_PWMCR_HCTR                 BIT(20)
+
+#define MX3_PWMCR_POUTC                        GENMASK(19, 18)
+#define MX3_PWMCR_POUTC_NORMAL         0
+#define MX3_PWMCR_POUTC_INVERTED       1
+#define MX3_PWMCR_POUTC_OFF            2
+
+#define MX3_PWMCR_CLKSRC               GENMASK(17, 16)
+#define MX3_PWMCR_CLKSRC_OFF           0
+#define MX3_PWMCR_CLKSRC_IPG           1
+#define MX3_PWMCR_CLKSRC_IPG_HIGH      2
+#define MX3_PWMCR_CLKSRC_IPG_32K       3
+
+#define MX3_PWMCR_PRESCALER            GENMASK(15, 4)
+
+#define MX3_PWMCR_SWR                  BIT(3)
+
+#define MX3_PWMCR_REPEAT               GENMASK(2, 1)
+#define MX3_PWMCR_REPEAT_1X            0
+#define MX3_PWMCR_REPEAT_2X            1
+#define MX3_PWMCR_REPEAT_4X            2
+#define MX3_PWMCR_REPEAT_8X            3
+
+#define MX3_PWMCR_EN                   BIT(0)
+
+#define MX3_PWMSR_FWE                  BIT(6)
+#define MX3_PWMSR_CMP                  BIT(5)
+#define MX3_PWMSR_ROV                  BIT(4)
+#define MX3_PWMSR_FE                   BIT(3)
+
+#define MX3_PWMSR_FIFOAV               GENMASK(2, 0)
+#define MX3_PWMSR_FIFOAV_EMPTY         0
+#define MX3_PWMSR_FIFOAV_1WORD         1
+#define MX3_PWMSR_FIFOAV_2WORDS                2
+#define MX3_PWMSR_FIFOAV_3WORDS                3
+#define MX3_PWMSR_FIFOAV_4WORDS                4
+
+#define MX3_PWMCR_PRESCALER_SET(x)     FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1)
+#define MX3_PWMCR_PRESCALER_GET(x)     (FIELD_GET(MX3_PWMCR_PRESCALER, \
+                                                  (x)) + 1)
 
 #define MX3_PWM_SWR_LOOP               5
 
+/* PWMPR register value of 0xffff has the same effect as 0xfffe */
+#define MX3_PWMPR_MAX                  0xfffe
+
 struct imx_chip {
+       struct clk      *clk_ipg;
+
        struct clk      *clk_per;
 
        void __iomem    *mmio_base;
@@ -56,6 +98,87 @@ struct imx_chip {
 
 #define to_imx_chip(chip)      container_of(chip, struct imx_chip, chip)
 
+static int imx_pwm_clk_prepare_enable(struct pwm_chip *chip)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       int ret;
+
+       ret = clk_prepare_enable(imx->clk_ipg);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(imx->clk_per);
+       if (ret) {
+               clk_disable_unprepare(imx->clk_ipg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void imx_pwm_clk_disable_unprepare(struct pwm_chip *chip)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+
+       clk_disable_unprepare(imx->clk_per);
+       clk_disable_unprepare(imx->clk_ipg);
+}
+
+static void imx_pwm_get_state(struct pwm_chip *chip,
+               struct pwm_device *pwm, struct pwm_state *state)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       u32 period, prescaler, pwm_clk, ret, val;
+       u64 tmp;
+
+       ret = imx_pwm_clk_prepare_enable(chip);
+       if (ret < 0)
+               return;
+
+       val = readl(imx->mmio_base + MX3_PWMCR);
+
+       if (val & MX3_PWMCR_EN) {
+               state->enabled = true;
+               ret = imx_pwm_clk_prepare_enable(chip);
+               if (ret)
+                       return;
+       } else {
+               state->enabled = false;
+       }
+
+       switch (FIELD_GET(MX3_PWMCR_POUTC, val)) {
+       case MX3_PWMCR_POUTC_NORMAL:
+               state->polarity = PWM_POLARITY_NORMAL;
+               break;
+       case MX3_PWMCR_POUTC_INVERTED:
+               state->polarity = PWM_POLARITY_INVERSED;
+               break;
+       default:
+               dev_warn(chip->dev, "can't set polarity, output disconnected");
+       }
+
+       prescaler = MX3_PWMCR_PRESCALER_GET(val);
+       pwm_clk = clk_get_rate(imx->clk_per);
+       pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler);
+       val = readl(imx->mmio_base + MX3_PWMPR);
+       period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
+
+       /* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */
+       tmp = NSEC_PER_SEC * (u64)(period + 2);
+       state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
+
+       /* PWMSAR can be read only if PWM is enabled */
+       if (state->enabled) {
+               val = readl(imx->mmio_base + MX3_PWMSAR);
+               tmp = NSEC_PER_SEC * (u64)(val);
+               state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
+       } else {
+               state->duty_cycle = 0;
+       }
+
+       imx_pwm_clk_disable_unprepare(chip);
+}
+
 static int imx_pwm_config_v1(struct pwm_chip *chip,
                struct pwm_device *pwm, int duty_ns, int period_ns)
 {
@@ -91,7 +214,7 @@ static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
        u32 val;
        int ret;
 
-       ret = clk_prepare_enable(imx->clk_per);
+       ret = imx_pwm_clk_prepare_enable(chip);
        if (ret < 0)
                return ret;
 
@@ -111,7 +234,7 @@ static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
        val &= ~MX1_PWMC_EN;
        writel(val, imx->mmio_base + MX1_PWMC);
 
-       clk_disable_unprepare(imx->clk_per);
+       imx_pwm_clk_disable_unprepare(chip);
 }
 
 static void imx_pwm_sw_reset(struct pwm_chip *chip)
@@ -142,14 +265,14 @@ static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip,
        u32 sr;
 
        sr = readl(imx->mmio_base + MX3_PWMSR);
-       fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
+       fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr);
        if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
                period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
                                         NSEC_PER_MSEC);
                msleep(period_ms);
 
                sr = readl(imx->mmio_base + MX3_PWMSR);
-               if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK))
+               if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr))
                        dev_warn(dev, "there is no free FIFO slot\n");
        }
 }
@@ -197,7 +320,7 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
                if (cstate.enabled) {
                        imx_pwm_wait_fifo_slot(chip, pwm);
                } else {
-                       ret = clk_prepare_enable(imx->clk_per);
+                       ret = imx_pwm_clk_prepare_enable(chip);
                        if (ret)
                                return ret;
 
@@ -207,19 +330,20 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
                writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
                writel(period_cycles, imx->mmio_base + MX3_PWMPR);
 
-               cr = MX3_PWMCR_PRESCALER(prescale) |
-                    MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
-                    MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH |
-                    MX3_PWMCR_EN;
+               cr = MX3_PWMCR_PRESCALER_SET(prescale) |
+                    MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
+                    FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
+                    MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
 
                if (state->polarity == PWM_POLARITY_INVERSED)
-                       cr |= MX3_PWMCR_POUTC;
+                       cr |= FIELD_PREP(MX3_PWMCR_POUTC,
+                                       MX3_PWMCR_POUTC_INVERTED);
 
                writel(cr, imx->mmio_base + MX3_PWMCR);
        } else if (cstate.enabled) {
                writel(0, imx->mmio_base + MX3_PWMCR);
 
-               clk_disable_unprepare(imx->clk_per);
+               imx_pwm_clk_disable_unprepare(chip);
        }
 
        return 0;
@@ -234,6 +358,7 @@ static const struct pwm_ops imx_pwm_ops_v1 = {
 
 static const struct pwm_ops imx_pwm_ops_v2 = {
        .apply = imx_pwm_apply_v2,
+       .get_state = imx_pwm_get_state,
        .owner = THIS_MODULE,
 };
 
@@ -276,6 +401,13 @@ static int imx_pwm_probe(struct platform_device *pdev)
        if (imx == NULL)
                return -ENOMEM;
 
+       imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(imx->clk_ipg)) {
+               dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
+                               PTR_ERR(imx->clk_ipg));
+               return PTR_ERR(imx->clk_ipg);
+       }
+
        imx->clk_per = devm_clk_get(&pdev->dev, "per");
        if (IS_ERR(imx->clk_per)) {
                dev_err(&pdev->dev, "getting per clock failed with %ld\n",
@@ -315,6 +447,8 @@ static int imx_pwm_remove(struct platform_device *pdev)
        if (imx == NULL)
                return -ENODEV;
 
+       imx_pwm_clk_disable_unprepare(&imx->chip);
+
        return pwmchip_remove(&imx->chip);
 }
 
index d7f5f7de030ddd1f5fe93db7f811bf74d7ff9a08..475918d9f54303a6e4e6667cd5127bbfa0c15f63 100644 (file)
@@ -296,7 +296,6 @@ static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
        set_bit(event, &lpc18xx_pwm->event_map);
        lpc18xx_data->duty_event = event;
-       lpc18xx_pwm_config_duty(chip, pwm, pwm_get_duty_cycle(pwm));
 
        return 0;
 }
@@ -306,8 +305,6 @@ static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
        struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
        struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
 
-       pwm_disable(pwm);
-       pwm_set_duty_cycle(pwm, 0);
        clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map);
 }
 
index fd86446e499b23057a4def120b3baa02e1950c2d..28f55248eb9033bc2b2d0ee00fd2b39eaee65799 100644 (file)
@@ -328,7 +328,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
                return -ENODEV;
        }
        for_each_child_of_node(nproot, np) {
-               if (!of_node_cmp(np->name, info->desc.name)) {
+               if (of_node_name_eq(np, info->desc.name)) {
                        config->init_data =
                                of_get_regulator_init_data(&pdev->dev, np,
                                                           &info->desc);
index 926cee0d0b5f98c145069baf5ced0cf60f39ff49..ee60a222f5ebb042fe5e938ead4ab4d081f97666 100644 (file)
@@ -567,6 +567,16 @@ config REGULATOR_MC13892
          Say y here to support the regulators found on the Freescale MC13892
          PMIC.
 
+config REGULATOR_MCP16502
+       tristate "Microchip MCP16502 PMIC"
+       depends on I2C && OF
+       select REGMAP_I2C
+       help
+         Say y here to support the MCP16502 PMIC. This driver supports
+         basic operations (get/set voltage, get/set operating mode)
+         through the regulator interface. In addition it enables
+         suspend-to-ram/standby transition.
+
 config REGULATOR_MT6311
        tristate "MediaTek MT6311 PMIC"
        depends on I2C
index 72488ef11b8ad495b0e9a5b5293e56a6c11e3ca9..b12e1c9b21187517af0e7071a924353beaeb1950 100644 (file)
@@ -74,6 +74,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
index 43fda8b4455acd87d4c910d5ecfdb885759bba06..603db77723b66de337b112459244de5bfd7454f3 100644 (file)
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
 
 /**
  * ACT8945A Global Register Map.
  */
 #define ACT8945A_SYS_MODE      0x00
 #define ACT8945A_SYS_CTRL      0x01
+#define ACT8945A_SYS_UNLK_REGS 0x0b
 #define ACT8945A_DCDC1_VSET1   0x20
 #define ACT8945A_DCDC1_VSET2   0x21
 #define ACT8945A_DCDC1_CTRL    0x22
+#define ACT8945A_DCDC1_SUS     0x24
 #define ACT8945A_DCDC2_VSET1   0x30
 #define ACT8945A_DCDC2_VSET2   0x31
 #define ACT8945A_DCDC2_CTRL    0x32
+#define ACT8945A_DCDC2_SUS     0x34
 #define ACT8945A_DCDC3_VSET1   0x40
 #define ACT8945A_DCDC3_VSET2   0x41
 #define ACT8945A_DCDC3_CTRL    0x42
+#define ACT8945A_DCDC3_SUS     0x44
 #define ACT8945A_LDO1_VSET     0x50
 #define ACT8945A_LDO1_CTRL     0x51
+#define ACT8945A_LDO1_SUS      0x52
 #define ACT8945A_LDO2_VSET     0x54
 #define ACT8945A_LDO2_CTRL     0x55
+#define ACT8945A_LDO2_SUS      0x56
 #define ACT8945A_LDO3_VSET     0x60
 #define ACT8945A_LDO3_CTRL     0x61
+#define ACT8945A_LDO3_SUS      0x62
 #define ACT8945A_LDO4_VSET     0x64
 #define ACT8945A_LDO4_CTRL     0x65
+#define ACT8945A_LDO4_SUS      0x66
 
 /**
  * Field Definitions.
@@ -60,7 +70,12 @@ enum {
        ACT8945A_ID_LDO2,
        ACT8945A_ID_LDO3,
        ACT8945A_ID_LDO4,
-       ACT8945A_REG_NUM,
+       ACT8945A_ID_MAX,
+};
+
+struct act8945a_pmic {
+       struct regmap *regmap;
+       u32 op_mode[ACT8945A_ID_MAX];
 };
 
 static const struct regulator_linear_range act8945a_voltage_ranges[] = {
@@ -69,6 +84,143 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
 };
 
+static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev->desc->id, reg, val;
+
+       switch (id) {
+       case ACT8945A_ID_DCDC1:
+               reg = ACT8945A_DCDC1_SUS;
+               val = 0xa8;
+               break;
+       case ACT8945A_ID_DCDC2:
+               reg = ACT8945A_DCDC2_SUS;
+               val = 0xa8;
+               break;
+       case ACT8945A_ID_DCDC3:
+               reg = ACT8945A_DCDC3_SUS;
+               val = 0xa8;
+               break;
+       case ACT8945A_ID_LDO1:
+               reg = ACT8945A_LDO1_SUS;
+               val = 0xe8;
+               break;
+       case ACT8945A_ID_LDO2:
+               reg = ACT8945A_LDO2_SUS;
+               val = 0xe8;
+               break;
+       case ACT8945A_ID_LDO3:
+               reg = ACT8945A_LDO3_SUS;
+               val = 0xe8;
+               break;
+       case ACT8945A_ID_LDO4:
+               reg = ACT8945A_LDO4_SUS;
+               val = 0xe8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (enable)
+               val |= BIT(4);
+
+       /*
+        * Ask the PMIC to enable/disable this output when entering hibernate
+        * mode.
+        */
+       return regmap_write(regmap, reg, val);
+}
+
+static int act8945a_set_suspend_enable(struct regulator_dev *rdev)
+{
+       return act8945a_set_suspend_state(rdev, true);
+}
+
+static int act8945a_set_suspend_disable(struct regulator_dev *rdev)
+{
+       return act8945a_set_suspend_state(rdev, false);
+}
+
+static unsigned int act8945a_of_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case ACT8945A_REGULATOR_MODE_FIXED:
+       case ACT8945A_REGULATOR_MODE_NORMAL:
+               return REGULATOR_MODE_NORMAL;
+       case ACT8945A_REGULATOR_MODE_LOWPOWER:
+               return REGULATOR_MODE_STANDBY;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev->desc->id;
+       int reg, ret, val = 0;
+
+       switch (id) {
+       case ACT8945A_ID_DCDC1:
+               reg = ACT8945A_DCDC1_CTRL;
+               break;
+       case ACT8945A_ID_DCDC2:
+               reg = ACT8945A_DCDC2_CTRL;
+               break;
+       case ACT8945A_ID_DCDC3:
+               reg = ACT8945A_DCDC3_CTRL;
+               break;
+       case ACT8945A_ID_LDO1:
+               reg = ACT8945A_LDO1_SUS;
+               break;
+       case ACT8945A_ID_LDO2:
+               reg = ACT8945A_LDO2_SUS;
+               break;
+       case ACT8945A_ID_LDO3:
+               reg = ACT8945A_LDO3_SUS;
+               break;
+       case ACT8945A_ID_LDO4:
+               reg = ACT8945A_LDO4_SUS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (mode) {
+       case REGULATOR_MODE_STANDBY:
+               if (rdev->desc->id > ACT8945A_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               if (rdev->desc->id <= ACT8945A_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(regmap, reg, BIT(5), val);
+       if (ret)
+               return ret;
+
+       act8945a->op_mode[id] = mode;
+
+       return 0;
+}
+
+static unsigned int act8945a_get_mode(struct regulator_dev *rdev)
+{
+       struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
+       int id = rdev->desc->id;
+
+       if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX)
+               return -EINVAL;
+
+       return act8945a->op_mode[id];
+}
+
 static const struct regulator_ops act8945a_ops = {
        .list_voltage           = regulator_list_voltage_linear_range,
        .map_voltage            = regulator_map_voltage_linear_range,
@@ -76,7 +228,11 @@ static const struct regulator_ops act8945a_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
+       .set_mode               = act8945a_set_mode,
+       .get_mode               = act8945a_get_mode,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_enable     = act8945a_set_suspend_enable,
+       .set_suspend_disable    = act8945a_set_suspend_disable,
 };
 
 #define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply)           \
@@ -84,6 +240,7 @@ static const struct regulator_ops act8945a_ops = {
                .name                   = _name,                        \
                .supply_name            = _supply,                      \
                .of_match               = of_match_ptr("REG_"#_id),     \
+               .of_map_mode            = act8945a_of_map_mode,         \
                .regulators_node        = of_match_ptr("regulators"),   \
                .id                     = _family##_ID_##_id,           \
                .type                   = REGULATOR_VOLTAGE,            \
@@ -122,10 +279,22 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
 {
        struct regulator_config config = { };
        const struct regulator_desc *regulators;
+       struct act8945a_pmic *act8945a;
        struct regulator_dev *rdev;
        int i, num_regulators;
        bool voltage_select;
 
+       act8945a = devm_kzalloc(&pdev->dev, sizeof(*act8945a), GFP_KERNEL);
+       if (!act8945a)
+               return -ENOMEM;
+
+       act8945a->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!act8945a->regmap) {
+               dev_err(&pdev->dev,
+                       "could not retrieve regmap from parent device\n");
+               return -EINVAL;
+       }
+
        voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
                                               "active-semi,vsel-high");
 
@@ -139,8 +308,10 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
 
        config.dev = &pdev->dev;
        config.dev->of_node = pdev->dev.parent->of_node;
+       config.driver_data = act8945a;
        for (i = 0; i < num_regulators; i++) {
-               rdev = devm_regulator_register(&pdev->dev, &regulators[i], &config);
+               rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+                                              &config);
                if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev,
                                "failed to register %s regulator\n",
@@ -149,14 +320,42 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
                }
        }
 
-       return 0;
+       platform_set_drvdata(pdev, act8945a);
+
+       /* Unlock expert registers. */
+       return regmap_write(act8945a->regmap, ACT8945A_SYS_UNLK_REGS, 0xef);
+}
+
+static int __maybe_unused act8945a_suspend(struct device *pdev)
+{
+       struct act8945a_pmic *act8945a = dev_get_drvdata(pdev);
+
+       /*
+        * Ask the PMIC to enter the suspend mode on the next PWRHLD
+        * transition.
+        */
+       return regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x42);
+}
+
+static SIMPLE_DEV_PM_OPS(act8945a_pm, act8945a_suspend, NULL);
+
+static void act8945a_pmic_shutdown(struct platform_device *pdev)
+{
+       struct act8945a_pmic *act8945a = platform_get_drvdata(pdev);
+
+       /*
+        * Ask the PMIC to shutdown everything on the next PWRHLD transition.
+        */
+       regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x0);
 }
 
 static struct platform_driver act8945a_pmic_driver = {
        .driver = {
                .name = "act8945a-regulator",
+               .pm = &act8945a_pm,
        },
        .probe = act8945a_pmic_probe,
+       .shutdown = act8945a_pmic_shutdown,
 };
 module_platform_driver(act8945a_pmic_driver);
 
index 9a72eae4926d5ceabad10d478851bedb604bfef1..b9a93049e41ee7b2ccddf7940e82d6b09ddc6911 100644 (file)
@@ -283,9 +283,6 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
        of_node_put(config.of_node);
 
        if (IS_ERR(ldo1->regulator)) {
-               if (config.ena_gpiod)
-                       gpiod_put(config.ena_gpiod);
-
                ret = PTR_ERR(ldo1->regulator);
                dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
                        ret);
index 565a71343a8e6014fa61ace5fb3a1b6b490f34b5..f7fe218bb3e4e36145f44f8ce32bf4555c1e4f4d 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies
  *
  * Copyright (C) 2012 Renesas Electronics Corporation
  * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License as
- * published by the Free Software Foundation
  */
 
 #include <linux/err.h>
index a3734039a86a7897c35d69f4f536dc94f8f27b29..48af859fd053445706195f18f8c59c9a309101ad 100644 (file)
  * GNU General Public License for more details.
  */
 
+#include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mfd/axp20x.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/mfd/axp20x.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 
+#define AXP20X_GPIO0_FUNC_MASK         GENMASK(3, 0)
+#define AXP20X_GPIO1_FUNC_MASK         GENMASK(3, 0)
+
 #define AXP20X_IO_ENABLED              0x03
 #define AXP20X_IO_DISABLED             0x07
 
+#define AXP20X_WORKMODE_DCDC2_MASK     BIT_MASK(2)
+#define AXP20X_WORKMODE_DCDC3_MASK     BIT_MASK(1)
+
+#define AXP20X_FREQ_DCDC_MASK          GENMASK(3, 0)
+
+#define AXP20X_VBUS_IPSOUT_MGMT_MASK   BIT_MASK(2)
+
+#define AXP20X_DCDC2_V_OUT_MASK                GENMASK(5, 0)
+#define AXP20X_DCDC3_V_OUT_MASK                GENMASK(7, 0)
+#define AXP20X_LDO24_V_OUT_MASK                GENMASK(7, 4)
+#define AXP20X_LDO3_V_OUT_MASK         GENMASK(6, 0)
+#define AXP20X_LDO5_V_OUT_MASK         GENMASK(7, 4)
+
+#define AXP20X_PWR_OUT_EXTEN_MASK      BIT_MASK(0)
+#define AXP20X_PWR_OUT_DCDC3_MASK      BIT_MASK(1)
+#define AXP20X_PWR_OUT_LDO2_MASK       BIT_MASK(2)
+#define AXP20X_PWR_OUT_LDO4_MASK       BIT_MASK(3)
+#define AXP20X_PWR_OUT_DCDC2_MASK      BIT_MASK(4)
+#define AXP20X_PWR_OUT_LDO3_MASK       BIT_MASK(6)
+
+#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK       BIT_MASK(0)
+#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE(x) \
+       ((x) << 0)
+#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK                BIT_MASK(1)
+#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE(x) \
+       ((x) << 1)
+#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK         BIT_MASK(2)
+#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN              BIT(2)
+#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK          BIT_MASK(3)
+#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN               BIT(3)
+
+#define AXP20X_LDO4_V_OUT_1250mV_START 0x0
+#define AXP20X_LDO4_V_OUT_1250mV_STEPS 0
+#define AXP20X_LDO4_V_OUT_1250mV_END   \
+       (AXP20X_LDO4_V_OUT_1250mV_START + AXP20X_LDO4_V_OUT_1250mV_STEPS)
+#define AXP20X_LDO4_V_OUT_1300mV_START 0x1
+#define AXP20X_LDO4_V_OUT_1300mV_STEPS 7
+#define AXP20X_LDO4_V_OUT_1300mV_END   \
+       (AXP20X_LDO4_V_OUT_1300mV_START + AXP20X_LDO4_V_OUT_1300mV_STEPS)
+#define AXP20X_LDO4_V_OUT_2500mV_START 0x9
+#define AXP20X_LDO4_V_OUT_2500mV_STEPS 0
+#define AXP20X_LDO4_V_OUT_2500mV_END   \
+       (AXP20X_LDO4_V_OUT_2500mV_START + AXP20X_LDO4_V_OUT_2500mV_STEPS)
+#define AXP20X_LDO4_V_OUT_2700mV_START 0xa
+#define AXP20X_LDO4_V_OUT_2700mV_STEPS 1
+#define AXP20X_LDO4_V_OUT_2700mV_END   \
+       (AXP20X_LDO4_V_OUT_2700mV_START + AXP20X_LDO4_V_OUT_2700mV_STEPS)
+#define AXP20X_LDO4_V_OUT_3000mV_START 0xc
+#define AXP20X_LDO4_V_OUT_3000mV_STEPS 3
+#define AXP20X_LDO4_V_OUT_3000mV_END   \
+       (AXP20X_LDO4_V_OUT_3000mV_START + AXP20X_LDO4_V_OUT_3000mV_STEPS)
+#define AXP20X_LDO4_V_OUT_NUM_VOLTAGES 16
+
 #define AXP22X_IO_ENABLED              0x03
 #define AXP22X_IO_DISABLED             0x04
 
-#define AXP20X_WORKMODE_DCDC2_MASK     BIT(2)
-#define AXP20X_WORKMODE_DCDC3_MASK     BIT(1)
-#define AXP22X_WORKMODE_DCDCX_MASK(x)  BIT(x)
-
-#define AXP20X_FREQ_DCDC_MASK          0x0f
+#define AXP22X_WORKMODE_DCDCX_MASK(x)  BIT_MASK(x)
 
 #define AXP22X_MISC_N_VBUSEN_FUNC      BIT(4)
 
+#define AXP22X_DCDC1_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DCDC2_V_OUT_MASK                GENMASK(5, 0)
+#define AXP22X_DCDC3_V_OUT_MASK                GENMASK(5, 0)
+#define AXP22X_DCDC4_V_OUT_MASK                GENMASK(5, 0)
+#define AXP22X_DCDC5_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DC5LDO_V_OUT_MASK       GENMASK(2, 0)
+#define AXP22X_ALDO1_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_ALDO2_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_ALDO3_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DLDO1_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DLDO2_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DLDO3_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_DLDO4_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_ELDO1_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_ELDO2_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_ELDO3_V_OUT_MASK                GENMASK(4, 0)
+#define AXP22X_LDO_IO0_V_OUT_MASK      GENMASK(4, 0)
+#define AXP22X_LDO_IO1_V_OUT_MASK      GENMASK(4, 0)
+
+#define AXP22X_PWR_OUT_DC5LDO_MASK     BIT_MASK(0)
+#define AXP22X_PWR_OUT_DCDC1_MASK      BIT_MASK(1)
+#define AXP22X_PWR_OUT_DCDC2_MASK      BIT_MASK(2)
+#define AXP22X_PWR_OUT_DCDC3_MASK      BIT_MASK(3)
+#define AXP22X_PWR_OUT_DCDC4_MASK      BIT_MASK(4)
+#define AXP22X_PWR_OUT_DCDC5_MASK      BIT_MASK(5)
+#define AXP22X_PWR_OUT_ALDO1_MASK      BIT_MASK(6)
+#define AXP22X_PWR_OUT_ALDO2_MASK      BIT_MASK(7)
+
+#define AXP22X_PWR_OUT_SW_MASK         BIT_MASK(6)
+#define AXP22X_PWR_OUT_DC1SW_MASK      BIT_MASK(7)
+
+#define AXP22X_PWR_OUT_ELDO1_MASK      BIT_MASK(0)
+#define AXP22X_PWR_OUT_ELDO2_MASK      BIT_MASK(1)
+#define AXP22X_PWR_OUT_ELDO3_MASK      BIT_MASK(2)
+#define AXP22X_PWR_OUT_DLDO1_MASK      BIT_MASK(3)
+#define AXP22X_PWR_OUT_DLDO2_MASK      BIT_MASK(4)
+#define AXP22X_PWR_OUT_DLDO3_MASK      BIT_MASK(5)
+#define AXP22X_PWR_OUT_DLDO4_MASK      BIT_MASK(6)
+#define AXP22X_PWR_OUT_ALDO3_MASK      BIT_MASK(7)
+
+#define AXP803_PWR_OUT_DCDC1_MASK      BIT_MASK(0)
+#define AXP803_PWR_OUT_DCDC2_MASK      BIT_MASK(1)
+#define AXP803_PWR_OUT_DCDC3_MASK      BIT_MASK(2)
+#define AXP803_PWR_OUT_DCDC4_MASK      BIT_MASK(3)
+#define AXP803_PWR_OUT_DCDC5_MASK      BIT_MASK(4)
+#define AXP803_PWR_OUT_DCDC6_MASK      BIT_MASK(5)
+
+#define AXP803_PWR_OUT_FLDO1_MASK      BIT_MASK(2)
+#define AXP803_PWR_OUT_FLDO2_MASK      BIT_MASK(3)
+
+#define AXP803_DCDC1_V_OUT_MASK                GENMASK(4, 0)
+#define AXP803_DCDC2_V_OUT_MASK                GENMASK(6, 0)
+#define AXP803_DCDC3_V_OUT_MASK                GENMASK(6, 0)
+#define AXP803_DCDC4_V_OUT_MASK                GENMASK(6, 0)
+#define AXP803_DCDC5_V_OUT_MASK                GENMASK(6, 0)
+#define AXP803_DCDC6_V_OUT_MASK                GENMASK(6, 0)
+
+#define AXP803_FLDO1_V_OUT_MASK                GENMASK(3, 0)
+#define AXP803_FLDO2_V_OUT_MASK                GENMASK(3, 0)
+
+#define AXP803_DCDC23_POLYPHASE_DUAL   BIT(6)
+#define AXP803_DCDC56_POLYPHASE_DUAL   BIT(5)
+
+#define AXP803_DCDC234_500mV_START     0x00
+#define AXP803_DCDC234_500mV_STEPS     70
+#define AXP803_DCDC234_500mV_END       \
+       (AXP803_DCDC234_500mV_START + AXP803_DCDC234_500mV_STEPS)
+#define AXP803_DCDC234_1220mV_START    0x47
+#define AXP803_DCDC234_1220mV_STEPS    4
+#define AXP803_DCDC234_1220mV_END      \
+       (AXP803_DCDC234_1220mV_START + AXP803_DCDC234_1220mV_STEPS)
+#define AXP803_DCDC234_NUM_VOLTAGES    76
+
+#define AXP803_DCDC5_800mV_START       0x00
+#define AXP803_DCDC5_800mV_STEPS       32
+#define AXP803_DCDC5_800mV_END         \
+       (AXP803_DCDC5_800mV_START + AXP803_DCDC5_800mV_STEPS)
+#define AXP803_DCDC5_1140mV_START      0x21
+#define AXP803_DCDC5_1140mV_STEPS      35
+#define AXP803_DCDC5_1140mV_END                \
+       (AXP803_DCDC5_1140mV_START + AXP803_DCDC5_1140mV_STEPS)
+#define AXP803_DCDC5_NUM_VOLTAGES      68
+
+#define AXP803_DCDC6_600mV_START       0x00
+#define AXP803_DCDC6_600mV_STEPS       50
+#define AXP803_DCDC6_600mV_END         \
+       (AXP803_DCDC6_600mV_START + AXP803_DCDC6_600mV_STEPS)
+#define AXP803_DCDC6_1120mV_START      0x33
+#define AXP803_DCDC6_1120mV_STEPS      14
+#define AXP803_DCDC6_1120mV_END                \
+       (AXP803_DCDC6_1120mV_START + AXP803_DCDC6_1120mV_STEPS)
+#define AXP803_DCDC6_NUM_VOLTAGES      72
+
+#define AXP803_DLDO2_700mV_START       0x00
+#define AXP803_DLDO2_700mV_STEPS       26
+#define AXP803_DLDO2_700mV_END         \
+       (AXP803_DLDO2_700mV_START + AXP803_DLDO2_700mV_STEPS)
+#define AXP803_DLDO2_3400mV_START      0x1b
+#define AXP803_DLDO2_3400mV_STEPS      4
+#define AXP803_DLDO2_3400mV_END                \
+       (AXP803_DLDO2_3400mV_START + AXP803_DLDO2_3400mV_STEPS)
+#define AXP803_DLDO2_NUM_VOLTAGES      32
+
+#define AXP806_DCDCA_V_CTRL_MASK       GENMASK(6, 0)
+#define AXP806_DCDCB_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_DCDCC_V_CTRL_MASK       GENMASK(6, 0)
+#define AXP806_DCDCD_V_CTRL_MASK       GENMASK(5, 0)
+#define AXP806_DCDCE_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_ALDO1_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_ALDO2_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_ALDO3_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_BLDO1_V_CTRL_MASK       GENMASK(3, 0)
+#define AXP806_BLDO2_V_CTRL_MASK       GENMASK(3, 0)
+#define AXP806_BLDO3_V_CTRL_MASK       GENMASK(3, 0)
+#define AXP806_BLDO4_V_CTRL_MASK       GENMASK(3, 0)
+#define AXP806_CLDO1_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_CLDO2_V_CTRL_MASK       GENMASK(4, 0)
+#define AXP806_CLDO3_V_CTRL_MASK       GENMASK(4, 0)
+
+#define AXP806_PWR_OUT_DCDCA_MASK      BIT_MASK(0)
+#define AXP806_PWR_OUT_DCDCB_MASK      BIT_MASK(1)
+#define AXP806_PWR_OUT_DCDCC_MASK      BIT_MASK(2)
+#define AXP806_PWR_OUT_DCDCD_MASK      BIT_MASK(3)
+#define AXP806_PWR_OUT_DCDCE_MASK      BIT_MASK(4)
+#define AXP806_PWR_OUT_ALDO1_MASK      BIT_MASK(5)
+#define AXP806_PWR_OUT_ALDO2_MASK      BIT_MASK(6)
+#define AXP806_PWR_OUT_ALDO3_MASK      BIT_MASK(7)
+#define AXP806_PWR_OUT_BLDO1_MASK      BIT_MASK(0)
+#define AXP806_PWR_OUT_BLDO2_MASK      BIT_MASK(1)
+#define AXP806_PWR_OUT_BLDO3_MASK      BIT_MASK(2)
+#define AXP806_PWR_OUT_BLDO4_MASK      BIT_MASK(3)
+#define AXP806_PWR_OUT_CLDO1_MASK      BIT_MASK(4)
+#define AXP806_PWR_OUT_CLDO2_MASK      BIT_MASK(5)
+#define AXP806_PWR_OUT_CLDO3_MASK      BIT_MASK(6)
+#define AXP806_PWR_OUT_SW_MASK         BIT_MASK(7)
+
+#define AXP806_DCDCAB_POLYPHASE_DUAL   0x40
+#define AXP806_DCDCABC_POLYPHASE_TRI   0x80
+#define AXP806_DCDCABC_POLYPHASE_MASK  GENMASK(7, 6)
+
+#define AXP806_DCDCDE_POLYPHASE_DUAL   BIT(5)
+
+#define AXP806_DCDCA_600mV_START       0x00
+#define AXP806_DCDCA_600mV_STEPS       50
+#define AXP806_DCDCA_600mV_END         \
+       (AXP806_DCDCA_600mV_START + AXP806_DCDCA_600mV_STEPS)
+#define AXP806_DCDCA_1120mV_START      0x33
+#define AXP806_DCDCA_1120mV_STEPS      14
+#define AXP806_DCDCA_1120mV_END                \
+       (AXP806_DCDCA_1120mV_START + AXP806_DCDCA_1120mV_STEPS)
+#define AXP806_DCDCA_NUM_VOLTAGES      72
+
+#define AXP806_DCDCD_600mV_START       0x00
+#define AXP806_DCDCD_600mV_STEPS       45
+#define AXP806_DCDCD_600mV_END         \
+       (AXP806_DCDCD_600mV_START + AXP806_DCDCD_600mV_STEPS)
+#define AXP806_DCDCD_1600mV_START      0x2e
+#define AXP806_DCDCD_1600mV_STEPS      17
+#define AXP806_DCDCD_1600mV_END                \
+       (AXP806_DCDCD_1600mV_START + AXP806_DCDCD_1600mV_STEPS)
+#define AXP806_DCDCD_NUM_VOLTAGES      64
+
+#define AXP809_DCDC4_600mV_START       0x00
+#define AXP809_DCDC4_600mV_STEPS       47
+#define AXP809_DCDC4_600mV_END         \
+       (AXP809_DCDC4_600mV_START + AXP809_DCDC4_600mV_STEPS)
+#define AXP809_DCDC4_1800mV_START      0x30
+#define AXP809_DCDC4_1800mV_STEPS      8
+#define AXP809_DCDC4_1800mV_END                \
+       (AXP809_DCDC4_1800mV_START + AXP809_DCDC4_1800mV_STEPS)
+#define AXP809_DCDC4_NUM_VOLTAGES      57
+
+#define AXP813_DCDC7_V_OUT_MASK                GENMASK(6, 0)
+
+#define AXP813_PWR_OUT_DCDC7_MASK      BIT_MASK(6)
+
 #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg,   \
                    _vmask, _ereg, _emask, _enable_val, _disable_val)           \
        [_family##_##_id] = {                                                   \
                .ops            = &axp20x_ops_range,                            \
        }
 
+static const int axp209_dcdc2_ldo3_slew_rates[] = {
+       1600,
+        800,
+};
+
+static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
+{
+       struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
+       const struct regulator_desc *desc = rdev->desc;
+       u8 reg, mask, enable, cfg = 0xff;
+       const int *slew_rates;
+       int rate_count = 0;
+
+       if (!rdev)
+               return -EINVAL;
+
+       switch (axp20x->variant) {
+       case AXP209_ID:
+               if (desc->id == AXP20X_DCDC2) {
+                       slew_rates = axp209_dcdc2_ldo3_slew_rates;
+                       rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates);
+                       reg = AXP20X_DCDC2_LDO3_V_RAMP;
+                       mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK |
+                              AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK;
+                       enable = (ramp > 0) ?
+                                AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN :
+                                !AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN;
+                       break;
+               }
+
+               if (desc->id == AXP20X_LDO3) {
+                       slew_rates = axp209_dcdc2_ldo3_slew_rates;
+                       rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates);
+                       reg = AXP20X_DCDC2_LDO3_V_RAMP;
+                       mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK |
+                              AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK;
+                       enable = (ramp > 0) ?
+                                AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN :
+                                !AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN;
+                       break;
+               }
+
+               if (rate_count > 0)
+                       break;
+
+               /* fall through */
+       default:
+               /* Not supported for this regulator */
+               return -ENOTSUPP;
+       }
+
+       if (ramp == 0) {
+               cfg = enable;
+       } else {
+               int i;
+
+               for (i = 0; i < rate_count; i++) {
+                       if (ramp <= slew_rates[i])
+                               cfg = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE(i);
+                       else
+                               break;
+               }
+
+               if (cfg == 0xff) {
+                       dev_err(axp20x->dev, "unsupported ramp value %d", ramp);
+                       return -EINVAL;
+               }
+
+               cfg |= enable;
+       }
+
+       return regmap_update_bits(axp20x->regmap, reg, mask, cfg);
+}
+
+static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev)
+{
+       struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
+       const struct regulator_desc *desc = rdev->desc;
+
+       if (!rdev)
+               return -EINVAL;
+
+       switch (axp20x->variant) {
+       case AXP209_ID:
+               if ((desc->id == AXP20X_LDO3) &&
+                   rdev->constraints && rdev->constraints->soft_start) {
+                       int v_out;
+                       int ret;
+
+                       /*
+                        * On some boards, the LDO3 can be overloaded when
+                        * turning on, causing the entire PMIC to shutdown
+                        * without warning. Turning it on at the minimal voltage
+                        * and then setting the voltage to the requested value
+                        * works reliably.
+                        */
+                       if (regulator_is_enabled_regmap(rdev))
+                               break;
+
+                       v_out = regulator_get_voltage_sel_regmap(rdev);
+                       if (v_out < 0)
+                               return v_out;
+
+                       if (v_out == 0)
+                               break;
+
+                       ret = regulator_set_voltage_sel_regmap(rdev, 0x00);
+                       /*
+                        * A small pause is needed between
+                        * setting the voltage and enabling the LDO to give the
+                        * internal state machine time to process the request.
+                        */
+                       usleep_range(1000, 5000);
+                       ret |= regulator_enable_regmap(rdev);
+                       ret |= regulator_set_voltage_sel_regmap(rdev, v_out);
+
+                       return ret;
+               }
+               break;
+       default:
+               /* No quirks */
+               break;
+       }
+
+       return regulator_enable_regmap(rdev);
+};
+
 static const struct regulator_ops axp20x_ops_fixed = {
        .list_voltage           = regulator_list_voltage_linear,
 };
@@ -145,9 +503,10 @@ static const struct regulator_ops axp20x_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear,
-       .enable                 = regulator_enable_regmap,
+       .enable                 = axp20x_regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_ramp_delay         = axp20x_set_ramp_delay,
 };
 
 static const struct regulator_ops axp20x_ops_sw = {
@@ -157,77 +516,116 @@ static const struct regulator_ops axp20x_ops_sw = {
 };
 
 static const struct regulator_linear_range axp20x_ldo4_ranges[] = {
-       REGULATOR_LINEAR_RANGE(1250000, 0x0, 0x0, 0),
-       REGULATOR_LINEAR_RANGE(1300000, 0x1, 0x8, 100000),
-       REGULATOR_LINEAR_RANGE(2500000, 0x9, 0x9, 0),
-       REGULATOR_LINEAR_RANGE(2700000, 0xa, 0xb, 100000),
-       REGULATOR_LINEAR_RANGE(3000000, 0xc, 0xf, 100000),
+       REGULATOR_LINEAR_RANGE(1250000,
+                              AXP20X_LDO4_V_OUT_1250mV_START,
+                              AXP20X_LDO4_V_OUT_1250mV_END,
+                              0),
+       REGULATOR_LINEAR_RANGE(1300000,
+                              AXP20X_LDO4_V_OUT_1300mV_START,
+                              AXP20X_LDO4_V_OUT_1300mV_END,
+                              100000),
+       REGULATOR_LINEAR_RANGE(2500000,
+                              AXP20X_LDO4_V_OUT_2500mV_START,
+                              AXP20X_LDO4_V_OUT_2500mV_END,
+                              0),
+       REGULATOR_LINEAR_RANGE(2700000,
+                              AXP20X_LDO4_V_OUT_2700mV_START,
+                              AXP20X_LDO4_V_OUT_2700mV_END,
+                              100000),
+       REGULATOR_LINEAR_RANGE(3000000,
+                              AXP20X_LDO4_V_OUT_3000mV_START,
+                              AXP20X_LDO4_V_OUT_3000mV_END,
+                              100000),
 };
 
 static const struct regulator_desc axp20x_regulators[] = {
        AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
-                AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
+                AXP20X_DCDC2_V_OUT, AXP20X_DCDC2_V_OUT_MASK,
+                AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_DCDC2_MASK),
        AXP_DESC(AXP20X, DCDC3, "dcdc3", "vin3", 700, 3500, 25,
-                AXP20X_DCDC3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
+                AXP20X_DCDC3_V_OUT, AXP20X_DCDC3_V_OUT_MASK,
+                AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_DCDC3_MASK),
        AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300),
        AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
-                AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
+                AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK,
+                AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO2_MASK),
        AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,
-                AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
-       AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_ranges,
-                       16, AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL,
-                       0x08),
+                AXP20X_LDO3_V_OUT, AXP20X_LDO3_V_OUT_MASK,
+                AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO3_MASK),
+       AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in",
+                       axp20x_ldo4_ranges, AXP20X_LDO4_V_OUT_NUM_VOLTAGES,
+                       AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK,
+                       AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO4_MASK),
        AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
-                   AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP20X_LDO5_V_OUT, AXP20X_LDO5_V_OUT_MASK,
+                   AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK,
                    AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
 };
 
 static const struct regulator_desc axp22x_regulators[] = {
        AXP_DESC(AXP22X, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
-                AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
+                AXP22X_DCDC1_V_OUT, AXP22X_DCDC1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC1_MASK),
        AXP_DESC(AXP22X, DCDC2, "dcdc2", "vin2", 600, 1540, 20,
-                AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)),
+                AXP22X_DCDC2_V_OUT, AXP22X_DCDC2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC2_MASK),
        AXP_DESC(AXP22X, DCDC3, "dcdc3", "vin3", 600, 1860, 20,
-                AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)),
+                AXP22X_DCDC3_V_OUT, AXP22X_DCDC3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC3_MASK),
        AXP_DESC(AXP22X, DCDC4, "dcdc4", "vin4", 600, 1540, 20,
-                AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(4)),
+                AXP22X_DCDC4_V_OUT, AXP22X_DCDC4_V_OUT,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC4_MASK),
        AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
-                AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
+                AXP22X_DCDC5_V_OUT, AXP22X_DCDC5_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC5_MASK),
        /* secondary switchable output of DCDC1 */
-       AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
-                   BIT(7)),
+       AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL,
+                   AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK),
        /* LDO regulator internally chained to DCDC5 */
        AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
-                AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
+                AXP22X_DC5LDO_V_OUT, AXP22X_DC5LDO_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DC5LDO_MASK),
        AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
+                AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO1_MASK),
        AXP_DESC(AXP22X, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
+                AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO2_MASK),
        AXP_DESC(AXP22X, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
+                AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP22X_PWR_OUT_ALDO3_MASK),
        AXP_DESC(AXP22X, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
+                AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK),
        AXP_DESC(AXP22X, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)),
+                AXP22X_DLDO2_V_OUT, AXP22X_PWR_OUT_DLDO2_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK),
        AXP_DESC(AXP22X, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
+                AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK),
        AXP_DESC(AXP22X, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)),
+                AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK),
        AXP_DESC(AXP22X, ELDO1, "eldo1", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+                AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK),
        AXP_DESC(AXP22X, ELDO2, "eldo2", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+                AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK),
        AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+                AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK),
        /* Note the datasheet only guarantees reliable operation up to
         * 3.3V, this needs to be enforced via dts provided constraints */
        AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 700, 3800, 100,
-                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK,
+                   AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        /* Note the datasheet only guarantees reliable operation up to
         * 3.3V, this needs to be enforced via dts provided constraints */
        AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 700, 3800, 100,
-                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+                   AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK,
+                   AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000),
 };
@@ -240,240 +638,354 @@ static const struct regulator_desc axp22x_drivevbus_regulator = {
        .type           = REGULATOR_VOLTAGE,
        .owner          = THIS_MODULE,
        .enable_reg     = AXP20X_VBUS_IPSOUT_MGMT,
-       .enable_mask    = BIT(2),
+       .enable_mask    = AXP20X_VBUS_IPSOUT_MGMT_MASK,
        .ops            = &axp20x_ops_sw,
 };
 
 /* DCDC ranges shared with AXP813 */
 static const struct regulator_linear_range axp803_dcdc234_ranges[] = {
-       REGULATOR_LINEAR_RANGE(500000, 0x0, 0x46, 10000),
-       REGULATOR_LINEAR_RANGE(1220000, 0x47, 0x4b, 20000),
+       REGULATOR_LINEAR_RANGE(500000,
+                              AXP803_DCDC234_500mV_START,
+                              AXP803_DCDC234_500mV_END,
+                              10000),
+       REGULATOR_LINEAR_RANGE(1220000,
+                              AXP803_DCDC234_1220mV_START,
+                              AXP803_DCDC234_1220mV_END,
+                              20000),
 };
 
 static const struct regulator_linear_range axp803_dcdc5_ranges[] = {
-       REGULATOR_LINEAR_RANGE(800000, 0x0, 0x20, 10000),
-       REGULATOR_LINEAR_RANGE(1140000, 0x21, 0x44, 20000),
+       REGULATOR_LINEAR_RANGE(800000,
+                              AXP803_DCDC5_800mV_START,
+                              AXP803_DCDC5_800mV_END,
+                              10000),
+       REGULATOR_LINEAR_RANGE(1140000,
+                              AXP803_DCDC5_1140mV_START,
+                              AXP803_DCDC5_1140mV_END,
+                              20000),
 };
 
 static const struct regulator_linear_range axp803_dcdc6_ranges[] = {
-       REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
-       REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
+       REGULATOR_LINEAR_RANGE(600000,
+                              AXP803_DCDC6_600mV_START,
+                              AXP803_DCDC6_600mV_END,
+                              10000),
+       REGULATOR_LINEAR_RANGE(1120000,
+                              AXP803_DCDC6_1120mV_START,
+                              AXP803_DCDC6_1120mV_END,
+                              20000),
 };
 
-/* AXP806's CLDO2 and AXP809's DLDO1 shares the same range */
+/* AXP806's CLDO2 and AXP809's DLDO1 share the same range */
 static const struct regulator_linear_range axp803_dldo2_ranges[] = {
-       REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
-       REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
+       REGULATOR_LINEAR_RANGE(700000,
+                              AXP803_DLDO2_700mV_START,
+                              AXP803_DLDO2_700mV_END,
+                              100000),
+       REGULATOR_LINEAR_RANGE(3400000,
+                              AXP803_DLDO2_3400mV_START,
+                              AXP803_DLDO2_3400mV_END,
+                              200000),
 };
 
 static const struct regulator_desc axp803_regulators[] = {
        AXP_DESC(AXP803, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
-                AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)),
-       AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(1)),
-       AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(2)),
-       AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(3)),
-       AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges,
-                       68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(4)),
-       AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges,
-                       72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(5)),
+                AXP803_DCDC1_V_OUT, AXP803_DCDC1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC1_MASK),
+       AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC2_V_OUT, AXP803_DCDC2_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC2_MASK),
+       AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC3_V_OUT, AXP803_DCDC3_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC3_MASK),
+       AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC4_V_OUT, AXP803_DCDC4_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC4_MASK),
+       AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5",
+                       axp803_dcdc5_ranges, AXP803_DCDC5_NUM_VOLTAGES,
+                       AXP803_DCDC5_V_OUT, AXP803_DCDC5_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC5_MASK),
+       AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6",
+                       axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES,
+                       AXP803_DCDC6_V_OUT, AXP803_DCDC6_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC6_MASK),
        /* secondary switchable output of DCDC1 */
-       AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
-                   BIT(7)),
+       AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL,
+                   AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK),
        AXP_DESC(AXP803, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)),
+                AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO1_MASK),
        AXP_DESC(AXP803, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)),
+                AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO2_MASK),
        AXP_DESC(AXP803, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
+                AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO3_MASK),
        AXP_DESC(AXP803, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
-       AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges,
-                       32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
-                       BIT(4)),
+                AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK),
+       AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin",
+                       axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES,
+                       AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT,
+                       AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK),
        AXP_DESC(AXP803, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
+                AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK),
        AXP_DESC(AXP803, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)),
+                AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK),
        AXP_DESC(AXP803, ELDO1, "eldo1", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+                AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK),
        AXP_DESC(AXP803, ELDO2, "eldo2", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+                AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK),
        AXP_DESC(AXP803, ELDO3, "eldo3", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+                AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK),
        AXP_DESC(AXP803, FLDO1, "fldo1", "fldoin", 700, 1450, 50,
-                AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)),
+                AXP803_FLDO1_V_OUT, AXP803_FLDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO1_MASK),
        AXP_DESC(AXP803, FLDO2, "fldo2", "fldoin", 700, 1450, 50,
-                AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)),
+                AXP803_FLDO2_V_OUT, AXP803_FLDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO2_MASK),
        AXP_DESC_IO(AXP803, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100,
-                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK,
+                   AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        AXP_DESC_IO(AXP803, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100,
-                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+                   AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK,
+                   AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        AXP_DESC_FIXED(AXP803, RTC_LDO, "rtc-ldo", "ips", 3000),
 };
 
 static const struct regulator_linear_range axp806_dcdca_ranges[] = {
-       REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
-       REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
+       REGULATOR_LINEAR_RANGE(600000,
+                              AXP806_DCDCA_600mV_START,
+                              AXP806_DCDCA_600mV_END,
+                              10000),
+       REGULATOR_LINEAR_RANGE(1120000,
+                              AXP806_DCDCA_1120mV_START,
+                              AXP806_DCDCA_1120mV_END,
+                              20000),
 };
 
 static const struct regulator_linear_range axp806_dcdcd_ranges[] = {
-       REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000),
-       REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000),
+       REGULATOR_LINEAR_RANGE(600000,
+                              AXP806_DCDCD_600mV_START,
+                              AXP806_DCDCD_600mV_END,
+                              20000),
+       REGULATOR_LINEAR_RANGE(1600000,
+                              AXP806_DCDCD_600mV_START,
+                              AXP806_DCDCD_600mV_END,
+                              100000),
 };
 
 static const struct regulator_desc axp806_regulators[] = {
-       AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges,
-                       72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
-                       BIT(0)),
+       AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina",
+                       axp806_dcdca_ranges, AXP806_DCDCA_NUM_VOLTAGES,
+                       AXP806_DCDCA_V_CTRL, AXP806_DCDCA_V_CTRL_MASK,
+                       AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCA_MASK),
        AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50,
-                AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)),
-       AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges,
-                       72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
-                       BIT(2)),
-       AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges,
-                       64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
-                       BIT(3)),
+                AXP806_DCDCB_V_CTRL, AXP806_DCDCB_V_CTRL,
+                AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCB_MASK),
+       AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc",
+                       axp806_dcdca_ranges, AXP806_DCDCA_NUM_VOLTAGES,
+                       AXP806_DCDCC_V_CTRL, AXP806_DCDCC_V_CTRL_MASK,
+                       AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCC_MASK),
+       AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind",
+                       axp806_dcdcd_ranges, AXP806_DCDCD_NUM_VOLTAGES,
+                       AXP806_DCDCD_V_CTRL, AXP806_DCDCD_V_CTRL_MASK,
+                       AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCD_MASK),
        AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
-                AXP806_DCDCE_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
+                AXP806_DCDCE_V_CTRL, AXP806_DCDCE_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCE_MASK),
        AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
-                AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
+                AXP806_ALDO1_V_CTRL, AXP806_ALDO1_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO1_MASK),
        AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
-                AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)),
+                AXP806_ALDO2_V_CTRL, AXP806_ALDO2_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO2_MASK),
        AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
-                AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)),
+                AXP806_ALDO3_V_CTRL, AXP806_ALDO3_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO3_MASK),
        AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100,
-                AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)),
+                AXP806_BLDO1_V_CTRL, AXP806_BLDO1_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO1_MASK),
        AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100,
-                AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)),
+                AXP806_BLDO2_V_CTRL, AXP806_BLDO2_V_CTRL,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO2_MASK),
        AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100,
-                AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)),
+                AXP806_BLDO3_V_CTRL, AXP806_BLDO3_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO3_MASK),
        AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100,
-                AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)),
+                AXP806_BLDO4_V_CTRL, AXP806_BLDO4_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO4_MASK),
        AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100,
-                AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)),
-       AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp803_dldo2_ranges,
-                       32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2,
-                       BIT(5)),
+                AXP806_CLDO1_V_CTRL, AXP806_CLDO1_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO1_MASK),
+       AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin",
+                       axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES,
+                       AXP806_CLDO2_V_CTRL, AXP806_CLDO2_V_CTRL_MASK,
+                       AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO2_MASK),
        AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100,
-                AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)),
-       AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)),
+                AXP806_CLDO3_V_CTRL, AXP806_CLDO3_V_CTRL_MASK,
+                AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO3_MASK),
+       AXP_DESC_SW(AXP806, SW, "sw", "swin",
+                   AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_SW_MASK),
 };
 
 static const struct regulator_linear_range axp809_dcdc4_ranges[] = {
-       REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000),
-       REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000),
+       REGULATOR_LINEAR_RANGE(600000,
+                              AXP809_DCDC4_600mV_START,
+                              AXP809_DCDC4_600mV_END,
+                              20000),
+       REGULATOR_LINEAR_RANGE(1800000,
+                              AXP809_DCDC4_1800mV_START,
+                              AXP809_DCDC4_1800mV_END,
+                              100000),
 };
 
 static const struct regulator_desc axp809_regulators[] = {
        AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
-                AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
+                AXP22X_DCDC1_V_OUT, AXP22X_DCDC1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC1_MASK),
        AXP_DESC(AXP809, DCDC2, "dcdc2", "vin2", 600, 1540, 20,
-                AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)),
+                AXP22X_DCDC2_V_OUT, AXP22X_DCDC2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC2_MASK),
        AXP_DESC(AXP809, DCDC3, "dcdc3", "vin3", 600, 1860, 20,
-                AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)),
-       AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", axp809_dcdc4_ranges,
-                       57, AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(4)),
+                AXP22X_DCDC3_V_OUT, AXP22X_DCDC3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC3_MASK),
+       AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4",
+                       axp809_dcdc4_ranges, AXP809_DCDC4_NUM_VOLTAGES,
+                       AXP22X_DCDC4_V_OUT, AXP22X_DCDC4_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC4_MASK),
        AXP_DESC(AXP809, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
-                AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
+                AXP22X_DCDC5_V_OUT, AXP22X_DCDC5_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC5_MASK),
        /* secondary switchable output of DCDC1 */
-       AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
-                   BIT(7)),
+       AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL,
+                   AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK),
        /* LDO regulator internally chained to DCDC5 */
        AXP_DESC(AXP809, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
-                AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
+                AXP22X_DC5LDO_V_OUT, AXP22X_DC5LDO_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DC5LDO_MASK),
        AXP_DESC(AXP809, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
+                AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO1_MASK),
        AXP_DESC(AXP809, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
+                AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO2_MASK),
        AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
-       AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp803_dldo2_ranges,
-                       32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
-                       BIT(3)),
+                AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ALDO3_MASK),
+       AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin",
+                       axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES,
+                       AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK),
        AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)),
+                AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK),
        AXP_DESC(AXP809, ELDO1, "eldo1", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+                AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK),
        AXP_DESC(AXP809, ELDO2, "eldo2", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+                AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK),
        AXP_DESC(AXP809, ELDO3, "eldo3", "eldoin", 700, 3300, 100,
-                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+                AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK),
        /*
         * Note the datasheet only guarantees reliable operation up to
         * 3.3V, this needs to be enforced via dts provided constraints
         */
        AXP_DESC_IO(AXP809, LDO_IO0, "ldo_io0", "ips", 700, 3800, 100,
-                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK,
+                   AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        /*
         * Note the datasheet only guarantees reliable operation up to
         * 3.3V, this needs to be enforced via dts provided constraints
         */
        AXP_DESC_IO(AXP809, LDO_IO1, "ldo_io1", "ips", 700, 3800, 100,
-                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+                   AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK,
+                   AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        AXP_DESC_FIXED(AXP809, RTC_LDO, "rtc_ldo", "ips", 1800),
-       AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)),
+       AXP_DESC_SW(AXP809, SW, "sw", "swin",
+                   AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_SW_MASK),
 };
 
 static const struct regulator_desc axp813_regulators[] = {
        AXP_DESC(AXP813, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
-                AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)),
-       AXP_DESC_RANGES(AXP813, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(1)),
-       AXP_DESC_RANGES(AXP813, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(2)),
-       AXP_DESC_RANGES(AXP813, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges,
-                       76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(3)),
-       AXP_DESC_RANGES(AXP813, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges,
-                       68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(4)),
-       AXP_DESC_RANGES(AXP813, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges,
-                       72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(5)),
-       AXP_DESC_RANGES(AXP813, DCDC7, "dcdc7", "vin7", axp803_dcdc6_ranges,
-                       72, AXP813_DCDC7_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
-                       BIT(6)),
+                AXP803_DCDC1_V_OUT, AXP803_DCDC1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC1_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC2, "dcdc2", "vin2",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC2_V_OUT, AXP803_DCDC2_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC2_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC3, "dcdc3", "vin3",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC3_V_OUT, AXP803_DCDC3_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC3_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC4, "dcdc4", "vin4",
+                       axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES,
+                       AXP803_DCDC4_V_OUT, AXP803_DCDC4_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC4_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC5, "dcdc5", "vin5",
+                       axp803_dcdc5_ranges, AXP803_DCDC5_NUM_VOLTAGES,
+                       AXP803_DCDC5_V_OUT, AXP803_DCDC5_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC5_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC6, "dcdc6", "vin6",
+                       axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES,
+                       AXP803_DCDC6_V_OUT, AXP803_DCDC6_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC6_MASK),
+       AXP_DESC_RANGES(AXP813, DCDC7, "dcdc7", "vin7",
+                       axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES,
+                       AXP813_DCDC7_V_OUT, AXP813_DCDC7_V_OUT_MASK,
+                       AXP22X_PWR_OUT_CTRL1, AXP813_PWR_OUT_DCDC7_MASK),
        AXP_DESC(AXP813, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)),
+                AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO1_MASK),
        AXP_DESC(AXP813, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)),
+                AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO2_MASK),
        AXP_DESC(AXP813, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
-                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
+                AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO3_MASK),
        AXP_DESC(AXP813, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
-       AXP_DESC_RANGES(AXP813, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges,
-                       32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
-                       BIT(4)),
+                AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK),
+       AXP_DESC_RANGES(AXP813, DLDO2, "dldo2", "dldoin",
+                       axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES,
+                       AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT,
+                       AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK),
        AXP_DESC(AXP813, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
+                AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK),
        AXP_DESC(AXP813, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
-                AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)),
+                AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK),
        AXP_DESC(AXP813, ELDO1, "eldo1", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+                AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK),
        AXP_DESC(AXP813, ELDO2, "eldo2", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+                AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK),
        AXP_DESC(AXP813, ELDO3, "eldo3", "eldoin", 700, 1900, 50,
-                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+                AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT,
+                AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK),
        /* to do / check ... */
        AXP_DESC(AXP813, FLDO1, "fldo1", "fldoin", 700, 1450, 50,
-                AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)),
+                AXP803_FLDO1_V_OUT, AXP803_FLDO1_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO1_MASK),
        AXP_DESC(AXP813, FLDO2, "fldo2", "fldoin", 700, 1450, 50,
-                AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)),
+                AXP803_FLDO2_V_OUT, AXP803_FLDO2_V_OUT_MASK,
+                AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO2_MASK),
        /*
         * TODO: FLDO3 = {DCDC5, FLDOIN} / 2
         *
@@ -482,12 +994,15 @@ static const struct regulator_desc axp813_regulators[] = {
         */
        AXP_DESC_FIXED(AXP813, RTC_LDO, "rtc-ldo", "ips", 1800),
        AXP_DESC_IO(AXP813, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100,
-                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK,
+                   AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
        AXP_DESC_IO(AXP813, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100,
-                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+                   AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK,
+                   AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK,
                    AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
-       AXP_DESC_SW(AXP813, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(7)),
+       AXP_DESC_SW(AXP813, SW, "sw", "swin",
+                   AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK),
 };
 
 static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
@@ -663,9 +1178,9 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
 
                switch (id) {
                case AXP803_DCDC3:
-                       return !!(reg & BIT(6));
+                       return !!(reg & AXP803_DCDC23_POLYPHASE_DUAL);
                case AXP803_DCDC6:
-                       return !!(reg & BIT(5));
+                       return !!(reg & AXP803_DCDC56_POLYPHASE_DUAL);
                }
                break;
 
@@ -674,12 +1189,15 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
 
                switch (id) {
                case AXP806_DCDCB:
-                       return (((reg & GENMASK(7, 6)) == BIT(6)) ||
-                               ((reg & GENMASK(7, 6)) == BIT(7)));
+                       return (((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
+                               AXP806_DCDCAB_POLYPHASE_DUAL) ||
+                               ((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
+                               AXP806_DCDCABC_POLYPHASE_TRI));
                case AXP806_DCDCC:
-                       return ((reg & GENMASK(7, 6)) == BIT(7));
+                       return ((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
+                               AXP806_DCDCABC_POLYPHASE_TRI);
                case AXP806_DCDCE:
-                       return !!(reg & BIT(5));
+                       return !!(reg & AXP806_DCDCDE_POLYPHASE_DUAL);
                }
                break;
 
index 3a47e0372e77c81248efc6bf04e7fb832d5b59ac..b8dcdc21dc2242e7f21a70db830ef3325619c53b 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/mfd/rohm-bd718x7.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -130,6 +131,7 @@ static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
        .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_ascend,
        .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_time_sel = regulator_set_voltage_time_sel,
@@ -1007,7 +1009,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 };
 
 struct bd718xx_pmic_inits {
-       const struct bd718xx_regulator_data (*r_datas)[];
+       const struct bd718xx_regulator_data *r_datas;
        unsigned int r_amount;
 };
 
@@ -1017,11 +1019,11 @@ static int bd718xx_probe(struct platform_device *pdev)
        struct regulator_config config = { 0 };
        struct bd718xx_pmic_inits pmic_regulators[] = {
                [BD718XX_TYPE_BD71837] = {
-                       .r_datas = &bd71837_regulators,
+                       .r_datas = bd71837_regulators,
                        .r_amount = ARRAY_SIZE(bd71837_regulators),
                },
                [BD718XX_TYPE_BD71847] = {
-                       .r_datas = &bd71847_regulators,
+                       .r_datas = bd71847_regulators,
                        .r_amount = ARRAY_SIZE(bd71847_regulators),
                },
        };
@@ -1053,13 +1055,36 @@ static int bd718xx_probe(struct platform_device *pdev)
                        BD718XX_REG_REGLOCK);
        }
 
+       /* At poweroff transition PMIC HW disables EN bit for regulators but
+        * leaves SEL bit untouched. So if state transition from POWEROFF
+        * is done to SNVS - then all power rails controlled by SW (having
+        * SEL bit set) stay disabled as EN is cleared. This may result boot
+        * failure if any crucial systems are powered by these rails.
+        *
+        * Change the next stage from poweroff to be READY instead of SNVS
+        * for all reset types because OTP loading at READY will clear SEL
+        * bit allowing HW defaults for power rails to be used
+        */
+       err = regmap_update_bits(mfd->regmap, BD718XX_REG_TRANS_COND1,
+                                BD718XX_ON_REQ_POWEROFF_MASK |
+                                BD718XX_SWRESET_POWEROFF_MASK |
+                                BD718XX_WDOG_POWEROFF_MASK |
+                                BD718XX_KEY_L_POWEROFF_MASK,
+                                BD718XX_POWOFF_TO_RDY);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to change reset target\n");
+               goto err;
+       } else {
+               dev_dbg(&pdev->dev, "Changed all resets from SVNS to READY\n");
+       }
+
        for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
 
                const struct regulator_desc *desc;
                struct regulator_dev *rdev;
                const struct bd718xx_regulator_data *r;
 
-               r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
+               r = &pmic_regulators[mfd->chip_type].r_datas[i];
                desc = &r->desc;
 
                config.dev = pdev->dev.parent;
index 274c5ed7cd737ecd3e4eae78458b1879af44747a..e12dd1f750f3495dabedaae2c72fb4397dec0770 100644 (file)
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * ROHM BD9571MWV-M regulator driver
  *
  * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License version 2 for more details.
- *
  * Based on the TPS65086 driver
  *
  * NOTE: VD09 is missing
index 2c66b528aedec02f4afdda7e8c04faf60711a70d..b9d7b45c7295459f0928e8436623b45897be23d1 100644 (file)
@@ -50,6 +50,8 @@
 #define rdev_dbg(rdev, fmt, ...)                                       \
        pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
 
+static DEFINE_WW_CLASS(regulator_ww_class);
+static DEFINE_MUTEX(regulator_nesting_mutex);
 static DEFINE_MUTEX(regulator_list_mutex);
 static LIST_HEAD(regulator_map_list);
 static LIST_HEAD(regulator_ena_gpio_list);
@@ -97,7 +99,7 @@ struct regulator_supply_alias {
 };
 
 static int _regulator_is_enabled(struct regulator_dev *rdev);
-static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_disable(struct regulator *regulator);
 static int _regulator_get_voltage(struct regulator_dev *rdev);
 static int _regulator_get_current_limit(struct regulator_dev *rdev);
 static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -105,6 +107,11 @@ static int _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                                     int min_uV, int max_uV);
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+                                    suspend_state_t state);
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
+                                     int min_uV, int max_uV,
+                                     suspend_state_t state);
 static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          struct device *dev,
                                          const char *supply_name);
@@ -149,7 +156,7 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
 /**
  * regulator_lock_nested - lock a single regulator
  * @rdev:              regulator source
- * @subclass:          mutex subclass used for lockdep
+ * @ww_ctx:            w/w mutex acquire context
  *
  * This function can be called many times by one task on
  * a single regulator and its mutex will be locked only
@@ -157,25 +164,54 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
  * than the one, which initially locked the mutex, it will
  * wait on mutex.
  */
-static void regulator_lock_nested(struct regulator_dev *rdev,
-                                 unsigned int subclass)
+static inline int regulator_lock_nested(struct regulator_dev *rdev,
+                                       struct ww_acquire_ctx *ww_ctx)
 {
-       if (!mutex_trylock(&rdev->mutex)) {
-               if (rdev->mutex_owner == current) {
+       bool lock = false;
+       int ret = 0;
+
+       mutex_lock(&regulator_nesting_mutex);
+
+       if (ww_ctx || !ww_mutex_trylock(&rdev->mutex)) {
+               if (rdev->mutex_owner == current)
                        rdev->ref_cnt++;
-                       return;
+               else
+                       lock = true;
+
+               if (lock) {
+                       mutex_unlock(&regulator_nesting_mutex);
+                       ret = ww_mutex_lock(&rdev->mutex, ww_ctx);
+                       mutex_lock(&regulator_nesting_mutex);
                }
-               mutex_lock_nested(&rdev->mutex, subclass);
+       } else {
+               lock = true;
+       }
+
+       if (lock && ret != -EDEADLK) {
+               rdev->ref_cnt++;
+               rdev->mutex_owner = current;
        }
 
-       rdev->ref_cnt = 1;
-       rdev->mutex_owner = current;
+       mutex_unlock(&regulator_nesting_mutex);
+
+       return ret;
 }
 
-static inline void regulator_lock(struct regulator_dev *rdev)
+/**
+ * regulator_lock - lock a single regulator
+ * @rdev:              regulator source
+ *
+ * This function can be called many times by one task on
+ * a single regulator and its mutex will be locked only
+ * once. If a task, which is calling this function is other
+ * than the one, which initially locked the mutex, it will
+ * wait on mutex.
+ */
+void regulator_lock(struct regulator_dev *rdev)
 {
-       regulator_lock_nested(rdev, 0);
+       regulator_lock_nested(rdev, NULL);
 }
+EXPORT_SYMBOL_GPL(regulator_lock);
 
 /**
  * regulator_unlock - unlock a single regulator
@@ -184,47 +220,191 @@ static inline void regulator_lock(struct regulator_dev *rdev)
  * This function unlocks the mutex when the
  * reference counter reaches 0.
  */
-static void regulator_unlock(struct regulator_dev *rdev)
+void regulator_unlock(struct regulator_dev *rdev)
+{
+       mutex_lock(&regulator_nesting_mutex);
+
+       if (--rdev->ref_cnt == 0) {
+               rdev->mutex_owner = NULL;
+               ww_mutex_unlock(&rdev->mutex);
+       }
+
+       WARN_ON_ONCE(rdev->ref_cnt < 0);
+
+       mutex_unlock(&regulator_nesting_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_unlock);
+
+static bool regulator_supply_is_couple(struct regulator_dev *rdev)
+{
+       struct regulator_dev *c_rdev;
+       int i;
+
+       for (i = 1; i < rdev->coupling_desc.n_coupled; i++) {
+               c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+               if (rdev->supply->rdev == c_rdev)
+                       return true;
+       }
+
+       return false;
+}
+
+static void regulator_unlock_recursive(struct regulator_dev *rdev,
+                                      unsigned int n_coupled)
+{
+       struct regulator_dev *c_rdev;
+       int i;
+
+       for (i = n_coupled; i > 0; i--) {
+               c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
+
+               if (!c_rdev)
+                       continue;
+
+               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev))
+                       regulator_unlock_recursive(
+                                       c_rdev->supply->rdev,
+                                       c_rdev->coupling_desc.n_coupled);
+
+               regulator_unlock(c_rdev);
+       }
+}
+
+static int regulator_lock_recursive(struct regulator_dev *rdev,
+                                   struct regulator_dev **new_contended_rdev,
+                                   struct regulator_dev **old_contended_rdev,
+                                   struct ww_acquire_ctx *ww_ctx)
 {
-       if (rdev->ref_cnt != 0) {
-               rdev->ref_cnt--;
+       struct regulator_dev *c_rdev;
+       int i, err;
 
-               if (!rdev->ref_cnt) {
-                       rdev->mutex_owner = NULL;
-                       mutex_unlock(&rdev->mutex);
+       for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
+               c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+               if (!c_rdev)
+                       continue;
+
+               if (c_rdev != *old_contended_rdev) {
+                       err = regulator_lock_nested(c_rdev, ww_ctx);
+                       if (err) {
+                               if (err == -EDEADLK) {
+                                       *new_contended_rdev = c_rdev;
+                                       goto err_unlock;
+                               }
+
+                               /* shouldn't happen */
+                               WARN_ON_ONCE(err != -EALREADY);
+                       }
+               } else {
+                       *old_contended_rdev = NULL;
+               }
+
+               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+                       err = regulator_lock_recursive(c_rdev->supply->rdev,
+                                                      new_contended_rdev,
+                                                      old_contended_rdev,
+                                                      ww_ctx);
+                       if (err) {
+                               regulator_unlock(c_rdev);
+                               goto err_unlock;
+                       }
                }
        }
+
+       return 0;
+
+err_unlock:
+       regulator_unlock_recursive(rdev, i);
+
+       return err;
 }
 
 /**
- * regulator_lock_supply - lock a regulator and its supplies
- * @rdev:         regulator source
+ * regulator_unlock_dependent - unlock regulator's suppliers and coupled
+ *                             regulators
+ * @rdev:                      regulator source
+ * @ww_ctx:                    w/w mutex acquire context
+ *
+ * Unlock all regulators related with rdev by coupling or suppling.
  */
-static void regulator_lock_supply(struct regulator_dev *rdev)
+static void regulator_unlock_dependent(struct regulator_dev *rdev,
+                                      struct ww_acquire_ctx *ww_ctx)
 {
-       int i;
-
-       for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
-               regulator_lock_nested(rdev, i);
+       regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled);
+       ww_acquire_fini(ww_ctx);
 }
 
 /**
- * regulator_unlock_supply - unlock a regulator and its supplies
- * @rdev:         regulator source
+ * regulator_lock_dependent - lock regulator's suppliers and coupled regulators
+ * @rdev:                      regulator source
+ * @ww_ctx:                    w/w mutex acquire context
+ *
+ * This function as a wrapper on regulator_lock_recursive(), which locks
+ * all regulators related with rdev by coupling or suppling.
  */
-static void regulator_unlock_supply(struct regulator_dev *rdev)
+static void regulator_lock_dependent(struct regulator_dev *rdev,
+                                    struct ww_acquire_ctx *ww_ctx)
 {
-       struct regulator *supply;
+       struct regulator_dev *new_contended_rdev = NULL;
+       struct regulator_dev *old_contended_rdev = NULL;
+       int err;
+
+       mutex_lock(&regulator_list_mutex);
+
+       ww_acquire_init(ww_ctx, &regulator_ww_class);
+
+       do {
+               if (new_contended_rdev) {
+                       ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+                       old_contended_rdev = new_contended_rdev;
+                       old_contended_rdev->ref_cnt++;
+               }
+
+               err = regulator_lock_recursive(rdev,
+                                              &new_contended_rdev,
+                                              &old_contended_rdev,
+                                              ww_ctx);
+
+               if (old_contended_rdev)
+                       regulator_unlock(old_contended_rdev);
+
+       } while (err == -EDEADLK);
+
+       ww_acquire_done(ww_ctx);
+
+       mutex_unlock(&regulator_list_mutex);
+}
 
-       while (1) {
-               regulator_unlock(rdev);
-               supply = rdev->supply;
+/**
+ * of_get_child_regulator - get a child regulator device node
+ * based on supply name
+ * @parent: Parent device node
+ * @prop_name: Combination regulator supply name and "-supply"
+ *
+ * Traverse all child nodes.
+ * Extract the child regulator device node corresponding to the supply name.
+ * returns the device node corresponding to the regulator if found, else
+ * returns NULL.
+ */
+static struct device_node *of_get_child_regulator(struct device_node *parent,
+                                                 const char *prop_name)
+{
+       struct device_node *regnode = NULL;
+       struct device_node *child = NULL;
 
-               if (!rdev->supply)
-                       return;
+       for_each_child_of_node(parent, child) {
+               regnode = of_parse_phandle(child, prop_name, 0);
 
-               rdev = supply->rdev;
+               if (!regnode) {
+                       regnode = of_get_child_regulator(child, prop_name);
+                       if (regnode)
+                               return regnode;
+               } else {
+                       return regnode;
+               }
        }
+       return NULL;
 }
 
 /**
@@ -247,6 +427,10 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
        regnode = of_parse_phandle(dev->of_node, prop_name, 0);
 
        if (!regnode) {
+               regnode = of_get_child_regulator(dev->of_node, prop_name);
+               if (regnode)
+                       return regnode;
+
                dev_dbg(dev, "Looking up %s property in node %pOF failed\n",
                                prop_name, dev->of_node);
                return NULL;
@@ -582,8 +766,10 @@ static ssize_t regulator_total_uA_show(struct device *dev,
        int uA = 0;
 
        regulator_lock(rdev);
-       list_for_each_entry(regulator, &rdev->consumer_list, list)
-               uA += regulator->uA_load;
+       list_for_each_entry(regulator, &rdev->consumer_list, list) {
+               if (regulator->enable_count)
+                       uA += regulator->uA_load;
+       }
        regulator_unlock(rdev);
        return sprintf(buf, "%d\n", uA);
 }
@@ -738,7 +924,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
        int current_uA = 0, output_uV, input_uV, err;
        unsigned int mode;
 
-       lockdep_assert_held_once(&rdev->mutex);
+       lockdep_assert_held_once(&rdev->mutex.base);
 
        /*
         * first check to see if we can set modes at all, otherwise just
@@ -756,8 +942,10 @@ static int drms_uA_update(struct regulator_dev *rdev)
                return -EINVAL;
 
        /* calc total requested load */
-       list_for_each_entry(sibling, &rdev->consumer_list, list)
-               current_uA += sibling->uA_load;
+       list_for_each_entry(sibling, &rdev->consumer_list, list) {
+               if (sibling->enable_count)
+                       current_uA += sibling->uA_load;
+       }
 
        current_uA += rdev->constraints->system_load;
 
@@ -1156,17 +1344,12 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                        rdev_err(rdev, "failed to set initial mode: %d\n", ret);
                        return ret;
                }
-       }
-
-       /* If the constraints say the regulator should be on at this point
-        * and we have control then make sure it is enabled.
-        */
-       if (rdev->constraints->always_on || rdev->constraints->boot_on) {
-               ret = _regulator_do_enable(rdev);
-               if (ret < 0 && ret != -EINVAL) {
-                       rdev_err(rdev, "failed to enable\n");
-                       return ret;
-               }
+       } else if (rdev->constraints->system_load) {
+               /*
+                * We'll only apply the initial system load if an
+                * initial mode wasn't specified.
+                */
+               drms_uA_update(rdev);
        }
 
        if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable)
@@ -1214,6 +1397,27 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
+       /* If the constraints say the regulator should be on at this point
+        * and we have control then make sure it is enabled.
+        */
+       if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+               if (rdev->supply) {
+                       ret = regulator_enable(rdev->supply);
+                       if (ret < 0) {
+                               _regulator_put(rdev->supply);
+                               rdev->supply = NULL;
+                               return ret;
+                       }
+               }
+
+               ret = _regulator_do_enable(rdev);
+               if (ret < 0 && ret != -EINVAL) {
+                       rdev_err(rdev, "failed to enable\n");
+                       return ret;
+               }
+               rdev->use_count++;
+       }
+
        print_constraints(rdev);
        return 0;
 }
@@ -1628,8 +1832,12 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
                return ret;
        }
 
-       /* Cascade always-on state to supply */
-       if (_regulator_is_enabled(rdev)) {
+       /*
+        * In set_machine_constraints() we may have turned this regulator on
+        * but we couldn't propagate to the supply if it hadn't been resolved
+        * yet.  Do it now.
+        */
+       if (rdev->use_count) {
                ret = regulator_enable(rdev->supply);
                if (ret < 0) {
                        _regulator_put(rdev->supply);
@@ -1713,6 +1921,16 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
                return regulator;
        }
 
+       mutex_lock(&regulator_list_mutex);
+       ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled);
+       mutex_unlock(&regulator_list_mutex);
+
+       if (ret != 0) {
+               regulator = ERR_PTR(-EPROBE_DEFER);
+               put_device(&rdev->dev);
+               return regulator;
+       }
+
        ret = regulator_resolve_supply(rdev);
        if (ret < 0) {
                regulator = ERR_PTR(ret);
@@ -1832,6 +2050,9 @@ static void _regulator_put(struct regulator *regulator)
 
        lockdep_assert_held_once(&regulator_list_mutex);
 
+       /* Docs say you must disable before calling regulator_put() */
+       WARN_ON(regulator->enable_count);
+
        rdev = regulator->rdev;
 
        debugfs_remove_recursive(regulator->debugfs);
@@ -2225,34 +2446,109 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
        return 0;
 }
 
+/**
+ * _regulator_handle_consumer_enable - handle that a consumer enabled
+ * @regulator: regulator source
+ *
+ * Some things on a regulator consumer (like the contribution towards total
+ * load on the regulator) only have an effect when the consumer wants the
+ * regulator enabled.  Explained in example with two consumers of the same
+ * regulator:
+ *   consumer A: set_load(100);       => total load = 0
+ *   consumer A: regulator_enable();  => total load = 100
+ *   consumer B: set_load(1000);      => total load = 100
+ *   consumer B: regulator_enable();  => total load = 1100
+ *   consumer A: regulator_disable(); => total_load = 1000
+ *
+ * This function (together with _regulator_handle_consumer_disable) is
+ * responsible for keeping track of the refcount for a given regulator consumer
+ * and applying / unapplying these things.
+ *
+ * Returns 0 upon no error; -error upon error.
+ */
+static int _regulator_handle_consumer_enable(struct regulator *regulator)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+
+       lockdep_assert_held_once(&rdev->mutex.base);
+
+       regulator->enable_count++;
+       if (regulator->uA_load && regulator->enable_count == 1)
+               return drms_uA_update(rdev);
+
+       return 0;
+}
+
+/**
+ * _regulator_handle_consumer_disable - handle that a consumer disabled
+ * @regulator: regulator source
+ *
+ * The opposite of _regulator_handle_consumer_enable().
+ *
+ * Returns 0 upon no error; -error upon error.
+ */
+static int _regulator_handle_consumer_disable(struct regulator *regulator)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+
+       lockdep_assert_held_once(&rdev->mutex.base);
+
+       if (!regulator->enable_count) {
+               rdev_err(rdev, "Underflow of regulator enable count\n");
+               return -EINVAL;
+       }
+
+       regulator->enable_count--;
+       if (regulator->uA_load && regulator->enable_count == 0)
+               return drms_uA_update(rdev);
+
+       return 0;
+}
+
 /* locks held by regulator_enable() */
-static int _regulator_enable(struct regulator_dev *rdev)
+static int _regulator_enable(struct regulator *regulator)
 {
+       struct regulator_dev *rdev = regulator->rdev;
        int ret;
 
-       lockdep_assert_held_once(&rdev->mutex);
+       lockdep_assert_held_once(&rdev->mutex.base);
 
-       /* check voltage and requested load before enabling */
-       if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
-               drms_uA_update(rdev);
+       if (rdev->use_count == 0 && rdev->supply) {
+               ret = _regulator_enable(rdev->supply);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* balance only if there are regulators coupled */
+       if (rdev->coupling_desc.n_coupled > 1) {
+               ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+               if (ret < 0)
+                       goto err_disable_supply;
+       }
+
+       ret = _regulator_handle_consumer_enable(regulator);
+       if (ret < 0)
+               goto err_disable_supply;
 
        if (rdev->use_count == 0) {
                /* The regulator may on if it's not switchable or left on */
                ret = _regulator_is_enabled(rdev);
                if (ret == -EINVAL || ret == 0) {
                        if (!regulator_ops_is_valid(rdev,
-                                       REGULATOR_CHANGE_STATUS))
-                               return -EPERM;
+                                       REGULATOR_CHANGE_STATUS)) {
+                               ret = -EPERM;
+                               goto err_consumer_disable;
+                       }
 
                        ret = _regulator_do_enable(rdev);
                        if (ret < 0)
-                               return ret;
+                               goto err_consumer_disable;
 
                        _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
                                             NULL);
                } else if (ret < 0) {
                        rdev_err(rdev, "is_enabled() failed: %d\n", ret);
-                       return ret;
+                       goto err_consumer_disable;
                }
                /* Fallthrough on positive return values - already enabled */
        }
@@ -2260,6 +2556,15 @@ static int _regulator_enable(struct regulator_dev *rdev)
        rdev->use_count++;
 
        return 0;
+
+err_consumer_disable:
+       _regulator_handle_consumer_disable(regulator);
+
+err_disable_supply:
+       if (rdev->use_count == 0 && rdev->supply)
+               _regulator_disable(rdev->supply);
+
+       return ret;
 }
 
 /**
@@ -2276,23 +2581,12 @@ static int _regulator_enable(struct regulator_dev *rdev)
 int regulator_enable(struct regulator *regulator)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       int ret = 0;
-
-       if (regulator->always_on)
-               return 0;
-
-       if (rdev->supply) {
-               ret = regulator_enable(rdev->supply);
-               if (ret != 0)
-                       return ret;
-       }
-
-       mutex_lock(&rdev->mutex);
-       ret = _regulator_enable(rdev);
-       mutex_unlock(&rdev->mutex);
+       struct ww_acquire_ctx ww_ctx;
+       int ret;
 
-       if (ret != 0 && rdev->supply)
-               regulator_disable(rdev->supply);
+       regulator_lock_dependent(rdev, &ww_ctx);
+       ret = _regulator_enable(regulator);
+       regulator_unlock_dependent(rdev, &ww_ctx);
 
        return ret;
 }
@@ -2330,11 +2624,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
 }
 
 /* locks held by regulator_disable() */
-static int _regulator_disable(struct regulator_dev *rdev)
+static int _regulator_disable(struct regulator *regulator)
 {
+       struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
 
-       lockdep_assert_held_once(&rdev->mutex);
+       lockdep_assert_held_once(&rdev->mutex.base);
 
        if (WARN(rdev->use_count <= 0,
                 "unbalanced disables for %s\n", rdev_get_name(rdev)))
@@ -2366,12 +2661,18 @@ static int _regulator_disable(struct regulator_dev *rdev)
 
                rdev->use_count = 0;
        } else if (rdev->use_count > 1) {
-               if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
-                       drms_uA_update(rdev);
-
                rdev->use_count--;
        }
 
+       if (ret == 0)
+               ret = _regulator_handle_consumer_disable(regulator);
+
+       if (ret == 0 && rdev->coupling_desc.n_coupled > 1)
+               ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+       if (ret == 0 && rdev->use_count == 0 && rdev->supply)
+               ret = _regulator_disable(rdev->supply);
+
        return ret;
 }
 
@@ -2390,17 +2691,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
 int regulator_disable(struct regulator *regulator)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       int ret = 0;
-
-       if (regulator->always_on)
-               return 0;
-
-       mutex_lock(&rdev->mutex);
-       ret = _regulator_disable(rdev);
-       mutex_unlock(&rdev->mutex);
+       struct ww_acquire_ctx ww_ctx;
+       int ret;
 
-       if (ret == 0 && rdev->supply)
-               regulator_disable(rdev->supply);
+       regulator_lock_dependent(rdev, &ww_ctx);
+       ret = _regulator_disable(regulator);
+       regulator_unlock_dependent(rdev, &ww_ctx);
 
        return ret;
 }
@@ -2411,7 +2707,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
-       lockdep_assert_held_once(&rdev->mutex);
+       lockdep_assert_held_once(&rdev->mutex.base);
 
        ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
                        REGULATOR_EVENT_PRE_DISABLE, NULL);
@@ -2444,16 +2740,25 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 int regulator_force_disable(struct regulator *regulator)
 {
        struct regulator_dev *rdev = regulator->rdev;
+       struct ww_acquire_ctx ww_ctx;
        int ret;
 
-       mutex_lock(&rdev->mutex);
-       regulator->uA_load = 0;
+       regulator_lock_dependent(rdev, &ww_ctx);
+
        ret = _regulator_force_disable(regulator->rdev);
-       mutex_unlock(&rdev->mutex);
 
-       if (rdev->supply)
-               while (rdev->open_count--)
-                       regulator_disable(rdev->supply);
+       if (rdev->coupling_desc.n_coupled > 1)
+               regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+       if (regulator->uA_load) {
+               regulator->uA_load = 0;
+               ret = drms_uA_update(rdev);
+       }
+
+       if (rdev->use_count != 0 && rdev->supply)
+               _regulator_disable(rdev->supply);
+
+       regulator_unlock_dependent(rdev, &ww_ctx);
 
        return ret;
 }
@@ -2463,14 +2768,12 @@ static void regulator_disable_work(struct work_struct *work)
 {
        struct regulator_dev *rdev = container_of(work, struct regulator_dev,
                                                  disable_work.work);
+       struct ww_acquire_ctx ww_ctx;
        int count, i, ret;
+       struct regulator *regulator;
+       int total_count = 0;
 
-       regulator_lock(rdev);
-
-       BUG_ON(!rdev->deferred_disables);
-
-       count = rdev->deferred_disables;
-       rdev->deferred_disables = 0;
+       regulator_lock_dependent(rdev, &ww_ctx);
 
        /*
         * Workqueue functions queue the new work instance while the previous
@@ -2480,23 +2783,27 @@ static void regulator_disable_work(struct work_struct *work)
         */
        cancel_delayed_work(&rdev->disable_work);
 
-       for (i = 0; i < count; i++) {
-               ret = _regulator_disable(rdev);
-               if (ret != 0)
-                       rdev_err(rdev, "Deferred disable failed: %d\n", ret);
-       }
+       list_for_each_entry(regulator, &rdev->consumer_list, list) {
+               count = regulator->deferred_disables;
 
-       regulator_unlock(rdev);
+               if (!count)
+                       continue;
+
+               total_count += count;
+               regulator->deferred_disables = 0;
 
-       if (rdev->supply) {
                for (i = 0; i < count; i++) {
-                       ret = regulator_disable(rdev->supply);
-                       if (ret != 0) {
-                               rdev_err(rdev,
-                                        "Supply disable failed: %d\n", ret);
-                       }
+                       ret = _regulator_disable(regulator);
+                       if (ret != 0)
+                               rdev_err(rdev, "Deferred disable failed: %d\n", ret);
                }
        }
+       WARN_ON(!total_count);
+
+       if (rdev->coupling_desc.n_coupled > 1)
+               regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+       regulator_unlock_dependent(rdev, &ww_ctx);
 }
 
 /**
@@ -2515,14 +2822,11 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
 {
        struct regulator_dev *rdev = regulator->rdev;
 
-       if (regulator->always_on)
-               return 0;
-
        if (!ms)
                return regulator_disable(regulator);
 
        regulator_lock(rdev);
-       rdev->deferred_disables++;
+       regulator->deferred_disables++;
        mod_delayed_work(system_power_efficient_wq, &rdev->disable_work,
                         msecs_to_jiffies(ms));
        regulator_unlock(rdev);
@@ -2597,9 +2901,9 @@ int regulator_is_enabled(struct regulator *regulator)
        if (regulator->always_on)
                return 1;
 
-       mutex_lock(&regulator->rdev->mutex);
+       regulator_lock(regulator->rdev);
        ret = _regulator_is_enabled(regulator->rdev);
-       mutex_unlock(&regulator->rdev->mutex);
+       regulator_unlock(regulator->rdev);
 
        return ret;
 }
@@ -3013,8 +3317,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
        int ret = 0;
        int old_min_uV, old_max_uV;
        int current_uV;
-       int best_supply_uV = 0;
-       int supply_change_uV = 0;
 
        /* If we're setting the same range as last time the change
         * should be a noop (some cpufreq implementations use the same
@@ -3054,10 +3356,27 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
        voltage->min_uV = min_uV;
        voltage->max_uV = max_uV;
 
-       ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
+       /* for not coupled regulators this will just set the voltage */
+       ret = regulator_balance_voltage(rdev, state);
        if (ret < 0)
                goto out2;
 
+out:
+       return 0;
+out2:
+       voltage->min_uV = old_min_uV;
+       voltage->max_uV = old_max_uV;
+
+       return ret;
+}
+
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+                                     int max_uV, suspend_state_t state)
+{
+       int best_supply_uV = 0;
+       int supply_change_uV = 0;
+       int ret;
+
        if (rdev->supply &&
            regulator_ops_is_valid(rdev->supply->rdev,
                                   REGULATOR_CHANGE_VOLTAGE) &&
@@ -3069,13 +3388,13 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
                selector = regulator_map_voltage(rdev, min_uV, max_uV);
                if (selector < 0) {
                        ret = selector;
-                       goto out2;
+                       goto out;
                }
 
                best_supply_uV = _regulator_list_voltage(rdev, selector, 0);
                if (best_supply_uV < 0) {
                        ret = best_supply_uV;
-                       goto out2;
+                       goto out;
                }
 
                best_supply_uV += rdev->desc->min_dropout_uV;
@@ -3083,7 +3402,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
                current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
                if (current_supply_uV < 0) {
                        ret = current_supply_uV;
-                       goto out2;
+                       goto out;
                }
 
                supply_change_uV = best_supply_uV - current_supply_uV;
@@ -3095,7 +3414,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
                if (ret) {
                        dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
                                        ret);
-                       goto out2;
+                       goto out;
                }
        }
 
@@ -3105,7 +3424,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
                ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
                                                        max_uV, state);
        if (ret < 0)
-               goto out2;
+               goto out;
 
        if (supply_change_uV < 0) {
                ret = regulator_set_voltage_unlocked(rdev->supply,
@@ -3119,10 +3438,273 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 
 out:
        return ret;
-out2:
-       voltage->min_uV = old_min_uV;
-       voltage->max_uV = old_max_uV;
+}
+
+static int regulator_limit_voltage_step(struct regulator_dev *rdev,
+                                       int *current_uV, int *min_uV)
+{
+       struct regulation_constraints *constraints = rdev->constraints;
+
+       /* Limit voltage change only if necessary */
+       if (!constraints->max_uV_step || !_regulator_is_enabled(rdev))
+               return 1;
+
+       if (*current_uV < 0) {
+               *current_uV = _regulator_get_voltage(rdev);
+
+               if (*current_uV < 0)
+                       return *current_uV;
+       }
+
+       if (abs(*current_uV - *min_uV) <= constraints->max_uV_step)
+               return 1;
+
+       /* Clamp target voltage within the given step */
+       if (*current_uV < *min_uV)
+               *min_uV = min(*current_uV + constraints->max_uV_step,
+                             *min_uV);
+       else
+               *min_uV = max(*current_uV - constraints->max_uV_step,
+                             *min_uV);
+
+       return 0;
+}
+
+static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
+                                        int *current_uV,
+                                        int *min_uV, int *max_uV,
+                                        suspend_state_t state,
+                                        int n_coupled)
+{
+       struct coupling_desc *c_desc = &rdev->coupling_desc;
+       struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
+       struct regulation_constraints *constraints = rdev->constraints;
+       int max_spread = constraints->max_spread;
+       int desired_min_uV = 0, desired_max_uV = INT_MAX;
+       int max_current_uV = 0, min_current_uV = INT_MAX;
+       int highest_min_uV = 0, target_uV, possible_uV;
+       int i, ret;
+       bool done;
+
+       *current_uV = -1;
+
+       /*
+        * If there are no coupled regulators, simply set the voltage
+        * demanded by consumers.
+        */
+       if (n_coupled == 1) {
+               /*
+                * If consumers don't provide any demands, set voltage
+                * to min_uV
+                */
+               desired_min_uV = constraints->min_uV;
+               desired_max_uV = constraints->max_uV;
+
+               ret = regulator_check_consumers(rdev,
+                                               &desired_min_uV,
+                                               &desired_max_uV, state);
+               if (ret < 0)
+                       return ret;
+
+               possible_uV = desired_min_uV;
+               done = true;
+
+               goto finish;
+       }
+
+       /* Find highest min desired voltage */
+       for (i = 0; i < n_coupled; i++) {
+               int tmp_min = 0;
+               int tmp_max = INT_MAX;
+
+               lockdep_assert_held_once(&c_rdevs[i]->mutex.base);
+
+               ret = regulator_check_consumers(c_rdevs[i],
+                                               &tmp_min,
+                                               &tmp_max, state);
+               if (ret < 0)
+                       return ret;
+
+               ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max);
+               if (ret < 0)
+                       return ret;
+
+               highest_min_uV = max(highest_min_uV, tmp_min);
+
+               if (i == 0) {
+                       desired_min_uV = tmp_min;
+                       desired_max_uV = tmp_max;
+               }
+       }
+
+       /*
+        * Let target_uV be equal to the desired one if possible.
+        * If not, set it to minimum voltage, allowed by other coupled
+        * regulators.
+        */
+       target_uV = max(desired_min_uV, highest_min_uV - max_spread);
+
+       /*
+        * Find min and max voltages, which currently aren't violating
+        * max_spread.
+        */
+       for (i = 1; i < n_coupled; i++) {
+               int tmp_act;
+
+               if (!_regulator_is_enabled(c_rdevs[i]))
+                       continue;
+
+               tmp_act = _regulator_get_voltage(c_rdevs[i]);
+               if (tmp_act < 0)
+                       return tmp_act;
+
+               min_current_uV = min(tmp_act, min_current_uV);
+               max_current_uV = max(tmp_act, max_current_uV);
+       }
+
+       /* There aren't any other regulators enabled */
+       if (max_current_uV == 0) {
+               possible_uV = target_uV;
+       } else {
+               /*
+                * Correct target voltage, so as it currently isn't
+                * violating max_spread
+                */
+               possible_uV = max(target_uV, max_current_uV - max_spread);
+               possible_uV = min(possible_uV, min_current_uV + max_spread);
+       }
+
+       if (possible_uV > desired_max_uV)
+               return -EINVAL;
+
+       done = (possible_uV == target_uV);
+       desired_min_uV = possible_uV;
 
+finish:
+       /* Apply max_uV_step constraint if necessary */
+       if (state == PM_SUSPEND_ON) {
+               ret = regulator_limit_voltage_step(rdev, current_uV,
+                                                  &desired_min_uV);
+               if (ret < 0)
+                       return ret;
+
+               if (ret == 0)
+                       done = false;
+       }
+
+       /* Set current_uV if wasn't done earlier in the code and if necessary */
+       if (n_coupled > 1 && *current_uV == -1) {
+
+               if (_regulator_is_enabled(rdev)) {
+                       ret = _regulator_get_voltage(rdev);
+                       if (ret < 0)
+                               return ret;
+
+                       *current_uV = ret;
+               } else {
+                       *current_uV = desired_min_uV;
+               }
+       }
+
+       *min_uV = desired_min_uV;
+       *max_uV = desired_max_uV;
+
+       return done;
+}
+
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+                                    suspend_state_t state)
+{
+       struct regulator_dev **c_rdevs;
+       struct regulator_dev *best_rdev;
+       struct coupling_desc *c_desc = &rdev->coupling_desc;
+       int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
+       bool best_c_rdev_done, c_rdev_done[MAX_COUPLED];
+       unsigned int delta, best_delta;
+
+       c_rdevs = c_desc->coupled_rdevs;
+       n_coupled = c_desc->n_coupled;
+
+       /*
+        * If system is in a state other than PM_SUSPEND_ON, don't check
+        * other coupled regulators.
+        */
+       if (state != PM_SUSPEND_ON)
+               n_coupled = 1;
+
+       if (c_desc->n_resolved < n_coupled) {
+               rdev_err(rdev, "Not all coupled regulators registered\n");
+               return -EPERM;
+       }
+
+       for (i = 0; i < n_coupled; i++)
+               c_rdev_done[i] = false;
+
+       /*
+        * Find the best possible voltage change on each loop. Leave the loop
+        * if there isn't any possible change.
+        */
+       do {
+               best_c_rdev_done = false;
+               best_delta = 0;
+               best_min_uV = 0;
+               best_max_uV = 0;
+               best_c_rdev = 0;
+               best_rdev = NULL;
+
+               /*
+                * Find highest difference between optimal voltage
+                * and current voltage.
+                */
+               for (i = 0; i < n_coupled; i++) {
+                       /*
+                        * optimal_uV is the best voltage that can be set for
+                        * i-th regulator at the moment without violating
+                        * max_spread constraint in order to balance
+                        * the coupled voltages.
+                        */
+                       int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
+
+                       if (c_rdev_done[i])
+                               continue;
+
+                       ret = regulator_get_optimal_voltage(c_rdevs[i],
+                                                           &current_uV,
+                                                           &optimal_uV,
+                                                           &optimal_max_uV,
+                                                           state, n_coupled);
+                       if (ret < 0)
+                               goto out;
+
+                       delta = abs(optimal_uV - current_uV);
+
+                       if (delta && best_delta <= delta) {
+                               best_c_rdev_done = ret;
+                               best_delta = delta;
+                               best_rdev = c_rdevs[i];
+                               best_min_uV = optimal_uV;
+                               best_max_uV = optimal_max_uV;
+                               best_c_rdev = i;
+                       }
+               }
+
+               /* Nothing to change, return successfully */
+               if (!best_rdev) {
+                       ret = 0;
+                       goto out;
+               }
+
+               ret = regulator_set_voltage_rdev(best_rdev, best_min_uV,
+                                                best_max_uV, state);
+
+               if (ret < 0)
+                       goto out;
+
+               c_rdev_done[best_c_rdev] = best_c_rdev_done;
+
+       } while (n_coupled > 1);
+
+out:
        return ret;
 }
 
@@ -3146,14 +3728,15 @@ out2:
  */
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
 {
-       int ret = 0;
+       struct ww_acquire_ctx ww_ctx;
+       int ret;
 
-       regulator_lock_supply(regulator->rdev);
+       regulator_lock_dependent(regulator->rdev, &ww_ctx);
 
        ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
                                             PM_SUSPEND_ON);
 
-       regulator_unlock_supply(regulator->rdev);
+       regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
        return ret;
 }
@@ -3225,18 +3808,19 @@ static int _regulator_set_suspend_voltage(struct regulator *regulator,
 int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
                                  int max_uV, suspend_state_t state)
 {
-       int ret = 0;
+       struct ww_acquire_ctx ww_ctx;
+       int ret;
 
        /* PM_SUSPEND_ON is handled by regulator_set_voltage() */
        if (regulator_check_states(state) || state == PM_SUSPEND_ON)
                return -EINVAL;
 
-       regulator_lock_supply(regulator->rdev);
+       regulator_lock_dependent(regulator->rdev, &ww_ctx);
 
        ret = _regulator_set_suspend_voltage(regulator, min_uV,
                                             max_uV, state);
 
-       regulator_unlock_supply(regulator->rdev);
+       regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
        return ret;
 }
@@ -3426,13 +4010,12 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
  */
 int regulator_get_voltage(struct regulator *regulator)
 {
+       struct ww_acquire_ctx ww_ctx;
        int ret;
 
-       regulator_lock_supply(regulator->rdev);
-
+       regulator_lock_dependent(regulator->rdev, &ww_ctx);
        ret = _regulator_get_voltage(regulator->rdev);
-
-       regulator_unlock_supply(regulator->rdev);
+       regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
        return ret;
 }
@@ -3650,16 +4233,30 @@ EXPORT_SYMBOL_GPL(regulator_get_error_flags);
  * DRMS will sum the total requested load on the regulator and change
  * to the most efficient operating mode if platform constraints allow.
  *
+ * NOTE: when a regulator consumer requests to have a regulator
+ * disabled then any load that consumer requested no longer counts
+ * toward the total requested load.  If the regulator is re-enabled
+ * then the previously requested load will start counting again.
+ *
+ * If a regulator is an always-on regulator then an individual consumer's
+ * load will still be removed if that consumer is fully disabled.
+ *
  * On error a negative errno is returned.
  */
 int regulator_set_load(struct regulator *regulator, int uA_load)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       int ret;
+       int old_uA_load;
+       int ret = 0;
 
        regulator_lock(rdev);
+       old_uA_load = regulator->uA_load;
        regulator->uA_load = uA_load;
-       ret = drms_uA_update(rdev);
+       if (regulator->enable_count && old_uA_load != uA_load) {
+               ret = drms_uA_update(rdev);
+               if (ret < 0)
+                       regulator->uA_load = old_uA_load;
+       }
        regulator_unlock(rdev);
 
        return ret;
@@ -3830,11 +4427,8 @@ int regulator_bulk_enable(int num_consumers,
        int ret = 0;
 
        for (i = 0; i < num_consumers; i++) {
-               if (consumers[i].consumer->always_on)
-                       consumers[i].ret = 0;
-               else
-                       async_schedule_domain(regulator_bulk_enable_async,
-                                             &consumers[i], &async_domain);
+               async_schedule_domain(regulator_bulk_enable_async,
+                                     &consumers[i], &async_domain);
        }
 
        async_synchronize_full_domain(&async_domain);
@@ -3968,7 +4562,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
 {
-       lockdep_assert_held_once(&rdev->mutex);
+       lockdep_assert_held_once(&rdev->mutex.base);
 
        _notifier_call_chain(rdev, event, data);
        return NOTIFY_DONE;
@@ -4070,10 +4664,6 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_bypass.attr)
                return ops->get_bypass ? mode : 0;
 
-       /* some attributes are type-specific */
-       if (attr == &dev_attr_requested_microamps.attr)
-               return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
-
        /* constraints need specific supporting methods */
        if (attr == &dev_attr_min_microvolts.attr ||
            attr == &dev_attr_max_microvolts.attr)
@@ -4157,7 +4747,7 @@ static int regulator_register_resolve_supply(struct device *dev, void *data)
        return 0;
 }
 
-static int regulator_fill_coupling_array(struct regulator_dev *rdev)
+static void regulator_resolve_coupling(struct regulator_dev *rdev)
 {
        struct coupling_desc *c_desc = &rdev->coupling_desc;
        int n_coupled = c_desc->n_coupled;
@@ -4171,33 +4761,58 @@ static int regulator_fill_coupling_array(struct regulator_dev *rdev)
 
                c_rdev = of_parse_coupled_regulator(rdev, i - 1);
 
-               if (c_rdev) {
-                       c_desc->coupled_rdevs[i] = c_rdev;
-                       c_desc->n_resolved++;
-               }
-       }
+               if (!c_rdev)
+                       continue;
 
-       if (rdev->coupling_desc.n_resolved < n_coupled)
-               return -1;
-       else
-               return 0;
+               regulator_lock(c_rdev);
+
+               c_desc->coupled_rdevs[i] = c_rdev;
+               c_desc->n_resolved++;
+
+               regulator_unlock(c_rdev);
+
+               regulator_resolve_coupling(c_rdev);
+       }
 }
 
-static int regulator_register_fill_coupling_array(struct device *dev,
-                                                 void *data)
+static void regulator_remove_coupling(struct regulator_dev *rdev)
 {
-       struct regulator_dev *rdev = dev_to_rdev(dev);
+       struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc;
+       struct regulator_dev *__c_rdev, *c_rdev;
+       unsigned int __n_coupled, n_coupled;
+       int i, k;
 
-       if (!IS_ENABLED(CONFIG_OF))
-               return 0;
+       n_coupled = c_desc->n_coupled;
 
-       if (regulator_fill_coupling_array(rdev))
-               rdev_dbg(rdev, "unable to resolve coupling\n");
+       for (i = 1; i < n_coupled; i++) {
+               c_rdev = c_desc->coupled_rdevs[i];
 
-       return 0;
+               if (!c_rdev)
+                       continue;
+
+               regulator_lock(c_rdev);
+
+               __c_desc = &c_rdev->coupling_desc;
+               __n_coupled = __c_desc->n_coupled;
+
+               for (k = 1; k < __n_coupled; k++) {
+                       __c_rdev = __c_desc->coupled_rdevs[k];
+
+                       if (__c_rdev == rdev) {
+                               __c_desc->coupled_rdevs[k] = NULL;
+                               __c_desc->n_resolved--;
+                               break;
+                       }
+               }
+
+               regulator_unlock(c_rdev);
+
+               c_desc->coupled_rdevs[i] = NULL;
+               c_desc->n_resolved--;
+       }
 }
 
-static int regulator_resolve_coupling(struct regulator_dev *rdev)
+static int regulator_init_coupling(struct regulator_dev *rdev)
 {
        int n_phandles;
 
@@ -4237,13 +4852,6 @@ static int regulator_resolve_coupling(struct regulator_dev *rdev)
        if (!of_check_coupling_data(rdev))
                return -EPERM;
 
-       /*
-        * After everything has been checked, try to fill rdevs array
-        * with pointers to regulators parsed from device tree. If some
-        * regulators are not registered yet, retry in late init call
-        */
-       regulator_fill_coupling_array(rdev);
-
        return 0;
 }
 
@@ -4265,21 +4873,33 @@ regulator_register(const struct regulator_desc *regulator_desc,
        struct regulator_config *config = NULL;
        static atomic_t regulator_no = ATOMIC_INIT(-1);
        struct regulator_dev *rdev;
+       bool dangling_cfg_gpiod = false;
+       bool dangling_of_gpiod = false;
        struct device *dev;
        int ret, i;
 
-       if (regulator_desc == NULL || cfg == NULL)
+       if (cfg == NULL)
                return ERR_PTR(-EINVAL);
+       if (cfg->ena_gpiod)
+               dangling_cfg_gpiod = true;
+       if (regulator_desc == NULL) {
+               ret = -EINVAL;
+               goto rinse;
+       }
 
        dev = cfg->dev;
        WARN_ON(!dev);
 
-       if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
-               return ERR_PTR(-EINVAL);
+       if (regulator_desc->name == NULL || regulator_desc->ops == NULL) {
+               ret = -EINVAL;
+               goto rinse;
+       }
 
        if (regulator_desc->type != REGULATOR_VOLTAGE &&
-           regulator_desc->type != REGULATOR_CURRENT)
-               return ERR_PTR(-EINVAL);
+           regulator_desc->type != REGULATOR_CURRENT) {
+               ret = -EINVAL;
+               goto rinse;
+       }
 
        /* Only one of each should be implemented */
        WARN_ON(regulator_desc->ops->get_voltage &&
@@ -4290,16 +4910,20 @@ regulator_register(const struct regulator_desc *regulator_desc,
        /* If we're using selectors we must implement list_voltage. */
        if (regulator_desc->ops->get_voltage_sel &&
            !regulator_desc->ops->list_voltage) {
-               return ERR_PTR(-EINVAL);
+               ret = -EINVAL;
+               goto rinse;
        }
        if (regulator_desc->ops->set_voltage_sel &&
            !regulator_desc->ops->list_voltage) {
-               return ERR_PTR(-EINVAL);
+               ret = -EINVAL;
+               goto rinse;
        }
 
        rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
-       if (rdev == NULL)
-               return ERR_PTR(-ENOMEM);
+       if (rdev == NULL) {
+               ret = -ENOMEM;
+               goto rinse;
+       }
 
        /*
         * Duplicate the config so the driver could override it after
@@ -4308,17 +4932,28 @@ regulator_register(const struct regulator_desc *regulator_desc,
        config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
        if (config == NULL) {
                kfree(rdev);
-               return ERR_PTR(-ENOMEM);
+               ret = -ENOMEM;
+               goto rinse;
        }
 
        init_data = regulator_of_get_init_data(dev, regulator_desc, config,
                                               &rdev->dev.of_node);
+       /*
+        * We need to keep track of any GPIO descriptor coming from the
+        * device tree until we have handled it over to the core. If the
+        * config that was passed in to this function DOES NOT contain
+        * a descriptor, and the config after this call DOES contain
+        * a descriptor, we definately got one from parsing the device
+        * tree.
+        */
+       if (!cfg->ena_gpiod && config->ena_gpiod)
+               dangling_of_gpiod = true;
        if (!init_data) {
                init_data = config->init_data;
                rdev->dev.of_node = of_node_get(config->of_node);
        }
 
-       mutex_init(&rdev->mutex);
+       ww_mutex_init(&rdev->mutex, &regulator_ww_class);
        rdev->reg_data = config->driver_data;
        rdev->owner = regulator_desc->owner;
        rdev->desc = regulator_desc;
@@ -4351,6 +4986,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
                                 config->ena_gpio, ret);
                        goto clean;
                }
+               /* The regulator core took over the GPIO descriptor */
+               dangling_cfg_gpiod = false;
+               dangling_of_gpiod = false;
        }
 
        /* register with sysfs */
@@ -4380,11 +5018,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
        if (ret < 0)
                goto wash;
 
-       mutex_lock(&regulator_list_mutex);
-       ret = regulator_resolve_coupling(rdev);
-       mutex_unlock(&regulator_list_mutex);
-
-       if (ret != 0)
+       ret = regulator_init_coupling(rdev);
+       if (ret < 0)
                goto wash;
 
        /* add consumers devices */
@@ -4418,6 +5053,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        rdev_init_debugfs(rdev);
 
+       /* try to resolve regulators coupling since a new one was registered */
+       mutex_lock(&regulator_list_mutex);
+       regulator_resolve_coupling(rdev);
+       mutex_unlock(&regulator_list_mutex);
+
        /* try to resolve regulators supply since a new one was registered */
        class_for_each_device(&regulator_class, NULL, NULL,
                              regulator_register_resolve_supply);
@@ -4434,8 +5074,13 @@ wash:
        regulator_ena_gpio_free(rdev);
        mutex_unlock(&regulator_list_mutex);
 clean:
+       if (dangling_of_gpiod)
+               gpiod_put(config->ena_gpiod);
        kfree(rdev);
        kfree(config);
+rinse:
+       if (dangling_cfg_gpiod)
+               gpiod_put(cfg->ena_gpiod);
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(regulator_register);
@@ -4456,15 +5101,19 @@ void regulator_unregister(struct regulator_dev *rdev)
                        regulator_disable(rdev->supply);
                regulator_put(rdev->supply);
        }
+
        mutex_lock(&regulator_list_mutex);
+
        debugfs_remove_recursive(rdev->debugfs);
        flush_work(&rdev->disable_work.work);
        WARN_ON(rdev->open_count);
+       regulator_remove_coupling(rdev);
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        regulator_ena_gpio_free(rdev);
-       mutex_unlock(&regulator_list_mutex);
        device_unregister(&rdev->dev);
+
+       mutex_unlock(&regulator_list_mutex);
 }
 EXPORT_SYMBOL_GPL(regulator_unregister);
 
@@ -4621,23 +5270,8 @@ static int supply_map_show(struct seq_file *sf, void *data)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(supply_map);
 
-static int supply_map_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, supply_map_show, inode->i_private);
-}
-#endif
-
-static const struct file_operations supply_map_fops = {
-#ifdef CONFIG_DEBUG_FS
-       .open = supply_map_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-#endif
-};
-
-#ifdef CONFIG_DEBUG_FS
 struct summary_data {
        struct seq_file *s;
        struct regulator_dev *parent;
@@ -4672,8 +5306,6 @@ static void regulator_summary_show_subtree(struct seq_file *s,
        if (!rdev)
                return;
 
-       regulator_lock_nested(rdev, level);
-
        opmode = _regulator_get_mode_unlocked(rdev);
        seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
                   level * 3 + 1, "",
@@ -4712,8 +5344,11 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 
                switch (rdev->desc->type) {
                case REGULATOR_VOLTAGE:
-                       seq_printf(s, "%37dmA %5dmV %5dmV",
+                       seq_printf(s, "%3d %33dmA%c%5dmV %5dmV",
+                                  consumer->enable_count,
                                   consumer->uA_load / 1000,
+                                  consumer->uA_load && !consumer->enable_count ?
+                                  '*' : ' ',
                                   consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
                                   consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
                        break;
@@ -4730,8 +5365,105 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 
        class_for_each_device(&regulator_class, NULL, &summary_data,
                              regulator_summary_show_children);
+}
+
+struct summary_lock_data {
+       struct ww_acquire_ctx *ww_ctx;
+       struct regulator_dev **new_contended_rdev;
+       struct regulator_dev **old_contended_rdev;
+};
+
+static int regulator_summary_lock_one(struct device *dev, void *data)
+{
+       struct regulator_dev *rdev = dev_to_rdev(dev);
+       struct summary_lock_data *lock_data = data;
+       int ret = 0;
+
+       if (rdev != *lock_data->old_contended_rdev) {
+               ret = regulator_lock_nested(rdev, lock_data->ww_ctx);
+
+               if (ret == -EDEADLK)
+                       *lock_data->new_contended_rdev = rdev;
+               else
+                       WARN_ON_ONCE(ret);
+       } else {
+               *lock_data->old_contended_rdev = NULL;
+       }
+
+       return ret;
+}
+
+static int regulator_summary_unlock_one(struct device *dev, void *data)
+{
+       struct regulator_dev *rdev = dev_to_rdev(dev);
+       struct summary_lock_data *lock_data = data;
+
+       if (lock_data) {
+               if (rdev == *lock_data->new_contended_rdev)
+                       return -EDEADLK;
+       }
 
        regulator_unlock(rdev);
+
+       return 0;
+}
+
+static int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx,
+                                     struct regulator_dev **new_contended_rdev,
+                                     struct regulator_dev **old_contended_rdev)
+{
+       struct summary_lock_data lock_data;
+       int ret;
+
+       lock_data.ww_ctx = ww_ctx;
+       lock_data.new_contended_rdev = new_contended_rdev;
+       lock_data.old_contended_rdev = old_contended_rdev;
+
+       ret = class_for_each_device(&regulator_class, NULL, &lock_data,
+                                   regulator_summary_lock_one);
+       if (ret)
+               class_for_each_device(&regulator_class, NULL, &lock_data,
+                                     regulator_summary_unlock_one);
+
+       return ret;
+}
+
+static void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx)
+{
+       struct regulator_dev *new_contended_rdev = NULL;
+       struct regulator_dev *old_contended_rdev = NULL;
+       int err;
+
+       mutex_lock(&regulator_list_mutex);
+
+       ww_acquire_init(ww_ctx, &regulator_ww_class);
+
+       do {
+               if (new_contended_rdev) {
+                       ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+                       old_contended_rdev = new_contended_rdev;
+                       old_contended_rdev->ref_cnt++;
+               }
+
+               err = regulator_summary_lock_all(ww_ctx,
+                                                &new_contended_rdev,
+                                                &old_contended_rdev);
+
+               if (old_contended_rdev)
+                       regulator_unlock(old_contended_rdev);
+
+       } while (err == -EDEADLK);
+
+       ww_acquire_done(ww_ctx);
+}
+
+static void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx)
+{
+       class_for_each_device(&regulator_class, NULL, NULL,
+                             regulator_summary_unlock_one);
+       ww_acquire_fini(ww_ctx);
+
+       mutex_unlock(&regulator_list_mutex);
 }
 
 static int regulator_summary_show_roots(struct device *dev, void *data)
@@ -4747,29 +5479,22 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
 
 static int regulator_summary_show(struct seq_file *s, void *data)
 {
+       struct ww_acquire_ctx ww_ctx;
+
        seq_puts(s, " regulator                      use open bypass  opmode voltage current     min     max\n");
        seq_puts(s, "---------------------------------------------------------------------------------------\n");
 
+       regulator_summary_lock(&ww_ctx);
+
        class_for_each_device(&regulator_class, NULL, s,
                              regulator_summary_show_roots);
 
-       return 0;
-}
+       regulator_summary_unlock(&ww_ctx);
 
-static int regulator_summary_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, regulator_summary_show, inode->i_private);
+       return 0;
 }
-#endif
-
-static const struct file_operations regulator_summary_fops = {
-#ifdef CONFIG_DEBUG_FS
-       .open           = regulator_summary_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-#endif
-};
+DEFINE_SHOW_ATTRIBUTE(regulator_summary);
+#endif /* CONFIG_DEBUG_FS */
 
 static int __init regulator_init(void)
 {
@@ -4781,12 +5506,13 @@ static int __init regulator_init(void)
        if (!debugfs_root)
                pr_warn("regulator: Failed to create debugfs directory\n");
 
+#ifdef CONFIG_DEBUG_FS
        debugfs_create_file("supply_map", 0444, debugfs_root, NULL,
                            &supply_map_fops);
 
        debugfs_create_file("regulator_summary", 0444, debugfs_root,
                            NULL, &regulator_summary_fops);
-
+#endif
        regulator_dummy_init();
 
        return ret;
@@ -4873,9 +5599,6 @@ static int __init regulator_init_complete(void)
        class_for_each_device(&regulator_class, NULL, NULL,
                              regulator_late_cleanup);
 
-       class_for_each_device(&regulator_class, NULL, NULL,
-                             regulator_register_fill_coupling_array);
-
        return 0;
 }
 late_initcall_sync(regulator_init_complete);
index 37e4025203e34949c42edeb09378caa06d7f4ddc..207cb3859dcc664229dc2d39c592dea82f0a1dde 100644 (file)
@@ -435,7 +435,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
                        return -ENODEV;
 
                for_each_child_of_node(nproot, np) {
-                       if (!of_node_cmp(np->name,
+                       if (of_node_name_eq(np,
                                         regulator->info->reg_desc.name)) {
                                config.init_data = of_get_regulator_init_data(
                                        &pdev->dev, np,
index d0496d6b09346b555c95b74e605aee0663c0dc10..84dba64ed11ecafd28d21c14d243519bc2633ef2 100644 (file)
@@ -131,7 +131,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
        if (error < 0)
                goto error_i2c;
 
-       mutex_lock(&chip->rdev->mutex);
+       regulator_lock(chip->rdev);
 
        if (val & DA9210_E_OVCURR) {
                regulator_notifier_call_chain(chip->rdev,
@@ -157,7 +157,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
                handled |= DA9210_E_VMAX;
        }
 
-       mutex_unlock(&chip->rdev->mutex);
+       regulator_unlock(chip->rdev);
 
        if (handled) {
                /* Clear handled events */
index 8f68c7a05d27968970287c8811f5e1764c1ad859..109ee12d43626ce2822ba872c252000bf3e7cea1 100644 (file)
@@ -389,6 +389,12 @@ static int da9211_regulator_init(struct da9211 *chip)
                else
                        config.ena_gpiod = NULL;
 
+               /*
+                * Hand the GPIO descriptor management over to the regulator
+                * core, remove it from GPIO devres management.
+                */
+               if (config.ena_gpiod)
+                       devm_gpiod_unhinge(chip->dev, config.ena_gpiod);
                chip->rdev[i] = devm_regulator_register(chip->dev,
                        &da9211_regulators[i], &config);
                if (IS_ERR(chip->rdev[i])) {
index 8976141c1438acf9ff4d4caa0bdcb17808d4374b..308e3ff0a1bd7c2af231b22e93e9d8f3a6cd1bda 100644 (file)
@@ -75,7 +75,7 @@ static struct ux500_regulator_debug {
        u8 *state_after_suspend;
 } rdebug;
 
-static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
+static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p)
 {
        /* print power state count */
        seq_printf(s, "ux500-regulator power state count: %i\n",
@@ -83,23 +83,9 @@ static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
 
        return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt);
 
-static int ux500_regulator_power_state_cnt_open(struct inode *inode,
-       struct file *file)
-{
-       return single_open(file, ux500_regulator_power_state_cnt_print,
-               inode->i_private);
-}
-
-static const struct file_operations ux500_regulator_power_state_cnt_fops = {
-       .open = ux500_regulator_power_state_cnt_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
-};
-
-static int ux500_regulator_status_print(struct seq_file *s, void *p)
+static int ux500_regulator_status_show(struct seq_file *s, void *p)
 {
        int i;
 
@@ -122,20 +108,7 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
 
        return 0;
 }
-
-static int ux500_regulator_status_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ux500_regulator_status_print,
-               inode->i_private);
-}
-
-static const struct file_operations ux500_regulator_status_fops = {
-       .open = ux500_regulator_status_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status);
 
 int __attribute__((weak)) dbx500_regulator_testcase(
        struct dbx500_regulator_info *regulator_info,
index ccc29038f19a98c8d7b292ab60536cc616345c0a..9abdb91307662a8abf5a64e2d52c023180755231 100644 (file)
@@ -183,7 +183,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
         */
        gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
 
-       cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
+       /*
+        * Do not use devm* here: the regulator core takes over the
+        * lifecycle management of the GPIO descriptor.
+        */
+       cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
        if (IS_ERR(cfg.ena_gpiod))
                return PTR_ERR(cfg.ena_gpiod);
 
index 943926a156f201f8e28e5bd6a9fd2905f950127d..6017f15c5d751047734cd1dbab5df3bb30d7e2f0 100644 (file)
@@ -42,6 +42,8 @@ struct regulator {
        unsigned int always_on:1;
        unsigned int bypass:1;
        int uA_load;
+       unsigned int enable_count;
+       unsigned int deferred_disables;
        struct regulator_voltage voltage[REGULATOR_STATES_NUM];
        const char *supply_name;
        struct device_attribute dev_attr;
index bbedb08d257b602e884ff1827422215302b0011c..8c0e8419c43f08a75239bcd580f7f65aa2dcd420 100644 (file)
@@ -224,13 +224,15 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
        /*
         * Check LCM_EN1/2_GPIO is configured.
         * Those pins are used for enabling VPOS/VNEG LDOs.
+        * Do not use devm* here: the regulator core takes over the
+        * lifecycle management of the GPIO descriptor.
         */
        switch (id) {
        case LM3632_LDO_POS:
-               return devm_gpiod_get_index_optional(dev, "enable", 0,
+               return gpiod_get_index_optional(dev, "enable", 0,
                                GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        case LM3632_LDO_NEG:
-               return devm_gpiod_get_index_optional(dev, "enable", 1,
+               return gpiod_get_index_optional(dev, "enable", 1,
                                GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
        default:
                return NULL;
@@ -263,6 +265,8 @@ static int lm363x_regulator_probe(struct platform_device *pdev)
                                         LM3632_EXT_EN_MASK,
                                         LM3632_EXT_EN_MASK);
                if (ret) {
+                       if (gpiod)
+                               gpiod_put(gpiod);
                        dev_err(dev, "External pin err: %d\n", ret);
                        return ret;
                }
index 2b5073b9ff868f441bcd152ea2d130fb8d74b74d..5a89e6d4b9a6bd51925d374a434614d159c69dd2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
@@ -20,6 +21,8 @@
 #include <linux/regulator/of_regulator.h>
 
 #include <linux/mfd/lochnagar.h>
+#include <linux/mfd/lochnagar1_regs.h>
+#include <linux/mfd/lochnagar2_regs.h>
 
 static const struct regulator_ops lochnagar_micvdd_ops = {
        .enable = regulator_enable_regmap,
@@ -212,28 +215,52 @@ static const struct regulator_desc lochnagar_regulators[] = {
        },
 };
 
+static const struct of_device_id lochnagar_of_match[] = {
+       {
+               .compatible = "cirrus,lochnagar2-micvdd",
+               .data = &lochnagar_regulators[LOCHNAGAR_MICVDD],
+       },
+       {
+               .compatible = "cirrus,lochnagar2-mic1vdd",
+               .data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
+       },
+       {
+               .compatible = "cirrus,lochnagar2-mic2vdd",
+               .data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
+       },
+       {
+               .compatible = "cirrus,lochnagar2-vddcore",
+               .data = &lochnagar_regulators[LOCHNAGAR_VDDCORE],
+       },
+       {},
+};
+
 static int lochnagar_regulator_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
        struct regulator_config config = { };
+       const struct of_device_id *of_id;
+       const struct regulator_desc *desc;
        struct regulator_dev *rdev;
-       int ret, i;
+       int ret;
 
-       config.dev = lochnagar->dev;
+       config.dev = dev;
        config.regmap = lochnagar->regmap;
        config.driver_data = lochnagar;
 
-       for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
-               const struct regulator_desc *desc = &lochnagar_regulators[i];
+       of_id = of_match_device(lochnagar_of_match, dev);
+       if (!of_id)
+               return -EINVAL;
 
-               rdev = devm_regulator_register(dev, desc, &config);
-               if (IS_ERR(rdev)) {
-                       ret = PTR_ERR(rdev);
-                       dev_err(dev, "Failed to register %s regulator: %d\n",
-                               desc->name, ret);
-                       return ret;
-               }
+       desc = of_id->data;
+
+       rdev = devm_regulator_register(dev, desc, &config);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(dev, "Failed to register %s regulator: %d\n",
+                       desc->name, ret);
+               return ret;
        }
 
        return 0;
@@ -242,6 +269,7 @@ static int lochnagar_regulator_probe(struct platform_device *pdev)
 static struct platform_driver lochnagar_regulator_driver = {
        .driver = {
                .name = "lochnagar-regulator",
+               .of_match_table = of_match_ptr(lochnagar_of_match),
        },
 
        .probe = lochnagar_regulator_probe,
index 553b4790050f6650a525155b64ccd4cc3c71a6e9..2ee22e7ea675671a6348f0c2c2eb413a8e0fa330 100644 (file)
@@ -501,8 +501,12 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
                return 0;
        }
 
-       /* FIXME: check default mode for GPIO here: high or low? */
-       ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
+       /*
+        * Do not use devm* here: the regulator core takes over the
+        * lifecycle management of the GPIO descriptor.
+        * FIXME: check default mode for GPIO here: high or low?
+        */
+       ldo->ena_gpiod = gpiod_get_index_optional(&pdev->dev,
                                               "enable",
                                               enable_id,
                                               GPIOD_OUT_HIGH |
index bee060937f56080709e235bb4ebe5c1b494c681d..8020eb57374a1b32d3a1c322483c5a0bb308c514 100644 (file)
@@ -11,8 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/bug.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
@@ -76,6 +75,7 @@ enum max77686_ramp_rate {
 };
 
 struct max77686_data {
+       struct device *dev;
        DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
 
        /* Array indexed by regulator id */
@@ -250,26 +250,34 @@ static int max77686_of_parse_cb(struct device_node *np,
                struct regulator_config *config)
 {
        struct max77686_data *max77686 = config->driver_data;
+       int ret;
 
        switch (desc->id) {
        case MAX77686_BUCK8:
        case MAX77686_BUCK9:
        case MAX77686_LDO20 ... MAX77686_LDO22:
-               config->ena_gpio = of_get_named_gpio(np,
-                                       "maxim,ena-gpios", 0);
-               config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
-               config->ena_gpio_initialized = true;
+               config->ena_gpiod = gpiod_get_from_of_node(np,
+                               "maxim,ena",
+                               0,
+                               GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+                               "max77686-regulator");
+               if (IS_ERR(config->ena_gpiod))
+                       config->ena_gpiod = NULL;
                break;
        default:
                return 0;
        }
 
-       if (gpio_is_valid(config->ena_gpio)) {
+       if (config->ena_gpiod) {
                set_bit(desc->id, max77686->gpio_enabled);
 
-               return regmap_update_bits(config->regmap, desc->enable_reg,
-                                         desc->enable_mask,
-                                         MAX77686_GPIO_CONTROL);
+               ret = regmap_update_bits(config->regmap, desc->enable_reg,
+                                        desc->enable_mask,
+                                        MAX77686_GPIO_CONTROL);
+               if (ret) {
+                       gpiod_put(config->ena_gpiod);
+                       config->ena_gpiod = NULL;
+               }
        }
 
        return 0;
@@ -507,6 +515,7 @@ static int max77686_pmic_probe(struct platform_device *pdev)
        if (!max77686)
                return -ENOMEM;
 
+       max77686->dev = &pdev->dev;
        config.dev = iodev->dev;
        config.regmap = iodev->regmap;
        config.driver_data = max77686;
index 6c39fff73b8acd61c57cb3fc7fc13c3af7a64bdc..cf2a2912cb1bcdeebc00c4c711c732acc9469f9a 100644 (file)
@@ -231,9 +231,13 @@ static int max8952_pmic_probe(struct i2c_client *client,
        else
                gflags = GPIOD_OUT_LOW;
        gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
-       gpiod = devm_gpiod_get_optional(&client->dev,
-                                       "max8952,en",
-                                       gflags);
+       /*
+        * Do not use devm* here: the regulator core takes over the
+        * lifecycle management of the GPIO descriptor.
+        */
+       gpiod = gpiod_get_optional(&client->dev,
+                                  "max8952,en",
+                                  gflags);
        if (IS_ERR(gpiod))
                return PTR_ERR(gpiod);
        if (gpiod)
index e7a58b50903203f81b669b5fa2b51031d574a090..9aee1444181dad29b9f21e980292996e62632706 100644 (file)
@@ -808,7 +808,13 @@ static int max8973_probe(struct i2c_client *client,
        config.of_node = client->dev.of_node;
        config.regmap = max->regmap;
 
-       /* Register the regulators */
+       /*
+        * Register the regulators
+        * Turn the GPIO descriptor over to the regulator core for
+        * lifecycle management if we pass an ena_gpiod.
+        */
+       if (config.ena_gpiod)
+               devm_gpiod_unhinge(&client->dev, config.ena_gpiod);
        rdev = devm_regulator_register(&client->dev, &max->desc, &config);
        if (IS_ERR(rdev)) {
                ret = PTR_ERR(rdev);
index 3bf5ddfaaea89d0cbebc5e70588759a8aa5b7d1a..4d2487279a0a01bb93e3d901397458358459166c 100644 (file)
@@ -925,7 +925,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
        pdata->regulators = rdata;
        for_each_child_of_node(regulators_np, reg_np) {
                for (i = 0; i < ARRAY_SIZE(regulators); i++)
-                       if (!of_node_cmp(reg_np->name, regulators[i].name))
+                       if (of_node_name_eq(reg_np, regulators[i].name))
                                break;
 
                if (i == ARRAY_SIZE(regulators)) {
index 65eb1e0350cfd3dc3f6df6d167bcf5e70a52fa2c..2243138d8a58062821a401ac518c3b2ef1f2bd84 100644 (file)
@@ -186,7 +186,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
                for (i = 0; i < num_regulators; i++) {
                        if (!regulators[i].desc.name)
                                continue;
-                       if (!of_node_cmp(child->name,
+                       if (of_node_name_eq(child,
                                         regulators[i].desc.name)) {
                                p->id = i;
                                p->init_data = of_get_regulator_init_data(
diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c
new file mode 100644 (file)
index 0000000..3479ae0
--- /dev/null
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MCP16502 PMIC driver
+//
+// Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries
+//
+// Author: Andrei Stefanescu <andrei.stefanescu@microchip.com>
+//
+// Inspired from tps65086-regulator.c
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/suspend.h>
+
+#define VDD_LOW_SEL 0x0D
+#define VDD_HIGH_SEL 0x3F
+
+#define MCP16502_FLT BIT(7)
+#define MCP16502_ENS BIT(0)
+
+/*
+ * The PMIC has four sets of registers corresponding to four power modes:
+ * Performance, Active, Low-power, Hibernate.
+ *
+ * Registers:
+ * Each regulator has a register for each power mode. To access a register
+ * for a specific regulator and mode BASE_* and OFFSET_* need to be added.
+ *
+ * Operating modes:
+ * In order for the PMIC to transition to operating modes it has to be
+ * controlled via GPIO lines called LPM and HPM.
+ *
+ * The registers are fully configurable such that you can put all regulators in
+ * a low-power state while the PMIC is in Active mode. They are supposed to be
+ * configured at startup and then simply transition to/from a global low-power
+ * state by setting the GPIO lpm pin high/low.
+ *
+ * This driver keeps the PMIC in Active mode, Low-power state is set for the
+ * regulators by enabling/disabling operating mode (FPWM or Auto PFM).
+ *
+ * The PMIC's Low-power and Hibernate modes are used during standby/suspend.
+ * To enter standby/suspend the PMIC will go to Low-power mode. From there, it
+ * will transition to Hibernate when the PWRHLD line is set to low by the MPU.
+ */
+
+/*
+ * This function is useful for iterating over all regulators and accessing their
+ * registers in a generic way or accessing a regulator device by its id.
+ */
+#define MCP16502_BASE(i) (((i) + 1) << 4)
+#define MCP16502_STAT_BASE(i) ((i) + 5)
+
+#define MCP16502_OFFSET_MODE_A 0
+#define MCP16502_OFFSET_MODE_LPM 1
+#define MCP16502_OFFSET_MODE_HIB 2
+
+#define MCP16502_OPMODE_ACTIVE REGULATOR_MODE_NORMAL
+#define MCP16502_OPMODE_LPM REGULATOR_MODE_IDLE
+#define MCP16502_OPMODE_HIB REGULATOR_MODE_STANDBY
+
+#define MCP16502_MODE_AUTO_PFM 0
+#define MCP16502_MODE_FPWM BIT(6)
+
+#define MCP16502_VSEL 0x3F
+#define MCP16502_EN BIT(7)
+#define MCP16502_MODE BIT(6)
+
+#define MCP16502_MIN_REG 0x0
+#define MCP16502_MAX_REG 0x65
+
+static unsigned int mcp16502_of_map_mode(unsigned int mode)
+{
+       if (mode == REGULATOR_MODE_NORMAL || mode == REGULATOR_MODE_IDLE)
+               return mode;
+
+       return REGULATOR_MODE_INVALID;
+}
+
+#define MCP16502_REGULATOR(_name, _id, _ranges, _ops)                  \
+       [_id] = {                                                       \
+               .name                   = _name,                        \
+               .regulators_node        = of_match_ptr("regulators"),   \
+               .id                     = _id,                          \
+               .ops                    = &(_ops),                      \
+               .type                   = REGULATOR_VOLTAGE,            \
+               .owner                  = THIS_MODULE,                  \
+               .n_voltages             = MCP16502_VSEL + 1,            \
+               .linear_ranges          = _ranges,                      \
+               .n_linear_ranges        = ARRAY_SIZE(_ranges),          \
+               .of_match               = of_match_ptr(_name),          \
+               .of_map_mode            = mcp16502_of_map_mode,         \
+               .vsel_reg               = (((_id) + 1) << 4),           \
+               .vsel_mask              = MCP16502_VSEL,                \
+               .enable_reg             = (((_id) + 1) << 4),           \
+               .enable_mask            = MCP16502_EN,                  \
+       }
+
+enum {
+       BUCK1 = 0,
+       BUCK2,
+       BUCK3,
+       BUCK4,
+       LDO1,
+       LDO2,
+       NUM_REGULATORS
+};
+
+/*
+ * struct mcp16502 - PMIC representation
+ * @rdev: the regulators belonging to this chip
+ * @rmap: regmap to be used for I2C communication
+ * @lpm: LPM GPIO descriptor
+ */
+struct mcp16502 {
+       struct regulator_dev *rdev[NUM_REGULATORS];
+       struct regmap *rmap;
+       struct gpio_desc *lpm;
+};
+
+/*
+ * mcp16502_gpio_set_mode() - set the GPIO corresponding value
+ *
+ * Used to prepare transitioning into hibernate or resuming from it.
+ */
+static void mcp16502_gpio_set_mode(struct mcp16502 *mcp, int mode)
+{
+       switch (mode) {
+       case MCP16502_OPMODE_ACTIVE:
+               gpiod_set_value(mcp->lpm, 0);
+               break;
+       case MCP16502_OPMODE_LPM:
+       case MCP16502_OPMODE_HIB:
+               gpiod_set_value(mcp->lpm, 1);
+               break;
+       default:
+               pr_err("%s: %d invalid\n", __func__, mode);
+       }
+}
+
+/*
+ * mcp16502_get_reg() - get the PMIC's configuration register for opmode
+ *
+ * @rdev: the regulator whose register we are searching
+ * @opmode: the PMIC's operating mode ACTIVE, Low-power, Hibernate
+ */
+static int mcp16502_get_reg(struct regulator_dev *rdev, int opmode)
+{
+       int reg = MCP16502_BASE(rdev_get_id(rdev));
+
+       switch (opmode) {
+       case MCP16502_OPMODE_ACTIVE:
+               return reg + MCP16502_OFFSET_MODE_A;
+       case MCP16502_OPMODE_LPM:
+               return reg + MCP16502_OFFSET_MODE_LPM;
+       case MCP16502_OPMODE_HIB:
+               return reg + MCP16502_OFFSET_MODE_HIB;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * mcp16502_get_mode() - return the current operating mode of a regulator
+ *
+ * Note: all functions that are not part of entering/exiting standby/suspend
+ *      use the Active mode registers.
+ *
+ * Note: this is different from the PMIC's operatig mode, it is the
+ *      MODE bit from the regulator's register.
+ */
+static unsigned int mcp16502_get_mode(struct regulator_dev *rdev)
+{
+       unsigned int val;
+       int ret, reg;
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+
+       reg = mcp16502_get_reg(rdev, MCP16502_OPMODE_ACTIVE);
+       if (reg < 0)
+               return reg;
+
+       ret = regmap_read(mcp->rmap, reg, &val);
+       if (ret)
+               return ret;
+
+       switch (val & MCP16502_MODE) {
+       case MCP16502_MODE_FPWM:
+               return REGULATOR_MODE_NORMAL;
+       case MCP16502_MODE_AUTO_PFM:
+               return REGULATOR_MODE_IDLE;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+/*
+ * _mcp16502_set_mode() - helper for set_mode and set_suspend_mode
+ *
+ * @rdev: the regulator for which we are setting the mode
+ * @mode: the regulator's mode (the one from MODE bit)
+ * @opmode: the PMIC's operating mode: Active/Low-power/Hibernate
+ */
+static int _mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode,
+                             unsigned int op_mode)
+{
+       int val;
+       int reg;
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+
+       reg = mcp16502_get_reg(rdev, op_mode);
+       if (reg < 0)
+               return reg;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               val = MCP16502_MODE_FPWM;
+               break;
+       case REGULATOR_MODE_IDLE:
+               val = MCP16502_MODE_AUTO_PFM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       reg = regmap_update_bits(mcp->rmap, reg, MCP16502_MODE, val);
+       return reg;
+}
+
+/*
+ * mcp16502_set_mode() - regulator_ops set_mode
+ */
+static int mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_ACTIVE);
+}
+
+/*
+ * mcp16502_get_status() - regulator_ops get_status
+ */
+static int mcp16502_get_status(struct regulator_dev *rdev)
+{
+       int ret;
+       unsigned int val;
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(mcp->rmap, MCP16502_STAT_BASE(rdev_get_id(rdev)),
+                         &val);
+       if (ret)
+               return ret;
+
+       if (val & MCP16502_FLT)
+               return REGULATOR_STATUS_ERROR;
+       else if (val & MCP16502_ENS)
+               return REGULATOR_STATUS_ON;
+       else if (!(val & MCP16502_ENS))
+               return REGULATOR_STATUS_OFF;
+
+       return REGULATOR_STATUS_UNDEFINED;
+}
+
+#ifdef CONFIG_SUSPEND
+/*
+ * mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC
+ *                                    mode
+ */
+static int mcp16502_suspend_get_target_reg(struct regulator_dev *rdev)
+{
+       switch (pm_suspend_target_state) {
+       case PM_SUSPEND_STANDBY:
+               return mcp16502_get_reg(rdev, MCP16502_OPMODE_LPM);
+       case PM_SUSPEND_ON:
+       case PM_SUSPEND_MEM:
+               return mcp16502_get_reg(rdev, MCP16502_OPMODE_HIB);
+       default:
+               dev_err(&rdev->dev, "invalid suspend target: %d\n",
+                       pm_suspend_target_state);
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * mcp16502_set_suspend_voltage() - regulator_ops set_suspend_voltage
+ */
+static int mcp16502_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+       int sel = regulator_map_voltage_linear_range(rdev, uV, uV);
+       int reg = mcp16502_suspend_get_target_reg(rdev);
+
+       if (sel < 0)
+               return sel;
+
+       if (reg < 0)
+               return reg;
+
+       return regmap_update_bits(mcp->rmap, reg, MCP16502_VSEL, sel);
+}
+
+/*
+ * mcp16502_set_suspend_mode() - regulator_ops set_suspend_mode
+ */
+static int mcp16502_set_suspend_mode(struct regulator_dev *rdev,
+                                    unsigned int mode)
+{
+       switch (pm_suspend_target_state) {
+       case PM_SUSPEND_STANDBY:
+               return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_LPM);
+       case PM_SUSPEND_ON:
+       case PM_SUSPEND_MEM:
+               return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_HIB);
+       default:
+               dev_err(&rdev->dev, "invalid suspend target: %d\n",
+                       pm_suspend_target_state);
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * mcp16502_set_suspend_enable() - regulator_ops set_suspend_enable
+ */
+static int mcp16502_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+       int reg = mcp16502_suspend_get_target_reg(rdev);
+
+       if (reg < 0)
+               return reg;
+
+       return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, MCP16502_EN);
+}
+
+/*
+ * mcp16502_set_suspend_disable() - regulator_ops set_suspend_disable
+ */
+static int mcp16502_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct mcp16502 *mcp = rdev_get_drvdata(rdev);
+       int reg = mcp16502_suspend_get_target_reg(rdev);
+
+       if (reg < 0)
+               return reg;
+
+       return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, 0);
+}
+#endif /* CONFIG_SUSPEND */
+
+static const struct regulator_ops mcp16502_buck_ops = {
+       .list_voltage                   = regulator_list_voltage_linear_range,
+       .map_voltage                    = regulator_map_voltage_linear_range,
+       .get_voltage_sel                = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel                = regulator_set_voltage_sel_regmap,
+       .enable                         = regulator_enable_regmap,
+       .disable                        = regulator_disable_regmap,
+       .is_enabled                     = regulator_is_enabled_regmap,
+       .get_status                     = mcp16502_get_status,
+
+       .set_mode                       = mcp16502_set_mode,
+       .get_mode                       = mcp16502_get_mode,
+
+#ifdef CONFIG_SUSPEND
+       .set_suspend_voltage            = mcp16502_set_suspend_voltage,
+       .set_suspend_mode               = mcp16502_set_suspend_mode,
+       .set_suspend_enable             = mcp16502_set_suspend_enable,
+       .set_suspend_disable            = mcp16502_set_suspend_disable,
+#endif /* CONFIG_SUSPEND */
+};
+
+/*
+ * LDOs cannot change operating modes.
+ */
+static const struct regulator_ops mcp16502_ldo_ops = {
+       .list_voltage                   = regulator_list_voltage_linear_range,
+       .map_voltage                    = regulator_map_voltage_linear_range,
+       .get_voltage_sel                = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel                = regulator_set_voltage_sel_regmap,
+       .enable                         = regulator_enable_regmap,
+       .disable                        = regulator_disable_regmap,
+       .is_enabled                     = regulator_is_enabled_regmap,
+       .get_status                     = mcp16502_get_status,
+
+#ifdef CONFIG_SUSPEND
+       .set_suspend_voltage            = mcp16502_set_suspend_voltage,
+       .set_suspend_enable             = mcp16502_set_suspend_enable,
+       .set_suspend_disable            = mcp16502_set_suspend_disable,
+#endif /* CONFIG_SUSPEND */
+};
+
+static const struct of_device_id mcp16502_ids[] = {
+       { .compatible = "microchip,mcp16502", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mcp16502_ids);
+
+static const struct regulator_linear_range b1l12_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1200000, VDD_LOW_SEL, VDD_HIGH_SEL, 50000),
+};
+
+static const struct regulator_linear_range b234_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, VDD_LOW_SEL, VDD_HIGH_SEL, 25000),
+};
+
+static const struct regulator_desc mcp16502_desc[] = {
+       /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */
+       MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops),
+       MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops),
+       MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops),
+       MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops),
+       MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops),
+       MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops)
+};
+
+static const struct regmap_range mcp16502_ranges[] = {
+       regmap_reg_range(MCP16502_MIN_REG, MCP16502_MAX_REG)
+};
+
+static const struct regmap_access_table mcp16502_yes_reg_table = {
+       .yes_ranges = mcp16502_ranges,
+       .n_yes_ranges = ARRAY_SIZE(mcp16502_ranges),
+};
+
+static const struct regmap_config mcp16502_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .max_register   = MCP16502_MAX_REG,
+       .cache_type     = REGCACHE_NONE,
+       .rd_table       = &mcp16502_yes_reg_table,
+       .wr_table       = &mcp16502_yes_reg_table,
+};
+
+/*
+ * set_up_regulators() - initialize all regulators
+ */
+static int setup_regulators(struct mcp16502 *mcp, struct device *dev,
+                           struct regulator_config config)
+{
+       int i;
+
+       for (i = 0; i < NUM_REGULATORS; i++) {
+               mcp->rdev[i] = devm_regulator_register(dev,
+                                                      &mcp16502_desc[i],
+                                                      &config);
+               if (IS_ERR(mcp->rdev[i])) {
+                       dev_err(dev,
+                               "failed to register %s regulator %ld\n",
+                               mcp16502_desc[i].name, PTR_ERR(mcp->rdev[i]));
+                       return PTR_ERR(mcp->rdev[i]);
+               }
+       }
+
+       return 0;
+}
+
+static int mcp16502_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct regulator_config config = { };
+       struct device *dev;
+       struct mcp16502 *mcp;
+       int ret = 0;
+
+       dev = &client->dev;
+       config.dev = dev;
+
+       mcp = devm_kzalloc(dev, sizeof(*mcp), GFP_KERNEL);
+       if (!mcp)
+               return -ENOMEM;
+
+       mcp->rmap = devm_regmap_init_i2c(client, &mcp16502_regmap_config);
+       if (IS_ERR(mcp->rmap)) {
+               ret = PTR_ERR(mcp->rmap);
+               dev_err(dev, "regmap init failed: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, mcp);
+       config.regmap = mcp->rmap;
+       config.driver_data = mcp;
+
+       mcp->lpm = devm_gpiod_get(dev, "lpm", GPIOD_OUT_LOW);
+       if (IS_ERR(mcp->lpm)) {
+               dev_err(dev, "failed to get lpm pin: %ld\n", PTR_ERR(mcp->lpm));
+               return PTR_ERR(mcp->lpm);
+       }
+
+       ret = setup_regulators(mcp, dev, config);
+       if (ret != 0)
+               return ret;
+
+       mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mcp16502_suspend_noirq(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mcp16502 *mcp = i2c_get_clientdata(client);
+
+       mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_LPM);
+
+       return 0;
+}
+
+static int mcp16502_resume_noirq(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mcp16502 *mcp = i2c_get_clientdata(client);
+
+       mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops mcp16502_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mcp16502_suspend_noirq,
+                                     mcp16502_resume_noirq)
+};
+#endif
+static const struct i2c_device_id mcp16502_i2c_id[] = {
+       { "mcp16502", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id);
+
+static struct i2c_driver mcp16502_drv = {
+       .probe          = mcp16502_probe,
+       .driver         = {
+               .name   = "mcp16502-regulator",
+               .of_match_table = of_match_ptr(mcp16502_ids),
+#ifdef CONFIG_PM
+               .pm = &mcp16502_pm_ops,
+#endif
+       },
+       .id_table       = mcp16502_i2c_id,
+};
+
+module_i2c_driver(mcp16502_drv);
+
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MCP16502 PMIC driver");
+MODULE_AUTHOR("Andrei Stefanescu andrei.stefanescu@microchip.com");
index c4223b3e0dffa6d846a153a7be468cfe4c6a70fb..ffa5fc3724e4f24b27d3981a43f0d05753e8b4c5 100644 (file)
@@ -20,6 +20,7 @@
 #include "internal.h"
 
 static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
+       [PM_SUSPEND_STANDBY]    = "regulator-state-standby",
        [PM_SUSPEND_MEM]        = "regulator-state-mem",
        [PM_SUSPEND_MAX]        = "regulator-state-disk",
 };
@@ -170,6 +171,10 @@ static void of_get_regulation_constraints(struct device_node *np,
                                  &pval))
                constraints->max_spread = pval;
 
+       if (!of_property_read_u32(np, "regulator-max-step-microvolt",
+                                 &pval))
+               constraints->max_uV_step = pval;
+
        constraints->over_current_protection = of_property_read_bool(np,
                                        "regulator-over-current-protection");
 
@@ -181,9 +186,11 @@ static void of_get_regulation_constraints(struct device_node *np,
                case PM_SUSPEND_MAX:
                        suspend_state = &constraints->state_disk;
                        break;
+               case PM_SUSPEND_STANDBY:
+                       suspend_state = &constraints->state_standby;
+                       break;
                case PM_SUSPEND_ON:
                case PM_SUSPEND_TO_IDLE:
-               case PM_SUSPEND_STANDBY:
                default:
                        continue;
                }
@@ -364,24 +371,25 @@ int of_regulator_match(struct device *dev, struct device_node *node,
 }
 EXPORT_SYMBOL_GPL(of_regulator_match);
 
-struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
-                                           const struct regulator_desc *desc,
-                                           struct regulator_config *config,
-                                           struct device_node **node)
+struct device_node *regulator_of_get_init_node(struct device *dev,
+                                              const struct regulator_desc *desc)
 {
        struct device_node *search, *child;
-       struct regulator_init_data *init_data = NULL;
        const char *name;
 
        if (!dev->of_node || !desc->of_match)
                return NULL;
 
-       if (desc->regulators_node)
+       if (desc->regulators_node) {
                search = of_get_child_by_name(dev->of_node,
                                              desc->regulators_node);
-       else
+       } else {
                search = of_node_get(dev->of_node);
 
+               if (!strcmp(desc->of_match, search->name))
+                       return search;
+       }
+
        if (!search) {
                dev_dbg(dev, "Failed to find regulator container node '%s'\n",
                        desc->regulators_node);
@@ -393,35 +401,48 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
                if (!name)
                        name = child->name;
 
-               if (strcmp(desc->of_match, name))
-                       continue;
+               if (!strcmp(desc->of_match, name))
+                       return of_node_get(child);
+       }
 
-               init_data = of_get_regulator_init_data(dev, child, desc);
-               if (!init_data) {
-                       dev_err(dev,
-                               "failed to parse DT for regulator %pOFn\n",
-                               child);
-                       break;
-               }
+       of_node_put(search);
 
-               if (desc->of_parse_cb) {
-                       if (desc->of_parse_cb(child, desc, config)) {
-                               dev_err(dev,
-                                       "driver callback failed to parse DT for regulator %pOFn\n",
-                                       child);
-                               init_data = NULL;
-                               break;
-                       }
-               }
+       return NULL;
+}
+
+struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
+                                           const struct regulator_desc *desc,
+                                           struct regulator_config *config,
+                                           struct device_node **node)
+{
+       struct device_node *child;
+       struct regulator_init_data *init_data = NULL;
 
-               of_node_get(child);
-               *node = child;
-               break;
+       child = regulator_of_get_init_node(dev, desc);
+       if (!child)
+               return NULL;
+
+       init_data = of_get_regulator_init_data(dev, child, desc);
+       if (!init_data) {
+               dev_err(dev, "failed to parse DT for regulator %pOFn\n", child);
+               goto error;
        }
 
-       of_node_put(search);
+       if (desc->of_parse_cb && desc->of_parse_cb(child, desc, config)) {
+               dev_err(dev,
+                       "driver callback failed to parse DT for regulator %pOFn\n",
+                       child);
+               goto error;
+       }
+
+       *node = child;
 
        return init_data;
+
+error:
+       of_node_put(child);
+
+       return NULL;
 }
 
 static int of_node_match(struct device *dev, const void *data)
index bb5ab7d78895b817a9d42e03e6bd890d6b99e33e..c2cc392a27d4075ffc40dc123a78775d0e034a8f 100644 (file)
@@ -443,13 +443,16 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
 static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
 {
        int id = rdev_get_id(dev);
+       int ret;
        struct palmas_pmic *pmic = rdev_get_drvdata(dev);
        struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
        struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
        unsigned int reg;
        bool rail_enable = true;
 
-       palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
+       ret = palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, &reg);
+       if (ret)
+               return ret;
 
        reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
 
index dd41a9bb3f5c62b7b2ef32ce27895e0db1976ecc..df5df1c495adb861322e356d59c091bbf94b342f 100644 (file)
@@ -370,6 +370,7 @@ static struct pfuze_regulator pfuze100_regulators[] = {
        PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
        PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
        PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+       PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
 };
 
 static struct pfuze_regulator pfuze200_regulators[] = {
@@ -436,6 +437,7 @@ static struct of_regulator_match pfuze100_matches[] = {
        { .name = "vgen4",      },
        { .name = "vgen5",      },
        { .name = "vgen6",      },
+       { .name = "coin",       },
 };
 
 /* PFUZE200 */
index 39ccf53fdeb38f1d7f039a47e4cc5baaad981b56..b2c2d01d1637060192f0d1554f201d276ef1b901 100644 (file)
@@ -410,7 +410,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
        vreg->dev = dev;
 
        for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
-               if (!strcmp(rpmh_data->name, node->name))
+               if (of_node_name_eq(node, rpmh_data->name))
                        break;
 
        if (!rpmh_data->name) {
index 5bb6f4ca48db8e0abb49b7af9b419829031b41f9..ee4a23ab06639a297bacfe0c2fc0877a5ee19cb8 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/bug.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -14,7 +14,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
-#include <linux/of_gpio.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s2mps11.h>
 #include <linux/mfd/samsung/s2mps13.h>
@@ -44,7 +43,7 @@ struct s2mps11_info {
         * Array (size: number of regulators) with GPIO-s for external
         * sleep control.
         */
-       int *ext_control_gpio;
+       struct gpio_desc **ext_control_gpiod;
 };
 
 static int get_ramp_delay(int ramp_delay)
@@ -511,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
        case S2MPS14X:
                if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
                        val = S2MPS14_ENABLE_SUSPEND;
-               else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
+               else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)])
                        val = S2MPS14_ENABLE_EXT_CONTROL;
                else
                        val = rdev->desc->enable_mask;
@@ -805,7 +804,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
 static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
                struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
 {
-       int *gpio = s2mps11->ext_control_gpio;
+       struct gpio_desc **gpio = s2mps11->ext_control_gpiod;
        unsigned int i;
        unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
                S2MPS14_LDO12 };
@@ -816,11 +815,20 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
                if (!rdata[reg].init_data || !rdata[reg].of_node)
                        continue;
 
-               gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
-                               "samsung,ext-control-gpios", 0);
-               if (gpio_is_valid(gpio[reg]))
-                       dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
-                                       gpio[reg], reg, rdata[reg].name);
+               gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev,
+                               rdata[reg].of_node,
+                               "samsung,ext-control-gpios",
+                               0,
+                               GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+                               "s2mps11-regulator");
+               if (IS_ERR(gpio[reg])) {
+                       dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n",
+                               reg, rdata[reg].name);
+                       continue;
+               }
+               if (gpio[reg])
+                       dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n",
+                               reg, rdata[reg].name);
        }
 }
 
@@ -1126,17 +1134,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       s2mps11->ext_control_gpio = devm_kmalloc_array(&pdev->dev,
-                       rdev_num, sizeof(*s2mps11->ext_control_gpio),
-                       GFP_KERNEL);
-       if (!s2mps11->ext_control_gpio)
+       s2mps11->ext_control_gpiod = devm_kcalloc(&pdev->dev, rdev_num,
+                              sizeof(*s2mps11->ext_control_gpiod), GFP_KERNEL);
+       if (!s2mps11->ext_control_gpiod)
                return -ENOMEM;
-       /*
-        * 0 is a valid GPIO so initialize all GPIO-s to negative value
-        * to indicate that external control won't be used for this regulator.
-        */
-       for (i = 0; i < rdev_num; i++)
-               s2mps11->ext_control_gpio[i] = -EINVAL;
 
        if (!iodev->dev->of_node) {
                if (iodev->pdata) {
@@ -1166,8 +1167,6 @@ common_reg:
        config.dev = &pdev->dev;
        config.regmap = iodev->regmap_pmic;
        config.driver_data = s2mps11;
-       config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
-       config.ena_gpio_initialized = true;
        for (i = 0; i < rdev_num; i++) {
                struct regulator_dev *regulator;
 
@@ -1178,8 +1177,13 @@ common_reg:
                        config.init_data = rdata[i].init_data;
                        config.of_node = rdata[i].of_node;
                }
-               config.ena_gpio = s2mps11->ext_control_gpio[i];
-
+               config.ena_gpiod = s2mps11->ext_control_gpiod[i];
+               /*
+                * Hand the GPIO descriptor management over to the regulator
+                * core, remove it from devres management.
+                */
+               if (config.ena_gpiod)
+                       devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod);
                regulator = devm_regulator_register(&pdev->dev,
                                                &regulators[i], &config);
                if (IS_ERR(regulator)) {
@@ -1189,7 +1193,7 @@ common_reg:
                        goto out;
                }
 
-               if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
+               if (s2mps11->ext_control_gpiod[i]) {
                        ret = s2mps14_pmic_enable_ext_control(s2mps11,
                                        regulator);
                        if (ret < 0) {
index 219b9afda0cb937c6cecd424c7481b339348c4d1..b581f01f3395762eec02ff5d0a70efda4ecdfe48 100644 (file)
@@ -561,7 +561,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
        pdata->opmode = rmode;
        for_each_child_of_node(regulators_np, reg_np) {
                for (i = 0; i < ARRAY_SIZE(regulators); i++)
-                       if (!of_node_cmp(reg_np->name, regulators[i].name))
+                       if (of_node_name_eq(reg_np, regulators[i].name))
                                break;
 
                if (i == ARRAY_SIZE(regulators)) {
@@ -956,10 +956,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                config.regmap = iodev->regmap_pmic;
                config.of_node = pdata->regulators[i].reg_node;
                config.ena_gpiod = NULL;
-               if (pdata->regulators[i].ext_control_gpiod)
+               if (pdata->regulators[i].ext_control_gpiod) {
+                       /* Assigns config.ena_gpiod */
                        s5m8767_regulator_config_ext_control(s5m8767,
                                        &pdata->regulators[i], &config);
 
+                       /*
+                        * Hand the GPIO descriptor management over to the
+                        * regulator core, remove it from devres management.
+                        */
+                       devm_gpiod_unhinge(s5m8767->dev, config.ena_gpiod);
+               }
                rdev = devm_regulator_register(&pdev->dev, &regulators[id],
                                                  &config);
                if (IS_ERR(rdev)) {
index e15634edb8cef8db5a0437ba947066a52097a9e5..16ba0297f709b1c05ae1b25f3cf618854ecfbec6 100644 (file)
@@ -489,14 +489,14 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
 {
        struct regulator_dev *rdev = (struct regulator_dev *)data;
 
-       mutex_lock(&rdev->mutex);
+       regulator_lock(rdev);
 
        /* Send an overcurrent notification */
        regulator_notifier_call_chain(rdev,
                                      REGULATOR_EVENT_OVER_CURRENT,
                                      NULL);
 
-       mutex_unlock(&rdev->mutex);
+       regulator_unlock(rdev);
 
        return IRQ_HANDLED;
 }
index db714d5edafc8846285b2bf500e4eb1a4ab334aa..0614551796a19a5877d0875d1097fecfeeb998a7 100644 (file)
@@ -480,6 +480,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
                else
                        config.of_node = NULL;
 
+               /*
+                * Hand the GPIO descriptor management over to the regulator
+                * core, remove it from devres management.
+                */
+               if (config.ena_gpiod)
+                       devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod);
                rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);
                if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev, "failed to register regulator %s\n",
index 02ccdaa226a73f97a5fc812f5173c2bef44d25f4..5ebb6ee73f0770283eff5c15f5c71d0b56fe08bb 100644 (file)
@@ -1102,8 +1102,10 @@ static int tps65910_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, pmic);
 
        /* Give control of all register to control port */
-       tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+       err = tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
                                DEVCTRL_SR_CTL_I2C_SEL_MASK);
+       if (err < 0)
+               return err;
 
        switch (tps65910_chip_id(tps65910)) {
        case TPS65910:
index 8ad11b074b49204a2589033d46b1e0f024463ec7..a1c7dfee5c37d74288938d02eb099dde33205110 100644 (file)
@@ -1153,7 +1153,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data)
 {
        struct regulator_dev *rdev = (struct regulator_dev *)data;
 
-       mutex_lock(&rdev->mutex);
+       regulator_lock(rdev);
        if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
                regulator_notifier_call_chain(rdev,
                                              REGULATOR_EVENT_REGULATION_OUT,
@@ -1162,7 +1162,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data)
                regulator_notifier_call_chain(rdev,
                                              REGULATOR_EVENT_UNDER_VOLTAGE,
                                              NULL);
-       mutex_unlock(&rdev->mutex);
+       regulator_unlock(rdev);
 
        return IRQ_HANDLED;
 }
index 7a4ce6df4f22a95323e2a0cae05572a0baa34a2f..38928cdcb6e6584e4b30adf0653e84f2963da0bd 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/wm8994/core.h>
@@ -129,6 +129,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
        int id = pdev->id % ARRAY_SIZE(pdata->ldo);
        struct regulator_config config = { };
        struct wm8994_ldo *ldo;
+       struct gpio_desc *gpiod;
        int ret;
 
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
@@ -145,12 +146,18 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
        config.driver_data = ldo;
        config.regmap = wm8994->regmap;
        config.init_data = &ldo->init_data;
-       if (pdata) {
-               config.ena_gpio = pdata->ldo[id].enable;
-       } else if (wm8994->dev->of_node) {
-               config.ena_gpio = wm8994->pdata.ldo[id].enable;
-               config.ena_gpio_initialized = true;
-       }
+
+       /*
+        * Look up LDO enable GPIO from the parent device node, we don't
+        * use devm because the regulator core will free the GPIO
+        */
+       gpiod = gpiod_get_optional(pdev->dev.parent,
+                                  id ? "wlf,ldo2ena" : "wlf,ldo1ena",
+                                  GPIOD_OUT_LOW |
+                                  GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+       if (IS_ERR(gpiod))
+               return PTR_ERR(gpiod);
+       config.ena_gpiod = gpiod;
 
        /* Use default constraints if none set up */
        if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) {
@@ -159,12 +166,17 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
 
                ldo->init_data = wm8994_ldo_default[id];
                ldo->init_data.consumer_supplies = &ldo->supply;
-               if (!config.ena_gpio)
+               if (!gpiod)
                        ldo->init_data.constraints.valid_ops_mask = 0;
        } else {
                ldo->init_data = *pdata->ldo[id].init_data;
        }
 
+       /*
+        * At this point the GPIO descriptor is handled over to the
+        * regulator core and we need not worry about it on the
+        * error path.
+        */
        ldo->regulator = devm_regulator_register(&pdev->dev,
                                                 &wm8994_ldo_desc[id],
                                                 &config);
@@ -172,15 +184,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
                ret = PTR_ERR(ldo->regulator);
                dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
                        id + 1, ret);
-               goto err;
+               return ret;
        }
 
        platform_set_drvdata(pdev, ldo);
 
        return 0;
-
-err:
-       return ret;
 }
 
 static struct platform_driver wm8994_ldo_driver = {
index cd160f2ec75d3ddd4803904fcd0b14c8742f86e1..bcd30e2374f18e8be5d16d88b117016dd59377df 100644 (file)
@@ -2364,7 +2364,7 @@ static int _bnx2fc_create(struct net_device *netdev,
        if (!interface) {
                printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
                rc = -ENOMEM;
-               goto ifput_err;
+               goto netdev_err;
        }
 
        if (is_vlan_dev(netdev)) {
index b658b9a5eb1e172b6549d05b1e8c3aece913f715..d0ecc729a90a3706b979898a00709d01312e3579 100644 (file)
@@ -4886,10 +4886,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        fcport->d_id = e->u.new_sess.id;
                        fcport->flags |= FCF_FABRIC_DEVICE;
                        fcport->fw_login_state = DSC_LS_PLOGI_PEND;
-                       if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP)
+                       if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP)
                                fcport->fc4_type = FC4_TYPE_FCP_SCSI;
 
-                       if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) {
+                       if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) {
                                fcport->fc4_type = FC4_TYPE_OTHER;
                                fcport->fc4f_nvme = FC4_TYPE_NVME;
                        }
index 3bb2b3351e35e6fbef7f424e79954abddcf573de..bd0a5c694a97eb0c32fce4f556b12f426fda8286 100644 (file)
@@ -133,6 +133,7 @@ static DEFINE_MUTEX(sd_ref_mutex);
 
 static struct kmem_cache *sd_cdb_cache;
 static mempool_t *sd_cdb_pool;
+static mempool_t *sd_page_pool;
 
 static const char *sd_cache_types[] = {
        "write through", "none", "write back",
@@ -759,9 +760,10 @@ static int sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
        unsigned int data_len = 24;
        char *buf;
 
-       rq->special_vec.bv_page = alloc_page(GFP_ATOMIC | __GFP_ZERO);
+       rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC);
        if (!rq->special_vec.bv_page)
                return BLKPREP_DEFER;
+       clear_highpage(rq->special_vec.bv_page);
        rq->special_vec.bv_offset = 0;
        rq->special_vec.bv_len = data_len;
        rq->rq_flags |= RQF_SPECIAL_PAYLOAD;
@@ -792,9 +794,10 @@ static int sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, bool unmap)
        u32 nr_sectors = blk_rq_sectors(rq) >> (ilog2(sdp->sector_size) - 9);
        u32 data_len = sdp->sector_size;
 
-       rq->special_vec.bv_page = alloc_page(GFP_ATOMIC | __GFP_ZERO);
+       rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC);
        if (!rq->special_vec.bv_page)
                return BLKPREP_DEFER;
+       clear_highpage(rq->special_vec.bv_page);
        rq->special_vec.bv_offset = 0;
        rq->special_vec.bv_len = data_len;
        rq->rq_flags |= RQF_SPECIAL_PAYLOAD;
@@ -822,9 +825,10 @@ static int sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, bool unmap)
        u32 nr_sectors = blk_rq_sectors(rq) >> (ilog2(sdp->sector_size) - 9);
        u32 data_len = sdp->sector_size;
 
-       rq->special_vec.bv_page = alloc_page(GFP_ATOMIC | __GFP_ZERO);
+       rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC);
        if (!rq->special_vec.bv_page)
                return BLKPREP_DEFER;
+       clear_highpage(rq->special_vec.bv_page);
        rq->special_vec.bv_offset = 0;
        rq->special_vec.bv_len = data_len;
        rq->rq_flags |= RQF_SPECIAL_PAYLOAD;
@@ -1286,7 +1290,7 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
        u8 *cmnd;
 
        if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
-               __free_page(rq->special_vec.bv_page);
+               mempool_free(rq->special_vec.bv_page, sd_page_pool);
 
        if (SCpnt->cmnd != scsi_req(rq)->cmd) {
                cmnd = SCpnt->cmnd;
@@ -3623,6 +3627,13 @@ static int __init init_sd(void)
                goto err_out_cache;
        }
 
+       sd_page_pool = mempool_create_page_pool(SD_MEMPOOL_SIZE, 0);
+       if (!sd_page_pool) {
+               printk(KERN_ERR "sd: can't init discard page pool\n");
+               err = -ENOMEM;
+               goto err_out_ppool;
+       }
+
        err = scsi_register_driver(&sd_template.gendrv);
        if (err)
                goto err_out_driver;
@@ -3630,6 +3641,9 @@ static int __init init_sd(void)
        return 0;
 
 err_out_driver:
+       mempool_destroy(sd_page_pool);
+
+err_out_ppool:
        mempool_destroy(sd_cdb_pool);
 
 err_out_cache:
@@ -3656,6 +3670,7 @@ static void __exit exit_sd(void)
 
        scsi_unregister_driver(&sd_template.gendrv);
        mempool_destroy(sd_cdb_pool);
+       mempool_destroy(sd_page_pool);
        kmem_cache_destroy(sd_cdb_cache);
 
        class_unregister(&sd_disk_class);
index 7d3a5c94727ec31c70fd9ef09010e7ad46a1bc43..9f89cb13454957e3d6633825c5106ccdea3747fa 100644 (file)
@@ -91,6 +91,15 @@ config SPI_AT91_USART
          This selects a driver for the AT91 USART Controller as SPI Master,
          present on AT91 and SAMA5 SoC series.
 
+config SPI_ATMEL_QUADSPI
+       tristate "Atmel Quad SPI Controller"
+       depends on ARCH_AT91 || (ARM && COMPILE_TEST && !ARCH_EBSA110)
+       depends on OF && HAS_IOMEM
+       help
+         This enables support for the Quad SPI controller in master mode.
+         This driver does not support generic SPI. The implementation only
+         supports spi-mem interface.
+
 config SPI_AU1550
        tristate "Au1550/Au1200/Au1300 SPI Controller"
        depends on MIPS_ALCHEMY
@@ -397,6 +406,13 @@ config SPI_MT65XX
          say Y or M here.If you are not sure, say N.
          SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
 
+config SPI_NPCM_PSPI
+       tristate "Nuvoton NPCM PSPI Controller"
+       depends on ARCH_NPCM || COMPILE_TEST
+       help
+         This driver provides support for Nuvoton NPCM BMC
+         Peripheral SPI controller in master mode.
+
 config SPI_NUC900
        tristate "Nuvoton NUC900 series SPI"
        depends on ARCH_W90X900
@@ -435,7 +451,7 @@ config SPI_OMAP_UWIRE
 
 config SPI_OMAP24XX
        tristate "McSPI driver for OMAP"
-       depends on ARCH_OMAP2PLUS || COMPILE_TEST
+       depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
        select SG_SPLIT
        help
          SPI master controller for OMAP24XX and later Multichannel SPI
@@ -684,6 +700,12 @@ config SPI_SUN6I
        help
          This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_MXIC
+        tristate "Macronix MX25F0A SPI controller"
+        depends on SPI_MASTER
+        help
+          This selects the Macronix MX25F0A SPI controller driver.
+
 config SPI_MXS
        tristate "Freescale MXS SPI controller"
        depends on ARCH_MXS
index 3575205c5c27196a601fec757642b7c49d19d0af..f29627040dfb8e18a31202c90502fbb1a79a9c98 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST)               += spi-loopback-test.o
 obj-$(CONFIG_SPI_ALTERA)               += spi-altera.o
 obj-$(CONFIG_SPI_ARMADA_3700)          += spi-armada-3700.o
 obj-$(CONFIG_SPI_ATMEL)                        += spi-atmel.o
+obj-$(CONFIG_SPI_ATMEL_QUADSPI)                += atmel-quadspi.o
 obj-$(CONFIG_SPI_AT91_USART)           += spi-at91-usart.o
 obj-$(CONFIG_SPI_ATH79)                        += spi-ath79.o
 obj-$(CONFIG_SPI_AU1550)               += spi-au1550.o
@@ -58,7 +59,9 @@ obj-$(CONFIG_SPI_MPC512x_PSC)         += spi-mpc512x-psc.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += spi-mpc52xx-psc.o
 obj-$(CONFIG_SPI_MPC52xx)              += spi-mpc52xx.o
 obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
+obj-$(CONFIG_SPI_MXIC)                 += spi-mxic.o
 obj-$(CONFIG_SPI_MXS)                  += spi-mxs.o
+obj-$(CONFIG_SPI_NPCM_PSPI)            += spi-npcm-pspi.o
 obj-$(CONFIG_SPI_NUC900)               += spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)              += spi-oc-tiny.o
 spi-octeon-objs                                := spi-cavium.o spi-cavium-octeon.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
new file mode 100644 (file)
index 0000000..ddc7124
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Driver for Atmel QSPI Controller
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ * Copyright (C) 2018 Cryptera A/S
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ * Author: Piotr Bugalski <bugalski.piotr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+
+#include <linux/io.h>
+#include <linux/spi/spi-mem.h>
+
+/* QSPI register offsets */
+#define QSPI_CR      0x0000  /* Control Register */
+#define QSPI_MR      0x0004  /* Mode Register */
+#define QSPI_RD      0x0008  /* Receive Data Register */
+#define QSPI_TD      0x000c  /* Transmit Data Register */
+#define QSPI_SR      0x0010  /* Status Register */
+#define QSPI_IER     0x0014  /* Interrupt Enable Register */
+#define QSPI_IDR     0x0018  /* Interrupt Disable Register */
+#define QSPI_IMR     0x001c  /* Interrupt Mask Register */
+#define QSPI_SCR     0x0020  /* Serial Clock Register */
+
+#define QSPI_IAR     0x0030  /* Instruction Address Register */
+#define QSPI_ICR     0x0034  /* Instruction Code Register */
+#define QSPI_IFR     0x0038  /* Instruction Frame Register */
+
+#define QSPI_SMR     0x0040  /* Scrambling Mode Register */
+#define QSPI_SKR     0x0044  /* Scrambling Key Register */
+
+#define QSPI_WPMR    0x00E4  /* Write Protection Mode Register */
+#define QSPI_WPSR    0x00E8  /* Write Protection Status Register */
+
+#define QSPI_VERSION 0x00FC  /* Version Register */
+
+
+/* Bitfields in QSPI_CR (Control Register) */
+#define QSPI_CR_QSPIEN                  BIT(0)
+#define QSPI_CR_QSPIDIS                 BIT(1)
+#define QSPI_CR_SWRST                   BIT(7)
+#define QSPI_CR_LASTXFER                BIT(24)
+
+/* Bitfields in QSPI_MR (Mode Register) */
+#define QSPI_MR_SMM                     BIT(0)
+#define QSPI_MR_LLB                     BIT(1)
+#define QSPI_MR_WDRBT                   BIT(2)
+#define QSPI_MR_SMRM                    BIT(3)
+#define QSPI_MR_CSMODE_MASK             GENMASK(5, 4)
+#define QSPI_MR_CSMODE_NOT_RELOADED     (0 << 4)
+#define QSPI_MR_CSMODE_LASTXFER         (1 << 4)
+#define QSPI_MR_CSMODE_SYSTEMATICALLY   (2 << 4)
+#define QSPI_MR_NBBITS_MASK             GENMASK(11, 8)
+#define QSPI_MR_NBBITS(n)               ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
+#define QSPI_MR_DLYBCT_MASK             GENMASK(23, 16)
+#define QSPI_MR_DLYBCT(n)               (((n) << 16) & QSPI_MR_DLYBCT_MASK)
+#define QSPI_MR_DLYCS_MASK              GENMASK(31, 24)
+#define QSPI_MR_DLYCS(n)                (((n) << 24) & QSPI_MR_DLYCS_MASK)
+
+/* Bitfields in QSPI_SR/QSPI_IER/QSPI_IDR/QSPI_IMR  */
+#define QSPI_SR_RDRF                    BIT(0)
+#define QSPI_SR_TDRE                    BIT(1)
+#define QSPI_SR_TXEMPTY                 BIT(2)
+#define QSPI_SR_OVRES                   BIT(3)
+#define QSPI_SR_CSR                     BIT(8)
+#define QSPI_SR_CSS                     BIT(9)
+#define QSPI_SR_INSTRE                  BIT(10)
+#define QSPI_SR_QSPIENS                 BIT(24)
+
+#define QSPI_SR_CMD_COMPLETED  (QSPI_SR_INSTRE | QSPI_SR_CSR)
+
+/* Bitfields in QSPI_SCR (Serial Clock Register) */
+#define QSPI_SCR_CPOL                   BIT(0)
+#define QSPI_SCR_CPHA                   BIT(1)
+#define QSPI_SCR_SCBR_MASK              GENMASK(15, 8)
+#define QSPI_SCR_SCBR(n)                (((n) << 8) & QSPI_SCR_SCBR_MASK)
+#define QSPI_SCR_DLYBS_MASK             GENMASK(23, 16)
+#define QSPI_SCR_DLYBS(n)               (((n) << 16) & QSPI_SCR_DLYBS_MASK)
+
+/* Bitfields in QSPI_ICR (Instruction Code Register) */
+#define QSPI_ICR_INST_MASK              GENMASK(7, 0)
+#define QSPI_ICR_INST(inst)             (((inst) << 0) & QSPI_ICR_INST_MASK)
+#define QSPI_ICR_OPT_MASK               GENMASK(23, 16)
+#define QSPI_ICR_OPT(opt)               (((opt) << 16) & QSPI_ICR_OPT_MASK)
+
+/* Bitfields in QSPI_IFR (Instruction Frame Register) */
+#define QSPI_IFR_WIDTH_MASK             GENMASK(2, 0)
+#define QSPI_IFR_WIDTH_SINGLE_BIT_SPI   (0 << 0)
+#define QSPI_IFR_WIDTH_DUAL_OUTPUT      (1 << 0)
+#define QSPI_IFR_WIDTH_QUAD_OUTPUT      (2 << 0)
+#define QSPI_IFR_WIDTH_DUAL_IO          (3 << 0)
+#define QSPI_IFR_WIDTH_QUAD_IO          (4 << 0)
+#define QSPI_IFR_WIDTH_DUAL_CMD         (5 << 0)
+#define QSPI_IFR_WIDTH_QUAD_CMD         (6 << 0)
+#define QSPI_IFR_INSTEN                 BIT(4)
+#define QSPI_IFR_ADDREN                 BIT(5)
+#define QSPI_IFR_OPTEN                  BIT(6)
+#define QSPI_IFR_DATAEN                 BIT(7)
+#define QSPI_IFR_OPTL_MASK              GENMASK(9, 8)
+#define QSPI_IFR_OPTL_1BIT              (0 << 8)
+#define QSPI_IFR_OPTL_2BIT              (1 << 8)
+#define QSPI_IFR_OPTL_4BIT              (2 << 8)
+#define QSPI_IFR_OPTL_8BIT              (3 << 8)
+#define QSPI_IFR_ADDRL                  BIT(10)
+#define QSPI_IFR_TFRTYP_MASK            GENMASK(13, 12)
+#define QSPI_IFR_TFRTYP_TRSFR_READ      (0 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_READ_MEM  (1 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_WRITE     (2 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM (3 << 13)
+#define QSPI_IFR_CRM                    BIT(14)
+#define QSPI_IFR_NBDUM_MASK             GENMASK(20, 16)
+#define QSPI_IFR_NBDUM(n)               (((n) << 16) & QSPI_IFR_NBDUM_MASK)
+
+/* Bitfields in QSPI_SMR (Scrambling Mode Register) */
+#define QSPI_SMR_SCREN                  BIT(0)
+#define QSPI_SMR_RVDIS                  BIT(1)
+
+/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
+#define QSPI_WPMR_WPEN                  BIT(0)
+#define QSPI_WPMR_WPKEY_MASK            GENMASK(31, 8)
+#define QSPI_WPMR_WPKEY(wpkey)          (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
+
+/* Bitfields in QSPI_WPSR (Write Protection Status Register) */
+#define QSPI_WPSR_WPVS                  BIT(0)
+#define QSPI_WPSR_WPVSRC_MASK           GENMASK(15, 8)
+#define QSPI_WPSR_WPVSRC(src)           (((src) << 8) & QSPI_WPSR_WPVSRC)
+
+
+struct atmel_qspi {
+       void __iomem            *regs;
+       void __iomem            *mem;
+       struct clk              *clk;
+       struct platform_device  *pdev;
+       u32                     pending;
+       struct completion       cmd_completion;
+};
+
+struct qspi_mode {
+       u8 cmd_buswidth;
+       u8 addr_buswidth;
+       u8 data_buswidth;
+       u32 config;
+};
+
+static const struct qspi_mode sama5d2_qspi_modes[] = {
+       { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI },
+       { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT },
+       { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT },
+       { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO },
+       { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO },
+       { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD },
+       { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
+};
+
+/* Register access functions */
+static inline u32 qspi_readl(struct atmel_qspi *aq, u32 reg)
+{
+       return readl_relaxed(aq->regs + reg);
+}
+
+static inline void qspi_writel(struct atmel_qspi *aq, u32 reg, u32 value)
+{
+       writel_relaxed(value, aq->regs + reg);
+}
+
+static inline bool is_compatible(const struct spi_mem_op *op,
+                                const struct qspi_mode *mode)
+{
+       if (op->cmd.buswidth != mode->cmd_buswidth)
+               return false;
+
+       if (op->addr.nbytes && op->addr.buswidth != mode->addr_buswidth)
+               return false;
+
+       if (op->data.nbytes && op->data.buswidth != mode->data_buswidth)
+               return false;
+
+       return true;
+}
+
+static int find_mode(const struct spi_mem_op *op)
+{
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(sama5d2_qspi_modes); i++)
+               if (is_compatible(op, &sama5d2_qspi_modes[i]))
+                       return i;
+
+       return -1;
+}
+
+static bool atmel_qspi_supports_op(struct spi_mem *mem,
+                                  const struct spi_mem_op *op)
+{
+       if (find_mode(op) < 0)
+               return false;
+
+       /* special case not supported by hardware */
+       if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth &&
+               op->dummy.nbytes == 0)
+               return false;
+
+       return true;
+}
+
+static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->master);
+       int mode;
+       u32 dummy_cycles = 0;
+       u32 iar, icr, ifr, sr;
+       int err = 0;
+
+       iar = 0;
+       icr = QSPI_ICR_INST(op->cmd.opcode);
+       ifr = QSPI_IFR_INSTEN;
+
+       qspi_writel(aq, QSPI_MR, QSPI_MR_SMM);
+
+       mode = find_mode(op);
+       if (mode < 0)
+               return -ENOTSUPP;
+
+       ifr |= sama5d2_qspi_modes[mode].config;
+
+       if (op->dummy.buswidth && op->dummy.nbytes)
+               dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
+
+       if (op->addr.buswidth) {
+               switch (op->addr.nbytes) {
+               case 0:
+                       break;
+               case 1:
+                       ifr |= QSPI_IFR_OPTEN | QSPI_IFR_OPTL_8BIT;
+                       icr |= QSPI_ICR_OPT(op->addr.val & 0xff);
+                       break;
+               case 2:
+                       if (dummy_cycles < 8 / op->addr.buswidth) {
+                               ifr &= ~QSPI_IFR_INSTEN;
+                               ifr |= QSPI_IFR_ADDREN;
+                               iar = (op->cmd.opcode << 16) |
+                                       (op->addr.val & 0xffff);
+                       } else {
+                               ifr |= QSPI_IFR_ADDREN;
+                               iar = (op->addr.val << 8) & 0xffffff;
+                               dummy_cycles -= 8 / op->addr.buswidth;
+                       }
+                       break;
+               case 3:
+                       ifr |= QSPI_IFR_ADDREN;
+                       iar = op->addr.val & 0xffffff;
+                       break;
+               case 4:
+                       ifr |= QSPI_IFR_ADDREN | QSPI_IFR_ADDRL;
+                       iar = op->addr.val & 0x7ffffff;
+                       break;
+               default:
+                       return -ENOTSUPP;
+               }
+       }
+
+       /* Set number of dummy cycles */
+       if (dummy_cycles)
+               ifr |= QSPI_IFR_NBDUM(dummy_cycles);
+
+       /* Set data enable */
+       if (op->data.nbytes)
+               ifr |= QSPI_IFR_DATAEN;
+
+       if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes)
+               ifr |= QSPI_IFR_TFRTYP_TRSFR_READ;
+       else
+               ifr |= QSPI_IFR_TFRTYP_TRSFR_WRITE;
+
+       /* Clear pending interrupts */
+       (void)qspi_readl(aq, QSPI_SR);
+
+       /* Set QSPI Instruction Frame registers */
+       qspi_writel(aq, QSPI_IAR, iar);
+       qspi_writel(aq, QSPI_ICR, icr);
+       qspi_writel(aq, QSPI_IFR, ifr);
+
+       /* Skip to the final steps if there is no data */
+       if (op->data.nbytes) {
+               /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
+               (void)qspi_readl(aq, QSPI_IFR);
+
+               /* Send/Receive data */
+               if (op->data.dir == SPI_MEM_DATA_IN)
+                       _memcpy_fromio(op->data.buf.in,
+                               aq->mem + iar, op->data.nbytes);
+               else
+                       _memcpy_toio(aq->mem + iar,
+                               op->data.buf.out, op->data.nbytes);
+
+               /* Release the chip-select */
+               qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
+       }
+
+       /* Poll INSTRuction End status */
+       sr = qspi_readl(aq, QSPI_SR);
+       if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
+               return err;
+
+       /* Wait for INSTRuction End interrupt */
+       reinit_completion(&aq->cmd_completion);
+       aq->pending = sr & QSPI_SR_CMD_COMPLETED;
+       qspi_writel(aq, QSPI_IER, QSPI_SR_CMD_COMPLETED);
+       if (!wait_for_completion_timeout(&aq->cmd_completion,
+                                        msecs_to_jiffies(1000)))
+               err = -ETIMEDOUT;
+       qspi_writel(aq, QSPI_IDR, QSPI_SR_CMD_COMPLETED);
+
+       return err;
+}
+
+const char *atmel_qspi_get_name(struct spi_mem *spimem)
+{
+       return dev_name(spimem->spi->dev.parent);
+}
+
+static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
+       .supports_op = atmel_qspi_supports_op,
+       .exec_op = atmel_qspi_exec_op,
+       .get_name = atmel_qspi_get_name
+};
+
+static int atmel_qspi_setup(struct spi_device *spi)
+{
+       struct spi_controller *ctrl = spi->master;
+       struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+       unsigned long src_rate;
+       u32 scr, scbr;
+
+       if (ctrl->busy)
+               return -EBUSY;
+
+       if (!spi->max_speed_hz)
+               return -EINVAL;
+
+       src_rate = clk_get_rate(aq->clk);
+       if (!src_rate)
+               return -EINVAL;
+
+       /* Compute the QSPI baudrate */
+       scbr = DIV_ROUND_UP(src_rate, spi->max_speed_hz);
+       if (scbr > 0)
+               scbr--;
+
+       scr = QSPI_SCR_SCBR(scbr);
+       qspi_writel(aq, QSPI_SCR, scr);
+
+       return 0;
+}
+
+static int atmel_qspi_init(struct atmel_qspi *aq)
+{
+       /* Reset the QSPI controller */
+       qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
+
+       /* Enable the QSPI controller */
+       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
+
+       return 0;
+}
+
+static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
+{
+       struct atmel_qspi *aq = (struct atmel_qspi *)dev_id;
+       u32 status, mask, pending;
+
+       status = qspi_readl(aq, QSPI_SR);
+       mask = qspi_readl(aq, QSPI_IMR);
+       pending = status & mask;
+
+       if (!pending)
+               return IRQ_NONE;
+
+       aq->pending |= pending;
+       if ((aq->pending & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
+               complete(&aq->cmd_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int atmel_qspi_probe(struct platform_device *pdev)
+{
+       struct spi_controller *ctrl;
+       struct atmel_qspi *aq;
+       struct resource *res;
+       int irq, err = 0;
+
+       ctrl = spi_alloc_master(&pdev->dev, sizeof(*aq));
+       if (!ctrl)
+               return -ENOMEM;
+
+       ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
+       ctrl->setup = atmel_qspi_setup;
+       ctrl->bus_num = -1;
+       ctrl->mem_ops = &atmel_qspi_mem_ops;
+       ctrl->num_chipselect = 1;
+       ctrl->dev.of_node = pdev->dev.of_node;
+       platform_set_drvdata(pdev, ctrl);
+
+       aq = spi_controller_get_devdata(ctrl);
+
+       init_completion(&aq->cmd_completion);
+       aq->pdev = pdev;
+
+       /* Map the registers */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
+       aq->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(aq->regs)) {
+               dev_err(&pdev->dev, "missing registers\n");
+               err = PTR_ERR(aq->regs);
+               goto exit;
+       }
+
+       /* Map the AHB memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap");
+       aq->mem = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(aq->mem)) {
+               dev_err(&pdev->dev, "missing AHB memory\n");
+               err = PTR_ERR(aq->mem);
+               goto exit;
+       }
+
+       /* Get the peripheral clock */
+       aq->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(aq->clk)) {
+               dev_err(&pdev->dev, "missing peripheral clock\n");
+               err = PTR_ERR(aq->clk);
+               goto exit;
+       }
+
+       /* Enable the peripheral clock */
+       err = clk_prepare_enable(aq->clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
+               goto exit;
+       }
+
+       /* Request the IRQ */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "missing IRQ\n");
+               err = irq;
+               goto disable_clk;
+       }
+       err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
+                              0, dev_name(&pdev->dev), aq);
+       if (err)
+               goto disable_clk;
+
+       err = atmel_qspi_init(aq);
+       if (err)
+               goto disable_clk;
+
+       err = spi_register_controller(ctrl);
+       if (err)
+               goto disable_clk;
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(aq->clk);
+exit:
+       spi_controller_put(ctrl);
+
+       return err;
+}
+
+static int atmel_qspi_remove(struct platform_device *pdev)
+{
+       struct spi_controller *ctrl = platform_get_drvdata(pdev);
+       struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+
+       spi_unregister_controller(ctrl);
+       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIDIS);
+       clk_disable_unprepare(aq->clk);
+       return 0;
+}
+
+static int __maybe_unused atmel_qspi_suspend(struct device *dev)
+{
+       struct atmel_qspi *aq = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(aq->clk);
+
+       return 0;
+}
+
+static int __maybe_unused atmel_qspi_resume(struct device *dev)
+{
+       struct atmel_qspi *aq = dev_get_drvdata(dev);
+
+       clk_prepare_enable(aq->clk);
+
+       return atmel_qspi_init(aq);
+}
+
+static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend,
+                        atmel_qspi_resume);
+
+static const struct of_device_id atmel_qspi_dt_ids[] = {
+       { .compatible = "atmel,sama5d2-qspi" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_qspi_dt_ids);
+
+static struct platform_driver atmel_qspi_driver = {
+       .driver = {
+               .name   = "atmel_qspi",
+               .of_match_table = atmel_qspi_dt_ids,
+               .pm     = &atmel_qspi_pm_ops,
+       },
+       .probe          = atmel_qspi_probe,
+       .remove         = atmel_qspi_remove,
+};
+module_platform_driver(atmel_qspi_driver);
+
+MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
+MODULE_AUTHOR("Piotr Bugalski <bugalski.piotr@gmail.com");
+MODULE_DESCRIPTION("Atmel QSPI Controller driver");
+MODULE_LICENSE("GPL v2");
index a924657642fa8c27446c402288896ae355b6d272..a694d702e5744e25244fba5985f3c86af9708356 100644 (file)
@@ -12,7 +12,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/spi/spi.h>
 
@@ -399,6 +401,59 @@ at91_usart_spi_probe_fail:
        return ret;
 }
 
+__maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev)
+{
+       struct spi_controller *ctlr = dev_get_drvdata(dev);
+       struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+
+       clk_disable_unprepare(aus->clk);
+       pinctrl_pm_select_sleep_state(dev);
+
+       return 0;
+}
+
+__maybe_unused static int at91_usart_spi_runtime_resume(struct device *dev)
+{
+       struct spi_controller *ctrl = dev_get_drvdata(dev);
+       struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+
+       pinctrl_pm_select_default_state(dev);
+
+       return clk_prepare_enable(aus->clk);
+}
+
+__maybe_unused static int at91_usart_spi_suspend(struct device *dev)
+{
+       struct spi_controller *ctrl = dev_get_drvdata(dev);
+       int ret;
+
+       ret = spi_controller_suspend(ctrl);
+       if (ret)
+               return ret;
+
+       if (!pm_runtime_suspended(dev))
+               at91_usart_spi_runtime_suspend(dev);
+
+       return 0;
+}
+
+__maybe_unused static int at91_usart_spi_resume(struct device *dev)
+{
+       struct spi_controller *ctrl = dev_get_drvdata(dev);
+       struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+       int ret;
+
+       if (!pm_runtime_suspended(dev)) {
+               ret = at91_usart_spi_runtime_resume(dev);
+               if (ret)
+                       return ret;
+       }
+
+       at91_usart_spi_init(aus);
+
+       return spi_controller_resume(ctrl);
+}
+
 static int at91_usart_spi_remove(struct platform_device *pdev)
 {
        struct spi_controller *ctlr = platform_get_drvdata(pdev);
@@ -409,6 +464,12 @@ static int at91_usart_spi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct dev_pm_ops at91_usart_spi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(at91_usart_spi_suspend, at91_usart_spi_resume)
+       SET_RUNTIME_PM_OPS(at91_usart_spi_runtime_suspend,
+                          at91_usart_spi_runtime_resume, NULL)
+};
+
 static const struct of_device_id at91_usart_spi_dt_ids[] = {
        { .compatible = "microchip,at91sam9g45-usart-spi"},
        { /* sentinel */}
@@ -419,6 +480,7 @@ MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids);
 static struct platform_driver at91_usart_spi_driver = {
        .driver = {
                .name = "at91_usart_spi",
+               .pm = &at91_usart_spi_pm_ops,
        },
        .probe = at91_usart_spi_probe,
        .remove = at91_usart_spi_remove,
index f35cc10772f6670397ea923ad30158270dd68578..35aebdfd3b4e80cee5140648afdf839e6201170e 100644 (file)
@@ -20,7 +20,6 @@
  * GNU General Public License for more details.
  */
 
-#include <asm/page.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
@@ -72,6 +71,8 @@
 #define BCM2835_SPI_CS_CS_10           0x00000002
 #define BCM2835_SPI_CS_CS_01           0x00000001
 
+#define BCM2835_SPI_FIFO_SIZE          64
+#define BCM2835_SPI_FIFO_SIZE_3_4      48
 #define BCM2835_SPI_POLLING_LIMIT_US   30
 #define BCM2835_SPI_POLLING_JIFFIES    2
 #define BCM2835_SPI_DMA_MIN_LENGTH     96
 
 #define DRV_NAME       "spi-bcm2835"
 
+/**
+ * struct bcm2835_spi - BCM2835 SPI controller
+ * @regs: base address of register map
+ * @clk: core clock, divided to calculate serial clock
+ * @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full
+ * @tfr: SPI transfer currently processed
+ * @tx_buf: pointer whence next transmitted byte is read
+ * @rx_buf: pointer where next received byte is written
+ * @tx_len: remaining bytes to transmit
+ * @rx_len: remaining bytes to receive
+ * @tx_prologue: bytes transmitted without DMA if first TX sglist entry's
+ *     length is not a multiple of 4 (to overcome hardware limitation)
+ * @rx_prologue: bytes received without DMA if first RX sglist entry's
+ *     length is not a multiple of 4 (to overcome hardware limitation)
+ * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
+ * @dma_pending: whether a DMA transfer is in progress
+ */
 struct bcm2835_spi {
        void __iomem *regs;
        struct clk *clk;
        int irq;
+       struct spi_transfer *tfr;
        const u8 *tx_buf;
        u8 *rx_buf;
        int tx_len;
        int rx_len;
-       bool dma_pending;
+       int tx_prologue;
+       int rx_prologue;
+       unsigned int tx_spillover;
+       unsigned int dma_pending;
 };
 
 static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
@@ -126,6 +148,115 @@ static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs)
        }
 }
 
+/**
+ * bcm2835_rd_fifo_count() - blindly read exactly @count bytes from RX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes to read from RX FIFO
+ *
+ * The caller must ensure that @bs->rx_len is greater than or equal to @count,
+ * that the RX FIFO contains at least @count bytes and that the DMA Enable flag
+ * in the CS register is set (such that a read from the FIFO register receives
+ * 32-bit instead of just 8-bit).  Moreover @bs->rx_buf must not be %NULL.
+ */
+static inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count)
+{
+       u32 val;
+       int len;
+
+       bs->rx_len -= count;
+
+       while (count > 0) {
+               val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
+               len = min(count, 4);
+               memcpy(bs->rx_buf, &val, len);
+               bs->rx_buf += len;
+               count -= 4;
+       }
+}
+
+/**
+ * bcm2835_wr_fifo_count() - blindly write exactly @count bytes to TX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes to write to TX FIFO
+ *
+ * The caller must ensure that @bs->tx_len is greater than or equal to @count,
+ * that the TX FIFO can accommodate @count bytes and that the DMA Enable flag
+ * in the CS register is set (such that a write to the FIFO register transmits
+ * 32-bit instead of just 8-bit).
+ */
+static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count)
+{
+       u32 val;
+       int len;
+
+       bs->tx_len -= count;
+
+       while (count > 0) {
+               if (bs->tx_buf) {
+                       len = min(count, 4);
+                       memcpy(&val, bs->tx_buf, len);
+                       bs->tx_buf += len;
+               } else {
+                       val = 0;
+               }
+               bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
+               count -= 4;
+       }
+}
+
+/**
+ * bcm2835_wait_tx_fifo_empty() - busy-wait for TX FIFO to empty
+ * @bs: BCM2835 SPI controller
+ *
+ * The caller must ensure that the RX FIFO can accommodate as many bytes
+ * as have been written to the TX FIFO:  Transmission is halted once the
+ * RX FIFO is full, causing this function to spin forever.
+ */
+static inline void bcm2835_wait_tx_fifo_empty(struct bcm2835_spi *bs)
+{
+       while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
+               cpu_relax();
+}
+
+/**
+ * bcm2835_rd_fifo_blind() - blindly read up to @count bytes from RX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes available for reading in RX FIFO
+ */
+static inline void bcm2835_rd_fifo_blind(struct bcm2835_spi *bs, int count)
+{
+       u8 val;
+
+       count = min(count, bs->rx_len);
+       bs->rx_len -= count;
+
+       while (count) {
+               val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
+               if (bs->rx_buf)
+                       *bs->rx_buf++ = val;
+               count--;
+       }
+}
+
+/**
+ * bcm2835_wr_fifo_blind() - blindly write up to @count bytes to TX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes available for writing in TX FIFO
+ */
+static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
+{
+       u8 val;
+
+       count = min(count, bs->tx_len);
+       bs->tx_len -= count;
+
+       while (count) {
+               val = bs->tx_buf ? *bs->tx_buf++ : 0;
+               bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
+               count--;
+       }
+}
+
 static void bcm2835_spi_reset_hw(struct spi_master *master)
 {
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
@@ -149,14 +280,26 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 {
        struct spi_master *master = dev_id;
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+       /*
+        * An interrupt is signaled either if DONE is set (TX FIFO empty)
+        * or if RXR is set (RX FIFO >= ¾ full).
+        */
+       if (cs & BCM2835_SPI_CS_RXF)
+               bcm2835_rd_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
+       else if (cs & BCM2835_SPI_CS_RXR)
+               bcm2835_rd_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE_3_4);
+
+       if (bs->tx_len && cs & BCM2835_SPI_CS_DONE)
+               bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
 
        /* Read as many bytes as possible from FIFO */
        bcm2835_rd_fifo(bs);
        /* Write as many bytes as possible to FIFO */
        bcm2835_wr_fifo(bs);
 
-       /* based on flags decide if we can finish the transfer */
-       if (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) {
+       if (!bs->rx_len) {
                /* Transfer complete - reset SPI HW */
                bcm2835_spi_reset_hw(master);
                /* wake up the framework */
@@ -169,32 +312,22 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
-                                       u32 cs)
+                                       u32 cs, bool fifo_empty)
 {
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
 
-       /* fill in fifo if we have gpio-cs
-        * note that there have been rare events where the native-CS
-        * flapped for <1us which may change the behaviour
-        * with gpio-cs this does not happen, so it is implemented
-        * only for this case
-        */
-       if (gpio_is_valid(spi->cs_gpio)) {
-               /* enable HW block, but without interrupts enabled
-                * this would triggern an immediate interrupt
-                */
-               bcm2835_wr(bs, BCM2835_SPI_CS,
-                          cs | BCM2835_SPI_CS_TA);
-               /* fill in tx fifo as much as possible */
-               bcm2835_wr_fifo(bs);
-       }
-
        /*
-        * Enable the HW block. This will immediately trigger a DONE (TX
-        * empty) interrupt, upon which we will fill the TX FIFO with the
-        * first TX bytes. Pre-filling the TX FIFO here to avoid the
-        * interrupt doesn't work:-(
+        * Enable HW block, but with interrupts still disabled.
+        * Otherwise the empty TX FIFO would immediately trigger an interrupt.
         */
+       bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
+
+       /* fill TX FIFO as much as possible */
+       if (fifo_empty)
+               bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
+       bcm2835_wr_fifo(bs);
+
+       /* enable interrupts */
        cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA;
        bcm2835_wr(bs, BCM2835_SPI_CS, cs);
 
@@ -211,15 +344,162 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
  * the main one being that DMA transfers are limited to 16 bit
  * (so 0 to 65535 bytes) by the SPI HW due to BCM2835_SPI_DLEN
  *
- * also we currently assume that the scatter-gather fragments are
- * all multiple of 4 (except the last) - otherwise we would need
- * to reset the FIFO before subsequent transfers...
- * this also means that tx/rx transfers sg's need to be of equal size!
- *
  * there may be a few more border-cases we may need to address as well
  * but unfortunately this would mean splitting up the scatter-gather
  * list making it slightly unpractical...
  */
+
+/**
+ * bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
+ * @master: SPI master
+ * @tfr: SPI transfer
+ * @bs: BCM2835 SPI controller
+ * @cs: CS register
+ *
+ * A limitation in DMA mode is that the FIFO must be accessed in 4 byte chunks.
+ * Only the final write access is permitted to transmit less than 4 bytes, the
+ * SPI controller deduces its intended size from the DLEN register.
+ *
+ * If a TX or RX sglist contains multiple entries, one per page, and the first
+ * entry starts in the middle of a page, that first entry's length may not be
+ * a multiple of 4.  Subsequent entries are fine because they span an entire
+ * page, hence do have a length that's a multiple of 4.
+ *
+ * This cannot happen with kmalloc'ed buffers (which is what most clients use)
+ * because they are contiguous in physical memory and therefore not split on
+ * page boundaries by spi_map_buf().  But it *can* happen with vmalloc'ed
+ * buffers.
+ *
+ * The DMA engine is incapable of combining sglist entries into a continuous
+ * stream of 4 byte chunks, it treats every entry separately:  A TX entry is
+ * rounded up a to a multiple of 4 bytes by transmitting surplus bytes, an RX
+ * entry is rounded up by throwing away received bytes.
+ *
+ * Overcome this limitation by transferring the first few bytes without DMA:
+ * E.g. if the first TX sglist entry's length is 23 and the first RX's is 42,
+ * write 3 bytes to the TX FIFO but read only 2 bytes from the RX FIFO.
+ * The residue of 1 byte in the RX FIFO is picked up by DMA.  Together with
+ * the rest of the first RX sglist entry it makes up a multiple of 4 bytes.
+ *
+ * Should the RX prologue be larger, say, 3 vis-à-vis a TX prologue of 1,
+ * write 1 + 4 = 5 bytes to the TX FIFO and read 3 bytes from the RX FIFO.
+ * Caution, the additional 4 bytes spill over to the second TX sglist entry
+ * if the length of the first is *exactly* 1.
+ *
+ * At most 6 bytes are written and at most 3 bytes read.  Do we know the
+ * transfer has this many bytes?  Yes, see BCM2835_SPI_DMA_MIN_LENGTH.
+ *
+ * The FIFO is normally accessed with 8-bit width by the CPU and 32-bit width
+ * by the DMA engine.  Toggling the DMA Enable flag in the CS register switches
+ * the width but also garbles the FIFO's contents.  The prologue must therefore
+ * be transmitted in 32-bit width to ensure that the following DMA transfer can
+ * pick up the residue in the RX FIFO in ungarbled form.
+ */
+static void bcm2835_spi_transfer_prologue(struct spi_master *master,
+                                         struct spi_transfer *tfr,
+                                         struct bcm2835_spi *bs,
+                                         u32 cs)
+{
+       int tx_remaining;
+
+       bs->tfr          = tfr;
+       bs->tx_prologue  = 0;
+       bs->rx_prologue  = 0;
+       bs->tx_spillover = false;
+
+       if (!sg_is_last(&tfr->tx_sg.sgl[0]))
+               bs->tx_prologue = sg_dma_len(&tfr->tx_sg.sgl[0]) & 3;
+
+       if (!sg_is_last(&tfr->rx_sg.sgl[0])) {
+               bs->rx_prologue = sg_dma_len(&tfr->rx_sg.sgl[0]) & 3;
+
+               if (bs->rx_prologue > bs->tx_prologue) {
+                       if (sg_is_last(&tfr->tx_sg.sgl[0])) {
+                               bs->tx_prologue  = bs->rx_prologue;
+                       } else {
+                               bs->tx_prologue += 4;
+                               bs->tx_spillover =
+                                       !(sg_dma_len(&tfr->tx_sg.sgl[0]) & ~3);
+                       }
+               }
+       }
+
+       /* rx_prologue > 0 implies tx_prologue > 0, so check only the latter */
+       if (!bs->tx_prologue)
+               return;
+
+       /* Write and read RX prologue.  Adjust first entry in RX sglist. */
+       if (bs->rx_prologue) {
+               bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->rx_prologue);
+               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA
+                                                 | BCM2835_SPI_CS_DMAEN);
+               bcm2835_wr_fifo_count(bs, bs->rx_prologue);
+               bcm2835_wait_tx_fifo_empty(bs);
+               bcm2835_rd_fifo_count(bs, bs->rx_prologue);
+               bcm2835_spi_reset_hw(master);
+
+               dma_sync_single_for_device(master->dma_rx->device->dev,
+                                          sg_dma_address(&tfr->rx_sg.sgl[0]),
+                                          bs->rx_prologue, DMA_FROM_DEVICE);
+
+               sg_dma_address(&tfr->rx_sg.sgl[0]) += bs->rx_prologue;
+               sg_dma_len(&tfr->rx_sg.sgl[0])     -= bs->rx_prologue;
+       }
+
+       /*
+        * Write remaining TX prologue.  Adjust first entry in TX sglist.
+        * Also adjust second entry if prologue spills over to it.
+        */
+       tx_remaining = bs->tx_prologue - bs->rx_prologue;
+       if (tx_remaining) {
+               bcm2835_wr(bs, BCM2835_SPI_DLEN, tx_remaining);
+               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA
+                                                 | BCM2835_SPI_CS_DMAEN);
+               bcm2835_wr_fifo_count(bs, tx_remaining);
+               bcm2835_wait_tx_fifo_empty(bs);
+               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_CLEAR_TX);
+       }
+
+       if (likely(!bs->tx_spillover)) {
+               sg_dma_address(&tfr->tx_sg.sgl[0]) += bs->tx_prologue;
+               sg_dma_len(&tfr->tx_sg.sgl[0])     -= bs->tx_prologue;
+       } else {
+               sg_dma_len(&tfr->tx_sg.sgl[0])      = 0;
+               sg_dma_address(&tfr->tx_sg.sgl[1]) += 4;
+               sg_dma_len(&tfr->tx_sg.sgl[1])     -= 4;
+       }
+}
+
+/**
+ * bcm2835_spi_undo_prologue() - reconstruct original sglist state
+ * @bs: BCM2835 SPI controller
+ *
+ * Undo changes which were made to an SPI transfer's sglist when transmitting
+ * the prologue.  This is necessary to ensure the same memory ranges are
+ * unmapped that were originally mapped.
+ */
+static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
+{
+       struct spi_transfer *tfr = bs->tfr;
+
+       if (!bs->tx_prologue)
+               return;
+
+       if (bs->rx_prologue) {
+               sg_dma_address(&tfr->rx_sg.sgl[0]) -= bs->rx_prologue;
+               sg_dma_len(&tfr->rx_sg.sgl[0])     += bs->rx_prologue;
+       }
+
+       if (likely(!bs->tx_spillover)) {
+               sg_dma_address(&tfr->tx_sg.sgl[0]) -= bs->tx_prologue;
+               sg_dma_len(&tfr->tx_sg.sgl[0])     += bs->tx_prologue;
+       } else {
+               sg_dma_len(&tfr->tx_sg.sgl[0])      = bs->tx_prologue - 4;
+               sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4;
+               sg_dma_len(&tfr->tx_sg.sgl[1])     += 4;
+       }
+}
+
 static void bcm2835_spi_dma_done(void *data)
 {
        struct spi_master *master = data;
@@ -233,10 +513,10 @@ static void bcm2835_spi_dma_done(void *data)
         * is called the tx-dma must have finished - can't get to this
         * situation otherwise...
         */
-       dmaengine_terminate_all(master->dma_tx);
-
-       /* mark as no longer pending */
-       bs->dma_pending = 0;
+       if (cmpxchg(&bs->dma_pending, true, false)) {
+               dmaengine_terminate_async(master->dma_tx);
+               bcm2835_spi_undo_prologue(bs);
+       }
 
        /* and mark as completed */;
        complete(&master->xfer_completion);
@@ -286,20 +566,6 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
        return dma_submit_error(cookie);
 }
 
-static inline int bcm2835_check_sg_length(struct sg_table *sgt)
-{
-       int i;
-       struct scatterlist *sgl;
-
-       /* check that the sg entries are word-sized (except for last) */
-       for_each_sg(sgt->sgl, sgl, (int)sgt->nents - 1, i) {
-               if (sg_dma_len(sgl) % 4)
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
 static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
@@ -308,18 +574,16 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
        int ret;
 
-       /* check that the scatter gather segments are all a multiple of 4 */
-       if (bcm2835_check_sg_length(&tfr->tx_sg) ||
-           bcm2835_check_sg_length(&tfr->rx_sg)) {
-               dev_warn_once(&spi->dev,
-                             "scatter gather segment length is not a multiple of 4 - falling back to interrupt mode\n");
-               return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
-       }
+       /*
+        * Transfer first few bytes without DMA if length of first TX or RX
+        * sglist entry is not a multiple of 4 bytes (hardware limitation).
+        */
+       bcm2835_spi_transfer_prologue(master, tfr, bs, cs);
 
        /* setup tx-DMA */
        ret = bcm2835_spi_prepare_sg(master, tfr, true);
        if (ret)
-               return ret;
+               goto err_reset_hw;
 
        /* start TX early */
        dma_async_issue_pending(master->dma_tx);
@@ -328,7 +592,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
        bs->dma_pending = 1;
 
        /* set the DMA length */
-       bcm2835_wr(bs, BCM2835_SPI_DLEN, tfr->len);
+       bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);
 
        /* start the HW */
        bcm2835_wr(bs, BCM2835_SPI_CS,
@@ -341,9 +605,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
        ret = bcm2835_spi_prepare_sg(master, tfr, false);
        if (ret) {
                /* need to reset on errors */
-               dmaengine_terminate_all(master->dma_tx);
-               bcm2835_spi_reset_hw(master);
-               return ret;
+               dmaengine_terminate_sync(master->dma_tx);
+               bs->dma_pending = false;
+               goto err_reset_hw;
        }
 
        /* start rx dma late */
@@ -351,16 +615,17 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
 
        /* wait for wakeup in framework */
        return 1;
+
+err_reset_hw:
+       bcm2835_spi_reset_hw(master);
+       bcm2835_spi_undo_prologue(bs);
+       return ret;
 }
 
 static bool bcm2835_spi_can_dma(struct spi_master *master,
                                struct spi_device *spi,
                                struct spi_transfer *tfr)
 {
-       /* only run for gpio_cs */
-       if (!gpio_is_valid(spi->cs_gpio))
-               return false;
-
        /* we start DMA efforts only on bigger transfers */
        if (tfr->len < BCM2835_SPI_DMA_MIN_LENGTH)
                return false;
@@ -378,25 +643,6 @@ static bool bcm2835_spi_can_dma(struct spi_master *master,
                return false;
        }
 
-       /* if we run rx/tx_buf with word aligned addresses then we are OK */
-       if ((((size_t)tfr->rx_buf & 3) == 0) &&
-           (((size_t)tfr->tx_buf & 3) == 0))
-               return true;
-
-       /* otherwise we only allow transfers within the same page
-        * to avoid wasting time on dma_mapping when it is not practical
-        */
-       if (((size_t)tfr->tx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) {
-               dev_warn_once(&spi->dev,
-                             "Unaligned spi tx-transfer bridging page\n");
-               return false;
-       }
-       if (((size_t)tfr->rx_buf & (PAGE_SIZE - 1)) + tfr->len > PAGE_SIZE) {
-               dev_warn_once(&spi->dev,
-                             "Unaligned spi rx-transfer bridging page\n");
-               return false;
-       }
-
        /* return OK */
        return true;
 }
@@ -404,12 +650,12 @@ static bool bcm2835_spi_can_dma(struct spi_master *master,
 static void bcm2835_dma_release(struct spi_master *master)
 {
        if (master->dma_tx) {
-               dmaengine_terminate_all(master->dma_tx);
+               dmaengine_terminate_sync(master->dma_tx);
                dma_release_channel(master->dma_tx);
                master->dma_tx = NULL;
        }
        if (master->dma_rx) {
-               dmaengine_terminate_all(master->dma_rx);
+               dmaengine_terminate_sync(master->dma_rx);
                dma_release_channel(master->dma_rx);
                master->dma_rx = NULL;
        }
@@ -492,7 +738,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
         * if we are interrupted here, then the data is
         * getting transferred by the HW while we are interrupted
         */
-       bcm2835_wr_fifo(bs);
+       bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
 
        /* set the timeout */
        timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
@@ -515,7 +761,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
                                            bs->tx_len, bs->rx_len);
                        /* fall back to interrupt mode */
                        return bcm2835_spi_transfer_one_irq(master, spi,
-                                                           tfr, cs);
+                                                           tfr, cs, false);
                }
        }
 
@@ -560,12 +806,12 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
        else
                cs &= ~BCM2835_SPI_CS_REN;
 
-       /* for gpio_cs set dummy CS so that no HW-CS get changed
-        * we can not run this in bcm2835_spi_set_cs, as it does
-        * not get called for cs_gpio cases, so we need to do it here
+       /*
+        * The driver always uses software-controlled GPIO Chip Select.
+        * Set the hardware-controlled native Chip Select to an invalid
+        * value to prevent it from interfering.
         */
-       if (gpio_is_valid(spi->cs_gpio) || (spi->mode & SPI_NO_CS))
-               cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
+       cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
 
        /* set transmit buffers and length */
        bs->tx_buf = tfr->tx_buf;
@@ -589,7 +835,7 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
                return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs);
 
        /* run in interrupt-mode */
-       return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
+       return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs, true);
 }
 
 static int bcm2835_spi_prepare_message(struct spi_master *master,
@@ -617,68 +863,15 @@ static void bcm2835_spi_handle_err(struct spi_master *master,
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
 
        /* if an error occurred and we have an active dma, then terminate */
-       if (bs->dma_pending) {
-               dmaengine_terminate_all(master->dma_tx);
-               dmaengine_terminate_all(master->dma_rx);
-               bs->dma_pending = 0;
+       if (cmpxchg(&bs->dma_pending, true, false)) {
+               dmaengine_terminate_sync(master->dma_tx);
+               dmaengine_terminate_sync(master->dma_rx);
+               bcm2835_spi_undo_prologue(bs);
        }
        /* and reset */
        bcm2835_spi_reset_hw(master);
 }
 
-static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level)
-{
-       /*
-        * we can assume that we are "native" as per spi_set_cs
-        *   calling us ONLY when cs_gpio is not set
-        * we can also assume that we are CS < 3 as per bcm2835_spi_setup
-        *   we would not get called because of error handling there.
-        * the level passed is the electrical level not enabled/disabled
-        *   so it has to get translated back to enable/disable
-        *   see spi_set_cs in spi.c for the implementation
-        */
-
-       struct spi_master *master = spi->master;
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
-       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
-       bool enable;
-
-       /* calculate the enable flag from the passed gpio_level */
-       enable = (spi->mode & SPI_CS_HIGH) ? gpio_level : !gpio_level;
-
-       /* set flags for "reverse" polarity in the registers */
-       if (spi->mode & SPI_CS_HIGH) {
-               /* set the correct CS-bits */
-               cs |= BCM2835_SPI_CS_CSPOL;
-               cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select;
-       } else {
-               /* clean the CS-bits */
-               cs &= ~BCM2835_SPI_CS_CSPOL;
-               cs &= ~(BCM2835_SPI_CS_CSPOL0 << spi->chip_select);
-       }
-
-       /* select the correct chip_select depending on disabled/enabled */
-       if (enable) {
-               /* set cs correctly */
-               if (spi->mode & SPI_NO_CS) {
-                       /* use the "undefined" chip-select */
-                       cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
-               } else {
-                       /* set the chip select */
-                       cs &= ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01);
-                       cs |= spi->chip_select;
-               }
-       } else {
-               /* disable CSPOL which puts HW-CS into deselected state */
-               cs &= ~BCM2835_SPI_CS_CSPOL;
-               /* use the "undefined" chip-select as precaution */
-               cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
-       }
-
-       /* finally set the calculated flags in SPI_CS */
-       bcm2835_wr(bs, BCM2835_SPI_CS, cs);
-}
-
 static int chip_match_name(struct gpio_chip *chip, void *data)
 {
        return !strcmp(chip->label, data);
@@ -750,7 +943,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->num_chipselect = 3;
        master->setup = bcm2835_spi_setup;
-       master->set_cs = bcm2835_spi_set_cs;
        master->transfer_one = bcm2835_spi_transfer_one;
        master->handle_err = bcm2835_spi_handle_err;
        master->prepare_message = bcm2835_spi_prepare_message;
@@ -843,4 +1035,4 @@ module_platform_driver(bcm2835_spi_driver);
 
 MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835");
 MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
index 3094d818cf06d4751122611bc2eb807e71d965fd..671e374e1b01fa50a73ed97050fc38624e20432e 100644 (file)
@@ -542,4 +542,4 @@ module_platform_driver(bcm2835aux_spi_driver);
 
 MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835 aux");
 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
index 3ffb6a40fe0c3040aada120769bf3a0dc7286012..d0dd7814e997834793f3e1e49339bd28c73d15ee 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_platform.h>
+#include <linux/acpi.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
 
@@ -243,12 +244,19 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
 
+static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
+       {"HISI0173", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
+
 static struct platform_driver dw_spi_mmio_driver = {
        .probe          = dw_spi_mmio_probe,
        .remove         = dw_spi_mmio_remove,
        .driver         = {
                .name   = DRIVER_NAME,
                .of_match_table = dw_spi_mmio_of_match,
+               .acpi_match_table = ACPI_PTR(dw_spi_mmio_acpi_match),
        },
 };
 module_platform_driver(dw_spi_mmio_driver);
index b705f2bdb8b9493cd39d416d512084f4b8d33849..2e822a56576acfa04afaf3c51064cdcd7d7d82c5 100644 (file)
@@ -507,6 +507,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        master->handle_err = dw_spi_handle_err;
        master->max_speed_hz = dws->max_freq;
        master->dev.of_node = dev->of_node;
+       master->dev.fwnode = dev->fwnode;
        master->flags = SPI_MASTER_GPIO_SS;
 
        if (dws->set_cs)
index 3082e72e4f6c62ed00651e389381ee2896336c52..5e10dc5c93a5a23fd460591da8425a5f9de34251 100644 (file)
@@ -1090,8 +1090,8 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_clk_put;
        }
 
-       ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0,
-                       pdev->name, dspi);
+       ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt,
+                              IRQF_SHARED, pdev->name, dspi);
        if (ret < 0) {
                dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n");
                goto out_clk_put;
index 51670976faa35b668152a35b69211e802cc613d6..08dcc3c22e8836c0a2032d0f5fb963d811461879 100644 (file)
@@ -3,6 +3,7 @@
 // Freescale i.MX7ULP LPSPI driver
 //
 // Copyright 2016 Freescale Semiconductor, Inc.
+// Copyright 2018 NXP Semiconductors
 
 #include <linux/clk.h>
 #include <linux/completion.h>
@@ -54,6 +55,7 @@
 #define IER_RDIE       BIT(1)
 #define IER_TDIE       BIT(0)
 #define CFGR1_PCSCFG   BIT(27)
+#define CFGR1_PINCFG   (BIT(24)|BIT(25))
 #define CFGR1_PCSPOL   BIT(8)
 #define CFGR1_NOSTALL  BIT(3)
 #define CFGR1_MASTER   BIT(0)
@@ -79,6 +81,7 @@ struct fsl_lpspi_data {
        struct device *dev;
        void __iomem *base;
        struct clk *clk;
+       bool is_slave;
 
        void *rx_buf;
        const void *tx_buf;
@@ -86,11 +89,14 @@ struct fsl_lpspi_data {
        void (*rx)(struct fsl_lpspi_data *);
 
        u32 remain;
+       u8 watermark;
        u8 txfifosize;
        u8 rxfifosize;
 
        struct lpspi_config config;
        struct completion xfer_done;
+
+       bool slave_aborted;
 };
 
 static const struct of_device_id fsl_lpspi_dt_ids[] = {
@@ -137,16 +143,18 @@ static void fsl_lpspi_intctrl(struct fsl_lpspi_data *fsl_lpspi,
        writel(enable, fsl_lpspi->base + IMX7ULP_IER);
 }
 
-static int lpspi_prepare_xfer_hardware(struct spi_master *master)
+static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
 {
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
 
        return clk_prepare_enable(fsl_lpspi->clk);
 }
 
-static int lpspi_unprepare_xfer_hardware(struct spi_master *master)
+static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
 {
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
 
        clk_disable_unprepare(fsl_lpspi->clk);
 
@@ -203,21 +211,22 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi,
        u32 temp = 0;
 
        temp |= fsl_lpspi->config.bpw - 1;
-       temp |= fsl_lpspi->config.prescale << 27;
        temp |= (fsl_lpspi->config.mode & 0x3) << 30;
-       temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
-
-       /*
-        * Set TCR_CONT will keep SS asserted after current transfer.
-        * For the first transfer, clear TCR_CONTC to assert SS.
-        * For subsequent transfer, set TCR_CONTC to keep SS asserted.
-        */
-       temp |= TCR_CONT;
-       if (is_first_xfer)
-               temp &= ~TCR_CONTC;
-       else
-               temp |= TCR_CONTC;
-
+       if (!fsl_lpspi->is_slave) {
+               temp |= fsl_lpspi->config.prescale << 27;
+               temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
+
+               /*
+                * Set TCR_CONT will keep SS asserted after current transfer.
+                * For the first transfer, clear TCR_CONTC to assert SS.
+                * For subsequent transfer, set TCR_CONTC to keep SS asserted.
+                */
+               temp |= TCR_CONT;
+               if (is_first_xfer)
+                       temp &= ~TCR_CONTC;
+               else
+                       temp |= TCR_CONTC;
+       }
        writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
 
        dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp);
@@ -227,7 +236,7 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
 {
        u32 temp;
 
-       temp = fsl_lpspi->txfifosize >> 1 | (fsl_lpspi->rxfifosize >> 1) << 16;
+       temp = fsl_lpspi->watermark >> 1 | (fsl_lpspi->watermark >> 1) << 16;
 
        writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
 
@@ -253,7 +262,8 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
        if (prescale == 8 && scldiv >= 256)
                return -EINVAL;
 
-       writel(scldiv, fsl_lpspi->base + IMX7ULP_CCR);
+       writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
+                                       fsl_lpspi->base + IMX7ULP_CCR);
 
        dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale =%d, scldiv=%d\n",
                perclk_rate, config.speed_hz, prescale, scldiv);
@@ -270,13 +280,18 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
        writel(temp, fsl_lpspi->base + IMX7ULP_CR);
        writel(0, fsl_lpspi->base + IMX7ULP_CR);
 
-       ret = fsl_lpspi_set_bitrate(fsl_lpspi);
-       if (ret)
-               return ret;
+       if (!fsl_lpspi->is_slave) {
+               ret = fsl_lpspi_set_bitrate(fsl_lpspi);
+               if (ret)
+                       return ret;
+       }
 
        fsl_lpspi_set_watermark(fsl_lpspi);
 
-       temp = CFGR1_PCSCFG | CFGR1_MASTER;
+       if (!fsl_lpspi->is_slave)
+               temp = CFGR1_MASTER;
+       else
+               temp = CFGR1_PINCFG;
        if (fsl_lpspi->config.mode & SPI_CS_HIGH)
                temp |= CFGR1_PCSPOL;
        writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
@@ -291,7 +306,8 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
 static void fsl_lpspi_setup_transfer(struct spi_device *spi,
                                     struct spi_transfer *t)
 {
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(spi->master);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(spi->controller);
 
        fsl_lpspi->config.mode = spi->mode;
        fsl_lpspi->config.bpw = t ? t->bits_per_word : spi->bits_per_word;
@@ -315,14 +331,51 @@ static void fsl_lpspi_setup_transfer(struct spi_device *spi,
                fsl_lpspi->tx = fsl_lpspi_buf_tx_u32;
        }
 
+       if (t->len <= fsl_lpspi->txfifosize)
+               fsl_lpspi->watermark = t->len;
+       else
+               fsl_lpspi->watermark = fsl_lpspi->txfifosize;
+
        fsl_lpspi_config(fsl_lpspi);
 }
 
-static int fsl_lpspi_transfer_one(struct spi_master *master,
+static int fsl_lpspi_slave_abort(struct spi_controller *controller)
+{
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
+
+       fsl_lpspi->slave_aborted = true;
+       complete(&fsl_lpspi->xfer_done);
+       return 0;
+}
+
+static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
+{
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
+
+       if (fsl_lpspi->is_slave) {
+               if (wait_for_completion_interruptible(&fsl_lpspi->xfer_done) ||
+                       fsl_lpspi->slave_aborted) {
+                       dev_dbg(fsl_lpspi->dev, "interrupted\n");
+                       return -EINTR;
+               }
+       } else {
+               if (!wait_for_completion_timeout(&fsl_lpspi->xfer_done, HZ)) {
+                       dev_dbg(fsl_lpspi->dev, "wait for completion timeout\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int fsl_lpspi_transfer_one(struct spi_controller *controller,
                                  struct spi_device *spi,
                                  struct spi_transfer *t)
 {
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
        int ret;
 
        fsl_lpspi->tx_buf = t->tx_buf;
@@ -330,13 +383,13 @@ static int fsl_lpspi_transfer_one(struct spi_master *master,
        fsl_lpspi->remain = t->len;
 
        reinit_completion(&fsl_lpspi->xfer_done);
+       fsl_lpspi->slave_aborted = false;
+
        fsl_lpspi_write_tx_fifo(fsl_lpspi);
 
-       ret = wait_for_completion_timeout(&fsl_lpspi->xfer_done, HZ);
-       if (!ret) {
-               dev_dbg(fsl_lpspi->dev, "wait for completion timeout\n");
-               return -ETIMEDOUT;
-       }
+       ret = fsl_lpspi_wait_for_completion(controller);
+       if (ret)
+               return ret;
 
        ret = fsl_lpspi_txfifo_empty(fsl_lpspi);
        if (ret)
@@ -347,10 +400,11 @@ static int fsl_lpspi_transfer_one(struct spi_master *master,
        return 0;
 }
 
-static int fsl_lpspi_transfer_one_msg(struct spi_master *master,
+static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
                                      struct spi_message *msg)
 {
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
        struct spi_device *spi = msg->spi;
        struct spi_transfer *xfer;
        bool is_first_xfer = true;
@@ -366,7 +420,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master,
 
                is_first_xfer = false;
 
-               ret = fsl_lpspi_transfer_one(master, spi, xfer);
+               ret = fsl_lpspi_transfer_one(controller, spi, xfer);
                if (ret < 0)
                        goto complete;
 
@@ -374,13 +428,15 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master,
        }
 
 complete:
-       /* de-assert SS, then finalize current message */
-       temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
-       temp &= ~TCR_CONTC;
-       writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+       if (!fsl_lpspi->is_slave) {
+               /* de-assert SS, then finalize current message */
+               temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
+               temp &= ~TCR_CONTC;
+               writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+       }
 
        msg->status = ret;
-       spi_finalize_current_message(master);
+       spi_finalize_current_message(controller);
 
        return ret;
 }
@@ -410,30 +466,39 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 static int fsl_lpspi_probe(struct platform_device *pdev)
 {
        struct fsl_lpspi_data *fsl_lpspi;
-       struct spi_master *master;
+       struct spi_controller *controller;
        struct resource *res;
        int ret, irq;
        u32 temp;
 
-       master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_lpspi_data));
-       if (!master)
+       if (of_property_read_bool((&pdev->dev)->of_node, "spi-slave"))
+               controller = spi_alloc_slave(&pdev->dev,
+                                       sizeof(struct fsl_lpspi_data));
+       else
+               controller = spi_alloc_master(&pdev->dev,
+                                       sizeof(struct fsl_lpspi_data));
+
+       if (!controller)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, master);
+       platform_set_drvdata(pdev, controller);
 
-       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
-       master->bus_num = pdev->id;
+       controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+       controller->bus_num = pdev->id;
 
-       fsl_lpspi = spi_master_get_devdata(master);
+       fsl_lpspi = spi_controller_get_devdata(controller);
        fsl_lpspi->dev = &pdev->dev;
-
-       master->transfer_one_message = fsl_lpspi_transfer_one_msg;
-       master->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
-       master->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
-       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-       master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
-       master->dev.of_node = pdev->dev.of_node;
-       master->bus_num = pdev->id;
+       fsl_lpspi->is_slave = of_property_read_bool((&pdev->dev)->of_node,
+                                                   "spi-slave");
+
+       controller->transfer_one_message = fsl_lpspi_transfer_one_msg;
+       controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
+       controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
+       controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+       controller->dev.of_node = pdev->dev.of_node;
+       controller->bus_num = pdev->id;
+       controller->slave_abort = fsl_lpspi_slave_abort;
 
        init_completion(&fsl_lpspi->xfer_done);
 
@@ -441,32 +506,32 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
        fsl_lpspi->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(fsl_lpspi->base)) {
                ret = PTR_ERR(fsl_lpspi->base);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = irq;
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0,
                               dev_name(&pdev->dev), fsl_lpspi);
        if (ret) {
                dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        fsl_lpspi->clk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(fsl_lpspi->clk)) {
                ret = PTR_ERR(fsl_lpspi->clk);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        ret = clk_prepare_enable(fsl_lpspi->clk);
        if (ret) {
                dev_err(&pdev->dev, "can't enable lpspi clock, ret=%d\n", ret);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
@@ -475,24 +540,25 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 
        clk_disable_unprepare(fsl_lpspi->clk);
 
-       ret = devm_spi_register_master(&pdev->dev, master);
+       ret = devm_spi_register_controller(&pdev->dev, controller);
        if (ret < 0) {
-               dev_err(&pdev->dev, "spi_register_master error.\n");
-               goto out_master_put;
+               dev_err(&pdev->dev, "spi_register_controller error.\n");
+               goto out_controller_put;
        }
 
        return 0;
 
-out_master_put:
-       spi_master_put(master);
+out_controller_put:
+       spi_controller_put(controller);
 
        return ret;
 }
 
 static int fsl_lpspi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
-       struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+       struct spi_controller *controller = platform_get_drvdata(pdev);
+       struct fsl_lpspi_data *fsl_lpspi =
+                               spi_controller_get_devdata(controller);
 
        clk_disable_unprepare(fsl_lpspi->clk);
 
@@ -509,6 +575,6 @@ static struct platform_driver fsl_lpspi_driver = {
 };
 module_platform_driver(fsl_lpspi_driver);
 
-MODULE_DESCRIPTION("LPSPI Master Controller driver");
+MODULE_DESCRIPTION("LPSPI Controller driver");
 MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
 MODULE_LICENSE("GPL");
index 6432ecc4e2ca9c1ca63a009e8d086f3e9f6ac6e4..fdb7cb88fb5673aeebdb36887ea2befea1240513 100644 (file)
 #define TIMESTAMP_AFTER                BIT(3)
 #define POST_CMD_DELAY         BIT(4)
 
-/* SPI M_COMMAND OPCODE */
-enum spi_mcmd_code {
+enum spi_m_cmd_opcode {
        CMD_NONE,
        CMD_XFER,
        CMD_CS,
        CMD_CANCEL,
 };
 
-
 struct spi_geni_master {
        struct geni_se se;
        struct device *dev;
@@ -87,7 +85,7 @@ struct spi_geni_master {
        struct completion xfer_done;
        unsigned int oversampling;
        spinlock_t lock;
-       unsigned int cur_mcmd;
+       enum spi_m_cmd_opcode cur_mcmd;
        int irq;
 };
 
@@ -129,7 +127,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
        struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
        struct spi_master *spi = dev_get_drvdata(mas->dev);
        struct geni_se *se = &mas->se;
-       unsigned long timeout;
+       unsigned long time_left;
 
        reinit_completion(&mas->xfer_done);
        pm_runtime_get_sync(mas->dev);
@@ -142,8 +140,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
        else
                geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0);
 
-       timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
-       if (!timeout)
+       time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
+       if (!time_left)
                handle_fifo_timeout(spi, NULL);
 
        pm_runtime_put(mas->dev);
@@ -485,7 +483,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
        struct geni_se *se = &mas->se;
        u32 m_irq;
        unsigned long flags;
-       irqreturn_t ret = IRQ_HANDLED;
 
        if (mas->cur_mcmd == CMD_NONE)
                return IRQ_NONE;
@@ -533,16 +530,35 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
 
        writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR);
        spin_unlock_irqrestore(&mas->lock, flags);
-       return ret;
+       return IRQ_HANDLED;
 }
 
 static int spi_geni_probe(struct platform_device *pdev)
 {
-       int ret;
+       int ret, irq;
        struct spi_master *spi;
        struct spi_geni_master *mas;
        struct resource *res;
-       struct geni_se *se;
+       void __iomem *base;
+       struct clk *clk;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Err getting IRQ %d\n", irq);
+               return irq;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       clk = devm_clk_get(&pdev->dev, "se");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "Err getting SE Core clk %ld\n",
+                                               PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
 
        spi = spi_alloc_master(&pdev->dev, sizeof(*mas));
        if (!spi)
@@ -550,27 +566,15 @@ static int spi_geni_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, spi);
        mas = spi_master_get_devdata(spi);
+       mas->irq = irq;
        mas->dev = &pdev->dev;
        mas->se.dev = &pdev->dev;
        mas->se.wrapper = dev_get_drvdata(pdev->dev.parent);
-       se = &mas->se;
+       mas->se.base = base;
+       mas->se.clk = clk;
 
        spi->bus_num = -1;
        spi->dev.of_node = pdev->dev.of_node;
-       mas->se.clk = devm_clk_get(&pdev->dev, "se");
-       if (IS_ERR(mas->se.clk)) {
-               ret = PTR_ERR(mas->se.clk);
-               dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
-               goto spi_geni_probe_err;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       se->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(se->base)) {
-               ret = PTR_ERR(se->base);
-               goto spi_geni_probe_err;
-       }
-
        spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH;
        spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        spi->num_chipselect = 4;
@@ -589,13 +593,6 @@ static int spi_geni_probe(struct platform_device *pdev)
        if (ret)
                goto spi_geni_probe_runtime_disable;
 
-       mas->irq = platform_get_irq(pdev, 0);
-       if (mas->irq < 0) {
-               ret = mas->irq;
-               dev_err(&pdev->dev, "Err getting IRQ %d\n", ret);
-               goto spi_geni_probe_runtime_disable;
-       }
-
        ret = request_irq(mas->irq, geni_spi_isr,
                        IRQF_TRIGGER_HIGH, "spi_geni", spi);
        if (ret)
@@ -610,7 +607,6 @@ spi_geni_probe_free_irq:
        free_irq(mas->irq, spi);
 spi_geni_probe_runtime_disable:
        pm_runtime_disable(&pdev->dev);
-spi_geni_probe_err:
        spi_master_put(spi);
        return ret;
 }
index 45973ee3ae119e59a3b6846889b0449a7ba3e0d6..a4aee26028cdf59c8bce2144e02b532e0d591cbd 100644 (file)
@@ -256,11 +256,29 @@ static int spi_gpio_setup(struct spi_device *spi)
 static int spi_gpio_set_direction(struct spi_device *spi, bool output)
 {
        struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+       int ret;
 
        if (output)
                return gpiod_direction_output(spi_gpio->mosi, 1);
-       else
-               return gpiod_direction_input(spi_gpio->mosi);
+
+       ret = gpiod_direction_input(spi_gpio->mosi);
+       if (ret)
+               return ret;
+       /*
+        * Send a turnaround high impedance cycle when switching
+        * from output to input. Theoretically there should be
+        * a clock delay here, but as has been noted above, the
+        * nsec delay function for bit-banged GPIO is simply
+        * {} because bit-banging just doesn't get fast enough
+        * anyway.
+        */
+       if (spi->mode & SPI_3WIRE_HIZ) {
+               gpiod_set_value_cansleep(spi_gpio->sck,
+                                        !(spi->mode & SPI_CPOL));
+               gpiod_set_value_cansleep(spi_gpio->sck,
+                                        !!(spi->mode & SPI_CPOL));
+       }
+       return 0;
 }
 
 static void spi_gpio_cleanup(struct spi_device *spi)
@@ -410,7 +428,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
                return status;
 
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
-       master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL;
+       master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL;
        master->flags = master_flags;
        master->bus_num = pdev->id;
        /* The master needs to think there is a chipselect even if not connected */
index dd1ce12aa386a75c1747d6081881feacc356a231..6ec647bbba77206b5e70774b16dc777705e03eb9 100644 (file)
@@ -39,8 +39,8 @@
 #define MXC_INT_TE     (1 << 1) /* Transmit FIFO empty interrupt */
 #define MXC_INT_RDR    BIT(4) /* Receive date threshold interrupt */
 
-/* The maximum  bytes that a sdma BD can transfer.*/
-#define MAX_SDMA_BD_BYTES  (1 << 15)
+/* The maximum bytes that a sdma BD can transfer. */
+#define MAX_SDMA_BD_BYTES (1 << 15)
 #define MX51_ECSPI_CTRL_MAX_BURST      512
 /* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
 #define MX53_MAX_TRANSFER_BYTES                512
@@ -59,7 +59,9 @@ struct spi_imx_data;
 
 struct spi_imx_devtype_data {
        void (*intctrl)(struct spi_imx_data *, int);
-       int (*config)(struct spi_device *);
+       int (*prepare_message)(struct spi_imx_data *, struct spi_message *);
+       int (*prepare_transfer)(struct spi_imx_data *, struct spi_device *,
+                               struct spi_transfer *);
        void (*trigger)(struct spi_imx_data *);
        int (*rx_available)(struct spi_imx_data *);
        void (*reset)(struct spi_imx_data *);
@@ -85,7 +87,6 @@ struct spi_imx_data {
        unsigned long spi_clk;
        unsigned int spi_bus_clk;
 
-       unsigned int speed_hz;
        unsigned int bits_per_word;
        unsigned int spi_drctl;
 
@@ -256,7 +257,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_INT_RREN            (1 <<  3)
 #define MX51_ECSPI_INT_RDREN           (1 <<  4)
 
-#define MX51_ECSPI_DMA      0x14
+#define MX51_ECSPI_DMA         0x14
 #define MX51_ECSPI_DMA_TX_WML(wml)     ((wml) & 0x3f)
 #define MX51_ECSPI_DMA_RX_WML(wml)     (((wml) & 0x3f) << 16)
 #define MX51_ECSPI_DMA_RXT_WML(wml)    (((wml) & 0x3f) << 24)
@@ -486,11 +487,12 @@ static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
        writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
 }
 
-static int mx51_ecspi_config(struct spi_device *spi)
+static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
+                                     struct spi_message *msg)
 {
-       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+       struct spi_device *spi = msg->spi;
        u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
-       u32 clk = spi_imx->speed_hz, delay, reg;
+       u32 testreg;
        u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
 
        /* set Master or Slave mode */
@@ -505,19 +507,21 @@ static int mx51_ecspi_config(struct spi_device *spi)
        if (spi->mode & SPI_READY)
                ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
 
-       /* set clock speed */
-       ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->speed_hz, &clk);
-       spi_imx->spi_bus_clk = clk;
-
        /* set chip select to use */
        ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
 
-       if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
-               ctrl |= (spi_imx->slave_burst * 8 - 1)
-                       << MX51_ECSPI_CTRL_BL_OFFSET;
+       /*
+        * The ctrl register must be written first, with the EN bit set other
+        * registers must not be written to.
+        */
+       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+
+       testreg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
+       if (spi->mode & SPI_LOOP)
+               testreg |= MX51_ECSPI_TESTREG_LBC;
        else
-               ctrl |= (spi_imx->bits_per_word - 1)
-                       << MX51_ECSPI_CTRL_BL_OFFSET;
+               testreg &= ~MX51_ECSPI_TESTREG_LBC;
+       writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
 
        /*
         * eCSPI burst completion by Chip Select signal in Slave mode
@@ -541,25 +545,43 @@ static int mx51_ecspi_config(struct spi_device *spi)
                cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(spi->chip_select);
                cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi->chip_select);
        }
+
        if (spi->mode & SPI_CS_HIGH)
                cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
        else
                cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
 
-       if (spi_imx->usedma)
-               ctrl |= MX51_ECSPI_CTRL_SMC;
+       writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
 
-       /* CTRL register always go first to bring out controller from reset */
-       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+       return 0;
+}
 
-       reg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
-       if (spi->mode & SPI_LOOP)
-               reg |= MX51_ECSPI_TESTREG_LBC;
+static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
+                                      struct spi_device *spi,
+                                      struct spi_transfer *t)
+{
+       u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+       u32 clk = t->speed_hz, delay;
+
+       /* Clear BL field and set the right value */
+       ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+       if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+               ctrl |= (spi_imx->slave_burst * 8 - 1)
+                       << MX51_ECSPI_CTRL_BL_OFFSET;
        else
-               reg &= ~MX51_ECSPI_TESTREG_LBC;
-       writel(reg, spi_imx->base + MX51_ECSPI_TESTREG);
+               ctrl |= (spi_imx->bits_per_word - 1)
+                       << MX51_ECSPI_CTRL_BL_OFFSET;
 
-       writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
+       /* set clock speed */
+       ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
+                 0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET);
+       ctrl |= mx51_ecspi_clkdiv(spi_imx, t->speed_hz, &clk);
+       spi_imx->spi_bus_clk = clk;
+
+       if (spi_imx->usedma)
+               ctrl |= MX51_ECSPI_CTRL_SMC;
+
+       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
 
        /*
         * Wait until the changes in the configuration register CONFIGREG
@@ -587,7 +609,6 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx)
         * Configure the DMA register: setup the watermark
         * and enable DMA request.
         */
-
        writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
                MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
                MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
@@ -659,13 +680,20 @@ static void mx31_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx31_config(struct spi_device *spi)
+static int mx31_prepare_message(struct spi_imx_data *spi_imx,
+                               struct spi_message *msg)
+{
+       return 0;
+}
+
+static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
+                                struct spi_device *spi,
+                                struct spi_transfer *t)
 {
-       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
        unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
        unsigned int clk;
 
-       reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->speed_hz, &clk) <<
+       reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, t->speed_hz, &clk) <<
                MX31_CSPICTRL_DR_SHIFT;
        spi_imx->spi_bus_clk = clk;
 
@@ -700,8 +728,10 @@ static int mx31_config(struct spi_device *spi)
        writel(reg, spi_imx->base + MX31_CSPI_TESTREG);
 
        if (spi_imx->usedma) {
-               /* configure DMA requests when RXFIFO is half full and
-                  when TXFIFO is half empty */
+               /*
+                * configure DMA requests when RXFIFO is half full and
+                * when TXFIFO is half empty
+                */
                writel(MX31_DMAREG_RH_DEN | MX31_DMAREG_TH_DEN,
                        spi_imx->base + MX31_CSPI_DMAREG);
        }
@@ -755,14 +785,21 @@ static void mx21_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx21_config(struct spi_device *spi)
+static int mx21_prepare_message(struct spi_imx_data *spi_imx,
+                               struct spi_message *msg)
+{
+       return 0;
+}
+
+static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
+                                struct spi_device *spi,
+                                struct spi_transfer *t)
 {
-       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
        unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
        unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
        unsigned int clk;
 
-       reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->speed_hz, max, &clk)
+       reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, t->speed_hz, max, &clk)
                << MX21_CSPICTRL_DR_SHIFT;
        spi_imx->spi_bus_clk = clk;
 
@@ -824,13 +861,20 @@ static void mx1_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx1_config(struct spi_device *spi)
+static int mx1_prepare_message(struct spi_imx_data *spi_imx,
+                              struct spi_message *msg)
+{
+       return 0;
+}
+
+static int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
+                               struct spi_device *spi,
+                               struct spi_transfer *t)
 {
-       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
        unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
        unsigned int clk;
 
-       reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->speed_hz, &clk) <<
+       reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, t->speed_hz, &clk) <<
                MX1_CSPICTRL_DR_SHIFT;
        spi_imx->spi_bus_clk = clk;
 
@@ -858,7 +902,8 @@ static void mx1_reset(struct spi_imx_data *spi_imx)
 
 static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
        .intctrl = mx1_intctrl,
-       .config = mx1_config,
+       .prepare_message = mx1_prepare_message,
+       .prepare_transfer = mx1_prepare_transfer,
        .trigger = mx1_trigger,
        .rx_available = mx1_rx_available,
        .reset = mx1_reset,
@@ -871,7 +916,8 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
 
 static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
        .intctrl = mx21_intctrl,
-       .config = mx21_config,
+       .prepare_message = mx21_prepare_message,
+       .prepare_transfer = mx21_prepare_transfer,
        .trigger = mx21_trigger,
        .rx_available = mx21_rx_available,
        .reset = mx21_reset,
@@ -885,7 +931,8 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
 static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
        /* i.mx27 cspi shares the functions with i.mx21 one */
        .intctrl = mx21_intctrl,
-       .config = mx21_config,
+       .prepare_message = mx21_prepare_message,
+       .prepare_transfer = mx21_prepare_transfer,
        .trigger = mx21_trigger,
        .rx_available = mx21_rx_available,
        .reset = mx21_reset,
@@ -898,7 +945,8 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
 
 static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
        .intctrl = mx31_intctrl,
-       .config = mx31_config,
+       .prepare_message = mx31_prepare_message,
+       .prepare_transfer = mx31_prepare_transfer,
        .trigger = mx31_trigger,
        .rx_available = mx31_rx_available,
        .reset = mx31_reset,
@@ -912,7 +960,8 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
 static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
        /* i.mx35 and later cspi shares the functions with i.mx31 one */
        .intctrl = mx31_intctrl,
-       .config = mx31_config,
+       .prepare_message = mx31_prepare_message,
+       .prepare_transfer = mx31_prepare_transfer,
        .trigger = mx31_trigger,
        .rx_available = mx31_rx_available,
        .reset = mx31_reset,
@@ -925,7 +974,8 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
 
 static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
        .intctrl = mx51_ecspi_intctrl,
-       .config = mx51_ecspi_config,
+       .prepare_message = mx51_ecspi_prepare_message,
+       .prepare_transfer = mx51_ecspi_prepare_transfer,
        .trigger = mx51_ecspi_trigger,
        .rx_available = mx51_ecspi_rx_available,
        .reset = mx51_ecspi_reset,
@@ -940,7 +990,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
 
 static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
        .intctrl = mx51_ecspi_intctrl,
-       .config = mx51_ecspi_config,
+       .prepare_message = mx51_ecspi_prepare_message,
+       .prepare_transfer = mx51_ecspi_prepare_transfer,
        .trigger = mx51_ecspi_trigger,
        .rx_available = mx51_ecspi_rx_available,
        .reset = mx51_ecspi_reset,
@@ -1048,7 +1099,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
                if (!spi_imx->count)
                        break;
                if (spi_imx->dynamic_burst &&
-                   spi_imx->txfifo >=  DIV_ROUND_UP(spi_imx->remainder,
+                   spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder,
                                                     fifo_words))
                        break;
                spi_imx->tx(spi_imx);
@@ -1142,7 +1193,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
                return 0;
 
        spi_imx->bits_per_word = t->bits_per_word;
-       spi_imx->speed_hz  = t->speed_hz;
 
        /*
         * Initialize the functions for transfer. To transfer non byte-aligned
@@ -1183,7 +1233,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
                spi_imx->slave_burst = t->len;
        }
 
-       spi_imx->devtype_data->config(spi);
+       spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t);
 
        return 0;
 }
@@ -1492,7 +1542,13 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
                return ret;
        }
 
-       return 0;
+       ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
+       if (ret) {
+               clk_disable(spi_imx->clk_ipg);
+               clk_disable(spi_imx->clk_per);
+       }
+
+       return ret;
 }
 
 static int
index 62a7b80801d22098f24f8bc0711b7d5f63c557d6..5217a5628be27e3f4edd2ca96547a2e4e20c83f3 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "internals.h"
 
-#define SPI_MEM_MAX_BUSWIDTH           4
+#define SPI_MEM_MAX_BUSWIDTH           8
 
 /**
  * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
@@ -121,6 +121,13 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx)
 
                break;
 
+       case 8:
+               if ((tx && (mode & SPI_TX_OCTAL)) ||
+                   (!tx && (mode & SPI_RX_OCTAL)))
+                       return 0;
+
+               break;
+
        default:
                break;
        }
@@ -142,7 +149,7 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,
            spi_check_buswidth_req(mem, op->dummy.buswidth, true))
                return false;
 
-       if (op->data.nbytes &&
+       if (op->data.dir != SPI_MEM_NO_DATA &&
            spi_check_buswidth_req(mem, op->data.buswidth,
                                   op->data.dir == SPI_MEM_DATA_OUT))
                return false;
@@ -213,6 +220,44 @@ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
 }
 EXPORT_SYMBOL_GPL(spi_mem_supports_op);
 
+static int spi_mem_access_start(struct spi_mem *mem)
+{
+       struct spi_controller *ctlr = mem->spi->controller;
+
+       /*
+        * Flush the message queue before executing our SPI memory
+        * operation to prevent preemption of regular SPI transfers.
+        */
+       spi_flush_queue(ctlr);
+
+       if (ctlr->auto_runtime_pm) {
+               int ret;
+
+               ret = pm_runtime_get_sync(ctlr->dev.parent);
+               if (ret < 0) {
+                       dev_err(&ctlr->dev, "Failed to power device: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       mutex_lock(&ctlr->bus_lock_mutex);
+       mutex_lock(&ctlr->io_mutex);
+
+       return 0;
+}
+
+static void spi_mem_access_end(struct spi_mem *mem)
+{
+       struct spi_controller *ctlr = mem->spi->controller;
+
+       mutex_unlock(&ctlr->io_mutex);
+       mutex_unlock(&ctlr->bus_lock_mutex);
+
+       if (ctlr->auto_runtime_pm)
+               pm_runtime_put(ctlr->dev.parent);
+}
+
 /**
  * spi_mem_exec_op() - Execute a memory operation
  * @mem: the SPI memory
@@ -242,30 +287,13 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
                return -ENOTSUPP;
 
        if (ctlr->mem_ops) {
-               /*
-                * Flush the message queue before executing our SPI memory
-                * operation to prevent preemption of regular SPI transfers.
-                */
-               spi_flush_queue(ctlr);
-
-               if (ctlr->auto_runtime_pm) {
-                       ret = pm_runtime_get_sync(ctlr->dev.parent);
-                       if (ret < 0) {
-                               dev_err(&ctlr->dev,
-                                       "Failed to power device: %d\n",
-                                       ret);
-                               return ret;
-                       }
-               }
+               ret = spi_mem_access_start(mem);
+               if (ret)
+                       return ret;
 
-               mutex_lock(&ctlr->bus_lock_mutex);
-               mutex_lock(&ctlr->io_mutex);
                ret = ctlr->mem_ops->exec_op(mem, op);
-               mutex_unlock(&ctlr->io_mutex);
-               mutex_unlock(&ctlr->bus_lock_mutex);
 
-               if (ctlr->auto_runtime_pm)
-                       pm_runtime_put(ctlr->dev.parent);
+               spi_mem_access_end(mem);
 
                /*
                 * Some controllers only optimize specific paths (typically the
@@ -411,6 +439,210 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 }
 EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
 
+static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
+                                     u64 offs, size_t len, void *buf)
+{
+       struct spi_mem_op op = desc->info.op_tmpl;
+       int ret;
+
+       op.addr.val = desc->info.offset + offs;
+       op.data.buf.in = buf;
+       op.data.nbytes = len;
+       ret = spi_mem_adjust_op_size(desc->mem, &op);
+       if (ret)
+               return ret;
+
+       ret = spi_mem_exec_op(desc->mem, &op);
+       if (ret)
+               return ret;
+
+       return op.data.nbytes;
+}
+
+static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
+                                      u64 offs, size_t len, const void *buf)
+{
+       struct spi_mem_op op = desc->info.op_tmpl;
+       int ret;
+
+       op.addr.val = desc->info.offset + offs;
+       op.data.buf.out = buf;
+       op.data.nbytes = len;
+       ret = spi_mem_adjust_op_size(desc->mem, &op);
+       if (ret)
+               return ret;
+
+       ret = spi_mem_exec_op(desc->mem, &op);
+       if (ret)
+               return ret;
+
+       return op.data.nbytes;
+}
+
+/**
+ * spi_mem_dirmap_create() - Create a direct mapping descriptor
+ * @mem: SPI mem device this direct mapping should be created for
+ * @info: direct mapping information
+ *
+ * This function is creating a direct mapping descriptor which can then be used
+ * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write().
+ * If the SPI controller driver does not support direct mapping, this function
+ * fallback to an implementation using spi_mem_exec_op(), so that the caller
+ * doesn't have to bother implementing a fallback on his own.
+ *
+ * Return: a valid pointer in case of success, and ERR_PTR() otherwise.
+ */
+struct spi_mem_dirmap_desc *
+spi_mem_dirmap_create(struct spi_mem *mem,
+                     const struct spi_mem_dirmap_info *info)
+{
+       struct spi_controller *ctlr = mem->spi->controller;
+       struct spi_mem_dirmap_desc *desc;
+       int ret = -ENOTSUPP;
+
+       /* Make sure the number of address cycles is between 1 and 8 bytes. */
+       if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8)
+               return ERR_PTR(-EINVAL);
+
+       /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */
+       if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA)
+               return ERR_PTR(-EINVAL);
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return ERR_PTR(-ENOMEM);
+
+       desc->mem = mem;
+       desc->info = *info;
+       if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create)
+               ret = ctlr->mem_ops->dirmap_create(desc);
+
+       if (ret) {
+               desc->nodirmap = true;
+               if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+                       ret = -ENOTSUPP;
+               else
+                       ret = 0;
+       }
+
+       if (ret) {
+               kfree(desc);
+               return ERR_PTR(ret);
+       }
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_create);
+
+/**
+ * spi_mem_dirmap_destroy() - Destroy a direct mapping descriptor
+ * @desc: the direct mapping descriptor to destroy
+ * @info: direct mapping information
+ *
+ * This function destroys a direct mapping descriptor previously created by
+ * spi_mem_dirmap_create().
+ */
+void spi_mem_dirmap_destroy(struct spi_mem_dirmap_desc *desc)
+{
+       struct spi_controller *ctlr = desc->mem->spi->controller;
+
+       if (!desc->nodirmap && ctlr->mem_ops && ctlr->mem_ops->dirmap_destroy)
+               ctlr->mem_ops->dirmap_destroy(desc);
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_destroy);
+
+/**
+ * spi_mem_dirmap_dirmap_read() - Read data through a direct mapping
+ * @desc: direct mapping descriptor
+ * @offs: offset to start reading from. Note that this is not an absolute
+ *       offset, but the offset within the direct mapping which already has
+ *       its own offset
+ * @len: length in bytes
+ * @buf: destination buffer. This buffer must be DMA-able
+ *
+ * This function reads data from a memory device using a direct mapping
+ * previously instantiated with spi_mem_dirmap_create().
+ *
+ * Return: the amount of data read from the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_read() again when that happens.
+ */
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+                           u64 offs, size_t len, void *buf)
+{
+       struct spi_controller *ctlr = desc->mem->spi->controller;
+       ssize_t ret;
+
+       if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+               return -EINVAL;
+
+       if (!len)
+               return 0;
+
+       if (desc->nodirmap) {
+               ret = spi_mem_no_dirmap_read(desc, offs, len, buf);
+       } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_read) {
+               ret = spi_mem_access_start(desc->mem);
+               if (ret)
+                       return ret;
+
+               ret = ctlr->mem_ops->dirmap_read(desc, offs, len, buf);
+
+               spi_mem_access_end(desc->mem);
+       } else {
+               ret = -ENOTSUPP;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_read);
+
+/**
+ * spi_mem_dirmap_dirmap_write() - Write data through a direct mapping
+ * @desc: direct mapping descriptor
+ * @offs: offset to start writing from. Note that this is not an absolute
+ *       offset, but the offset within the direct mapping which already has
+ *       its own offset
+ * @len: length in bytes
+ * @buf: source buffer. This buffer must be DMA-able
+ *
+ * This function writes data to a memory device using a direct mapping
+ * previously instantiated with spi_mem_dirmap_create().
+ *
+ * Return: the amount of data written to the memory device or a negative error
+ * code. Note that the returned size might be smaller than @len, and the caller
+ * is responsible for calling spi_mem_dirmap_write() again when that happens.
+ */
+ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+                            u64 offs, size_t len, const void *buf)
+{
+       struct spi_controller *ctlr = desc->mem->spi->controller;
+       ssize_t ret;
+
+       if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT)
+               return -EINVAL;
+
+       if (!len)
+               return 0;
+
+       if (desc->nodirmap) {
+               ret = spi_mem_no_dirmap_write(desc, offs, len, buf);
+       } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_write) {
+               ret = spi_mem_access_start(desc->mem);
+               if (ret)
+                       return ret;
+
+               ret = ctlr->mem_ops->dirmap_write(desc, offs, len, buf);
+
+               spi_mem_access_end(desc->mem);
+       } else {
+               ret = -ENOTSUPP;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_dirmap_write);
+
 static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
 {
        return container_of(drv, struct spi_mem_driver, spidrv.driver);
index 0c2867deb36fce48c74b92388d210371ebd1a6d0..0cce6f0ba8249fe50a8cf70d37eb2a177737fa5f 100644 (file)
@@ -120,6 +120,12 @@ static const struct mtk_spi_compatible mt8173_compat = {
        .must_tx = true,
 };
 
+static const struct mtk_spi_compatible mt8183_compat = {
+       .need_pad_sel = true,
+       .must_tx = true,
+       .enhance_timing = true,
+};
+
 /*
  * A piece of default chip info unless the platform
  * supplies it.
@@ -144,12 +150,18 @@ static const struct of_device_id mtk_spi_of_match[] = {
        { .compatible = "mediatek,mt7622-spi",
                .data = (void *)&mt7622_compat,
        },
+       { .compatible = "mediatek,mt7629-spi",
+               .data = (void *)&mt7622_compat,
+       },
        { .compatible = "mediatek,mt8135-spi",
                .data = (void *)&mtk_common_compat,
        },
        { .compatible = "mediatek,mt8173-spi",
                .data = (void *)&mt8173_compat,
        },
+       { .compatible = "mediatek,mt8183-spi",
+               .data = (void *)&mt8183_compat,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
new file mode 100644 (file)
index 0000000..e41ae6e
--- /dev/null
@@ -0,0 +1,619 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 Macronix International Co., Ltd.
+//
+// Authors:
+//     Mason Yang <masonccyang@mxic.com.tw>
+//     zhengxunli <zhengxunli@mxic.com.tw>
+//     Boris Brezillon <boris.brezillon@bootlin.com>
+//
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+#define HC_CFG                 0x0
+#define HC_CFG_IF_CFG(x)       ((x) << 27)
+#define HC_CFG_DUAL_SLAVE      BIT(31)
+#define HC_CFG_INDIVIDUAL      BIT(30)
+#define HC_CFG_NIO(x)          (((x) / 4) << 27)
+#define HC_CFG_TYPE(s, t)      ((t) << (23 + ((s) * 2)))
+#define HC_CFG_TYPE_SPI_NOR    0
+#define HC_CFG_TYPE_SPI_NAND   1
+#define HC_CFG_TYPE_SPI_RAM    2
+#define HC_CFG_TYPE_RAW_NAND   3
+#define HC_CFG_SLV_ACT(x)      ((x) << 21)
+#define HC_CFG_CLK_PH_EN       BIT(20)
+#define HC_CFG_CLK_POL_INV     BIT(19)
+#define HC_CFG_BIG_ENDIAN      BIT(18)
+#define HC_CFG_DATA_PASS       BIT(17)
+#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16)
+#define HC_CFG_MAN_START_EN    BIT(3)
+#define HC_CFG_MAN_START       BIT(2)
+#define HC_CFG_MAN_CS_EN       BIT(1)
+#define HC_CFG_MAN_CS_ASSERT   BIT(0)
+
+#define INT_STS                        0x4
+#define INT_STS_EN             0x8
+#define INT_SIG_EN             0xc
+#define INT_STS_ALL            GENMASK(31, 0)
+#define INT_RDY_PIN            BIT(26)
+#define INT_RDY_SR             BIT(25)
+#define INT_LNR_SUSP           BIT(24)
+#define INT_ECC_ERR            BIT(17)
+#define INT_CRC_ERR            BIT(16)
+#define INT_LWR_DIS            BIT(12)
+#define INT_LRD_DIS            BIT(11)
+#define INT_SDMA_INT           BIT(10)
+#define INT_DMA_FINISH         BIT(9)
+#define INT_RX_NOT_FULL                BIT(3)
+#define INT_RX_NOT_EMPTY       BIT(2)
+#define INT_TX_NOT_FULL                BIT(1)
+#define INT_TX_EMPTY           BIT(0)
+
+#define HC_EN                  0x10
+#define HC_EN_BIT              BIT(0)
+
+#define TXD(x)                 (0x14 + ((x) * 4))
+#define RXD                    0x24
+
+#define SS_CTRL(s)             (0x30 + ((s) * 4))
+#define LRD_CFG                        0x44
+#define LWR_CFG                        0x80
+#define RWW_CFG                        0x70
+#define OP_READ                        BIT(23)
+#define OP_DUMMY_CYC(x)                ((x) << 17)
+#define OP_ADDR_BYTES(x)       ((x) << 14)
+#define OP_CMD_BYTES(x)                (((x) - 1) << 13)
+#define OP_OCTA_CRC_EN         BIT(12)
+#define OP_DQS_EN              BIT(11)
+#define OP_ENHC_EN             BIT(10)
+#define OP_PREAMBLE_EN         BIT(9)
+#define OP_DATA_DDR            BIT(8)
+#define OP_DATA_BUSW(x)                ((x) << 6)
+#define OP_ADDR_DDR            BIT(5)
+#define OP_ADDR_BUSW(x)                ((x) << 3)
+#define OP_CMD_DDR             BIT(2)
+#define OP_CMD_BUSW(x)         (x)
+#define OP_BUSW_1              0
+#define OP_BUSW_2              1
+#define OP_BUSW_4              2
+#define OP_BUSW_8              3
+
+#define OCTA_CRC               0x38
+#define OCTA_CRC_IN_EN(s)      BIT(3 + ((s) * 16))
+#define OCTA_CRC_CHUNK(s, x)   ((fls((x) / 32)) << (1 + ((s) * 16)))
+#define OCTA_CRC_OUT_EN(s)     BIT(0 + ((s) * 16))
+
+#define ONFI_DIN_CNT(s)                (0x3c + (s))
+
+#define LRD_CTRL               0x48
+#define RWW_CTRL               0x74
+#define LWR_CTRL               0x84
+#define LMODE_EN               BIT(31)
+#define LMODE_SLV_ACT(x)       ((x) << 21)
+#define LMODE_CMD1(x)          ((x) << 8)
+#define LMODE_CMD0(x)          (x)
+
+#define LRD_ADDR               0x4c
+#define LWR_ADDR               0x88
+#define LRD_RANGE              0x50
+#define LWR_RANGE              0x8c
+
+#define AXI_SLV_ADDR           0x54
+
+#define DMAC_RD_CFG            0x58
+#define DMAC_WR_CFG            0x94
+#define DMAC_CFG_PERIPH_EN     BIT(31)
+#define DMAC_CFG_ALLFLUSH_EN   BIT(30)
+#define DMAC_CFG_LASTFLUSH_EN  BIT(29)
+#define DMAC_CFG_QE(x)         (((x) + 1) << 16)
+#define DMAC_CFG_BURST_LEN(x)  (((x) + 1) << 12)
+#define DMAC_CFG_BURST_SZ(x)   ((x) << 8)
+#define DMAC_CFG_DIR_READ      BIT(1)
+#define DMAC_CFG_START         BIT(0)
+
+#define DMAC_RD_CNT            0x5c
+#define DMAC_WR_CNT            0x98
+
+#define SDMA_ADDR              0x60
+
+#define DMAM_CFG               0x64
+#define DMAM_CFG_START         BIT(31)
+#define DMAM_CFG_CONT          BIT(30)
+#define DMAM_CFG_SDMA_GAP(x)   (fls((x) / 8192) << 2)
+#define DMAM_CFG_DIR_READ      BIT(1)
+#define DMAM_CFG_EN            BIT(0)
+
+#define DMAM_CNT               0x68
+
+#define LNR_TIMER_TH           0x6c
+
+#define RDM_CFG0               0x78
+#define RDM_CFG0_POLY(x)       (x)
+
+#define RDM_CFG1               0x7c
+#define RDM_CFG1_RDM_EN                BIT(31)
+#define RDM_CFG1_SEED(x)       (x)
+
+#define LWR_SUSP_CTRL          0x90
+#define LWR_SUSP_CTRL_EN       BIT(31)
+
+#define DMAS_CTRL              0x9c
+#define DMAS_CTRL_DIR_READ     BIT(31)
+#define DMAS_CTRL_EN           BIT(30)
+
+#define DATA_STROB             0xa0
+#define DATA_STROB_EDO_EN      BIT(2)
+#define DATA_STROB_INV_POL     BIT(1)
+#define DATA_STROB_DELAY_2CYC  BIT(0)
+
+#define IDLY_CODE(x)           (0xa4 + ((x) * 4))
+#define IDLY_CODE_VAL(x, v)    ((v) << (((x) % 4) * 8))
+
+#define GPIO                   0xc4
+#define GPIO_PT(x)             BIT(3 + ((x) * 16))
+#define GPIO_RESET(x)          BIT(2 + ((x) * 16))
+#define GPIO_HOLDB(x)          BIT(1 + ((x) * 16))
+#define GPIO_WPB(x)            BIT((x) * 16)
+
+#define HC_VER                 0xd0
+
+#define HW_TEST(x)             (0xe0 + ((x) * 4))
+
+struct mxic_spi {
+       struct clk *ps_clk;
+       struct clk *send_clk;
+       struct clk *send_dly_clk;
+       void __iomem *regs;
+       u32 cur_speed_hz;
+};
+
+static int mxic_spi_clk_enable(struct mxic_spi *mxic)
+{
+       int ret;
+
+       ret = clk_prepare_enable(mxic->send_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(mxic->send_dly_clk);
+       if (ret)
+               goto err_send_dly_clk;
+
+       return ret;
+
+err_send_dly_clk:
+       clk_disable_unprepare(mxic->send_clk);
+
+       return ret;
+}
+
+static void mxic_spi_clk_disable(struct mxic_spi *mxic)
+{
+       clk_disable_unprepare(mxic->send_clk);
+       clk_disable_unprepare(mxic->send_dly_clk);
+}
+
+static void mxic_spi_set_input_delay_dqs(struct mxic_spi *mxic, u8 idly_code)
+{
+       writel(IDLY_CODE_VAL(0, idly_code) |
+              IDLY_CODE_VAL(1, idly_code) |
+              IDLY_CODE_VAL(2, idly_code) |
+              IDLY_CODE_VAL(3, idly_code),
+              mxic->regs + IDLY_CODE(0));
+       writel(IDLY_CODE_VAL(4, idly_code) |
+              IDLY_CODE_VAL(5, idly_code) |
+              IDLY_CODE_VAL(6, idly_code) |
+              IDLY_CODE_VAL(7, idly_code),
+              mxic->regs + IDLY_CODE(1));
+}
+
+static int mxic_spi_clk_setup(struct mxic_spi *mxic, unsigned long freq)
+{
+       int ret;
+
+       ret = clk_set_rate(mxic->send_clk, freq);
+       if (ret)
+               return ret;
+
+       ret = clk_set_rate(mxic->send_dly_clk, freq);
+       if (ret)
+               return ret;
+
+       /*
+        * A constant delay range from 0x0 ~ 0x1F for input delay,
+        * the unit is 78 ps, the max input delay is 2.418 ns.
+        */
+       mxic_spi_set_input_delay_dqs(mxic, 0xf);
+
+       /*
+        * Phase degree = 360 * freq * output-delay
+        * where output-delay is a constant value 1 ns in FPGA.
+        *
+        * Get Phase degree = 360 * freq * 1 ns
+        *                  = 360 * freq * 1 sec / 1000000000
+        *                  = 9 * freq / 25000000
+        */
+       ret = clk_set_phase(mxic->send_dly_clk, 9 * freq / 25000000);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mxic_spi_set_freq(struct mxic_spi *mxic, unsigned long freq)
+{
+       int ret;
+
+       if (mxic->cur_speed_hz == freq)
+               return 0;
+
+       mxic_spi_clk_disable(mxic);
+       ret = mxic_spi_clk_setup(mxic, freq);
+       if (ret)
+               return ret;
+
+       ret = mxic_spi_clk_enable(mxic);
+       if (ret)
+               return ret;
+
+       mxic->cur_speed_hz = freq;
+
+       return 0;
+}
+
+static void mxic_spi_hw_init(struct mxic_spi *mxic)
+{
+       writel(0, mxic->regs + DATA_STROB);
+       writel(INT_STS_ALL, mxic->regs + INT_STS_EN);
+       writel(0, mxic->regs + HC_EN);
+       writel(0, mxic->regs + LRD_CFG);
+       writel(0, mxic->regs + LRD_CTRL);
+       writel(HC_CFG_NIO(1) | HC_CFG_TYPE(0, HC_CFG_TYPE_SPI_NAND) |
+              HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN | HC_CFG_IDLE_SIO_LVL(1),
+              mxic->regs + HC_CFG);
+}
+
+static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
+                             void *rxbuf, unsigned int len)
+{
+       unsigned int pos = 0;
+
+       while (pos < len) {
+               unsigned int nbytes = len - pos;
+               u32 data = 0xffffffff;
+               u32 sts;
+               int ret;
+
+               if (nbytes > 4)
+                       nbytes = 4;
+
+               if (txbuf)
+                       memcpy(&data, txbuf + pos, nbytes);
+
+               ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+                                        sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
+               if (ret)
+                       return ret;
+
+               writel(data, mxic->regs + TXD(nbytes % 4));
+
+               if (rxbuf) {
+                       ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+                                                sts & INT_TX_EMPTY, 0,
+                                                USEC_PER_SEC);
+                       if (ret)
+                               return ret;
+
+                       ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+                                                sts & INT_RX_NOT_EMPTY, 0,
+                                                USEC_PER_SEC);
+                       if (ret)
+                               return ret;
+
+                       data = readl(mxic->regs + RXD);
+                       data >>= (8 * (4 - nbytes));
+                       memcpy(rxbuf + pos, &data, nbytes);
+                       WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
+               } else {
+                       readl(mxic->regs + RXD);
+               }
+               WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
+
+               pos += nbytes;
+       }
+
+       return 0;
+}
+
+static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
+                                    const struct spi_mem_op *op)
+{
+       if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
+           op->dummy.buswidth > 4 || op->cmd.buswidth > 4)
+               return false;
+
+       if (op->data.nbytes && op->dummy.nbytes &&
+           op->data.buswidth != op->dummy.buswidth)
+               return false;
+
+       if (op->addr.nbytes > 7)
+               return false;
+
+       return true;
+}
+
+static int mxic_spi_mem_exec_op(struct spi_mem *mem,
+                               const struct spi_mem_op *op)
+{
+       struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
+       int nio = 1, i, ret;
+       u32 ss_ctrl;
+       u8 addr[8];
+
+       ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
+       if (ret)
+               return ret;
+
+       if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
+               nio = 4;
+       else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
+               nio = 2;
+
+       writel(HC_CFG_NIO(nio) |
+              HC_CFG_TYPE(mem->spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
+              HC_CFG_SLV_ACT(mem->spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1) |
+              HC_CFG_MAN_CS_EN,
+              mxic->regs + HC_CFG);
+       writel(HC_EN_BIT, mxic->regs + HC_EN);
+
+       ss_ctrl = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1);
+
+       if (op->addr.nbytes)
+               ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) |
+                          OP_ADDR_BUSW(fls(op->addr.buswidth) - 1);
+
+       if (op->dummy.nbytes)
+               ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes);
+
+       if (op->data.nbytes) {
+               ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1);
+               if (op->data.dir == SPI_MEM_DATA_IN)
+                       ss_ctrl |= OP_READ;
+       }
+
+       writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select));
+
+       writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
+              mxic->regs + HC_CFG);
+
+       ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1);
+       if (ret)
+               goto out;
+
+       for (i = 0; i < op->addr.nbytes; i++)
+               addr[i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
+
+       ret = mxic_spi_data_xfer(mxic, addr, NULL, op->addr.nbytes);
+       if (ret)
+               goto out;
+
+       ret = mxic_spi_data_xfer(mxic, NULL, NULL, op->dummy.nbytes);
+       if (ret)
+               goto out;
+
+       ret = mxic_spi_data_xfer(mxic,
+                                op->data.dir == SPI_MEM_DATA_OUT ?
+                                op->data.buf.out : NULL,
+                                op->data.dir == SPI_MEM_DATA_IN ?
+                                op->data.buf.in : NULL,
+                                op->data.nbytes);
+
+out:
+       writel(readl(mxic->regs + HC_CFG) & ~HC_CFG_MAN_CS_ASSERT,
+              mxic->regs + HC_CFG);
+       writel(0, mxic->regs + HC_EN);
+
+       return ret;
+}
+
+static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
+       .supports_op = mxic_spi_mem_supports_op,
+       .exec_op = mxic_spi_mem_exec_op,
+};
+
+static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
+{
+       struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
+
+       if (!lvl) {
+               writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
+                      mxic->regs + HC_CFG);
+               writel(HC_EN_BIT, mxic->regs + HC_EN);
+               writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
+                      mxic->regs + HC_CFG);
+       } else {
+               writel(readl(mxic->regs + HC_CFG) & ~HC_CFG_MAN_CS_ASSERT,
+                      mxic->regs + HC_CFG);
+               writel(0, mxic->regs + HC_EN);
+       }
+}
+
+static int mxic_spi_transfer_one(struct spi_master *master,
+                                struct spi_device *spi,
+                                struct spi_transfer *t)
+{
+       struct mxic_spi *mxic = spi_master_get_devdata(master);
+       unsigned int busw = OP_BUSW_1;
+       int ret;
+
+       if (t->rx_buf && t->tx_buf) {
+               if (((spi->mode & SPI_TX_QUAD) &&
+                    !(spi->mode & SPI_RX_QUAD)) ||
+                   ((spi->mode & SPI_TX_DUAL) &&
+                    !(spi->mode & SPI_RX_DUAL)))
+                       return -ENOTSUPP;
+       }
+
+       ret = mxic_spi_set_freq(mxic, t->speed_hz);
+       if (ret)
+               return ret;
+
+       if (t->tx_buf) {
+               if (spi->mode & SPI_TX_QUAD)
+                       busw = OP_BUSW_4;
+               else if (spi->mode & SPI_TX_DUAL)
+                       busw = OP_BUSW_2;
+       } else if (t->rx_buf) {
+               if (spi->mode & SPI_RX_QUAD)
+                       busw = OP_BUSW_4;
+               else if (spi->mode & SPI_RX_DUAL)
+                       busw = OP_BUSW_2;
+       }
+
+       writel(OP_CMD_BYTES(1) | OP_CMD_BUSW(busw) |
+              OP_DATA_BUSW(busw) | (t->rx_buf ? OP_READ : 0),
+              mxic->regs + SS_CTRL(0));
+
+       ret = mxic_spi_data_xfer(mxic, t->tx_buf, t->rx_buf, t->len);
+       if (ret)
+               return ret;
+
+       spi_finalize_current_transfer(master);
+
+       return 0;
+}
+
+static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct mxic_spi *mxic = spi_master_get_devdata(master);
+
+       mxic_spi_clk_disable(mxic);
+       clk_disable_unprepare(mxic->ps_clk);
+
+       return 0;
+}
+
+static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct mxic_spi *mxic = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(mxic->ps_clk);
+       if (ret) {
+               dev_err(dev, "Cannot enable ps_clock.\n");
+               return ret;
+       }
+
+       return mxic_spi_clk_enable(mxic);
+}
+
+static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(mxic_spi_runtime_suspend,
+                          mxic_spi_runtime_resume, NULL)
+};
+
+static int mxic_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct resource *res;
+       struct mxic_spi *mxic;
+       int ret;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
+       if (!master)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, master);
+
+       mxic = spi_master_get_devdata(master);
+
+       master->dev.of_node = pdev->dev.of_node;
+
+       mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
+       if (IS_ERR(mxic->ps_clk))
+               return PTR_ERR(mxic->ps_clk);
+
+       mxic->send_clk = devm_clk_get(&pdev->dev, "send_clk");
+       if (IS_ERR(mxic->send_clk))
+               return PTR_ERR(mxic->send_clk);
+
+       mxic->send_dly_clk = devm_clk_get(&pdev->dev, "send_dly_clk");
+       if (IS_ERR(mxic->send_dly_clk))
+               return PTR_ERR(mxic->send_dly_clk);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+       mxic->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mxic->regs))
+               return PTR_ERR(mxic->regs);
+
+       pm_runtime_enable(&pdev->dev);
+       master->auto_runtime_pm = true;
+
+       master->num_chipselect = 1;
+       master->mem_ops = &mxic_spi_mem_ops;
+
+       master->set_cs = mxic_spi_set_cs;
+       master->transfer_one = mxic_spi_transfer_one;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->mode_bits = SPI_CPOL | SPI_CPHA |
+                       SPI_RX_DUAL | SPI_TX_DUAL |
+                       SPI_RX_QUAD | SPI_TX_QUAD;
+
+       mxic_spi_hw_init(mxic);
+
+       ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "spi_register_master failed\n");
+               goto err_put_master;
+       }
+
+       return 0;
+
+err_put_master:
+       spi_master_put(master);
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static int mxic_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       spi_unregister_master(master);
+
+       return 0;
+}
+
+static const struct of_device_id mxic_spi_of_ids[] = {
+       { .compatible = "mxicy,mx25f0a-spi", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxic_spi_of_ids);
+
+static struct platform_driver mxic_spi_driver = {
+       .probe = mxic_spi_probe,
+       .remove = mxic_spi_remove,
+       .driver = {
+               .name = "mxic-spi",
+               .of_match_table = mxic_spi_of_ids,
+               .pm = &mxic_spi_dev_pm_ops,
+       },
+};
+module_platform_driver(mxic_spi_driver);
+
+MODULE_AUTHOR("Mason Yang <masonccyang@mxic.com.tw>");
+MODULE_DESCRIPTION("MX25F0A SPI controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c
new file mode 100644 (file)
index 0000000..e1dca79
--- /dev/null
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Nuvoton Technology corporation.
+
+#include <linux/kernel.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+struct npcm_pspi {
+       struct completion xfer_done;
+       struct regmap *rst_regmap;
+       struct spi_master *master;
+       unsigned int tx_bytes;
+       unsigned int rx_bytes;
+       void __iomem *base;
+       bool is_save_param;
+       u8 bits_per_word;
+       const u8 *tx_buf;
+       struct clk *clk;
+       u32 speed_hz;
+       u8 *rx_buf;
+       u16 mode;
+       u32 id;
+};
+
+#define DRIVER_NAME "npcm-pspi"
+
+#define NPCM_PSPI_DATA         0x00
+#define NPCM_PSPI_CTL1         0x02
+#define NPCM_PSPI_STAT         0x04
+
+/* definitions for control and status register */
+#define NPCM_PSPI_CTL1_SPIEN   BIT(0)
+#define NPCM_PSPI_CTL1_MOD     BIT(2)
+#define NPCM_PSPI_CTL1_EIR     BIT(5)
+#define NPCM_PSPI_CTL1_EIW     BIT(6)
+#define NPCM_PSPI_CTL1_SCM     BIT(7)
+#define NPCM_PSPI_CTL1_SCIDL   BIT(8)
+#define NPCM_PSPI_CTL1_SCDV6_0 GENMASK(15, 9)
+
+#define NPCM_PSPI_STAT_BSY     BIT(0)
+#define NPCM_PSPI_STAT_RBF     BIT(1)
+
+/* general definitions */
+#define NPCM_PSPI_TIMEOUT_MS           2000
+#define NPCM_PSPI_MAX_CLK_DIVIDER      256
+#define NPCM_PSPI_MIN_CLK_DIVIDER      4
+#define NPCM_PSPI_DEFAULT_CLK          25000000
+
+/* reset register */
+#define NPCM7XX_IPSRST2_OFFSET 0x24
+
+#define NPCM7XX_PSPI1_RESET    BIT(22)
+#define NPCM7XX_PSPI2_RESET    BIT(23)
+
+static inline unsigned int bytes_per_word(unsigned int bits)
+{
+       return bits <= 8 ? 1 : 2;
+}
+
+static inline void npcm_pspi_irq_enable(struct npcm_pspi *priv, u16 mask)
+{
+       u16 val;
+
+       val = ioread16(priv->base + NPCM_PSPI_CTL1);
+       val |= mask;
+       iowrite16(val, priv->base + NPCM_PSPI_CTL1);
+}
+
+static inline void npcm_pspi_irq_disable(struct npcm_pspi *priv, u16 mask)
+{
+       u16 val;
+
+       val = ioread16(priv->base + NPCM_PSPI_CTL1);
+       val &= ~mask;
+       iowrite16(val, priv->base + NPCM_PSPI_CTL1);
+}
+
+static inline void npcm_pspi_enable(struct npcm_pspi *priv)
+{
+       u16 val;
+
+       val = ioread16(priv->base + NPCM_PSPI_CTL1);
+       val |= NPCM_PSPI_CTL1_SPIEN;
+       iowrite16(val, priv->base + NPCM_PSPI_CTL1);
+}
+
+static inline void npcm_pspi_disable(struct npcm_pspi *priv)
+{
+       u16 val;
+
+       val = ioread16(priv->base + NPCM_PSPI_CTL1);
+       val &= ~NPCM_PSPI_CTL1_SPIEN;
+       iowrite16(val, priv->base + NPCM_PSPI_CTL1);
+}
+
+static void npcm_pspi_set_mode(struct spi_device *spi)
+{
+       struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
+       u16 regtemp;
+       u16 mode_val;
+
+       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       case SPI_MODE_0:
+               mode_val = 0;
+               break;
+       case SPI_MODE_1:
+               mode_val = NPCM_PSPI_CTL1_SCIDL;
+               break;
+       case SPI_MODE_2:
+               mode_val = NPCM_PSPI_CTL1_SCM;
+               break;
+       case SPI_MODE_3:
+               mode_val = NPCM_PSPI_CTL1_SCIDL | NPCM_PSPI_CTL1_SCM;
+               break;
+       }
+
+       regtemp = ioread16(priv->base + NPCM_PSPI_CTL1);
+       regtemp &= ~(NPCM_PSPI_CTL1_SCM | NPCM_PSPI_CTL1_SCIDL);
+       iowrite16(regtemp | mode_val, priv->base + NPCM_PSPI_CTL1);
+}
+
+static void npcm_pspi_set_transfer_size(struct npcm_pspi *priv, int size)
+{
+       u16 regtemp;
+
+       regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
+
+       switch (size) {
+       case 8:
+               regtemp &= ~NPCM_PSPI_CTL1_MOD;
+               break;
+       case 16:
+               regtemp |= NPCM_PSPI_CTL1_MOD;
+               break;
+       }
+
+       iowrite16(regtemp, NPCM_PSPI_CTL1 + priv->base);
+}
+
+static void npcm_pspi_set_baudrate(struct npcm_pspi *priv, unsigned int speed)
+{
+       u32 ckdiv;
+       u16 regtemp;
+
+       /* the supported rates are numbers from 4 to 256. */
+       ckdiv = DIV_ROUND_CLOSEST(clk_get_rate(priv->clk), (2 * speed)) - 1;
+
+       regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
+       regtemp &= ~NPCM_PSPI_CTL1_SCDV6_0;
+       iowrite16(regtemp | (ckdiv << 9), NPCM_PSPI_CTL1 + priv->base);
+}
+
+static void npcm_pspi_setup_transfer(struct spi_device *spi,
+                                    struct spi_transfer *t)
+{
+       struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
+
+       priv->tx_buf = t->tx_buf;
+       priv->rx_buf = t->rx_buf;
+       priv->tx_bytes = t->len;
+       priv->rx_bytes = t->len;
+
+       if (!priv->is_save_param || priv->mode != spi->mode) {
+               npcm_pspi_set_mode(spi);
+               priv->mode = spi->mode;
+       }
+
+       if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
+               npcm_pspi_set_transfer_size(priv, t->bits_per_word);
+               priv->bits_per_word = t->bits_per_word;
+       }
+
+       if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
+               npcm_pspi_set_baudrate(priv, t->speed_hz);
+               priv->speed_hz = t->speed_hz;
+       }
+
+       if (!priv->is_save_param)
+               priv->is_save_param = true;
+}
+
+static void npcm_pspi_send(struct npcm_pspi *priv)
+{
+       int wsize;
+
+       wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
+       priv->tx_bytes -= wsize;
+
+       if (!priv->tx_buf)
+               return;
+
+       switch (wsize) {
+       case 1:
+               iowrite8(*priv->tx_buf, NPCM_PSPI_DATA + priv->base);
+               break;
+       case 2:
+               iowrite16(*priv->tx_buf, NPCM_PSPI_DATA + priv->base);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       priv->tx_buf += wsize;
+}
+
+static void npcm_pspi_recv(struct npcm_pspi *priv)
+{
+       int rsize;
+       u16 val;
+
+       rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
+       priv->rx_bytes -= rsize;
+
+       if (!priv->rx_buf)
+               return;
+
+       switch (rsize) {
+       case 1:
+               val = ioread8(priv->base + NPCM_PSPI_DATA);
+               break;
+       case 2:
+               val = ioread16(priv->base + NPCM_PSPI_DATA);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       *priv->rx_buf = val;
+       priv->rx_buf += rsize;
+}
+
+static int npcm_pspi_transfer_one(struct spi_master *master,
+                                 struct spi_device *spi,
+                                 struct spi_transfer *t)
+{
+       struct npcm_pspi *priv = spi_master_get_devdata(master);
+       int status;
+
+       npcm_pspi_setup_transfer(spi, t);
+       reinit_completion(&priv->xfer_done);
+       npcm_pspi_enable(priv);
+       status = wait_for_completion_timeout(&priv->xfer_done,
+                                            msecs_to_jiffies
+                                            (NPCM_PSPI_TIMEOUT_MS));
+       if (status == 0) {
+               npcm_pspi_disable(priv);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int npcm_pspi_prepare_transfer_hardware(struct spi_master *master)
+{
+       struct npcm_pspi *priv = spi_master_get_devdata(master);
+
+       npcm_pspi_irq_enable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
+
+       return 0;
+}
+
+static int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master)
+{
+       struct npcm_pspi *priv = spi_master_get_devdata(master);
+
+       npcm_pspi_irq_disable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
+
+       return 0;
+}
+
+static void npcm_pspi_reset_hw(struct npcm_pspi *priv)
+{
+       regmap_write(priv->rst_regmap, NPCM7XX_IPSRST2_OFFSET,
+                    NPCM7XX_PSPI1_RESET << priv->id);
+       regmap_write(priv->rst_regmap, NPCM7XX_IPSRST2_OFFSET, 0x0);
+}
+
+static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
+{
+       struct npcm_pspi *priv = dev_id;
+       u16 val;
+       u8 stat;
+
+       stat = ioread8(priv->base + NPCM_PSPI_STAT);
+
+       if (!priv->tx_buf && !priv->rx_buf)
+               return IRQ_NONE;
+
+       if (priv->tx_buf) {
+               if (stat & NPCM_PSPI_STAT_RBF) {
+                       val = ioread8(NPCM_PSPI_DATA + priv->base);
+                       if (priv->tx_bytes == 0) {
+                               npcm_pspi_disable(priv);
+                               complete(&priv->xfer_done);
+                               return IRQ_HANDLED;
+                       }
+               }
+
+               if ((stat & NPCM_PSPI_STAT_BSY) == 0)
+                       if (priv->tx_bytes)
+                               npcm_pspi_send(priv);
+       }
+
+       if (priv->rx_buf) {
+               if (stat & NPCM_PSPI_STAT_RBF) {
+                       if (!priv->rx_bytes)
+                               return IRQ_NONE;
+
+                       npcm_pspi_recv(priv);
+
+                       if (!priv->rx_bytes) {
+                               npcm_pspi_disable(priv);
+                               complete(&priv->xfer_done);
+                               return IRQ_HANDLED;
+                       }
+               }
+
+               if (((stat & NPCM_PSPI_STAT_BSY) == 0) && !priv->tx_buf)
+                       iowrite8(0x0, NPCM_PSPI_DATA + priv->base);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int npcm_pspi_probe(struct platform_device *pdev)
+{
+       struct npcm_pspi *priv;
+       struct spi_master *master;
+       struct resource *res;
+       unsigned long clk_hz;
+       struct device_node *np = pdev->dev.of_node;
+       int num_cs, i;
+       int csgpio;
+       int irq;
+       int ret;
+
+       num_cs = of_gpio_named_count(np, "cs-gpios");
+       if (num_cs < 0)
+               return num_cs;
+
+       pdev->id = of_alias_get_id(np, "spi");
+       if (pdev->id < 0)
+               pdev->id = 0;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+       if (!master)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, master);
+
+       priv = spi_master_get_devdata(master);
+       priv->master = master;
+       priv->is_save_param = false;
+       priv->id = pdev->id;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->base)) {
+               ret = PTR_ERR(priv->base);
+               goto out_master_put;
+       }
+
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               ret = PTR_ERR(priv->clk);
+               goto out_master_put;
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto out_master_put;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get IRQ\n");
+               ret = irq;
+               goto out_disable_clk;
+       }
+
+       priv->rst_regmap =
+               syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
+       if (IS_ERR(priv->rst_regmap)) {
+               dev_err(&pdev->dev, "failed to find nuvoton,npcm750-rst\n");
+               return PTR_ERR(priv->rst_regmap);
+       }
+
+       /* reset SPI-HW block */
+       npcm_pspi_reset_hw(priv);
+
+       ret = devm_request_irq(&pdev->dev, irq, npcm_pspi_handler, 0,
+                              "npcm-pspi", priv);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto out_disable_clk;
+       }
+
+       init_completion(&priv->xfer_done);
+
+       clk_hz = clk_get_rate(priv->clk);
+
+       master->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
+       master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
+       master->mode_bits = SPI_CPHA | SPI_CPOL;
+       master->dev.of_node = pdev->dev.of_node;
+       master->bus_num = pdev->id;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+       master->transfer_one = npcm_pspi_transfer_one;
+       master->prepare_transfer_hardware =
+               npcm_pspi_prepare_transfer_hardware;
+       master->unprepare_transfer_hardware =
+               npcm_pspi_unprepare_transfer_hardware;
+       master->num_chipselect = num_cs;
+
+       for (i = 0; i < num_cs; i++) {
+               csgpio = of_get_named_gpio(np, "cs-gpios", i);
+               if (csgpio < 0) {
+                       dev_err(&pdev->dev, "failed to get csgpio#%u\n", i);
+                       goto out_disable_clk;
+               }
+               dev_dbg(&pdev->dev, "csgpio#%u = %d\n", i, csgpio);
+               ret = devm_gpio_request_one(&pdev->dev, csgpio,
+                                           GPIOF_OUT_INIT_HIGH, DRIVER_NAME);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "failed to configure csgpio#%u %d\n"
+                               , i, csgpio);
+                       goto out_disable_clk;
+               }
+       }
+
+       /* set to default clock rate */
+       npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret)
+               goto out_disable_clk;
+
+       pr_info("NPCM Peripheral SPI %d probed\n", pdev->id);
+
+       return 0;
+
+out_disable_clk:
+       clk_disable_unprepare(priv->clk);
+
+out_master_put:
+       spi_master_put(master);
+       return ret;
+}
+
+static int npcm_pspi_remove(struct platform_device *pdev)
+{
+       struct npcm_pspi *priv = platform_get_drvdata(pdev);
+
+       npcm_pspi_reset_hw(priv);
+       clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static const struct of_device_id npcm_pspi_match[] = {
+       { .compatible = "nuvoton,npcm750-pspi", .data = NULL },
+       {}
+};
+MODULE_DEVICE_TABLE(of, npcm_pspi_match);
+
+static struct platform_driver npcm_pspi_driver = {
+       .driver         = {
+               .name           = DRIVER_NAME,
+               .of_match_table = npcm_pspi_match,
+       },
+       .probe          = npcm_pspi_probe,
+       .remove         = npcm_pspi_remove,
+};
+module_platform_driver(npcm_pspi_driver);
+
+MODULE_DESCRIPTION("NPCM peripheral SPI Controller driver");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
+
index 6120e6abcd9683f9114b8c12d24fe3431966720c..0c793e31d60f4237680ee1ef98dd869bf61f8dce 100644 (file)
@@ -861,11 +861,10 @@ static void dma_callback(void *data)
 
        /* Update total bytes transferred */
        msg->actual_length += pl022->cur_transfer->len;
-       if (pl022->cur_transfer->cs_change)
-               pl022_cs_control(pl022, SSP_CHIP_DESELECT);
-
        /* Move to next transfer */
        msg->state = next_transfer(pl022);
+       if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
+               pl022_cs_control(pl022, SSP_CHIP_DESELECT);
        tasklet_schedule(&pl022->pump_transfers);
 }
 
@@ -1333,10 +1332,10 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
                }
                /* Update total bytes transferred */
                msg->actual_length += pl022->cur_transfer->len;
-               if (pl022->cur_transfer->cs_change)
-                       pl022_cs_control(pl022, SSP_CHIP_DESELECT);
                /* Move to next transfer */
                msg->state = next_transfer(pl022);
+               if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
+                       pl022_cs_control(pl022, SSP_CHIP_DESELECT);
                tasklet_schedule(&pl022->pump_transfers);
                return IRQ_HANDLED;
        }
@@ -1544,10 +1543,11 @@ static void do_polling_transfer(struct pl022 *pl022)
 
                /* Update total byte transferred */
                message->actual_length += pl022->cur_transfer->len;
-               if (pl022->cur_transfer->cs_change)
-                       pl022_cs_control(pl022, SSP_CHIP_DESELECT);
                /* Move to next transfer */
                message->state = next_transfer(pl022);
+               if (message->state != STATE_DONE
+                   && pl022->cur_transfer->cs_change)
+                       pl022_cs_control(pl022, SSP_CHIP_DESELECT);
        }
 out:
        /* Handle end of message */
index 612cc49db28ff2ad95c976c4adfec976aaa1babf..d84b893a64d7e7ba922c158bbc7afbd907f68dbe 100644 (file)
@@ -626,6 +626,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
                return IRQ_HANDLED;
        }
 
+       if (irq_status & SSSR_TUR) {
+               int_error_stop(drv_data, "interrupt_transfer: fifo underrun");
+               return IRQ_HANDLED;
+       }
+
        if (irq_status & SSSR_TINT) {
                pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
                if (drv_data->read(drv_data)) {
@@ -1073,6 +1078,30 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *master,
                        pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
        }
 
+       if (drv_data->ssp_type == MMP2_SSP) {
+               u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR)
+                                       & SSSR_TFL_MASK) >> 8;
+
+               if (tx_level) {
+                       /* On MMP2, flipping SSE doesn't to empty TXFIFO. */
+                       dev_warn(&spi->dev, "%d bytes of garbage in TXFIFO!\n",
+                                                               tx_level);
+                       if (tx_level > transfer->len)
+                               tx_level = transfer->len;
+                       drv_data->tx += tx_level;
+               }
+       }
+
+       if (spi_controller_is_slave(master)) {
+               while (drv_data->write(drv_data))
+                       ;
+               if (drv_data->gpiod_ready) {
+                       gpiod_set_value(drv_data->gpiod_ready, 1);
+                       udelay(1);
+                       gpiod_set_value(drv_data->gpiod_ready, 0);
+               }
+       }
+
        /*
         * Release the data by enabling service requests and interrupts,
         * without changing any mode bits
@@ -1082,6 +1111,27 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *master,
        return 1;
 }
 
+static int pxa2xx_spi_slave_abort(struct spi_master *master)
+{
+       struct driver_data *drv_data = spi_controller_get_devdata(master);
+
+       /* Stop and reset SSP */
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
+       reset_sccr1(drv_data);
+       if (!pxa25x_ssp_comp(drv_data))
+               pxa2xx_spi_write(drv_data, SSTO, 0);
+       pxa2xx_spi_flush(drv_data);
+       pxa2xx_spi_write(drv_data, SSCR0,
+                        pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
+
+       dev_dbg(&drv_data->pdev->dev, "transfer aborted\n");
+
+       drv_data->master->cur_msg->status = -EINTR;
+       spi_finalize_current_transfer(drv_data->master);
+
+       return 0;
+}
+
 static void pxa2xx_spi_handle_err(struct spi_controller *master,
                                 struct spi_message *msg)
 {
@@ -1209,9 +1259,14 @@ static int setup(struct spi_device *spi)
                rx_thres = config->rx_threshold;
                break;
        default:
-               tx_thres = TX_THRESH_DFLT;
                tx_hi_thres = 0;
-               rx_thres = RX_THRESH_DFLT;
+               if (spi_controller_is_slave(drv_data->master)) {
+                       tx_thres = 1;
+                       rx_thres = 2;
+               } else {
+                       tx_thres = TX_THRESH_DFLT;
+                       rx_thres = RX_THRESH_DFLT;
+               }
                break;
        }
 
@@ -1255,6 +1310,12 @@ static int setup(struct spi_device *spi)
                if (chip_info->enable_loopback)
                        chip->cr1 = SSCR1_LBM;
        }
+       if (spi_controller_is_slave(drv_data->master)) {
+               chip->cr1 |= SSCR1_SCFR;
+               chip->cr1 |= SSCR1_SCLKDIR;
+               chip->cr1 |= SSCR1_SFRMDIR;
+               chip->cr1 |= SSCR1_SPH;
+       }
 
        chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
        chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
@@ -1500,6 +1561,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
        ssp->pdev = pdev;
        ssp->port_id = pxa2xx_spi_get_port_id(adev);
 
+       pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave");
        pdata->num_chipselect = 1;
        pdata->enable_dma = true;
 
@@ -1559,7 +1621,11 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       master = spi_alloc_master(dev, sizeof(struct driver_data));
+       if (platform_info->is_slave)
+               master = spi_alloc_slave(dev, sizeof(struct driver_data));
+       else
+               master = spi_alloc_master(dev, sizeof(struct driver_data));
+
        if (!master) {
                dev_err(&pdev->dev, "cannot alloc spi_master\n");
                pxa_ssp_free(ssp);
@@ -1581,6 +1647,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        master->setup = setup;
        master->set_cs = pxa2xx_spi_set_cs;
        master->transfer_one = pxa2xx_spi_transfer_one;
+       master->slave_abort = pxa2xx_spi_slave_abort;
        master->handle_err = pxa2xx_spi_handle_err;
        master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
        master->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
@@ -1610,7 +1677,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
                drv_data->dma_cr1 = DEFAULT_DMA_CR1;
                drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
-               drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
+               drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS
+                                               | SSSR_ROR | SSSR_TUR;
        }
 
        status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
@@ -1658,10 +1726,22 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                pxa2xx_spi_write(drv_data, SSCR0, tmp);
                break;
        default:
-               tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
-                     SSCR1_TxTresh(TX_THRESH_DFLT);
+
+               if (spi_controller_is_slave(master)) {
+                       tmp = SSCR1_SCFR |
+                             SSCR1_SCLKDIR |
+                             SSCR1_SFRMDIR |
+                             SSCR1_RxTresh(2) |
+                             SSCR1_TxTresh(1) |
+                             SSCR1_SPH;
+               } else {
+                       tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
+                             SSCR1_TxTresh(TX_THRESH_DFLT);
+               }
                pxa2xx_spi_write(drv_data, SSCR1, tmp);
-               tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8);
+               tmp = SSCR0_Motorola | SSCR0_DataSize(8);
+               if (!spi_controller_is_slave(master))
+                       tmp |= SSCR0_SCR(2);
                pxa2xx_spi_write(drv_data, SSCR0, tmp);
                break;
        }
@@ -1711,7 +1791,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                                if (PTR_ERR(gpiod) == -ENOENT)
                                        continue;
 
-                               status = (int)PTR_ERR(gpiod);
+                               status = PTR_ERR(gpiod);
                                goto out_error_clock_enabled;
                        } else {
                                drv_data->cs_gpiods[i] = gpiod;
@@ -1719,6 +1799,15 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                }
        }
 
+       if (platform_info->is_slave) {
+               drv_data->gpiod_ready = devm_gpiod_get_optional(dev,
+                                               "ready", GPIOD_OUT_LOW);
+               if (IS_ERR(drv_data->gpiod_ready)) {
+                       status = PTR_ERR(drv_data->gpiod_ready);
+                       goto out_error_clock_enabled;
+               }
+       }
+
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
@@ -1811,10 +1900,6 @@ static int pxa2xx_spi_resume(struct device *dev)
                        return status;
        }
 
-       /* Restore LPSS private register bits */
-       if (is_lpss_ssp(drv_data))
-               lpss_ssp_setup(drv_data);
-
        /* Start the queue running */
        return spi_controller_resume(drv_data->master);
 }
index 513c53aaeab233bf5a340d758ff375166f87b51d..4e324da66ef7544fbcbb47edc21e3155b5cb27d0 100644 (file)
@@ -64,6 +64,9 @@ struct driver_data {
 
        /* GPIOs for chip selects */
        struct gpio_desc **cs_gpiods;
+
+       /* Optional slave FIFO ready signal */
+       struct gpio_desc *gpiod_ready;
 };
 
 struct chip_data {
index b8163b40bb92c571386ba945b303ce3433dbcc4d..e0f061139c8f5b97d6bed7e1846fadfe79290941 100644 (file)
@@ -90,6 +90,9 @@
 #define PIO_DATAOUT_1B         0x0020
 #define PIO_DATAOUT_4B         0x0024
 
+#define RD_FIFO_CFG            0x0028
+#define CONTINUOUS_MODE                BIT(0)
+
 #define RD_FIFO_STATUS 0x002c
 #define FIFO_EMPTY     BIT(11)
 #define WR_CNTS_MSK    0x7f0
 #define RDY_16BYTE     BIT(1)
 #define FIFO_RDY       BIT(0)
 
-#define RD_FIFO_CFG            0x0028
-#define CONTINUOUS_MODE                BIT(0)
-
 #define RD_FIFO_RESET          0x0030
 #define RESET_FIFO             BIT(0)
 
@@ -139,7 +139,7 @@ struct qcom_qspi {
        struct device *dev;
        struct clk_bulk_data clks[QSPI_NUM_CLKS];
        struct qspi_xfer xfer;
-       /* Lock to protect data accessed by IRQs */
+       /* Lock to protect xfer and IRQ accessed registers */
        spinlock_t lock;
 };
 
index 51ef632bca52564b8db1f79063f29e99078874a1..3912526ead6641067e189a825c9df8ebf8faabfc 100644 (file)
@@ -54,6 +54,9 @@
 
 /* Bit fields in CTRLR0 */
 #define CR0_DFS_OFFSET                         0
+#define CR0_DFS_4BIT                           0x0
+#define CR0_DFS_8BIT                           0x1
+#define CR0_DFS_16BIT                          0x2
 
 #define CR0_CFS_OFFSET                         2
 
@@ -94,6 +97,7 @@
 #define CR0_BHT_8BIT                           0x1
 
 #define CR0_RSD_OFFSET                         14
+#define CR0_RSD_MAX                            0x3
 
 #define CR0_FRF_OFFSET                         16
 #define CR0_FRF_SPI                                    0x0
 /* Bit fields in SER, 2bit */
 #define SER_MASK                                       0x3
 
+/* Bit fields in BAUDR */
+#define BAUDR_SCKDV_MIN                                2
+#define BAUDR_SCKDV_MAX                                65534
+
 /* Bit fields in SR, 5bit */
 #define SR_MASK                                                0x1f
 #define SR_BUSY                                                (1 << 0)
 #define RF_DMA_EN                                      (1 << 0)
 #define TF_DMA_EN                                      (1 << 1)
 
-#define RXBUSY                                         (1 << 0)
-#define TXBUSY                                         (1 << 1)
+/* Driver state flags */
+#define RXDMA                                  (1 << 0)
+#define TXDMA                                  (1 << 1)
 
 /* sclk_out: spi master internal logic in rk3x can support 50Mhz */
-#define MAX_SCLK_OUT           50000000
+#define MAX_SCLK_OUT                           50000000U
 
 /*
  * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However,
 
 #define ROCKCHIP_SPI_MAX_CS_NUM                        2
 
-enum rockchip_ssi_type {
-       SSI_MOTO_SPI = 0,
-       SSI_TI_SSP,
-       SSI_NS_MICROWIRE,
-};
-
-struct rockchip_spi_dma_data {
-       struct dma_chan *ch;
-       dma_addr_t addr;
-};
-
 struct rockchip_spi {
        struct device *dev;
-       struct spi_master *master;
 
        struct clk *spiclk;
        struct clk *apb_pclk;
 
        void __iomem *regs;
-       /*depth of the FIFO buffer */
-       u32 fifo_len;
-       /* max bus freq supported */
-       u32 max_freq;
-       /* supported slave numbers */
-       enum rockchip_ssi_type type;
-
-       u16 mode;
-       u8 tmode;
-       u8 bpw;
-       u8 n_bytes;
-       u32 rsd_nsecs;
-       unsigned len;
-       u32 speed;
+       dma_addr_t dma_addr_rx;
+       dma_addr_t dma_addr_tx;
 
        const void *tx;
-       const void *tx_end;
        void *rx;
-       void *rx_end;
+       unsigned int tx_left;
+       unsigned int rx_left;
 
-       u32 state;
-       /* protect state */
-       spinlock_t lock;
+       atomic_t state;
 
-       bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
-
-       bool use_dma;
-       struct sg_table tx_sg;
-       struct sg_table rx_sg;
-       struct rockchip_spi_dma_data dma_rx;
-       struct rockchip_spi_dma_data dma_tx;
-};
+       /*depth of the FIFO buffer */
+       u32 fifo_len;
+       /* frequency of spiclk */
+       u32 freq;
 
-static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
-{
-       writel_relaxed((enable ? 1 : 0), rs->regs + ROCKCHIP_SPI_SSIENR);
-}
+       u8 n_bytes;
+       u8 rsd;
 
-static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
-{
-       writel_relaxed(div, rs->regs + ROCKCHIP_SPI_BAUDR);
-}
+       bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
+};
 
-static inline void flush_fifo(struct rockchip_spi *rs)
+static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
 {
-       while (readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR))
-               readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
+       writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
 }
 
 static inline void wait_for_idle(struct rockchip_spi *rs)
@@ -251,24 +225,6 @@ static u32 get_fifo_len(struct rockchip_spi *rs)
        return (fifo == 31) ? 0 : fifo;
 }
 
-static inline u32 tx_max(struct rockchip_spi *rs)
-{
-       u32 tx_left, tx_room;
-
-       tx_left = (rs->tx_end - rs->tx) / rs->n_bytes;
-       tx_room = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
-
-       return min(tx_left, tx_room);
-}
-
-static inline u32 rx_max(struct rockchip_spi *rs)
-{
-       u32 rx_left = (rs->rx_end - rs->rx) / rs->n_bytes;
-       u32 rx_room = (u32)readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
-
-       return min(rx_left, rx_room);
-}
-
 static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
 {
        struct spi_master *master = spi->master;
@@ -296,64 +252,39 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
        rs->cs_asserted[spi->chip_select] = cs_asserted;
 }
 
-static int rockchip_spi_prepare_message(struct spi_master *master,
-                                       struct spi_message *msg)
-{
-       struct rockchip_spi *rs = spi_master_get_devdata(master);
-       struct spi_device *spi = msg->spi;
-
-       rs->mode = spi->mode;
-
-       return 0;
-}
-
 static void rockchip_spi_handle_err(struct spi_master *master,
                                    struct spi_message *msg)
 {
-       unsigned long flags;
        struct rockchip_spi *rs = spi_master_get_devdata(master);
 
-       spin_lock_irqsave(&rs->lock, flags);
-
-       /*
-        * For DMA mode, we need terminate DMA channel and flush
-        * fifo for the next transfer if DMA thansfer timeout.
-        * handle_err() was called by core if transfer failed.
-        * Maybe it is reasonable for error handling here.
+       /* stop running spi transfer
+        * this also flushes both rx and tx fifos
         */
-       if (rs->use_dma) {
-               if (rs->state & RXBUSY) {
-                       dmaengine_terminate_async(rs->dma_rx.ch);
-                       flush_fifo(rs);
-               }
-
-               if (rs->state & TXBUSY)
-                       dmaengine_terminate_async(rs->dma_tx.ch);
-       }
+       spi_enable_chip(rs, false);
 
-       spin_unlock_irqrestore(&rs->lock, flags);
-}
+       /* make sure all interrupts are masked */
+       writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
 
-static int rockchip_spi_unprepare_message(struct spi_master *master,
-                                         struct spi_message *msg)
-{
-       struct rockchip_spi *rs = spi_master_get_devdata(master);
+       if (atomic_read(&rs->state) & TXDMA)
+               dmaengine_terminate_async(master->dma_tx);
 
-       spi_enable_chip(rs, 0);
-
-       return 0;
+       if (atomic_read(&rs->state) & RXDMA)
+               dmaengine_terminate_async(master->dma_rx);
 }
 
 static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
 {
-       u32 max = tx_max(rs);
-       u32 txw = 0;
+       u32 tx_free = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
+       u32 words = min(rs->tx_left, tx_free);
+
+       rs->tx_left -= words;
+       for (; words; words--) {
+               u32 txw;
 
-       while (max--) {
                if (rs->n_bytes == 1)
-                       txw = *(u8 *)(rs->tx);
+                       txw = *(u8 *)rs->tx;
                else
-                       txw = *(u16 *)(rs->tx);
+                       txw = *(u16 *)rs->tx;
 
                writel_relaxed(txw, rs->regs + ROCKCHIP_SPI_TXDR);
                rs->tx += rs->n_bytes;
@@ -362,229 +293,249 @@ static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
 
 static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
 {
-       u32 max = rx_max(rs);
-       u32 rxw;
+       u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
+       u32 rx_left = rs->rx_left - words;
+
+       /* the hardware doesn't allow us to change fifo threshold
+        * level while spi is enabled, so instead make sure to leave
+        * enough words in the rx fifo to get the last interrupt
+        * exactly when all words have been received
+        */
+       if (rx_left) {
+               u32 ftl = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFTLR) + 1;
+
+               if (rx_left < ftl) {
+                       rx_left = ftl;
+                       words = rs->rx_left - rx_left;
+               }
+       }
+
+       rs->rx_left = rx_left;
+       for (; words; words--) {
+               u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
+
+               if (!rs->rx)
+                       continue;
 
-       while (max--) {
-               rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
                if (rs->n_bytes == 1)
-                       *(u8 *)(rs->rx) = (u8)rxw;
+                       *(u8 *)rs->rx = (u8)rxw;
                else
-                       *(u16 *)(rs->rx) = (u16)rxw;
+                       *(u16 *)rs->rx = (u16)rxw;
                rs->rx += rs->n_bytes;
        }
 }
 
-static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
+static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
 {
-       int remain = 0;
+       struct spi_master *master = dev_id;
+       struct rockchip_spi *rs = spi_master_get_devdata(master);
 
-       spi_enable_chip(rs, 1);
+       if (rs->tx_left)
+               rockchip_spi_pio_writer(rs);
 
-       do {
-               if (rs->tx) {
-                       remain = rs->tx_end - rs->tx;
-                       rockchip_spi_pio_writer(rs);
-               }
+       rockchip_spi_pio_reader(rs);
+       if (!rs->rx_left) {
+               spi_enable_chip(rs, false);
+               writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
+               spi_finalize_current_transfer(master);
+       }
 
-               if (rs->rx) {
-                       remain = rs->rx_end - rs->rx;
-                       rockchip_spi_pio_reader(rs);
-               }
+       return IRQ_HANDLED;
+}
 
-               cpu_relax();
-       } while (remain);
+static int rockchip_spi_prepare_irq(struct rockchip_spi *rs,
+               struct spi_transfer *xfer)
+{
+       rs->tx = xfer->tx_buf;
+       rs->rx = xfer->rx_buf;
+       rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0;
+       rs->rx_left = xfer->len / rs->n_bytes;
 
-       /* If tx, wait until the FIFO data completely. */
-       if (rs->tx)
-               wait_for_idle(rs);
+       writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR);
+       spi_enable_chip(rs, true);
 
-       spi_enable_chip(rs, 0);
+       if (rs->tx_left)
+               rockchip_spi_pio_writer(rs);
 
-       return 0;
+       /* 1 means the transfer is in progress */
+       return 1;
 }
 
 static void rockchip_spi_dma_rxcb(void *data)
 {
-       unsigned long flags;
-       struct rockchip_spi *rs = data;
-
-       spin_lock_irqsave(&rs->lock, flags);
+       struct spi_master *master = data;
+       struct rockchip_spi *rs = spi_master_get_devdata(master);
+       int state = atomic_fetch_andnot(RXDMA, &rs->state);
 
-       rs->state &= ~RXBUSY;
-       if (!(rs->state & TXBUSY)) {
-               spi_enable_chip(rs, 0);
-               spi_finalize_current_transfer(rs->master);
-       }
+       if (state & TXDMA)
+               return;
 
-       spin_unlock_irqrestore(&rs->lock, flags);
+       spi_enable_chip(rs, false);
+       spi_finalize_current_transfer(master);
 }
 
 static void rockchip_spi_dma_txcb(void *data)
 {
-       unsigned long flags;
-       struct rockchip_spi *rs = data;
+       struct spi_master *master = data;
+       struct rockchip_spi *rs = spi_master_get_devdata(master);
+       int state = atomic_fetch_andnot(TXDMA, &rs->state);
+
+       if (state & RXDMA)
+               return;
 
        /* Wait until the FIFO data completely. */
        wait_for_idle(rs);
 
-       spin_lock_irqsave(&rs->lock, flags);
-
-       rs->state &= ~TXBUSY;
-       if (!(rs->state & RXBUSY)) {
-               spi_enable_chip(rs, 0);
-               spi_finalize_current_transfer(rs->master);
-       }
-
-       spin_unlock_irqrestore(&rs->lock, flags);
+       spi_enable_chip(rs, false);
+       spi_finalize_current_transfer(master);
 }
 
-static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
+               struct spi_master *master, struct spi_transfer *xfer)
 {
-       unsigned long flags;
-       struct dma_slave_config rxconf, txconf;
        struct dma_async_tx_descriptor *rxdesc, *txdesc;
 
-       memset(&rxconf, 0, sizeof(rxconf));
-       memset(&txconf, 0, sizeof(txconf));
-
-       spin_lock_irqsave(&rs->lock, flags);
-       rs->state &= ~RXBUSY;
-       rs->state &= ~TXBUSY;
-       spin_unlock_irqrestore(&rs->lock, flags);
+       atomic_set(&rs->state, 0);
 
        rxdesc = NULL;
-       if (rs->rx) {
-               rxconf.direction = DMA_DEV_TO_MEM;
-               rxconf.src_addr = rs->dma_rx.addr;
-               rxconf.src_addr_width = rs->n_bytes;
-               rxconf.src_maxburst = 1;
-               dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
+       if (xfer->rx_buf) {
+               struct dma_slave_config rxconf = {
+                       .direction = DMA_DEV_TO_MEM,
+                       .src_addr = rs->dma_addr_rx,
+                       .src_addr_width = rs->n_bytes,
+                       .src_maxburst = 1,
+               };
+
+               dmaengine_slave_config(master->dma_rx, &rxconf);
 
                rxdesc = dmaengine_prep_slave_sg(
-                               rs->dma_rx.ch,
-                               rs->rx_sg.sgl, rs->rx_sg.nents,
+                               master->dma_rx,
+                               xfer->rx_sg.sgl, xfer->rx_sg.nents,
                                DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
                if (!rxdesc)
                        return -EINVAL;
 
                rxdesc->callback = rockchip_spi_dma_rxcb;
-               rxdesc->callback_param = rs;
+               rxdesc->callback_param = master;
        }
 
        txdesc = NULL;
-       if (rs->tx) {
-               txconf.direction = DMA_MEM_TO_DEV;
-               txconf.dst_addr = rs->dma_tx.addr;
-               txconf.dst_addr_width = rs->n_bytes;
-               txconf.dst_maxburst = rs->fifo_len / 2;
-               dmaengine_slave_config(rs->dma_tx.ch, &txconf);
+       if (xfer->tx_buf) {
+               struct dma_slave_config txconf = {
+                       .direction = DMA_MEM_TO_DEV,
+                       .dst_addr = rs->dma_addr_tx,
+                       .dst_addr_width = rs->n_bytes,
+                       .dst_maxburst = rs->fifo_len / 2,
+               };
+
+               dmaengine_slave_config(master->dma_tx, &txconf);
 
                txdesc = dmaengine_prep_slave_sg(
-                               rs->dma_tx.ch,
-                               rs->tx_sg.sgl, rs->tx_sg.nents,
+                               master->dma_tx,
+                               xfer->tx_sg.sgl, xfer->tx_sg.nents,
                                DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
                if (!txdesc) {
                        if (rxdesc)
-                               dmaengine_terminate_sync(rs->dma_rx.ch);
+                               dmaengine_terminate_sync(master->dma_rx);
                        return -EINVAL;
                }
 
                txdesc->callback = rockchip_spi_dma_txcb;
-               txdesc->callback_param = rs;
+               txdesc->callback_param = master;
        }
 
        /* rx must be started before tx due to spi instinct */
        if (rxdesc) {
-               spin_lock_irqsave(&rs->lock, flags);
-               rs->state |= RXBUSY;
-               spin_unlock_irqrestore(&rs->lock, flags);
+               atomic_or(RXDMA, &rs->state);
                dmaengine_submit(rxdesc);
-               dma_async_issue_pending(rs->dma_rx.ch);
+               dma_async_issue_pending(master->dma_rx);
        }
 
-       spi_enable_chip(rs, 1);
+       spi_enable_chip(rs, true);
 
        if (txdesc) {
-               spin_lock_irqsave(&rs->lock, flags);
-               rs->state |= TXBUSY;
-               spin_unlock_irqrestore(&rs->lock, flags);
+               atomic_or(TXDMA, &rs->state);
                dmaengine_submit(txdesc);
-               dma_async_issue_pending(rs->dma_tx.ch);
+               dma_async_issue_pending(master->dma_tx);
        }
 
        /* 1 means the transfer is in progress */
        return 1;
 }
 
-static void rockchip_spi_config(struct rockchip_spi *rs)
+static void rockchip_spi_config(struct rockchip_spi *rs,
+               struct spi_device *spi, struct spi_transfer *xfer,
+               bool use_dma)
 {
-       u32 div = 0;
+       u32 cr0 = CR0_FRF_SPI  << CR0_FRF_OFFSET
+               | CR0_BHT_8BIT << CR0_BHT_OFFSET
+               | CR0_SSD_ONE  << CR0_SSD_OFFSET
+               | CR0_EM_BIG   << CR0_EM_OFFSET;
+       u32 cr1;
        u32 dmacr = 0;
-       int rsd = 0;
-
-       u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
-               | (CR0_SSD_ONE << CR0_SSD_OFFSET)
-               | (CR0_EM_BIG << CR0_EM_OFFSET);
 
-       cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
-       cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
-       cr0 |= (rs->tmode << CR0_XFM_OFFSET);
-       cr0 |= (rs->type << CR0_FRF_OFFSET);
+       cr0 |= rs->rsd << CR0_RSD_OFFSET;
+       cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+       if (spi->mode & SPI_LSB_FIRST)
+               cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
+
+       if (xfer->rx_buf && xfer->tx_buf)
+               cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
+       else if (xfer->rx_buf)
+               cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET;
+       else if (use_dma)
+               cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;
+
+       switch (xfer->bits_per_word) {
+       case 4:
+               cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET;
+               cr1 = xfer->len - 1;
+               break;
+       case 8:
+               cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET;
+               cr1 = xfer->len - 1;
+               break;
+       case 16:
+               cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET;
+               cr1 = xfer->len / 2 - 1;
+               break;
+       default:
+               /* we only whitelist 4, 8 and 16 bit words in
+                * master->bits_per_word_mask, so this shouldn't
+                * happen
+                */
+               unreachable();
+       }
 
-       if (rs->use_dma) {
-               if (rs->tx)
+       if (use_dma) {
+               if (xfer->tx_buf)
                        dmacr |= TF_DMA_EN;
-               if (rs->rx)
+               if (xfer->rx_buf)
                        dmacr |= RF_DMA_EN;
        }
 
-       if (WARN_ON(rs->speed > MAX_SCLK_OUT))
-               rs->speed = MAX_SCLK_OUT;
-
-       /* the minimum divisor is 2 */
-       if (rs->max_freq < 2 * rs->speed) {
-               clk_set_rate(rs->spiclk, 2 * rs->speed);
-               rs->max_freq = clk_get_rate(rs->spiclk);
-       }
-
-       /* div doesn't support odd number */
-       div = DIV_ROUND_UP(rs->max_freq, rs->speed);
-       div = (div + 1) & 0xfffe;
-
-       /* Rx sample delay is expressed in parent clock cycles (max 3) */
-       rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
-                               1000000000 >> 8);
-       if (!rsd && rs->rsd_nsecs) {
-               pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
-                            rs->max_freq, rs->rsd_nsecs);
-       } else if (rsd > 3) {
-               rsd = 3;
-               pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
-                            rs->max_freq, rs->rsd_nsecs,
-                            rsd * 1000000000U / rs->max_freq);
-       }
-       cr0 |= rsd << CR0_RSD_OFFSET;
-
        writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
+       writel_relaxed(cr1, rs->regs + ROCKCHIP_SPI_CTRLR1);
 
-       if (rs->n_bytes == 1)
-               writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
-       else if (rs->n_bytes == 2)
-               writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+       /* unfortunately setting the fifo threshold level to generate an
+        * interrupt exactly when the fifo is full doesn't seem to work,
+        * so we need the strict inequality here
+        */
+       if (xfer->len < rs->fifo_len)
+               writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
        else
-               writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
-
-       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
-       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+               writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
 
        writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
        writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
        writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
 
-       spi_set_clk(rs, div);
-
-       dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
+       /* the hardware only supports an even clock divisor, so
+        * round divisor = spiclk / speed up to nearest even number
+        * so that the resulting speed is <= the requested speed
+        */
+       writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz),
+                       rs->regs + ROCKCHIP_SPI_BAUDR);
 }
 
 static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
@@ -598,6 +549,7 @@ static int rockchip_spi_transfer_one(
                struct spi_transfer *xfer)
 {
        struct rockchip_spi *rs = spi_master_get_devdata(master);
+       bool use_dma;
 
        WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
                (readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY));
@@ -612,38 +564,16 @@ static int rockchip_spi_transfer_one(
                return -EINVAL;
        }
 
-       rs->speed = xfer->speed_hz;
-       rs->bpw = xfer->bits_per_word;
-       rs->n_bytes = rs->bpw >> 3;
+       rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2;
 
-       rs->tx = xfer->tx_buf;
-       rs->tx_end = rs->tx + xfer->len;
-       rs->rx = xfer->rx_buf;
-       rs->rx_end = rs->rx + xfer->len;
-       rs->len = xfer->len;
-
-       rs->tx_sg = xfer->tx_sg;
-       rs->rx_sg = xfer->rx_sg;
-
-       if (rs->tx && rs->rx)
-               rs->tmode = CR0_XFM_TR;
-       else if (rs->tx)
-               rs->tmode = CR0_XFM_TO;
-       else if (rs->rx)
-               rs->tmode = CR0_XFM_RO;
-
-       /* we need prepare dma before spi was enabled */
-       if (master->can_dma && master->can_dma(master, spi, xfer))
-               rs->use_dma = true;
-       else
-               rs->use_dma = false;
+       use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;
 
-       rockchip_spi_config(rs);
+       rockchip_spi_config(rs, spi, xfer, use_dma);
 
-       if (rs->use_dma)
-               return rockchip_spi_prepare_dma(rs);
+       if (use_dma)
+               return rockchip_spi_prepare_dma(rs, master, xfer);
 
-       return rockchip_spi_pio_transfer(rs);
+       return rockchip_spi_prepare_irq(rs, xfer);
 }
 
 static bool rockchip_spi_can_dma(struct spi_master *master,
@@ -651,8 +581,13 @@ static bool rockchip_spi_can_dma(struct spi_master *master,
                                 struct spi_transfer *xfer)
 {
        struct rockchip_spi *rs = spi_master_get_devdata(master);
+       unsigned int bytes_per_word = xfer->bits_per_word <= 8 ? 1 : 2;
 
-       return (xfer->len > rs->fifo_len);
+       /* if the numbor of spi words to transfer is less than the fifo
+        * length we can just fill the fifo and wait for a single irq,
+        * so don't bother setting up dma
+        */
+       return xfer->len / bytes_per_word >= rs->fifo_len;
 }
 
 static int rockchip_spi_probe(struct platform_device *pdev)
@@ -705,16 +640,36 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                goto err_disable_apbclk;
        }
 
-       spi_enable_chip(rs, 0);
+       spi_enable_chip(rs, false);
+
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               goto err_disable_spiclk;
+
+       ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL,
+                       IRQF_ONESHOT, dev_name(&pdev->dev), master);
+       if (ret)
+               goto err_disable_spiclk;
 
-       rs->type = SSI_MOTO_SPI;
-       rs->master = master;
        rs->dev = &pdev->dev;
-       rs->max_freq = clk_get_rate(rs->spiclk);
+       rs->freq = clk_get_rate(rs->spiclk);
 
        if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
-                                 &rsd_nsecs))
-               rs->rsd_nsecs = rsd_nsecs;
+                                 &rsd_nsecs)) {
+               /* rx sample delay is expressed in parent clock cycles (max 3) */
+               u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
+                               1000000000 >> 8);
+               if (!rsd) {
+                       dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n",
+                                       rs->freq, rsd_nsecs);
+               } else if (rsd > CR0_RSD_MAX) {
+                       rsd = CR0_RSD_MAX;
+                       dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
+                                       rs->freq, rsd_nsecs,
+                                       CR0_RSD_MAX * 1000000000U / rs->freq);
+               }
+               rs->rsd = rsd;
+       }
 
        rs->fifo_len = get_fifo_len(rs);
        if (!rs->fifo_len) {
@@ -723,54 +678,49 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                goto err_disable_spiclk;
        }
 
-       spin_lock_init(&rs->lock);
-
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
        master->auto_runtime_pm = true;
        master->bus_num = pdev->id;
-       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
        master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
        master->dev.of_node = pdev->dev.of_node;
-       master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+       master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
+       master->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
+       master->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);
 
        master->set_cs = rockchip_spi_set_cs;
-       master->prepare_message = rockchip_spi_prepare_message;
-       master->unprepare_message = rockchip_spi_unprepare_message;
        master->transfer_one = rockchip_spi_transfer_one;
        master->max_transfer_size = rockchip_spi_max_transfer_size;
        master->handle_err = rockchip_spi_handle_err;
        master->flags = SPI_MASTER_GPIO_SS;
 
-       rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
-       if (IS_ERR(rs->dma_tx.ch)) {
+       master->dma_tx = dma_request_chan(rs->dev, "tx");
+       if (IS_ERR(master->dma_tx)) {
                /* Check tx to see if we need defer probing driver */
-               if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
+               if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
                        goto err_disable_pm_runtime;
                }
                dev_warn(rs->dev, "Failed to request TX DMA channel\n");
-               rs->dma_tx.ch = NULL;
+               master->dma_tx = NULL;
        }
 
-       rs->dma_rx.ch = dma_request_chan(rs->dev, "rx");
-       if (IS_ERR(rs->dma_rx.ch)) {
-               if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) {
+       master->dma_rx = dma_request_chan(rs->dev, "rx");
+       if (IS_ERR(master->dma_rx)) {
+               if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
                        goto err_free_dma_tx;
                }
                dev_warn(rs->dev, "Failed to request RX DMA channel\n");
-               rs->dma_rx.ch = NULL;
+               master->dma_rx = NULL;
        }
 
-       if (rs->dma_tx.ch && rs->dma_rx.ch) {
-               rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
-               rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
-
+       if (master->dma_tx && master->dma_rx) {
+               rs->dma_addr_tx = mem->start + ROCKCHIP_SPI_TXDR;
+               rs->dma_addr_rx = mem->start + ROCKCHIP_SPI_RXDR;
                master->can_dma = rockchip_spi_can_dma;
-               master->dma_tx = rs->dma_tx.ch;
-               master->dma_rx = rs->dma_rx.ch;
        }
 
        ret = devm_spi_register_master(&pdev->dev, master);
@@ -782,11 +732,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
        return 0;
 
 err_free_dma_rx:
-       if (rs->dma_rx.ch)
-               dma_release_channel(rs->dma_rx.ch);
+       if (master->dma_rx)
+               dma_release_channel(master->dma_rx);
 err_free_dma_tx:
-       if (rs->dma_tx.ch)
-               dma_release_channel(rs->dma_tx.ch);
+       if (master->dma_tx)
+               dma_release_channel(master->dma_tx);
 err_disable_pm_runtime:
        pm_runtime_disable(&pdev->dev);
 err_disable_spiclk:
@@ -813,10 +763,10 @@ static int rockchip_spi_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
 
-       if (rs->dma_tx.ch)
-               dma_release_channel(rs->dma_tx.ch);
-       if (rs->dma_rx.ch)
-               dma_release_channel(rs->dma_rx.ch);
+       if (master->dma_tx)
+               dma_release_channel(master->dma_tx);
+       if (master->dma_rx)
+               dma_release_channel(master->dma_rx);
 
        spi_master_put(master);
 
@@ -828,9 +778,8 @@ static int rockchip_spi_suspend(struct device *dev)
 {
        int ret;
        struct spi_master *master = dev_get_drvdata(dev);
-       struct rockchip_spi *rs = spi_master_get_devdata(master);
 
-       ret = spi_master_suspend(rs->master);
+       ret = spi_master_suspend(master);
        if (ret < 0)
                return ret;
 
@@ -855,7 +804,7 @@ static int rockchip_spi_resume(struct device *dev)
        if (ret < 0)
                return ret;
 
-       ret = spi_master_resume(rs->master);
+       ret = spi_master_resume(master);
        if (ret < 0) {
                clk_disable_unprepare(rs->spiclk);
                clk_disable_unprepare(rs->apb_pclk);
index 55f8e55327b3fa6901d8213685b7a76b196d5f29..a4ef641b522727e008daccbbc980af62566ee297 100644 (file)
@@ -1347,16 +1347,14 @@ MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 #ifdef CONFIG_PM_SLEEP
 static int rspi_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rspi_data *rspi = platform_get_drvdata(pdev);
+       struct rspi_data *rspi = dev_get_drvdata(dev);
 
        return spi_master_suspend(rspi->master);
 }
 
 static int rspi_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rspi_data *rspi = platform_get_drvdata(pdev);
+       struct rspi_data *rspi = dev_get_drvdata(dev);
 
        return spi_master_resume(rspi->master);
 }
index adf384323934a6e432183bb16bcad27090b29881..d14b407cc800169a89b5a8cfb1b92ea8242f7c72 100644 (file)
@@ -977,7 +977,7 @@ static int sh_msiof_transfer_one(struct spi_master *master,
                        return 0;
        }
 
-       if (bits <= 8 && len > 15 && !(len & 3)) {
+       if (bits <= 8 && len > 15) {
                bits = 32;
                swab = true;
        } else {
@@ -1038,6 +1038,14 @@ static int sh_msiof_transfer_one(struct spi_master *master,
                if (rx_buf)
                        rx_buf += n * bytes_per_word;
                words -= n;
+
+               if (words == 0 && (len % bytes_per_word)) {
+                       words = len % bytes_per_word;
+                       bits = t->bits_per_word;
+                       bytes_per_word = 1;
+                       tx_fifo = sh_msiof_spi_write_fifo_8;
+                       rx_fifo = sh_msiof_spi_read_fifo_8;
+               }
        }
 
        return 0;
@@ -1426,16 +1434,14 @@ MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 #ifdef CONFIG_PM_SLEEP
 static int sh_msiof_spi_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+       struct sh_msiof_spi_priv *p = dev_get_drvdata(dev);
 
        return spi_master_suspend(p->master);
 }
 
 static int sh_msiof_spi_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+       struct sh_msiof_spi_priv *p = dev_get_drvdata(dev);
 
        return spi_master_resume(p->master);
 }
index cc4d31033494348249eb79c0e32872fb15b00b37..9f83e1b17aa16b6aa934d24955e5da7773af10a7 100644 (file)
@@ -960,8 +960,7 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev)
  */
 static int __maybe_unused zynqmp_runtime_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = dev_get_drvdata(dev);
        struct zynqmp_qspi *xqspi = spi_master_get_devdata(master);
 
        clk_disable(xqspi->refclk);
@@ -980,8 +979,7 @@ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev)
  */
 static int __maybe_unused zynqmp_runtime_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = dev_get_drvdata(dev);
        struct zynqmp_qspi *xqspi = spi_master_get_devdata(master);
        int ret;
 
index 6ca59406b0b7a5bbe965833cb7e5fa8d86b388dd..9a7def7c3237001b10b2abd21851fbdc42fa6d0d 100644 (file)
@@ -1,10 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SPI init/core code
- *
- * Copyright (C) 2005 David Brownell
- * Copyright (C) 2008 Secret Lab Technologies Ltd.
- */
+// SPI init/core code
+//
+// Copyright (C) 2005 David Brownell
+// Copyright (C) 2008 Secret Lab Technologies Ltd.
 
 #include <linux/kernel.h>
 #include <linux/device.h>
@@ -1037,6 +1035,42 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
        return __spi_map_msg(ctlr, msg);
 }
 
+static int spi_transfer_wait(struct spi_controller *ctlr,
+                            struct spi_message *msg,
+                            struct spi_transfer *xfer)
+{
+       struct spi_statistics *statm = &ctlr->statistics;
+       struct spi_statistics *stats = &msg->spi->statistics;
+       unsigned long long ms = 1;
+
+       if (spi_controller_is_slave(ctlr)) {
+               if (wait_for_completion_interruptible(&ctlr->xfer_completion)) {
+                       dev_dbg(&msg->spi->dev, "SPI transfer interrupted\n");
+                       return -EINTR;
+               }
+       } else {
+               ms = 8LL * 1000LL * xfer->len;
+               do_div(ms, xfer->speed_hz);
+               ms += ms + 200; /* some tolerance */
+
+               if (ms > UINT_MAX)
+                       ms = UINT_MAX;
+
+               ms = wait_for_completion_timeout(&ctlr->xfer_completion,
+                                                msecs_to_jiffies(ms));
+
+               if (ms == 0) {
+                       SPI_STATISTICS_INCREMENT_FIELD(statm, timedout);
+                       SPI_STATISTICS_INCREMENT_FIELD(stats, timedout);
+                       dev_err(&msg->spi->dev,
+                               "SPI transfer timed out\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * spi_transfer_one_message - Default implementation of transfer_one_message()
  *
@@ -1050,7 +1084,6 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
        struct spi_transfer *xfer;
        bool keep_cs = false;
        int ret = 0;
-       unsigned long long ms = 1;
        struct spi_statistics *statm = &ctlr->statistics;
        struct spi_statistics *stats = &msg->spi->statistics;
 
@@ -1080,26 +1113,9 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                        }
 
                        if (ret > 0) {
-                               ret = 0;
-                               ms = 8LL * 1000LL * xfer->len;
-                               do_div(ms, xfer->speed_hz);
-                               ms += ms + 200; /* some tolerance */
-
-                               if (ms > UINT_MAX)
-                                       ms = UINT_MAX;
-
-                               ms = wait_for_completion_timeout(&ctlr->xfer_completion,
-                                                                msecs_to_jiffies(ms));
-                       }
-
-                       if (ms == 0) {
-                               SPI_STATISTICS_INCREMENT_FIELD(statm,
-                                                              timedout);
-                               SPI_STATISTICS_INCREMENT_FIELD(stats,
-                                                              timedout);
-                               dev_err(&msg->spi->dev,
-                                       "SPI transfer timed out\n");
-                               msg->status = -ETIMEDOUT;
+                               ret = spi_transfer_wait(ctlr, msg, xfer);
+                               if (ret < 0)
+                                       msg->status = ret;
                        }
                } else {
                        if (xfer->len)
@@ -1617,6 +1633,9 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
                case 4:
                        spi->mode |= SPI_TX_QUAD;
                        break;
+               case 8:
+                       spi->mode |= SPI_TX_OCTAL;
+                       break;
                default:
                        dev_warn(&ctlr->dev,
                                "spi-tx-bus-width %d not supported\n",
@@ -1635,6 +1654,9 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
                case 4:
                        spi->mode |= SPI_RX_QUAD;
                        break;
+               case 8:
+                       spi->mode |= SPI_RX_OCTAL;
+                       break;
                default:
                        dev_warn(&ctlr->dev,
                                "spi-rx-bus-width %d not supported\n",
@@ -1644,7 +1666,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
        }
 
        if (spi_controller_is_slave(ctlr)) {
-               if (strcmp(nc->name, "slave")) {
+               if (!of_node_name_eq(nc, "slave")) {
                        dev_err(&ctlr->dev, "%pOF is not called 'slave'\n",
                                nc);
                        return -EINVAL;
@@ -2823,7 +2845,8 @@ int spi_setup(struct spi_device *spi)
        /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
         */
        if ((spi->mode & SPI_3WIRE) && (spi->mode &
-               (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
+               (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
+                SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
                return -EINVAL;
        /* help drivers fail *cleanly* when they need options
         * that aren't supported with their current controller
@@ -2832,7 +2855,8 @@ int spi_setup(struct spi_device *spi)
         */
        bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);
        ugly_bits = bad_bits &
-                   (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
+                   (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
+                    SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
        if (ugly_bits) {
                dev_warn(&spi->dev,
                         "setup: ignoring unsupported mode bits %x\n",
index 7c015536360dd871c266080128cd1b601bb340a0..e4f608815c05741ba1523d21ed2a0c7bfa2e6349 100644 (file)
@@ -78,8 +78,6 @@ source "drivers/staging/goldfish/Kconfig"
 
 source "drivers/staging/netlogic/Kconfig"
 
-source "drivers/staging/mt29f_spinand/Kconfig"
-
 source "drivers/staging/gs_fpgaboot/Kconfig"
 
 source "drivers/staging/unisys/Kconfig"
index a79b3fe20cf05c84f4def5e17e37aeded54b0cdf..5868631e8f1b583feb69621f3d88c3512c09469b 100644 (file)
@@ -29,7 +29,6 @@ obj-$(CONFIG_STAGING_BOARD)   += board/
 obj-$(CONFIG_LTE_GDM724X)      += gdm724x/
 obj-$(CONFIG_FIREWIRE_SERIAL)  += fwserial/
 obj-$(CONFIG_GOLDFISH)         += goldfish/
-obj-$(CONFIG_MTD_SPINAND_MT29F)        += mt29f_spinand/
 obj-$(CONFIG_GS_FPGABOOT)      += gs_fpgaboot/
 obj-$(CONFIG_UNISYSSPAR)       += unisys/
 obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD)  += clocking-wizard/
index b3620a8f2d9f7a91051a544bb072576a3252afb4..19cadd17e542a0157d3e0ac3ec08aadcc842fcfe 100644 (file)
@@ -31,10 +31,14 @@ source "drivers/staging/media/mt9t031/Kconfig"
 
 source "drivers/staging/media/omap4iss/Kconfig"
 
+source "drivers/staging/media/rockchip/vpu/Kconfig"
+
 source "drivers/staging/media/sunxi/Kconfig"
 
 source "drivers/staging/media/tegra-vde/Kconfig"
 
 source "drivers/staging/media/zoran/Kconfig"
 
+source "drivers/staging/media/ipu3/Kconfig"
+
 endif
index 42948f8055482fc6fa911a8600f017aea29dd35e..edde1960b030dcd0558d0aceca87a9628651e715 100644 (file)
@@ -8,3 +8,5 @@ obj-$(CONFIG_VIDEO_OMAP4)       += omap4iss/
 obj-$(CONFIG_VIDEO_SUNXI)      += sunxi/
 obj-$(CONFIG_TEGRA_VDE)                += tegra-vde/
 obj-$(CONFIG_VIDEO_ZORAN)      += zoran/
+obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/
+obj-$(CONFIG_VIDEO_IPU3_IMGU)  += ipu3/
index 874d290f962268987bdd39749c6371b7837712b6..debd1122875dda7e768ccd2a277be393823c6be5 100644 (file)
@@ -2574,8 +2574,7 @@ static const struct video_device bcm2048_viddev_template = {
 /*
  *     I2C driver interface
  */
-static int bcm2048_i2c_driver_probe(struct i2c_client *client,
-                                   const struct i2c_device_id *id)
+static int bcm2048_i2c_driver_probe(struct i2c_client *client)
 {
        struct bcm2048_device *bdev;
        int err;
@@ -2679,7 +2678,7 @@ static struct i2c_driver bcm2048_i2c_driver = {
        .driver         = {
                .name   = BCM2048_DRIVER_NAME,
        },
-       .probe          = bcm2048_i2c_driver_probe,
+       .probe_new      = bcm2048_i2c_driver_probe,
        .remove         = bcm2048_i2c_driver_remove,
        .id_table       = bcm2048_id,
 };
index b2e840f96c50d159e5dc0ade4ffb7b595b4c240e..a01327f6e045b33d69629224592ea0807278ac1a 100644 (file)
@@ -162,7 +162,7 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
                fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
                fwnode = fwnode_get_next_parent(fwnode);
                if (is_of_node(fwnode) &&
-                   of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
+                   of_node_name_eq(to_of_node(fwnode), "ports"))
                        fwnode = fwnode_get_next_parent(fwnode);
                link.remote_node = fwnode;
 
diff --git a/drivers/staging/media/ipu3/Kconfig b/drivers/staging/media/ipu3/Kconfig
new file mode 100644 (file)
index 0000000..75cd889
--- /dev/null
@@ -0,0 +1,14 @@
+config VIDEO_IPU3_IMGU
+       tristate "Intel ipu3-imgu driver"
+       depends on PCI && VIDEO_V4L2
+       depends on MEDIA_CONTROLLER && VIDEO_V4L2_SUBDEV_API
+       depends on X86
+       select IOMMU_IOVA
+       select VIDEOBUF2_DMA_SG
+       ---help---
+         This is the Video4Linux2 driver for Intel IPU3 image processing unit,
+         found in Intel Skylake and Kaby Lake SoCs and used for processing
+         images and video.
+
+         Say Y or M here if you have a Skylake/Kaby Lake SoC with a MIPI
+         camera. The module will be called ipu3-imgu.
diff --git a/drivers/staging/media/ipu3/Makefile b/drivers/staging/media/ipu3/Makefile
new file mode 100644 (file)
index 0000000..fb146d1
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the IPU3 ImgU drivers
+#
+
+ipu3-imgu-objs += \
+               ipu3-mmu.o ipu3-dmamap.o \
+               ipu3-tables.o ipu3-css-pool.o \
+               ipu3-css-fw.o ipu3-css-params.o \
+               ipu3-css.o ipu3-v4l2.o ipu3.o
+
+obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3-imgu.o
diff --git a/drivers/staging/media/ipu3/TODO b/drivers/staging/media/ipu3/TODO
new file mode 100644 (file)
index 0000000..905bbb1
--- /dev/null
@@ -0,0 +1,34 @@
+This is a list of things that need to be done to get this driver out of the
+staging directory.
+
+- Request API conversion. Remove of the dual pipeline and associate buffers
+  as well as formats and the binary used to a request. Remove the
+  opportunistic buffer management. (Sakari)
+
+- Using ENABLED and IMMUTABLE link flags for the links where those are
+  relevant. (Sakari)
+
+- Prefix imgu for all public APIs, i.e. change ipu3_v4l2_register() to
+  imgu_v4l2_register(). (Sakari)
+
+- Use V4L2_CTRL_TYPE_MENU for dual-pipe mode control. (Sakari)
+
+- IPU3 driver documentation (Laurent)
+  Add diagram in driver rst to describe output capability.
+  Comments on configuring v4l2 subdevs for CIO2 and ImgU.
+
+- uAPI documentation:
+  Further clarification on some ambiguities such as data type conversion of
+  IEFD CU inputs. (Sakari)
+  Move acronyms to doc-rst file. (Mauro)
+
+- Switch to yavta from v4l2n in driver docs.
+
+- Elaborate the functionality of different selection rectangles in driver
+  documentation. This may require driver changes as well.
+
+- More detailed documentation on calculating BDS, GCD etc. sizes needed.
+
+- Document different operation modes, and which buffer queues are relevant
+  in each mode. To process an image, which queues require a buffer an in
+  which ones is it optional?
diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h
new file mode 100644 (file)
index 0000000..ec0b748
--- /dev/null
@@ -0,0 +1,2785 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2017 - 2018 Intel Corporation */
+
+#ifndef __IPU3_UAPI_H
+#define __IPU3_UAPI_H
+
+#include <linux/types.h>
+
+/* from /drivers/staging/media/ipu3/include/videodev2.h */
+
+/* Vendor specific - used for IPU3 camera sub-system */
+#define V4L2_META_FMT_IPU3_PARAMS      v4l2_fourcc('i', 'p', '3', 'p') /* IPU3 processing parameters */
+#define V4L2_META_FMT_IPU3_STAT_3A     v4l2_fourcc('i', 'p', '3', 's') /* IPU3 3A statistics */
+
+/* from include/uapi/linux/v4l2-controls.h */
+#define V4L2_CID_INTEL_IPU3_BASE       (V4L2_CID_USER_BASE + 0x10c0)
+#define V4L2_CID_INTEL_IPU3_MODE       (V4L2_CID_INTEL_IPU3_BASE + 1)
+
+/* custom ctrl to set pipe mode */
+enum ipu3_running_mode {
+       IPU3_RUNNING_MODE_VIDEO = 0,
+       IPU3_RUNNING_MODE_STILL = 1,
+};
+
+/******************* ipu3_uapi_stats_3a *******************/
+
+#define IPU3_UAPI_MAX_STRIPES                          2
+#define IPU3_UAPI_MAX_BUBBLE_SIZE                      10
+
+#define IPU3_UAPI_GRID_START_MASK                      ((1 << 12) - 1)
+#define IPU3_UAPI_GRID_Y_START_EN                      (1 << 15)
+
+/* controls generation of meta_data (like FF enable/disable) */
+#define IPU3_UAPI_AWB_RGBS_THR_B_EN                    (1 << 14)
+#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT              (1 << 15)
+
+/**
+ * struct ipu3_uapi_grid_config - Grid plane config
+ *
+ * @width:     Grid horizontal dimensions, in number of grid blocks(cells).
+ * @height:    Grid vertical dimensions, in number of grid cells.
+ * @block_width_log2:  Log2 of the width of each cell in pixels.
+ *                     for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7].
+ * @block_height_log2: Log2 of the height of each cell in pixels.
+ *                     for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7].
+ * @height_per_slice:  The number of blocks in vertical axis per slice.
+ *                     Default 2.
+ * @x_start: X value of top left corner of Region of Interest(ROI).
+ * @y_start: Y value of top left corner of ROI
+ * @x_end: X value of bottom right corner of ROI
+ * @y_end: Y value of bottom right corner of ROI
+ *
+ * Due to the size of total amount of collected data, most statistics
+ * create a grid-based output, and the data is then divided into "slices".
+ */
+struct ipu3_uapi_grid_config {
+       __u8 width;
+       __u8 height;
+       __u16 block_width_log2:3;
+       __u16 block_height_log2:3;
+       __u16 height_per_slice:8;
+       __u16 x_start;
+       __u16 y_start;
+       __u16 x_end;
+       __u16 y_end;
+} __packed;
+
+/*
+ * The grid based data is divided into "slices" called set, each slice of setX
+ * refers to ipu3_uapi_grid_config width * height_per_slice.
+ */
+#define IPU3_UAPI_AWB_MAX_SETS                         60
+/* Based on grid size 80 * 60 and cell size 16 x 16 */
+#define IPU3_UAPI_AWB_SET_SIZE                         1280
+#define IPU3_UAPI_AWB_MD_ITEM_SIZE                     8
+#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \
+       (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+        IPU3_UAPI_AWB_MD_ITEM_SIZE)
+#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \
+       (IPU3_UAPI_AWB_MAX_SETS * \
+        (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
+
+
+/**
+ * struct ipu3_uapi_awb_raw_buffer - AWB raw buffer
+ *
+ * @meta_data: buffer to hold auto white balance meta data which is
+ *             the average values for each color channel.
+ */
+struct ipu3_uapi_awb_raw_buffer {
+       __u8 meta_data[IPU3_UAPI_AWB_MAX_BUFFER_SIZE]
+               __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_awb_config_s - AWB config
+ *
+ * @rgbs_thr_gr: gr threshold value.
+ * @rgbs_thr_r: Red threshold value.
+ * @rgbs_thr_gb: gb threshold value.
+ * @rgbs_thr_b: Blue threshold value.
+ * @grid: &ipu3_uapi_grid_config, the default grid resolution is 16x16 cells.
+ *
+ * The threshold is a saturation measure range [0, 8191], 8191 is default.
+ * Values over threshold may be optionally rejected for averaging.
+ */
+struct ipu3_uapi_awb_config_s {
+       __u16 rgbs_thr_gr;
+       __u16 rgbs_thr_r;
+       __u16 rgbs_thr_gb;
+       __u16 rgbs_thr_b;
+       struct ipu3_uapi_grid_config grid;
+} __attribute__((aligned(32))) __packed;
+
+/**
+ * struct ipu3_uapi_awb_config - AWB config wrapper
+ *
+ * @config: config for auto white balance as defined by &ipu3_uapi_awb_config_s
+ */
+struct ipu3_uapi_awb_config {
+       struct ipu3_uapi_awb_config_s config __attribute__((aligned(32)));
+} __packed;
+
+#define IPU3_UAPI_AE_COLORS                            4       /* R, G, B, Y */
+#define IPU3_UAPI_AE_BINS                              256
+#define IPU3_UAPI_AE_WEIGHTS                           96
+
+/**
+ + * struct ipu3_uapi_ae_raw_buffer - AE global weighted histogram
+ + *
+ + * @vals: Sum of IPU3_UAPI_AE_COLORS in cell
+ + *
+ + * Each histogram contains IPU3_UAPI_AE_BINS bins. Each bin has 24 bit unsigned
+ + * for counting the number of the pixel.
+ + */
+struct ipu3_uapi_ae_raw_buffer {
+       __u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_ae_raw_buffer_aligned - AE raw buffer
+ *
+ * @buff: &ipu3_uapi_ae_raw_buffer to hold full frame meta data.
+ */
+struct ipu3_uapi_ae_raw_buffer_aligned {
+       struct ipu3_uapi_ae_raw_buffer buff __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_ae_grid_config - AE weight grid
+ *
+ * @width: Grid horizontal dimensions. Value: [16, 32], default 16.
+ * @height: Grid vertical dimensions. Value: [16, 24], default 16.
+ * @block_width_log2: Log2 of the width of the grid cell, value: [3, 7].
+ * @block_height_log2: Log2 of the height of the grid cell, value: [3, 7].
+ *                     default is 3 (cell size 8x8), 4 cell per grid.
+ * @reserved0: reserved
+ * @ae_en: 0: does not write to &ipu3_uapi_ae_raw_buffer_aligned array,
+ *             1: write normally.
+ * @rst_hist_array: write 1 to trigger histogram array reset.
+ * @done_rst_hist_array: flag for histogram array reset done.
+ * @x_start: X value of top left corner of ROI, default 0.
+ * @y_start: Y value of top left corner of ROI, default 0.
+ * @x_end: X value of bottom right corner of ROI
+ * @y_end: Y value of bottom right corner of ROI
+ *
+ * The AE block accumulates 4 global weighted histograms(R, G, B, Y) over
+ * a defined ROI within the frame. The contribution of each pixel into the
+ * histogram, defined by &ipu3_uapi_ae_weight_elem LUT, is indexed by a grid.
+ */
+struct ipu3_uapi_ae_grid_config {
+       __u8 width;
+       __u8 height;
+       __u8 block_width_log2:4;
+       __u8 block_height_log2:4;
+       __u8 reserved0:5;
+       __u8 ae_en:1;
+       __u8 rst_hist_array:1;
+       __u8 done_rst_hist_array:1;
+       __u16 x_start;
+       __u16 y_start;
+       __u16 x_end;
+       __u16 y_end;
+} __packed;
+
+/**
+ * struct ipu3_uapi_ae_weight_elem - AE weights LUT
+ *
+ * @cell0: weighted histogram grid value.
+ * @cell1: weighted histogram grid value.
+ * @cell2: weighted histogram grid value.
+ * @cell3: weighted histogram grid value.
+ * @cell4: weighted histogram grid value.
+ * @cell5: weighted histogram grid value.
+ * @cell6: weighted histogram grid value.
+ * @cell7: weighted histogram grid value.
+ *
+ * Use weighted grid value to give a different contribution factor to each cell.
+ * Precision u4, range [0, 15].
+ */
+struct ipu3_uapi_ae_weight_elem {
+       __u32 cell0:4;
+       __u32 cell1:4;
+       __u32 cell2:4;
+       __u32 cell3:4;
+       __u32 cell4:4;
+       __u32 cell5:4;
+       __u32 cell6:4;
+       __u32 cell7:4;
+} __packed;
+
+/**
+ * struct ipu3_uapi_ae_ccm - AE coefficients for WB and CCM
+ *
+ * @gain_gr: WB gain factor for the gr channels. Default 256.
+ * @gain_r: WB gain factor for the r channel. Default 256.
+ * @gain_b: WB gain factor for the b channel. Default 256.
+ * @gain_gb: WB gain factor for the gb channels. Default 256.
+ * @mat: 4x4 matrix that transforms Bayer quad output from WB to RGB+Y.
+ *
+ * Default:
+ *     128, 0, 0, 0,
+ *     0, 128, 0, 0,
+ *     0, 0, 128, 0,
+ *     0, 0, 0, 128,
+ *
+ * As part of the raw frame pre-process stage, the WB and color conversion need
+ * to be applied to expose the impact of these gain operations.
+ */
+struct ipu3_uapi_ae_ccm {
+       __u16 gain_gr;
+       __u16 gain_r;
+       __u16 gain_b;
+       __u16 gain_gb;
+       __s16 mat[16];
+} __packed;
+
+/**
+ * struct ipu3_uapi_ae_config - AE config
+ *
+ * @grid_cfg:  config for auto exposure statistics grid. See struct
+ *             &ipu3_uapi_ae_grid_config
+ * @weights:   &IPU3_UAPI_AE_WEIGHTS is based on 32x24 blocks in the grid.
+ *             Each grid cell has a corresponding value in weights LUT called
+ *             grid value, global histogram is updated based on grid value and
+ *             pixel value.
+ * @ae_ccm:    Color convert matrix pre-processing block.
+ *
+ * Calculate AE grid from image resolution, resample ae weights.
+ */
+struct ipu3_uapi_ae_config {
+       struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32)));
+       struct ipu3_uapi_ae_weight_elem weights[
+                       IPU3_UAPI_AE_WEIGHTS] __attribute__((aligned(32)));
+       struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_af_filter_config - AF 2D filter for contrast measurements
+ *
+ * @y1_coeff_0:        filter Y1, structure: 3x11, support both symmetry and
+ *             anti-symmetry type. A12 is center, A1-A11 are neighbours.
+ *             for analyzing low frequency content, used to calculate sum
+ *             of gradients in x direction.
+ * @y1_coeff_0.a1:     filter1 coefficients A1, u8, default 0.
+ * @y1_coeff_0.a2:     filter1 coefficients A2, u8, default 0.
+ * @y1_coeff_0.a3:     filter1 coefficients A3, u8, default 0.
+ * @y1_coeff_0.a4:     filter1 coefficients A4, u8, default 0.
+ * @y1_coeff_1:                Struct
+ * @y1_coeff_1.a5:     filter1 coefficients A5, u8, default 0.
+ * @y1_coeff_1.a6:     filter1 coefficients A6, u8, default 0.
+ * @y1_coeff_1.a7:     filter1 coefficients A7, u8, default 0.
+ * @y1_coeff_1.a8:     filter1 coefficients A8, u8, default 0.
+ * @y1_coeff_2:                Struct
+ * @y1_coeff_2.a9:     filter1 coefficients A9, u8, default 0.
+ * @y1_coeff_2.a10:    filter1 coefficients A10, u8, default 0.
+ * @y1_coeff_2.a11:    filter1 coefficients A11, u8, default 0.
+ * @y1_coeff_2.a12:    filter1 coefficients A12, u8, default 128.
+ * @y1_sign_vec:       Each bit corresponds to one coefficient sign bit,
+ *                     0: positive, 1: negative, default 0.
+ * @y2_coeff_0:        Y2, same structure as Y1. For analyzing high frequency content.
+ * @y2_coeff_0.a1:     filter2 coefficients A1, u8, default 0.
+ * @y2_coeff_0.a2:     filter2 coefficients A2, u8, default 0.
+ * @y2_coeff_0.a3:     filter2 coefficients A3, u8, default 0.
+ * @y2_coeff_0.a4:     filter2 coefficients A4, u8, default 0.
+ * @y2_coeff_1:        Struct
+ * @y2_coeff_1.a5:     filter2 coefficients A5, u8, default 0.
+ * @y2_coeff_1.a6:     filter2 coefficients A6, u8, default 0.
+ * @y2_coeff_1.a7:     filter2 coefficients A7, u8, default 0.
+ * @y2_coeff_1.a8:     filter2 coefficients A8, u8, default 0.
+ * @y2_coeff_2:        Struct
+ * @y2_coeff_2.a9:     filter1 coefficients A9, u8, default 0.
+ * @y2_coeff_2.a10:    filter1 coefficients A10, u8, default 0.
+ * @y2_coeff_2.a11:    filter1 coefficients A11, u8, default 0.
+ * @y2_coeff_2.a12:    filter1 coefficients A12, u8, default 128.
+ * @y2_sign_vec:       Each bit corresponds to one coefficient sign bit,
+ *                     0: positive, 1: negative, default 0.
+ * @y_calc:    Pre-processing that converts Bayer quad to RGB+Y values to be
+ *             used for building histogram. Range [0, 32], default 8.
+ * Rule:
+ *             y_gen_rate_gr + y_gen_rate_r + y_gen_rate_b + y_gen_rate_gb = 32
+ *             A single Y is calculated based on sum of Gr/R/B/Gb based on
+ *             their contribution ratio.
+ * @y_calc.y_gen_rate_gr:      Contribution ratio Gr for Y
+ * @y_calc.y_gen_rate_r:       Contribution ratio R for Y
+ * @y_calc.y_gen_rate_b:       Contribution ratio B for Y
+ * @y_calc.y_gen_rate_gb:      Contribution ratio Gb for Y
+ * @nf:        The shift right value that should be applied during the Y1/Y2 filter to
+ *     make sure the total memory needed is 2 bytes per grid cell.
+ * @nf.reserved0:      reserved
+ * @nf.y1_nf:  Normalization factor for the convolution coeffs of y1,
+ *             should be log2 of the sum of the abs values of the filter
+ *             coeffs, default 7 (2^7 = 128).
+ * @nf.reserved1:      reserved
+ * @nf.y2_nf:  Normalization factor for y2, should be log2 of the sum of the
+ *             abs values of the filter coeffs.
+ * @nf.reserved2:      reserved
+ */
+struct ipu3_uapi_af_filter_config {
+       struct {
+               __u8 a1;
+               __u8 a2;
+               __u8 a3;
+               __u8 a4;
+       } y1_coeff_0;
+       struct {
+               __u8 a5;
+               __u8 a6;
+               __u8 a7;
+               __u8 a8;
+       } y1_coeff_1;
+       struct {
+               __u8 a9;
+               __u8 a10;
+               __u8 a11;
+               __u8 a12;
+       } y1_coeff_2;
+
+       __u32 y1_sign_vec;
+
+       struct {
+               __u8 a1;
+               __u8 a2;
+               __u8 a3;
+               __u8 a4;
+       } y2_coeff_0;
+       struct {
+               __u8 a5;
+               __u8 a6;
+               __u8 a7;
+               __u8 a8;
+       } y2_coeff_1;
+       struct {
+               __u8 a9;
+               __u8 a10;
+               __u8 a11;
+               __u8 a12;
+       } y2_coeff_2;
+
+       __u32 y2_sign_vec;
+
+       struct {
+               __u8 y_gen_rate_gr;
+               __u8 y_gen_rate_r;
+               __u8 y_gen_rate_b;
+               __u8 y_gen_rate_gb;
+       } y_calc;
+
+       struct {
+               __u32 reserved0:8;
+               __u32 y1_nf:4;
+               __u32 reserved1:4;
+               __u32 y2_nf:4;
+               __u32 reserved2:12;
+       } nf;
+} __packed;
+
+#define IPU3_UAPI_AF_MAX_SETS                          24
+#define IPU3_UAPI_AF_MD_ITEM_SIZE                      4
+#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \
+       (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+        IPU3_UAPI_AF_MD_ITEM_SIZE)
+#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE                  128
+#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \
+       (IPU3_UAPI_AF_MAX_SETS * \
+        (IPU3_UAPI_AF_Y_TABLE_SET_SIZE + IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \
+        IPU3_UAPI_MAX_STRIPES)
+
+/**
+ * struct ipu3_uapi_af_raw_buffer - AF meta data
+ *
+ * @y_table:   Each color component will be convolved separately with filter1
+ *             and filter2 and the result will be summed out and averaged for
+ *             each cell.
+ */
+struct ipu3_uapi_af_raw_buffer {
+       __u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_af_config_s - AF config
+ *
+ * @filter_config: AF uses Y1 and Y2 filters as configured in
+ *                &ipu3_uapi_af_filter_config
+ * @padding: paddings
+ * @grid_cfg: See &ipu3_uapi_grid_config, default resolution 16x16. Use large
+ *           grid size for large image and vice versa.
+ */
+struct ipu3_uapi_af_config_s {
+       struct ipu3_uapi_af_filter_config filter_config __attribute__((aligned(32)));
+       __u8 padding[4];
+       struct ipu3_uapi_grid_config grid_cfg __attribute__((aligned(32)));
+} __packed;
+
+#define IPU3_UAPI_AWB_FR_MAX_SETS                      24
+#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE                  8
+#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE                        256
+#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \
+       (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+        IPU3_UAPI_AWB_FR_MD_ITEM_SIZE)
+#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \
+       (IPU3_UAPI_AWB_FR_MAX_SETS * \
+       (IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \
+        IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * IPU3_UAPI_MAX_STRIPES)
+
+/**
+ * struct ipu3_uapi_awb_fr_meta_data - AWB filter response meta data
+ *
+ * @meta_data: Statistics output on the grid after convolving with 1D filter.
+ */
+struct ipu3_uapi_awb_fr_raw_buffer {
+       __u8 meta_data[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE]
+               __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_awb_fr_config_s - AWB filter response config
+ *
+ * @grid_cfg:  grid config, default 16x16.
+ * @bayer_coeff:       1D Filter 1x11 center symmetry/anti-symmetry.
+ *                     coeffcients defaults { 0, 0, 0, 0, 0, 128 }.
+ *                     Applied on whole image for each Bayer channel separately
+ *                     by a weighted sum of its 11x1 neighbors.
+ * @reserved1: reserved
+ * @bayer_sign:        sign of filter coeffcients, default 0.
+ * @bayer_nf:  normalization factor for the convolution coeffs, to make sure
+ *             total memory needed is within pre-determined range.
+ *             NF should be the log2 of the sum of the abs values of the
+ *             filter coeffs, range [7, 14], default 7.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_awb_fr_config_s {
+       struct ipu3_uapi_grid_config grid_cfg;
+       __u8 bayer_coeff[6];
+       __u16 reserved1;
+       __u32 bayer_sign;
+       __u8 bayer_nf;
+       __u8 reserved2[3];
+} __attribute__((aligned(32))) __packed;
+
+/**
+ * struct ipu3_uapi_4a_config - 4A config
+ *
+ * @awb_config: &ipu3_uapi_awb_config_s, default resolution 16x16
+ * @ae_grd_config: auto exposure statistics &ipu3_uapi_ae_grid_config
+ * @padding: paddings
+ * @af_config: auto focus config &ipu3_uapi_af_config_s
+ * @awb_fr_config: &ipu3_uapi_awb_fr_config_s, default resolution 16x16
+ */
+struct ipu3_uapi_4a_config {
+       struct ipu3_uapi_awb_config_s awb_config __attribute__((aligned(32)));
+       struct ipu3_uapi_ae_grid_config ae_grd_config;
+       __u8 padding[20];
+       struct ipu3_uapi_af_config_s af_config;
+       struct ipu3_uapi_awb_fr_config_s awb_fr_config;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bubble_info - Bubble info for host side debugging
+ *
+ * @num_of_stripes: A single frame is divided into several parts called stripes
+ *                 due to limitation on line buffer memory.
+ *                 The separation between the stripes is vertical. Each such
+ *                 stripe is processed as a single frame by the ISP pipe.
+ * @padding: padding bytes.
+ * @num_sets: number of sets.
+ * @padding1: padding bytes.
+ * @size_of_set: set size.
+ * @padding2: padding bytes.
+ * @bubble_size: is the amount of padding in the bubble expressed in "sets".
+ * @padding3: padding bytes.
+ */
+struct ipu3_uapi_bubble_info {
+       __u32 num_of_stripes __attribute__((aligned(32)));
+       __u8 padding[28];
+       __u32 num_sets;
+       __u8 padding1[28];
+       __u32 size_of_set;
+       __u8 padding2[28];
+       __u32 bubble_size;
+       __u8 padding3[28];
+} __packed;
+
+/*
+ * struct ipu3_uapi_stats_3a_bubble_info_per_stripe
+ */
+struct ipu3_uapi_stats_3a_bubble_info_per_stripe {
+       struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES];
+       struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES];
+       struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+/**
+ * struct ipu3_uapi_ff_status - Enable bits for each 3A fixed function
+ *
+ * @awb_en: auto white balance enable
+ * @padding: padding config
+ * @ae_en: auto exposure enable
+ * @padding1: padding config
+ * @af_en: auto focus enable
+ * @padding2: padding config
+ * @awb_fr_en: awb filter response enable bit
+ * @padding3: padding config
+ */
+struct ipu3_uapi_ff_status {
+       __u32 awb_en __attribute__((aligned(32)));
+       __u8 padding[28];
+       __u32 ae_en;
+       __u8 padding1[28];
+       __u32 af_en;
+       __u8 padding2[28];
+       __u32 awb_fr_en;
+       __u8 padding3[28];
+} __packed;
+
+/**
+ * struct ipu3_uapi_stats_3a - 3A statistics
+ *
+ * @awb_raw_buffer: auto white balance meta data &ipu3_uapi_awb_raw_buffer
+ * @ae_raw_buffer: auto exposure raw data &ipu3_uapi_ae_raw_buffer_aligned
+ * @af_raw_buffer: &ipu3_uapi_af_raw_buffer for auto focus meta data
+ * @awb_fr_raw_buffer: value as specified by &ipu3_uapi_awb_fr_raw_buffer
+ * @stats_4a_config: 4a statistics config as defined by &ipu3_uapi_4a_config.
+ * @ae_join_buffers: 1 to use ae_raw_buffer.
+ * @padding: padding config
+ * @stats_3a_bubble_per_stripe: a &ipu3_uapi_stats_3a_bubble_info_per_stripe
+ * @stats_3a_status: 3a statistics status set in &ipu3_uapi_ff_status
+ */
+struct ipu3_uapi_stats_3a {
+       struct ipu3_uapi_awb_raw_buffer awb_raw_buffer;
+       struct ipu3_uapi_ae_raw_buffer_aligned
+                       ae_raw_buffer[IPU3_UAPI_MAX_STRIPES];
+       struct ipu3_uapi_af_raw_buffer af_raw_buffer;
+       struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer;
+       struct ipu3_uapi_4a_config stats_4a_config;
+       __u32 ae_join_buffers;
+       __u8 padding[28];
+       struct ipu3_uapi_stats_3a_bubble_info_per_stripe
+                       stats_3a_bubble_per_stripe;
+       struct ipu3_uapi_ff_status stats_3a_status;
+} __packed;
+
+/******************* ipu3_uapi_acc_param *******************/
+
+#define IPU3_UAPI_ISP_VEC_ELEMS                                64
+#define IPU3_UAPI_ISP_TNR3_VMEM_LEN                    9
+
+#define IPU3_UAPI_BNR_LUT_SIZE                         32
+
+/* number of elements in gamma correction LUT */
+#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES               256
+
+/* largest grid is 73x56, for grid_height_per_slice of 2, 73x2 = 146 */
+#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET                        146
+#define IPU3_UAPI_SHD_MAX_CFG_SETS                     28
+/* Normalization shift aka nf */
+#define IPU3_UAPI_SHD_BLGR_NF_SHIFT                    13
+#define IPU3_UAPI_SHD_BLGR_NF_MASK                     7
+
+#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS                16
+#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS         14
+#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS     258
+#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS         24
+
+#define IPU3_UAPI_ANR_LUT_SIZE                         26
+#define IPU3_UAPI_ANR_PYRAMID_SIZE                     22
+
+#define IPU3_UAPI_LIN_LUT_SIZE                         64
+
+/* Bayer Noise Reduction related structs */
+
+/**
+ * struct ipu3_uapi_bnr_static_config_wb_gains_config - White balance gains
+ *
+ * @gr:        white balance gain for Gr channel.
+ * @r: white balance gain for R channel.
+ * @b: white balance gain for B channel.
+ * @gb:        white balance gain for Gb channel.
+ *
+ * Precision u3.13, range [0, 8). White balance correction is done by applying
+ * a multiplicative gain to each color channels prior to BNR.
+ */
+struct ipu3_uapi_bnr_static_config_wb_gains_config {
+       __u16 gr;
+       __u16 r;
+       __u16 b;
+       __u16 gb;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_wb_gains_thr_config - Threshold config
+ *
+ * @gr:        white balance threshold gain for Gr channel.
+ * @r: white balance threshold gain for R channel.
+ * @b: white balance threshold gain for B channel.
+ * @gb:        white balance threshold gain for Gb channel.
+ *
+ * Defines the threshold that specifies how different a defect pixel can be from
+ * its neighbors.(used by dynamic defect pixel correction sub block)
+ * Precision u4.4 range [0, 8].
+ */
+struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
+       __u8 gr;
+       __u8 r;
+       __u8 b;
+       __u8 gb;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_thr_coeffs_config - Noise model
+ *                             coefficients that controls noise threshold
+ *
+ * @cf:        Free coefficient for threshold calculation, range [0, 8191], default 0.
+ * @reserved0: reserved
+ * @cg:        Gain coefficient for threshold calculation, [0, 31], default 8.
+ * @ci:        Intensity coefficient for threshold calculation. range [0, 0x1f]
+ *     default 6.
+ *     format: u3.2 (3 most significant bits represent whole number,
+ *     2 least significant bits represent the fractional part
+ *     with each count representing 0.25)
+ *     e.g. 6 in binary format is 00110, that translates to 1.5
+ * @reserved1: reserved
+ * @r_nf:      Normalization shift value for r^2 calculation, range [12, 20]
+ *             where r is a radius of pixel [row, col] from centor of sensor.
+ *             default 14.
+ *
+ * Threshold used to distinguish between noise and details.
+ */
+struct ipu3_uapi_bnr_static_config_thr_coeffs_config {
+       __u32 cf:13;
+       __u32 reserved0:3;
+       __u32 cg:5;
+       __u32 ci:5;
+       __u32 reserved1:1;
+       __u32 r_nf:5;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config - Shading config
+ *
+ * @gr:        Coefficient defines lens shading gain approximation for gr channel
+ * @r: Coefficient defines lens shading gain approximation for r channel
+ * @b: Coefficient defines lens shading gain approximation for b channel
+ * @gb:        Coefficient defines lens shading gain approximation for gb channel
+ *
+ * Parameters for noise model (NM) adaptation of BNR due to shading correction.
+ * All above have precision of u3.3, default to 0.
+ */
+struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config {
+       __u8 gr;
+       __u8 r;
+       __u8 b;
+       __u8 gb;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_opt_center_config - Optical center config
+ *
+ * @x_reset:   Reset value of X (col start - X center). Precision s12.0.
+ * @reserved0: reserved
+ * @y_reset:   Reset value of Y (row start - Y center). Precision s12.0.
+ * @reserved2: reserved
+ *
+ * Distance from corner to optical center for NM adaptation due to shading
+ * correction (should be calculated based on shading tables)
+ */
+struct ipu3_uapi_bnr_static_config_opt_center_config {
+       __s32 x_reset:13;
+       __u32 reserved0:3;
+       __s32 y_reset:13;
+       __u32 reserved2:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_lut_config - BNR square root lookup table
+ *
+ * @values: pre-calculated values of square root function.
+ *
+ * LUT implementation of square root operation.
+ */
+struct ipu3_uapi_bnr_static_config_lut_config {
+       __u8 values[IPU3_UAPI_BNR_LUT_SIZE];
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_bp_ctrl_config - Detect bad pixels (bp)
+ *
+ * @bp_thr_gain:       Defines the threshold that specifies how different a
+ *                     defect pixel can be from its neighbors. Threshold is
+ *                     dependent on de-noise threshold calculated by algorithm.
+ *                     Range [4, 31], default 4.
+ * @reserved0: reserved
+ * @defect_mode:       Mode of addressed defect pixels,
+ *                     0 - single defect pixel is expected,
+ *                     1 - 2 adjacent defect pixels are expected, default 1.
+ * @bp_gain:   Defines how 2nd derivation that passes through a defect pixel
+ *             is different from 2nd derivations that pass through
+ *             neighbor pixels. u4.2, range [0, 256], default 8.
+ * @reserved1: reserved
+ * @w0_coeff:  Blending coefficient of defect pixel correction.
+ *             Precision u4, range [0, 8], default 8.
+ * @reserved2: reserved
+ * @w1_coeff:  Enable influence of incorrect defect pixel correction to be
+ *             avoided. Precision u4, range [1, 8], default 8.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_bnr_static_config_bp_ctrl_config {
+       __u32 bp_thr_gain:5;
+       __u32 reserved0:2;
+       __u32 defect_mode:1;
+       __u32 bp_gain:6;
+       __u32 reserved1:18;
+       __u32 w0_coeff:4;
+       __u32 reserved2:4;
+       __u32 w1_coeff:4;
+       __u32 reserved3:20;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config - Denoising config
+ *
+ * @alpha:     Weight of central element of smoothing filter.
+ * @beta:      Weight of peripheral elements of smoothing filter, default 4.
+ * @gamma:     Weight of diagonal elements of smoothing filter, default 4.
+ *
+ * beta and gamma parameter define the strength of the noise removal filter.
+ *             All above has precision u0.4, range [0, 0xf]
+ *             format: u0.4 (no / zero bits represent whole number,
+ *             4 bits represent the fractional part
+ *             with each count representing 0.0625)
+ *             e.g. 0xf translates to 0.0625x15 = 0.9375
+ *
+ * @reserved0: reserved
+ * @max_inf:   Maximum increase of peripheral or diagonal element influence
+ *             relative to the pre-defined value range: [0x5, 0xa]
+ * @reserved1: reserved
+ * @gd_enable: Green disparity enable control, 0 - disable, 1 - enable.
+ * @bpc_enable:        Bad pixel correction enable control, 0 - disable, 1 - enable.
+ * @bnr_enable:        Bayer noise removal enable control, 0 - disable, 1 - enable.
+ * @ff_enable: Fixed function enable, 0 - disable, 1 - enable.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config {
+       __u32 alpha:4;
+       __u32 beta:4;
+       __u32 gamma:4;
+       __u32 reserved0:4;
+       __u32 max_inf:4;
+       __u32 reserved1:7;
+       __u32 gd_enable:1;
+       __u32 bpc_enable:1;
+       __u32 bnr_enable:1;
+       __u32 ff_enable:1;
+       __u32 reserved2:1;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_opt_center_sqr_config - BNR optical square
+ *
+ * @x_sqr_reset: Reset value of X^2.
+ * @y_sqr_reset: Reset value of Y^2.
+ *
+ * Please note:
+ *
+ *    #. X and Y ref to
+ *       &ipu3_uapi_bnr_static_config_opt_center_config
+ *    #. Both structs are used in threshold formula to calculate r^2, where r
+ *       is a radius of pixel [row, col] from centor of sensor.
+ */
+struct ipu3_uapi_bnr_static_config_opt_center_sqr_config {
+       __u32 x_sqr_reset;
+       __u32 y_sqr_reset;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config - BNR static config
+ *
+ * @wb_gains:  white balance gains &ipu3_uapi_bnr_static_config_wb_gains_config
+ * @wb_gains_thr:      white balance gains threshold as defined by
+ *                     &ipu3_uapi_bnr_static_config_wb_gains_thr_config
+ * @thr_coeffs:        coefficients of threshold
+ *             &ipu3_uapi_bnr_static_config_thr_coeffs_config
+ * @thr_ctrl_shd:      control of shading threshold
+ *                     &ipu3_uapi_bnr_static_config_thr_ctrl_shd_config
+ * @opt_center:        optical center &ipu3_uapi_bnr_static_config_opt_center_config
+ *
+ * Above parameters and opt_center_sqr are used for white balance and shading.
+ *
+ * @lut:       lookup table &ipu3_uapi_bnr_static_config_lut_config
+ * @bp_ctrl:   detect and remove bad pixels as defined in struct
+ *             &ipu3_uapi_bnr_static_config_bp_ctrl_config
+ * @dn_detect_ctrl:    detect and remove noise.
+ *                     &ipu3_uapi_bnr_static_config_dn_detect_ctrl_config
+ * @column_size:       The number of pixels in column.
+ * @opt_center_sqr:    Reset value of r^2 to optical center, see
+ *                     &ipu3_uapi_bnr_static_config_opt_center_sqr_config.
+ */
+struct ipu3_uapi_bnr_static_config {
+       struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains;
+       struct ipu3_uapi_bnr_static_config_wb_gains_thr_config wb_gains_thr;
+       struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs;
+       struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd;
+       struct ipu3_uapi_bnr_static_config_opt_center_config opt_center;
+       struct ipu3_uapi_bnr_static_config_lut_config lut;
+       struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl;
+       struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config dn_detect_ctrl;
+       __u32 column_size;
+       struct ipu3_uapi_bnr_static_config_opt_center_sqr_config opt_center_sqr;
+} __packed;
+
+/**
+ * struct ipu3_uapi_bnr_static_config_green_disparity - Correct green disparity
+ *
+ * @gd_red:    Shading gain coeff for gr disparity level in bright red region.
+ *             Precision u0.6, default 4(0.0625).
+ * @reserved0: reserved
+ * @gd_green:  Shading gain coeff for gr disparity level in bright green
+ *             region. Precision u0.6, default 4(0.0625).
+ * @reserved1: reserved
+ * @gd_blue:   Shading gain coeff for gr disparity level in bright blue region.
+ *             Precision u0.6, default 4(0.0625).
+ * @reserved2: reserved
+ * @gd_black:  Maximal green disparity level in dark region (stronger disparity
+ *             assumed to be image detail). Precision u14, default 80.
+ * @reserved3: reserved
+ * @gd_shading:        Change maximal green disparity level according to square
+ *             distance from image center.
+ * @reserved4: reserved
+ * @gd_support:        Lower bound for the number of second green color pixels in
+ *             current pixel neighborhood with less than threshold difference
+ *             from it.
+ *
+ * The shading gain coeff of red, green, blue and black are used to calculate
+ * threshold given a pixel's color value and its coordinates in the image.
+ *
+ * @reserved5: reserved
+ * @gd_clip:   Turn green disparity clip on/off, [0, 1], default 1.
+ * @gd_central_weight: Central pixel weight in 9 pixels weighted sum.
+ */
+struct ipu3_uapi_bnr_static_config_green_disparity {
+       __u32 gd_red:6;
+       __u32 reserved0:2;
+       __u32 gd_green:6;
+       __u32 reserved1:2;
+       __u32 gd_blue:6;
+       __u32 reserved2:10;
+       __u32 gd_black:14;
+       __u32 reserved3:2;
+       __u32 gd_shading:7;
+       __u32 reserved4:1;
+       __u32 gd_support:2;
+       __u32 reserved5:1;
+       __u32 gd_clip:1;
+       __u32 gd_central_weight:4;
+} __packed;
+
+/**
+ * struct ipu3_uapi_dm_config - De-mosaic parameters
+ *
+ * @dm_en:     de-mosaic enable.
+ * @ch_ar_en:  Checker artifacts removal enable flag. Default 0.
+ * @fcc_en:    False color correction (FCC) enable flag. Default 0.
+ * @reserved0: reserved
+ * @frame_width:       do not care
+ * @gamma_sc:  Sharpening coefficient (coefficient of 2-d derivation of
+ *             complementary color in Hamilton-Adams interpolation).
+ *             u5, range [0, 31], default 8.
+ * @reserved1: reserved
+ * @lc_ctrl:   Parameter that controls weights of Chroma Homogeneity metric
+ *             in calculation of final homogeneity metric.
+ *             u5, range [0, 31], default 7.
+ * @reserved2: reserved
+ * @cr_param1: First parameter that defines Checker artifact removal
+ *             feature gain. Precision u5, range [0, 31], default 8.
+ * @reserved3: reserved
+ * @cr_param2: Second parameter that defines Checker artifact removal
+ *             feature gain. Precision u5, range [0, 31], default 8.
+ * @reserved4: reserved
+ * @coring_param:      Defines power of false color correction operation.
+ *                     low for preserving edge colors, high for preserving gray
+ *                     edge artifacts.
+ *                     Precision u1.4, range [0, 1.9375], default 4 (0.25).
+ * @reserved5: reserved
+ *
+ * The demosaic fixed function block is responsible to covert Bayer(mosaiced)
+ * images into color images based on demosaicing algorithm.
+ */
+struct ipu3_uapi_dm_config {
+       __u32 dm_en:1;
+       __u32 ch_ar_en:1;
+       __u32 fcc_en:1;
+       __u32 reserved0:13;
+       __u32 frame_width:16;
+
+       __u32 gamma_sc:5;
+       __u32 reserved1:3;
+       __u32 lc_ctrl:5;
+       __u32 reserved2:3;
+       __u32 cr_param1:5;
+       __u32 reserved3:3;
+       __u32 cr_param2:5;
+       __u32 reserved4:3;
+
+       __u32 coring_param:5;
+       __u32 reserved5:27;
+} __packed;
+
+/**
+ * struct ipu3_uapi_ccm_mat_config - Color correction matrix
+ *
+ * @coeff_m11: CCM 3x3 coefficient, range [-65536, 65535]
+ * @coeff_m12: CCM 3x3 coefficient, range [-8192, 8191]
+ * @coeff_m13: CCM 3x3 coefficient, range [-32768, 32767]
+ * @coeff_o_r: Bias 3x1 coefficient, range [-8191, 8181]
+ * @coeff_m21: CCM 3x3 coefficient, range [-32767, 32767]
+ * @coeff_m22: CCM 3x3 coefficient, range [-8192, 8191]
+ * @coeff_m23: CCM 3x3 coefficient, range [-32768, 32767]
+ * @coeff_o_g: Bias 3x1 coefficient, range [-8191, 8181]
+ * @coeff_m31: CCM 3x3 coefficient, range [-32768, 32767]
+ * @coeff_m32: CCM 3x3 coefficient, range [-8192, 8191]
+ * @coeff_m33: CCM 3x3 coefficient, range [-32768, 32767]
+ * @coeff_o_b: Bias 3x1 coefficient, range [-8191, 8181]
+ *
+ * Transform sensor specific color space to standard sRGB by applying 3x3 matrix
+ * and adding a bias vector O. The transformation is basically a rotation and
+ * translation in the 3-dimensional color spaces. Here are the defaults:
+ *
+ *     9775,   -2671,  1087,   0
+ *     -1071,  8303,   815,    0
+ *     -23,    -7887,  16103,  0
+ */
+struct ipu3_uapi_ccm_mat_config {
+       __s16 coeff_m11;
+       __s16 coeff_m12;
+       __s16 coeff_m13;
+       __s16 coeff_o_r;
+       __s16 coeff_m21;
+       __s16 coeff_m22;
+       __s16 coeff_m23;
+       __s16 coeff_o_g;
+       __s16 coeff_m31;
+       __s16 coeff_m32;
+       __s16 coeff_m33;
+       __s16 coeff_o_b;
+} __packed;
+
+/**
+ * struct ipu3_uapi_gamma_corr_ctrl - Gamma correction
+ *
+ * @enable: gamma correction enable.
+ * @reserved: reserved
+ */
+struct ipu3_uapi_gamma_corr_ctrl {
+       __u32 enable:1;
+       __u32 reserved:31;
+} __packed;
+
+/**
+ * struct ipu3_uapi_gamma_corr_lut - Per-pixel tone mapping implemented as LUT.
+ *
+ * @lut:       256 tabulated values of the gamma function. LUT[1].. LUT[256]
+ *             format u13.0, range [0, 8191].
+ *
+ * The tone mapping operation is done by a Piece wise linear graph
+ * that is implemented as a lookup table(LUT). The pixel component input
+ * intensity is the X-axis of the graph which is the table entry.
+ */
+struct ipu3_uapi_gamma_corr_lut {
+       __u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES];
+} __packed;
+
+/**
+ * struct ipu3_uapi_gamma_config - Gamma config
+ *
+ * @gc_ctrl: control of gamma correction &ipu3_uapi_gamma_corr_ctrl
+ * @gc_lut: lookup table of gamma correction &ipu3_uapi_gamma_corr_lut
+ */
+struct ipu3_uapi_gamma_config {
+       struct ipu3_uapi_gamma_corr_ctrl gc_ctrl __attribute__((aligned(32)));
+       struct ipu3_uapi_gamma_corr_lut gc_lut __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_csc_mat_config - Color space conversion matrix config
+ *
+ * @coeff_c11: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_c12: Conversion matrix value, format s0.14, range [-8192, 8191].
+ * @coeff_c13: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_b1:  Bias 3x1 coefficient, s13.0 range [-8192, 8191].
+ * @coeff_c21: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_c22: Conversion matrix value, format s0.14, range [-8192, 8191].
+ * @coeff_c23: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_b2:  Bias 3x1 coefficient, s13.0 range [-8192, 8191].
+ * @coeff_c31: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_c32: Conversion matrix value, format s0.14, range [-8192, 8191].
+ * @coeff_c33: Conversion matrix value, format s0.14, range [-16384, 16383].
+ * @coeff_b3:  Bias 3x1 coefficient, s13.0 range [-8192, 8191].
+ *
+ * To transform each pixel from RGB to YUV (Y - brightness/luminance,
+ * UV -chroma) by applying the pixel's values by a 3x3 matrix and adding an
+ * optional bias 3x1 vector. Here are the default values for the matrix:
+ *
+ *     4898,   9617,  1867, 0,
+ *     -2410, -4732,  7143, 0,
+ *     10076, -8437, -1638, 0,
+ *
+ *     (i.e. for real number 0.299, 0.299 * 2^14 becomes 4898.)
+ */
+struct ipu3_uapi_csc_mat_config {
+       __s16 coeff_c11;
+       __s16 coeff_c12;
+       __s16 coeff_c13;
+       __s16 coeff_b1;
+       __s16 coeff_c21;
+       __s16 coeff_c22;
+       __s16 coeff_c23;
+       __s16 coeff_b2;
+       __s16 coeff_c31;
+       __s16 coeff_c32;
+       __s16 coeff_c33;
+       __s16 coeff_b3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_cds_params - Chroma down-scaling
+ *
+ * @ds_c00:    range [0, 3]
+ * @ds_c01:    range [0, 3]
+ * @ds_c02:    range [0, 3]
+ * @ds_c03:    range [0, 3]
+ * @ds_c10:    range [0, 3]
+ * @ds_c11:    range [0, 3]
+ * @ds_c12:    range [0, 3]
+ * @ds_c13:    range [0, 3]
+ *
+ * In case user does not provide, above 4x2 filter will use following defaults:
+ *     1, 3, 3, 1,
+ *     1, 3, 3, 1,
+ *
+ * @ds_nf:     Normalization factor for Chroma output downscaling filter,
+ *             range 0,4, default 2.
+ * @reserved0: reserved
+ * @csc_en:    Color space conversion enable
+ * @uv_bin_output:     0: output YUV 4.2.0, 1: output YUV 4.2.2(default).
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_cds_params {
+       __u32 ds_c00:2;
+       __u32 ds_c01:2;
+       __u32 ds_c02:2;
+       __u32 ds_c03:2;
+       __u32 ds_c10:2;
+       __u32 ds_c11:2;
+       __u32 ds_c12:2;
+       __u32 ds_c13:2;
+       __u32 ds_nf:5;
+       __u32 reserved0:3;
+       __u32 csc_en:1;
+       __u32 uv_bin_output:1;
+       __u32 reserved1:6;
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_grid_config - Bayer shading(darkening) correction
+ *
+ * @width:     Grid horizontal dimensions, u8, [8, 128], default 73
+ * @height:    Grid vertical dimensions, u8, [8, 128], default 56
+ * @block_width_log2:  Log2 of the width of the grid cell in pixel count
+ *                     u4, [0, 15], default value 5.
+ * @reserved0: reserved
+ * @block_height_log2: Log2 of the height of the grid cell in pixel count
+ *                     u4, [0, 15], default value 6.
+ * @reserved1: reserved
+ * @grid_height_per_slice:     SHD_MAX_CELLS_PER_SET/width.
+ *                             (with SHD_MAX_CELLS_PER_SET = 146).
+ * @x_start:   X value of top left corner of sensor relative to ROI
+ *             s13, [-4096, 0], default 0, only negative values.
+ * @y_start:   Y value of top left corner of sensor relative to ROI
+ *             s13, [-4096, 0], default 0, only negative values.
+ */
+struct ipu3_uapi_shd_grid_config {
+       /* reg 0 */
+       __u8 width;
+       __u8 height;
+       __u8 block_width_log2:3;
+       __u8 reserved0:1;
+       __u8 block_height_log2:3;
+       __u8 reserved1:1;
+       __u8 grid_height_per_slice;
+       /* reg 1 */
+       __s16 x_start;
+       __s16 y_start;
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_general_config - Shading general config
+ *
+ * @init_set_vrt_offst_ul: set vertical offset,
+ *                     y_start >> block_height_log2 % grid_height_per_slice.
+ * @shd_enable: shading enable.
+ * @gain_factor: Gain factor. Shift calculated anti shading value. Precision u2.
+ *             0x0 - gain factor [1, 5], means no shift interpolated value.
+ *             0x1 - gain factor [1, 9], means shift interpolated by 1.
+ *             0x2 - gain factor [1, 17], means shift interpolated by 2.
+ * @reserved: reserved
+ *
+ * Correction is performed by multiplying a gain factor for each of the 4 Bayer
+ * channels as a function of the pixel location in the sensor.
+ */
+struct ipu3_uapi_shd_general_config {
+       __u32 init_set_vrt_offst_ul:8;
+       __u32 shd_enable:1;
+       __u32 gain_factor:2;
+       __u32 reserved:21;
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_black_level_config - Black level correction
+ *
+ * @bl_r:      Bios values for green red. s11 range [-2048, 2047].
+ * @bl_gr:     Bios values for green blue. s11 range [-2048, 2047].
+ * @bl_gb:     Bios values for red. s11 range [-2048, 2047].
+ * @bl_b:      Bios values for blue. s11 range [-2048, 2047].
+ */
+struct ipu3_uapi_shd_black_level_config {
+       __s16 bl_r;
+       __s16 bl_gr;
+       __s16 bl_gb;
+       __s16 bl_b;
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_config_static - Shading config static
+ *
+ * @grid:      shading grid config &ipu3_uapi_shd_grid_config
+ * @general:   shading general config &ipu3_uapi_shd_general_config
+ * @black_level:       black level config for shading correction as defined by
+ *                     &ipu3_uapi_shd_black_level_config
+ */
+struct ipu3_uapi_shd_config_static {
+       struct ipu3_uapi_shd_grid_config grid;
+       struct ipu3_uapi_shd_general_config general;
+       struct ipu3_uapi_shd_black_level_config black_level;
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_lut - Shading gain factor lookup table.
+ *
+ * @sets: array
+ * @sets.r_and_gr: Red and GreenR Lookup table.
+ * @sets.r_and_gr.r: Red shading factor.
+ * @sets.r_and_gr.gr: GreenR shading factor.
+ * @sets.reserved1: reserved
+ * @sets.gb_and_b: GreenB and Blue Lookup table.
+ * @sets.gb_and_b.gb: GreenB shading factor.
+ * @sets.gb_and_b.b: Blue shading factor.
+ * @sets.reserved2: reserved
+ *
+ * Map to shading correction LUT register set.
+ */
+struct ipu3_uapi_shd_lut {
+       struct {
+               struct {
+                       __u16 r;
+                       __u16 gr;
+               } r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
+               __u8 reserved1[24];
+               struct {
+                       __u16 gb;
+                       __u16 b;
+               } gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
+               __u8 reserved2[24];
+       } sets[IPU3_UAPI_SHD_MAX_CFG_SETS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_shd_config - Shading config
+ *
+ * @shd:       shading static config, see &ipu3_uapi_shd_config_static
+ * @shd_lut:   shading lookup table &ipu3_uapi_shd_lut
+ */
+struct ipu3_uapi_shd_config {
+       struct ipu3_uapi_shd_config_static shd __attribute__((aligned(32)));
+       struct ipu3_uapi_shd_lut shd_lut __attribute__((aligned(32)));
+} __packed;
+
+/* Image Enhancement Filter directed */
+
+/**
+ * struct ipu3_uapi_iefd_cux2 - IEFd Config Unit 2 parameters
+ *
+ * @x0:                X0 point of Config Unit, u9.0, default 0.
+ * @x1:                X1 point of Config Unit, u9.0, default 0.
+ * @a01:       Slope A of Config Unit, s4.4, default 0.
+ * @b01:       Slope B, always 0.
+ *
+ * Calculate weight for blending directed and non-directed denoise elements
+ *
+ * Note:
+ * Each instance of Config Unit needs X coordinate of n points and
+ * slope A factor between points calculated by driver based on calibration
+ * parameters.
+ *
+ * All CU inputs are unsigned, they will be converted to signed when written
+ * to register, i.e. a01 will be written to 9 bit register in s4.4 format.
+ * This applies to &ipu3_uapi_iefd_cux6_ed, &ipu3_uapi_iefd_cux2_1,
+ * &ipu3_uapi_iefd_cux2_1, &ipu3_uapi_iefd_cux4 and &ipu3_uapi_iefd_cux6_rad.
+ */
+struct ipu3_uapi_iefd_cux2 {
+       __u32 x0:9;
+       __u32 x1:9;
+       __u32 a01:9;
+       __u32 b01:5;
+} __packed;
+
+/**
+ * struct ipu3_uapi_iefd_cux6_ed - Calculate power of non-directed sharpening
+ *                                element, Config Unit 6 for edge detail (ED).
+ *
+ * @x0:        X coordinate of point 0, u9.0, default 0.
+ * @x1:        X coordinate of point 1, u9.0, default 0.
+ * @x2:        X coordinate of point 2, u9.0, default 0.
+ * @reserved0: reserved
+ * @x3:        X coordinate of point 3, u9.0, default 0.
+ * @x4:        X coordinate of point 4, u9.0, default 0.
+ * @x5:        X coordinate of point 5, u9.0, default 0.
+ * @reserved1: reserved
+ * @a01:       slope A points 01, s4.4, default 0.
+ * @a12:       slope A points 12, s4.4, default 0.
+ * @a23:       slope A points 23, s4.4, default 0.
+ * @reserved2: reserved
+ * @a34:       slope A points 34, s4.4, default 0.
+ * @a45:       slope A points 45, s4.4, default 0.
+ * @reserved3: reserved
+ * @b01:       slope B points 01, s4.4, default 0.
+ * @b12:       slope B points 12, s4.4, default 0.
+ * @b23:       slope B points 23, s4.4, default 0.
+ * @reserved4: reserved
+ * @b34:       slope B points 34, s4.4, default 0.
+ * @b45:       slope B points 45, s4.4, default 0.
+ * @reserved5: reserved.
+ */
+struct ipu3_uapi_iefd_cux6_ed {
+       __u32 x0:9;
+       __u32 x1:9;
+       __u32 x2:9;
+       __u32 reserved0:5;
+
+       __u32 x3:9;
+       __u32 x4:9;
+       __u32 x5:9;
+       __u32 reserved1:5;
+
+       __u32 a01:9;
+       __u32 a12:9;
+       __u32 a23:9;
+       __u32 reserved2:5;
+
+       __u32 a34:9;
+       __u32 a45:9;
+       __u32 reserved3:14;
+
+       __u32 b01:9;
+       __u32 b12:9;
+       __u32 b23:9;
+       __u32 reserved4:5;
+
+       __u32 b34:9;
+       __u32 b45:9;
+       __u32 reserved5:14;
+} __packed;
+
+/**
+ * struct ipu3_uapi_iefd_cux2_1 - Calculate power of non-directed denoise
+ *                               element apply.
+ * @x0: X0 point of Config Unit, u9.0, default 0.
+ * @x1: X1 point of Config Unit, u9.0, default 0.
+ * @a01: Slope A of Config Unit, s4.4, default 0.
+ * @reserved1: reserved
+ * @b01: offset B0 of Config Unit, u7.0, default 0.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_iefd_cux2_1 {
+       __u32 x0:9;
+       __u32 x1:9;
+       __u32 a01:9;
+       __u32 reserved1:5;
+
+       __u32 b01:8;
+       __u32 reserved2:24;
+} __packed;
+
+/**
+ * struct ipu3_uapi_iefd_cux4 - Calculate power of non-directed sharpening
+ *                             element.
+ *
+ * @x0:        X0 point of Config Unit, u9.0, default 0.
+ * @x1:        X1 point of Config Unit, u9.0, default 0.
+ * @x2:        X2 point of Config Unit, u9.0, default 0.
+ * @reserved0: reserved
+ * @x3:        X3 point of Config Unit, u9.0, default 0.
+ * @a01:       Slope A0 of Config Unit, s4.4, default 0.
+ * @a12:       Slope A1 of Config Unit, s4.4, default 0.
+ * @reserved1: reserved
+ * @a23:       Slope A2 of Config Unit, s4.4, default 0.
+ * @b01:       Offset B0 of Config Unit, s7.0, default 0.
+ * @b12:       Offset B1 of Config Unit, s7.0, default 0.
+ * @reserved2: reserved
+ * @b23:       Offset B2 of Config Unit, s7.0, default 0.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_iefd_cux4 {
+       __u32 x0:9;
+       __u32 x1:9;
+       __u32 x2:9;
+       __u32 reserved0:5;
+
+       __u32 x3:9;
+       __u32 a01:9;
+       __u32 a12:9;
+       __u32 reserved1:5;
+
+       __u32 a23:9;
+       __u32 b01:8;
+       __u32 b12:8;
+       __u32 reserved2:7;
+
+       __u32 b23:8;
+       __u32 reserved3:24;
+} __packed;
+
+/**
+ * struct ipu3_uapi_iefd_cux6_rad - Radial Config Unit (CU)
+ *
+ * @x0:        x0 points of Config Unit radial, u8.0
+ * @x1:        x1 points of Config Unit radial, u8.0
+ * @x2:        x2 points of Config Unit radial, u8.0
+ * @x3:        x3 points of Config Unit radial, u8.0
+ * @x4:        x4 points of Config Unit radial, u8.0
+ * @x5:        x5 points of Config Unit radial, u8.0
+ * @reserved1: reserved
+ * @a01:       Slope A of Config Unit radial, s7.8
+ * @a12:       Slope A of Config Unit radial, s7.8
+ * @a23:       Slope A of Config Unit radial, s7.8
+ * @a34:       Slope A of Config Unit radial, s7.8
+ * @a45:       Slope A of Config Unit radial, s7.8
+ * @reserved2: reserved
+ * @b01:       Slope B of Config Unit radial, s9.0
+ * @b12:       Slope B of Config Unit radial, s9.0
+ * @b23:       Slope B of Config Unit radial, s9.0
+ * @reserved4: reserved
+ * @b34:       Slope B of Config Unit radial, s9.0
+ * @b45:       Slope B of Config Unit radial, s9.0
+ * @reserved5: reserved
+ */
+struct ipu3_uapi_iefd_cux6_rad {
+       __u32 x0:8;
+       __u32 x1:8;
+       __u32 x2:8;
+       __u32 x3:8;
+
+       __u32 x4:8;
+       __u32 x5:8;
+       __u32 reserved1:16;
+
+       __u32 a01:16;
+       __u32 a12:16;
+
+       __u32 a23:16;
+       __u32 a34:16;
+
+       __u32 a45:16;
+       __u32 reserved2:16;
+
+       __u32 b01:10;
+       __u32 b12:10;
+       __u32 b23:10;
+       __u32 reserved4:2;
+
+       __u32 b34:10;
+       __u32 b45:10;
+       __u32 reserved5:12;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_cfg_units - IEFd Config Units parameters
+ *
+ * @cu_1: calculate weight for blending directed and
+ *       non-directed denoise elements. See &ipu3_uapi_iefd_cux2
+ * @cu_ed: calculate power of non-directed sharpening element, see
+ *        &ipu3_uapi_iefd_cux6_ed
+ * @cu_3: calculate weight for blending directed and
+ *       non-directed denoise elements. A &ipu3_uapi_iefd_cux2
+ * @cu_5: calculate power of non-directed denoise element apply, use
+ *       &ipu3_uapi_iefd_cux2_1
+ * @cu_6: calculate power of non-directed sharpening element. See
+ *       &ipu3_uapi_iefd_cux4
+ * @cu_7: calculate weight for blending directed and
+ *       non-directed denoise elements. Use &ipu3_uapi_iefd_cux2
+ * @cu_unsharp: Config Unit of unsharp &ipu3_uapi_iefd_cux4
+ * @cu_radial: Config Unit of radial &ipu3_uapi_iefd_cux6_rad
+ * @cu_vssnlm: Config Unit of vssnlm &ipu3_uapi_iefd_cux2
+ */
+struct ipu3_uapi_yuvp1_iefd_cfg_units {
+       struct ipu3_uapi_iefd_cux2 cu_1;
+       struct ipu3_uapi_iefd_cux6_ed cu_ed;
+       struct ipu3_uapi_iefd_cux2 cu_3;
+       struct ipu3_uapi_iefd_cux2_1 cu_5;
+       struct ipu3_uapi_iefd_cux4 cu_6;
+       struct ipu3_uapi_iefd_cux2 cu_7;
+       struct ipu3_uapi_iefd_cux4 cu_unsharp;
+       struct ipu3_uapi_iefd_cux6_rad cu_radial;
+       struct ipu3_uapi_iefd_cux2 cu_vssnlm;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_config_s - IEFd config
+ *
+ * @horver_diag_coeff: Gradient compensation. Compared with vertical /
+ *                    horizontal (0 / 90 degree), coefficient of diagonal (45 /
+ *                    135 degree) direction should be corrected by approx.
+ *                    1/sqrt(2).
+ * @reserved0: reserved
+ * @clamp_stitch: Slope to stitch between clamped and unclamped edge values
+ * @reserved1: reserved
+ * @direct_metric_update: Update coeff for direction metric
+ * @reserved2: reserved
+ * @ed_horver_diag_coeff: Radial Coefficient that compensates for
+ *                       different distance for vertical/horizontal and
+ *                       diagonal gradient calculation (approx. 1/sqrt(2))
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp1_iefd_config_s {
+       __u32 horver_diag_coeff:7;
+       __u32 reserved0:1;
+       __u32 clamp_stitch:6;
+       __u32 reserved1:2;
+       __u32 direct_metric_update:5;
+       __u32 reserved2:3;
+       __u32 ed_horver_diag_coeff:7;
+       __u32 reserved3:1;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_control - IEFd control
+ *
+ * @iefd_en:   Enable IEFd
+ * @denoise_en:        Enable denoise
+ * @direct_smooth_en:  Enable directional smooth
+ * @rad_en:    Enable radial update
+ * @vssnlm_en: Enable VSSNLM output filter
+ * @reserved:  reserved
+ */
+struct ipu3_uapi_yuvp1_iefd_control {
+       __u32 iefd_en:1;
+       __u32 denoise_en:1;
+       __u32 direct_smooth_en:1;
+       __u32 rad_en:1;
+       __u32 vssnlm_en:1;
+       __u32 reserved:27;
+} __packed;
+
+/**
+ * struct ipu3_uapi_sharp_cfg - Sharpening config
+ *
+ * @nega_lmt_txt: Sharpening limit for negative overshoots for texture.
+ * @reserved0: reserved
+ * @posi_lmt_txt: Sharpening limit for positive overshoots for texture.
+ * @reserved1: reserved
+ * @nega_lmt_dir: Sharpening limit for negative overshoots for direction (edge).
+ * @reserved2: reserved
+ * @posi_lmt_dir: Sharpening limit for positive overshoots for direction (edge).
+ * @reserved3: reserved
+ *
+ * Fixed point type u13.0, range [0, 8191].
+ */
+struct ipu3_uapi_sharp_cfg {
+       __u32 nega_lmt_txt:13;
+       __u32 reserved0:19;
+       __u32 posi_lmt_txt:13;
+       __u32 reserved1:19;
+       __u32 nega_lmt_dir:13;
+       __u32 reserved2:19;
+       __u32 posi_lmt_dir:13;
+       __u32 reserved3:19;
+} __packed;
+
+/**
+ * struct struct ipu3_uapi_far_w - Sharpening config for far sub-group
+ *
+ * @dir_shrp:  Weight of wide direct sharpening, u1.6, range [0, 64], default 64.
+ * @reserved0: reserved
+ * @dir_dns:   Weight of wide direct denoising, u1.6, range [0, 64], default 0.
+ * @reserved1: reserved
+ * @ndir_dns_powr:     Power of non-direct denoising,
+ *                     Precision u1.6, range [0, 64], default 64.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_far_w {
+       __u32 dir_shrp:7;
+       __u32 reserved0:1;
+       __u32 dir_dns:7;
+       __u32 reserved1:1;
+       __u32 ndir_dns_powr:7;
+       __u32 reserved2:9;
+} __packed;
+
+/**
+ * struct struct ipu3_uapi_unsharp_cfg - Unsharp config
+ *
+ * @unsharp_weight: Unsharp mask blending weight.
+ *                 u1.6, range [0, 64], default 16.
+ *                 0 - disabled, 64 - use only unsharp.
+ * @reserved0: reserved
+ * @unsharp_amount: Unsharp mask amount, u4.5, range [0, 511], default 0.
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_unsharp_cfg {
+       __u32 unsharp_weight:7;
+       __u32 reserved0:1;
+       __u32 unsharp_amount:9;
+       __u32 reserved1:15;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_shrp_cfg - IEFd sharpness config
+ *
+ * @cfg: sharpness config &ipu3_uapi_sharp_cfg
+ * @far_w: wide range config, value as specified by &ipu3_uapi_far_w:
+ *     The 5x5 environment is separated into 2 sub-groups, the 3x3 nearest
+ *     neighbors (8 pixels called Near), and the second order neighborhood
+ *     around them (16 pixels called Far).
+ * @unshrp_cfg: unsharpness config. &ipu3_uapi_unsharp_cfg
+ */
+struct ipu3_uapi_yuvp1_iefd_shrp_cfg {
+       struct ipu3_uapi_sharp_cfg cfg;
+       struct ipu3_uapi_far_w far_w;
+       struct ipu3_uapi_unsharp_cfg unshrp_cfg;
+} __packed;
+
+/**
+ * struct ipu3_uapi_unsharp_coef0 - Unsharp mask coefficients
+ *
+ * @c00: Coeff11, s0.8, range [-255, 255], default 1.
+ * @c01: Coeff12, s0.8, range [-255, 255], default 5.
+ * @c02: Coeff13, s0.8, range [-255, 255], default 9.
+ * @reserved: reserved
+ *
+ * Configurable registers for common sharpening support.
+ */
+struct ipu3_uapi_unsharp_coef0 {
+       __u32 c00:9;
+       __u32 c01:9;
+       __u32 c02:9;
+       __u32 reserved:5;
+} __packed;
+
+/**
+ * struct ipu3_uapi_unsharp_coef1 - Unsharp mask coefficients
+ *
+ * @c11: Coeff22, s0.8, range [-255, 255], default 29.
+ * @c12: Coeff23, s0.8, range [-255, 255], default 55.
+ * @c22: Coeff33, s0.8, range [-255, 255], default 96.
+ * @reserved: reserved
+ */
+struct ipu3_uapi_unsharp_coef1 {
+       __u32 c11:9;
+       __u32 c12:9;
+       __u32 c22:9;
+       __u32 reserved:5;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_unshrp_cfg - Unsharp mask config
+ *
+ * @unsharp_coef0: unsharp coefficient 0 config. See &ipu3_uapi_unsharp_coef0
+ * @unsharp_coef1: unsharp coefficient 1 config. See &ipu3_uapi_unsharp_coef1
+ */
+struct ipu3_uapi_yuvp1_iefd_unshrp_cfg {
+       struct ipu3_uapi_unsharp_coef0 unsharp_coef0;
+       struct ipu3_uapi_unsharp_coef1 unsharp_coef1;
+} __packed;
+
+/**
+ * struct ipu3_uapi_radial_reset_xy - Radial coordinate reset
+ *
+ * @x: Radial reset of x coordinate. Precision s12, [-4095, 4095], default 0.
+ * @reserved0: reserved
+ * @y: Radial center y coordinate. Precision s12, [-4095, 4095], default 0.
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_radial_reset_xy {
+       __s32 x:13;
+       __u32 reserved0:3;
+       __s32 y:13;
+       __u32 reserved1:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_radial_reset_x2 - Radial X^2 reset
+ *
+ * @x2:        Radial reset of x^2 coordinate. Precision u24, default 0.
+ * @reserved:  reserved
+ */
+struct ipu3_uapi_radial_reset_x2 {
+       __u32 x2:24;
+       __u32 reserved:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_radial_reset_y2 - Radial Y^2 reset
+ *
+ * @y2:        Radial reset of y^2 coordinate. Precision u24, default 0.
+ * @reserved:  reserved
+ */
+struct ipu3_uapi_radial_reset_y2 {
+       __u32 y2:24;
+       __u32 reserved:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_radial_cfg - Radial config
+ *
+ * @rad_nf: Radial. R^2 normalization factor is scale down by 2^ - (15 + scale)
+ * @reserved0: reserved
+ * @rad_inv_r2: Radial R^-2 normelized to (0.5..1).
+ *             Precision u7, range [0, 127].
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_radial_cfg {
+       __u32 rad_nf:4;
+       __u32 reserved0:4;
+       __u32 rad_inv_r2:7;
+       __u32 reserved1:17;
+} __packed;
+
+/**
+ * struct ipu3_uapi_rad_far_w - Radial FAR sub-group
+ *
+ * @rad_dir_far_sharp_w: Weight of wide direct sharpening, u1.6, range [0, 64],
+ *                      default 64.
+ * @rad_dir_far_dns_w: Weight of wide direct denoising, u1.6, range [0, 64],
+ *                      default 0.
+ * @rad_ndir_far_dns_power: power of non-direct sharpening, u1.6, range [0, 64],
+ *                      default 0.
+ * @reserved: reserved
+ */
+struct ipu3_uapi_rad_far_w {
+       __u32 rad_dir_far_sharp_w:8;
+       __u32 rad_dir_far_dns_w:8;
+       __u32 rad_ndir_far_dns_power:8;
+       __u32 reserved:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_cu_cfg0 - Radius Config Unit cfg0 register
+ *
+ * @cu6_pow: Power of CU6. Power of non-direct sharpening, u3.4.
+ * @reserved0: reserved
+ * @cu_unsharp_pow: Power of unsharp mask, u2.4.
+ * @reserved1: reserved
+ * @rad_cu6_pow: Radial/corner CU6. Directed sharpening power, u3.4.
+ * @reserved2: reserved
+ * @rad_cu_unsharp_pow: Radial power of unsharp mask, u2.4.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_cu_cfg0 {
+       __u32 cu6_pow:7;
+       __u32 reserved0:1;
+       __u32 cu_unsharp_pow:7;
+       __u32 reserved1:1;
+       __u32 rad_cu6_pow:7;
+       __u32 reserved2:1;
+       __u32 rad_cu_unsharp_pow:6;
+       __u32 reserved3:2;
+} __packed;
+
+/**
+ * struct ipu3_uapi_cu_cfg1 - Radius Config Unit cfg1 register
+ *
+ * @rad_cu6_x1: X1 point of Config Unit 6, precision u9.0.
+ * @reserved0: reserved
+ * @rad_cu_unsharp_x1: X1 point for Config Unit unsharp for radial/corner point
+ *                     precision u9.0.
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_cu_cfg1 {
+       __u32 rad_cu6_x1:9;
+       __u32 reserved0:1;
+       __u32 rad_cu_unsharp_x1:9;
+       __u32 reserved1:13;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_rad_cfg - IEFd parameters changed radially over
+ *                                      the picture plane.
+ *
+ * @reset_xy: reset xy value in radial calculation. &ipu3_uapi_radial_reset_xy
+ * @reset_x2: reset x square value in radial calculation. See struct
+ *           &ipu3_uapi_radial_reset_x2
+ * @reset_y2: reset y square value in radial calculation. See struct
+ *           &ipu3_uapi_radial_reset_y2
+ * @cfg: radial config defined in &ipu3_uapi_radial_cfg
+ * @rad_far_w: weight for wide range radial. &ipu3_uapi_rad_far_w
+ * @cu_cfg0: configuration unit 0. See &ipu3_uapi_cu_cfg0
+ * @cu_cfg1: configuration unit 1. See &ipu3_uapi_cu_cfg1
+ */
+struct ipu3_uapi_yuvp1_iefd_rad_cfg {
+       struct ipu3_uapi_radial_reset_xy reset_xy;
+       struct ipu3_uapi_radial_reset_x2 reset_x2;
+       struct ipu3_uapi_radial_reset_y2 reset_y2;
+       struct ipu3_uapi_radial_cfg cfg;
+       struct ipu3_uapi_rad_far_w rad_far_w;
+       struct ipu3_uapi_cu_cfg0 cu_cfg0;
+       struct ipu3_uapi_cu_cfg1 cu_cfg1;
+} __packed;
+
+/* Vssnlm - Very small scale non-local mean algorithm */
+
+/**
+ * struct ipu3_uapi_vss_lut_x - Vssnlm LUT x0/x1/x2
+ *
+ * @vs_x0: Vssnlm LUT x0, precision u8, range [0, 255], default 16.
+ * @vs_x1: Vssnlm LUT x1, precision u8, range [0, 255], default 32.
+ * @vs_x2: Vssnlm LUT x2, precision u8, range [0, 255], default 64.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_vss_lut_x {
+       __u32 vs_x0:8;
+       __u32 vs_x1:8;
+       __u32 vs_x2:8;
+       __u32 reserved2:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_vss_lut_y - Vssnlm LUT y0/y1/y2
+ *
+ * @vs_y1: Vssnlm LUT y1, precision u4, range [0, 8], default 1.
+ * @reserved0: reserved
+ * @vs_y2: Vssnlm LUT y2, precision u4, range [0, 8], default 3.
+ * @reserved1: reserved
+ * @vs_y3: Vssnlm LUT y3, precision u4, range [0, 8], default 8.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_vss_lut_y {
+       __u32 vs_y1:4;
+       __u32 reserved0:4;
+       __u32 vs_y2:4;
+       __u32 reserved1:4;
+       __u32 vs_y3:4;
+       __u32 reserved2:12;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_vssnlm_cf - IEFd Vssnlm Lookup table
+ *
+ * @vss_lut_x: vss lookup table. See &ipu3_uapi_vss_lut_x description
+ * @vss_lut_y: vss lookup table. See &ipu3_uapi_vss_lut_y description
+ */
+struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg {
+       struct ipu3_uapi_vss_lut_x vss_lut_x;
+       struct ipu3_uapi_vss_lut_y vss_lut_y;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_iefd_config - IEFd config
+ *
+ * @units: configuration unit setting, &ipu3_uapi_yuvp1_iefd_cfg_units
+ * @config: configuration, as defined by &ipu3_uapi_yuvp1_iefd_config_s
+ * @control: control setting, as defined by &ipu3_uapi_yuvp1_iefd_control
+ * @sharp: sharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_shrp_cfg
+ * @unsharp: unsharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_unshrp_cfg
+ * @rad: radial setting, as defined by &ipu3_uapi_yuvp1_iefd_rad_cfg
+ * @vsslnm: vsslnm setting, as defined by &ipu3_uapi_yuvp1_iefd_vssnlm_cfg
+ */
+struct ipu3_uapi_yuvp1_iefd_config {
+       struct ipu3_uapi_yuvp1_iefd_cfg_units units;
+       struct ipu3_uapi_yuvp1_iefd_config_s config;
+       struct ipu3_uapi_yuvp1_iefd_control control;
+       struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp;
+       struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp;
+       struct ipu3_uapi_yuvp1_iefd_rad_cfg rad;
+       struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_yds_config - Y Down-Sampling config
+ *
+ * @c00: range [0, 3], default 0x0
+ * @c01: range [0, 3], default 0x1
+ * @c02: range [0, 3], default 0x1
+ * @c03: range [0, 3], default 0x0
+ * @c10: range [0, 3], default 0x0
+ * @c11: range [0, 3], default 0x1
+ * @c12: range [0, 3], default 0x1
+ * @c13: range [0, 3], default 0x0
+ *
+ * Above are 4x2 filter coefficients for chroma output downscaling.
+ *
+ * @norm_factor: Normalization factor, range [0, 4], default 2
+ *             0 - divide by 1
+ *             1 - divide by 2
+ *             2 - divide by 4
+ *             3 - divide by 8
+ *             4 - divide by 16
+ * @reserved0: reserved
+ * @bin_output: Down sampling on Luma channel in two optional modes
+ *             0 - Bin output 4.2.0 (default), 1 output 4.2.2.
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_yuvp1_yds_config {
+       __u32 c00:2;
+       __u32 c01:2;
+       __u32 c02:2;
+       __u32 c03:2;
+       __u32 c10:2;
+       __u32 c11:2;
+       __u32 c12:2;
+       __u32 c13:2;
+       __u32 norm_factor:5;
+       __u32 reserved0:4;
+       __u32 bin_output:1;
+       __u32 reserved1:6;
+} __packed;
+
+/* Chroma Noise Reduction */
+
+/**
+ * struct ipu3_uapi_yuvp1_chnr_enable_config - Chroma noise reduction enable
+ *
+ * @enable: enable/disable chroma noise reduction
+ * @yuv_mode: 0 - YUV420, 1 - YUV422
+ * @reserved0: reserved
+ * @col_size: number of columns in the frame, max width is 2560
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_yuvp1_chnr_enable_config {
+       __u32 enable:1;
+       __u32 yuv_mode:1;
+       __u32 reserved0:14;
+       __u32 col_size:12;
+       __u32 reserved1:4;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_chnr_coring_config - Coring thresholds for UV
+ *
+ * @u: U coring level, u0.13, range [0.0, 1.0], default 0.0
+ * @reserved0: reserved
+ * @v: V coring level, u0.13, range [0.0, 1.0], default 0.0
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_yuvp1_chnr_coring_config {
+       __u32 u:13;
+       __u32 reserved0:3;
+       __u32 v:13;
+       __u32 reserved1:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_chnr_sense_gain_config - Chroma noise reduction gains
+ *
+ * All sensitivity gain parameters have precision u13.0, range [0, 8191].
+ *
+ * @vy: Sensitivity of horizontal edge of Y, default 100
+ * @vu: Sensitivity of horizontal edge of U, default 100
+ * @vv: Sensitivity of horizontal edge of V, default 100
+ * @reserved0: reserved
+ * @hy: Sensitivity of vertical edge of Y, default 50
+ * @hu: Sensitivity of vertical edge of U, default 50
+ * @hv: Sensitivity of vertical edge of V, default 50
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_yuvp1_chnr_sense_gain_config {
+       __u32 vy:8;
+       __u32 vu:8;
+       __u32 vv:8;
+       __u32 reserved0:8;
+
+       __u32 hy:8;
+       __u32 hu:8;
+       __u32 hv:8;
+       __u32 reserved1:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_chnr_iir_fir_config - Chroma IIR/FIR filter config
+ *
+ * @fir_0h: Value of center tap in horizontal FIR, range [0, 32], default 8.
+ * @reserved0: reserved
+ * @fir_1h: Value of distance 1 in horizontal FIR, range [0, 32], default 12.
+ * @reserved1: reserved
+ * @fir_2h: Value of distance 2 tap in horizontal FIR, range [0, 32], default 0.
+ * @dalpha_clip_val: weight for previous row in IIR, range [1, 256], default 0.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_yuvp1_chnr_iir_fir_config {
+       __u32 fir_0h:6;
+       __u32 reserved0:2;
+       __u32 fir_1h:6;
+       __u32 reserved1:2;
+       __u32 fir_2h:6;
+       __u32 dalpha_clip_val:9;
+       __u32 reserved2:1;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_chnr_config - Chroma noise reduction config
+ *
+ * @enable: chroma noise reduction enable, see
+ *         &ipu3_uapi_yuvp1_chnr_enable_config
+ * @coring: coring config for chroma noise reduction, see
+ *         &ipu3_uapi_yuvp1_chnr_coring_config
+ * @sense_gain: sensitivity config for chroma noise reduction, see
+ *             ipu3_uapi_yuvp1_chnr_sense_gain_config
+ * @iir_fir: iir and fir config for chroma noise reduction, see
+ *          ipu3_uapi_yuvp1_chnr_iir_fir_config
+ */
+struct ipu3_uapi_yuvp1_chnr_config {
+       struct ipu3_uapi_yuvp1_chnr_enable_config enable;
+       struct ipu3_uapi_yuvp1_chnr_coring_config coring;
+       struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain;
+       struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir;
+} __packed;
+
+/* Edge Enhancement and Noise Reduction */
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config - Luma(Y) edge enhancement low-pass
+ *                                            filter coefficients
+ *
+ * @a_diag: Smoothing diagonal coefficient, u5.0.
+ * @reserved0: reserved
+ * @a_periph: Image smoothing perpherial, u5.0.
+ * @reserved1: reserved
+ * @a_cent: Image Smoothing center coefficient, u5.0.
+ * @reserved2: reserved
+ * @enable: 0: Y_EE_NR disabled, output = input; 1: Y_EE_NR enabled.
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config {
+       __u32 a_diag:5;
+       __u32 reserved0:3;
+       __u32 a_periph:5;
+       __u32 reserved1:3;
+       __u32 a_cent:5;
+       __u32 reserved2:9;
+       __u32 enable:1;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_sense_config - Luma(Y) edge enhancement
+ *                                     noise reduction sensitivity gains
+ *
+ * @edge_sense_0: Sensitivity of edge in dark area. u13.0, default 8191.
+ * @reserved0: reserved
+ * @delta_edge_sense: Difference in the sensitivity of edges between
+ *                   the bright and dark areas. u13.0, default 0.
+ * @reserved1: reserved
+ * @corner_sense_0: Sensitivity of corner in dark area. u13.0, default 0.
+ * @reserved2: reserved
+ * @delta_corner_sense: Difference in the sensitivity of corners between
+ *                     the bright and dark areas. u13.0, default 8191.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_sense_config {
+       __u32 edge_sense_0:13;
+       __u32 reserved0:3;
+       __u32 delta_edge_sense:13;
+       __u32 reserved1:3;
+       __u32 corner_sense_0:13;
+       __u32 reserved2:3;
+       __u32 delta_corner_sense:13;
+       __u32 reserved3:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_gain_config - Luma(Y) edge enhancement
+ *                                             noise reduction gain config
+ *
+ * @gain_pos_0: Gain for positive edge in dark area. u5.0, [0, 16], default 2.
+ * @reserved0: reserved
+ * @delta_gain_posi: Difference in the gain of edges between the bright and
+ *                  dark areas for positive edges. u5.0, [0, 16], default 0.
+ * @reserved1: reserved
+ * @gain_neg_0: Gain for negative edge in dark area. u5.0, [0, 16], default 8.
+ * @reserved2: reserved
+ * @delta_gain_neg: Difference in the gain of edges between the bright and
+ *                 dark areas for negative edges. u5.0, [0, 16], default 0.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_gain_config {
+       __u32 gain_pos_0:5;
+       __u32 reserved0:3;
+       __u32 delta_gain_posi:5;
+       __u32 reserved1:3;
+       __u32 gain_neg_0:5;
+       __u32 reserved2:3;
+       __u32 delta_gain_neg:5;
+       __u32 reserved3:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_clip_config - Luma(Y) edge enhancement
+ *                                     noise reduction clipping config
+ *
+ * @clip_pos_0: Limit of positive edge in dark area
+ *             u5, value [0, 16], default 8.
+ * @reserved0: reserved
+ * @delta_clip_posi: Difference in the limit of edges between the bright
+ *                  and dark areas for positive edges.
+ *                  u5, value [0, 16], default 8.
+ * @reserved1: reserved
+ * @clip_neg_0: Limit of negative edge in dark area
+ *             u5, value [0, 16], default 8.
+ * @reserved2: reserved
+ * @delta_clip_neg: Difference in the limit of edges between the bright
+ *                 and dark areas for negative edges.
+ *                 u5, value [0, 16], default 8.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_clip_config {
+       __u32 clip_pos_0:5;
+       __u32 reserved0:3;
+       __u32 delta_clip_posi:5;
+       __u32 reserved1:3;
+       __u32 clip_neg_0:5;
+       __u32 reserved2:3;
+       __u32 delta_clip_neg:5;
+       __u32 reserved3:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_frng_config - Luma(Y) edge enhancement
+ *                                             noise reduction fringe config
+ *
+ * @gain_exp: Common exponent of gains, u4, [0, 8], default 2.
+ * @reserved0: reserved
+ * @min_edge: Threshold for edge and smooth stitching, u13.
+ * @reserved1: reserved
+ * @lin_seg_param: Power of LinSeg, u4.
+ * @reserved2: reserved
+ * @t1: Parameter for enabling/disabling the edge enhancement, u1.0, [0, 1],
+ *     default 1.
+ * @t2: Parameter for enabling/disabling the smoothing, u1.0, [0, 1],
+ *     default 1.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_frng_config {
+       __u32 gain_exp:4;
+       __u32 reserved0:28;
+       __u32 min_edge:13;
+       __u32 reserved1:3;
+       __u32 lin_seg_param:4;
+       __u32 reserved2:4;
+       __u32 t1:1;
+       __u32 t2:1;
+       __u32 reserved3:6;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_diag_config - Luma(Y) edge enhancement
+ *                                     noise reduction diagonal config
+ *
+ * @diag_disc_g: Coefficient that prioritize diagonal edge direction on
+ *              horizontal or vertical for final enhancement.
+ *              u4.0, [1, 15], default 1.
+ * @reserved0: reserved
+ * @hvw_hor: Weight of horizontal/vertical edge enhancement for hv edge.
+ *             u2.2, [1, 15], default 4.
+ * @dw_hor: Weight of diagonal edge enhancement for hv edge.
+ *             u2.2, [1, 15], default 1.
+ * @hvw_diag: Weight of horizontal/vertical edge enhancement for diagonal edge.
+ *             u2.2, [1, 15], default 1.
+ * @dw_diag: Weight of diagonal edge enhancement for diagonal edge.
+ *             u2.2, [1, 15], default 4.
+ * @reserved1: reserved
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_diag_config {
+       __u32 diag_disc_g:4;
+       __u32 reserved0:4;
+       __u32 hvw_hor:4;
+       __u32 dw_hor:4;
+       __u32 hvw_diag:4;
+       __u32 dw_diag:4;
+       __u32 reserved1:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config - Luma(Y) edge enhancement
+ *             noise reduction false color correction (FCC) coring config
+ *
+ * @pos_0: Gain for positive edge in dark, u13.0, [0, 16], default 0.
+ * @reserved0: reserved
+ * @pos_delta: Gain for positive edge in bright, value: pos_0 + pos_delta <=16
+ *             u13.0, default 0.
+ * @reserved1: reserved
+ * @neg_0: Gain for negative edge in dark area, u13.0, range [0, 16], default 0.
+ * @reserved2: reserved
+ * @neg_delta: Gain for negative edge in bright area. neg_0 + neg_delta <=16
+ *             u13.0, default 0.
+ * @reserved3: reserved
+ *
+ * Coring is a simple soft thresholding technique.
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config {
+       __u32 pos_0:13;
+       __u32 reserved0:3;
+       __u32 pos_delta:13;
+       __u32 reserved1:3;
+       __u32 neg_0:13;
+       __u32 reserved2:3;
+       __u32 neg_delta:13;
+       __u32 reserved3:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp1_y_ee_nr_config - Edge enhancement and noise reduction
+ *
+ * @lpf: low-pass filter config. See &ipu3_uapi_yuvp1_y_ee_nr_lpf_config
+ * @sense: sensitivity config. See &ipu3_uapi_yuvp1_y_ee_nr_sense_config
+ * @gain: gain config as defined in &ipu3_uapi_yuvp1_y_ee_nr_gain_config
+ * @clip: clip config as defined in &ipu3_uapi_yuvp1_y_ee_nr_clip_config
+ * @frng: fringe config as defined in &ipu3_uapi_yuvp1_y_ee_nr_frng_config
+ * @diag: diagonal edge config. See &ipu3_uapi_yuvp1_y_ee_nr_diag_config
+ * @fc_coring: coring config for fringe control. See
+ *            &ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config
+ */
+struct ipu3_uapi_yuvp1_y_ee_nr_config {
+       struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf;
+       struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense;
+       struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain;
+       struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip;
+       struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng;
+       struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag;
+       struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring;
+} __packed;
+
+/* Total Color Correction */
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_gen_control_static_config - Total color correction
+ *                             general control config
+ *
+ * @en:        0 - TCC disabled. Output = input 1 - TCC enabled.
+ * @blend_shift:       blend shift, Range[3, 4], default NA.
+ * @gain_according_to_y_only:  0: Gain is calculated according to YUV,
+ *                             1: Gain is calculated according to Y only
+ * @reserved0: reserved
+ * @gamma:     Final blending coefficients. Values[-16, 16], default NA.
+ * @reserved1: reserved
+ * @delta:     Final blending coefficients. Values[-16, 16], default NA.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_yuvp2_tcc_gen_control_static_config {
+       __u32 en:1;
+       __u32 blend_shift:3;
+       __u32 gain_according_to_y_only:1;
+       __u32 reserved0:11;
+       __s32 gamma:5;
+       __u32 reserved1:3;
+       __s32 delta:5;
+       __u32 reserved2:3;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config - Total color correction
+ *                             multi-axis color control (MACC) config
+ *
+ * @a: a coefficient for 2x2 MACC conversion matrix.
+ * @reserved0: reserved
+ * @b: b coefficient  2x2 MACC conversion matrix.
+ * @reserved1: reserved
+ * @c: c coefficient for 2x2 MACC conversion matrix.
+ * @reserved2: reserved
+ * @d: d coefficient for 2x2 MACC conversion matrix.
+ * @reserved3: reserved
+ */
+struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config {
+       __s32 a:12;
+       __u32 reserved0:4;
+       __s32 b:12;
+       __u32 reserved1:4;
+       __s32 c:12;
+       __u32 reserved2:4;
+       __s32 d:12;
+       __u32 reserved3:4;
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_macc_table_static_config - Total color correction
+ *                             multi-axis color control (MACC) table array
+ *
+ * @entries: config for multi axis color correction, as specified by
+ *          &ipu3_uapi_yuvp2_tcc_macc_elem_static_config
+ */
+struct ipu3_uapi_yuvp2_tcc_macc_table_static_config {
+       struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config
+               entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config - Total color correction
+ *                             inverse y lookup table
+ *
+ * @entries: lookup table for inverse y estimation, and use it to estimate the
+ *          ratio between luma and chroma. Chroma by approximate the absolute
+ *          value of the radius on the chroma plane (R = sqrt(u^2+v^2) ) and
+ *          luma by approximate by 1/Y.
+ */
+struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config {
+       __u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config - Total color
+ *                                     correction lookup table for PCWL
+ *
+ * @entries: lookup table for gain piece wise linear transformation (PCWL)
+ */
+struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config {
+       __u16 entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config - Total color correction
+ *                             lookup table for r square root
+ *
+ * @entries: lookup table for r square root estimation
+ */
+struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config {
+       __s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_yuvp2_tcc_static_config- Total color correction static
+ *
+ * @gen_control: general config for Total Color Correction
+ * @macc_table: config for multi axis color correction
+ * @inv_y_lut: lookup table for inverse y estimation
+ * @gain_pcwl: lookup table for gain PCWL
+ * @r_sqr_lut: lookup table for r square root estimation.
+ */
+struct ipu3_uapi_yuvp2_tcc_static_config {
+       struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control;
+       struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table;
+       struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut;
+       struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl;
+       struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut;
+} __packed;
+
+/* Advanced Noise Reduction related structs */
+
+/*
+ * struct ipu3_uapi_anr_alpha - Advanced noise reduction alpha
+ *
+ * Tunable parameters that are subject to modification according to the
+ * total gain used.
+ */
+struct ipu3_uapi_anr_alpha {
+       __u16 gr;
+       __u16 r;
+       __u16 b;
+       __u16 gb;
+       __u16 dc_gr;
+       __u16 dc_r;
+       __u16 dc_b;
+       __u16 dc_gb;
+} __packed;
+
+/*
+ * struct ipu3_uapi_anr_beta - Advanced noise reduction beta
+ *
+ * Tunable parameters that are subject to modification according to the
+ * total gain used.
+ */
+struct ipu3_uapi_anr_beta {
+       __u16 beta_gr;
+       __u16 beta_r;
+       __u16 beta_b;
+       __u16 beta_gb;
+} __packed;
+
+/*
+ * struct ipu3_uapi_anr_plane_color - Advanced noise reduction per plane R, Gr,
+ *                                   Gb and B register settings
+ *
+ * Tunable parameters that are subject to modification according to the
+ * total gain used.
+ */
+struct ipu3_uapi_anr_plane_color {
+       __u16 reg_w_gr[16];
+       __u16 reg_w_r[16];
+       __u16 reg_w_b[16];
+       __u16 reg_w_gb[16];
+} __packed;
+
+/**
+ * struct ipu3_uapi_anr_transform_config - Advanced noise reduction transform
+ *
+ * @enable: advanced noise reduction enabled.
+ * @adaptive_treshhold_en: On IPU3, adaptive threshold is always enabled.
+ * @reserved1: reserved
+ * @reserved2: reserved
+ * @alpha: using following defaults:
+ *             13, 13, 13, 13, 0, 0, 0, 0
+ *             11, 11, 11, 11, 0, 0, 0, 0
+ *             14,  14, 14, 14, 0, 0, 0, 0
+ * @beta: use following defaults:
+ *             24, 24, 24, 24
+ *             21, 20, 20, 21
+ *             25, 25, 25, 25
+ * @color: use defaults defined in driver/media/pci/intel/ipu3-tables.c
+ * @sqrt_lut: 11 bits per element, values =
+ *                                     [724 768 810 849 887
+ *                                     923 958 991 1024 1056
+ *                                     1116 1145 1173 1201 1086
+ *                                     1228 1254 1280 1305 1330
+ *                                     1355 1379 1402 1425 1448]
+ * @xreset: Reset value of X for r^2 calculation Value: col_start-X_center
+ *     Constraint: Xreset + FrameWdith=4095 Xreset= -4095, default -1632.
+ * @reserved3: reserved
+ * @yreset: Reset value of Y for r^2 calculation Value: row_start-Y_center
+ *      Constraint: Yreset + FrameHeight=4095 Yreset= -4095, default -1224.
+ * @reserved4: reserved
+ * @x_sqr_reset: Reset value of X^2 for r^2 calculation Value = (Xreset)^2
+ * @r_normfactor: Normalization factor for R. Default 14.
+ * @reserved5: reserved
+ * @y_sqr_reset: Reset value of Y^2 for r^2 calculation Value = (Yreset)^2
+ * @gain_scale: Parameter describing shading gain as a function of distance
+ *             from the image center.
+ *             A single value per frame, loaded by the driver. Default 115.
+ */
+struct ipu3_uapi_anr_transform_config {
+       __u32 enable:1;                 /* 0 or 1, disabled or enabled */
+       __u32 adaptive_treshhold_en:1;  /* On IPU3, always enabled */
+
+       __u32 reserved1:30;
+       __u8 reserved2[44];
+
+       struct ipu3_uapi_anr_alpha alpha[3];
+       struct ipu3_uapi_anr_beta beta[3];
+       struct ipu3_uapi_anr_plane_color color[3];
+
+       __u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE]; /* 11 bits per element */
+
+       __s16 xreset:13;
+       __u16 reserved3:3;
+       __s16 yreset:13;
+       __u16 reserved4:3;
+
+       __u32 x_sqr_reset:24;
+       __u32 r_normfactor:5;
+       __u32 reserved5:3;
+
+       __u32 y_sqr_reset:24;
+       __u32 gain_scale:8;
+} __packed;
+
+/**
+ * struct ipu3_uapi_anr_stitch_pyramid - ANR stitch pyramid
+ *
+ * @entry0: pyramid LUT entry0, range [0x0, 0x3f]
+ * @entry1: pyramid LUT entry1, range [0x0, 0x3f]
+ * @entry2: pyramid LUT entry2, range [0x0, 0x3f]
+ * @reserved: reserved
+ */
+struct ipu3_uapi_anr_stitch_pyramid {
+       __u32 entry0:6;
+       __u32 entry1:6;
+       __u32 entry2:6;
+       __u32 reserved:14;
+} __packed;
+
+/**
+ * struct ipu3_uapi_anr_stitch_config - ANR stitch config
+ *
+ * @anr_stitch_en: enable stitch. Enabled with 1.
+ * @reserved: reserved
+ * @pyramid: pyramid table as defined by &ipu3_uapi_anr_stitch_pyramid
+ *             default values:
+ *             { 1, 3, 5 }, { 7, 7, 5 }, { 3, 1, 3 },
+ *             { 9, 15, 21 }, { 21, 15, 9 }, { 3, 5, 15 },
+ *             { 25, 35, 35 }, { 25, 15, 5 }, { 7, 21, 35 },
+ *             { 49, 49, 35 }, { 21, 7, 7 }, { 21, 35, 49 },
+ *             { 49, 35, 21 }, { 7, 5, 15 }, { 25, 35, 35 },
+ *             { 25, 15, 5 }, { 3, 9, 15 }, { 21, 21, 15 },
+ *             { 9, 3, 1 }, { 3, 5, 7 }, { 7, 5, 3}, { 1 }
+ */
+struct ipu3_uapi_anr_stitch_config {
+       __u32 anr_stitch_en;
+       __u8 reserved[44];
+       struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE];
+} __packed;
+
+/**
+ * struct ipu3_uapi_anr_config - ANR config
+ *
+ * @transform: advanced noise reduction transform config as specified by
+ *             &ipu3_uapi_anr_transform_config
+ * @stitch: create 4x4 patch from 4 surrounding 8x8 patches.
+ */
+struct ipu3_uapi_anr_config {
+       struct ipu3_uapi_anr_transform_config transform __attribute__((aligned(32)));
+       struct ipu3_uapi_anr_stitch_config stitch __attribute__((aligned(32)));
+} __packed;
+
+/**
+ * struct ipu3_uapi_acc_param - Accelerator cluster parameters
+ *
+ * ACC refers to the HW cluster containing all Fixed Functions (FFs). Each FF
+ * implements a specific algorithm.
+ *
+ * @bnr:       parameters for bayer noise reduction static config. See
+ *             &ipu3_uapi_bnr_static_config
+ * @green_disparity:   disparity static config between gr and gb channel.
+ *                     See &ipu3_uapi_bnr_static_config_green_disparity
+ * @dm:        de-mosaic config. See &ipu3_uapi_dm_config
+ * @ccm:       color correction matrix. See &ipu3_uapi_ccm_mat_config
+ * @gamma:     gamma correction config. See &ipu3_uapi_gamma_config
+ * @csc:       color space conversion matrix. See &ipu3_uapi_csc_mat_config
+ * @cds:       color down sample config. See &ipu3_uapi_cds_params
+ * @shd:       lens shading correction config. See &ipu3_uapi_shd_config
+ * @iefd:      Image enhancement filter and denoise config.
+ *             &ipu3_uapi_yuvp1_iefd_config
+ * @yds_c0:    y down scaler config. &ipu3_uapi_yuvp1_yds_config
+ * @chnr_c0:   chroma noise reduction config. &ipu3_uapi_yuvp1_chnr_config
+ * @y_ee_nr:   y edge enhancement and noise reduction config.
+ *             &ipu3_uapi_yuvp1_y_ee_nr_config
+ * @yds:       y down scaler config. See &ipu3_uapi_yuvp1_yds_config
+ * @chnr:      chroma noise reduction config. See &ipu3_uapi_yuvp1_chnr_config
+ * @reserved1: reserved
+ * @yds2:      y channel down scaler config. See &ipu3_uapi_yuvp1_yds_config
+ * @tcc:       total color correction config as defined in struct
+ *             &ipu3_uapi_yuvp2_tcc_static_config
+ * @reserved2: reserved
+ * @anr:       advanced noise reduction config.See &ipu3_uapi_anr_config
+ * @awb_fr:    AWB filter response config. See ipu3_uapi_awb_fr_config
+ * @ae:        auto exposure config  As specified by &ipu3_uapi_ae_config
+ * @af:        auto focus config. As specified by &ipu3_uapi_af_config
+ * @awb:       auto white balance config. As specified by &ipu3_uapi_awb_config
+ */
+struct ipu3_uapi_acc_param {
+       struct ipu3_uapi_bnr_static_config bnr;
+       struct ipu3_uapi_bnr_static_config_green_disparity
+                               green_disparity __attribute__((aligned(32)));
+       struct ipu3_uapi_dm_config dm __attribute__((aligned(32)));
+       struct ipu3_uapi_ccm_mat_config ccm __attribute__((aligned(32)));
+       struct ipu3_uapi_gamma_config gamma __attribute__((aligned(32)));
+       struct ipu3_uapi_csc_mat_config csc __attribute__((aligned(32)));
+       struct ipu3_uapi_cds_params cds __attribute__((aligned(32)));
+       struct ipu3_uapi_shd_config shd __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_iefd_config iefd __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_yds_config yds_c0 __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_chnr_config chnr_c0 __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_yds_config yds __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_chnr_config chnr __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp1_yds_config yds2 __attribute__((aligned(32)));
+       struct ipu3_uapi_yuvp2_tcc_static_config tcc __attribute__((aligned(32)));
+       struct ipu3_uapi_anr_config anr;
+       struct ipu3_uapi_awb_fr_config_s awb_fr;
+       struct ipu3_uapi_ae_config ae;
+       struct ipu3_uapi_af_config_s af;
+       struct ipu3_uapi_awb_config awb;
+} __packed;
+
+/**
+ * struct ipu3_uapi_isp_lin_vmem_params - Linearization parameters
+ *
+ * @lin_lutlow_gr: linearization look-up table for GR channel interpolation.
+ * @lin_lutlow_r: linearization look-up table for R channel interpolation.
+ * @lin_lutlow_b: linearization look-up table for B channel interpolation.
+ * @lin_lutlow_gb: linearization look-up table for GB channel interpolation.
+ *                     lin_lutlow_gr / lin_lutlow_r / lin_lutlow_b /
+ *                     lin_lutlow_gb <= LIN_MAX_VALUE - 1.
+ * @lin_lutdif_gr:     lin_lutlow_gr[i+1] - lin_lutlow_gr[i].
+ * @lin_lutdif_r:      lin_lutlow_r[i+1] - lin_lutlow_r[i].
+ * @lin_lutdif_b:      lin_lutlow_b[i+1] - lin_lutlow_b[i].
+ * @lin_lutdif_gb:     lin_lutlow_gb[i+1] - lin_lutlow_gb[i].
+ */
+struct ipu3_uapi_isp_lin_vmem_params {
+       __s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE];
+       __s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE];
+} __packed;
+
+/* Temporal Noise Reduction */
+
+/**
+ * struct ipu3_uapi_isp_tnr3_vmem_params - Temporal noise reduction vector
+ *                                        memory parameters
+ *
+ * @slope: slope setting in interpolation curve for temporal noise reduction.
+ * @reserved1: reserved
+ * @sigma: knee point setting in interpolation curve for temporal
+ *        noise reduction.
+ * @reserved2: reserved
+ */
+struct ipu3_uapi_isp_tnr3_vmem_params {
+       __u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+       __u16 reserved1[IPU3_UAPI_ISP_VEC_ELEMS
+                                               - IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+       __u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+       __u16 reserved2[IPU3_UAPI_ISP_VEC_ELEMS
+                                               - IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+} __packed;
+
+/**
+ * struct ipu3_uapi_isp_tnr3_params - Temporal noise reduction v3 parameters
+ *
+ * @knee_y1: Knee point TNR3 assumes standard deviation of Y,U and
+ *     V at Y1 are TnrY1_Sigma_Y, U and V.
+ * @knee_y2: Knee point TNR3 assumes standard deviation of Y,U and
+ *             V at Y2 are TnrY2_Sigma_Y, U and V.
+ * @maxfb_y: Max feedback gain for Y
+ * @maxfb_u: Max feedback gain for U
+ * @maxfb_v: Max feedback gain for V
+ * @round_adj_y: rounding Adjust for Y
+ * @round_adj_u: rounding Adjust for U
+ * @round_adj_v: rounding Adjust for V
+ * @ref_buf_select: selection of the reference frame buffer to be used.
+ */
+struct ipu3_uapi_isp_tnr3_params {
+       __u32 knee_y1;
+       __u32 knee_y2;
+       __u32 maxfb_y;
+       __u32 maxfb_u;
+       __u32 maxfb_v;
+       __u32 round_adj_y;
+       __u32 round_adj_u;
+       __u32 round_adj_v;
+       __u32 ref_buf_select;
+} __packed;
+
+/* Extreme Noise Reduction version 3 */
+
+/**
+ * struct ipu3_uapi_isp_xnr3_vmem_params - Extreme noise reduction v3
+ *                                        vector memory parameters
+ *
+ * @x: xnr3 parameters.
+ * @a: xnr3 parameters.
+ * @b: xnr3 parameters.
+ * @c: xnr3 parameters.
+ */
+struct ipu3_uapi_isp_xnr3_vmem_params {
+       __u16 x[IPU3_UAPI_ISP_VEC_ELEMS];
+       __u16 a[IPU3_UAPI_ISP_VEC_ELEMS];
+       __u16 b[IPU3_UAPI_ISP_VEC_ELEMS];
+       __u16 c[IPU3_UAPI_ISP_VEC_ELEMS];
+} __packed;
+
+/**
+ * struct ipu3_uapi_xnr3_alpha_params - Extreme noise reduction v3
+ *                                     alpha tuning parameters
+ *
+ * @y0: Sigma for Y range similarity in dark area.
+ * @u0: Sigma for U range similarity in dark area.
+ * @v0: Sigma for V range similarity in dark area.
+ * @ydiff: Sigma difference for Y between bright area and dark area.
+ * @udiff: Sigma difference for U between bright area and dark area.
+ * @vdiff: Sigma difference for V between bright area and dark area.
+ */
+struct ipu3_uapi_xnr3_alpha_params {
+       __u32 y0;
+       __u32 u0;
+       __u32 v0;
+       __u32 ydiff;
+       __u32 udiff;
+       __u32 vdiff;
+} __packed;
+
+/**
+ * struct ipu3_uapi_xnr3_coring_params - Extreme noise reduction v3
+ *                                      coring parameters
+ *
+ * @u0: Coring Threshold of U channel in dark area.
+ * @v0: Coring Threshold of V channel in dark area.
+ * @udiff: Threshold difference of U channel between bright and dark area.
+ * @vdiff: Threshold difference of V channel between bright and dark area.
+ */
+struct ipu3_uapi_xnr3_coring_params {
+       __u32 u0;
+       __u32 v0;
+       __u32 udiff;
+       __u32 vdiff;
+} __packed;
+
+/**
+ * struct ipu3_uapi_xnr3_blending_params - Blending factor
+ *
+ * @strength: The factor for blending output with input. This is tuning
+ *           parameterHigher values lead to more aggressive XNR operation.
+ */
+struct ipu3_uapi_xnr3_blending_params {
+       __u32 strength;
+} __packed;
+
+/**
+ * struct ipu3_uapi_isp_xnr3_params - Extreme noise reduction v3 parameters
+ *
+ * @alpha: parameters for xnr3 alpha. See &ipu3_uapi_xnr3_alpha_params
+ * @coring: parameters for xnr3 coring. See &ipu3_uapi_xnr3_coring_params
+ * @blending: parameters for xnr3 blending. See &ipu3_uapi_xnr3_blending_params
+ */
+struct ipu3_uapi_isp_xnr3_params {
+       struct ipu3_uapi_xnr3_alpha_params alpha;
+       struct ipu3_uapi_xnr3_coring_params coring;
+       struct ipu3_uapi_xnr3_blending_params blending;
+} __packed;
+
+/***** Obgrid (optical black level compensation) table entry *****/
+
+/**
+ * struct ipu3_uapi_obgrid_param - Optical black level compensation parameters
+ *
+ * @gr: Grid table values for color GR
+ * @r: Grid table values for color R
+ * @b: Grid table values for color B
+ * @gb: Grid table values for color GB
+ *
+ * Black level is different for red, green, and blue channels. So black level
+ * compensation is different per channel.
+ */
+struct ipu3_uapi_obgrid_param {
+       __u16 gr;
+       __u16 r;
+       __u16 b;
+       __u16 gb;
+} __packed;
+
+/******************* V4L2_META_FMT_IPU3_PARAMS *******************/
+
+/**
+ * struct ipu3_uapi_flags - bits to indicate which pipeline needs update
+ *
+ * @gdc: 0 = no update, 1 = update.
+ * @obgrid: 0 = no update, 1 = update.
+ * @reserved1: Not used.
+ * @acc_bnr: 0 = no update, 1 = update.
+ * @acc_green_disparity: 0 = no update, 1 = update.
+ * @acc_dm: 0 = no update, 1 = update.
+ * @acc_ccm: 0 = no update, 1 = update.
+ * @acc_gamma: 0 = no update, 1 = update.
+ * @acc_csc: 0 = no update, 1 = update.
+ * @acc_cds: 0 = no update, 1 = update.
+ * @acc_shd: 0 = no update, 1 = update.
+ * @reserved2: Not used.
+ * @acc_iefd: 0 = no update, 1 = update.
+ * @acc_yds_c0: 0 = no update, 1 = update.
+ * @acc_chnr_c0: 0 = no update, 1 = update.
+ * @acc_y_ee_nr: 0 = no update, 1 = update.
+ * @acc_yds: 0 = no update, 1 = update.
+ * @acc_chnr: 0 = no update, 1 = update.
+ * @acc_ytm: 0 = no update, 1 = update.
+ * @acc_yds2: 0 = no update, 1 = update.
+ * @acc_tcc: 0 = no update, 1 = update.
+ * @acc_dpc: 0 = no update, 1 = update.
+ * @acc_bds: 0 = no update, 1 = update.
+ * @acc_anr: 0 = no update, 1 = update.
+ * @acc_awb_fr: 0 = no update, 1 = update.
+ * @acc_ae: 0 = no update, 1 = update.
+ * @acc_af: 0 = no update, 1 = update.
+ * @acc_awb: 0 = no update, 1 = update.
+ * @__acc_osys: 0 = no update, 1 = update.
+ * @reserved3: Not used.
+ * @lin_vmem_params: 0 = no update, 1 = update.
+ * @tnr3_vmem_params: 0 = no update, 1 = update.
+ * @xnr3_vmem_params: 0 = no update, 1 = update.
+ * @tnr3_dmem_params: 0 = no update, 1 = update.
+ * @xnr3_dmem_params: 0 = no update, 1 = update.
+ * @reserved4: Not used.
+ * @obgrid_param: 0 = no update, 1 = update.
+ * @reserved5: Not used.
+ */
+struct ipu3_uapi_flags {
+       __u32 gdc:1;
+       __u32 obgrid:1;
+       __u32 reserved1:30;
+
+       __u32 acc_bnr:1;
+       __u32 acc_green_disparity:1;
+       __u32 acc_dm:1;
+       __u32 acc_ccm:1;
+       __u32 acc_gamma:1;
+       __u32 acc_csc:1;
+       __u32 acc_cds:1;
+       __u32 acc_shd:1;
+       __u32 reserved2:2;
+       __u32 acc_iefd:1;
+       __u32 acc_yds_c0:1;
+       __u32 acc_chnr_c0:1;
+       __u32 acc_y_ee_nr:1;
+       __u32 acc_yds:1;
+       __u32 acc_chnr:1;
+       __u32 acc_ytm:1;
+       __u32 acc_yds2:1;
+       __u32 acc_tcc:1;
+       __u32 acc_dpc:1;
+       __u32 acc_bds:1;
+       __u32 acc_anr:1;
+       __u32 acc_awb_fr:1;
+       __u32 acc_ae:1;
+       __u32 acc_af:1;
+       __u32 acc_awb:1;
+       __u32 reserved3:4;
+
+       __u32 lin_vmem_params:1;
+       __u32 tnr3_vmem_params:1;
+       __u32 xnr3_vmem_params:1;
+       __u32 tnr3_dmem_params:1;
+       __u32 xnr3_dmem_params:1;
+       __u32 reserved4:1;
+       __u32 obgrid_param:1;
+       __u32 reserved5:25;
+} __packed;
+
+/**
+ * struct ipu3_uapi_params - V4L2_META_FMT_IPU3_PARAMS
+ *
+ * @use:       select which parameters to apply, see &ipu3_uapi_flags
+ * @acc_param: ACC parameters, as specified by &ipu3_uapi_acc_param
+ * @lin_vmem_params:   linearization VMEM, as specified by
+ *                     &ipu3_uapi_isp_lin_vmem_params
+ * @tnr3_vmem_params:  tnr3 VMEM as specified by
+ *                     &ipu3_uapi_isp_tnr3_vmem_params
+ * @xnr3_vmem_params:  xnr3 VMEM as specified by
+ *                     &ipu3_uapi_isp_xnr3_vmem_params
+ * @tnr3_dmem_params:  tnr3 DMEM as specified by &ipu3_uapi_isp_tnr3_params
+ * @xnr3_dmem_params:  xnr3 DMEM as specified by &ipu3_uapi_isp_xnr3_params
+ * @obgrid_param:      obgrid parameters as specified by
+ *                     &ipu3_uapi_obgrid_param
+ *
+ * The video queue "parameters" is of format V4L2_META_FMT_IPU3_PARAMS.
+ * This is a "single plane" v4l2_meta_format using V4L2_BUF_TYPE_META_OUTPUT.
+ *
+ * struct ipu3_uapi_params as defined below contains a lot of parameters and
+ * ipu3_uapi_flags selects which parameters to apply.
+ */
+struct ipu3_uapi_params {
+       /* Flags which of the settings below are to be applied */
+       struct ipu3_uapi_flags use __attribute__((aligned(32)));
+
+       /* Accelerator cluster parameters */
+       struct ipu3_uapi_acc_param acc_param;
+
+       /* ISP vector address space parameters */
+       struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
+       struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
+       struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
+
+       /* ISP data memory (DMEM) parameters */
+       struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
+       struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
+
+       /* Optical black level compensation */
+       struct ipu3_uapi_obgrid_param obgrid_param;
+} __packed;
+
+#endif /* __IPU3_UAPI_H */
diff --git a/drivers/staging/media/ipu3/ipu3-abi.h b/drivers/staging/media/ipu3/ipu3-abi.h
new file mode 100644 (file)
index 0000000..25be56f
--- /dev/null
@@ -0,0 +1,2011 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_ABI_H
+#define __IPU3_ABI_H
+
+#include "include/intel-ipu3.h"
+
+/******************* IMGU Hardware information *******************/
+
+typedef u32 imgu_addr_t;
+
+#define IMGU_ISP_VMEM_ALIGN                    128
+#define IMGU_DVS_BLOCK_W                       64
+#define IMGU_DVS_BLOCK_H                       32
+#define IMGU_GDC_BUF_X                         (2 * IMGU_DVS_BLOCK_W)
+#define IMGU_GDC_BUF_Y                         IMGU_DVS_BLOCK_H
+/* n = 0..1 */
+#define IMGU_SP_PMEM_BASE(n)                   (0x20000 + (n) * 0x4000)
+#define IMGU_MAX_BQ_GRID_WIDTH                 80
+#define IMGU_MAX_BQ_GRID_HEIGHT                        60
+#define IMGU_OBGRID_TILE_SIZE                  16
+#define IMGU_PIXELS_PER_WORD                   50
+#define IMGU_BYTES_PER_WORD                    64
+#define IMGU_STRIPE_FIXED_HALF_OVERLAP         2
+#define IMGU_SHD_SETS                          3
+#define IMGU_BDS_MIN_CLIP_VAL                  0
+#define IMGU_BDS_MAX_CLIP_VAL                  2
+
+#define IMGU_ABI_AWB_MAX_CELLS_PER_SET         160
+#define IMGU_ABI_AF_MAX_CELLS_PER_SET          32
+#define IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET      32
+
+#define IMGU_ABI_ACC_OP_IDLE                   0
+#define IMGU_ABI_ACC_OP_END_OF_ACK             1
+#define IMGU_ABI_ACC_OP_END_OF_OPS             2
+#define IMGU_ABI_ACC_OP_NO_OPS                 3
+
+#define IMGU_ABI_ACC_OPTYPE_PROCESS_LINES      0
+#define IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA      1
+
+/* Register definitions */
+
+/* PM_CTRL_0_5_0_IMGHMMADR */
+#define IMGU_REG_PM_CTRL                       0x0
+#define IMGU_PM_CTRL_START                     BIT(0)
+#define IMGU_PM_CTRL_CFG_DONE                  BIT(1)
+#define IMGU_PM_CTRL_RACE_TO_HALT              BIT(2)
+#define IMGU_PM_CTRL_NACK_ALL                  BIT(3)
+#define IMGU_PM_CTRL_CSS_PWRDN                 BIT(4)
+#define IMGU_PM_CTRL_RST_AT_EOF                        BIT(5)
+#define IMGU_PM_CTRL_FORCE_HALT                        BIT(6)
+#define IMGU_PM_CTRL_FORCE_UNHALT              BIT(7)
+#define IMGU_PM_CTRL_FORCE_PWRDN               BIT(8)
+#define IMGU_PM_CTRL_FORCE_RESET               BIT(9)
+
+/* SYSTEM_REQ_0_5_0_IMGHMMADR */
+#define IMGU_REG_SYSTEM_REQ                    0x18
+#define IMGU_SYSTEM_REQ_FREQ_MASK              0x3f
+#define IMGU_SYSTEM_REQ_FREQ_DIVIDER           25
+#define IMGU_REG_INT_STATUS                    0x30
+#define IMGU_REG_INT_ENABLE                    0x34
+#define IMGU_REG_INT_CSS_IRQ                   BIT(31)
+/* STATE_0_5_0_IMGHMMADR */
+#define IMGU_REG_STATE                         0x130
+#define IMGU_STATE_HALT_STS                    BIT(0)
+#define IMGU_STATE_IDLE_STS                    BIT(1)
+#define IMGU_STATE_POWER_UP                    BIT(2)
+#define IMGU_STATE_POWER_DOWN                  BIT(3)
+#define IMGU_STATE_CSS_BUSY_MASK               0xc0
+#define IMGU_STATE_PM_FSM_MASK                 0x180
+#define IMGU_STATE_PWRDNM_FSM_MASK             0x1E00000
+/* PM_STS_0_5_0_IMGHMMADR */
+#define IMGU_REG_PM_STS                                0x140
+
+#define IMGU_REG_BASE                          0x4000
+
+#define IMGU_REG_ISP_CTRL                      (IMGU_REG_BASE + 0x00)
+#define IMGU_CTRL_RST                          BIT(0)
+#define IMGU_CTRL_START                                BIT(1)
+#define IMGU_CTRL_BREAK                                BIT(2)
+#define IMGU_CTRL_RUN                          BIT(3)
+#define IMGU_CTRL_BROKEN                       BIT(4)
+#define IMGU_CTRL_IDLE                         BIT(5)
+#define IMGU_CTRL_SLEEPING                     BIT(6)
+#define IMGU_CTRL_STALLING                     BIT(7)
+#define IMGU_CTRL_IRQ_CLEAR                    BIT(8)
+#define IMGU_CTRL_IRQ_READY                    BIT(10)
+#define IMGU_CTRL_IRQ_SLEEPING                 BIT(11)
+#define IMGU_CTRL_ICACHE_INV                   BIT(12)
+#define IMGU_CTRL_IPREFETCH_EN                 BIT(13)
+#define IMGU_REG_ISP_START_ADDR                        (IMGU_REG_BASE + 0x04)
+#define IMGU_REG_ISP_ICACHE_ADDR               (IMGU_REG_BASE + 0x10)
+#define IMGU_REG_ISP_PC                                (IMGU_REG_BASE + 0x1c)
+
+/* SP Registers, sp = 0:SP0; 1:SP1 */
+#define IMGU_REG_SP_CTRL(sp)           (IMGU_REG_BASE + (sp) * 0x100 + 0x100)
+       /* For bits in IMGU_REG_SP_CTRL, see IMGU_CTRL_* */
+#define IMGU_REG_SP_START_ADDR(sp)     (IMGU_REG_BASE + (sp) * 0x100 + 0x104)
+#define IMGU_REG_SP_ICACHE_ADDR(sp)    (IMGU_REG_BASE + (sp) * 0x100 + 0x11c)
+#define IMGU_REG_SP_CTRL_SINK(sp)      (IMGU_REG_BASE + (sp) * 0x100 + 0x130)
+#define IMGU_REG_SP_PC(sp)             (IMGU_REG_BASE + (sp) * 0x100 + 0x134)
+
+#define IMGU_REG_TLB_INVALIDATE                (IMGU_REG_BASE + 0x300)
+#define IMGU_TLB_INVALIDATE                    1
+#define IMGU_REG_L1_PHYS               (IMGU_REG_BASE + 0x304) /* 27-bit pfn */
+
+#define IMGU_REG_CIO_GATE_BURST_STATE  (IMGU_REG_BASE + 0x404)
+#define IMGU_CIO_GATE_BURST_MASK        0x80
+
+#define IMGU_REG_GP_BUSY               (IMGU_REG_BASE + 0x500)
+#define IMGU_REG_GP_STARVING           (IMGU_REG_BASE + 0x504)
+#define IMGU_REG_GP_WORKLOAD           (IMGU_REG_BASE + 0x508)
+#define IMGU_REG_GP_IRQ(n)     (IMGU_REG_BASE + (n) * 4 + 0x50c) /* n = 0..4 */
+#define IMGU_REG_GP_SP1_STRMON_STAT    (IMGU_REG_BASE + 0x520)
+#define IMGU_REG_GP_SP2_STRMON_STAT    (IMGU_REG_BASE + 0x524)
+#define IMGU_REG_GP_ISP_STRMON_STAT    (IMGU_REG_BASE + 0x528)
+#define IMGU_REG_GP_MOD_STRMON_STAT    (IMGU_REG_BASE + 0x52c)
+
+/* Port definitions for the streaming monitors. */
+/* For each definition there is signal pair : valid [bit 0]- accept [bit 1] */
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12DMA           BIT(0)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1           BIT(2)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12SP2           BIT(4)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP22SP1           BIT(6)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12ISP           BIT(8)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1           BIT(10)
+
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22DMA           BIT(0)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_DMA2SP2           BIT(2)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22SP1           BIT(4)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP12SP2           BIT(6)
+
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2DMA           BIT(0)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP           BIT(2)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2SP1           BIT(4)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP           BIT(6)
+
+/* Between the devices and the fifo */
+#define IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA           BIT(0)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2SP1           BIT(2)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_SP22DMA           BIT(4)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2SP2           BIT(6)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA           BIT(8)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2ISP           BIT(10)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC         BIT(12)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS         BIT(14)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2DECOMP      BIT(16)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DECOMP2CELLS      BIT(18)
+/* n = 1..6 */
+#define IMGU_GP_STRMON_STAT_MOD_PORT_S2V(n)    (1 << (((n) - 1) * 2 + 20))
+
+/* n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS_PORT_ACC(n)           (1 << (((n) - 1) * 2))
+
+/* After FIFO and demux before SP1, n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS2SP1_MON_PORT_ACC(n)   (1 << (((n) - 1) * 2))
+
+/* After FIFO and demux before SP2, n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS2SP2_MON_PORT_ACC(n)   (1 << (((n) - 1) * 2))
+
+#define IMGU_REG_GP_HALT                               (IMGU_REG_BASE + 0x5dc)
+
+                                       /* n = 0..2 (main ctrl, SP0, SP1) */
+#define IMGU_REG_IRQCTRL_BASE(n)       (IMGU_REG_BASE + (n) * 0x100 + 0x700)
+#define IMGU_IRQCTRL_MAIN                      0
+#define IMGU_IRQCTRL_SP0                       1
+#define IMGU_IRQCTRL_SP1                       2
+#define IMGU_IRQCTRL_NUM                       3
+#define IMGU_IRQCTRL_IRQ_SP1                   BIT(0)
+#define IMGU_IRQCTRL_IRQ_SP2                   BIT(1)
+#define IMGU_IRQCTRL_IRQ_ISP                   BIT(2)
+#define IMGU_IRQCTRL_IRQ_SP1_STREAM_MON                BIT(3)
+#define IMGU_IRQCTRL_IRQ_SP2_STREAM_MON                BIT(4)
+#define IMGU_IRQCTRL_IRQ_ISP_STREAM_MON                BIT(5)
+#define IMGU_IRQCTRL_IRQ_MOD_STREAM_MON                BIT(6)
+#define IMGU_IRQCTRL_IRQ_MOD_ISP_STREAM_MON    BIT(7)
+#define IMGU_IRQCTRL_IRQ_ACCS_STREAM_MON       BIT(8)
+#define IMGU_IRQCTRL_IRQ_ACCS_SP1_STREAM_MON   BIT(9)
+#define IMGU_IRQCTRL_IRQ_ACCS_SP2_STREAM_MON   BIT(10)
+#define IMGU_IRQCTRL_IRQ_ISP_PMEM_ERROR                BIT(11)
+#define IMGU_IRQCTRL_IRQ_ISP_BAMEM_ERROR       BIT(12)
+#define IMGU_IRQCTRL_IRQ_ISP_VMEM_ERROR                BIT(13)
+#define IMGU_IRQCTRL_IRQ_ISP_DMEM_ERROR                BIT(14)
+#define IMGU_IRQCTRL_IRQ_SP1_ICACHE_MEM_ERROR  BIT(15)
+#define IMGU_IRQCTRL_IRQ_SP1_DMEM_ERROR                BIT(16)
+#define IMGU_IRQCTRL_IRQ_SP2_ICACHE_MEM_ERROR  BIT(17)
+#define IMGU_IRQCTRL_IRQ_SP2_DMEM_ERROR                BIT(18)
+#define IMGU_IRQCTRL_IRQ_ACCS_SCRATCH_MEM_ERROR        BIT(19)
+#define IMGU_IRQCTRL_IRQ_GP_TIMER(n)           BIT(20 + (n)) /* n=0..1 */
+#define IMGU_IRQCTRL_IRQ_DMA                   BIT(22)
+#define IMGU_IRQCTRL_IRQ_SW_PIN(n)             BIT(23 + (n)) /* n=0..4 */
+#define IMGU_IRQCTRL_IRQ_ACC_SYS               BIT(28)
+#define IMGU_IRQCTRL_IRQ_OUT_FORM_IRQ_CTRL     BIT(29)
+#define IMGU_IRQCTRL_IRQ_SP1_IRQ_CTRL          BIT(30)
+#define IMGU_IRQCTRL_IRQ_SP2_IRQ_CTRL          BIT(31)
+#define IMGU_REG_IRQCTRL_EDGE(n)       (IMGU_REG_IRQCTRL_BASE(n) + 0x00)
+#define IMGU_REG_IRQCTRL_MASK(n)       (IMGU_REG_IRQCTRL_BASE(n) + 0x04)
+#define IMGU_REG_IRQCTRL_STATUS(n)     (IMGU_REG_IRQCTRL_BASE(n) + 0x08)
+#define IMGU_REG_IRQCTRL_CLEAR(n)      (IMGU_REG_IRQCTRL_BASE(n) + 0x0c)
+#define IMGU_REG_IRQCTRL_ENABLE(n)     (IMGU_REG_IRQCTRL_BASE(n) + 0x10)
+#define IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(n) (IMGU_REG_IRQCTRL_BASE(n) + 0x14)
+#define IMGU_REG_IRQCTRL_STR_OUT_ENABLE(n) (IMGU_REG_IRQCTRL_BASE(n) + 0x18)
+
+#define IMGU_REG_GP_TIMER              (IMGU_REG_BASE + 0xa34)
+
+#define IMGU_REG_SP_DMEM_BASE(n)       (IMGU_REG_BASE + (n) * 0x4000 + 0x4000)
+#define IMGU_REG_ISP_DMEM_BASE         (IMGU_REG_BASE + 0xc000)
+
+#define IMGU_REG_GDC_BASE              (IMGU_REG_BASE + 0x18000)
+#define IMGU_REG_GDC_LUT_BASE          (IMGU_REG_GDC_BASE + 0x140)
+#define IMGU_GDC_LUT_MASK              ((1 << 12) - 1) /* Range -1024..+1024 */
+
+#define IMGU_SCALER_PHASES                     32
+#define IMGU_SCALER_COEFF_BITS                 24
+#define IMGU_SCALER_PHASE_COUNTER_PREC_REF     6
+#define IMGU_SCALER_MAX_EXPONENT_SHIFT         3
+#define IMGU_SCALER_FILTER_TAPS                        4
+#define IMGU_SCALER_TAPS_Y                     IMGU_SCALER_FILTER_TAPS
+#define IMGU_SCALER_TAPS_UV                    (IMGU_SCALER_FILTER_TAPS / 2)
+#define IMGU_SCALER_FIR_PHASES \
+               (IMGU_SCALER_PHASES << IMGU_SCALER_PHASE_COUNTER_PREC_REF)
+
+/******************* imgu_abi_acc_param *******************/
+
+#define IMGU_ABI_SHD_MAX_PROCESS_LINES         31
+#define IMGU_ABI_SHD_MAX_TRANSFERS             31
+#define IMGU_ABI_SHD_MAX_OPERATIONS \
+               (IMGU_ABI_SHD_MAX_PROCESS_LINES + IMGU_ABI_SHD_MAX_TRANSFERS)
+#define IMGU_ABI_SHD_MAX_CELLS_PER_SET         146
+/* largest grid is 73x56 */
+#define IMGU_ABI_SHD_MAX_CFG_SETS              (2 * 28)
+
+#define IMGU_ABI_DVS_STAT_MAX_OPERATIONS       100
+#define IMGU_ABI_DVS_STAT_MAX_PROCESS_LINES    52
+#define IMGU_ABI_DVS_STAT_MAX_TRANSFERS                52
+
+#define IMGU_ABI_BDS_SAMPLE_PATTERN_ARRAY_SIZE 8
+#define IMGU_ABI_BDS_PHASE_COEFFS_ARRAY_SIZE   32
+
+#define IMGU_ABI_AWB_FR_MAX_TRANSFERS          30
+#define IMGU_ABI_AWB_FR_MAX_PROCESS_LINES      30
+#define IMGU_ABI_AWB_FR_MAX_OPERATIONS \
+       (IMGU_ABI_AWB_FR_MAX_TRANSFERS + IMGU_ABI_AWB_FR_MAX_PROCESS_LINES)
+
+#define IMGU_ABI_AF_MAX_TRANSFERS              30
+#define IMGU_ABI_AF_MAX_PROCESS_LINES          30
+#define IMGU_ABI_AF_MAX_OPERATIONS \
+               (IMGU_ABI_AF_MAX_TRANSFERS + IMGU_ABI_AF_MAX_PROCESS_LINES)
+
+#define IMGU_ABI_AWB_MAX_PROCESS_LINES         68
+#define IMGU_ABI_AWB_MAX_TRANSFERS             68
+#define IMGU_ABI_AWB_MAX_OPERATIONS \
+               (IMGU_ABI_AWB_MAX_PROCESS_LINES + IMGU_ABI_AWB_MAX_TRANSFERS)
+
+#define IMGU_ABI_OSYS_PIN_VF                   0
+#define IMGU_ABI_OSYS_PIN_OUT                  1
+#define IMGU_ABI_OSYS_PINS                     2
+
+#define IMGU_ABI_DVS_STAT_LEVELS               3
+#define IMGU_ABI_YUVP2_YTM_LUT_ENTRIES         256
+#define IMGU_ABI_GDC_FRAC_BITS                 8
+#define IMGU_ABI_BINARY_MAX_OUTPUT_PORTS       2
+#define IMGU_ABI_MAX_BINARY_NAME               64
+#define IMGU_ABI_ISP_DDR_WORD_BITS             256
+#define IMGU_ABI_ISP_DDR_WORD_BYTES    (IMGU_ABI_ISP_DDR_WORD_BITS / 8)
+#define IMGU_ABI_MAX_STAGES                    3
+#define IMGU_ABI_MAX_IF_CONFIGS                        3
+#define IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP       BIT(31)
+#define IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST   BIT(0)
+#define IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST  BIT(4)
+#define IMGU_ABI_MAX_SP_THREADS                        4
+#define IMGU_ABI_FRAMES_REF                    3
+#define IMGU_ABI_FRAMES_TNR                    4
+#define IMGU_ABI_BUF_SETS_TNR                  1
+
+#define IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread, queue)  \
+                               (0 << 24 | (thread) << 16 | (queue) << 8)
+#define IMGU_ABI_EVENT_BUFFER_DEQUEUED(queue)  (1 << 24 | (queue) << 8)
+#define IMGU_ABI_EVENT_EVENT_DEQUEUED          (2 << 24)
+#define IMGU_ABI_EVENT_START_STREAM            (3 << 24)
+#define IMGU_ABI_EVENT_STOP_STREAM             (4 << 24)
+#define IMGU_ABI_EVENT_MIPI_BUFFERS_READY      (5 << 24)
+#define IMGU_ABI_EVENT_UNLOCK_RAW_BUFFER       (6 << 24)
+#define IMGU_ABI_EVENT_STAGE_ENABLE_DISABLE    (7 << 24)
+
+#define IMGU_ABI_HOST2SP_BUFQ_SIZE     3
+#define IMGU_ABI_SP2HOST_BUFQ_SIZE     (2 * IMGU_ABI_MAX_SP_THREADS)
+#define IMGU_ABI_HOST2SP_EVTQ_SIZE     (IMGU_ABI_QUEUE_NUM * \
+               IMGU_ABI_MAX_SP_THREADS * 2 + IMGU_ABI_MAX_SP_THREADS * 4)
+#define IMGU_ABI_SP2HOST_EVTQ_SIZE     (6 * IMGU_ABI_MAX_SP_THREADS)
+
+#define IMGU_ABI_EVTTYPE_EVENT_SHIFT   0
+#define IMGU_ABI_EVTTYPE_EVENT_MASK    (0xff << IMGU_ABI_EVTTYPE_EVENT_SHIFT)
+#define IMGU_ABI_EVTTYPE_PIPE_SHIFT    8
+#define IMGU_ABI_EVTTYPE_PIPE_MASK     (0xff << IMGU_ABI_EVTTYPE_PIPE_SHIFT)
+#define IMGU_ABI_EVTTYPE_PIPEID_SHIFT  16
+#define IMGU_ABI_EVTTYPE_PIPEID_MASK   (0xff << IMGU_ABI_EVTTYPE_PIPEID_SHIFT)
+#define IMGU_ABI_EVTTYPE_MODULEID_SHIFT        8
+#define IMGU_ABI_EVTTYPE_MODULEID_MASK (0xff << IMGU_ABI_EVTTYPE_MODULEID_SHIFT)
+#define IMGU_ABI_EVTTYPE_LINENO_SHIFT  16
+#define IMGU_ABI_EVTTYPE_LINENO_MASK   (0xffff << IMGU_ABI_EVTTYPE_LINENO_SHIFT)
+
+/* Output frame ready */
+#define IMGU_ABI_EVTTYPE_OUT_FRAME_DONE                        0
+/* Second output frame ready */
+#define IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE            1
+/* Viewfinder Output frame ready */
+#define IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE             2
+/* Second viewfinder Output frame ready */
+#define IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE         3
+/* Indication that 3A statistics are available */
+#define IMGU_ABI_EVTTYPE_3A_STATS_DONE                 4
+/* Indication that DIS statistics are available */
+#define IMGU_ABI_EVTTYPE_DIS_STATS_DONE                        5
+/* Pipeline Done event, sent after last pipeline stage */
+#define IMGU_ABI_EVTTYPE_PIPELINE_DONE                 6
+/* Frame tagged */
+#define IMGU_ABI_EVTTYPE_FRAME_TAGGED                  7
+/* Input frame ready */
+#define IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE              8
+/* Metadata ready */
+#define IMGU_ABI_EVTTYPE_METADATA_DONE                 9
+/* Indication that LACE statistics are available */
+#define IMGU_ABI_EVTTYPE_LACE_STATS_DONE               10
+/* Extension stage executed */
+#define IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE            11
+/* Timing measurement data */
+#define IMGU_ABI_EVTTYPE_TIMER                         12
+/* End Of Frame event, sent when in buffered sensor mode */
+#define IMGU_ABI_EVTTYPE_PORT_EOF                      13
+/* Performance warning encountered by FW */
+#define IMGU_ABI_EVTTYPE_FW_WARNING                    14
+/* Assertion hit by FW */
+#define IMGU_ABI_EVTTYPE_FW_ASSERT                     15
+
+#define IMGU_ABI_NUM_CONTINUOUS_FRAMES         10
+#define IMGU_ABI_SP_COMM_COMMAND               0x00
+
+/*
+ * The host2sp_cmd_ready command is the only command written by the SP
+ * It acknowledges that is previous command has been received.
+ * (this does not mean that the command has been executed)
+ * It also indicates that a new command can be send (it is a queue
+ * with depth 1).
+ */
+#define IMGU_ABI_SP_COMM_COMMAND_READY         1
+/* Command written by the Host */
+#define IMGU_ABI_SP_COMM_COMMAND_DUMMY         2       /* No action */
+#define IMGU_ABI_SP_COMM_COMMAND_START_FLASH   3       /* Start the flash */
+#define IMGU_ABI_SP_COMM_COMMAND_TERMINATE     4       /* Terminate */
+
+/* n = 0..IPU3_CSS_PIPE_ID_NUM-1 */
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(n)             ((n) * 4 + 0x60)
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT       0
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_AND_SHIFT      16
+
+#define IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM                1       /* sp_pmem */
+
+/***** For parameter computation *****/
+
+#define IMGU_HIVE_OF_SYS_SCALER_TO_FA_OFFSET   0xC
+#define IMGU_HIVE_OF_SYS_OF_TO_FA_OFFSET       0x8
+#define IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS       32
+
+#define IMGU_SCALER_ELEMS_PER_VEC              0x10
+#define IMGU_SCALER_FILTER_TAPS_Y              0x4
+#define IMGU_SCALER_OUT_BPP                    0x8
+
+#define IMGU_SCALER_MS_TO_OUTFORMACC_SL_ADDR   0x400
+#define IMGU_SCALER_TO_OF_ACK_FA_ADDR \
+       (0xC00  + IMGU_HIVE_OF_SYS_SCALER_TO_FA_OFFSET)
+#define IMGU_OF_TO_ACK_FA_ADDR (0xC00 + IMGU_HIVE_OF_SYS_OF_TO_FA_OFFSET)
+#define IMGU_OUTFORMACC_MS_TO_SCALER_SL_ADDR 0
+#define IMGU_SCALER_INTR_BPP                   10
+
+#define IMGU_PS_SNR_PRESERVE_BITS              3
+#define IMGU_CNTX_BPP                          11
+#define IMGU_SCALER_FILTER_TAPS_UV     (IMGU_SCALER_FILTER_TAPS_Y / 2)
+
+#define IMGU_VMEM2_ELEMS_PER_VEC       (IMGU_SCALER_ELEMS_PER_VEC)
+#define IMGU_STRIDE_Y                  (IMGU_SCALER_FILTER_TAPS_Y + 1)
+#define IMGU_MAX_FRAME_WIDTH           3840
+#define IMGU_VMEM3_ELEMS_PER_VEC       (IMGU_SCALER_ELEMS_PER_VEC)
+
+#define IMGU_VER_CNTX_WORDS            DIV_ROUND_UP((IMGU_SCALER_OUT_BPP + \
+       IMGU_PS_SNR_PRESERVE_BITS), IMGU_CNTX_BPP)      /* 1 */
+#define IMGU_MAX_INPUT_BLOCK_HEIGHT    64
+#define IMGU_HOR_CNTX_WORDS            DIV_ROUND_UP((IMGU_SCALER_INTR_BPP + \
+       IMGU_PS_SNR_PRESERVE_BITS), IMGU_CNTX_BPP)      /* 2 */
+#define IMGU_MAX_OUTPUT_BLOCK_WIDTH            128
+#define IMGU_CNTX_STRIDE_UV            (IMGU_SCALER_FILTER_TAPS_UV + 1)
+
+#define IMGU_OSYS_DMA_CROP_W_LIMIT             64
+#define IMGU_OSYS_DMA_CROP_H_LIMIT             4
+#define IMGU_OSYS_BLOCK_WIDTH                  (2 * IPU3_UAPI_ISP_VEC_ELEMS)
+#define IMGU_OSYS_BLOCK_HEIGHT                 32
+#define IMGU_OSYS_PHASES                       0x20
+#define IMGU_OSYS_FILTER_TAPS                  0x4
+#define IMGU_OSYS_PHASE_COUNTER_PREC_REF       6
+#define IMGU_OSYS_NUM_INPUT_BUFFERS            2
+#define IMGU_OSYS_FIR_PHASES \
+       (IMGU_OSYS_PHASES << IMGU_OSYS_PHASE_COUNTER_PREC_REF)
+#define IMGU_OSYS_TAPS_UV                      (IMGU_OSYS_FILTER_TAPS / 2)
+#define IMGU_OSYS_TAPS_Y                       (IMGU_OSYS_FILTER_TAPS)
+#define IMGU_OSYS_NUM_INTERM_BUFFERS           2
+
+#define IMGU_VMEM1_Y_SIZE \
+       (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
+#define IMGU_VMEM1_UV_SIZE                     (IMGU_VMEM1_Y_SIZE / 4)
+#define IMGU_VMEM1_OUT_BUF_ADDR                        (IMGU_VMEM1_INP_BUF_ADDR + \
+       (IMGU_OSYS_NUM_INPUT_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+#define IMGU_OSYS_NUM_OUTPUT_BUFFERS           2
+
+/* transpose of input height */
+#define IMGU_VMEM2_VECS_PER_LINE \
+       (DIV_ROUND_UP(IMGU_OSYS_BLOCK_HEIGHT, IMGU_VMEM2_ELEMS_PER_VEC))
+/* size in words (vectors)  */
+#define IMGU_VMEM2_BUF_SIZE \
+       (IMGU_VMEM2_VECS_PER_LINE * IMGU_VMEM2_LINES_PER_BLOCK)
+#define IMGU_VMEM3_VER_Y_SIZE  \
+                       ((IMGU_STRIDE_Y * IMGU_MAX_FRAME_WIDTH \
+                        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS)
+#define IMGU_VMEM3_HOR_Y_SIZE \
+       ((IMGU_STRIDE_Y * IMGU_MAX_INPUT_BLOCK_HEIGHT \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_HOR_CNTX_WORDS)
+#define IMGU_VMEM3_VER_Y_EXTRA \
+       ((IMGU_STRIDE_Y * IMGU_MAX_OUTPUT_BLOCK_WIDTH \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS)
+#define IMGU_VMEM3_VER_U_SIZE \
+       (((IMGU_CNTX_STRIDE_UV * IMGU_MAX_FRAME_WIDTH \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_HOR_U_SIZE \
+       (((IMGU_STRIDE_Y * IMGU_MAX_INPUT_BLOCK_HEIGHT \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_HOR_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_VER_U_EXTRA \
+       (((IMGU_CNTX_STRIDE_UV * IMGU_MAX_OUTPUT_BLOCK_WIDTH \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_VER_V_SIZE \
+       (((IMGU_CNTX_STRIDE_UV * IMGU_MAX_FRAME_WIDTH \
+        / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+
+#define IMGU_ISP_VEC_NELEMS            64
+#define IMGU_LUMA_TO_CHROMA_RATIO      2
+#define IMGU_INPUT_BLOCK_WIDTH                 (128)
+#define IMGU_FIFO_ADDR_SCALER_TO_FMT \
+       (IMGU_SCALER_MS_TO_OUTFORMACC_SL_ADDR >> 2)
+#define IMGU_FIFO_ADDR_SCALER_TO_SP    (IMGU_SCALER_TO_OF_ACK_FA_ADDR >> 2)
+#define IMGU_VMEM1_INP_BUF_ADDR                0
+#define IMGU_VMEM1_Y_STRIDE \
+       (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
+#define IMGU_VMEM1_BUF_SIZE    (IMGU_VMEM1_V_OFFSET + IMGU_VMEM1_UV_SIZE)
+
+#define IMGU_VMEM1_U_OFFSET            (IMGU_VMEM1_Y_SIZE)
+#define IMGU_VMEM1_V_OFFSET    (IMGU_VMEM1_U_OFFSET + IMGU_VMEM1_UV_SIZE)
+#define IMGU_VMEM1_UV_STRIDE           (IMGU_VMEM1_Y_STRIDE / 2)
+#define IMGU_VMEM1_INT_BUF_ADDR                (IMGU_VMEM1_OUT_BUF_ADDR + \
+       (IMGU_OSYS_NUM_OUTPUT_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+
+#define IMGU_VMEM1_ELEMS_PER_VEC       (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
+#define IMGU_VMEM2_BUF_Y_ADDR          0
+#define IMGU_VMEM2_BUF_Y_STRIDE                (IMGU_VMEM2_VECS_PER_LINE)
+#define IMGU_VMEM2_BUF_U_ADDR \
+       (IMGU_VMEM2_BUF_Y_ADDR + IMGU_VMEM2_BUF_SIZE)
+#define IMGU_VMEM2_BUF_V_ADDR \
+       (IMGU_VMEM2_BUF_U_ADDR + IMGU_VMEM2_BUF_SIZE / 4)
+#define IMGU_VMEM2_BUF_UV_STRIDE       (IMGU_VMEM2_VECS_PER_LINE / 2)
+/* 1.5 x depth of intermediate buffer */
+#define IMGU_VMEM2_LINES_PER_BLOCK     192
+#define IMGU_VMEM3_HOR_Y_ADDR \
+       (IMGU_VMEM3_VER_Y_ADDR + IMGU_VMEM3_VER_Y_SIZE)
+#define IMGU_VMEM3_HOR_U_ADDR \
+       (IMGU_VMEM3_VER_U_ADDR + IMGU_VMEM3_VER_U_SIZE)
+#define IMGU_VMEM3_HOR_V_ADDR \
+       (IMGU_VMEM3_VER_V_ADDR + IMGU_VMEM3_VER_V_SIZE)
+#define IMGU_VMEM3_VER_Y_ADDR          0
+#define IMGU_VMEM3_VER_U_ADDR \
+       (IMGU_VMEM3_VER_Y_ADDR + IMGU_VMEM3_VER_Y_SIZE + \
+       max(IMGU_VMEM3_HOR_Y_SIZE, IMGU_VMEM3_VER_Y_EXTRA))
+#define IMGU_VMEM3_VER_V_ADDR \
+       (IMGU_VMEM3_VER_U_ADDR + IMGU_VMEM3_VER_U_SIZE + \
+       max(IMGU_VMEM3_HOR_U_SIZE, IMGU_VMEM3_VER_U_EXTRA))
+#define IMGU_FIFO_ADDR_FMT_TO_SP       (IMGU_OF_TO_ACK_FA_ADDR >> 2)
+#define IMGU_FIFO_ADDR_FMT_TO_SCALER (IMGU_OUTFORMACC_MS_TO_SCALER_SL_ADDR >> 2)
+#define IMGU_VMEM1_HST_BUF_ADDR                (IMGU_VMEM1_INT_BUF_ADDR + \
+       (IMGU_OSYS_NUM_INTERM_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+#define IMGU_VMEM1_HST_BUF_STRIDE      120
+#define IMGU_VMEM1_HST_BUF_NLINES      3
+
+enum imgu_abi_frame_format {
+       IMGU_ABI_FRAME_FORMAT_NV11,     /* 12 bit YUV 411, Y, UV plane */
+       IMGU_ABI_FRAME_FORMAT_NV12,     /* 12 bit YUV 420, Y, UV plane */
+       IMGU_ABI_FRAME_FORMAT_NV12_16,  /* 16 bit YUV 420, Y, UV plane */
+       IMGU_ABI_FRAME_FORMAT_NV12_TILEY,/* 12 bit YUV 420,Intel tiled format */
+       IMGU_ABI_FRAME_FORMAT_NV16,     /* 16 bit YUV 422, Y, UV plane */
+       IMGU_ABI_FRAME_FORMAT_NV21,     /* 12 bit YUV 420, Y, VU plane */
+       IMGU_ABI_FRAME_FORMAT_NV61,     /* 16 bit YUV 422, Y, VU plane */
+       IMGU_ABI_FRAME_FORMAT_YV12,     /* 12 bit YUV 420, Y, V, U plane */
+       IMGU_ABI_FRAME_FORMAT_YV16,     /* 16 bit YUV 422, Y, V, U plane */
+       IMGU_ABI_FRAME_FORMAT_YUV420,   /* 12 bit YUV 420, Y, U, V plane */
+       IMGU_ABI_FRAME_FORMAT_YUV420_16,/* yuv420, 16 bits per subpixel */
+       IMGU_ABI_FRAME_FORMAT_YUV422,   /* 16 bit YUV 422, Y, U, V plane */
+       IMGU_ABI_FRAME_FORMAT_YUV422_16,/* yuv422, 16 bits per subpixel */
+       IMGU_ABI_FRAME_FORMAT_UYVY,     /* 16 bit YUV 422, UYVY interleaved */
+       IMGU_ABI_FRAME_FORMAT_YUYV,     /* 16 bit YUV 422, YUYV interleaved */
+       IMGU_ABI_FRAME_FORMAT_YUV444,   /* 24 bit YUV 444, Y, U, V plane */
+       IMGU_ABI_FRAME_FORMAT_YUV_LINE, /* Internal format, 2 y lines */
+                                       /* followed by a uv-interleaved line */
+       IMGU_ABI_FRAME_FORMAT_RAW,      /* RAW, 1 plane */
+       IMGU_ABI_FRAME_FORMAT_RGB565,   /* 16 bit RGB, 1 plane. Each 3 sub
+                                        * pixels are packed into one 16 bit
+                                        * value, 5 bits for R, 6 bits for G
+                                        * and 5 bits for B.
+                                        */
+       IMGU_ABI_FRAME_FORMAT_PLANAR_RGB888, /* 24 bit RGB, 3 planes */
+       IMGU_ABI_FRAME_FORMAT_RGBA888,  /* 32 bit RGBA, 1 plane, A=Alpha
+                                        * (alpha is unused)
+                                        */
+       IMGU_ABI_FRAME_FORMAT_QPLANE6,  /* Internal, for advanced ISP */
+       IMGU_ABI_FRAME_FORMAT_BINARY_8, /* byte stream, used for jpeg. For
+                                        * frames of this type, we set the
+                                        * height to 1 and the width to the
+                                        * number of allocated bytes.
+                                        */
+       IMGU_ABI_FRAME_FORMAT_MIPI,     /* MIPI frame, 1 plane */
+       IMGU_ABI_FRAME_FORMAT_RAW_PACKED,        /* RAW, 1 plane, packed */
+       IMGU_ABI_FRAME_FORMAT_CSI_MIPI_YUV420_8, /* 8 bit per Y/U/V. Y odd line
+                                                 * UYVY interleaved even line
+                                                 */
+       IMGU_ABI_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8, /* Legacy YUV420.
+                                                        * UY odd line;
+                                                        * VY even line
+                                                        */
+       IMGU_ABI_FRAME_FORMAT_CSI_MIPI_YUV420_10,/* 10 bit per Y/U/V. Y odd
+                                                 * line; UYVY interleaved
+                                                 * even line
+                                                 */
+       IMGU_ABI_FRAME_FORMAT_YCGCO444_16, /* Internal format for ISP2.7,
+                                           * 16 bits per plane YUV 444,
+                                           * Y, U, V plane
+                                           */
+       IMGU_ABI_FRAME_FORMAT_NUM
+};
+
+enum imgu_abi_bayer_order {
+       IMGU_ABI_BAYER_ORDER_GRBG,
+       IMGU_ABI_BAYER_ORDER_RGGB,
+       IMGU_ABI_BAYER_ORDER_BGGR,
+       IMGU_ABI_BAYER_ORDER_GBRG
+};
+
+enum imgu_abi_osys_format {
+       IMGU_ABI_OSYS_FORMAT_YUV420,
+       IMGU_ABI_OSYS_FORMAT_YV12,
+       IMGU_ABI_OSYS_FORMAT_NV12,
+       IMGU_ABI_OSYS_FORMAT_NV21,
+       IMGU_ABI_OSYS_FORMAT_YUV_LINE,
+       IMGU_ABI_OSYS_FORMAT_YUY2,      /* = IMGU_ABI_OSYS_FORMAT_YUYV */
+       IMGU_ABI_OSYS_FORMAT_NV16,
+       IMGU_ABI_OSYS_FORMAT_RGBA,
+       IMGU_ABI_OSYS_FORMAT_BGRA
+};
+
+enum imgu_abi_osys_tiling {
+       IMGU_ABI_OSYS_TILING_NONE,
+       IMGU_ABI_OSYS_TILING_Y,
+       IMGU_ABI_OSYS_TILING_YF,
+};
+
+enum imgu_abi_osys_procmode {
+       IMGU_ABI_OSYS_PROCMODE_BYPASS,
+       IMGU_ABI_OSYS_PROCMODE_UPSCALE,
+       IMGU_ABI_OSYS_PROCMODE_DOWNSCALE,
+};
+
+enum imgu_abi_queue_id {
+       IMGU_ABI_QUEUE_EVENT_ID = -1,
+       IMGU_ABI_QUEUE_A_ID = 0,
+       IMGU_ABI_QUEUE_B_ID,
+       IMGU_ABI_QUEUE_C_ID,
+       IMGU_ABI_QUEUE_D_ID,
+       IMGU_ABI_QUEUE_E_ID,
+       IMGU_ABI_QUEUE_F_ID,
+       IMGU_ABI_QUEUE_G_ID,
+       IMGU_ABI_QUEUE_H_ID,            /* input frame queue for skycam */
+       IMGU_ABI_QUEUE_NUM
+};
+
+enum imgu_abi_buffer_type {
+       IMGU_ABI_BUFFER_TYPE_INVALID = -1,
+       IMGU_ABI_BUFFER_TYPE_3A_STATISTICS = 0,
+       IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS,
+       IMGU_ABI_BUFFER_TYPE_LACE_STATISTICS,
+       IMGU_ABI_BUFFER_TYPE_INPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_SEC_OUTPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_RAW_OUTPUT_FRAME,
+       IMGU_ABI_BUFFER_TYPE_CUSTOM_INPUT,
+       IMGU_ABI_BUFFER_TYPE_CUSTOM_OUTPUT,
+       IMGU_ABI_BUFFER_TYPE_METADATA,
+       IMGU_ABI_BUFFER_TYPE_PARAMETER_SET,
+       IMGU_ABI_BUFFER_TYPE_PER_FRAME_PARAMETER_SET,
+       IMGU_ABI_NUM_DYNAMIC_BUFFER_TYPE,
+       IMGU_ABI_NUM_BUFFER_TYPE
+};
+
+enum imgu_abi_raw_type {
+       IMGU_ABI_RAW_TYPE_BAYER,
+       IMGU_ABI_RAW_TYPE_IR_ON_GR,
+       IMGU_ABI_RAW_TYPE_IR_ON_GB
+};
+
+enum imgu_abi_memories {
+       IMGU_ABI_MEM_ISP_PMEM0 = 0,
+       IMGU_ABI_MEM_ISP_DMEM0,
+       IMGU_ABI_MEM_ISP_VMEM0,
+       IMGU_ABI_MEM_ISP_VAMEM0,
+       IMGU_ABI_MEM_ISP_VAMEM1,
+       IMGU_ABI_MEM_ISP_VAMEM2,
+       IMGU_ABI_MEM_ISP_HMEM0,
+       IMGU_ABI_MEM_SP0_DMEM0,
+       IMGU_ABI_MEM_SP1_DMEM0,
+       IMGU_ABI_MEM_DDR,
+       IMGU_ABI_NUM_MEMORIES
+};
+
+enum imgu_abi_param_class {
+       IMGU_ABI_PARAM_CLASS_PARAM,     /* Late binding parameters, like 3A */
+       IMGU_ABI_PARAM_CLASS_CONFIG,    /* Pipe config time parameters */
+       IMGU_ABI_PARAM_CLASS_STATE,     /* State parameters, eg. buffer index */
+       IMGU_ABI_PARAM_CLASS_NUM
+};
+
+enum imgu_abi_bin_input_src {
+       IMGU_ABI_BINARY_INPUT_SOURCE_SENSOR,
+       IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY,
+       IMGU_ABI_BINARY_INPUT_SOURCE_VARIABLE,
+};
+
+enum imgu_abi_sp_swstate {
+       IMGU_ABI_SP_SWSTATE_TERMINATED,
+       IMGU_ABI_SP_SWSTATE_INITIALIZED,
+       IMGU_ABI_SP_SWSTATE_CONNECTED,
+       IMGU_ABI_SP_SWSTATE_RUNNING,
+};
+
+enum imgu_abi_bl_swstate {
+       IMGU_ABI_BL_SWSTATE_OK = 0x100,
+       IMGU_ABI_BL_SWSTATE_BUSY,
+       IMGU_ABI_BL_SWSTATE_ERR,
+};
+
+/* The type of pipe stage */
+enum imgu_abi_stage_type {
+       IMGU_ABI_STAGE_TYPE_SP,
+       IMGU_ABI_STAGE_TYPE_ISP,
+};
+
+struct imgu_abi_acc_operation {
+       /*
+        * zero means on init,
+        * others mean upon receiving an ack signal from the BC acc.
+        */
+       u8 op_indicator;
+       u8 op_type;
+} __packed;
+
+struct imgu_abi_acc_process_lines_cmd_data {
+       u16 lines;
+       u8 cfg_set;
+       u8 reserved;            /* Align to 4 bytes */
+} __packed;
+
+/* Bayer shading definitions */
+
+struct imgu_abi_shd_transfer_luts_set_data {
+       u8 set_number;
+       u8 padding[3];
+       imgu_addr_t rg_lut_ddr_addr;
+       imgu_addr_t bg_lut_ddr_addr;
+       u32 align_dummy;
+} __packed;
+
+struct imgu_abi_shd_grid_config {
+       /* reg 0 */
+       u32 grid_width:8;
+       u32 grid_height:8;
+       u32 block_width:3;
+       u32 reserved0:1;
+       u32 block_height:3;
+       u32 reserved1:1;
+       u32 grid_height_per_slice:8;
+       /* reg 1 */
+       s32 x_start:13;
+       s32 reserved2:3;
+       s32 y_start:13;
+       s32 reserved3:3;
+} __packed;
+
+struct imgu_abi_shd_general_config {
+       u32 init_set_vrt_offst_ul:8;
+       u32 shd_enable:1;
+       /* aka 'gf' */
+       u32 gain_factor:2;
+       u32 reserved:21;
+} __packed;
+
+struct imgu_abi_shd_black_level_config {
+       /* reg 0 */
+       s32 bl_r:12;
+       s32 reserved0:4;
+       s32 bl_gr:12;
+       u32 reserved1:1;
+       /* aka 'nf' */
+       u32 normalization_shift:3;
+       /* reg 1 */
+       s32 bl_gb:12;
+       s32 reserved2:4;
+       s32 bl_b:12;
+       s32 reserved3:4;
+} __packed;
+
+struct imgu_abi_shd_intra_frame_operations_data {
+       struct imgu_abi_acc_operation
+               operation_list[IMGU_ABI_SHD_MAX_OPERATIONS] __aligned(32);
+       struct imgu_abi_acc_process_lines_cmd_data
+               process_lines_data[IMGU_ABI_SHD_MAX_PROCESS_LINES] __aligned(32);
+       struct imgu_abi_shd_transfer_luts_set_data
+               transfer_data[IMGU_ABI_SHD_MAX_TRANSFERS] __aligned(32);
+} __packed;
+
+struct imgu_abi_shd_config {
+       struct ipu3_uapi_shd_config_static shd __aligned(32);
+       struct imgu_abi_shd_intra_frame_operations_data shd_ops __aligned(32);
+       struct ipu3_uapi_shd_lut shd_lut __aligned(32);
+} __packed;
+
+struct imgu_abi_stripe_input_frame_resolution {
+       u16 width;
+       u16 height;
+       u32 bayer_order;                /* enum ipu3_uapi_bayer_order */
+       u32 raw_bit_depth;
+} __packed;
+
+/* Stripe-based processing */
+
+struct imgu_abi_stripes {
+       /* offset from start of frame - measured in pixels */
+       u16 offset;
+       /* stripe width - measured in pixels */
+       u16 width;
+       /* stripe width - measured in pixels */
+       u16 height;
+} __packed;
+
+struct imgu_abi_stripe_data {
+       /*
+        * number of stripes for current processing source
+        * - VLIW binary parameter we currently support 1 or 2 stripes
+        */
+       u16 num_of_stripes;
+
+       u8 padding[2];
+
+       /*
+        * the following data is derived from resolution-related
+        * pipe config and from num_of_stripes
+        */
+
+       /*
+        *'input-stripes' - before input cropping
+        * used by input feeder
+        */
+       struct imgu_abi_stripe_input_frame_resolution input_frame;
+
+       /*'effective-stripes' - after input cropping used dpc, bds */
+       struct imgu_abi_stripes effective_stripes[IPU3_UAPI_MAX_STRIPES];
+
+       /* 'down-scaled-stripes' - after down-scaling ONLY. used by BDS */
+       struct imgu_abi_stripes down_scaled_stripes[IPU3_UAPI_MAX_STRIPES];
+
+       /*
+        *'bds-out-stripes' - after bayer down-scaling and padding.
+        * used by all algos starting with norm up to the ref-frame for GDC
+        * (currently up to the output kernel)
+        */
+       struct imgu_abi_stripes bds_out_stripes[IPU3_UAPI_MAX_STRIPES];
+
+       /* 'bds-out-stripes (no overlap)' - used for ref kernel */
+       struct imgu_abi_stripes
+                       bds_out_stripes_no_overlap[IPU3_UAPI_MAX_STRIPES];
+
+       /*
+        * input resolution for output system (equal to bds_out - envelope)
+        * output-system input frame width as configured by user
+        */
+       u16 output_system_in_frame_width;
+       /* output-system input frame height as configured by user */
+       u16 output_system_in_frame_height;
+
+       /*
+        * 'output-stripes' - accounts for stiching on the output (no overlap)
+        * used by the output kernel
+        */
+       struct imgu_abi_stripes output_stripes[IPU3_UAPI_MAX_STRIPES];
+
+       /*
+        * 'block-stripes' - accounts for stiching by the output system
+        * (1 or more blocks overlap)
+        * used by DVS, TNR and the output system kernel
+        */
+       struct imgu_abi_stripes block_stripes[IPU3_UAPI_MAX_STRIPES];
+
+       u16 effective_frame_width;      /* Needed for vertical cropping */
+       u16 bds_frame_width;
+       u16 out_frame_width;    /* Output frame width as configured by user */
+       u16 out_frame_height;   /* Output frame height as configured by user */
+
+       /* GDC in buffer (A.K.A delay frame,ref buffer) info */
+       u16 gdc_in_buffer_width;        /* GDC in buffer width  */
+       u16 gdc_in_buffer_height;       /* GDC in buffer height */
+       /* GDC in buffer first valid pixel x offset */
+       u16 gdc_in_buffer_offset_x;
+       /* GDC in buffer first valid pixel y offset */
+       u16 gdc_in_buffer_offset_y;
+
+       /* Display frame width as configured by user */
+       u16 display_frame_width;
+       /* Display frame height as configured by user */
+       u16 display_frame_height;
+       u16 bds_aligned_frame_width;
+       /* Number of vectors to left-crop when writing stripes (not stripe 0) */
+       u16 half_overlap_vectors;
+       /* Decimate ISP and fixed func resolutions after BDS (ir_extraction) */
+       u16 ir_ext_decimation;
+       u8 padding1[2];
+} __packed;
+
+/* Input feeder related structs */
+
+struct imgu_abi_input_feeder_data {
+       u32 row_stride;                 /* row stride */
+       u32 start_row_address;          /* start row address */
+       u32 start_pixel;                /* start pixel */
+} __packed;
+
+struct imgu_abi_input_feeder_data_aligned {
+       struct imgu_abi_input_feeder_data data __aligned(32);
+} __packed;
+
+struct imgu_abi_input_feeder_data_per_stripe {
+       struct imgu_abi_input_feeder_data_aligned
+               input_feeder_data[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct imgu_abi_input_feeder_config {
+       struct imgu_abi_input_feeder_data data;
+       struct imgu_abi_input_feeder_data_per_stripe data_per_stripe
+               __aligned(32);
+} __packed;
+
+/* DVS related definitions */
+
+struct imgu_abi_dvs_stat_grd_config {
+       u8 grid_width;
+       u8 grid_height;
+       u8 block_width;
+       u8 block_height;
+       u16 x_start;
+       u16 y_start;
+       u16 enable;
+       u16 x_end;
+       u16 y_end;
+} __packed;
+
+struct imgu_abi_dvs_stat_cfg {
+       u8 reserved0[4];
+       struct imgu_abi_dvs_stat_grd_config
+                                       grd_config[IMGU_ABI_DVS_STAT_LEVELS];
+       u8 reserved1[18];
+} __packed;
+
+struct imgu_abi_dvs_stat_transfer_op_data {
+       u8 set_number;
+} __packed;
+
+struct imgu_abi_dvs_stat_intra_frame_operations_data {
+       struct imgu_abi_acc_operation
+               ops[IMGU_ABI_DVS_STAT_MAX_OPERATIONS] __aligned(32);
+       struct imgu_abi_acc_process_lines_cmd_data
+               process_lines_data[IMGU_ABI_DVS_STAT_MAX_PROCESS_LINES]
+               __aligned(32);
+       struct imgu_abi_dvs_stat_transfer_op_data
+               transfer_data[IMGU_ABI_DVS_STAT_MAX_TRANSFERS] __aligned(32);
+} __packed;
+
+struct imgu_abi_dvs_stat_config {
+       struct imgu_abi_dvs_stat_cfg cfg __aligned(32);
+       u8 reserved0[128];
+       struct imgu_abi_dvs_stat_intra_frame_operations_data operations_data;
+       u8 reserved1[64];
+} __packed;
+
+/* Y-tone Mapping */
+
+struct imgu_abi_yuvp2_y_tm_lut_static_config {
+       u16 entries[IMGU_ABI_YUVP2_YTM_LUT_ENTRIES];
+       u32 enable;
+} __packed;
+
+/* Output formatter related structs */
+
+struct imgu_abi_osys_formatter_params {
+       u32 format;
+       u32 flip;
+       u32 mirror;
+       u32 tiling;
+       u32 reduce_range;
+       u32 alpha_blending;
+       u32 release_inp_addr;
+       u32 release_inp_en;
+       u32 process_out_buf_addr;
+       u32 image_width_vecs;
+       u32 image_height_lines;
+       u32 inp_buff_y_st_addr;
+       u32 inp_buff_y_line_stride;
+       u32 inp_buff_y_buffer_stride;
+       u32 int_buff_u_st_addr;
+       u32 int_buff_v_st_addr;
+       u32 inp_buff_uv_line_stride;
+       u32 inp_buff_uv_buffer_stride;
+       u32 out_buff_level;
+       u32 out_buff_nr_y_lines;
+       u32 out_buff_u_st_offset;
+       u32 out_buff_v_st_offset;
+       u32 out_buff_y_line_stride;
+       u32 out_buff_uv_line_stride;
+       u32 hist_buff_st_addr;
+       u32 hist_buff_line_stride;
+       u32 hist_buff_nr_lines;
+} __packed;
+
+struct imgu_abi_osys_formatter {
+       struct imgu_abi_osys_formatter_params param __aligned(32);
+} __packed;
+
+struct imgu_abi_osys_scaler_params {
+       u32 inp_buf_y_st_addr;
+       u32 inp_buf_y_line_stride;
+       u32 inp_buf_y_buffer_stride;
+       u32 inp_buf_u_st_addr;
+       u32 inp_buf_v_st_addr;
+       u32 inp_buf_uv_line_stride;
+       u32 inp_buf_uv_buffer_stride;
+       u32 inp_buf_chunk_width;
+       u32 inp_buf_nr_buffers;
+       /* Output buffers */
+       u32 out_buf_y_st_addr;
+       u32 out_buf_y_line_stride;
+       u32 out_buf_y_buffer_stride;
+       u32 out_buf_u_st_addr;
+       u32 out_buf_v_st_addr;
+       u32 out_buf_uv_line_stride;
+       u32 out_buf_uv_buffer_stride;
+       u32 out_buf_nr_buffers;
+       /* Intermediate buffers */
+       u32 int_buf_y_st_addr;
+       u32 int_buf_y_line_stride;
+       u32 int_buf_u_st_addr;
+       u32 int_buf_v_st_addr;
+       u32 int_buf_uv_line_stride;
+       u32 int_buf_height;
+       u32 int_buf_chunk_width;
+       u32 int_buf_chunk_height;
+       /* Context buffers */
+       u32 ctx_buf_hor_y_st_addr;
+       u32 ctx_buf_hor_u_st_addr;
+       u32 ctx_buf_hor_v_st_addr;
+       u32 ctx_buf_ver_y_st_addr;
+       u32 ctx_buf_ver_u_st_addr;
+       u32 ctx_buf_ver_v_st_addr;
+       /* Addresses for release-input and process-output tokens */
+       u32 release_inp_buf_addr;
+       u32 release_inp_buf_en;
+       u32 release_out_buf_en;
+       u32 process_out_buf_addr;
+       /* Settings dimensions, padding, cropping */
+       u32 input_image_y_width;
+       u32 input_image_y_height;
+       u32 input_image_y_start_column;
+       u32 input_image_uv_start_column;
+       u32 input_image_y_left_pad;
+       u32 input_image_uv_left_pad;
+       u32 input_image_y_right_pad;
+       u32 input_image_uv_right_pad;
+       u32 input_image_y_top_pad;
+       u32 input_image_uv_top_pad;
+       u32 input_image_y_bottom_pad;
+       u32 input_image_uv_bottom_pad;
+       u32 processing_mode;    /* enum imgu_abi_osys_procmode */
+       u32 scaling_ratio;
+       u32 y_left_phase_init;
+       u32 uv_left_phase_init;
+       u32 y_top_phase_init;
+       u32 uv_top_phase_init;
+       u32 coeffs_exp_shift;
+       u32 out_y_left_crop;
+       u32 out_uv_left_crop;
+       u32 out_y_top_crop;
+       u32 out_uv_top_crop;
+} __packed;
+
+struct imgu_abi_osys_scaler {
+       struct imgu_abi_osys_scaler_params param __aligned(32);
+} __packed;
+
+struct imgu_abi_osys_frame_params {
+       /* Output pins */
+       u32 enable;
+       u32 format;             /* enum imgu_abi_osys_format */
+       u32 flip;
+       u32 mirror;
+       u32 tiling;             /* enum imgu_abi_osys_tiling */
+       u32 width;
+       u32 height;
+       u32 stride;
+       u32 scaled;
+} __packed;
+
+struct imgu_abi_osys_frame {
+       struct imgu_abi_osys_frame_params param __aligned(32);
+} __packed;
+
+struct imgu_abi_osys_stripe {
+       /* Input resolution */
+       u32 input_width;
+       u32 input_height;
+       /* Output Stripe */
+       u32 output_width[IMGU_ABI_OSYS_PINS];
+       u32 output_height[IMGU_ABI_OSYS_PINS];
+       u32 output_offset[IMGU_ABI_OSYS_PINS];
+       u32 buf_stride[IMGU_ABI_OSYS_PINS];
+       /* Scaler params */
+       u32 block_width;
+       u32 block_height;
+       /* Output Crop factor */
+       u32 crop_top[IMGU_ABI_OSYS_PINS];
+       u32 crop_left[IMGU_ABI_OSYS_PINS];
+} __packed;
+
+struct imgu_abi_osys_config {
+       struct imgu_abi_osys_formatter
+               formatter[IPU3_UAPI_MAX_STRIPES][IMGU_ABI_OSYS_PINS];
+       struct imgu_abi_osys_scaler scaler[IPU3_UAPI_MAX_STRIPES];
+       struct imgu_abi_osys_frame frame[IMGU_ABI_OSYS_PINS];
+       struct imgu_abi_osys_stripe stripe[IPU3_UAPI_MAX_STRIPES];
+       /* 32 packed coefficients for luma and chroma */
+       s8 scaler_coeffs_chroma[128];
+       s8 scaler_coeffs_luma[128];
+} __packed;
+
+/* BDS */
+
+struct imgu_abi_bds_hor_ctrl0 {
+       u32 sample_patrn_length:9;
+       u32 reserved0:3;
+       u32 hor_ds_en:1;
+       u32 min_clip_val:1;
+       u32 max_clip_val:2;
+       u32 out_frame_width:13;
+       u32 reserved1:3;
+} __packed;
+
+struct imgu_abi_bds_ptrn_arr {
+       u32 elems[IMGU_ABI_BDS_SAMPLE_PATTERN_ARRAY_SIZE];
+} __packed;
+
+struct imgu_abi_bds_phase_entry {
+       s8 coeff_min2;
+       s8 coeff_min1;
+       s8 coeff_0;
+       s8 nf;
+       s8 coeff_pls1;
+       s8 coeff_pls2;
+       s8 coeff_pls3;
+       u8 reserved;
+} __packed;
+
+struct imgu_abi_bds_phase_arr {
+       struct imgu_abi_bds_phase_entry
+               even[IMGU_ABI_BDS_PHASE_COEFFS_ARRAY_SIZE];
+       struct imgu_abi_bds_phase_entry
+               odd[IMGU_ABI_BDS_PHASE_COEFFS_ARRAY_SIZE];
+} __packed;
+
+struct imgu_abi_bds_hor_ctrl1 {
+       u32 hor_crop_start:13;
+       u32 reserved0:3;
+       u32 hor_crop_end:13;
+       u32 reserved1:1;
+       u32 hor_crop_en:1;
+       u32 reserved2:1;
+} __packed;
+
+struct imgu_abi_bds_hor_ctrl2 {
+       u32 input_frame_height:13;
+       u32 reserved0:19;
+} __packed;
+
+struct imgu_abi_bds_hor {
+       struct imgu_abi_bds_hor_ctrl0 hor_ctrl0;
+       struct imgu_abi_bds_ptrn_arr hor_ptrn_arr;
+       struct imgu_abi_bds_phase_arr hor_phase_arr;
+       struct imgu_abi_bds_hor_ctrl1 hor_ctrl1;
+       struct imgu_abi_bds_hor_ctrl2 hor_ctrl2;
+} __packed;
+
+struct imgu_abi_bds_ver_ctrl0 {
+       u32 sample_patrn_length:9;
+       u32 reserved0:3;
+       u32 ver_ds_en:1;
+       u32 min_clip_val:1;
+       u32 max_clip_val:2;
+       u32 reserved1:16;
+} __packed;
+
+struct imgu_abi_bds_ver_ctrl1 {
+       u32 out_frame_width:13;
+       u32 reserved0:3;
+       u32 out_frame_height:13;
+       u32 reserved1:3;
+} __packed;
+
+struct imgu_abi_bds_ver {
+       struct imgu_abi_bds_ver_ctrl0 ver_ctrl0;
+       struct imgu_abi_bds_ptrn_arr ver_ptrn_arr;
+       struct imgu_abi_bds_phase_arr ver_phase_arr;
+       struct imgu_abi_bds_ver_ctrl1 ver_ctrl1;
+} __packed;
+
+struct imgu_abi_bds_per_stripe_data {
+       struct imgu_abi_bds_hor_ctrl0 hor_ctrl0;
+       struct imgu_abi_bds_ver_ctrl1 ver_ctrl1;
+       struct imgu_abi_bds_hor_ctrl1 crop;
+} __packed;
+
+struct imgu_abi_bds_per_stripe_data_aligned {
+       struct imgu_abi_bds_per_stripe_data data __aligned(32);
+} __packed;
+
+struct imgu_abi_bds_per_stripe {
+       struct imgu_abi_bds_per_stripe_data_aligned
+               aligned_data[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct imgu_abi_bds_config {
+       struct imgu_abi_bds_hor hor __aligned(32);
+       struct imgu_abi_bds_ver ver __aligned(32);
+       struct imgu_abi_bds_per_stripe per_stripe __aligned(32);
+       u32 enabled;
+} __packed;
+
+/* ANR */
+
+struct imgu_abi_anr_search_config {
+       u32 enable;
+       u16 frame_width;
+       u16 frame_height;
+} __packed;
+
+struct imgu_abi_anr_stitch_config {
+       u32 anr_stitch_en;
+       u16 frame_width;
+       u16 frame_height;
+       u8 reserved[40];
+       struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE];
+} __packed;
+
+struct imgu_abi_anr_tile2strm_config {
+       u32 enable;
+       u16 frame_width;
+       u16 frame_height;
+} __packed;
+
+struct imgu_abi_anr_config {
+       struct imgu_abi_anr_search_config search __aligned(32);
+       struct ipu3_uapi_anr_transform_config transform __aligned(32);
+       struct imgu_abi_anr_stitch_config stitch __aligned(32);
+       struct imgu_abi_anr_tile2strm_config tile2strm __aligned(32);
+} __packed;
+
+/* AF */
+
+struct imgu_abi_af_frame_size {
+       u16 width;
+       u16 height;
+} __packed;
+
+struct imgu_abi_af_config_s {
+       struct ipu3_uapi_af_filter_config filter_config __aligned(32);
+       struct imgu_abi_af_frame_size frame_size;
+       struct ipu3_uapi_grid_config grid_cfg __aligned(32);
+} __packed;
+
+struct imgu_abi_af_intra_frame_operations_data {
+       struct imgu_abi_acc_operation ops[IMGU_ABI_AF_MAX_OPERATIONS]
+               __aligned(32);
+       struct imgu_abi_acc_process_lines_cmd_data
+               process_lines_data[IMGU_ABI_AF_MAX_PROCESS_LINES] __aligned(32);
+} __packed;
+
+struct imgu_abi_af_stripe_config {
+       struct imgu_abi_af_frame_size frame_size __aligned(32);
+       struct ipu3_uapi_grid_config grid_cfg __aligned(32);
+} __packed;
+
+struct imgu_abi_af_config {
+       struct imgu_abi_af_config_s config;
+       struct imgu_abi_af_intra_frame_operations_data operations_data;
+       struct imgu_abi_af_stripe_config stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+/* AE */
+
+struct imgu_abi_ae_config {
+       struct ipu3_uapi_ae_grid_config grid_cfg __aligned(32);
+       struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
+                                                               __aligned(32);
+       struct ipu3_uapi_ae_ccm ae_ccm __aligned(32);
+       struct {
+               struct ipu3_uapi_ae_grid_config grid __aligned(32);
+       } stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+/* AWB_FR */
+
+struct imgu_abi_awb_fr_intra_frame_operations_data {
+       struct imgu_abi_acc_operation ops[IMGU_ABI_AWB_FR_MAX_OPERATIONS]
+                                                               __aligned(32);
+       struct imgu_abi_acc_process_lines_cmd_data
+             process_lines_data[IMGU_ABI_AWB_FR_MAX_PROCESS_LINES] __aligned(32);
+} __packed;
+
+struct imgu_abi_awb_fr_config {
+       struct ipu3_uapi_awb_fr_config_s config;
+       struct imgu_abi_awb_fr_intra_frame_operations_data operations_data;
+       struct ipu3_uapi_awb_fr_config_s stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct imgu_abi_acc_transfer_op_data {
+       u8 set_number;
+} __packed;
+
+struct imgu_abi_awb_intra_frame_operations_data {
+       struct imgu_abi_acc_operation ops[IMGU_ABI_AWB_MAX_OPERATIONS]
+               __aligned(32);
+       struct imgu_abi_acc_process_lines_cmd_data
+               process_lines_data[IMGU_ABI_AWB_MAX_PROCESS_LINES] __aligned(32);
+       struct imgu_abi_acc_transfer_op_data
+               transfer_data[IMGU_ABI_AWB_MAX_TRANSFERS] __aligned(32);
+} __aligned(32) __packed;
+
+struct imgu_abi_awb_config {
+       struct ipu3_uapi_awb_config_s config __aligned(32);
+       struct imgu_abi_awb_intra_frame_operations_data operations_data;
+       struct ipu3_uapi_awb_config_s stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct imgu_abi_acc_param {
+       struct imgu_abi_stripe_data stripe;
+       u8 padding[8];
+       struct imgu_abi_input_feeder_config input_feeder;
+       struct ipu3_uapi_bnr_static_config bnr;
+       struct ipu3_uapi_bnr_static_config_green_disparity green_disparity
+               __aligned(32);
+       struct ipu3_uapi_dm_config dm __aligned(32);
+       struct ipu3_uapi_ccm_mat_config ccm __aligned(32);
+       struct ipu3_uapi_gamma_config gamma __aligned(32);
+       struct ipu3_uapi_csc_mat_config csc __aligned(32);
+       struct ipu3_uapi_cds_params cds __aligned(32);
+       struct imgu_abi_shd_config shd __aligned(32);
+       struct imgu_abi_dvs_stat_config dvs_stat;
+       u8 padding1[224];       /* reserved for lace_stat */
+       struct ipu3_uapi_yuvp1_iefd_config iefd __aligned(32);
+       struct ipu3_uapi_yuvp1_yds_config yds_c0 __aligned(32);
+       struct ipu3_uapi_yuvp1_chnr_config chnr_c0 __aligned(32);
+       struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr __aligned(32);
+       struct ipu3_uapi_yuvp1_yds_config yds __aligned(32);
+       struct ipu3_uapi_yuvp1_chnr_config chnr __aligned(32);
+       struct imgu_abi_yuvp2_y_tm_lut_static_config ytm __aligned(32);
+       struct ipu3_uapi_yuvp1_yds_config yds2 __aligned(32);
+       struct ipu3_uapi_yuvp2_tcc_static_config tcc __aligned(32);
+       /* reserved for defect pixel correction */
+       u8 dpc[240832] __aligned(32);
+       struct imgu_abi_bds_config bds;
+       struct imgu_abi_anr_config anr;
+       struct imgu_abi_awb_fr_config awb_fr;
+       struct imgu_abi_ae_config ae;
+       struct imgu_abi_af_config af;
+       struct imgu_abi_awb_config awb;
+       struct imgu_abi_osys_config osys;
+} __packed;
+
+/***** Morphing table entry *****/
+
+struct imgu_abi_gdc_warp_param {
+       u32 origin_x;
+       u32 origin_y;
+       u32 in_addr_offset;
+       u32 in_block_width;
+       u32 in_block_height;
+       u32 p0_x;
+       u32 p0_y;
+       u32 p1_x;
+       u32 p1_y;
+       u32 p2_x;
+       u32 p2_y;
+       u32 p3_x;
+       u32 p3_y;
+       u32 in_block_width_a;
+       u32 in_block_width_b;
+       u32 padding;            /* struct size multiple of DDR word */
+} __packed;
+
+/******************* Firmware ABI definitions *******************/
+
+/***** struct imgu_abi_sp_stage *****/
+
+struct imgu_abi_crop_pos {
+       u16 x;
+       u16 y;
+} __packed;
+
+struct imgu_abi_sp_resolution {
+       u16 width;                      /* Width of valid data in pixels */
+       u16 height;                     /* Height of valid data in lines */
+} __packed;
+
+/*
+ * Frame info struct. This describes the contents of an image frame buffer.
+ */
+struct imgu_abi_frame_sp_info {
+       struct imgu_abi_sp_resolution res;
+       u16 padded_width;               /* stride of line in memory
+                                        * (in pixels)
+                                        */
+       u8 format;                      /* format of the frame data */
+       u8 raw_bit_depth;               /* number of valid bits per pixel,
+                                        * only valid for RAW bayer frames
+                                        */
+       u8 raw_bayer_order;             /* bayer order, only valid
+                                        * for RAW bayer frames
+                                        */
+       u8 raw_type;            /* To choose the proper raw frame type. for
+                                * Legacy SKC pipes/Default is set to
+                                * IMGU_ABI_RAW_TYPE_BAYER. For RGB IR sensor -
+                                * driver should set it to:
+                                * IronGr case - IMGU_ABI_RAW_TYPE_IR_ON_GR
+                                * IronGb case - IMGU_ABI_RAW_TYPE_IR_ON_GB
+                                */
+       u8 padding[2];                  /* Extend to 32 bit multiple */
+} __packed;
+
+struct imgu_abi_buffer_sp {
+       union {
+               imgu_addr_t xmem_addr;
+               s32 queue_id;   /* enum imgu_abi_queue_id */
+       } buf_src;
+       s32 buf_type;   /* enum imgu_abi_buffer_type */
+} __packed;
+
+struct imgu_abi_frame_sp_plane {
+       u32 offset;             /* offset in bytes to start of frame data */
+                               /* offset is wrt data in imgu_abi_sp_sp_frame */
+} __packed;
+
+struct imgu_abi_frame_sp_rgb_planes {
+       struct imgu_abi_frame_sp_plane r;
+       struct imgu_abi_frame_sp_plane g;
+       struct imgu_abi_frame_sp_plane b;
+} __packed;
+
+struct imgu_abi_frame_sp_yuv_planes {
+       struct imgu_abi_frame_sp_plane y;
+       struct imgu_abi_frame_sp_plane u;
+       struct imgu_abi_frame_sp_plane v;
+} __packed;
+
+struct imgu_abi_frame_sp_nv_planes {
+       struct imgu_abi_frame_sp_plane y;
+       struct imgu_abi_frame_sp_plane uv;
+} __packed;
+
+struct imgu_abi_frame_sp_plane6 {
+       struct imgu_abi_frame_sp_plane r;
+       struct imgu_abi_frame_sp_plane r_at_b;
+       struct imgu_abi_frame_sp_plane gr;
+       struct imgu_abi_frame_sp_plane gb;
+       struct imgu_abi_frame_sp_plane b;
+       struct imgu_abi_frame_sp_plane b_at_r;
+} __packed;
+
+struct imgu_abi_frame_sp_binary_plane {
+       u32 size;
+       struct imgu_abi_frame_sp_plane data;
+} __packed;
+
+struct imgu_abi_frame_sp {
+       struct imgu_abi_frame_sp_info info;
+       struct imgu_abi_buffer_sp buf_attr;
+       union {
+               struct imgu_abi_frame_sp_plane raw;
+               struct imgu_abi_frame_sp_plane rgb;
+               struct imgu_abi_frame_sp_rgb_planes planar_rgb;
+               struct imgu_abi_frame_sp_plane yuyv;
+               struct imgu_abi_frame_sp_yuv_planes yuv;
+               struct imgu_abi_frame_sp_nv_planes nv;
+               struct imgu_abi_frame_sp_plane6 plane6;
+               struct imgu_abi_frame_sp_binary_plane binary;
+       } planes;
+} __packed;
+
+struct imgu_abi_resolution {
+       u32 width;
+       u32 height;
+} __packed;
+
+struct imgu_abi_frames_sp {
+       struct imgu_abi_frame_sp in;
+       struct imgu_abi_frame_sp out[IMGU_ABI_BINARY_MAX_OUTPUT_PORTS];
+       struct imgu_abi_resolution effective_in_res;
+       struct imgu_abi_frame_sp out_vf;
+       struct imgu_abi_frame_sp_info internal_frame_info;
+       struct imgu_abi_buffer_sp s3a_buf;
+       struct imgu_abi_buffer_sp dvs_buf;
+       struct imgu_abi_buffer_sp lace_buf;
+} __packed;
+
+struct imgu_abi_uds_info {
+       u16 curr_dx;
+       u16 curr_dy;
+       u16 xc;
+       u16 yc;
+} __packed;
+
+/* Information for a single pipeline stage */
+struct imgu_abi_sp_stage {
+       /* Multiple boolean flags can be stored in an integer */
+       u8 num;                 /* Stage number */
+       u8 isp_online;
+       u8 isp_copy_vf;
+       u8 isp_copy_output;
+       u8 sp_enable_xnr;
+       u8 isp_deci_log_factor;
+       u8 isp_vf_downscale_bits;
+       u8 deinterleaved;
+       /*
+        * NOTE: Programming the input circuit can only be done at the
+        * start of a session. It is illegal to program it during execution
+        * The input circuit defines the connectivity
+        */
+       u8 program_input_circuit;
+       u8 func;
+       u8 stage_type;          /* enum imgu_abi_stage_type */
+       u8 num_stripes;
+       u8 isp_pipe_version;
+       struct {
+               u8 vf_output;
+               u8 s3a;
+               u8 sdis;
+               u8 dvs_stats;
+               u8 lace_stats;
+       } enable;
+
+       struct imgu_abi_crop_pos sp_out_crop_pos;
+       u8 padding[2];
+       struct imgu_abi_frames_sp frames;
+       struct imgu_abi_resolution dvs_envelope;
+       struct imgu_abi_uds_info uds;
+       imgu_addr_t isp_stage_addr;
+       imgu_addr_t xmem_bin_addr;
+       imgu_addr_t xmem_map_addr;
+
+       u16 top_cropping;
+       u16 row_stripes_height;
+       u16 row_stripes_overlap_lines;
+       u8 if_config_index;     /* Which should be applied by this stage. */
+       u8 padding2;
+} __packed;
+
+/***** struct imgu_abi_isp_stage *****/
+
+struct imgu_abi_isp_param_memory_offsets {
+       u32 offsets[IMGU_ABI_PARAM_CLASS_NUM];  /* offset wrt hdr in bytes */
+} __packed;
+
+/*
+ * Blob descriptor.
+ * This structure describes an SP or ISP blob.
+ * It describes the test, data and bss sections as well as position in a
+ * firmware file.
+ * For convenience, it contains dynamic data after loading.
+ */
+struct imgu_abi_blob_info {
+       /* Static blob data */
+       u32 offset;                     /* Blob offset in fw file */
+       struct imgu_abi_isp_param_memory_offsets memory_offsets;
+                                       /* offset wrt hdr in bytes */
+       u32 prog_name_offset;           /* offset wrt hdr in bytes */
+       u32 size;                       /* Size of blob */
+       u32 padding_size;               /* total cummulative of bytes added
+                                        * due to section alignment
+                                        */
+       u32 icache_source;              /* Position of icache in blob */
+       u32 icache_size;                /* Size of icache section */
+       u32 icache_padding;     /* added due to icache section alignment */
+       u32 text_source;                /* Position of text in blob */
+       u32 text_size;                  /* Size of text section */
+       u32 text_padding;       /* bytes added due to text section alignment */
+       u32 data_source;                /* Position of data in blob */
+       u32 data_target;                /* Start of data in SP dmem */
+       u32 data_size;                  /* Size of text section */
+       u32 data_padding;       /* bytes added due to data section alignment */
+       u32 bss_target;         /* Start position of bss in SP dmem */
+       u32 bss_size;                   /* Size of bss section
+                                        * Dynamic data filled by loader
+                                        */
+       u64 code __aligned(8);  /* Code section absolute pointer */
+                                       /* within fw, code = icache + text */
+       u64 data __aligned(8);  /* Data section absolute pointer */
+                                       /* within fw, data = data + bss */
+} __packed;
+
+struct imgu_abi_binary_pipeline_info {
+       u32 mode;
+       u32 isp_pipe_version;
+       u32 pipelining;
+       u32 c_subsampling;
+       u32 top_cropping;
+       u32 left_cropping;
+       u32 variable_resolution;
+} __packed;
+
+struct imgu_abi_binary_input_info {
+       u32 min_width;
+       u32 min_height;
+       u32 max_width;
+       u32 max_height;
+       u32 source;     /* enum imgu_abi_bin_input_src */
+} __packed;
+
+struct imgu_abi_binary_output_info {
+       u32 min_width;
+       u32 min_height;
+       u32 max_width;
+       u32 max_height;
+       u32 num_chunks;
+       u32 variable_format;
+} __packed;
+
+struct imgu_abi_binary_internal_info {
+       u32 max_width;
+       u32 max_height;
+} __packed;
+
+struct imgu_abi_binary_bds_info {
+       u32 supported_bds_factors;
+} __packed;
+
+struct imgu_abi_binary_dvs_info {
+       u32 max_envelope_width;
+       u32 max_envelope_height;
+} __packed;
+
+struct imgu_abi_binary_vf_dec_info {
+       u32 is_variable;
+       u32 max_log_downscale;
+} __packed;
+
+struct imgu_abi_binary_s3a_info {
+       u32 s3atbl_use_dmem;
+       u32 fixed_s3a_deci_log;
+} __packed;
+
+struct imgu_abi_binary_dpc_info {
+       u32 bnr_lite;                   /* bnr lite enable flag */
+} __packed;
+
+struct imgu_abi_binary_iterator_info {
+       u32 num_stripes;
+       u32 row_stripes_height;
+       u32 row_stripes_overlap_lines;
+} __packed;
+
+struct imgu_abi_binary_address_info {
+       u32 isp_addresses;              /* Address in ISP dmem */
+       u32 main_entry;                 /* Address of entry fct */
+       u32 in_frame;                   /* Address in ISP dmem */
+       u32 out_frame;                  /* Address in ISP dmem */
+       u32 in_data;                    /* Address in ISP dmem */
+       u32 out_data;                   /* Address in ISP dmem */
+       u32 sh_dma_cmd_ptr;             /* In ISP dmem */
+} __packed;
+
+struct imgu_abi_binary_uds_info {
+       u16 bpp;
+       u16 use_bci;
+       u16 use_str;
+       u16 woix;
+       u16 woiy;
+       u16 extra_out_vecs;
+       u16 vectors_per_line_in;
+       u16 vectors_per_line_out;
+       u16 vectors_c_per_line_in;
+       u16 vectors_c_per_line_out;
+       u16 vmem_gdc_in_block_height_y;
+       u16 vmem_gdc_in_block_height_c;
+} __packed;
+
+struct imgu_abi_binary_block_info {
+       u32 block_width;
+       u32 block_height;
+       u32 output_block_height;
+} __packed;
+
+struct imgu_abi_isp_data {
+       imgu_addr_t address;            /* ISP address */
+       u32 size;                       /* Disabled if 0 */
+} __packed;
+
+struct imgu_abi_isp_param_segments {
+       struct imgu_abi_isp_data
+                       params[IMGU_ABI_PARAM_CLASS_NUM][IMGU_ABI_NUM_MEMORIES];
+} __packed;
+
+struct imgu_abi_binary_info {
+       u32 id __aligned(8);            /* IMGU_ABI_BINARY_ID_* */
+       struct imgu_abi_binary_pipeline_info pipeline;
+       struct imgu_abi_binary_input_info input;
+       struct imgu_abi_binary_output_info output;
+       struct imgu_abi_binary_internal_info internal;
+       struct imgu_abi_binary_bds_info bds;
+       struct imgu_abi_binary_dvs_info dvs;
+       struct imgu_abi_binary_vf_dec_info vf_dec;
+       struct imgu_abi_binary_s3a_info s3a;
+       struct imgu_abi_binary_dpc_info dpc_bnr; /* DPC related binary info */
+       struct imgu_abi_binary_iterator_info iterator;
+       struct imgu_abi_binary_address_info addresses;
+       struct imgu_abi_binary_uds_info uds;
+       struct imgu_abi_binary_block_info block;
+       struct imgu_abi_isp_param_segments mem_initializers;
+       struct {
+               u8 input_feeder;
+               u8 output_system;
+               u8 obgrid;
+               u8 lin;
+               u8 dpc_acc;
+               u8 bds_acc;
+               u8 shd_acc;
+               u8 shd_ff;
+               u8 stats_3a_raw_buffer;
+               u8 acc_bayer_denoise;
+               u8 bnr_ff;
+               u8 awb_acc;
+               u8 awb_fr_acc;
+               u8 anr_acc;
+               u8 rgbpp_acc;
+               u8 rgbpp_ff;
+               u8 demosaic_acc;
+               u8 demosaic_ff;
+               u8 dvs_stats;
+               u8 lace_stats;
+               u8 yuvp1_b0_acc;
+               u8 yuvp1_c0_acc;
+               u8 yuvp2_acc;
+               u8 ae;
+               u8 af;
+               u8 dergb;
+               u8 rgb2yuv;
+               u8 high_quality;
+               u8 kerneltest;
+               u8 routing_shd_to_bnr;          /* connect SHD with BNR ACCs */
+               u8 routing_bnr_to_anr;          /* connect BNR with ANR ACCs */
+               u8 routing_anr_to_de;           /* connect ANR with DE ACCs */
+               u8 routing_rgb_to_yuvp1;        /* connect RGB with YUVP1 */
+               u8 routing_yuvp1_to_yuvp2;      /* connect YUVP1 with YUVP2 */
+               u8 luma_only;
+               u8 input_yuv;
+               u8 input_raw;
+               u8 reduced_pipe;
+               u8 vf_veceven;
+               u8 dis;
+               u8 dvs_envelope;
+               u8 uds;
+               u8 dvs_6axis;
+               u8 block_output;
+               u8 streaming_dma;
+               u8 ds;
+               u8 bayer_fir_6db;
+               u8 raw_binning;
+               u8 continuous;
+               u8 s3a;
+               u8 fpnr;
+               u8 sc;
+               u8 macc;
+               u8 output;
+               u8 ref_frame;
+               u8 tnr;
+               u8 xnr;
+               u8 params;
+               u8 ca_gdc;
+               u8 isp_addresses;
+               u8 in_frame;
+               u8 out_frame;
+               u8 high_speed;
+               u8 dpc;
+               u8 padding[2];
+               u8 rgbir;
+       } enable;
+       struct {
+               u8 ref_y_channel;
+               u8 ref_c_channel;
+               u8 tnr_channel;
+               u8 tnr_out_channel;
+               u8 dvs_coords_channel;
+               u8 output_channel;
+               u8 c_channel;
+               u8 vfout_channel;
+               u8 vfout_c_channel;
+               u8 vfdec_bits_per_pixel;
+               u8 claimed_by_isp;
+               u8 padding[2];
+       } dma;
+} __packed;
+
+struct imgu_abi_isp_stage {
+       struct imgu_abi_blob_info blob_info;
+       struct imgu_abi_binary_info binary_info;
+       char binary_name[IMGU_ABI_MAX_BINARY_NAME];
+       struct imgu_abi_isp_param_segments mem_initializers;
+} __packed;
+
+/***** struct imgu_abi_ddr_address_map and parameter set *****/
+
+/* xmem address map allocation */
+struct imgu_abi_ddr_address_map {
+       imgu_addr_t isp_mem_param[IMGU_ABI_MAX_STAGES][IMGU_ABI_NUM_MEMORIES];
+       imgu_addr_t obgrid_tbl[IPU3_UAPI_MAX_STRIPES];
+       imgu_addr_t acc_cluster_params_for_sp;
+       imgu_addr_t dvs_6axis_params_y;
+} __packed;
+
+struct imgu_abi_parameter_set_info {
+       /* Pointers to Parameters in ISP format IMPT */
+       struct imgu_abi_ddr_address_map mem_map;
+       /* Unique ID to track per-frame configurations */
+       u32 isp_parameters_id;
+       /* Output frame to which this config has to be applied (optional) */
+       imgu_addr_t output_frame_ptr;
+} __packed;
+
+/***** struct imgu_abi_sp_group *****/
+
+/* SP configuration information */
+struct imgu_abi_sp_config {
+       u8 no_isp_sync;         /* Signal host immediately after start */
+       u8 enable_raw_pool_locking;    /* Enable Raw Buffer Locking for HALv3 */
+       u8 lock_all;
+       u8 disable_cont_vf;
+       u8 disable_preview_on_capture;
+       u8 padding[3];
+} __packed;
+
+/* Information for a pipeline */
+struct imgu_abi_sp_pipeline {
+       u32 pipe_id;                    /* the pipe ID */
+       u32 pipe_num;                   /* the dynamic pipe number */
+       u32 thread_id;                  /* the sp thread ID */
+       u32 pipe_config;                /* the pipe config */
+       u32 pipe_qos_config;            /* Bitmap of multiple QOS extension fw
+                                        * state, 0xffffffff indicates non
+                                        * QOS pipe.
+                                        */
+       u32 inout_port_config;
+       u32 required_bds_factor;
+       u32 dvs_frame_delay;
+       u32 num_stages;         /* the pipe config */
+       u32 running;                    /* needed for pipe termination */
+       imgu_addr_t sp_stage_addr[IMGU_ABI_MAX_STAGES];
+       imgu_addr_t scaler_pp_lut;      /* Early bound LUT */
+       u32 stage;                      /* stage ptr is only used on sp */
+       s32 num_execs;                  /* number of times to run if this is
+                                        * an acceleration pipe.
+                                        */
+       union {
+               struct {
+                       u32 bytes_available;
+               } bin;
+               struct {
+                       u32 height;
+                       u32 width;
+                       u32 padded_width;
+                       u32 max_input_width;
+                       u32 raw_bit_depth;
+               } raw;
+       } copy;
+
+       /* Parameters passed to Shading Correction kernel. */
+       struct {
+               /* Origin X (bqs) of internal frame on shading table */
+               u32 internal_frame_origin_x_bqs_on_sctbl;
+               /* Origin Y (bqs) of internal frame on shading table */
+               u32 internal_frame_origin_y_bqs_on_sctbl;
+       } shading;
+} __packed;
+
+struct imgu_abi_sp_debug_command {
+       /*
+        * The DMA software-mask,
+        *      Bit 31...24: unused.
+        *      Bit 23...16: unused.
+        *      Bit 15...08: reading-request enabling bits for DMA channel 7..0
+        *      Bit 07...00: writing-request enabling bits for DMA channel 7..0
+        *
+        * For example, "0...0 0...0 11111011 11111101" indicates that the
+        * writing request through DMA Channel 1 and the reading request
+        * through DMA channel 2 are both disabled. The others are enabled.
+        */
+       u32 dma_sw_reg;
+} __packed;
+
+/*
+ * Group all host initialized SP variables into this struct.
+ * This is initialized every stage through dma.
+ * The stage part itself is transferred through imgu_abi_sp_stage.
+ */
+struct imgu_abi_sp_group {
+       struct imgu_abi_sp_config config;
+       struct imgu_abi_sp_pipeline pipe[IMGU_ABI_MAX_SP_THREADS];
+       struct imgu_abi_sp_debug_command debug;
+} __packed;
+
+/***** parameter and state class binary configurations *****/
+
+struct imgu_abi_isp_iterator_config {
+       struct imgu_abi_frame_sp_info input_info;
+       struct imgu_abi_frame_sp_info internal_info;
+       struct imgu_abi_frame_sp_info output_info;
+       struct imgu_abi_frame_sp_info vf_info;
+       struct imgu_abi_sp_resolution dvs_envelope;
+} __packed;
+
+struct imgu_abi_dma_port_config {
+       u8 crop, elems;
+       u16 width;
+       u32 stride;
+} __packed;
+
+struct imgu_abi_isp_ref_config {
+       u32 width_a_over_b;
+       struct imgu_abi_dma_port_config port_b;
+       u32 ref_frame_addr_y[IMGU_ABI_FRAMES_REF];
+       u32 ref_frame_addr_c[IMGU_ABI_FRAMES_REF];
+       u32 dvs_frame_delay;
+} __packed;
+
+struct imgu_abi_isp_ref_dmem_state {
+       u32 ref_in_buf_idx;
+       u32 ref_out_buf_idx;
+} __packed;
+
+struct imgu_abi_isp_dvs_config {
+       u32 num_horizontal_blocks;
+       u32 num_vertical_blocks;
+} __packed;
+
+struct imgu_abi_isp_tnr3_config {
+       u32 width_a_over_b;
+       u32 frame_height;
+       struct imgu_abi_dma_port_config port_b;
+       u32 delay_frame;
+       u32 frame_addr[IMGU_ABI_FRAMES_TNR];
+} __packed;
+
+struct imgu_abi_isp_tnr3_dmem_state {
+       u32 in_bufidx;
+       u32 out_bufidx;
+       u32 total_frame_counter;
+       u32 buffer_frame_counter[IMGU_ABI_BUF_SETS_TNR];
+       u32 bypass_filter;
+} __packed;
+
+/***** Queues *****/
+
+struct imgu_abi_queue_info {
+       u8 size;                /* the maximum number of elements*/
+       u8 step;                /* number of bytes per element */
+       u8 start;               /* index of the oldest element */
+       u8 end;                 /* index at which to write the new element */
+} __packed;
+
+struct imgu_abi_queues {
+       /*
+        * Queues for the dynamic frame information,
+        * i.e. the "in_frame" buffer, the "out_frame"
+        * buffer and the "vf_out_frame" buffer.
+        */
+       struct imgu_abi_queue_info host2sp_bufq_info
+                       [IMGU_ABI_MAX_SP_THREADS][IMGU_ABI_QUEUE_NUM];
+       u32 host2sp_bufq[IMGU_ABI_MAX_SP_THREADS][IMGU_ABI_QUEUE_NUM]
+                       [IMGU_ABI_HOST2SP_BUFQ_SIZE];
+       struct imgu_abi_queue_info sp2host_bufq_info[IMGU_ABI_QUEUE_NUM];
+       u32 sp2host_bufq[IMGU_ABI_QUEUE_NUM][IMGU_ABI_SP2HOST_BUFQ_SIZE];
+
+       /*
+        * The queues for the events.
+        */
+       struct imgu_abi_queue_info host2sp_evtq_info;
+       u32 host2sp_evtq[IMGU_ABI_HOST2SP_EVTQ_SIZE];
+       struct imgu_abi_queue_info sp2host_evtq_info;
+       u32 sp2host_evtq[IMGU_ABI_SP2HOST_EVTQ_SIZE];
+} __packed;
+
+/***** Buffer descriptor *****/
+
+struct imgu_abi_metadata_info {
+       struct imgu_abi_resolution resolution;  /* Resolution */
+       u32 stride;                             /* Stride in bytes */
+       u32 size;                               /* Total size in bytes */
+} __packed;
+
+struct imgu_abi_isp_3a_statistics {
+       union {
+               struct {
+                       imgu_addr_t s3a_tbl;
+               } dmem;
+               struct {
+                       imgu_addr_t s3a_tbl_hi;
+                       imgu_addr_t s3a_tbl_lo;
+               } vmem;
+       } data;
+       struct {
+               imgu_addr_t rgby_tbl;
+       } data_hmem;
+       u32 exp_id;     /* exposure id, to match statistics to a frame, */
+       u32 isp_config_id;              /* Tracks per-frame configs */
+       imgu_addr_t data_ptr;           /* pointer to base of all data */
+       u32 size;                       /* total size of all data */
+       u32 dmem_size;
+       u32 vmem_size;                  /* both lo and hi have this size */
+       u32 hmem_size;
+} __packed;
+
+struct imgu_abi_metadata {
+       struct imgu_abi_metadata_info info;     /* Layout info */
+       imgu_addr_t address;            /* CSS virtual address */
+       u32 exp_id;                     /* Exposure ID */
+} __packed;
+
+struct imgu_abi_time_meas {
+       u32 start_timer_value;          /* measured time in ticks */
+       u32 end_timer_value;            /* measured time in ticks */
+} __packed;
+
+struct imgu_abi_buffer {
+       union {
+               struct imgu_abi_isp_3a_statistics s3a;
+               u8 reserved[28];
+               imgu_addr_t skc_dvs_statistics;
+               imgu_addr_t lace_stat;
+               struct imgu_abi_metadata metadata;
+               struct {
+                       imgu_addr_t frame_data;
+                       u32 flashed;
+                       u32 exp_id;
+                       u32 isp_parameters_id;   /* Tracks per-frame configs */
+                       u32 padded_width;
+               } frame;
+               imgu_addr_t ddr_ptrs;
+       } payload;
+       /*
+        * kernel_ptr is present for host administration purposes only.
+        * type is uint64_t in order to be 64-bit host compatible.
+        * uint64_t does not exist on SP/ISP.
+        * Size of the struct is checked by sp.hive.c.
+        */
+       u64 cookie_ptr __aligned(8);
+       u64 kernel_ptr;
+       struct imgu_abi_time_meas timing_data;
+       u32 isys_eof_clock_tick;
+} __packed;
+
+struct imgu_abi_bl_dma_cmd_entry {
+       u32 src_addr;                   /* virtual DDR address */
+       u32 size;                       /* number of bytes to transferred */
+       u32 dst_type;
+       u32 dst_addr;                   /* hmm address of xMEM or MMIO */
+} __packed;
+
+struct imgu_abi_sp_init_dmem_cfg {
+       u32 ddr_data_addr;              /* data segment address in ddr  */
+       u32 dmem_data_addr;             /* data segment address in dmem */
+       u32 dmem_bss_addr;              /* bss segment address in dmem  */
+       u32 data_size;                  /* data segment size            */
+       u32 bss_size;                   /* bss segment size             */
+       u32 sp_id;                      /* sp id */
+} __packed;
+
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c
new file mode 100644 (file)
index 0000000..55861aa
--- /dev/null
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-dmamap.h"
+
+static void ipu3_css_fw_show_binary(struct device *dev, struct imgu_fw_info *bi,
+                                   const char *name)
+{
+       unsigned int i;
+
+       dev_dbg(dev, "found firmware binary type %i size %i name %s\n",
+               bi->type, bi->blob.size, name);
+       if (bi->type != IMGU_FW_ISP_FIRMWARE)
+               return;
+
+       dev_dbg(dev, "    id %i mode %i bds 0x%x veceven %i/%i out_pins %i\n",
+               bi->info.isp.sp.id, bi->info.isp.sp.pipeline.mode,
+               bi->info.isp.sp.bds.supported_bds_factors,
+               bi->info.isp.sp.enable.vf_veceven,
+               bi->info.isp.sp.vf_dec.is_variable,
+               bi->info.isp.num_output_pins);
+
+       dev_dbg(dev, "    input (%i,%i)-(%i,%i) formats %s%s%s\n",
+               bi->info.isp.sp.input.min_width,
+               bi->info.isp.sp.input.min_height,
+               bi->info.isp.sp.input.max_width,
+               bi->info.isp.sp.input.max_height,
+               bi->info.isp.sp.enable.input_yuv ? "yuv420 " : "",
+               bi->info.isp.sp.enable.input_feeder ||
+               bi->info.isp.sp.enable.input_raw ? "raw8 raw10 " : "",
+               bi->info.isp.sp.enable.input_raw ? "raw12" : "");
+
+       dev_dbg(dev, "    internal (%i,%i)\n",
+               bi->info.isp.sp.internal.max_width,
+               bi->info.isp.sp.internal.max_height);
+
+       dev_dbg(dev, "    output (%i,%i)-(%i,%i) formats",
+               bi->info.isp.sp.output.min_width,
+               bi->info.isp.sp.output.min_height,
+               bi->info.isp.sp.output.max_width,
+               bi->info.isp.sp.output.max_height);
+       for (i = 0; i < bi->info.isp.num_output_formats; i++)
+               dev_dbg(dev, " %i", bi->info.isp.output_formats[i]);
+       dev_dbg(dev, " vf");
+       for (i = 0; i < bi->info.isp.num_vf_formats; i++)
+               dev_dbg(dev, " %i", bi->info.isp.vf_formats[i]);
+       dev_dbg(dev, "\n");
+}
+
+unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi)
+{
+       unsigned int width = DIV_ROUND_UP(bi->info.isp.sp.internal.max_width,
+                                         IMGU_OBGRID_TILE_SIZE * 2) + 1;
+       unsigned int height = DIV_ROUND_UP(bi->info.isp.sp.internal.max_height,
+                                          IMGU_OBGRID_TILE_SIZE * 2) + 1;
+       unsigned int obgrid_size;
+
+       width = ALIGN(width, IPU3_UAPI_ISP_VEC_ELEMS / 4);
+       obgrid_size = PAGE_ALIGN(width * height *
+                                sizeof(struct ipu3_uapi_obgrid_param)) *
+                                bi->info.isp.sp.iterator.num_stripes;
+       return obgrid_size;
+}
+
+void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
+                                 enum imgu_abi_param_class cls,
+                                 enum imgu_abi_memories mem,
+                                 struct imgu_fw_isp_parameter *par,
+                                 size_t par_size, void *binary_params)
+{
+       struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css->pipes[pipe].bindex];
+
+       if (par->offset + par->size >
+           bi->info.isp.sp.mem_initializers.params[cls][mem].size)
+               return NULL;
+
+       if (par->size != par_size)
+               pr_warn("parameter size doesn't match defined size\n");
+
+       if (par->size < par_size)
+               return NULL;
+
+       return binary_params + par->offset;
+}
+
+void ipu3_css_fw_cleanup(struct ipu3_css *css)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+
+       if (css->binary) {
+               unsigned int i;
+
+               for (i = 0; i < css->fwp->file_header.binary_nr; i++)
+                       ipu3_dmamap_free(imgu, &css->binary[i]);
+               kfree(css->binary);
+       }
+       if (css->fw)
+               release_firmware(css->fw);
+
+       css->binary = NULL;
+       css->fw = NULL;
+}
+
+int ipu3_css_fw_init(struct ipu3_css *css)
+{
+       static const u32 BLOCK_MAX = 65536;
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       struct device *dev = css->dev;
+       unsigned int i, j, binary_nr;
+       int r;
+
+       r = request_firmware(&css->fw, IMGU_FW_NAME, css->dev);
+       if (r)
+               return r;
+
+       /* Check and display fw header info */
+
+       css->fwp = (struct imgu_fw_header *)css->fw->data;
+       if (css->fw->size < sizeof(struct imgu_fw_header *) ||
+           css->fwp->file_header.h_size != sizeof(struct imgu_fw_bi_file_h))
+               goto bad_fw;
+       if (sizeof(struct imgu_fw_bi_file_h) +
+           css->fwp->file_header.binary_nr * sizeof(struct imgu_fw_info) >
+           css->fw->size)
+               goto bad_fw;
+
+       dev_info(dev, "loaded firmware version %.64s, %u binaries, %zu bytes\n",
+                css->fwp->file_header.version, css->fwp->file_header.binary_nr,
+                css->fw->size);
+
+       /* Validate and display info on fw binaries */
+
+       binary_nr = css->fwp->file_header.binary_nr;
+
+       css->fw_bl = -1;
+       css->fw_sp[0] = -1;
+       css->fw_sp[1] = -1;
+
+       for (i = 0; i < binary_nr; i++) {
+               struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+               const char *name = (void *)css->fwp + bi->blob.prog_name_offset;
+               size_t len;
+
+               if (bi->blob.prog_name_offset >= css->fw->size)
+                       goto bad_fw;
+               len = strnlen(name, css->fw->size - bi->blob.prog_name_offset);
+               if (len + 1 > css->fw->size - bi->blob.prog_name_offset ||
+                   len + 1 >= IMGU_ABI_MAX_BINARY_NAME)
+                       goto bad_fw;
+
+               if (bi->blob.size != bi->blob.text_size + bi->blob.icache_size
+                   + bi->blob.data_size + bi->blob.padding_size)
+                       goto bad_fw;
+               if (bi->blob.offset + bi->blob.size > css->fw->size)
+                       goto bad_fw;
+
+               if (bi->type == IMGU_FW_BOOTLOADER_FIRMWARE) {
+                       css->fw_bl = i;
+                       if (bi->info.bl.sw_state >= css->iomem_length ||
+                           bi->info.bl.num_dma_cmds >= css->iomem_length ||
+                           bi->info.bl.dma_cmd_list >= css->iomem_length)
+                               goto bad_fw;
+               }
+               if (bi->type == IMGU_FW_SP_FIRMWARE ||
+                   bi->type == IMGU_FW_SP1_FIRMWARE) {
+                       css->fw_sp[bi->type == IMGU_FW_SP_FIRMWARE ? 0 : 1] = i;
+                       if (bi->info.sp.per_frame_data >= css->iomem_length ||
+                           bi->info.sp.init_dmem_data >= css->iomem_length ||
+                           bi->info.sp.host_sp_queue >= css->iomem_length ||
+                           bi->info.sp.isp_started >= css->iomem_length ||
+                           bi->info.sp.sw_state >= css->iomem_length ||
+                           bi->info.sp.sleep_mode >= css->iomem_length ||
+                           bi->info.sp.invalidate_tlb >= css->iomem_length ||
+                           bi->info.sp.host_sp_com >= css->iomem_length ||
+                           bi->info.sp.output + 12 >= css->iomem_length ||
+                           bi->info.sp.host_sp_queues_initialized >=
+                           css->iomem_length)
+                               goto bad_fw;
+               }
+               if (bi->type != IMGU_FW_ISP_FIRMWARE)
+                       continue;
+
+               if (bi->info.isp.sp.pipeline.mode >= IPU3_CSS_PIPE_ID_NUM)
+                       goto bad_fw;
+
+               if (bi->info.isp.sp.iterator.num_stripes >
+                   IPU3_UAPI_MAX_STRIPES)
+                       goto bad_fw;
+
+               if (bi->info.isp.num_vf_formats > IMGU_ABI_FRAME_FORMAT_NUM ||
+                   bi->info.isp.num_output_formats > IMGU_ABI_FRAME_FORMAT_NUM)
+                       goto bad_fw;
+
+               for (j = 0; j < bi->info.isp.num_output_formats; j++)
+                       if (bi->info.isp.output_formats[j] < 0 ||
+                           bi->info.isp.output_formats[j] >=
+                           IMGU_ABI_FRAME_FORMAT_NUM)
+                               goto bad_fw;
+               for (j = 0; j < bi->info.isp.num_vf_formats; j++)
+                       if (bi->info.isp.vf_formats[j] < 0 ||
+                           bi->info.isp.vf_formats[j] >=
+                           IMGU_ABI_FRAME_FORMAT_NUM)
+                               goto bad_fw;
+
+               if (bi->info.isp.sp.block.block_width <= 0 ||
+                   bi->info.isp.sp.block.block_width > BLOCK_MAX ||
+                   bi->info.isp.sp.block.output_block_height <= 0 ||
+                   bi->info.isp.sp.block.output_block_height > BLOCK_MAX)
+                       goto bad_fw;
+
+               if (bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]
+                   + sizeof(struct imgu_fw_param_memory_offsets) >
+                   css->fw->size ||
+                   bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG]
+                   + sizeof(struct imgu_fw_config_memory_offsets) >
+                   css->fw->size ||
+                   bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE]
+                   + sizeof(struct imgu_fw_state_memory_offsets) >
+                   css->fw->size)
+                       goto bad_fw;
+
+               ipu3_css_fw_show_binary(dev, bi, name);
+       }
+
+       if (css->fw_bl == -1 || css->fw_sp[0] == -1 || css->fw_sp[1] == -1)
+               goto bad_fw;
+
+       /* Allocate and map fw binaries into IMGU */
+
+       css->binary = kcalloc(binary_nr, sizeof(*css->binary), GFP_KERNEL);
+       if (!css->binary) {
+               r = -ENOMEM;
+               goto error_out;
+       }
+
+       for (i = 0; i < css->fwp->file_header.binary_nr; i++) {
+               struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+               void *blob = (void *)css->fwp + bi->blob.offset;
+               size_t size = bi->blob.size;
+
+               if (!ipu3_dmamap_alloc(imgu, &css->binary[i], size)) {
+                       r = -ENOMEM;
+                       goto error_out;
+               }
+               memcpy(css->binary[i].vaddr, blob, size);
+       }
+
+       return 0;
+
+bad_fw:
+       dev_err(dev, "invalid firmware binary, size %u\n", (int)css->fw->size);
+       r = -ENODEV;
+
+error_out:
+       ipu3_css_fw_cleanup(css);
+       return r;
+}
diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.h b/drivers/staging/media/ipu3/ipu3-css-fw.h
new file mode 100644 (file)
index 0000000..07d8bb8
--- /dev/null
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_CSS_FW_H
+#define __IPU3_CSS_FW_H
+
+/******************* Firmware file definitions *******************/
+
+#define IMGU_FW_NAME                   "intel/ipu3-fw.bin"
+
+typedef u32 imgu_fw_ptr;
+
+enum imgu_fw_type {
+       IMGU_FW_SP_FIRMWARE,    /* Firmware for the SP */
+       IMGU_FW_SP1_FIRMWARE,   /* Firmware for the SP1 */
+       IMGU_FW_ISP_FIRMWARE,   /* Firmware for the ISP */
+       IMGU_FW_BOOTLOADER_FIRMWARE,    /* Firmware for the BootLoader */
+       IMGU_FW_ACC_FIRMWARE    /* Firmware for accelerations */
+};
+
+enum imgu_fw_acc_type {
+       IMGU_FW_ACC_NONE,       /* Normal binary */
+       IMGU_FW_ACC_OUTPUT,     /* Accelerator stage on output frame */
+       IMGU_FW_ACC_VIEWFINDER, /* Accelerator stage on viewfinder frame */
+       IMGU_FW_ACC_STANDALONE, /* Stand-alone acceleration */
+};
+
+struct imgu_fw_isp_parameter {
+       u32 offset;             /* Offset in isp_<mem> config, params, etc. */
+       u32 size;               /* Disabled if 0 */
+};
+
+struct imgu_fw_param_memory_offsets {
+       struct {
+               struct imgu_fw_isp_parameter lin;       /* lin_vmem_params */
+               struct imgu_fw_isp_parameter tnr3;      /* tnr3_vmem_params */
+               struct imgu_fw_isp_parameter xnr3;      /* xnr3_vmem_params */
+       } vmem;
+       struct {
+               struct imgu_fw_isp_parameter tnr;
+               struct imgu_fw_isp_parameter tnr3;      /* tnr3_params */
+               struct imgu_fw_isp_parameter xnr3;      /* xnr3_params */
+               struct imgu_fw_isp_parameter plane_io_config;   /* 192 bytes */
+               struct imgu_fw_isp_parameter rgbir;     /* rgbir_params */
+       } dmem;
+};
+
+struct imgu_fw_config_memory_offsets {
+       struct {
+               struct imgu_fw_isp_parameter iterator;
+               struct imgu_fw_isp_parameter dvs;
+               struct imgu_fw_isp_parameter output;
+               struct imgu_fw_isp_parameter raw;
+               struct imgu_fw_isp_parameter input_yuv;
+               struct imgu_fw_isp_parameter tnr;
+               struct imgu_fw_isp_parameter tnr3;
+               struct imgu_fw_isp_parameter ref;
+       } dmem;
+};
+
+struct imgu_fw_state_memory_offsets {
+       struct {
+               struct imgu_fw_isp_parameter tnr;
+               struct imgu_fw_isp_parameter tnr3;
+               struct imgu_fw_isp_parameter ref;
+       } dmem;
+};
+
+union imgu_fw_all_memory_offsets {
+       struct {
+               u64 imgu_fw_mem_offsets[3]; /* params, config, state */
+       } offsets;
+       struct {
+               u64 ptr;
+       } array[IMGU_ABI_PARAM_CLASS_NUM];
+};
+
+struct imgu_fw_binary_xinfo {
+       /* Part that is of interest to the SP. */
+       struct imgu_abi_binary_info sp;
+
+       /* Rest of the binary info, only interesting to the host. */
+       u32 type;       /* enum imgu_fw_acc_type */
+
+       u32 num_output_formats __aligned(8);
+       u32 output_formats[IMGU_ABI_FRAME_FORMAT_NUM];  /* enum frame_format */
+
+       /* number of supported vf formats */
+       u32 num_vf_formats __aligned(8);
+       /* types of supported vf formats */
+       u32 vf_formats[IMGU_ABI_FRAME_FORMAT_NUM];      /* enum frame_format */
+       u8 num_output_pins;
+       imgu_fw_ptr xmem_addr;
+
+       u64 imgu_fw_blob_descr_ptr __aligned(8);
+       u32 blob_index __aligned(8);
+       union imgu_fw_all_memory_offsets mem_offsets __aligned(8);
+       struct imgu_fw_binary_xinfo *next __aligned(8);
+};
+
+struct imgu_fw_sp_info {
+       u32 init_dmem_data;     /* data sect config, stored to dmem */
+       u32 per_frame_data;     /* Per frame data, stored to dmem */
+       u32 group;              /* Per pipeline data, loaded by dma */
+       u32 output;             /* SP output data, loaded by dmem */
+       u32 host_sp_queue;      /* Host <-> SP queues */
+       u32 host_sp_com;        /* Host <-> SP commands */
+       u32 isp_started;        /* P'ed from sensor thread, csim only */
+       u32 sw_state;           /* Polled from css, enum imgu_abi_sp_swstate */
+       u32 host_sp_queues_initialized; /* Polled from the SP */
+       u32 sleep_mode;         /* different mode to halt SP */
+       u32 invalidate_tlb;     /* inform SP to invalidate mmu TLB */
+       u32 debug_buffer_ddr_address;   /* the addr of DDR debug queue */
+
+       /* input system perf count array */
+       u32 perf_counter_input_system_error;
+       u32 threads_stack;      /* sp thread's stack pointers */
+       u32 threads_stack_size; /* sp thread's stack sizes */
+       u32 curr_binary_id;     /* current binary id */
+       u32 raw_copy_line_count;        /* raw copy line counter */
+       u32 ddr_parameter_address;      /* acc param ddrptr, sp dmem */
+       u32 ddr_parameter_size; /* acc param size, sp dmem */
+       /* Entry functions */
+       u32 sp_entry;           /* The SP entry function */
+       u32 tagger_frames_addr; /* Base address of tagger state */
+};
+
+struct imgu_fw_bl_info {
+       u32 num_dma_cmds;       /* Number of cmds sent by CSS */
+       u32 dma_cmd_list;       /* Dma command list sent by CSS */
+       u32 sw_state;           /* Polled from css, enum imgu_abi_bl_swstate */
+       /* Entry functions */
+       u32 bl_entry;           /* The SP entry function */
+};
+
+struct imgu_fw_acc_info {
+       u32 per_frame_data;     /* Dummy for now */
+};
+
+union imgu_fw_union {
+       struct imgu_fw_binary_xinfo isp;        /* ISP info */
+       struct imgu_fw_sp_info sp;      /* SP info */
+       struct imgu_fw_sp_info sp1;     /* SP1 info */
+       struct imgu_fw_bl_info bl;      /* Bootloader info */
+       struct imgu_fw_acc_info acc;    /* Accelerator info */
+};
+
+struct imgu_fw_info {
+       size_t header_size;     /* size of fw header */
+       u32 type __aligned(8);  /* enum imgu_fw_type */
+       union imgu_fw_union info;       /* Binary info */
+       struct imgu_abi_blob_info blob; /* Blob info */
+       /* Dynamic part */
+       u64 next;
+
+       u32 loaded __aligned(8);        /* Firmware has been loaded */
+       const u64 isp_code __aligned(8);        /* ISP pointer to code */
+       /* Firmware handle between user space and kernel */
+       u32 handle __aligned(8);
+       /* Sections to copy from/to ISP */
+       struct imgu_abi_isp_param_segments mem_initializers;
+       /* Initializer for local ISP memories */
+};
+
+struct imgu_fw_bi_file_h {
+       char version[64];       /* branch tag + week day + time */
+       int binary_nr;          /* Number of binaries */
+       unsigned int h_size;    /* sizeof(struct imgu_fw_bi_file_h) */
+};
+
+struct imgu_fw_header {
+       struct imgu_fw_bi_file_h file_header;
+       struct imgu_fw_info binary_header[1];   /* binary_nr items */
+};
+
+/******************* Firmware functions *******************/
+
+int ipu3_css_fw_init(struct ipu3_css *css);
+void ipu3_css_fw_cleanup(struct ipu3_css *css);
+
+unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi);
+void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
+                                 enum imgu_abi_param_class cls,
+                                 enum imgu_abi_memories mem,
+                                 struct imgu_fw_isp_parameter *par,
+                                 size_t par_size, void *binary_params);
+
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c
new file mode 100644 (file)
index 0000000..776206d
--- /dev/null
@@ -0,0 +1,2943 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <linux/device.h>
+
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-tables.h"
+
+#define DIV_ROUND_CLOSEST_DOWN(a, b)   (((a) + ((b) / 2) - 1) / (b))
+#define roundclosest_down(a, b)                (DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
+
+#define IPU3_UAPI_ANR_MAX_RESET                ((1 << 12) - 1)
+#define IPU3_UAPI_ANR_MIN_RESET                (((-1) << 12) + 1)
+
+struct ipu3_css_scaler_info {
+       unsigned int phase_step;        /* Same for luma/chroma */
+       int exp_shift;
+
+       unsigned int phase_init;        /* luma/chroma dependent */
+       int pad_left;
+       int pad_right;
+       int crop_left;
+       int crop_top;
+};
+
+static unsigned int ipu3_css_scaler_get_exp(unsigned int counter,
+                                           unsigned int divider)
+{
+       int i = fls(divider) - fls(counter);
+
+       if (i <= 0)
+               return 0;
+
+       if (divider >> i < counter)
+               i = i - 1;
+
+       return i;
+}
+
+/* Set up the CSS scaler look up table */
+static void
+ipu3_css_scaler_setup_lut(unsigned int taps, unsigned int input_width,
+                         unsigned int output_width, int phase_step_correction,
+                         const int *coeffs, unsigned int coeffs_size,
+                         s8 coeff_lut[], struct ipu3_css_scaler_info *info)
+{
+       int tap, phase, phase_sum_left, phase_sum_right;
+       int exponent = ipu3_css_scaler_get_exp(output_width, input_width);
+       int mantissa = (1 << exponent) * output_width;
+       unsigned int phase_step;
+
+       if (input_width == output_width) {
+               for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
+                       for (tap = 0; tap < taps; tap++) {
+                               coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap]
+                                       = 0;
+                       }
+               }
+
+               info->phase_step = IMGU_SCALER_PHASES *
+                       (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF);
+               info->exp_shift = 0;
+               info->pad_left = 0;
+               info->pad_right = 0;
+               info->phase_init = 0;
+               info->crop_left = 0;
+               info->crop_top = 0;
+               return;
+       }
+
+       for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
+               for (tap = 0; tap < taps; tap++) {
+                       /* flip table to for convolution reverse indexing */
+                       s64 coeff = coeffs[coeffs_size -
+                               ((tap * (coeffs_size / taps)) + phase) - 1];
+                       coeff *= mantissa;
+                       coeff = div64_long(coeff, input_width);
+
+                       /* Add +"0.5" */
+                       coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1);
+                       coeff >>= IMGU_SCALER_COEFF_BITS;
+
+                       coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap] =
+                               coeff;
+               }
+       }
+
+       phase_step = IMGU_SCALER_PHASES *
+                       (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF) *
+                       output_width / input_width;
+       phase_step += phase_step_correction;
+       phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES *
+                       (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) -
+                       (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
+       phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES *
+                       (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) +
+                       (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
+
+       info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent;
+       info->pad_left = (phase_sum_left % phase_step == 0) ?
+               phase_sum_left / phase_step - 1 : phase_sum_left / phase_step;
+       info->pad_right = (phase_sum_right % phase_step == 0) ?
+               phase_sum_right / phase_step - 1 : phase_sum_right / phase_step;
+       info->phase_init = phase_sum_left - phase_step * info->pad_left;
+       info->phase_step = phase_step;
+       info->crop_left = taps - 1;
+       info->crop_top = taps - 1;
+}
+
+/*
+ * Calculates the exact output image width/height, based on phase_step setting
+ * (must be perfectly aligned with hardware).
+ */
+static unsigned int
+ipu3_css_scaler_calc_scaled_output(unsigned int input,
+                                  struct ipu3_css_scaler_info *info)
+{
+       unsigned int arg1 = input * info->phase_step +
+                       (1 - IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES -
+                       IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES);
+       unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES +
+                       IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES)) *
+                       IMGU_SCALER_FIR_PHASES + info->phase_step / 2;
+
+       return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step) /
+               IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2;
+}
+
+/*
+ * Calculate the output width and height, given the luma
+ * and chroma details of a scaler
+ */
+static void
+ipu3_css_scaler_calc(u32 input_width, u32 input_height, u32 target_width,
+                    u32 target_height, struct imgu_abi_osys_config *cfg,
+                    struct ipu3_css_scaler_info *info_luma,
+                    struct ipu3_css_scaler_info *info_chroma,
+                    unsigned int *output_width, unsigned int *output_height,
+                    unsigned int *procmode)
+{
+       u32 out_width = target_width;
+       u32 out_height = target_height;
+       const unsigned int height_alignment = 2;
+       int phase_step_correction = -1;
+
+       /*
+        * Calculate scaled output width. If the horizontal and vertical scaling
+        * factor is different, then choose the biggest and crop off excess
+        * lines or columns after formatting.
+        */
+       if (target_height * input_width > target_width * input_height)
+               target_width = DIV_ROUND_UP(target_height * input_width,
+                                           input_height);
+
+       if (input_width == target_width)
+               *procmode = IMGU_ABI_OSYS_PROCMODE_BYPASS;
+       else
+               *procmode = IMGU_ABI_OSYS_PROCMODE_DOWNSCALE;
+
+       memset(&cfg->scaler_coeffs_chroma, 0,
+              sizeof(cfg->scaler_coeffs_chroma));
+       memset(&cfg->scaler_coeffs_luma, 0, sizeof(*cfg->scaler_coeffs_luma));
+       do {
+               phase_step_correction++;
+
+               ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y,
+                                         input_width, target_width,
+                                         phase_step_correction,
+                                         ipu3_css_downscale_4taps,
+                                         IMGU_SCALER_DOWNSCALE_4TAPS_LEN,
+                                         cfg->scaler_coeffs_luma, info_luma);
+
+               ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV,
+                                         input_width, target_width,
+                                         phase_step_correction,
+                                         ipu3_css_downscale_2taps,
+                                         IMGU_SCALER_DOWNSCALE_2TAPS_LEN,
+                                         cfg->scaler_coeffs_chroma,
+                                         info_chroma);
+
+               out_width = ipu3_css_scaler_calc_scaled_output(input_width,
+                                                              info_luma);
+               out_height = ipu3_css_scaler_calc_scaled_output(input_height,
+                                                               info_luma);
+       } while ((out_width < target_width || out_height < target_height ||
+                !IS_ALIGNED(out_height, height_alignment)) &&
+                phase_step_correction <= 5);
+
+       *output_width = out_width;
+       *output_height = out_height;
+}
+
+/********************** Osys routines for scaler****************************/
+
+static void ipu3_css_osys_set_format(enum imgu_abi_frame_format host_format,
+                                    unsigned int *osys_format,
+                                    unsigned int *osys_tiling)
+{
+       *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
+       *osys_tiling = IMGU_ABI_OSYS_TILING_NONE;
+
+       switch (host_format) {
+       case IMGU_ABI_FRAME_FORMAT_YUV420:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
+               break;
+       case IMGU_ABI_FRAME_FORMAT_YV12:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_YV12;
+               break;
+       case IMGU_ABI_FRAME_FORMAT_NV12:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
+               break;
+       case IMGU_ABI_FRAME_FORMAT_NV16:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_NV16;
+               break;
+       case IMGU_ABI_FRAME_FORMAT_NV21:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_NV21;
+               break;
+       case IMGU_ABI_FRAME_FORMAT_NV12_TILEY:
+               *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
+               *osys_tiling = IMGU_ABI_OSYS_TILING_Y;
+               break;
+       default:
+               /* For now, assume use default values */
+               break;
+       }
+}
+
+/*
+ * Function calculates input frame stripe offset, based
+ * on output frame stripe offset and filter parameters.
+ */
+static int ipu3_css_osys_calc_stripe_offset(int stripe_offset_out,
+                                           int fir_phases, int phase_init,
+                                           int phase_step, int pad_left)
+{
+       int stripe_offset_inp = stripe_offset_out * fir_phases -
+                               pad_left * phase_step;
+
+       return DIV_ROUND_UP(stripe_offset_inp - phase_init, phase_step);
+}
+
+/*
+ * Calculate input frame phase, given the output frame
+ * stripe offset and filter parameters
+ */
+static int ipu3_css_osys_calc_stripe_phase_init(int stripe_offset_out,
+                                               int fir_phases, int phase_init,
+                                               int phase_step, int pad_left)
+{
+       int stripe_offset_inp =
+               ipu3_css_osys_calc_stripe_offset(stripe_offset_out,
+                                                fir_phases, phase_init,
+                                                phase_step, pad_left);
+
+       return phase_init + ((pad_left + stripe_offset_inp) * phase_step) -
+               stripe_offset_out * fir_phases;
+}
+
+/*
+ * This function calculates input frame stripe width,
+ * based on output frame stripe offset and filter parameters
+ */
+static int ipu3_css_osys_calc_inp_stripe_width(int stripe_width_out,
+                                              int fir_phases, int phase_init,
+                                              int phase_step, int fir_taps,
+                                              int pad_left, int pad_right)
+{
+       int stripe_width_inp = (stripe_width_out + fir_taps - 1) * fir_phases;
+
+       stripe_width_inp = DIV_ROUND_UP(stripe_width_inp - phase_init,
+                                       phase_step);
+
+       return stripe_width_inp - pad_left - pad_right;
+}
+
+/*
+ * This function calculates output frame stripe width, basedi
+ * on output frame stripe offset and filter parameters
+ */
+static int ipu3_css_osys_out_stripe_width(int stripe_width_inp, int fir_phases,
+                                         int phase_init, int phase_step,
+                                         int fir_taps, int pad_left,
+                                         int pad_right, int column_offset)
+{
+       int stripe_width_out = (pad_left + stripe_width_inp +
+                               pad_right - column_offset) * phase_step;
+
+       stripe_width_out = (stripe_width_out + phase_init) / fir_phases;
+
+       return stripe_width_out - (fir_taps - 1);
+}
+
+struct ipu3_css_reso {
+       unsigned int input_width;
+       unsigned int input_height;
+       enum imgu_abi_frame_format input_format;
+       unsigned int pin_width[IMGU_ABI_OSYS_PINS];
+       unsigned int pin_height[IMGU_ABI_OSYS_PINS];
+       unsigned int pin_stride[IMGU_ABI_OSYS_PINS];
+       enum imgu_abi_frame_format pin_format[IMGU_ABI_OSYS_PINS];
+       int chunk_width;
+       int chunk_height;
+       int block_height;
+       int block_width;
+};
+
+struct ipu3_css_frame_params {
+       /* Output pins */
+       unsigned int enable;
+       unsigned int format;
+       unsigned int flip;
+       unsigned int mirror;
+       unsigned int tiling;
+       unsigned int reduce_range;
+       unsigned int width;
+       unsigned int height;
+       unsigned int stride;
+       unsigned int scaled;
+       unsigned int crop_left;
+       unsigned int crop_top;
+};
+
+struct ipu3_css_stripe_params {
+       unsigned int processing_mode;
+       unsigned int phase_step;
+       unsigned int exp_shift;
+       unsigned int phase_init_left_y;
+       unsigned int phase_init_left_uv;
+       unsigned int phase_init_top_y;
+       unsigned int phase_init_top_uv;
+       unsigned int pad_left_y;
+       unsigned int pad_left_uv;
+       unsigned int pad_right_y;
+       unsigned int pad_right_uv;
+       unsigned int pad_top_y;
+       unsigned int pad_top_uv;
+       unsigned int pad_bottom_y;
+       unsigned int pad_bottom_uv;
+       unsigned int crop_left_y;
+       unsigned int crop_top_y;
+       unsigned int crop_left_uv;
+       unsigned int crop_top_uv;
+       unsigned int start_column_y;
+       unsigned int start_column_uv;
+       unsigned int chunk_width;
+       unsigned int chunk_height;
+       unsigned int block_width;
+       unsigned int block_height;
+       unsigned int input_width;
+       unsigned int input_height;
+       int output_width[IMGU_ABI_OSYS_PINS];
+       int output_height[IMGU_ABI_OSYS_PINS];
+       int output_offset[IMGU_ABI_OSYS_PINS];
+};
+
+/*
+ * frame_params - size IMGU_ABI_OSYS_PINS
+ * stripe_params - size IPU3_UAPI_MAX_STRIPES
+ */
+static int ipu3_css_osys_calc_frame_and_stripe_params(
+               struct ipu3_css *css, unsigned int stripes,
+               struct imgu_abi_osys_config *osys,
+               struct ipu3_css_scaler_info *scaler_luma,
+               struct ipu3_css_scaler_info *scaler_chroma,
+               struct ipu3_css_frame_params frame_params[],
+               struct ipu3_css_stripe_params stripe_params[],
+               unsigned int pipe)
+{
+       struct ipu3_css_reso reso;
+       unsigned int output_width, pin, s;
+       u32 input_width, input_height, target_width, target_height;
+       unsigned int procmode = 0;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
+       input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
+       target_width = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       target_height = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+
+       /* Frame parameters */
+
+       /* Input width for Output System is output width of DVS (with GDC) */
+       reso.input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
+
+       /* Input height for Output System is output height of DVS (with GDC) */
+       reso.input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
+
+       reso.input_format =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+
+       reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+       reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+
+       reso.pin_width[IMGU_ABI_OSYS_PIN_VF] =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       reso.pin_height[IMGU_ABI_OSYS_PIN_VF] =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
+       reso.pin_format[IMGU_ABI_OSYS_PIN_VF] =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+
+       /* Configure the frame parameters for all output pins */
+
+       frame_params[IMGU_ABI_OSYS_PIN_OUT].width =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       frame_params[IMGU_ABI_OSYS_PIN_OUT].height =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       frame_params[IMGU_ABI_OSYS_PIN_VF].width =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       frame_params[IMGU_ABI_OSYS_PIN_VF].height =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0;
+       frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0;
+
+       for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
+               int enable = 0;
+               int scaled = 0;
+               unsigned int format = 0;
+               unsigned int tiling = 0;
+
+               frame_params[pin].flip = 0;
+               frame_params[pin].mirror = 0;
+               frame_params[pin].reduce_range = 0;
+               if (reso.pin_width[pin] != 0 && reso.pin_height[pin] != 0) {
+                       enable = 1;
+                       if (pin == IMGU_ABI_OSYS_PIN_OUT) {
+                               if (reso.input_width < reso.pin_width[pin] ||
+                                   reso.input_height < reso.pin_height[pin])
+                                       return -EINVAL;
+                               /*
+                                * When input and output resolution is
+                                * different instead of scaling, cropping
+                                * should happen. Determine the crop factor
+                                * to do the symmetric cropping
+                                */
+                               frame_params[pin].crop_left = roundclosest_down(
+                                               (reso.input_width -
+                                                reso.pin_width[pin]) / 2,
+                                                IMGU_OSYS_DMA_CROP_W_LIMIT);
+                               frame_params[pin].crop_top = roundclosest_down(
+                                               (reso.input_height -
+                                                reso.pin_height[pin]) / 2,
+                                                IMGU_OSYS_DMA_CROP_H_LIMIT);
+                       } else {
+                               if (reso.pin_width[pin] != reso.input_width ||
+                                   reso.pin_height[pin] != reso.input_height) {
+                                       /*
+                                        * If resolution is different at input
+                                        * and output of OSYS, scaling is
+                                        * considered except when pin is MAIN.
+                                        * Later it will be decide whether
+                                        * scaler factor is 1 or other
+                                        * and cropping has to be done or not.
+                                        */
+                                       scaled = 1;
+                               }
+                       }
+                       ipu3_css_osys_set_format(reso.pin_format[pin], &format,
+                                                &tiling);
+               } else {
+                       enable = 0;
+               }
+               frame_params[pin].enable = enable;
+               frame_params[pin].format = format;
+               frame_params[pin].tiling = tiling;
+               frame_params[pin].stride = reso.pin_stride[pin];
+               frame_params[pin].scaled = scaled;
+       }
+
+       ipu3_css_scaler_calc(input_width, input_height, target_width,
+                            target_height, osys, scaler_luma, scaler_chroma,
+                            &reso.pin_width[IMGU_ABI_OSYS_PIN_VF],
+                            &reso.pin_height[IMGU_ABI_OSYS_PIN_VF], &procmode);
+       dev_dbg(css->dev, "osys scaler procmode is %u", procmode);
+       output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
+
+       if (output_width < reso.input_width / 2) {
+               /* Scaling factor <= 0.5 */
+               reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH;
+               reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
+       } else { /* 0.5 <= Scaling factor <= 1.0 */
+               reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH / 2;
+               reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
+       }
+
+       if (output_width <= reso.input_width * 7 / 8) {
+               /* Scaling factor <= 0.875 */
+               reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT;
+               reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
+       } else { /* 1.0 <= Scaling factor <= 1.75 */
+               reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT / 2;
+               reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
+       }
+
+       /*
+        * Calculate scaler configuration parameters based on input and output
+        * resolution.
+        */
+
+       if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
+               /*
+                * When aspect ratio is different between target resolution and
+                * required resolution, determine the crop factor to do
+                * symmetric cropping
+                */
+               u32 w = reso.pin_width[IMGU_ABI_OSYS_PIN_VF] -
+                       frame_params[IMGU_ABI_OSYS_PIN_VF].width;
+               u32 h = reso.pin_height[IMGU_ABI_OSYS_PIN_VF] -
+                       frame_params[IMGU_ABI_OSYS_PIN_VF].height;
+
+               frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left =
+                       roundclosest_down(w / 2, IMGU_OSYS_DMA_CROP_W_LIMIT);
+               frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top =
+                       roundclosest_down(h / 2, IMGU_OSYS_DMA_CROP_H_LIMIT);
+
+               if (reso.input_height % 4 || reso.input_width % 8) {
+                       dev_err(css->dev, "OSYS input width is not multiple of 8 or\n");
+                       dev_err(css->dev, "height is not multiple of 4\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* Stripe parameters */
+
+       if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
+               output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
+       } else {
+               /*
+                * in case scaler output is not enabled
+                * take output width as input width since
+                * there is no scaling at main pin.
+                * Due to the fact that main pin can be different
+                * from input resolution to osys in the case of cropping,
+                * main pin resolution is not taken.
+                */
+               output_width = reso.input_width;
+       }
+
+       for (s = 0; s < stripes; s++) {
+               int stripe_offset_inp_y = 0;
+               int stripe_offset_inp_uv = 0;
+               int stripe_offset_out_y = 0;
+               int stripe_offset_out_uv = 0;
+               int stripe_phase_init_y = scaler_luma->phase_init;
+               int stripe_phase_init_uv = scaler_chroma->phase_init;
+               int stripe_offset_blk_y = 0;
+               int stripe_offset_blk_uv = 0;
+               int stripe_offset_col_y = 0;
+               int stripe_offset_col_uv = 0;
+               int stripe_pad_left_y = scaler_luma->pad_left;
+               int stripe_pad_left_uv = scaler_chroma->pad_left;
+               int stripe_pad_right_y = scaler_luma->pad_right;
+               int stripe_pad_right_uv = scaler_chroma->pad_right;
+               int stripe_crop_left_y = scaler_luma->crop_left;
+               int stripe_crop_left_uv = scaler_chroma->crop_left;
+               int stripe_input_width_y = reso.input_width;
+               int stripe_input_width_uv = 0;
+               int stripe_output_width_y = output_width;
+               int stripe_output_width_uv = 0;
+               int chunk_floor_y = 0;
+               int chunk_floor_uv = 0;
+               int chunk_ceil_uv = 0;
+
+               if (stripes > 1) {
+                       if (s > 0) {
+                               /* Calculate stripe offsets */
+                               stripe_offset_out_y =
+                                       output_width * s / stripes;
+                               stripe_offset_out_y =
+                                       rounddown(stripe_offset_out_y,
+                                                 IPU3_UAPI_ISP_VEC_ELEMS);
+                               stripe_offset_out_uv = stripe_offset_out_y /
+                                               IMGU_LUMA_TO_CHROMA_RATIO;
+                               stripe_offset_inp_y =
+                                       ipu3_css_osys_calc_stripe_offset(
+                                               stripe_offset_out_y,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               scaler_luma->phase_init,
+                                               scaler_luma->phase_step,
+                                               scaler_luma->pad_left);
+                               stripe_offset_inp_uv =
+                                       ipu3_css_osys_calc_stripe_offset(
+                                               stripe_offset_out_uv,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               scaler_chroma->phase_init,
+                                               scaler_chroma->phase_step,
+                                               scaler_chroma->pad_left);
+
+                               /* Calculate stripe phase init */
+                               stripe_phase_init_y =
+                                       ipu3_css_osys_calc_stripe_phase_init(
+                                               stripe_offset_out_y,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               scaler_luma->phase_init,
+                                               scaler_luma->phase_step,
+                                               scaler_luma->pad_left);
+                               stripe_phase_init_uv =
+                                       ipu3_css_osys_calc_stripe_phase_init(
+                                               stripe_offset_out_uv,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               scaler_chroma->phase_init,
+                                               scaler_chroma->phase_step,
+                                               scaler_chroma->pad_left);
+
+                               /*
+                                * Chunk boundary corner case - luma and chroma
+                                * start from different input chunks.
+                                */
+                               chunk_floor_y = rounddown(stripe_offset_inp_y,
+                                                         reso.chunk_width);
+                               chunk_floor_uv =
+                                       rounddown(stripe_offset_inp_uv,
+                                                 reso.chunk_width /
+                                                 IMGU_LUMA_TO_CHROMA_RATIO);
+
+                               if (chunk_floor_y != chunk_floor_uv *
+                                   IMGU_LUMA_TO_CHROMA_RATIO) {
+                                       /*
+                                        * Match starting luma/chroma chunks.
+                                        * Decrease offset for UV and add output
+                                        * cropping.
+                                        */
+                                       stripe_offset_inp_uv -= 1;
+                                       stripe_crop_left_uv += 1;
+                                       stripe_phase_init_uv -=
+                                               scaler_luma->phase_step;
+                                       if (stripe_phase_init_uv < 0)
+                                               stripe_phase_init_uv =
+                                                       stripe_phase_init_uv +
+                                                       IMGU_OSYS_FIR_PHASES;
+                               }
+                               /*
+                                * FW workaround for a HW bug: if the first
+                                * chroma pixel is generated exactly at the end
+                                * of chunck scaler HW may not output the pixel
+                                * for downscale factors smaller than 1.5
+                                * (timing issue).
+                                */
+                               chunk_ceil_uv =
+                                       roundup(stripe_offset_inp_uv,
+                                               reso.chunk_width /
+                                               IMGU_LUMA_TO_CHROMA_RATIO);
+
+                               if (stripe_offset_inp_uv ==
+                                   chunk_ceil_uv - IMGU_OSYS_TAPS_UV) {
+                                       /*
+                                        * Decrease input offset and add
+                                        * output cropping
+                                        */
+                                       stripe_offset_inp_uv -= 1;
+                                       stripe_phase_init_uv -=
+                                               scaler_luma->phase_step;
+                                       if (stripe_phase_init_uv < 0) {
+                                               stripe_phase_init_uv +=
+                                                       IMGU_OSYS_FIR_PHASES;
+                                               stripe_crop_left_uv += 1;
+                                       }
+                               }
+
+                               /*
+                                * Calculate block and column offsets for the
+                                * input stripe
+                                */
+                               stripe_offset_blk_y =
+                                       rounddown(stripe_offset_inp_y,
+                                                 IMGU_INPUT_BLOCK_WIDTH);
+                               stripe_offset_blk_uv =
+                                       rounddown(stripe_offset_inp_uv,
+                                                 IMGU_INPUT_BLOCK_WIDTH /
+                                                 IMGU_LUMA_TO_CHROMA_RATIO);
+                               stripe_offset_col_y = stripe_offset_inp_y -
+                                                       stripe_offset_blk_y;
+                               stripe_offset_col_uv = stripe_offset_inp_uv -
+                                                       stripe_offset_blk_uv;
+
+                               /* Left padding is only for the first stripe */
+                               stripe_pad_left_y = 0;
+                               stripe_pad_left_uv = 0;
+                       }
+
+                       /* Right padding is only for the last stripe */
+                       if (s < stripes - 1) {
+                               int next_offset;
+
+                               stripe_pad_right_y = 0;
+                               stripe_pad_right_uv = 0;
+
+                               next_offset = output_width * (s + 1) / stripes;
+                               next_offset = rounddown(next_offset, 64);
+                               stripe_output_width_y = next_offset -
+                                                       stripe_offset_out_y;
+                       } else {
+                               stripe_output_width_y = output_width -
+                                                       stripe_offset_out_y;
+                       }
+
+                       /* Calculate target output stripe width */
+                       stripe_output_width_uv = stripe_output_width_y /
+                                               IMGU_LUMA_TO_CHROMA_RATIO;
+                       /* Calculate input stripe width */
+                       stripe_input_width_y = stripe_offset_col_y +
+                               ipu3_css_osys_calc_inp_stripe_width(
+                                               stripe_output_width_y,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               stripe_phase_init_y,
+                                               scaler_luma->phase_step,
+                                               IMGU_OSYS_TAPS_Y,
+                                               stripe_pad_left_y,
+                                               stripe_pad_right_y);
+
+                       stripe_input_width_uv = stripe_offset_col_uv +
+                               ipu3_css_osys_calc_inp_stripe_width(
+                                               stripe_output_width_uv,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               stripe_phase_init_uv,
+                                               scaler_chroma->phase_step,
+                                               IMGU_OSYS_TAPS_UV,
+                                               stripe_pad_left_uv,
+                                               stripe_pad_right_uv);
+
+                       stripe_input_width_uv = max(DIV_ROUND_UP(
+                                                   stripe_input_width_y,
+                                                   IMGU_LUMA_TO_CHROMA_RATIO),
+                                                   stripe_input_width_uv);
+
+                       stripe_input_width_y = stripe_input_width_uv *
+                                               IMGU_LUMA_TO_CHROMA_RATIO;
+
+                       if (s >= stripes - 1) {
+                               stripe_input_width_y = reso.input_width -
+                                       stripe_offset_blk_y;
+                               /*
+                                * The scaler requires that the last stripe
+                                * spans at least two input blocks.
+                                */
+                       }
+
+                       /*
+                        * Spec: input stripe width must be a multiple of 8.
+                        * Increase the input width and recalculate the output
+                        * width. This may produce an extra column of junk
+                        * blocks which will be overwritten by the
+                        * next stripe.
+                        */
+                       stripe_input_width_y = ALIGN(stripe_input_width_y, 8);
+                       stripe_output_width_y =
+                               ipu3_css_osys_out_stripe_width(
+                                               stripe_input_width_y,
+                                               IMGU_OSYS_FIR_PHASES,
+                                               stripe_phase_init_y,
+                                               scaler_luma->phase_step,
+                                               IMGU_OSYS_TAPS_Y,
+                                               stripe_pad_left_y,
+                                               stripe_pad_right_y,
+                                               stripe_offset_col_y);
+
+                       stripe_output_width_y =
+                                       rounddown(stripe_output_width_y,
+                                                 IMGU_LUMA_TO_CHROMA_RATIO);
+               }
+               /*
+                * Following section executes and process parameters
+                * for both cases - Striping or No Striping.
+                */
+               {
+                       unsigned int i;
+                       int pin_scale = 0;
+                       /*Input resolution */
+
+                       stripe_params[s].input_width = stripe_input_width_y;
+                       stripe_params[s].input_height = reso.input_height;
+
+                       for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) {
+                               if (frame_params[i].scaled) {
+                                       /*
+                                        * Output stripe resolution and offset
+                                        * as produced by the scaler; actual
+                                        * output resolution may be slightly
+                                        * smaller.
+                                        */
+                                       stripe_params[s].output_width[i] =
+                                               stripe_output_width_y;
+                                       stripe_params[s].output_height[i] =
+                                               reso.pin_height[i];
+                                       stripe_params[s].output_offset[i] =
+                                               stripe_offset_out_y;
+
+                                       pin_scale += frame_params[i].scaled;
+                               } else {
+                                       /* Unscaled pin */
+                                       stripe_params[s].output_width[i] =
+                                               stripe_params[s].input_width;
+                                       stripe_params[s].output_height[i] =
+                                               stripe_params[s].input_height;
+                                       stripe_params[s].output_offset[i] =
+                                               stripe_offset_blk_y;
+                               }
+                       }
+
+                       /* If no pin use scale, we use BYPASS mode */
+                       stripe_params[s].processing_mode = procmode;
+                       stripe_params[s].phase_step = scaler_luma->phase_step;
+                       stripe_params[s].exp_shift = scaler_luma->exp_shift;
+                       stripe_params[s].phase_init_left_y =
+                               stripe_phase_init_y;
+                       stripe_params[s].phase_init_left_uv =
+                               stripe_phase_init_uv;
+                       stripe_params[s].phase_init_top_y =
+                               scaler_luma->phase_init;
+                       stripe_params[s].phase_init_top_uv =
+                               scaler_chroma->phase_init;
+                       stripe_params[s].pad_left_y = stripe_pad_left_y;
+                       stripe_params[s].pad_left_uv = stripe_pad_left_uv;
+                       stripe_params[s].pad_right_y = stripe_pad_right_y;
+                       stripe_params[s].pad_right_uv = stripe_pad_right_uv;
+                       stripe_params[s].pad_top_y = scaler_luma->pad_left;
+                       stripe_params[s].pad_top_uv = scaler_chroma->pad_left;
+                       stripe_params[s].pad_bottom_y = scaler_luma->pad_right;
+                       stripe_params[s].pad_bottom_uv =
+                               scaler_chroma->pad_right;
+                       stripe_params[s].crop_left_y = stripe_crop_left_y;
+                       stripe_params[s].crop_top_y = scaler_luma->crop_top;
+                       stripe_params[s].crop_left_uv = stripe_crop_left_uv;
+                       stripe_params[s].crop_top_uv = scaler_chroma->crop_top;
+                       stripe_params[s].start_column_y = stripe_offset_col_y;
+                       stripe_params[s].start_column_uv = stripe_offset_col_uv;
+                       stripe_params[s].chunk_width = reso.chunk_width;
+                       stripe_params[s].chunk_height = reso.chunk_height;
+                       stripe_params[s].block_width = reso.block_width;
+                       stripe_params[s].block_height = reso.block_height;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * This function configures the Output Formatter System, given the number of
+ * stripes, scaler luma and chrome parameters
+ */
+static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int pipe,
+                             unsigned int stripes,
+                             struct imgu_abi_osys_config *osys,
+                             struct ipu3_css_scaler_info *scaler_luma,
+                             struct ipu3_css_scaler_info *scaler_chroma,
+                             struct imgu_abi_stripes block_stripes[])
+{
+       struct ipu3_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
+       struct ipu3_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
+       struct imgu_abi_osys_formatter_params *param;
+       unsigned int pin, s;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       memset(osys, 0, sizeof(*osys));
+
+       /* Compute the frame and stripe params */
+       if (ipu3_css_osys_calc_frame_and_stripe_params(css, stripes, osys,
+                                                      scaler_luma,
+                                                      scaler_chroma,
+                                                      frame_params,
+                                                      stripe_params, pipe))
+               return -EINVAL;
+
+       /* Output formatter system parameters */
+
+       for (s = 0; s < stripes; s++) {
+               struct imgu_abi_osys_scaler_params *scaler =
+                                       &osys->scaler[s].param;
+               int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT;
+               int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP;
+
+               /* OUTPUT 0 / PIN 0 is only Scaler output */
+               scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
+
+               /*
+                * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
+                * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) /
+                *   (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
+                * = 2 * 64 / 32 = 4
+                */
+               scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE;
+               /*
+                * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size)
+                * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) +
+                *      (VMEM1_y_size / 4)
+                * = (VMEM1_y_size) + (VMEM1_y_size / 4) +
+                * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4
+                * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
+                */
+               scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+               scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+                                               IMGU_VMEM1_U_OFFSET;
+               scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+                                               IMGU_VMEM1_V_OFFSET;
+               scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE;
+               scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+               scaler->inp_buf_chunk_width = stripe_params[s].chunk_width;
+               scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS;
+
+               /* Output buffers */
+               scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
+               scaler->out_buf_y_line_stride = stripe_params[s].block_width /
+                                               IMGU_VMEM1_ELEMS_PER_VEC;
+               scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+               scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+                                               IMGU_VMEM1_U_OFFSET;
+               scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+                                               IMGU_VMEM1_V_OFFSET;
+               scaler->out_buf_uv_line_stride = stripe_params[s].block_width /
+                                               IMGU_VMEM1_ELEMS_PER_VEC / 2;
+               scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+               scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS;
+
+               /* Intermediate buffers */
+               scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR;
+               scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE;
+               scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR;
+               scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR;
+               scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE;
+               scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK;
+               scaler->int_buf_chunk_width = stripe_params[s].chunk_height;
+               scaler->int_buf_chunk_height = stripe_params[s].block_width;
+
+               /* Context buffers */
+               scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR;
+               scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR;
+               scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR;
+               scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR;
+               scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR;
+               scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR;
+
+               /* Addresses for release-input and process-output tokens */
+               scaler->release_inp_buf_addr = fifo_addr_ack;
+               scaler->release_inp_buf_en = 1;
+               scaler->release_out_buf_en = 1;
+               scaler->process_out_buf_addr = fifo_addr_fmt;
+
+               /* Settings dimensions, padding, cropping */
+               scaler->input_image_y_width = stripe_params[s].input_width;
+               scaler->input_image_y_height = stripe_params[s].input_height;
+               scaler->input_image_y_start_column =
+                                       stripe_params[s].start_column_y;
+               scaler->input_image_uv_start_column =
+                                       stripe_params[s].start_column_uv;
+               scaler->input_image_y_left_pad = stripe_params[s].pad_left_y;
+               scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv;
+               scaler->input_image_y_right_pad = stripe_params[s].pad_right_y;
+               scaler->input_image_uv_right_pad =
+                                       stripe_params[s].pad_right_uv;
+               scaler->input_image_y_top_pad = stripe_params[s].pad_top_y;
+               scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv;
+               scaler->input_image_y_bottom_pad =
+                                       stripe_params[s].pad_bottom_y;
+               scaler->input_image_uv_bottom_pad =
+                                       stripe_params[s].pad_bottom_uv;
+               scaler->processing_mode = stripe_params[s].processing_mode;
+               scaler->scaling_ratio = stripe_params[s].phase_step;
+               scaler->y_left_phase_init = stripe_params[s].phase_init_left_y;
+               scaler->uv_left_phase_init =
+                                       stripe_params[s].phase_init_left_uv;
+               scaler->y_top_phase_init = stripe_params[s].phase_init_top_y;
+               scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv;
+               scaler->coeffs_exp_shift = stripe_params[s].exp_shift;
+               scaler->out_y_left_crop = stripe_params[s].crop_left_y;
+               scaler->out_uv_left_crop = stripe_params[s].crop_left_uv;
+               scaler->out_y_top_crop = stripe_params[s].crop_top_y;
+               scaler->out_uv_top_crop = stripe_params[s].crop_top_uv;
+
+               for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
+                       int in_fifo_addr;
+                       int out_fifo_addr;
+                       int block_width_vecs;
+                       int input_width_s;
+                       int input_width_vecs;
+                       int input_buf_y_st_addr;
+                       int input_buf_u_st_addr;
+                       int input_buf_v_st_addr;
+                       int input_buf_y_line_stride;
+                       int input_buf_uv_line_stride;
+                       int output_buf_y_line_stride;
+                       int output_buf_uv_line_stride;
+                       int output_buf_nr_y_lines;
+                       int block_height;
+                       int block_width;
+                       struct imgu_abi_osys_frame_params *fr_pr;
+
+                       fr_pr = &osys->frame[pin].param;
+
+                       /* Frame parameters */
+                       fr_pr->enable = frame_params[pin].enable;
+                       fr_pr->format = frame_params[pin].format;
+                       fr_pr->mirror = frame_params[pin].mirror;
+                       fr_pr->flip = frame_params[pin].flip;
+                       fr_pr->tiling = frame_params[pin].tiling;
+                       fr_pr->width = frame_params[pin].width;
+                       fr_pr->height = frame_params[pin].height;
+                       fr_pr->stride = frame_params[pin].stride;
+                       fr_pr->scaled = frame_params[pin].scaled;
+
+                       /* Stripe parameters */
+                       osys->stripe[s].crop_top[pin] =
+                               frame_params[pin].crop_top;
+                       osys->stripe[s].input_width =
+                               stripe_params[s].input_width;
+                       osys->stripe[s].input_height =
+                               stripe_params[s].input_height;
+                       osys->stripe[s].block_height =
+                               stripe_params[s].block_height;
+                       osys->stripe[s].block_width =
+                               stripe_params[s].block_width;
+                       osys->stripe[s].output_width[pin] =
+                               stripe_params[s].output_width[pin];
+                       osys->stripe[s].output_height[pin] =
+                               stripe_params[s].output_height[pin];
+
+                       if (s == 0) {
+                               /* Only first stripe should do left cropping */
+                               osys->stripe[s].crop_left[pin] =
+                                       frame_params[pin].crop_left;
+                               osys->stripe[s].output_offset[pin] =
+                                       stripe_params[s].output_offset[pin];
+                       } else {
+                               /*
+                                * Stripe offset for other strips should be
+                                * adjusted according to the cropping done
+                                * at the first strip
+                                */
+                               osys->stripe[s].crop_left[pin] = 0;
+                               osys->stripe[s].output_offset[pin] =
+                                       (stripe_params[s].output_offset[pin] -
+                                        osys->stripe[0].crop_left[pin]);
+                       }
+
+                       if (!frame_params[pin].enable)
+                               continue;
+
+                       /* Formatter: configurations */
+
+                       /*
+                        * Get the dimensions of the input blocks of the
+                        * formatter, which is the same as the output
+                        * blocks of the scaler.
+                        */
+                       if (frame_params[pin].scaled) {
+                               block_height = stripe_params[s].block_height;
+                               block_width = stripe_params[s].block_width;
+                       } else {
+                               block_height = IMGU_OSYS_BLOCK_HEIGHT;
+                               block_width = IMGU_OSYS_BLOCK_WIDTH;
+                       }
+                       block_width_vecs =
+                                       block_width / IMGU_VMEM1_ELEMS_PER_VEC;
+                       /*
+                        * The input/output line stride depends on the
+                        * block size.
+                        */
+                       input_buf_y_line_stride = block_width_vecs;
+                       input_buf_uv_line_stride = block_width_vecs / 2;
+                       output_buf_y_line_stride = block_width_vecs;
+                       output_buf_uv_line_stride = block_width_vecs / 2;
+                       output_buf_nr_y_lines = block_height;
+                       if (frame_params[pin].format ==
+                           IMGU_ABI_OSYS_FORMAT_NV12 ||
+                           frame_params[pin].format ==
+                           IMGU_ABI_OSYS_FORMAT_NV21)
+                               output_buf_uv_line_stride =
+                                       output_buf_y_line_stride;
+
+                       /*
+                        * Tiled outputs use a different output buffer
+                        * configuration. The input (= scaler output) block
+                        * width translates to a tile height, and the block
+                        * height to the tile width. The default block size of
+                        * 128x32 maps exactly onto a 4kB tile (512x8) for Y.
+                        * For UV, the tile width is always half.
+                        */
+                       if (frame_params[pin].tiling) {
+                               output_buf_nr_y_lines = 8;
+                               output_buf_y_line_stride = 512 /
+                                       IMGU_VMEM1_ELEMS_PER_VEC;
+                               output_buf_uv_line_stride = 256 /
+                                       IMGU_VMEM1_ELEMS_PER_VEC;
+                       }
+
+                       /*
+                        * Store the output buffer line stride. Will be
+                        * used to compute buffer offsets in boundary
+                        * conditions when output blocks are partially
+                        * outside the image.
+                        */
+                       osys->stripe[s].buf_stride[pin] =
+                               output_buf_y_line_stride *
+                               IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS;
+                       if (frame_params[pin].scaled) {
+                               /*
+                                * The input buffs are the intermediate
+                                * buffers (scalers' output)
+                                */
+                               input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
+                               input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+                                                       IMGU_VMEM1_U_OFFSET;
+                               input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+                                                       IMGU_VMEM1_V_OFFSET;
+                       } else {
+                               /*
+                                * The input bufferss are the buffers
+                                * filled by the SP
+                                */
+                               input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
+                               input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+                                                       IMGU_VMEM1_U_OFFSET;
+                               input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+                                                       IMGU_VMEM1_V_OFFSET;
+                       }
+
+                       /*
+                        * The formatter input width must be rounded to
+                        * the block width. Otherwise the formatter will
+                        * not recognize the end of the line, resulting
+                        * in incorrect tiling (system may hang!) and
+                        * possibly other problems.
+                        */
+                       input_width_s =
+                               roundup(stripe_params[s].output_width[pin],
+                                       block_width);
+                       input_width_vecs = input_width_s /
+                                       IMGU_VMEM1_ELEMS_PER_VEC;
+                       out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
+                       /*
+                        * Process-output tokens must be sent to the SP.
+                        * When scaling, the release-input tokens can be
+                        * sent directly to the scaler, otherwise the
+                        * formatter should send them to the SP.
+                        */
+                       if (frame_params[pin].scaled)
+                               in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER;
+                       else
+                               in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
+
+                       /* Formatter */
+                       param = &osys->formatter[s][pin].param;
+
+                       param->format = frame_params[pin].format;
+                       param->flip = frame_params[pin].flip;
+                       param->mirror = frame_params[pin].mirror;
+                       param->tiling = frame_params[pin].tiling;
+                       param->reduce_range = frame_params[pin].reduce_range;
+                       param->alpha_blending = 0;
+                       param->release_inp_addr = in_fifo_addr;
+                       param->release_inp_en = 1;
+                       param->process_out_buf_addr = out_fifo_addr;
+                       param->image_width_vecs = input_width_vecs;
+                       param->image_height_lines =
+                               stripe_params[s].output_height[pin];
+                       param->inp_buff_y_st_addr = input_buf_y_st_addr;
+                       param->inp_buff_y_line_stride = input_buf_y_line_stride;
+                       param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+                       param->int_buff_u_st_addr = input_buf_u_st_addr;
+                       param->int_buff_v_st_addr = input_buf_v_st_addr;
+                       param->inp_buff_uv_line_stride =
+                               input_buf_uv_line_stride;
+                       param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+                       param->out_buff_level = 0;
+                       param->out_buff_nr_y_lines = output_buf_nr_y_lines;
+                       param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET;
+                       param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET;
+                       param->out_buff_y_line_stride =
+                               output_buf_y_line_stride;
+                       param->out_buff_uv_line_stride =
+                               output_buf_uv_line_stride;
+                       param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR;
+                       param->hist_buff_line_stride =
+                               IMGU_VMEM1_HST_BUF_STRIDE;
+                       param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES;
+               }
+       }
+
+       block_stripes[0].offset = 0;
+       if (stripes <= 1) {
+               block_stripes[0].width = stripe_params[0].input_width;
+               block_stripes[0].height = stripe_params[0].input_height;
+       } else {
+               struct imgu_fw_info *bi =
+                       &css->fwp->binary_header[css_pipe->bindex];
+               unsigned int sp_block_width =
+                               bi->info.isp.sp.block.block_width *
+                               IPU3_UAPI_ISP_VEC_ELEMS;
+
+               block_stripes[0].width = roundup(stripe_params[0].input_width,
+                                                sp_block_width);
+               block_stripes[1].offset =
+                       rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
+                                 stripe_params[1].input_width, sp_block_width);
+               block_stripes[1].width =
+                       roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
+                               block_stripes[1].offset, sp_block_width);
+               block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
+               block_stripes[1].height = block_stripes[0].height;
+       }
+
+       return 0;
+}
+
+/*********************** Mostly 3A operations ******************************/
+
+/*
+ * This function creates a "TO-DO list" (operations) for the sp code.
+ *
+ * There are 2 types of operations:
+ * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to
+ *    accelerator space (NOTE that this space is limited) associated data:
+ *    DDR address + accelerator's config set index(acc's address).
+ *
+ * 2. Issue "Process Lines Command" to shd accelerator
+ *    associated data: #lines + which config set to use (actually, accelerator
+ *    will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction
+ *    of not touching config sets x & (x+1)%num_of_sets when process_lines(x)
+ *    is active).
+ *
+ * Basically there are 2 types of operations "chunks":
+ * 1. "initial chunk": Initially, we do as much transfers as we can (and need)
+ *    [0 - max sets(3) ] followed by 1 or 2 "process lines" operations.
+ *
+ * 2. "regular chunk" - 1 transfer followed by 1 process line operation.
+ *    (in some cases we might need additional transfer ate the last chunk).
+ *
+ * for some case:
+ * --> init
+ *     tr (0)
+ *     tr (1)
+ *     tr (2)
+ *     pl (0)
+ *     pl (1)
+ * --> ack (0)
+ *     tr (3)
+ *     pl (2)
+ * --> ack (1)
+ *     pl (3)
+ * --> ack (2)
+ *     do nothing
+ * --> ack (3)
+ *     do nothing
+ */
+
+static int
+ipu3_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops,
+                     const struct ipu3_uapi_shd_grid_config *grid,
+                     unsigned int image_height)
+{
+       unsigned int block_height = 1 << grid->block_height_log2;
+       unsigned int grid_height_per_slice = grid->grid_height_per_slice;
+       unsigned int set_height = grid_height_per_slice * block_height;
+
+       /* We currently support only abs(y_start) > grid_height_per_slice */
+       unsigned int positive_y_start = (unsigned int)-grid->y_start;
+       unsigned int first_process_lines =
+                               set_height - (positive_y_start % set_height);
+       unsigned int last_set_height;
+       unsigned int num_of_sets;
+
+       struct imgu_abi_acc_operation *p_op;
+       struct imgu_abi_acc_process_lines_cmd_data *p_pl;
+       struct imgu_abi_shd_transfer_luts_set_data *p_tr;
+
+       unsigned int op_idx, pl_idx, tr_idx;
+       unsigned char tr_set_num, pl_cfg_set;
+
+       /*
+        * When the number of lines for the last process lines command
+        * is equal to a set height, we need another line of grid cell -
+        * additional transfer is required.
+        */
+       unsigned char last_tr = 0;
+
+       /* Add "process lines" command to the list of operations */
+       bool add_pl;
+       /* Add DMA xfer (config set) command to the list of ops */
+       bool add_tr;
+
+       /*
+        * Available partial grid (the part that fits into #IMGU_SHD_SETS sets)
+        * doesn't cover whole frame - need to process in chunks
+        */
+       if (image_height > first_process_lines) {
+               last_set_height =
+                       (image_height - first_process_lines) % set_height;
+               num_of_sets = last_set_height > 0 ?
+                       (image_height - first_process_lines) / set_height + 2 :
+                       (image_height - first_process_lines) / set_height + 1;
+               last_tr = (set_height - last_set_height <= block_height ||
+                          last_set_height == 0) ? 1 : 0;
+       } else { /* partial grid covers whole frame */
+               last_set_height = 0;
+               num_of_sets = 1;
+               first_process_lines = image_height;
+               last_tr = set_height - image_height <= block_height ? 1 : 0;
+       }
+
+       /* Init operations lists and counters */
+       p_op = ops->operation_list;
+       op_idx = 0;
+       p_pl = ops->process_lines_data;
+       pl_idx = 0;
+       p_tr = ops->transfer_data;
+       tr_idx = 0;
+
+       memset(ops, 0, sizeof(*ops));
+
+       /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */
+       tr_set_num = 0;
+       pl_cfg_set = 0;
+
+       /*
+        * Always start with a transfer - process lines command must be
+        * initiated only after appropriate config sets are in place
+        * (2 configuration sets per process line command, except for last one).
+        */
+       add_pl = false;
+       add_tr = true;
+
+       while (add_pl || add_tr) {
+               /* Transfer ops */
+               if (add_tr) {
+                       if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
+                           tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS)
+                               return -EINVAL;
+                       p_op[op_idx].op_type =
+                               IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
+                       p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE;
+                       op_idx++;
+                       p_tr[tr_idx].set_number = tr_set_num;
+                       tr_idx++;
+                       tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS;
+               }
+
+               /* Process-lines ops */
+               if (add_pl) {
+                       if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
+                           pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES)
+                               return -EINVAL;
+                       p_op[op_idx].op_type =
+                               IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+
+                       /*
+                        * In case we have 2 process lines commands -
+                        * don't stop after the first one
+                        */
+                       if (pl_idx == 0 && num_of_sets != 1)
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_IDLE;
+                       /*
+                        * Initiate last process lines command -
+                        * end of operation list.
+                        */
+                       else if (pl_idx == num_of_sets - 1)
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_END_OF_OPS;
+                       /*
+                        * Intermediate process line command - end of operation
+                        * "chunk" (meaning few "transfers" followed by few
+                        * "process lines" commands).
+                        */
+                       else
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_END_OF_ACK;
+
+                       op_idx++;
+
+                       /* first process line operation */
+                       if (pl_idx == 0)
+                               p_pl[pl_idx].lines = first_process_lines;
+                       /* Last process line operation */
+                       else if (pl_idx == num_of_sets - 1 &&
+                                last_set_height > 0)
+                               p_pl[pl_idx].lines = last_set_height;
+                       else    /* "regular" process lines operation */
+                               p_pl[pl_idx].lines = set_height;
+
+                       p_pl[pl_idx].cfg_set = pl_cfg_set;
+                       pl_idx++;
+                       pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS;
+               }
+
+               /*
+                * Initially, we always transfer
+                * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the
+                * corresponding process lines commands.
+                */
+               if (tr_idx == IMGU_SHD_SETS ||
+                   tr_idx == num_of_sets + last_tr) {
+                       add_tr = false;
+                       add_pl = true;
+               }
+
+               /*
+                * We have finished the "initial" operations chunk -
+                * be ready to get more chunks.
+                */
+               if (pl_idx == 2) {
+                       add_tr = true;
+                       add_pl = true;
+               }
+
+               /* Stop conditions for each operation type */
+               if (tr_idx == num_of_sets + last_tr)
+                       add_tr = false;
+               if (pl_idx == num_of_sets)
+                       add_pl = false;
+       }
+
+       return 0;
+}
+
+/*
+ * The follow handshake procotol is the same for AF, AWB and AWB FR.
+ *
+ * for n sets of meta-data, the flow is:
+ * --> init
+ *  process-lines  (0)
+ *  process-lines  (1)  eoc
+ *  --> ack (0)
+ *  read-meta-data (0)
+ *  process-lines  (2)  eoc
+ *  --> ack (1)
+ *  read-meta-data (1)
+ *  process-lines  (3)  eoc
+ *  ...
+ *
+ *  --> ack (n-3)
+ *  read-meta-data (n-3)
+ *  process-lines  (n-1) eoc
+ *  --> ack (n-2)
+ *  read-meta-data (n-2) eoc
+ *  --> ack (n-1)
+ *  read-meta-data (n-1) eof
+ *
+ * for 2 sets we get:
+ * --> init
+ * pl (0)
+ * pl (1) eoc
+ * --> ack (0)
+ * pl (2) - rest of image, if applicable)
+ * rmd (0) eoc
+ * --> ack (1)
+ * rmd (1) eof
+ * --> (ack (2))
+ * do nothing
+ *
+ * for only one set:
+ *
+ * --> init
+ * pl(0)   eoc
+ * --> ack (0)
+ * rmd (0) eof
+ *
+ * grid smaller than image case
+ * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
+ * start at (0,0)
+ * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
+ * => 1st process lines = 80
+ * we're left with 128-80=48 lines (6 blocks vertical)
+ * => 2nd process lines = 48
+ * last process lines to cover the image - image_height - 128
+ *
+ * --> init
+ * pl (0) first
+ * pl (1) last-in-grid
+ * --> ack (0)
+ * rmd (0)
+ * pl (2) after-grid
+ * --> ack (1)
+ * rmd (1) eof
+ * --> ack (2)
+ * do nothing
+ */
+struct process_lines {
+       unsigned int image_height;
+       unsigned short grid_height;
+       unsigned short block_height;
+       unsigned short y_start;
+       unsigned char grid_height_per_slice;
+
+       unsigned short max_op; /* max operation */
+       unsigned short max_tr; /* max transaction */
+       unsigned char acc_enable;
+};
+
+/* Helper to config intra_frame_operations_data. */
+static int
+ipu3_css_acc_process_lines(const struct process_lines *pl,
+                          struct imgu_abi_acc_operation *p_op,
+                          struct imgu_abi_acc_process_lines_cmd_data *p_pl,
+                          struct imgu_abi_acc_transfer_op_data *p_tr)
+{
+       unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0;
+       unsigned char tr_set_num = 0, pl_cfg_set = 0;
+       const unsigned short grid_last_line =
+                       pl->y_start + pl->grid_height * pl->block_height;
+       const unsigned short process_lines =
+                       pl->grid_height_per_slice * pl->block_height;
+
+       unsigned int process_lines_after_grid;
+       unsigned short first_process_lines;
+       unsigned short last_process_lines_in_grid;
+
+       unsigned short num_of_process_lines;
+       unsigned short num_of_sets;
+
+       if (pl->grid_height_per_slice == 0)
+               return -EINVAL;
+
+       if (pl->acc_enable && grid_last_line > pl->image_height)
+               return -EINVAL;
+
+       num_of_sets = pl->grid_height / pl->grid_height_per_slice;
+       if (num_of_sets * pl->grid_height_per_slice < pl->grid_height)
+               num_of_sets++;
+
+       /* Account for two line delay inside the FF */
+       if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) {
+               first_process_lines = process_lines + pl->y_start + 2;
+               last_process_lines_in_grid =
+                       (grid_last_line - first_process_lines) -
+                       ((num_of_sets - 2) * process_lines) + 4;
+               process_lines_after_grid =
+                       pl->image_height - grid_last_line - 4;
+       } else {
+               first_process_lines = process_lines + pl->y_start;
+               last_process_lines_in_grid =
+                       (grid_last_line - first_process_lines) -
+                       ((num_of_sets - 2) * process_lines);
+               process_lines_after_grid = pl->image_height - grid_last_line;
+       }
+
+       num_of_process_lines = num_of_sets;
+       if (process_lines_after_grid > 0)
+               num_of_process_lines++;
+
+       while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) {
+               /* Read meta-data */
+               if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) {
+                       if (op_idx >= pl->max_op || tr_idx >= pl->max_tr)
+                               return -EINVAL;
+
+                       p_op[op_idx].op_type =
+                               IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
+
+                       if (tr_idx == num_of_sets - 1)
+                               /* The last operation is always a tr */
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_END_OF_OPS;
+                       else if (tr_idx == num_of_sets - 2)
+                               if (process_lines_after_grid == 0)
+                                       /*
+                                        * No additional pl op left -
+                                        * this op is left as lats of cycle
+                                        */
+                                       p_op[op_idx].op_indicator =
+                                               IMGU_ABI_ACC_OP_END_OF_ACK;
+                               else
+                                       /*
+                                        * We still have to process-lines after
+                                        * the grid so have one more pl op
+                                        */
+                                       p_op[op_idx].op_indicator =
+                                               IMGU_ABI_ACC_OP_IDLE;
+                       else
+                               /* Default - usually there's a pl after a tr */
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_IDLE;
+
+                       op_idx++;
+                       if (p_tr) {
+                               p_tr[tr_idx].set_number = tr_set_num;
+                               tr_set_num = 1 - tr_set_num;
+                       }
+                       tr_idx++;
+               }
+
+               /* process_lines */
+               if (pl_idx < num_of_process_lines) {
+                       if (op_idx >= pl->max_op || pl_idx >= pl->max_tr)
+                               return -EINVAL;
+
+                       p_op[op_idx].op_type =
+                               IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+                       if (pl_idx == 0)
+                               if (num_of_process_lines == 1)
+                                       /* Only one pl op */
+                                       p_op[op_idx].op_indicator =
+                                               IMGU_ABI_ACC_OP_END_OF_ACK;
+                               else
+                                       /* On init - do two pl ops */
+                                       p_op[op_idx].op_indicator =
+                                               IMGU_ABI_ACC_OP_IDLE;
+                       else
+                               /* Usually pl is the end of the ack cycle */
+                               p_op[op_idx].op_indicator =
+                                       IMGU_ABI_ACC_OP_END_OF_ACK;
+
+                       op_idx++;
+
+                       if (pl_idx == 0)
+                               /* First process line */
+                               p_pl[pl_idx].lines = first_process_lines;
+                       else if (pl_idx == num_of_sets - 1)
+                               /* Last in grid */
+                               p_pl[pl_idx].lines = last_process_lines_in_grid;
+                       else if (pl_idx == num_of_process_lines - 1)
+                               /* After the grid */
+                               p_pl[pl_idx].lines = process_lines_after_grid;
+                       else
+                               /* Inside the grid */
+                               p_pl[pl_idx].lines = process_lines;
+
+                       if (p_tr) {
+                               p_pl[pl_idx].cfg_set = pl_cfg_set;
+                               pl_cfg_set = 1 - pl_cfg_set;
+                       }
+                       pl_idx++;
+               }
+       }
+
+       return 0;
+}
+
+static int ipu3_css_af_ops_calc(struct ipu3_css *css, unsigned int pipe,
+                               struct imgu_abi_af_config *af_config)
+{
+       struct imgu_abi_af_intra_frame_operations_data *to =
+               &af_config->operations_data;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+
+       struct process_lines pl = {
+               .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
+               .grid_height = af_config->config.grid_cfg.height,
+               .block_height =
+                       1 << af_config->config.grid_cfg.block_height_log2,
+               .y_start = af_config->config.grid_cfg.y_start &
+                       IPU3_UAPI_GRID_START_MASK,
+               .grid_height_per_slice =
+                       af_config->stripes[0].grid_cfg.height_per_slice,
+               .max_op = IMGU_ABI_AF_MAX_OPERATIONS,
+               .max_tr = IMGU_ABI_AF_MAX_TRANSFERS,
+               .acc_enable = bi->info.isp.sp.enable.af,
+       };
+
+       return ipu3_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
+                                         NULL);
+}
+
+static int
+ipu3_css_awb_fr_ops_calc(struct ipu3_css *css, unsigned int pipe,
+                        struct imgu_abi_awb_fr_config *awb_fr_config)
+{
+       struct imgu_abi_awb_fr_intra_frame_operations_data *to =
+               &awb_fr_config->operations_data;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+       struct process_lines pl = {
+               .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
+               .grid_height = awb_fr_config->config.grid_cfg.height,
+               .block_height =
+                       1 << awb_fr_config->config.grid_cfg.block_height_log2,
+               .y_start = awb_fr_config->config.grid_cfg.y_start &
+                       IPU3_UAPI_GRID_START_MASK,
+               .grid_height_per_slice =
+                       awb_fr_config->stripes[0].grid_cfg.height_per_slice,
+               .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS,
+               .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES,
+               .acc_enable = bi->info.isp.sp.enable.awb_fr_acc,
+       };
+
+       return ipu3_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
+                                         NULL);
+}
+
+static int ipu3_css_awb_ops_calc(struct ipu3_css *css, unsigned int pipe,
+                                struct imgu_abi_awb_config *awb_config)
+{
+       struct imgu_abi_awb_intra_frame_operations_data *to =
+               &awb_config->operations_data;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+
+       struct process_lines pl = {
+               .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
+               .grid_height = awb_config->config.grid.height,
+               .block_height =
+                       1 << awb_config->config.grid.block_height_log2,
+               .y_start = awb_config->config.grid.y_start,
+               .grid_height_per_slice =
+                       awb_config->stripes[0].grid.height_per_slice,
+               .max_op = IMGU_ABI_AWB_MAX_OPERATIONS,
+               .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS,
+               .acc_enable = bi->info.isp.sp.enable.awb_acc,
+       };
+
+       return ipu3_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
+                                         to->transfer_data);
+}
+
+static u16 ipu3_css_grid_end(u16 start, u8 width, u8 block_width_log2)
+{
+       return (start & IPU3_UAPI_GRID_START_MASK) +
+               (width << block_width_log2) - 1;
+}
+
+static void ipu3_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
+{
+       grid_cfg->x_end = ipu3_css_grid_end(grid_cfg->x_start, grid_cfg->width,
+                                           grid_cfg->block_width_log2);
+       grid_cfg->y_end = ipu3_css_grid_end(grid_cfg->y_start, grid_cfg->height,
+                                           grid_cfg->block_height_log2);
+}
+
+/****************** config computation *****************************/
+
+static int ipu3_css_cfg_acc_stripe(struct ipu3_css *css, unsigned int pipe,
+                                  struct imgu_abi_acc_param *acc)
+{
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       const struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+       struct ipu3_css_scaler_info scaler_luma, scaler_chroma;
+       const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+       const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
+       unsigned int bds_ds, i;
+
+       memset(acc, 0, sizeof(*acc));
+
+       /* acc_param: osys_config */
+
+       if (ipu3_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma,
+                              &scaler_chroma, acc->stripe.block_stripes))
+               return -EINVAL;
+
+       /* acc_param: stripe data */
+
+       /*
+        * For the striped case the approach is as follows:
+        * 1. down-scaled stripes are calculated - with 128 overlap
+        *    (this is the main limiter therefore it's first)
+        * 2. input stripes are derived by up-scaling the down-scaled stripes
+        *    (there are no alignment requirements on input stripes)
+        * 3. output stripes are derived from down-scaled stripes too
+        */
+
+       acc->stripe.num_of_stripes = stripes;
+       acc->stripe.input_frame.width =
+               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+       acc->stripe.input_frame.height =
+               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+       acc->stripe.input_frame.bayer_order =
+               css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+
+       for (i = 0; i < stripes; i++)
+               acc->stripe.bds_out_stripes[i].height =
+                                       css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       acc->stripe.bds_out_stripes[0].offset = 0;
+       if (stripes <= 1) {
+               acc->stripe.bds_out_stripes[0].width =
+                       ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
+       } else {
+               /* Image processing is divided into two stripes */
+               acc->stripe.bds_out_stripes[0].width =
+                       acc->stripe.bds_out_stripes[1].width =
+                       (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
+               /*
+                * Sum of width of the two stripes should not be smaller
+                * than output width and must be even times of overlapping
+                * unit f.
+                */
+               if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) !=
+                   !!(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1)))
+                       acc->stripe.bds_out_stripes[0].width += f;
+               if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
+                   (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
+                       acc->stripe.bds_out_stripes[0].width += f;
+                       acc->stripe.bds_out_stripes[1].width += f;
+               }
+               /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
+               acc->stripe.bds_out_stripes[1].offset =
+                       acc->stripe.bds_out_stripes[0].width - 2 * f;
+       }
+
+       acc->stripe.effective_stripes[0].height =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+       acc->stripe.effective_stripes[0].offset = 0;
+       acc->stripe.bds_out_stripes_no_overlap[0].height =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
+       acc->stripe.output_stripes[0].height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       acc->stripe.output_stripes[0].offset = 0;
+       if (stripes <= 1) {
+               acc->stripe.down_scaled_stripes[0].width =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+               acc->stripe.down_scaled_stripes[0].height =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+               acc->stripe.down_scaled_stripes[0].offset = 0;
+
+               acc->stripe.effective_stripes[0].width =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+               acc->stripe.bds_out_stripes_no_overlap[0].width =
+                       ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
+
+               acc->stripe.output_stripes[0].width =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       } else { /* Two stripes */
+               bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width *
+                               IMGU_BDS_GRANULARITY /
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+
+               acc->stripe.down_scaled_stripes[0] =
+                       acc->stripe.bds_out_stripes[0];
+               acc->stripe.down_scaled_stripes[1] =
+                       acc->stripe.bds_out_stripes[1];
+               if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f))
+                       acc->stripe.down_scaled_stripes[1].width +=
+                               (css_pipe->rect[IPU3_CSS_RECT_BDS].width
+                               & (f - 1)) - f;
+
+               acc->stripe.effective_stripes[0].width = bds_ds *
+                       acc->stripe.down_scaled_stripes[0].width /
+                       IMGU_BDS_GRANULARITY;
+               acc->stripe.effective_stripes[1].width = bds_ds *
+                       acc->stripe.down_scaled_stripes[1].width /
+                       IMGU_BDS_GRANULARITY;
+               acc->stripe.effective_stripes[1].height =
+                       css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+               acc->stripe.effective_stripes[1].offset = bds_ds *
+                       acc->stripe.down_scaled_stripes[1].offset /
+                       IMGU_BDS_GRANULARITY;
+
+               acc->stripe.bds_out_stripes_no_overlap[0].width =
+               acc->stripe.bds_out_stripes_no_overlap[1].offset =
+                       ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
+               acc->stripe.bds_out_stripes_no_overlap[1].width =
+                       DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)
+                       / 2 * f;
+               acc->stripe.bds_out_stripes_no_overlap[1].height =
+                       css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+
+               acc->stripe.output_stripes[0].width =
+                       acc->stripe.down_scaled_stripes[0].width - f;
+               acc->stripe.output_stripes[1].width =
+                       acc->stripe.down_scaled_stripes[1].width - f;
+               acc->stripe.output_stripes[1].height =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+               acc->stripe.output_stripes[1].offset =
+                       acc->stripe.output_stripes[0].width;
+       }
+
+       acc->stripe.output_system_in_frame_width =
+               css_pipe->rect[IPU3_CSS_RECT_GDC].width;
+       acc->stripe.output_system_in_frame_height =
+               css_pipe->rect[IPU3_CSS_RECT_GDC].height;
+
+       acc->stripe.effective_frame_width =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+       acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       acc->stripe.out_frame_width =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       acc->stripe.out_frame_height =
+               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       acc->stripe.gdc_in_buffer_width =
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
+       acc->stripe.gdc_in_buffer_height =
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+       acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
+       acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
+       acc->stripe.display_frame_width =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       acc->stripe.display_frame_height =
+               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       acc->stripe.bds_aligned_frame_width =
+               roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
+                       2 * IPU3_UAPI_ISP_VEC_ELEMS);
+
+       if (stripes > 1)
+               acc->stripe.half_overlap_vectors =
+                       IMGU_STRIPE_FIXED_HALF_OVERLAP;
+       else
+               acc->stripe.half_overlap_vectors = 0;
+
+       return 0;
+}
+
+static void ipu3_css_cfg_acc_dvs(struct ipu3_css *css,
+                                struct imgu_abi_acc_param *acc,
+                                unsigned int pipe)
+{
+       unsigned int i;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       /* Disable DVS statistics */
+       acc->dvs_stat.operations_data.process_lines_data[0].lines =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
+       acc->dvs_stat.operations_data.ops[0].op_type =
+               IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+       acc->dvs_stat.operations_data.ops[0].op_indicator =
+               IMGU_ABI_ACC_OP_NO_OPS;
+       for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++)
+               acc->dvs_stat.cfg.grd_config[i].enable = 0;
+}
+
+static void acc_bds_per_stripe_data(struct ipu3_css *css,
+                                   struct imgu_abi_acc_param *acc,
+                                   const int i, unsigned int pipe)
+{
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
+       acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
+       acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
+       acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 =
+               acc->bds.hor.hor_ctrl0;
+       acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width =
+               acc->stripe.down_scaled_stripes[i].width;
+       acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
+               acc->stripe.down_scaled_stripes[i].width;
+       acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
+               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+}
+
+/*
+ * Configure `acc' parameters. `acc_old' contains the old values (or is NULL)
+ * and `acc_user' contains new prospective values. `use' contains flags
+ * telling which fields to take from the old values (or generate if it is NULL)
+ * and which to take from the new user values.
+ */
+int ipu3_css_cfg_acc(struct ipu3_css *css, unsigned int pipe,
+                    struct ipu3_uapi_flags *use,
+                    struct imgu_abi_acc_param *acc,
+                    struct imgu_abi_acc_param *acc_old,
+                    struct ipu3_uapi_acc_param *acc_user)
+{
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       const struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+       const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+       const unsigned int tnr_frame_width =
+               acc->stripe.bds_aligned_frame_width;
+       const unsigned int min_overlap = 10;
+       const struct v4l2_pix_format_mplane *pixm =
+               &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
+       const struct ipu3_css_bds_config *cfg_bds;
+       struct imgu_abi_input_feeder_data *feeder_data;
+
+       unsigned int bds_ds, ofs_x, ofs_y, i, width, height;
+       u8 b_w_log2; /* Block width log2 */
+
+       /* Update stripe using chroma and luma */
+
+       if (ipu3_css_cfg_acc_stripe(css, pipe, acc))
+               return -EINVAL;
+
+       /* acc_param: input_feeder_config */
+
+       ofs_x = ((pixm->width -
+                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
+       ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+               IMGU_ABI_BAYER_ORDER_RGGB ||
+               css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+               IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
+       ofs_y = ((pixm->height -
+                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
+       ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+               IMGU_ABI_BAYER_ORDER_BGGR ||
+               css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+               IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
+       acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
+       acc->input_feeder.data.start_row_address =
+               ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
+               ofs_y * acc->input_feeder.data.row_stride;
+       acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
+
+       acc->input_feeder.data_per_stripe.input_feeder_data[0].data =
+               acc->input_feeder.data;
+
+       ofs_x += acc->stripe.effective_stripes[1].offset;
+
+       feeder_data =
+               &acc->input_feeder.data_per_stripe.input_feeder_data[1].data;
+       feeder_data->row_stride = acc->input_feeder.data.row_stride;
+       feeder_data->start_row_address =
+               ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
+               ofs_y * acc->input_feeder.data.row_stride;
+       feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
+
+       /* acc_param: bnr_static_config */
+
+       /*
+        * Originate from user or be the original default values if user has
+        * never set them before, when user gives a new set of parameters,
+        * for each chunk in the parameter structure there is a flag use->xxx
+        * whether to use the user-provided parameter or not. If not, the
+        * parameter remains unchanged in the driver:
+        * it's value is taken from acc_old.
+        */
+       if (use && use->acc_bnr) {
+               /* Take values from user */
+               acc->bnr = acc_user->bnr;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->bnr = acc_old->bnr;
+       } else {
+               /* Calculate from scratch */
+               acc->bnr = ipu3_css_bnr_defaults;
+       }
+
+       acc->bnr.column_size = tnr_frame_width;
+
+       /* acc_param: bnr_static_config_green_disparity */
+
+       if (use && use->acc_green_disparity) {
+               /* Take values from user */
+               acc->green_disparity = acc_user->green_disparity;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->green_disparity = acc_old->green_disparity;
+       } else {
+               /* Calculate from scratch */
+               memset(&acc->green_disparity, 0, sizeof(acc->green_disparity));
+       }
+
+       /* acc_param: dm_config */
+
+       if (use && use->acc_dm) {
+               /* Take values from user */
+               acc->dm = acc_user->dm;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->dm = acc_old->dm;
+       } else {
+               /* Calculate from scratch */
+               acc->dm = ipu3_css_dm_defaults;
+       }
+
+       acc->dm.frame_width = tnr_frame_width;
+
+       /* acc_param: ccm_mat_config */
+
+       if (use && use->acc_ccm) {
+               /* Take values from user */
+               acc->ccm = acc_user->ccm;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->ccm = acc_old->ccm;
+       } else {
+               /* Calculate from scratch */
+               acc->ccm = ipu3_css_ccm_defaults;
+       }
+
+       /* acc_param: gamma_config */
+
+       if (use && use->acc_gamma) {
+               /* Take values from user */
+               acc->gamma = acc_user->gamma;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->gamma = acc_old->gamma;
+       } else {
+               /* Calculate from scratch */
+               acc->gamma.gc_ctrl.enable = 1;
+               acc->gamma.gc_lut = ipu3_css_gamma_lut;
+       }
+
+       /* acc_param: csc_mat_config */
+
+       if (use && use->acc_csc) {
+               /* Take values from user */
+               acc->csc = acc_user->csc;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->csc = acc_old->csc;
+       } else {
+               /* Calculate from scratch */
+               acc->csc = ipu3_css_csc_defaults;
+       }
+
+       /* acc_param: cds_params */
+
+       if (use && use->acc_cds) {
+               /* Take values from user */
+               acc->cds = acc_user->cds;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->cds = acc_old->cds;
+       } else {
+               /* Calculate from scratch */
+               acc->cds = ipu3_css_cds_defaults;
+       }
+
+       /* acc_param: shd_config */
+
+       if (use && use->acc_shd) {
+               /* Take values from user */
+               acc->shd.shd = acc_user->shd.shd;
+               acc->shd.shd_lut = acc_user->shd.shd_lut;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->shd.shd = acc_old->shd.shd;
+               acc->shd.shd_lut = acc_old->shd.shd_lut;
+       } else {
+               /* Calculate from scratch */
+               acc->shd.shd = ipu3_css_shd_defaults;
+               memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut));
+       }
+
+       if (acc->shd.shd.grid.width <= 0)
+               return -EINVAL;
+
+       acc->shd.shd.grid.grid_height_per_slice =
+               IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width;
+
+       if (acc->shd.shd.grid.grid_height_per_slice <= 0)
+               return -EINVAL;
+
+       acc->shd.shd.general.init_set_vrt_offst_ul =
+                               (-acc->shd.shd.grid.y_start >>
+                                acc->shd.shd.grid.block_height_log2) %
+                               acc->shd.shd.grid.grid_height_per_slice;
+
+       if (ipu3_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
+                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height))
+               return -EINVAL;
+
+       /* acc_param: dvs_stat_config */
+       ipu3_css_cfg_acc_dvs(css, acc, pipe);
+
+       /* acc_param: yuvp1_iefd_config */
+
+       if (use && use->acc_iefd) {
+               /* Take values from user */
+               acc->iefd = acc_user->iefd;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->iefd = acc_old->iefd;
+       } else {
+               /* Calculate from scratch */
+               acc->iefd = ipu3_css_iefd_defaults;
+       }
+
+       /* acc_param: yuvp1_yds_config yds_c0 */
+
+       if (use && use->acc_yds_c0) {
+               /* Take values from user */
+               acc->yds_c0 = acc_user->yds_c0;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->yds_c0 = acc_old->yds_c0;
+       } else {
+               /* Calculate from scratch */
+               acc->yds_c0 = ipu3_css_yds_defaults;
+       }
+
+       /* acc_param: yuvp1_chnr_config chnr_c0 */
+
+       if (use && use->acc_chnr_c0) {
+               /* Take values from user */
+               acc->chnr_c0 = acc_user->chnr_c0;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->chnr_c0 = acc_old->chnr_c0;
+       } else {
+               /* Calculate from scratch */
+               acc->chnr_c0 = ipu3_css_chnr_defaults;
+       }
+
+       /* acc_param: yuvp1_y_ee_nr_config */
+
+       if (use && use->acc_y_ee_nr) {
+               /* Take values from user */
+               acc->y_ee_nr = acc_user->y_ee_nr;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->y_ee_nr = acc_old->y_ee_nr;
+       } else {
+               /* Calculate from scratch */
+               acc->y_ee_nr = ipu3_css_y_ee_nr_defaults;
+       }
+
+       /* acc_param: yuvp1_yds_config yds */
+
+       if (use && use->acc_yds) {
+               /* Take values from user */
+               acc->yds = acc_user->yds;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->yds = acc_old->yds;
+       } else {
+               /* Calculate from scratch */
+               acc->yds = ipu3_css_yds_defaults;
+       }
+
+       /* acc_param: yuvp1_chnr_config chnr */
+
+       if (use && use->acc_chnr) {
+               /* Take values from user */
+               acc->chnr = acc_user->chnr;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->chnr = acc_old->chnr;
+       } else {
+               /* Calculate from scratch */
+               acc->chnr = ipu3_css_chnr_defaults;
+       }
+
+       /* acc_param: yuvp2_y_tm_lut_static_config */
+
+       for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++)
+               acc->ytm.entries[i] = i * 32;
+       acc->ytm.enable = 0;    /* Always disabled on IPU3 */
+
+       /* acc_param: yuvp1_yds_config yds2 */
+
+       if (use && use->acc_yds2) {
+               /* Take values from user */
+               acc->yds2 = acc_user->yds2;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->yds2 = acc_old->yds2;
+       } else {
+               /* Calculate from scratch */
+               acc->yds2 = ipu3_css_yds_defaults;
+       }
+
+       /* acc_param: yuvp2_tcc_static_config */
+
+       if (use && use->acc_tcc) {
+               /* Take values from user */
+               acc->tcc = acc_user->tcc;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->tcc = acc_old->tcc;
+       } else {
+               /* Calculate from scratch */
+               memset(&acc->tcc, 0, sizeof(acc->tcc));
+
+               acc->tcc.gen_control.en = 1;
+               acc->tcc.gen_control.blend_shift = 3;
+               acc->tcc.gen_control.gain_according_to_y_only = 1;
+               acc->tcc.gen_control.gamma = 8;
+               acc->tcc.gen_control.delta = 0;
+
+               for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) {
+                       acc->tcc.macc_table.entries[i].a = 1024;
+                       acc->tcc.macc_table.entries[i].b = 0;
+                       acc->tcc.macc_table.entries[i].c = 0;
+                       acc->tcc.macc_table.entries[i].d = 1024;
+               }
+
+               acc->tcc.inv_y_lut.entries[6] = 1023;
+               for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++)
+                       acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6);
+
+               acc->tcc.gain_pcwl = ipu3_css_tcc_gain_pcwl_lut;
+               acc->tcc.r_sqr_lut = ipu3_css_tcc_r_sqr_lut;
+       }
+
+       /* acc_param: dpc_config */
+
+       if (use && use->acc_dpc)
+               return -EINVAL; /* Not supported yet */
+
+       /* Just disable by default */
+       memset(&acc->dpc, 0, sizeof(acc->dpc));
+
+       /* acc_param: bds_config */
+
+       bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height *
+                 IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       if (bds_ds < IMGU_BDS_MIN_SF_INV ||
+           bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(ipu3_css_bds_configs))
+               return -EINVAL;
+
+       cfg_bds = &ipu3_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV];
+       acc->bds.hor.hor_ctrl1.hor_crop_en = 0;
+       acc->bds.hor.hor_ctrl1.hor_crop_start = 0;
+       acc->bds.hor.hor_ctrl1.hor_crop_end = 0;
+       acc->bds.hor.hor_ctrl0.sample_patrn_length =
+                               cfg_bds->sample_patrn_length;
+       acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en;
+       acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
+       acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
+       acc->bds.hor.hor_ctrl0.out_frame_width =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
+       acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
+       acc->bds.hor.hor_ctrl2.input_frame_height =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+       acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
+       acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
+       acc->bds.ver.ver_ctrl0.sample_patrn_length =
+                               cfg_bds->sample_patrn_length;
+       acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en;
+       acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
+       acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
+       acc->bds.ver.ver_ctrl1.out_frame_width =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       acc->bds.ver.ver_ctrl1.out_frame_height =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       for (i = 0; i < stripes; i++)
+               acc_bds_per_stripe_data(css, acc, i, pipe);
+
+       acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
+
+       /* acc_param: anr_config */
+
+       if (use && use->acc_anr) {
+               /* Take values from user */
+               acc->anr.transform = acc_user->anr.transform;
+               acc->anr.stitch.anr_stitch_en =
+                       acc_user->anr.stitch.anr_stitch_en;
+               memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid,
+                      sizeof(acc->anr.stitch.pyramid));
+       } else if (acc_old) {
+               /* Use old value */
+               acc->anr.transform = acc_old->anr.transform;
+               acc->anr.stitch.anr_stitch_en =
+                       acc_old->anr.stitch.anr_stitch_en;
+               memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid,
+                      sizeof(acc->anr.stitch.pyramid));
+       } else {
+               /* Calculate from scratch */
+               acc->anr = ipu3_css_anr_defaults;
+       }
+
+       /* Always enabled */
+       acc->anr.search.enable = 1;
+       acc->anr.transform.enable = 1;
+       acc->anr.tile2strm.enable = 1;
+       acc->anr.tile2strm.frame_width =
+               ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
+       acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
+       acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
+       acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
+       acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
+
+       width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
+       height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+
+       if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET)
+               acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width;
+       if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET)
+               acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET;
+
+       if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET)
+               acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height;
+       if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET)
+               acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET;
+
+       /* acc_param: awb_fr_config */
+
+       if (use && use->acc_awb_fr) {
+               /* Take values from user */
+               acc->awb_fr.config = acc_user->awb_fr;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->awb_fr.config = acc_old->awb_fr.config;
+       } else {
+               /* Set from scratch */
+               acc->awb_fr.config = ipu3_css_awb_fr_defaults;
+       }
+
+       ipu3_css_grid_end_calc(&acc->awb_fr.config.grid_cfg);
+
+       if (acc->awb_fr.config.grid_cfg.width <= 0)
+               return -EINVAL;
+
+       acc->awb_fr.config.grid_cfg.height_per_slice =
+               IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET /
+               acc->awb_fr.config.grid_cfg.width;
+
+       for (i = 0; i < stripes; i++)
+               acc->awb_fr.stripes[i] = acc->awb_fr.config;
+
+       if (acc->awb_fr.config.grid_cfg.x_start >=
+           acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+               /* Enable only for rightmost stripe, disable left */
+               acc->awb_fr.stripes[0].grid_cfg.y_start &=
+                                       ~IPU3_UAPI_GRID_Y_START_EN;
+       } else if (acc->awb_fr.config.grid_cfg.x_end <=
+                  acc->stripe.bds_out_stripes[0].width - min_overlap) {
+               /* Enable only for leftmost stripe, disable right */
+               acc->awb_fr.stripes[1].grid_cfg.y_start &=
+                                       ~IPU3_UAPI_GRID_Y_START_EN;
+       } else {
+               /* Enable for both stripes */
+               u16 end; /* width for grid end */
+
+               acc->awb_fr.stripes[0].grid_cfg.width =
+                       (acc->stripe.bds_out_stripes[0].width - min_overlap -
+                        acc->awb_fr.config.grid_cfg.x_start + 1) >>
+                       acc->awb_fr.config.grid_cfg.block_width_log2;
+               acc->awb_fr.stripes[1].grid_cfg.width =
+                       acc->awb_fr.config.grid_cfg.width -
+                       acc->awb_fr.stripes[0].grid_cfg.width;
+
+               b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2;
+               end = ipu3_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start,
+                                       acc->awb_fr.stripes[0].grid_cfg.width,
+                                       b_w_log2);
+               acc->awb_fr.stripes[0].grid_cfg.x_end = end;
+
+               acc->awb_fr.stripes[1].grid_cfg.x_start =
+                       (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 -
+                        acc->stripe.down_scaled_stripes[1].offset) &
+                       IPU3_UAPI_GRID_START_MASK;
+               b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2;
+               end = ipu3_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start,
+                                       acc->awb_fr.stripes[1].grid_cfg.width,
+                                       b_w_log2);
+               acc->awb_fr.stripes[1].grid_cfg.x_end = end;
+
+               /*
+                * To reduce complexity of debubbling and loading
+                * statistics fix grid_height_per_slice to 1 for both
+                * stripes.
+                */
+               for (i = 0; i < stripes; i++)
+                       acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1;
+       }
+
+       if (ipu3_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr))
+               return -EINVAL;
+
+       /* acc_param: ae_config */
+
+       if (use && use->acc_ae) {
+               /* Take values from user */
+               acc->ae.grid_cfg = acc_user->ae.grid_cfg;
+               acc->ae.ae_ccm = acc_user->ae.ae_ccm;
+               for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+                       acc->ae.weights[i] = acc_user->ae.weights[i];
+       } else if (acc_old) {
+               /* Use old value */
+               acc->ae.grid_cfg = acc_old->ae.grid_cfg;
+               acc->ae.ae_ccm = acc_old->ae.ae_ccm;
+               for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+                       acc->ae.weights[i] = acc_old->ae.weights[i];
+       } else {
+               /* Set from scratch */
+               static const struct ipu3_uapi_ae_weight_elem
+                       weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+               acc->ae.grid_cfg = ipu3_css_ae_grid_defaults;
+               acc->ae.ae_ccm = ipu3_css_ae_ccm_defaults;
+               for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+                       acc->ae.weights[i] = weight_def;
+       }
+
+       b_w_log2 = acc->ae.grid_cfg.block_width_log2;
+       acc->ae.grid_cfg.x_end = ipu3_css_grid_end(acc->ae.grid_cfg.x_start,
+                                                  acc->ae.grid_cfg.width,
+                                                  b_w_log2);
+       b_w_log2 = acc->ae.grid_cfg.block_height_log2;
+       acc->ae.grid_cfg.y_end = ipu3_css_grid_end(acc->ae.grid_cfg.y_start,
+                                                  acc->ae.grid_cfg.height,
+                                                  b_w_log2);
+
+       for (i = 0; i < stripes; i++)
+               acc->ae.stripes[i].grid = acc->ae.grid_cfg;
+
+       if (acc->ae.grid_cfg.x_start >=
+           acc->stripe.down_scaled_stripes[1].offset) {
+               /* Enable only for rightmost stripe, disable left */
+               acc->ae.stripes[0].grid.ae_en = 0;
+       } else if (acc->ae.grid_cfg.x_end <=
+                  acc->stripe.bds_out_stripes[0].width) {
+               /* Enable only for leftmost stripe, disable right */
+               acc->ae.stripes[1].grid.ae_en = 0;
+       } else {
+               /* Enable for both stripes */
+               u8 b_w_log2;
+
+               acc->ae.stripes[0].grid.width =
+                       (acc->stripe.bds_out_stripes[0].width -
+                        acc->ae.grid_cfg.x_start + 1) >>
+                       acc->ae.grid_cfg.block_width_log2;
+
+               acc->ae.stripes[1].grid.width =
+                       acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width;
+
+               b_w_log2 = acc->ae.stripes[0].grid.block_width_log2;
+               acc->ae.stripes[0].grid.x_end =
+                       ipu3_css_grid_end(acc->ae.stripes[0].grid.x_start,
+                                         acc->ae.stripes[0].grid.width,
+                                         b_w_log2);
+
+               acc->ae.stripes[1].grid.x_start =
+                       (acc->ae.stripes[0].grid.x_end + 1 -
+                        acc->stripe.down_scaled_stripes[1].offset) &
+                       IPU3_UAPI_GRID_START_MASK;
+               b_w_log2 = acc->ae.stripes[1].grid.block_width_log2;
+               acc->ae.stripes[1].grid.x_end =
+                       ipu3_css_grid_end(acc->ae.stripes[1].grid.x_start,
+                                         acc->ae.stripes[1].grid.width,
+                                         b_w_log2);
+       }
+
+       /* acc_param: af_config */
+
+       if (use && use->acc_af) {
+               /* Take values from user */
+               acc->af.config.filter_config = acc_user->af.filter_config;
+               acc->af.config.grid_cfg = acc_user->af.grid_cfg;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->af.config = acc_old->af.config;
+       } else {
+               /* Set from scratch */
+               acc->af.config.filter_config =
+                               ipu3_css_af_defaults.filter_config;
+               acc->af.config.grid_cfg = ipu3_css_af_defaults.grid_cfg;
+       }
+
+       ipu3_css_grid_end_calc(&acc->af.config.grid_cfg);
+
+       if (acc->af.config.grid_cfg.width <= 0)
+               return -EINVAL;
+
+       acc->af.config.grid_cfg.height_per_slice =
+               IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
+       acc->af.config.frame_size.width =
+               ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
+       acc->af.config.frame_size.height =
+               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+
+       if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
+               return -EINVAL;
+
+       for (i = 0; i < stripes; i++) {
+               acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg;
+               acc->af.stripes[i].frame_size.height =
+                               css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+               acc->af.stripes[i].frame_size.width =
+                       acc->stripe.bds_out_stripes[i].width;
+       }
+
+       if (acc->af.config.grid_cfg.x_start >=
+           acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+               /* Enable only for rightmost stripe, disable left */
+               acc->af.stripes[0].grid_cfg.y_start &=
+                       ~IPU3_UAPI_GRID_Y_START_EN;
+       } else if (acc->af.config.grid_cfg.x_end <=
+                  acc->stripe.bds_out_stripes[0].width - min_overlap) {
+               /* Enable only for leftmost stripe, disable right */
+               acc->af.stripes[1].grid_cfg.y_start &=
+                       ~IPU3_UAPI_GRID_Y_START_EN;
+       } else {
+               /* Enable for both stripes */
+
+               acc->af.stripes[0].grid_cfg.width =
+                       (acc->stripe.bds_out_stripes[0].width - min_overlap -
+                        acc->af.config.grid_cfg.x_start + 1) >>
+                       acc->af.config.grid_cfg.block_width_log2;
+               acc->af.stripes[1].grid_cfg.width =
+                       acc->af.config.grid_cfg.width -
+                       acc->af.stripes[0].grid_cfg.width;
+
+               b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2;
+               acc->af.stripes[0].grid_cfg.x_end =
+                       ipu3_css_grid_end(acc->af.stripes[0].grid_cfg.x_start,
+                                         acc->af.stripes[0].grid_cfg.width,
+                                         b_w_log2);
+
+               acc->af.stripes[1].grid_cfg.x_start =
+                       (acc->af.stripes[0].grid_cfg.x_end + 1 -
+                        acc->stripe.down_scaled_stripes[1].offset) &
+                       IPU3_UAPI_GRID_START_MASK;
+
+               b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
+               acc->af.stripes[1].grid_cfg.x_end =
+                       ipu3_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
+                                         acc->af.stripes[1].grid_cfg.width,
+                                         b_w_log2);
+
+               /*
+                * To reduce complexity of debubbling and loading statistics
+                * fix grid_height_per_slice to 1 for both stripes
+                */
+               for (i = 0; i < stripes; i++)
+                       acc->af.stripes[i].grid_cfg.height_per_slice = 1;
+       }
+
+       if (ipu3_css_af_ops_calc(css, pipe, &acc->af))
+               return -EINVAL;
+
+       /* acc_param: awb_config */
+
+       if (use && use->acc_awb) {
+               /* Take values from user */
+               acc->awb.config = acc_user->awb.config;
+       } else if (acc_old) {
+               /* Use old value */
+               acc->awb.config = acc_old->awb.config;
+       } else {
+               /* Set from scratch */
+               acc->awb.config = ipu3_css_awb_defaults;
+       }
+
+       if (acc->awb.config.grid.width <= 0)
+               return -EINVAL;
+
+       acc->awb.config.grid.height_per_slice =
+               IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width,
+       ipu3_css_grid_end_calc(&acc->awb.config.grid);
+
+       for (i = 0; i < stripes; i++)
+               acc->awb.stripes[i] = acc->awb.config;
+
+       if (acc->awb.config.grid.x_start >=
+           acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+               /* Enable only for rightmost stripe, disable left */
+               acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
+       } else if (acc->awb.config.grid.x_end <=
+                  acc->stripe.bds_out_stripes[0].width - min_overlap) {
+               /* Enable only for leftmost stripe, disable right */
+               acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
+       } else {
+               /* Enable for both stripes */
+
+               acc->awb.stripes[0].grid.width =
+                       (acc->stripe.bds_out_stripes[0].width -
+                        acc->awb.config.grid.x_start + 1) >>
+                       acc->awb.config.grid.block_width_log2;
+               acc->awb.stripes[1].grid.width = acc->awb.config.grid.width -
+                               acc->awb.stripes[0].grid.width;
+
+               b_w_log2 = acc->awb.stripes[0].grid.block_width_log2;
+               acc->awb.stripes[0].grid.x_end =
+                       ipu3_css_grid_end(acc->awb.stripes[0].grid.x_start,
+                                         acc->awb.stripes[0].grid.width,
+                                         b_w_log2);
+
+               acc->awb.stripes[1].grid.x_start =
+                       (acc->awb.stripes[0].grid.x_end + 1 -
+                        acc->stripe.down_scaled_stripes[1].offset) &
+                       IPU3_UAPI_GRID_START_MASK;
+
+               b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
+               acc->awb.stripes[1].grid.x_end =
+                       ipu3_css_grid_end(acc->awb.stripes[1].grid.x_start,
+                                         acc->awb.stripes[1].grid.width,
+                                         b_w_log2);
+
+               /*
+                * To reduce complexity of debubbling and loading statistics
+                * fix grid_height_per_slice to 1 for both stripes
+                */
+               for (i = 0; i < stripes; i++)
+                       acc->awb.stripes[i].grid.height_per_slice = 1;
+       }
+
+       if (ipu3_css_awb_ops_calc(css, pipe, &acc->awb))
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Fill the indicated structure in `new_binary_params' from the possible
+ * sources based on `use_user' flag: if the flag is false, copy from
+ * `old_binary_params', or if the flag is true, copy from `user_setting'
+ * and return NULL (or error pointer on error).
+ * If the flag is false and `old_binary_params' is NULL, return pointer
+ * to the structure inside `new_binary_params'. In that case the caller
+ * should calculate and fill the structure from scratch.
+ */
+static void *ipu3_css_cfg_copy(struct ipu3_css *css,
+                              unsigned int pipe, bool use_user,
+                              void *user_setting, void *old_binary_params,
+                              void *new_binary_params,
+                              enum imgu_abi_memories m,
+                              struct imgu_fw_isp_parameter *par,
+                              size_t par_size)
+{
+       const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+       void *new_setting, *old_setting;
+
+       new_setting = ipu3_css_fw_pipeline_params(css, pipe, c, m, par,
+                                                 par_size, new_binary_params);
+       if (!new_setting)
+               return ERR_PTR(-EPROTO);        /* Corrupted firmware */
+
+       if (use_user) {
+               /* Take new user parameters */
+               memcpy(new_setting, user_setting, par_size);
+       } else if (old_binary_params) {
+               /* Take previous value */
+               old_setting = ipu3_css_fw_pipeline_params(css, pipe, c, m, par,
+                                                         par_size,
+                                                         old_binary_params);
+               if (!old_setting)
+                       return ERR_PTR(-EPROTO);
+               memcpy(new_setting, old_setting, par_size);
+       } else {
+               return new_setting;     /* Need to calculate */
+       }
+
+       return NULL;            /* Copied from other value */
+}
+
+/*
+ * Configure VMEM0 parameters (late binding parameters).
+ */
+int ipu3_css_cfg_vmem0(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_uapi_flags *use,
+                      void *vmem0, void *vmem0_old,
+                      struct ipu3_uapi_params *user)
+{
+       const struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css->pipes[pipe].bindex];
+       struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
+               bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
+       struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL;
+       struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL;
+       struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL;
+       const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+       const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0;
+       unsigned int i;
+
+       /* Configure VMEM0 */
+
+       memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
+
+       /* Configure Linearization VMEM0 parameters */
+
+       lin_vmem = ipu3_css_cfg_copy(css, pipe, use && use->lin_vmem_params,
+                                    &user->lin_vmem_params, vmem0_old, vmem0,
+                                    m, &pofs->vmem.lin, sizeof(*lin_vmem));
+       if (!IS_ERR_OR_NULL(lin_vmem)) {
+               /* Generate parameter from scratch */
+               for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) {
+                       lin_vmem->lin_lutlow_gr[i] = 32 * i;
+                       lin_vmem->lin_lutlow_r[i] = 32 * i;
+                       lin_vmem->lin_lutlow_b[i] = 32 * i;
+                       lin_vmem->lin_lutlow_gb[i] = 32 * i;
+
+                       lin_vmem->lin_lutdif_gr[i] = 32;
+                       lin_vmem->lin_lutdif_r[i] = 32;
+                       lin_vmem->lin_lutdif_b[i] = 32;
+                       lin_vmem->lin_lutdif_gb[i] = 32;
+               }
+       }
+
+       /* Configure TNR3 VMEM parameters */
+       if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+               tnr_vmem = ipu3_css_cfg_copy(css, pipe,
+                                            use && use->tnr3_vmem_params,
+                                            &user->tnr3_vmem_params,
+                                            vmem0_old, vmem0, m,
+                                            &pofs->vmem.tnr3,
+                                            sizeof(*tnr_vmem));
+               if (!IS_ERR_OR_NULL(tnr_vmem)) {
+                       /* Generate parameter from scratch */
+                       for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++)
+                               tnr_vmem->sigma[i] = 256;
+               }
+       }
+       i = IPU3_UAPI_ISP_TNR3_VMEM_LEN;
+
+       /* Configure XNR3 VMEM parameters */
+
+       xnr_vmem = ipu3_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params,
+                                    &user->xnr3_vmem_params, vmem0_old, vmem0,
+                                    m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
+       if (!IS_ERR_OR_NULL(xnr_vmem)) {
+               xnr_vmem->x[i] = ipu3_css_xnr3_vmem_defaults.x
+                       [i % IMGU_XNR3_VMEM_LUT_LEN];
+               xnr_vmem->a[i] = ipu3_css_xnr3_vmem_defaults.a
+                       [i % IMGU_XNR3_VMEM_LUT_LEN];
+               xnr_vmem->b[i] = ipu3_css_xnr3_vmem_defaults.b
+                       [i % IMGU_XNR3_VMEM_LUT_LEN];
+               xnr_vmem->c[i] = ipu3_css_xnr3_vmem_defaults.c
+                       [i % IMGU_XNR3_VMEM_LUT_LEN];
+       }
+
+       return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ?
+               -EPROTO : 0;
+}
+
+/*
+ * Configure DMEM0 parameters (late binding parameters).
+ */
+int ipu3_css_cfg_dmem0(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_uapi_flags *use,
+                      void *dmem0, void *dmem0_old,
+                      struct ipu3_uapi_params *user)
+{
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       const struct imgu_fw_info *bi =
+               &css->fwp->binary_header[css_pipe->bindex];
+       struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
+               bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
+
+       struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL;
+       struct ipu3_uapi_isp_xnr3_params *xnr_dmem;
+
+       const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+       const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0;
+
+       /* Configure DMEM0 */
+
+       memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
+
+       /* Configure TNR3 DMEM0 parameters */
+       if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+               tnr_dmem = ipu3_css_cfg_copy(css, pipe,
+                                            use && use->tnr3_dmem_params,
+                                            &user->tnr3_dmem_params,
+                                            dmem0_old, dmem0, m,
+                                            &pofs->dmem.tnr3,
+                                            sizeof(*tnr_dmem));
+               if (!IS_ERR_OR_NULL(tnr_dmem)) {
+                       /* Generate parameter from scratch */
+                       tnr_dmem->knee_y1 = 768;
+                       tnr_dmem->knee_y2 = 1280;
+               }
+       }
+
+       /* Configure XNR3 DMEM0 parameters */
+
+       xnr_dmem = ipu3_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params,
+                                    &user->xnr3_dmem_params, dmem0_old, dmem0,
+                                    m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
+       if (!IS_ERR_OR_NULL(xnr_dmem)) {
+               /* Generate parameter from scratch */
+               xnr_dmem->alpha.y0 = 2047;
+               xnr_dmem->alpha.u0 = 2047;
+               xnr_dmem->alpha.v0 = 2047;
+       }
+
+       return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0;
+}
+
+/* Generate unity morphing table without morphing effect */
+void ipu3_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
+                           int frame_in_x, int frame_in_y,
+                           int frame_out_x, int frame_out_y,
+                           int env_w, int env_h)
+{
+       static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS;
+       static const unsigned int XMEM_ALIGN = 1 << 4;
+       const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1);
+       static const unsigned int BCI_ENV = 4;
+       static const unsigned int BYP = 2;      /* Bytes per pixel */
+       const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1;
+       const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1;
+
+       struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma;
+
+       unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x,
+                                                  IMGU_DVS_BLOCK_W), 2);
+       unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H);
+       unsigned int y0, x0, x1, x, y;
+
+       /* Global luma settings */
+       gdc_luma.origin_x = 0;
+       gdc_luma.origin_y = 0;
+       gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS;
+       gdc_luma.p0_y = 0;
+       gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
+       gdc_luma.p1_y = gdc_luma.p0_y;
+       gdc_luma.p2_x = gdc_luma.p0_x;
+       gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS);
+       gdc_luma.p3_x = gdc_luma.p1_x;
+       gdc_luma.p3_y = gdc_luma.p2_y;
+
+       gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV +
+                                       OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK);
+       gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width,
+                                                IPU3_UAPI_ISP_VEC_ELEMS);
+       gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width,
+                                                IMGU_ABI_ISP_DDR_WORD_BYTES /
+                                                BYP);
+       gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV;
+       gdc_luma.padding = 0;
+
+       /* Global chroma settings */
+       gdc_chroma.origin_x = 0;
+       gdc_chroma.origin_y = 0;
+       gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) <<
+                          FRAC_BITS;
+       gdc_chroma.p0_y = 0;
+       gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
+       gdc_chroma.p1_y = gdc_chroma.p0_y;
+       gdc_chroma.p2_x = gdc_chroma.p0_x;
+       gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS);
+       gdc_chroma.p3_x = gdc_chroma.p1_x;
+       gdc_chroma.p3_y = gdc_chroma.p2_y;
+
+       gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV;
+       gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width,
+                                                  IPU3_UAPI_ISP_VEC_ELEMS);
+       gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width,
+                                                  IMGU_ABI_ISP_DDR_WORD_BYTES /
+                                                  BYP);
+       gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV;
+       gdc_chroma.padding = 0;
+
+       /* Calculate block offsets for luma and chroma */
+       for (y0 = 0; y0 < blocks_y; y0++) {
+               for (x0 = 0; x0 < blocks_x / 2; x0++) {
+                       for (x1 = 0; x1 < 2; x1++) {
+                               /* Luma blocks */
+                               x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X;
+                               x &= XMEM_ALIGN_MASK;
+                               y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y;
+                               *gdc = gdc_luma;
+                               gdc->in_addr_offset =
+                                       (y * frame_in_x + x) * BYP;
+                               gdc++;
+                       }
+
+                       /* Chroma block */
+                       x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2;
+                       x &= XMEM_ALIGN_MASK;
+                       y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2;
+                       *gdc = gdc_chroma;
+                       gdc->in_addr_offset = (y * frame_in_x + x) * BYP;
+                       gdc++;
+               }
+       }
+}
diff --git a/drivers/staging/media/ipu3/ipu3-css-params.h b/drivers/staging/media/ipu3/ipu3-css-params.h
new file mode 100644 (file)
index 0000000..f3a0a47
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_PARAMS_H
+#define __IPU3_PARAMS_H
+
+int ipu3_css_cfg_acc(struct ipu3_css *css, unsigned int pipe,
+                    struct ipu3_uapi_flags *use,
+                    struct imgu_abi_acc_param *acc,
+                    struct imgu_abi_acc_param *acc_old,
+                    struct ipu3_uapi_acc_param *acc_user);
+
+int ipu3_css_cfg_vmem0(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_uapi_flags *use,
+                      void *vmem0, void *vmem0_old,
+                      struct ipu3_uapi_params *user);
+
+int ipu3_css_cfg_dmem0(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_uapi_flags *use,
+                      void *dmem0, void *dmem0_old,
+                      struct ipu3_uapi_params *user);
+
+void ipu3_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
+                           int frame_in_x, int frame_in_y,
+                           int frame_out_x, int frame_out_y,
+                           int env_w, int env_h);
+
+#endif /*__IPU3_PARAMS_H */
diff --git a/drivers/staging/media/ipu3/ipu3-css-pool.c b/drivers/staging/media/ipu3/ipu3-css-pool.c
new file mode 100644 (file)
index 0000000..6f271f8
--- /dev/null
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <linux/device.h>
+
+#include "ipu3.h"
+#include "ipu3-css-pool.h"
+#include "ipu3-dmamap.h"
+
+int ipu3_css_dma_buffer_resize(struct imgu_device *imgu,
+                              struct ipu3_css_map *map, size_t size)
+{
+       if (map->size < size && map->vaddr) {
+               dev_warn(&imgu->pci_dev->dev, "dma buf resized from %zu to %zu",
+                        map->size, size);
+
+               ipu3_dmamap_free(imgu, map);
+               if (!ipu3_dmamap_alloc(imgu, map, size))
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void ipu3_css_pool_cleanup(struct imgu_device *imgu, struct ipu3_css_pool *pool)
+{
+       unsigned int i;
+
+       for (i = 0; i < IPU3_CSS_POOL_SIZE; i++)
+               ipu3_dmamap_free(imgu, &pool->entry[i].param);
+}
+
+int ipu3_css_pool_init(struct imgu_device *imgu, struct ipu3_css_pool *pool,
+                      size_t size)
+{
+       unsigned int i;
+
+       for (i = 0; i < IPU3_CSS_POOL_SIZE; i++) {
+               pool->entry[i].valid = false;
+               if (size == 0) {
+                       pool->entry[i].param.vaddr = NULL;
+                       continue;
+               }
+
+               if (!ipu3_dmamap_alloc(imgu, &pool->entry[i].param, size))
+                       goto fail;
+       }
+
+       pool->last = IPU3_CSS_POOL_SIZE;
+
+       return 0;
+
+fail:
+       ipu3_css_pool_cleanup(imgu, pool);
+       return -ENOMEM;
+}
+
+/*
+ * Allocate a new parameter via recycling the oldest entry in the pool.
+ */
+void ipu3_css_pool_get(struct ipu3_css_pool *pool)
+{
+       /* Get the oldest entry */
+       u32 n = (pool->last + 1) % IPU3_CSS_POOL_SIZE;
+
+       pool->entry[n].valid = true;
+       pool->last = n;
+}
+
+/*
+ * Undo, for all practical purposes, the effect of pool_get().
+ */
+void ipu3_css_pool_put(struct ipu3_css_pool *pool)
+{
+       pool->entry[pool->last].valid = false;
+       pool->last = (pool->last + IPU3_CSS_POOL_SIZE - 1) % IPU3_CSS_POOL_SIZE;
+}
+
+/**
+ * ipu3_css_pool_last - Retrieve the nth pool entry from last
+ *
+ * @pool: a pointer to &struct ipu3_css_pool.
+ * @n: the distance to the last index.
+ *
+ * Returns:
+ *  The nth entry from last or null map to indicate no frame stored.
+ */
+const struct ipu3_css_map *
+ipu3_css_pool_last(struct ipu3_css_pool *pool, unsigned int n)
+{
+       static const struct ipu3_css_map null_map = { 0 };
+       int i = (pool->last + IPU3_CSS_POOL_SIZE - n) % IPU3_CSS_POOL_SIZE;
+
+       WARN_ON(n >= IPU3_CSS_POOL_SIZE);
+
+       if (!pool->entry[i].valid)
+               return &null_map;
+
+       return &pool->entry[i].param;
+}
diff --git a/drivers/staging/media/ipu3/ipu3-css-pool.h b/drivers/staging/media/ipu3/ipu3-css-pool.h
new file mode 100644 (file)
index 0000000..2657c39
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_UTIL_H
+#define __IPU3_UTIL_H
+
+struct device;
+struct imgu_device;
+
+#define IPU3_CSS_POOL_SIZE             4
+
+/**
+ * ipu3_css_map - store DMA mapping info for buffer
+ *
+ * @size:              size of the buffer in bytes.
+ * @vaddr:             kernel virtual address.
+ * @daddr:             iova dma address to access IPU3.
+ * @vma:               private, a pointer to &struct vm_struct,
+ *                     used for ipu3_dmamap_free.
+ */
+struct ipu3_css_map {
+       size_t size;
+       void *vaddr;
+       dma_addr_t daddr;
+       struct vm_struct *vma;
+};
+
+/**
+ * ipu3_css_pool - circular buffer pool definition
+ *
+ * @entry:             array with IPU3_CSS_POOL_SIZE elements.
+ * @entry.param:       a &struct ipu3_css_map for storing the mem mapping.
+ * @entry.valid:       used to mark if the entry has valid data.
+ * @last:              write pointer, initialized to IPU3_CSS_POOL_SIZE.
+ */
+struct ipu3_css_pool {
+       struct {
+               struct ipu3_css_map param;
+               bool valid;
+       } entry[IPU3_CSS_POOL_SIZE];
+       u32 last;
+};
+
+int ipu3_css_dma_buffer_resize(struct imgu_device *imgu,
+                              struct ipu3_css_map *map, size_t size);
+void ipu3_css_pool_cleanup(struct imgu_device *imgu,
+                          struct ipu3_css_pool *pool);
+int ipu3_css_pool_init(struct imgu_device *imgu, struct ipu3_css_pool *pool,
+                      size_t size);
+void ipu3_css_pool_get(struct ipu3_css_pool *pool);
+void ipu3_css_pool_put(struct ipu3_css_pool *pool);
+const struct ipu3_css_map *ipu3_css_pool_last(struct ipu3_css_pool *pool,
+                                             u32 last);
+
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c
new file mode 100644 (file)
index 0000000..44c5563
--- /dev/null
@@ -0,0 +1,2391 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/iopoll.h>
+
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-css-params.h"
+#include "ipu3-dmamap.h"
+#include "ipu3-tables.h"
+
+/* IRQ configuration */
+#define IMGU_IRQCTRL_IRQ_MASK  (IMGU_IRQCTRL_IRQ_SP1 | \
+                                IMGU_IRQCTRL_IRQ_SP2 | \
+                                IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
+                                IMGU_IRQCTRL_IRQ_SW_PIN(1))
+
+#define IPU3_CSS_FORMAT_BPP_DEN        50      /* Denominator */
+
+/* Some sane limits for resolutions */
+#define IPU3_CSS_MIN_RES       32
+#define IPU3_CSS_MAX_H         3136
+#define IPU3_CSS_MAX_W         4224
+
+/* filter size from graph settings is fixed as 4 */
+#define FILTER_SIZE             4
+#define MIN_ENVELOPE            8
+
+/*
+ * pre-allocated buffer size for CSS ABI, auxiliary frames
+ * after BDS and before GDC. Those values should be tuned
+ * to big enough to avoid buffer re-allocation when
+ * streaming to lower streaming latency.
+ */
+#define CSS_ABI_SIZE    136
+#define CSS_BDS_SIZE    (4480 * 3200 * 3)
+#define CSS_GDC_SIZE    (4224 * 3200 * 12 / 8)
+
+#define IPU3_CSS_QUEUE_TO_FLAGS(q)     (1 << (q))
+#define IPU3_CSS_FORMAT_FL_IN          \
+                       IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_IN)
+#define IPU3_CSS_FORMAT_FL_OUT         \
+                       IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_OUT)
+#define IPU3_CSS_FORMAT_FL_VF          \
+                       IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_VF)
+
+/* Formats supported by IPU3 Camera Sub System */
+static const struct ipu3_css_format ipu3_css_formats[] = {
+       {
+               .pixelformat = V4L2_PIX_FMT_NV12,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .frame_format = IMGU_ABI_FRAME_FORMAT_NV12,
+               .osys_format = IMGU_ABI_OSYS_FORMAT_NV12,
+               .osys_tiling = IMGU_ABI_OSYS_TILING_NONE,
+               .bytesperpixel_num = 1 * IPU3_CSS_FORMAT_BPP_DEN,
+               .chroma_decim = 4,
+               .width_align = IPU3_UAPI_ISP_VEC_ELEMS,
+               .flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF,
+       }, {
+               /* Each 32 bytes contains 25 10-bit pixels */
+               .pixelformat = V4L2_PIX_FMT_IPU3_SBGGR10,
+               .colorspace = V4L2_COLORSPACE_RAW,
+               .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+               .bayer_order = IMGU_ABI_BAYER_ORDER_BGGR,
+               .bit_depth = 10,
+               .bytesperpixel_num = 64,
+               .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+               .flags = IPU3_CSS_FORMAT_FL_IN,
+       }, {
+               .pixelformat = V4L2_PIX_FMT_IPU3_SGBRG10,
+               .colorspace = V4L2_COLORSPACE_RAW,
+               .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+               .bayer_order = IMGU_ABI_BAYER_ORDER_GBRG,
+               .bit_depth = 10,
+               .bytesperpixel_num = 64,
+               .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+               .flags = IPU3_CSS_FORMAT_FL_IN,
+       }, {
+               .pixelformat = V4L2_PIX_FMT_IPU3_SGRBG10,
+               .colorspace = V4L2_COLORSPACE_RAW,
+               .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+               .bayer_order = IMGU_ABI_BAYER_ORDER_GRBG,
+               .bit_depth = 10,
+               .bytesperpixel_num = 64,
+               .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+               .flags = IPU3_CSS_FORMAT_FL_IN,
+       }, {
+               .pixelformat = V4L2_PIX_FMT_IPU3_SRGGB10,
+               .colorspace = V4L2_COLORSPACE_RAW,
+               .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+               .bayer_order = IMGU_ABI_BAYER_ORDER_RGGB,
+               .bit_depth = 10,
+               .bytesperpixel_num = 64,
+               .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+               .flags = IPU3_CSS_FORMAT_FL_IN,
+       },
+};
+
+static const struct {
+       enum imgu_abi_queue_id qid;
+       size_t ptr_ofs;
+} ipu3_css_queues[IPU3_CSS_QUEUES] = {
+       [IPU3_CSS_QUEUE_IN] = {
+               IMGU_ABI_QUEUE_C_ID,
+               offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+       },
+       [IPU3_CSS_QUEUE_OUT] = {
+               IMGU_ABI_QUEUE_D_ID,
+               offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+       },
+       [IPU3_CSS_QUEUE_VF] = {
+               IMGU_ABI_QUEUE_E_ID,
+               offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+       },
+       [IPU3_CSS_QUEUE_STAT_3A] = {
+               IMGU_ABI_QUEUE_F_ID,
+               offsetof(struct imgu_abi_buffer, payload.s3a.data_ptr)
+       },
+};
+
+/* Initialize queue based on given format, adjust format as needed */
+static int ipu3_css_queue_init(struct ipu3_css_queue *queue,
+                              struct v4l2_pix_format_mplane *fmt, u32 flags)
+{
+       struct v4l2_pix_format_mplane *const f = &queue->fmt.mpix;
+       unsigned int i;
+       u32 sizeimage;
+
+       INIT_LIST_HEAD(&queue->bufs);
+
+       queue->css_fmt = NULL;  /* Disable */
+       if (!fmt)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(ipu3_css_formats); i++) {
+               if (!(ipu3_css_formats[i].flags & flags))
+                       continue;
+               queue->css_fmt = &ipu3_css_formats[i];
+               if (ipu3_css_formats[i].pixelformat == fmt->pixelformat)
+                       break;
+       }
+       if (!queue->css_fmt)
+               return -EINVAL; /* Could not find any suitable format */
+
+       queue->fmt.mpix = *fmt;
+
+       f->width = ALIGN(clamp_t(u32, f->width,
+                                IPU3_CSS_MIN_RES, IPU3_CSS_MAX_W), 2);
+       f->height = ALIGN(clamp_t(u32, f->height,
+                                 IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2);
+       queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align);
+       if (queue->css_fmt->frame_format != IMGU_ABI_FRAME_FORMAT_RAW_PACKED)
+               f->plane_fmt[0].bytesperline = DIV_ROUND_UP(queue->width_pad *
+                                       queue->css_fmt->bytesperpixel_num,
+                                       IPU3_CSS_FORMAT_BPP_DEN);
+       else
+               /* For packed raw, alignment for bpl is by 50 to the width */
+               f->plane_fmt[0].bytesperline =
+                               DIV_ROUND_UP(f->width,
+                                            IPU3_CSS_FORMAT_BPP_DEN) *
+                                            queue->css_fmt->bytesperpixel_num;
+
+       sizeimage = f->height * f->plane_fmt[0].bytesperline;
+       if (queue->css_fmt->chroma_decim)
+               sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim;
+
+       f->plane_fmt[0].sizeimage = sizeimage;
+       f->field = V4L2_FIELD_NONE;
+       f->num_planes = 1;
+       f->colorspace = queue->css_fmt->colorspace;
+       f->flags = 0;
+       f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       f->quantization = V4L2_QUANTIZATION_DEFAULT;
+       f->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+       memset(f->reserved, 0, sizeof(f->reserved));
+
+       return 0;
+}
+
+static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
+{
+       return q->css_fmt;
+}
+
+/******************* css hw *******************/
+
+/* In the style of writesl() defined in include/asm-generic/io.h */
+static inline void writes(const void *mem, ssize_t count, void __iomem *addr)
+{
+       if (count >= 4) {
+               const u32 *buf = mem;
+
+               count /= 4;
+               do {
+                       writel(*buf++, addr);
+                       addr += 4;
+               } while (--count);
+       }
+}
+
+/* Wait until register `reg', masked with `mask', becomes `cmp' */
+static int ipu3_hw_wait(void __iomem *base, int reg, u32 mask, u32 cmp)
+{
+       u32 val;
+
+       return readl_poll_timeout(base + reg, val, (val & mask) == cmp,
+                                 1000, 100 * 1000);
+}
+
+/* Initialize the IPU3 CSS hardware and associated h/w blocks */
+
+int ipu3_css_set_powerup(struct device *dev, void __iomem *base)
+{
+       static const unsigned int freq = 450;
+       u32 pm_ctrl, state, val;
+
+       dev_dbg(dev, "%s\n", __func__);
+       /* Clear the CSS busy signal */
+       readl(base + IMGU_REG_GP_BUSY);
+       writel(0, base + IMGU_REG_GP_BUSY);
+
+       /* Wait for idle signal */
+       if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+                        IMGU_STATE_IDLE_STS)) {
+               dev_err(dev, "failed to set CSS idle\n");
+               goto fail;
+       }
+
+       /* Reset the css */
+       writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
+              base + IMGU_REG_PM_CTRL);
+
+       usleep_range(200, 300);
+
+       /** Prepare CSS */
+
+       pm_ctrl = readl(base + IMGU_REG_PM_CTRL);
+       state = readl(base + IMGU_REG_STATE);
+
+       dev_dbg(dev, "CSS pm_ctrl 0x%x state 0x%x (power %s)\n",
+               pm_ctrl, state, state & IMGU_STATE_POWER_DOWN ? "down" : "up");
+
+       /* Power up CSS using wrapper */
+       if (state & IMGU_STATE_POWER_DOWN) {
+               writel(IMGU_PM_CTRL_RACE_TO_HALT | IMGU_PM_CTRL_START,
+                      base + IMGU_REG_PM_CTRL);
+               if (ipu3_hw_wait(base, IMGU_REG_PM_CTRL,
+                                IMGU_PM_CTRL_START, 0)) {
+                       dev_err(dev, "failed to power up CSS\n");
+                       goto fail;
+               }
+               usleep_range(2000, 3000);
+       } else {
+               writel(IMGU_PM_CTRL_RACE_TO_HALT, base + IMGU_REG_PM_CTRL);
+       }
+
+       /* Set the busy bit */
+       writel(readl(base + IMGU_REG_GP_BUSY) | 1, base + IMGU_REG_GP_BUSY);
+
+       /* Set CSS clock frequency */
+       pm_ctrl = readl(base + IMGU_REG_PM_CTRL);
+       val = pm_ctrl & ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+       writel(val, base + IMGU_REG_PM_CTRL);
+       writel(0, base + IMGU_REG_GP_BUSY);
+       if (ipu3_hw_wait(base, IMGU_REG_STATE,
+                        IMGU_STATE_PWRDNM_FSM_MASK, 0)) {
+               dev_err(dev, "failed to pwrdn CSS\n");
+               goto fail;
+       }
+       val = (freq / IMGU_SYSTEM_REQ_FREQ_DIVIDER) & IMGU_SYSTEM_REQ_FREQ_MASK;
+       writel(val, base + IMGU_REG_SYSTEM_REQ);
+       writel(1, base + IMGU_REG_GP_BUSY);
+       writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_HALT,
+              base + IMGU_REG_PM_CTRL);
+       if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
+                        IMGU_STATE_HALT_STS)) {
+               dev_err(dev, "failed to halt CSS\n");
+               goto fail;
+       }
+
+       writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_START,
+              base + IMGU_REG_PM_CTRL);
+       if (ipu3_hw_wait(base, IMGU_REG_PM_CTRL, IMGU_PM_CTRL_START, 0)) {
+               dev_err(dev, "failed to start CSS\n");
+               goto fail;
+       }
+       writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_UNHALT,
+              base + IMGU_REG_PM_CTRL);
+
+       val = readl(base + IMGU_REG_PM_CTRL);   /* get pm_ctrl */
+       val &= ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+       val |= pm_ctrl & (IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+       writel(val, base + IMGU_REG_PM_CTRL);
+
+       return 0;
+
+fail:
+       ipu3_css_set_powerdown(dev, base);
+       return -EIO;
+}
+
+void ipu3_css_set_powerdown(struct device *dev, void __iomem *base)
+{
+       dev_dbg(dev, "%s\n", __func__);
+       /* wait for cio idle signal */
+       if (ipu3_hw_wait(base, IMGU_REG_CIO_GATE_BURST_STATE,
+                        IMGU_CIO_GATE_BURST_MASK, 0))
+               dev_warn(dev, "wait cio gate idle timeout");
+
+       /* wait for css idle signal */
+       if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+                        IMGU_STATE_IDLE_STS))
+               dev_warn(dev, "wait css idle timeout\n");
+
+       /* do halt-halted handshake with css */
+       writel(1, base + IMGU_REG_GP_HALT);
+       if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
+                        IMGU_STATE_HALT_STS))
+               dev_warn(dev, "failed to halt css");
+
+       /* de-assert the busy bit */
+       writel(0, base + IMGU_REG_GP_BUSY);
+}
+
+static void ipu3_css_hw_enable_irq(struct ipu3_css *css)
+{
+       void __iomem *const base = css->base;
+       u32 val, i;
+
+       /* Set up interrupts */
+
+       /*
+        * Enable IRQ on the SP which signals that SP goes to idle
+        * (aka ready state) and set trigger to pulse
+        */
+       val = readl(base + IMGU_REG_SP_CTRL(0)) | IMGU_CTRL_IRQ_READY;
+       writel(val, base + IMGU_REG_SP_CTRL(0));
+       writel(val | IMGU_CTRL_IRQ_CLEAR, base + IMGU_REG_SP_CTRL(0));
+
+       /* Enable IRQs from the IMGU wrapper */
+       writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_ENABLE);
+       /* Clear */
+       writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_STATUS);
+
+       /* Enable IRQs from main IRQ controller */
+       writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(IMGU_IRQCTRL_MAIN));
+       writel(0, base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
+       writel(IMGU_IRQCTRL_IRQ_MASK,
+              base + IMGU_REG_IRQCTRL_EDGE(IMGU_IRQCTRL_MAIN));
+       writel(IMGU_IRQCTRL_IRQ_MASK,
+              base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
+       writel(IMGU_IRQCTRL_IRQ_MASK,
+              base + IMGU_REG_IRQCTRL_CLEAR(IMGU_IRQCTRL_MAIN));
+       writel(IMGU_IRQCTRL_IRQ_MASK,
+              base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
+       /* Wait for write complete */
+       readl(base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
+
+       /* Enable IRQs from SP0 and SP1 controllers */
+       for (i = IMGU_IRQCTRL_SP0; i <= IMGU_IRQCTRL_SP1; i++) {
+               writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(i));
+               writel(0, base + IMGU_REG_IRQCTRL_MASK(i));
+               writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_EDGE(i));
+               writel(IMGU_IRQCTRL_IRQ_MASK,
+                      base + IMGU_REG_IRQCTRL_ENABLE(i));
+               writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_CLEAR(i));
+               writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_MASK(i));
+               /* Wait for write complete */
+               readl(base + IMGU_REG_IRQCTRL_ENABLE(i));
+       }
+}
+
+static int ipu3_css_hw_init(struct ipu3_css *css)
+{
+       /* For checking that streaming monitor statuses are valid */
+       static const struct {
+               u32 reg;
+               u32 mask;
+               const char *name;
+       } stream_monitors[] = {
+               {
+                       IMGU_REG_GP_SP1_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP,
+                       "ISP0 to SP0"
+               }, {
+                       IMGU_REG_GP_ISP_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1,
+                       "SP0 to ISP0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA,
+                       "ISP0 to DMA0"
+               }, {
+                       IMGU_REG_GP_ISP_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP,
+                       "DMA0 to ISP0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
+                       "ISP0 to GDC0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
+                       "GDC0 to ISP0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA,
+                       "SP0 to DMA0"
+               }, {
+                       IMGU_REG_GP_SP1_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1,
+                       "DMA0 to SP0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
+                       "SP0 to GDC0"
+               }, {
+                       IMGU_REG_GP_MOD_STRMON_STAT,
+                       IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
+                       "GDC0 to SP0"
+               },
+       };
+
+       struct device *dev = css->dev;
+       void __iomem *const base = css->base;
+       u32 val, i;
+
+       /* Set instruction cache address and inv bit for ISP, SP, and SP1 */
+       for (i = 0; i < IMGU_NUM_SP; i++) {
+               struct imgu_fw_info *bi =
+                                       &css->fwp->binary_header[css->fw_sp[i]];
+
+               writel(css->binary[css->fw_sp[i]].daddr,
+                      base + IMGU_REG_SP_ICACHE_ADDR(bi->type));
+               writel(readl(base + IMGU_REG_SP_CTRL(bi->type)) |
+                      IMGU_CTRL_ICACHE_INV,
+                      base + IMGU_REG_SP_CTRL(bi->type));
+       }
+       writel(css->binary[css->fw_bl].daddr, base + IMGU_REG_ISP_ICACHE_ADDR);
+       writel(readl(base + IMGU_REG_ISP_CTRL) | IMGU_CTRL_ICACHE_INV,
+              base + IMGU_REG_ISP_CTRL);
+
+       /* Check that IMGU hardware is ready */
+
+       if (!(readl(base + IMGU_REG_SP_CTRL(0)) & IMGU_CTRL_IDLE)) {
+               dev_err(dev, "SP is not idle\n");
+               return -EIO;
+       }
+       if (!(readl(base + IMGU_REG_ISP_CTRL) & IMGU_CTRL_IDLE)) {
+               dev_err(dev, "ISP is not idle\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(stream_monitors); i++) {
+               val = readl(base + stream_monitors[i].reg);
+               if (val & stream_monitors[i].mask) {
+                       dev_err(dev, "error: Stream monitor %s is valid\n",
+                               stream_monitors[i].name);
+                       return -EIO;
+               }
+       }
+
+       /* Initialize GDC with default values */
+
+       for (i = 0; i < ARRAY_SIZE(ipu3_css_gdc_lut[0]); i++) {
+               u32 val0 = ipu3_css_gdc_lut[0][i] & IMGU_GDC_LUT_MASK;
+               u32 val1 = ipu3_css_gdc_lut[1][i] & IMGU_GDC_LUT_MASK;
+               u32 val2 = ipu3_css_gdc_lut[2][i] & IMGU_GDC_LUT_MASK;
+               u32 val3 = ipu3_css_gdc_lut[3][i] & IMGU_GDC_LUT_MASK;
+
+               writel(val0 | (val1 << 16),
+                      base + IMGU_REG_GDC_LUT_BASE + i * 8);
+               writel(val2 | (val3 << 16),
+                      base + IMGU_REG_GDC_LUT_BASE + i * 8 + 4);
+       }
+
+       return 0;
+}
+
+/* Boot the given IPU3 CSS SP */
+static int ipu3_css_hw_start_sp(struct ipu3_css *css, int sp)
+{
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+       struct imgu_abi_sp_init_dmem_cfg dmem_cfg = {
+               .ddr_data_addr = css->binary[css->fw_sp[sp]].daddr
+                       + bi->blob.data_source,
+               .dmem_data_addr = bi->blob.data_target,
+               .dmem_bss_addr = bi->blob.bss_target,
+               .data_size = bi->blob.data_size,
+               .bss_size = bi->blob.bss_size,
+               .sp_id = sp,
+       };
+
+       writes(&dmem_cfg, sizeof(dmem_cfg), base +
+              IMGU_REG_SP_DMEM_BASE(sp) + bi->info.sp.init_dmem_data);
+
+       writel(bi->info.sp.sp_entry, base + IMGU_REG_SP_START_ADDR(sp));
+
+       writel(readl(base + IMGU_REG_SP_CTRL(sp))
+               | IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_SP_CTRL(sp));
+
+       if (ipu3_hw_wait(css->base, IMGU_REG_SP_DMEM_BASE(sp)
+                        + bi->info.sp.sw_state,
+                        ~0, IMGU_ABI_SP_SWSTATE_INITIALIZED))
+               return -EIO;
+
+       return 0;
+}
+
+/* Start the IPU3 CSS ImgU (Imaging Unit) and all the SPs */
+static int ipu3_css_hw_start(struct ipu3_css *css)
+{
+       static const u32 event_mask =
+               ((1 << IMGU_ABI_EVTTYPE_OUT_FRAME_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_3A_STATS_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_DIS_STATS_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_PIPELINE_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_FRAME_TAGGED) |
+               (1 << IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_METADATA_DONE) |
+               (1 << IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE))
+               << IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT;
+
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi, *bl = &css->fwp->binary_header[css->fw_bl];
+       unsigned int i;
+
+       writel(IMGU_TLB_INVALIDATE, base + IMGU_REG_TLB_INVALIDATE);
+
+       /* Start bootloader */
+
+       writel(IMGU_ABI_BL_SWSTATE_BUSY,
+              base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.sw_state);
+       writel(IMGU_NUM_SP,
+              base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.num_dma_cmds);
+
+       for (i = 0; i < IMGU_NUM_SP; i++) {
+               int j = IMGU_NUM_SP - i - 1;    /* load sp1 first, then sp0 */
+               struct imgu_fw_info *sp =
+                                       &css->fwp->binary_header[css->fw_sp[j]];
+               struct imgu_abi_bl_dma_cmd_entry dma_cmd = {
+                       .src_addr = css->binary[css->fw_sp[j]].daddr
+                               + sp->blob.text_source,
+                       .size = sp->blob.text_size,
+                       .dst_type = IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM,
+                       .dst_addr = IMGU_SP_PMEM_BASE(j),
+               };
+
+               writes(&dma_cmd, sizeof(dma_cmd),
+                      base + IMGU_REG_ISP_DMEM_BASE + i * sizeof(dma_cmd) +
+                      bl->info.bl.dma_cmd_list);
+       }
+
+       writel(bl->info.bl.bl_entry, base + IMGU_REG_ISP_START_ADDR);
+
+       writel(readl(base + IMGU_REG_ISP_CTRL)
+               | IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_ISP_CTRL);
+       if (ipu3_hw_wait(css->base, IMGU_REG_ISP_DMEM_BASE
+                        + bl->info.bl.sw_state, ~0,
+                        IMGU_ABI_BL_SWSTATE_OK)) {
+               dev_err(css->dev, "failed to start bootloader\n");
+               return -EIO;
+       }
+
+       /* Start ISP */
+
+       memset(css->xmem_sp_group_ptrs.vaddr, 0,
+              sizeof(struct imgu_abi_sp_group));
+
+       bi = &css->fwp->binary_header[css->fw_sp[0]];
+
+       writel(css->xmem_sp_group_ptrs.daddr,
+              base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.per_frame_data);
+
+       writel(IMGU_ABI_SP_SWSTATE_TERMINATED,
+              base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state);
+       writel(1, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
+
+       if (ipu3_css_hw_start_sp(css, 0))
+               return -EIO;
+
+       writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.isp_started);
+       writel(0, base + IMGU_REG_SP_DMEM_BASE(0) +
+               bi->info.sp.host_sp_queues_initialized);
+       writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sleep_mode);
+       writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
+       writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(0)
+               + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
+
+       /* Enable all events for all queues */
+
+       for (i = 0; i < IPU3_CSS_PIPE_ID_NUM; i++)
+               writel(event_mask, base + IMGU_REG_SP_DMEM_BASE(0)
+                       + bi->info.sp.host_sp_com
+                       + IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(i));
+       writel(1, base + IMGU_REG_SP_DMEM_BASE(0) +
+               bi->info.sp.host_sp_queues_initialized);
+
+       /* Start SP1 */
+
+       bi = &css->fwp->binary_header[css->fw_sp[1]];
+
+       writel(IMGU_ABI_SP_SWSTATE_TERMINATED,
+              base + IMGU_REG_SP_DMEM_BASE(1) + bi->info.sp.sw_state);
+
+       if (ipu3_css_hw_start_sp(css, 1))
+               return -EIO;
+
+       writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(1)
+               + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
+
+       return 0;
+}
+
+static void ipu3_css_hw_stop(struct ipu3_css *css)
+{
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]];
+
+       /* Stop fw */
+       writel(IMGU_ABI_SP_COMM_COMMAND_TERMINATE,
+              base + IMGU_REG_SP_DMEM_BASE(0) +
+              bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
+       if (ipu3_hw_wait(css->base, IMGU_REG_SP_CTRL(0),
+                        IMGU_CTRL_IDLE, IMGU_CTRL_IDLE))
+               dev_err(css->dev, "wait sp0 idle timeout.\n");
+       if (readl(base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state) !=
+                 IMGU_ABI_SP_SWSTATE_TERMINATED)
+               dev_err(css->dev, "sp0 is not terminated.\n");
+       if (ipu3_hw_wait(css->base, IMGU_REG_ISP_CTRL,
+                        IMGU_CTRL_IDLE, IMGU_CTRL_IDLE))
+               dev_err(css->dev, "wait isp idle timeout\n");
+}
+
+static void ipu3_css_hw_cleanup(struct ipu3_css *css)
+{
+       void __iomem *const base = css->base;
+
+       /** Reset CSS **/
+
+       /* Clear the CSS busy signal */
+       readl(base + IMGU_REG_GP_BUSY);
+       writel(0, base + IMGU_REG_GP_BUSY);
+
+       /* Wait for idle signal */
+       if (ipu3_hw_wait(css->base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+                        IMGU_STATE_IDLE_STS))
+               dev_err(css->dev, "failed to shut down hw cleanly\n");
+
+       /* Reset the css */
+       writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
+              base + IMGU_REG_PM_CTRL);
+
+       usleep_range(200, 300);
+}
+
+static void ipu3_css_pipeline_cleanup(struct ipu3_css *css, unsigned int pipe)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       unsigned int i;
+
+       ipu3_css_pool_cleanup(imgu,
+                             &css->pipes[pipe].pool.parameter_set_info);
+       ipu3_css_pool_cleanup(imgu, &css->pipes[pipe].pool.acc);
+       ipu3_css_pool_cleanup(imgu, &css->pipes[pipe].pool.gdc);
+       ipu3_css_pool_cleanup(imgu, &css->pipes[pipe].pool.obgrid);
+
+       for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+               ipu3_css_pool_cleanup(imgu,
+                                     &css->pipes[pipe].pool.binary_params_p[i]);
+}
+
+/*
+ * This function initializes various stages of the
+ * IPU3 CSS ISP pipeline
+ */
+static int ipu3_css_pipeline_init(struct ipu3_css *css, unsigned int pipe)
+{
+       static const int BYPC = 2;      /* Bytes per component */
+       static const struct imgu_abi_buffer_sp buffer_sp_init = {
+               .buf_src = {.queue_id = IMGU_ABI_QUEUE_EVENT_ID},
+               .buf_type = IMGU_ABI_BUFFER_TYPE_INVALID,
+       };
+
+       struct imgu_abi_isp_iterator_config *cfg_iter;
+       struct imgu_abi_isp_ref_config *cfg_ref;
+       struct imgu_abi_isp_dvs_config *cfg_dvs;
+       struct imgu_abi_isp_tnr3_config *cfg_tnr;
+       struct imgu_abi_isp_ref_dmem_state *cfg_ref_state;
+       struct imgu_abi_isp_tnr3_dmem_state *cfg_tnr_state;
+
+       const int stage = 0;
+       unsigned int i, j;
+
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       const struct imgu_fw_info *bi =
+                       &css->fwp->binary_header[css_pipe->bindex];
+       const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+
+       struct imgu_fw_config_memory_offsets *cofs = (void *)css->fwp +
+               bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG];
+       struct imgu_fw_state_memory_offsets *sofs = (void *)css->fwp +
+               bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE];
+
+       struct imgu_abi_isp_stage *isp_stage;
+       struct imgu_abi_sp_stage *sp_stage;
+       struct imgu_abi_sp_group *sp_group;
+
+       const unsigned int bds_width_pad =
+                               ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
+                                     2 * IPU3_UAPI_ISP_VEC_ELEMS);
+
+       const enum imgu_abi_memories m0 = IMGU_ABI_MEM_ISP_DMEM0;
+       enum imgu_abi_param_class cfg = IMGU_ABI_PARAM_CLASS_CONFIG;
+       void *vaddr = css_pipe->binary_params_cs[cfg - 1][m0].vaddr;
+
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+
+       dev_dbg(css->dev, "%s for pipe %d", __func__, pipe);
+
+       /* Configure iterator */
+
+       cfg_iter = ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                              &cofs->dmem.iterator,
+                                              sizeof(*cfg_iter), vaddr);
+       if (!cfg_iter)
+               goto bad_firmware;
+
+       cfg_iter->input_info.res.width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+       cfg_iter->input_info.res.height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+       cfg_iter->input_info.padded_width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_IN].width_pad;
+       cfg_iter->input_info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
+       cfg_iter->input_info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
+       cfg_iter->input_info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+       cfg_iter->input_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+       cfg_iter->internal_info.res.width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       cfg_iter->internal_info.res.height =
+                                       css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       cfg_iter->internal_info.padded_width = bds_width_pad;
+       cfg_iter->internal_info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+       cfg_iter->internal_info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+       cfg_iter->internal_info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+       cfg_iter->internal_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+       cfg_iter->output_info.res.width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       cfg_iter->output_info.res.height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       cfg_iter->output_info.padded_width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+       cfg_iter->output_info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+       cfg_iter->output_info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+       cfg_iter->output_info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+       cfg_iter->output_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+       cfg_iter->vf_info.res.width =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       cfg_iter->vf_info.res.height =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       cfg_iter->vf_info.padded_width =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
+       cfg_iter->vf_info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+       cfg_iter->vf_info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
+       cfg_iter->vf_info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
+       cfg_iter->vf_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+       cfg_iter->dvs_envelope.width = css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].width;
+       cfg_iter->dvs_envelope.height =
+                               css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].height;
+
+       /* Configure reference (delay) frames */
+
+       cfg_ref = ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                             &cofs->dmem.ref,
+                                             sizeof(*cfg_ref), vaddr);
+       if (!cfg_ref)
+               goto bad_firmware;
+
+       cfg_ref->port_b.crop = 0;
+       cfg_ref->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES / BYPC;
+       cfg_ref->port_b.width =
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].width;
+       cfg_ref->port_b.stride =
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline;
+       cfg_ref->width_a_over_b =
+                               IPU3_UAPI_ISP_VEC_ELEMS / cfg_ref->port_b.elems;
+       cfg_ref->dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++) {
+               cfg_ref->ref_frame_addr_y[i] =
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr;
+               cfg_ref->ref_frame_addr_c[i] =
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr +
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline *
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+       }
+       for (; i < IMGU_ABI_FRAMES_REF; i++) {
+               cfg_ref->ref_frame_addr_y[i] = 0;
+               cfg_ref->ref_frame_addr_c[i] = 0;
+       }
+
+       /* Configure DVS (digital video stabilization) */
+
+       cfg_dvs = ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                             &cofs->dmem.dvs, sizeof(*cfg_dvs),
+                                             vaddr);
+       if (!cfg_dvs)
+               goto bad_firmware;
+
+       cfg_dvs->num_horizontal_blocks =
+                       ALIGN(DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_GDC].width,
+                                          IMGU_DVS_BLOCK_W), 2);
+       cfg_dvs->num_vertical_blocks =
+                       DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_GDC].height,
+                                    IMGU_DVS_BLOCK_H);
+
+       /* Configure TNR (temporal noise reduction) */
+
+       if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+               cfg_tnr = ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                                     &cofs->dmem.tnr3,
+                                                     sizeof(*cfg_tnr),
+                                                     vaddr);
+               if (!cfg_tnr)
+                       goto bad_firmware;
+
+               cfg_tnr->port_b.crop = 0;
+               cfg_tnr->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES;
+               cfg_tnr->port_b.width =
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
+               cfg_tnr->port_b.stride =
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline;
+               cfg_tnr->width_a_over_b =
+                       IPU3_UAPI_ISP_VEC_ELEMS / cfg_tnr->port_b.elems;
+               cfg_tnr->frame_height =
+                       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
+               cfg_tnr->delay_frame = IPU3_CSS_AUX_FRAMES - 1;
+               for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+                       cfg_tnr->frame_addr[i] =
+                               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR]
+                                       .mem[i].daddr;
+               for (; i < IMGU_ABI_FRAMES_TNR; i++)
+                       cfg_tnr->frame_addr[i] = 0;
+       }
+
+       /* Configure ref dmem state parameters */
+
+       cfg = IMGU_ABI_PARAM_CLASS_STATE;
+       vaddr = css_pipe->binary_params_cs[cfg - 1][m0].vaddr;
+
+       cfg_ref_state = ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                                   &sofs->dmem.ref,
+                                                   sizeof(*cfg_ref_state),
+                                                   vaddr);
+       if (!cfg_ref_state)
+               goto bad_firmware;
+
+       cfg_ref_state->ref_in_buf_idx = 0;
+       cfg_ref_state->ref_out_buf_idx = 1;
+
+       /* Configure tnr dmem state parameters */
+       if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+               cfg_tnr_state =
+                       ipu3_css_fw_pipeline_params(css, pipe, cfg, m0,
+                                                   &sofs->dmem.tnr3,
+                                                   sizeof(*cfg_tnr_state),
+                                                   vaddr);
+               if (!cfg_tnr_state)
+                       goto bad_firmware;
+
+               cfg_tnr_state->in_bufidx = 0;
+               cfg_tnr_state->out_bufidx = 1;
+               cfg_tnr_state->bypass_filter = 0;
+               cfg_tnr_state->total_frame_counter = 0;
+               for (i = 0; i < IMGU_ABI_BUF_SETS_TNR; i++)
+                       cfg_tnr_state->buffer_frame_counter[i] = 0;
+       }
+
+       /* Configure ISP stage */
+
+       isp_stage = css_pipe->xmem_isp_stage_ptrs[pipe][stage].vaddr;
+       memset(isp_stage, 0, sizeof(*isp_stage));
+       isp_stage->blob_info = bi->blob;
+       isp_stage->binary_info = bi->info.isp.sp;
+       strscpy(isp_stage->binary_name,
+               (char *)css->fwp + bi->blob.prog_name_offset,
+               sizeof(isp_stage->binary_name));
+       isp_stage->mem_initializers = bi->info.isp.sp.mem_initializers;
+       for (i = IMGU_ABI_PARAM_CLASS_CONFIG; i < IMGU_ABI_PARAM_CLASS_NUM; i++)
+               for (j = 0; j < IMGU_ABI_NUM_MEMORIES; j++)
+                       isp_stage->mem_initializers.params[i][j].address =
+                                       css_pipe->binary_params_cs[i - 1][j].daddr;
+
+       /* Configure SP stage */
+
+       sp_stage = css_pipe->xmem_sp_stage_ptrs[pipe][stage].vaddr;
+       memset(sp_stage, 0, sizeof(*sp_stage));
+
+       sp_stage->frames.in.buf_attr = buffer_sp_init;
+       for (i = 0; i < IMGU_ABI_BINARY_MAX_OUTPUT_PORTS; i++)
+               sp_stage->frames.out[i].buf_attr = buffer_sp_init;
+       sp_stage->frames.out_vf.buf_attr = buffer_sp_init;
+       sp_stage->frames.s3a_buf = buffer_sp_init;
+       sp_stage->frames.dvs_buf = buffer_sp_init;
+
+       sp_stage->stage_type = IMGU_ABI_STAGE_TYPE_ISP;
+       sp_stage->num = stage;
+       sp_stage->isp_online = 0;
+       sp_stage->isp_copy_vf = 0;
+       sp_stage->isp_copy_output = 0;
+
+       sp_stage->enable.vf_output = css_pipe->vf_output_en;
+
+       sp_stage->frames.effective_in_res.width =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+       sp_stage->frames.effective_in_res.height =
+                               css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+       sp_stage->frames.in.info.res.width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+       sp_stage->frames.in.info.res.height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+       sp_stage->frames.in.info.padded_width =
+                                       css_pipe->queue[IPU3_CSS_QUEUE_IN].width_pad;
+       sp_stage->frames.in.info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
+       sp_stage->frames.in.info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
+       sp_stage->frames.in.info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+       sp_stage->frames.in.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+       sp_stage->frames.in.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_C_ID;
+       sp_stage->frames.in.buf_attr.buf_type =
+                                       IMGU_ABI_BUFFER_TYPE_INPUT_FRAME;
+
+       sp_stage->frames.out[0].info.res.width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+       sp_stage->frames.out[0].info.res.height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       sp_stage->frames.out[0].info.padded_width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+       sp_stage->frames.out[0].info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+       sp_stage->frames.out[0].info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+       sp_stage->frames.out[0].info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+       sp_stage->frames.out[0].info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+       sp_stage->frames.out[0].planes.nv.uv.offset =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad *
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+       sp_stage->frames.out[0].buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_D_ID;
+       sp_stage->frames.out[0].buf_attr.buf_type =
+                                       IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME;
+
+       sp_stage->frames.out[1].buf_attr.buf_src.queue_id =
+                                                       IMGU_ABI_QUEUE_EVENT_ID;
+
+       sp_stage->frames.internal_frame_info.res.width =
+                                       css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       sp_stage->frames.internal_frame_info.res.height =
+                                       css_pipe->rect[IPU3_CSS_RECT_BDS].height;
+       sp_stage->frames.internal_frame_info.padded_width = bds_width_pad;
+
+       sp_stage->frames.internal_frame_info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+       sp_stage->frames.internal_frame_info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+       sp_stage->frames.internal_frame_info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+       sp_stage->frames.internal_frame_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+       sp_stage->frames.out_vf.info.res.width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+       sp_stage->frames.out_vf.info.res.height =
+                               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       sp_stage->frames.out_vf.info.padded_width =
+                                       css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
+       sp_stage->frames.out_vf.info.format =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+       sp_stage->frames.out_vf.info.raw_bit_depth =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
+       sp_stage->frames.out_vf.info.raw_bayer_order =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
+       sp_stage->frames.out_vf.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+       sp_stage->frames.out_vf.planes.yuv.u.offset =
+                               css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad *
+                               css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+       sp_stage->frames.out_vf.planes.yuv.v.offset =
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad *
+                       css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height * 5 / 4;
+       sp_stage->frames.out_vf.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_E_ID;
+       sp_stage->frames.out_vf.buf_attr.buf_type =
+                                       IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME;
+
+       sp_stage->frames.s3a_buf.buf_src.queue_id = IMGU_ABI_QUEUE_F_ID;
+       sp_stage->frames.s3a_buf.buf_type = IMGU_ABI_BUFFER_TYPE_3A_STATISTICS;
+
+       sp_stage->frames.dvs_buf.buf_src.queue_id = IMGU_ABI_QUEUE_G_ID;
+       sp_stage->frames.dvs_buf.buf_type = IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS;
+
+       sp_stage->dvs_envelope.width = css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].width;
+       sp_stage->dvs_envelope.height =
+                               css_pipe->rect[IPU3_CSS_RECT_ENVELOPE].height;
+
+       sp_stage->isp_pipe_version =
+                               bi->info.isp.sp.pipeline.isp_pipe_version;
+       sp_stage->isp_deci_log_factor =
+                       clamp(max(fls(css_pipe->rect[IPU3_CSS_RECT_BDS].width /
+                                     IMGU_MAX_BQ_GRID_WIDTH),
+                                 fls(css_pipe->rect[IPU3_CSS_RECT_BDS].height /
+                                     IMGU_MAX_BQ_GRID_HEIGHT)) - 1, 3, 5);
+       sp_stage->isp_vf_downscale_bits = 0;
+       sp_stage->if_config_index = 255;
+       sp_stage->sp_enable_xnr = 0;
+       sp_stage->num_stripes = stripes;
+       sp_stage->enable.s3a = 1;
+       sp_stage->enable.dvs_stats = 0;
+
+       sp_stage->xmem_bin_addr = css->binary[css_pipe->bindex].daddr;
+       sp_stage->xmem_map_addr = css_pipe->sp_ddr_ptrs.daddr;
+       sp_stage->isp_stage_addr =
+               css_pipe->xmem_isp_stage_ptrs[pipe][stage].daddr;
+
+       /* Configure SP group */
+
+       sp_group = css->xmem_sp_group_ptrs.vaddr;
+       memset(&sp_group->pipe[pipe], 0, sizeof(struct imgu_abi_sp_pipeline));
+
+       sp_group->pipe[pipe].num_stages = 1;
+       sp_group->pipe[pipe].pipe_id = css_pipe->pipe_id;
+       sp_group->pipe[pipe].thread_id = pipe;
+       sp_group->pipe[pipe].pipe_num = pipe;
+       sp_group->pipe[pipe].num_execs = -1;
+       sp_group->pipe[pipe].pipe_qos_config = -1;
+       sp_group->pipe[pipe].required_bds_factor = 0;
+       sp_group->pipe[pipe].dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
+       sp_group->pipe[pipe].inout_port_config =
+                                       IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
+                                       IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;
+       sp_group->pipe[pipe].scaler_pp_lut = 0;
+       sp_group->pipe[pipe].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
+       sp_group->pipe[pipe].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
+       sp_group->pipe[pipe].sp_stage_addr[stage] =
+                       css_pipe->xmem_sp_stage_ptrs[pipe][stage].daddr;
+       sp_group->pipe[pipe].pipe_config =
+                       bi->info.isp.sp.enable.params ? (1 << pipe) : 0;
+       sp_group->pipe[pipe].pipe_config |= IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP;
+
+       /* Initialize parameter pools */
+
+       if (ipu3_css_pool_init(imgu, &css_pipe->pool.parameter_set_info,
+                              sizeof(struct imgu_abi_parameter_set_info)) ||
+           ipu3_css_pool_init(imgu, &css_pipe->pool.acc,
+                              sizeof(struct imgu_abi_acc_param)) ||
+           ipu3_css_pool_init(imgu, &css_pipe->pool.gdc,
+                              sizeof(struct imgu_abi_gdc_warp_param) *
+                              3 * cfg_dvs->num_horizontal_blocks / 2 *
+                              cfg_dvs->num_vertical_blocks) ||
+           ipu3_css_pool_init(imgu, &css_pipe->pool.obgrid,
+                              ipu3_css_fw_obgrid_size(
+                              &css->fwp->binary_header[css_pipe->bindex])))
+               goto out_of_memory;
+
+       for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+               if (ipu3_css_pool_init(imgu,
+                                      &css_pipe->pool.binary_params_p[i],
+                                      bi->info.isp.sp.mem_initializers.params
+                                      [IMGU_ABI_PARAM_CLASS_PARAM][i].size))
+                       goto out_of_memory;
+
+       return 0;
+
+bad_firmware:
+       ipu3_css_pipeline_cleanup(css, pipe);
+       return -EPROTO;
+
+out_of_memory:
+       ipu3_css_pipeline_cleanup(css, pipe);
+       return -ENOMEM;
+}
+
+static u8 ipu3_css_queue_pos(struct ipu3_css *css, int queue, int thread)
+{
+       static const unsigned int sp;
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+       struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+                                               bi->info.sp.host_sp_queue;
+
+       return queue >= 0 ? readb(&q->host2sp_bufq_info[thread][queue].end) :
+                           readb(&q->host2sp_evtq_info.end);
+}
+
+/* Sent data to sp using given buffer queue, or if queue < 0, event queue. */
+static int ipu3_css_queue_data(struct ipu3_css *css,
+                              int queue, int thread, u32 data)
+{
+       static const unsigned int sp;
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+       struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+                                               bi->info.sp.host_sp_queue;
+       u8 size, start, end, end2;
+
+       if (queue >= 0) {
+               size = readb(&q->host2sp_bufq_info[thread][queue].size);
+               start = readb(&q->host2sp_bufq_info[thread][queue].start);
+               end = readb(&q->host2sp_bufq_info[thread][queue].end);
+       } else {
+               size = readb(&q->host2sp_evtq_info.size);
+               start = readb(&q->host2sp_evtq_info.start);
+               end = readb(&q->host2sp_evtq_info.end);
+       }
+
+       if (size == 0)
+               return -EIO;
+
+       end2 = (end + 1) % size;
+       if (end2 == start)
+               return -EBUSY;  /* Queue full */
+
+       if (queue >= 0) {
+               writel(data, &q->host2sp_bufq[thread][queue][end]);
+               writeb(end2, &q->host2sp_bufq_info[thread][queue].end);
+       } else {
+               writel(data, &q->host2sp_evtq[end]);
+               writeb(end2, &q->host2sp_evtq_info.end);
+       }
+
+       return 0;
+}
+
+/* Receive data using given buffer queue, or if queue < 0, event queue. */
+static int ipu3_css_dequeue_data(struct ipu3_css *css, int queue, u32 *data)
+{
+       static const unsigned int sp;
+       void __iomem *const base = css->base;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+       struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+                                               bi->info.sp.host_sp_queue;
+       u8 size, start, end, start2;
+
+       if (queue >= 0) {
+               size = readb(&q->sp2host_bufq_info[queue].size);
+               start = readb(&q->sp2host_bufq_info[queue].start);
+               end = readb(&q->sp2host_bufq_info[queue].end);
+       } else {
+               size = readb(&q->sp2host_evtq_info.size);
+               start = readb(&q->sp2host_evtq_info.start);
+               end = readb(&q->sp2host_evtq_info.end);
+       }
+
+       if (size == 0)
+               return -EIO;
+
+       if (end == start)
+               return -EBUSY;  /* Queue empty */
+
+       start2 = (start + 1) % size;
+
+       if (queue >= 0) {
+               *data = readl(&q->sp2host_bufq[queue][start]);
+               writeb(start2, &q->sp2host_bufq_info[queue].start);
+       } else {
+               int r;
+
+               *data = readl(&q->sp2host_evtq[start]);
+               writeb(start2, &q->sp2host_evtq_info.start);
+
+               /* Acknowledge events dequeued from event queue */
+               r = ipu3_css_queue_data(css, queue, 0,
+                                       IMGU_ABI_EVENT_EVENT_DEQUEUED);
+               if (r < 0)
+                       return r;
+       }
+
+       return 0;
+}
+
+/* Free binary-specific resources */
+static void ipu3_css_binary_cleanup(struct ipu3_css *css, unsigned int pipe)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       unsigned int i, j;
+
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       for (j = 0; j < IMGU_ABI_PARAM_CLASS_NUM - 1; j++)
+               for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+                       ipu3_dmamap_free(imgu,
+                                        &css_pipe->binary_params_cs[j][i]);
+
+       j = IPU3_CSS_AUX_FRAME_REF;
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               ipu3_dmamap_free(imgu,
+                                &css_pipe->aux_frames[j].mem[i]);
+
+       j = IPU3_CSS_AUX_FRAME_TNR;
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               ipu3_dmamap_free(imgu,
+                                &css_pipe->aux_frames[j].mem[i]);
+}
+
+static int ipu3_css_binary_preallocate(struct ipu3_css *css, unsigned int pipe)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       unsigned int i, j;
+
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       for (j = IMGU_ABI_PARAM_CLASS_CONFIG;
+            j < IMGU_ABI_PARAM_CLASS_NUM; j++)
+               for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+                       if (!ipu3_dmamap_alloc(imgu,
+                                              &css_pipe->binary_params_cs[j - 1][i],
+                                              CSS_ABI_SIZE))
+                               goto out_of_memory;
+
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               if (!ipu3_dmamap_alloc(imgu,
+                                      &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].
+                                      mem[i], CSS_BDS_SIZE))
+                       goto out_of_memory;
+
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               if (!ipu3_dmamap_alloc(imgu,
+                                      &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].
+                                      mem[i], CSS_GDC_SIZE))
+                       goto out_of_memory;
+
+       return 0;
+
+out_of_memory:
+       ipu3_css_binary_cleanup(css, pipe);
+       return -ENOMEM;
+}
+
+/* allocate binary-specific resources */
+static int ipu3_css_binary_setup(struct ipu3_css *css, unsigned int pipe)
+{
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css_pipe->bindex];
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       int i, j, size;
+       static const int BYPC = 2;      /* Bytes per component */
+       unsigned int w, h;
+
+       /* Allocate parameter memory blocks for this binary */
+
+       for (j = IMGU_ABI_PARAM_CLASS_CONFIG; j < IMGU_ABI_PARAM_CLASS_NUM; j++)
+               for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++) {
+                       if (ipu3_css_dma_buffer_resize(
+                           imgu,
+                           &css_pipe->binary_params_cs[j - 1][i],
+                           bi->info.isp.sp.mem_initializers.params[j][i].size))
+                               goto out_of_memory;
+               }
+
+       /* Allocate internal frame buffers */
+
+       /* Reference frames for DVS, FRAME_FORMAT_YUV420_16 */
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel = BYPC;
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].width =
+                                       css_pipe->rect[IPU3_CSS_RECT_BDS].width;
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height =
+                               ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].height,
+                                     IMGU_DVS_BLOCK_H) + 2 * IMGU_GDC_BUF_Y;
+       h = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+       w = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
+                 2 * IPU3_UAPI_ISP_VEC_ELEMS) + 2 * IMGU_GDC_BUF_X;
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline =
+               css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel * w;
+       size = w * h * BYPC + (w / 2) * (h / 2) * BYPC * 2;
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               if (ipu3_css_dma_buffer_resize(
+                       imgu,
+                       &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i],
+                       size))
+                       goto out_of_memory;
+
+       /* TNR frames for temporal noise reduction, FRAME_FORMAT_YUV_LINE */
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperpixel = 1;
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width =
+                       roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width,
+                               bi->info.isp.sp.block.block_width *
+                               IPU3_UAPI_ISP_VEC_ELEMS);
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height =
+                       roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].height,
+                               bi->info.isp.sp.block.output_block_height);
+
+       w = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
+       css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline = w;
+       h = css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
+       size = w * ALIGN(h * 3 / 2 + 3, 2);     /* +3 for vf_pp prefetch */
+       for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+               if (ipu3_css_dma_buffer_resize(
+                       imgu,
+                       &css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_TNR].mem[i],
+                       size))
+                       goto out_of_memory;
+
+       return 0;
+
+out_of_memory:
+       ipu3_css_binary_cleanup(css, pipe);
+       return -ENOMEM;
+}
+
+int ipu3_css_start_streaming(struct ipu3_css *css)
+{
+       u32 data;
+       int r, pipe;
+
+       if (css->streaming)
+               return -EPROTO;
+
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = ipu3_css_binary_setup(css, pipe);
+               if (r < 0)
+                       return r;
+       }
+
+       r = ipu3_css_hw_init(css);
+       if (r < 0)
+               return r;
+
+       r = ipu3_css_hw_start(css);
+       if (r < 0)
+               goto fail;
+
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = ipu3_css_pipeline_init(css, pipe);
+               if (r < 0)
+                       goto fail;
+       }
+
+       css->streaming = true;
+
+       ipu3_css_hw_enable_irq(css);
+
+       /* Initialize parameters to default */
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = ipu3_css_set_parameters(css, pipe, NULL);
+               if (r < 0)
+                       goto fail;
+       }
+
+       while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_A_ID, &data)))
+               ;
+       if (r != -EBUSY)
+               goto fail;
+
+       while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_B_ID, &data)))
+               ;
+       if (r != -EBUSY)
+               goto fail;
+
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe,
+                                       IMGU_ABI_EVENT_START_STREAM |
+                                       pipe << 16);
+               if (r < 0)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       css->streaming = false;
+       ipu3_css_hw_cleanup(css);
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               ipu3_css_pipeline_cleanup(css, pipe);
+               ipu3_css_binary_cleanup(css, pipe);
+       }
+
+       return r;
+}
+
+void ipu3_css_stop_streaming(struct ipu3_css *css)
+{
+       struct ipu3_css_buffer *b, *b0;
+       int q, r, pipe;
+
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe,
+                                       IMGU_ABI_EVENT_STOP_STREAM);
+               if (r < 0)
+                       dev_warn(css->dev, "failed on stop stream event\n");
+       }
+
+       if (!css->streaming)
+               return;
+
+       ipu3_css_hw_stop(css);
+
+       ipu3_css_hw_cleanup(css);
+
+       for_each_set_bit(pipe, css->enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+               ipu3_css_pipeline_cleanup(css, pipe);
+
+               spin_lock(&css_pipe->qlock);
+               for (q = 0; q < IPU3_CSS_QUEUES; q++)
+                       list_for_each_entry_safe(b, b0,
+                                                &css_pipe->queue[q].bufs,
+                                                list) {
+                               b->state = IPU3_CSS_BUFFER_FAILED;
+                               list_del(&b->list);
+                       }
+               spin_unlock(&css_pipe->qlock);
+       }
+
+       css->streaming = false;
+}
+
+bool ipu3_css_pipe_queue_empty(struct ipu3_css *css, unsigned int pipe)
+{
+       int q;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       spin_lock(&css_pipe->qlock);
+       for (q = 0; q < IPU3_CSS_QUEUES; q++)
+               if (!list_empty(&css_pipe->queue[q].bufs))
+                       break;
+       spin_unlock(&css_pipe->qlock);
+       return (q == IPU3_CSS_QUEUES);
+}
+
+bool ipu3_css_queue_empty(struct ipu3_css *css)
+{
+       unsigned int pipe;
+       bool ret = 0;
+
+       for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++)
+               ret &= ipu3_css_pipe_queue_empty(css, pipe);
+
+       return ret;
+}
+
+bool ipu3_css_is_streaming(struct ipu3_css *css)
+{
+       return css->streaming;
+}
+
+static int ipu3_css_map_init(struct ipu3_css *css, unsigned int pipe)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       unsigned int p, q, i;
+
+       /* Allocate and map common structures with imgu hardware */
+       for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
+               for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
+                       if (!ipu3_dmamap_alloc(imgu,
+                                              &css_pipe->
+                                              xmem_sp_stage_ptrs[p][i],
+                                              sizeof(struct imgu_abi_sp_stage)))
+                               return -ENOMEM;
+                       if (!ipu3_dmamap_alloc(imgu,
+                                              &css_pipe->
+                                              xmem_isp_stage_ptrs[p][i],
+                                              sizeof(struct imgu_abi_isp_stage)))
+                               return -ENOMEM;
+               }
+
+       if (!ipu3_dmamap_alloc(imgu, &css_pipe->sp_ddr_ptrs,
+                              ALIGN(sizeof(struct imgu_abi_ddr_address_map),
+                                    IMGU_ABI_ISP_DDR_WORD_BYTES)))
+               return -ENOMEM;
+
+       for (q = 0; q < IPU3_CSS_QUEUES; q++) {
+               unsigned int abi_buf_num = ARRAY_SIZE(css_pipe->abi_buffers[q]);
+
+               for (i = 0; i < abi_buf_num; i++)
+                       if (!ipu3_dmamap_alloc(imgu,
+                                              &css_pipe->abi_buffers[q][i],
+                                              sizeof(struct imgu_abi_buffer)))
+                               return -ENOMEM;
+       }
+
+       if (ipu3_css_binary_preallocate(css, pipe)) {
+               ipu3_css_binary_cleanup(css, pipe);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void ipu3_css_pipe_cleanup(struct ipu3_css *css, unsigned int pipe)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       unsigned int p, q, i, abi_buf_num;
+
+       ipu3_css_binary_cleanup(css, pipe);
+
+       for (q = 0; q < IPU3_CSS_QUEUES; q++) {
+               abi_buf_num = ARRAY_SIZE(css_pipe->abi_buffers[q]);
+               for (i = 0; i < abi_buf_num; i++)
+                       ipu3_dmamap_free(imgu, &css_pipe->abi_buffers[q][i]);
+       }
+
+       for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
+               for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
+                       ipu3_dmamap_free(imgu,
+                                        &css_pipe->xmem_sp_stage_ptrs[p][i]);
+                       ipu3_dmamap_free(imgu,
+                                        &css_pipe->xmem_isp_stage_ptrs[p][i]);
+               }
+
+       ipu3_dmamap_free(imgu, &css_pipe->sp_ddr_ptrs);
+}
+
+void ipu3_css_cleanup(struct ipu3_css *css)
+{
+       struct imgu_device *imgu = dev_get_drvdata(css->dev);
+       unsigned int pipe;
+
+       ipu3_css_stop_streaming(css);
+       for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++)
+               ipu3_css_pipe_cleanup(css, pipe);
+       ipu3_dmamap_free(imgu, &css->xmem_sp_group_ptrs);
+       ipu3_css_fw_cleanup(css);
+}
+
+int ipu3_css_init(struct device *dev, struct ipu3_css *css,
+                 void __iomem *base, int length)
+{
+       struct imgu_device *imgu = dev_get_drvdata(dev);
+       int r, q, pipe;
+
+       /* Initialize main data structure */
+       css->dev = dev;
+       css->base = base;
+       css->iomem_length = length;
+
+       for (pipe = 0; pipe < IMGU_MAX_PIPE_NUM; pipe++) {
+               struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+               css_pipe->vf_output_en = false;
+               spin_lock_init(&css_pipe->qlock);
+               css_pipe->bindex = IPU3_CSS_DEFAULT_BINARY;
+               css_pipe->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
+               for (q = 0; q < IPU3_CSS_QUEUES; q++) {
+                       r = ipu3_css_queue_init(&css_pipe->queue[q], NULL, 0);
+                       if (r)
+                               return r;
+               }
+               r = ipu3_css_map_init(css, pipe);
+               if (r) {
+                       ipu3_css_cleanup(css);
+                       return r;
+               }
+       }
+       if (!ipu3_dmamap_alloc(imgu, &css->xmem_sp_group_ptrs,
+                              sizeof(struct imgu_abi_sp_group)))
+               return -ENOMEM;
+
+       r = ipu3_css_fw_init(css);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static u32 ipu3_css_adjust(u32 res, u32 align)
+{
+       u32 val = max_t(u32, IPU3_CSS_MIN_RES, res);
+
+       return DIV_ROUND_CLOSEST(val, align) * align;
+}
+
+/* Select a binary matching the required resolutions and formats */
+static int ipu3_css_find_binary(struct ipu3_css *css,
+                               unsigned int pipe,
+                               struct ipu3_css_queue queue[IPU3_CSS_QUEUES],
+                               struct v4l2_rect rects[IPU3_CSS_RECTS])
+{
+       const int binary_nr = css->fwp->file_header.binary_nr;
+       unsigned int binary_mode =
+               (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_CAPTURE) ?
+               IA_CSS_BINARY_MODE_PRIMARY : IA_CSS_BINARY_MODE_VIDEO;
+       const struct v4l2_pix_format_mplane *in =
+                                       &queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
+       const struct v4l2_pix_format_mplane *out =
+                                       &queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+       const struct v4l2_pix_format_mplane *vf =
+                                       &queue[IPU3_CSS_QUEUE_VF].fmt.mpix;
+       u32 stripe_w = 0, stripe_h = 0;
+       const char *name;
+       int i, j;
+
+       if (!ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_IN]))
+               return -EINVAL;
+
+       /* Find out the strip size boundary */
+       for (i = 0; i < binary_nr; i++) {
+               struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+
+               u32 max_width = bi->info.isp.sp.output.max_width;
+               u32 max_height = bi->info.isp.sp.output.max_height;
+
+               if (bi->info.isp.sp.iterator.num_stripes <= 1) {
+                       stripe_w = stripe_w ?
+                               min(stripe_w, max_width) : max_width;
+                       stripe_h = stripe_h ?
+                               min(stripe_h, max_height) : max_height;
+               }
+       }
+
+       for (i = 0; i < binary_nr; i++) {
+               struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+               enum imgu_abi_frame_format q_fmt;
+
+               name = (void *)css->fwp + bi->blob.prog_name_offset;
+
+               /* Check that binary supports memory-to-memory processing */
+               if (bi->info.isp.sp.input.source !=
+                   IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY)
+                       continue;
+
+               /* Check that binary supports raw10 input */
+               if (!bi->info.isp.sp.enable.input_feeder &&
+                   !bi->info.isp.sp.enable.input_raw)
+                       continue;
+
+               /* Check binary mode */
+               if (bi->info.isp.sp.pipeline.mode != binary_mode)
+                       continue;
+
+               /* Since input is RGGB bayer, need to process colors */
+               if (bi->info.isp.sp.enable.luma_only)
+                       continue;
+
+               if (in->width < bi->info.isp.sp.input.min_width ||
+                   in->width > bi->info.isp.sp.input.max_width ||
+                   in->height < bi->info.isp.sp.input.min_height ||
+                   in->height > bi->info.isp.sp.input.max_height)
+                       continue;
+
+               if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_OUT])) {
+                       if (bi->info.isp.num_output_pins <= 0)
+                               continue;
+
+                       q_fmt = queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+                       for (j = 0; j < bi->info.isp.num_output_formats; j++)
+                               if (bi->info.isp.output_formats[j] == q_fmt)
+                                       break;
+                       if (j >= bi->info.isp.num_output_formats)
+                               continue;
+
+                       if (out->width < bi->info.isp.sp.output.min_width ||
+                           out->width > bi->info.isp.sp.output.max_width ||
+                           out->height < bi->info.isp.sp.output.min_height ||
+                           out->height > bi->info.isp.sp.output.max_height)
+                               continue;
+
+                       if (out->width > bi->info.isp.sp.internal.max_width ||
+                           out->height > bi->info.isp.sp.internal.max_height)
+                               continue;
+               }
+
+               if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_VF])) {
+                       if (bi->info.isp.num_output_pins <= 1)
+                               continue;
+
+                       q_fmt = queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+                       for (j = 0; j < bi->info.isp.num_output_formats; j++)
+                               if (bi->info.isp.output_formats[j] == q_fmt)
+                                       break;
+                       if (j >= bi->info.isp.num_output_formats)
+                               continue;
+
+                       if (vf->width < bi->info.isp.sp.output.min_width ||
+                           vf->width > bi->info.isp.sp.output.max_width ||
+                           vf->height < bi->info.isp.sp.output.min_height ||
+                           vf->height > bi->info.isp.sp.output.max_height)
+                               continue;
+               }
+
+               /* All checks passed, select the binary */
+               dev_dbg(css->dev, "using binary %s id = %u\n", name,
+                       bi->info.isp.sp.id);
+               return i;
+       }
+
+       /* Can not find suitable binary for these parameters */
+       return -EINVAL;
+}
+
+/*
+ * Check that there is a binary matching requirements. Parameters may be
+ * NULL indicating disabled input/output. Return negative if given
+ * parameters can not be supported or on error, zero or positive indicating
+ * found binary number. May modify the given parameters if not exact match
+ * is found.
+ */
+int ipu3_css_fmt_try(struct ipu3_css *css,
+                    struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+                    struct v4l2_rect *rects[IPU3_CSS_RECTS],
+                    unsigned int pipe)
+{
+       static const u32 EFF_ALIGN_W = 2;
+       static const u32 BDS_ALIGN_W = 4;
+       static const u32 OUT_ALIGN_W = 8;
+       static const u32 OUT_ALIGN_H = 4;
+       static const u32 VF_ALIGN_W  = 2;
+       static const char *qnames[IPU3_CSS_QUEUES] = {
+               [IPU3_CSS_QUEUE_IN] = "in",
+               [IPU3_CSS_QUEUE_PARAMS]    = "params",
+               [IPU3_CSS_QUEUE_OUT] = "out",
+               [IPU3_CSS_QUEUE_VF] = "vf",
+               [IPU3_CSS_QUEUE_STAT_3A]   = "3a",
+       };
+       static const char *rnames[IPU3_CSS_RECTS] = {
+               [IPU3_CSS_RECT_EFFECTIVE] = "effective resolution",
+               [IPU3_CSS_RECT_BDS]       = "bayer-domain scaled resolution",
+               [IPU3_CSS_RECT_ENVELOPE]  = "DVS envelope size",
+               [IPU3_CSS_RECT_GDC]  = "GDC output res",
+       };
+       struct v4l2_rect r[IPU3_CSS_RECTS] = { };
+       struct v4l2_rect *const eff = &r[IPU3_CSS_RECT_EFFECTIVE];
+       struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
+       struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
+       struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
+       struct ipu3_css_queue q[IPU3_CSS_QUEUES];
+       struct v4l2_pix_format_mplane *const in =
+                                       &q[IPU3_CSS_QUEUE_IN].fmt.mpix;
+       struct v4l2_pix_format_mplane *const out =
+                                       &q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+       struct v4l2_pix_format_mplane *const vf =
+                                       &q[IPU3_CSS_QUEUE_VF].fmt.mpix;
+       int i, s;
+
+       /* Adjust all formats, get statistics buffer sizes and formats */
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               if (fmts[i])
+                       dev_dbg(css->dev, "%s %s: (%i,%i) fmt 0x%x\n", __func__,
+                               qnames[i], fmts[i]->width, fmts[i]->height,
+                               fmts[i]->pixelformat);
+               else
+                       dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
+                               qnames[i]);
+               if (ipu3_css_queue_init(&q[i], fmts[i],
+                                       IPU3_CSS_QUEUE_TO_FLAGS(i))) {
+                       dev_notice(css->dev, "can not initialize queue %s\n",
+                                  qnames[i]);
+                       return -EINVAL;
+               }
+       }
+       for (i = 0; i < IPU3_CSS_RECTS; i++) {
+               if (rects[i]) {
+                       dev_dbg(css->dev, "%s %s: (%i,%i)\n", __func__,
+                               rnames[i], rects[i]->width, rects[i]->height);
+                       r[i].width  = rects[i]->width;
+                       r[i].height = rects[i]->height;
+               } else {
+                       dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
+                               rnames[i]);
+               }
+               /* For now, force known good resolutions */
+               r[i].left = 0;
+               r[i].top  = 0;
+       }
+
+       /* Always require one input and vf only if out is also enabled */
+       if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) ||
+           !ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
+               dev_warn(css->dev, "required queues are disabled\n");
+               return -EINVAL;
+       }
+
+       if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
+               out->width = in->width;
+               out->height = in->height;
+       }
+       if (eff->width <= 0 || eff->height <= 0) {
+               eff->width = in->width;
+               eff->height = in->height;
+       }
+       if (bds->width <= 0 || bds->height <= 0) {
+               bds->width = out->width;
+               bds->height = out->height;
+       }
+       if (gdc->width <= 0 || gdc->height <= 0) {
+               gdc->width = out->width;
+               gdc->height = out->height;
+       }
+
+       in->width   = ipu3_css_adjust(in->width, 1);
+       in->height  = ipu3_css_adjust(in->height, 1);
+       eff->width  = ipu3_css_adjust(eff->width, EFF_ALIGN_W);
+       eff->height = ipu3_css_adjust(eff->height, 1);
+       bds->width  = ipu3_css_adjust(bds->width, BDS_ALIGN_W);
+       bds->height = ipu3_css_adjust(bds->height, 1);
+       gdc->width  = ipu3_css_adjust(gdc->width, OUT_ALIGN_W);
+       gdc->height = ipu3_css_adjust(gdc->height, OUT_ALIGN_H);
+       out->width  = ipu3_css_adjust(out->width, OUT_ALIGN_W);
+       out->height = ipu3_css_adjust(out->height, OUT_ALIGN_H);
+       vf->width   = ipu3_css_adjust(vf->width, VF_ALIGN_W);
+       vf->height  = ipu3_css_adjust(vf->height, 1);
+
+       s = (bds->width - gdc->width) / 2 - FILTER_SIZE;
+       env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
+       s = (bds->height - gdc->height) / 2 - FILTER_SIZE;
+       env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
+
+       css->pipes[pipe].bindex =
+               ipu3_css_find_binary(css, pipe, q, r);
+       if (css->pipes[pipe].bindex < 0) {
+               dev_err(css->dev, "failed to find suitable binary\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(css->dev, "Binary index %d for pipe %d found.",
+               css->pipes[pipe].bindex, pipe);
+
+       /* Final adjustment and set back the queried formats */
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               if (fmts[i]) {
+                       if (ipu3_css_queue_init(&q[i], &q[i].fmt.mpix,
+                                               IPU3_CSS_QUEUE_TO_FLAGS(i))) {
+                               dev_err(css->dev,
+                                       "final resolution adjustment failed\n");
+                               return -EINVAL;
+                       }
+                       *fmts[i] = q[i].fmt.mpix;
+               }
+       }
+
+       for (i = 0; i < IPU3_CSS_RECTS; i++)
+               if (rects[i])
+                       *rects[i] = r[i];
+
+       dev_dbg(css->dev,
+               "in(%u,%u) if(%u,%u) ds(%u,%u) gdc(%u,%u) out(%u,%u) vf(%u,%u)",
+                in->width, in->height, eff->width, eff->height,
+                bds->width, bds->height, gdc->width, gdc->height,
+                out->width, out->height, vf->width, vf->height);
+
+       return 0;
+}
+
+int ipu3_css_fmt_set(struct ipu3_css *css,
+                    struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+                    struct v4l2_rect *rects[IPU3_CSS_RECTS],
+                    unsigned int pipe)
+{
+       struct v4l2_rect rect_data[IPU3_CSS_RECTS];
+       struct v4l2_rect *all_rects[IPU3_CSS_RECTS];
+       int i, r;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       for (i = 0; i < IPU3_CSS_RECTS; i++) {
+               if (rects[i])
+                       rect_data[i] = *rects[i];
+               else
+                       memset(&rect_data[i], 0, sizeof(rect_data[i]));
+               all_rects[i] = &rect_data[i];
+       }
+       r = ipu3_css_fmt_try(css, fmts, all_rects, pipe);
+       if (r < 0)
+               return r;
+
+       for (i = 0; i < IPU3_CSS_QUEUES; i++)
+               if (ipu3_css_queue_init(&css_pipe->queue[i], fmts[i],
+                                       IPU3_CSS_QUEUE_TO_FLAGS(i)))
+                       return -EINVAL;
+       for (i = 0; i < IPU3_CSS_RECTS; i++) {
+               css_pipe->rect[i] = rect_data[i];
+               if (rects[i])
+                       *rects[i] = rect_data[i];
+       }
+
+       return 0;
+}
+
+int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt)
+{
+       switch (fmt->dataformat) {
+       case V4L2_META_FMT_IPU3_PARAMS:
+               fmt->buffersize = sizeof(struct ipu3_uapi_params);
+               break;
+       case V4L2_META_FMT_IPU3_STAT_3A:
+               fmt->buffersize = sizeof(struct ipu3_uapi_stats_3a);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Queue given buffer to CSS. ipu3_css_buf_prepare() must have been first
+ * called for the buffer. May be called from interrupt context.
+ * Returns 0 on success, -EBUSY if the buffer queue is full, or some other
+ * code on error conditions.
+ */
+int ipu3_css_buf_queue(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_css_buffer *b)
+{
+       struct imgu_abi_buffer *abi_buf;
+       struct imgu_addr_t *buf_addr;
+       u32 data;
+       int r;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+
+       if (!css->streaming)
+               return -EPROTO; /* CSS or buffer in wrong state */
+
+       if (b->queue >= IPU3_CSS_QUEUES || !ipu3_css_queues[b->queue].qid)
+               return -EINVAL;
+
+       b->queue_pos = ipu3_css_queue_pos(css, ipu3_css_queues[b->queue].qid,
+                                         pipe);
+
+       if (b->queue_pos >= ARRAY_SIZE(css->pipes[pipe].abi_buffers[b->queue]))
+               return -EIO;
+       abi_buf = css->pipes[pipe].abi_buffers[b->queue][b->queue_pos].vaddr;
+
+       /* Fill struct abi_buffer for firmware */
+       memset(abi_buf, 0, sizeof(*abi_buf));
+
+       buf_addr = (void *)abi_buf + ipu3_css_queues[b->queue].ptr_ofs;
+       *(imgu_addr_t *)buf_addr = b->daddr;
+
+       if (b->queue == IPU3_CSS_QUEUE_STAT_3A)
+               abi_buf->payload.s3a.data.dmem.s3a_tbl = b->daddr;
+
+       if (b->queue == IPU3_CSS_QUEUE_OUT)
+               abi_buf->payload.frame.padded_width =
+                               css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+
+       if (b->queue == IPU3_CSS_QUEUE_VF)
+               abi_buf->payload.frame.padded_width =
+                                       css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
+
+       spin_lock(&css_pipe->qlock);
+       list_add_tail(&b->list, &css_pipe->queue[b->queue].bufs);
+       spin_unlock(&css_pipe->qlock);
+       b->state = IPU3_CSS_BUFFER_QUEUED;
+
+       data = css->pipes[pipe].abi_buffers[b->queue][b->queue_pos].daddr;
+       r = ipu3_css_queue_data(css, ipu3_css_queues[b->queue].qid,
+                               pipe, data);
+       if (r < 0)
+               goto queueing_failed;
+
+       data = IMGU_ABI_EVENT_BUFFER_ENQUEUED(pipe,
+                                             ipu3_css_queues[b->queue].qid);
+       r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe, data);
+       if (r < 0)
+               goto queueing_failed;
+
+       dev_dbg(css->dev, "queued buffer %p to css queue %i in pipe %d\n",
+               b, b->queue, pipe);
+
+       return 0;
+
+queueing_failed:
+       b->state = (r == -EBUSY || r == -EAGAIN) ?
+               IPU3_CSS_BUFFER_NEW : IPU3_CSS_BUFFER_FAILED;
+       list_del(&b->list);
+
+       return r;
+}
+
+/*
+ * Get next ready CSS buffer. Returns -EAGAIN in which case the function
+ * should be called again, or -EBUSY which means that there are no more
+ * buffers available. May be called from interrupt context.
+ */
+struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css)
+{
+       static const unsigned char evtype_to_queue[] = {
+               [IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE] = IPU3_CSS_QUEUE_IN,
+               [IMGU_ABI_EVTTYPE_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_OUT,
+               [IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_VF,
+               [IMGU_ABI_EVTTYPE_3A_STATS_DONE] = IPU3_CSS_QUEUE_STAT_3A,
+       };
+       struct ipu3_css_buffer *b = ERR_PTR(-EAGAIN);
+       u32 event, daddr;
+       int evtype, pipe, pipeid, queue, qid, r;
+       struct ipu3_css_pipe *css_pipe;
+
+       if (!css->streaming)
+               return ERR_PTR(-EPROTO);
+
+       r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
+       if (r < 0)
+               return ERR_PTR(r);
+
+       evtype = (event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
+                 IMGU_ABI_EVTTYPE_EVENT_SHIFT;
+
+       switch (evtype) {
+       case IMGU_ABI_EVTTYPE_OUT_FRAME_DONE:
+       case IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE:
+       case IMGU_ABI_EVTTYPE_3A_STATS_DONE:
+       case IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE:
+               pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
+                       IMGU_ABI_EVTTYPE_PIPE_SHIFT;
+               pipeid = (event & IMGU_ABI_EVTTYPE_PIPEID_MASK) >>
+                       IMGU_ABI_EVTTYPE_PIPEID_SHIFT;
+               queue = evtype_to_queue[evtype];
+               qid = ipu3_css_queues[queue].qid;
+
+               if (pipe >= IMGU_MAX_PIPE_NUM) {
+                       dev_err(css->dev, "Invalid pipe: %i\n", pipe);
+                       return ERR_PTR(-EIO);
+               }
+
+               if (qid >= IMGU_ABI_QUEUE_NUM) {
+                       dev_err(css->dev, "Invalid qid: %i\n", qid);
+                       return ERR_PTR(-EIO);
+               }
+               css_pipe = &css->pipes[pipe];
+               dev_dbg(css->dev,
+                       "event: buffer done 0x%x queue %i pipe %i pipeid %i\n",
+                       event, queue, pipe, pipeid);
+
+               r = ipu3_css_dequeue_data(css, qid, &daddr);
+               if (r < 0) {
+                       dev_err(css->dev, "failed to dequeue buffer\n");
+                       /* Force real error, not -EBUSY */
+                       return ERR_PTR(-EIO);
+               }
+
+               r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe,
+                                       IMGU_ABI_EVENT_BUFFER_DEQUEUED(qid));
+               if (r < 0) {
+                       dev_err(css->dev, "failed to queue event\n");
+                       return ERR_PTR(-EIO);
+               }
+
+               spin_lock(&css_pipe->qlock);
+               if (list_empty(&css_pipe->queue[queue].bufs)) {
+                       spin_unlock(&css_pipe->qlock);
+                       dev_err(css->dev, "event on empty queue\n");
+                       return ERR_PTR(-EIO);
+               }
+               b = list_first_entry(&css_pipe->queue[queue].bufs,
+                                    struct ipu3_css_buffer, list);
+               if (queue != b->queue ||
+                   daddr != css_pipe->abi_buffers
+                       [b->queue][b->queue_pos].daddr) {
+                       spin_unlock(&css_pipe->qlock);
+                       dev_err(css->dev, "dequeued bad buffer 0x%x\n", daddr);
+                       return ERR_PTR(-EIO);
+               }
+
+               dev_dbg(css->dev, "buffer 0x%8x done from pipe %d\n", daddr, pipe);
+               b->pipe = pipe;
+               b->state = IPU3_CSS_BUFFER_DONE;
+               list_del(&b->list);
+               spin_unlock(&css_pipe->qlock);
+               break;
+       case IMGU_ABI_EVTTYPE_PIPELINE_DONE:
+               pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
+                       IMGU_ABI_EVTTYPE_PIPE_SHIFT;
+               if (pipe >= IMGU_MAX_PIPE_NUM) {
+                       dev_err(css->dev, "Invalid pipe: %i\n", pipe);
+                       return ERR_PTR(-EIO);
+               }
+
+               css_pipe = &css->pipes[pipe];
+               dev_dbg(css->dev, "event: pipeline done 0x%8x for pipe %d\n",
+                       event, pipe);
+               break;
+       case IMGU_ABI_EVTTYPE_TIMER:
+               r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
+               if (r < 0)
+                       return ERR_PTR(r);
+
+               if ((event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
+                   IMGU_ABI_EVTTYPE_EVENT_SHIFT == IMGU_ABI_EVTTYPE_TIMER)
+                       dev_dbg(css->dev, "event: timer\n");
+               else
+                       dev_warn(css->dev, "half of timer event missing\n");
+               break;
+       case IMGU_ABI_EVTTYPE_FW_WARNING:
+               dev_warn(css->dev, "event: firmware warning 0x%x\n", event);
+               break;
+       case IMGU_ABI_EVTTYPE_FW_ASSERT:
+               dev_err(css->dev,
+                       "event: firmware assert 0x%x module_id %i line_no %i\n",
+                       event,
+                       (event & IMGU_ABI_EVTTYPE_MODULEID_MASK) >>
+                       IMGU_ABI_EVTTYPE_MODULEID_SHIFT,
+                       swab16((event & IMGU_ABI_EVTTYPE_LINENO_MASK) >>
+                              IMGU_ABI_EVTTYPE_LINENO_SHIFT));
+               break;
+       default:
+               dev_warn(css->dev, "received unknown event 0x%x\n", event);
+       }
+
+       return b;
+}
+
+/*
+ * Get a new set of parameters from pool and initialize them based on
+ * the parameters params, gdc, and obgrid. Any of these may be NULL,
+ * in which case the previously set parameters are used.
+ * If parameters haven't been set previously, initialize from scratch.
+ *
+ * Return index to css->parameter_set_info which has the newly created
+ * parameters or negative value on error.
+ */
+int ipu3_css_set_parameters(struct ipu3_css *css, unsigned int pipe,
+                           struct ipu3_uapi_params *set_params)
+{
+       static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
+       struct ipu3_css_pipe *css_pipe = &css->pipes[pipe];
+       const int stage = 0;
+       const struct imgu_fw_info *bi;
+       int obgrid_size;
+       unsigned int stripes, i;
+       struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
+
+       /* Destination buffers which are filled here */
+       struct imgu_abi_parameter_set_info *param_set;
+       struct imgu_abi_acc_param *acc = NULL;
+       struct imgu_abi_gdc_warp_param *gdc = NULL;
+       struct ipu3_uapi_obgrid_param *obgrid = NULL;
+       const struct ipu3_css_map *map;
+       void *vmem0 = NULL;
+       void *dmem0 = NULL;
+
+       enum imgu_abi_memories m;
+       int r = -EBUSY;
+
+       if (!css->streaming)
+               return -EPROTO;
+
+       dev_dbg(css->dev, "%s for pipe %d", __func__, pipe);
+
+       bi = &css->fwp->binary_header[css_pipe->bindex];
+       obgrid_size = ipu3_css_fw_obgrid_size(bi);
+       stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
+
+       /*
+        * TODO(b/118782861): If userspace queues more than 4 buffers, the
+        * parameters from previous buffers will be overwritten. Fix the driver
+        * not to allow this.
+        */
+       ipu3_css_pool_get(&css_pipe->pool.parameter_set_info);
+       param_set = ipu3_css_pool_last(&css_pipe->pool.parameter_set_info,
+                                      0)->vaddr;
+
+       /* Get a new acc only if new parameters given, or none yet */
+       map = ipu3_css_pool_last(&css_pipe->pool.acc, 0);
+       if (set_params || !map->vaddr) {
+               ipu3_css_pool_get(&css_pipe->pool.acc);
+               map = ipu3_css_pool_last(&css_pipe->pool.acc, 0);
+               acc = map->vaddr;
+       }
+
+       /* Get new VMEM0 only if needed, or none yet */
+       m = IMGU_ABI_MEM_ISP_VMEM0;
+       map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 0);
+       if (!map->vaddr || (set_params && (set_params->use.lin_vmem_params ||
+                                          set_params->use.tnr3_vmem_params ||
+                                          set_params->use.xnr3_vmem_params))) {
+               ipu3_css_pool_get(&css_pipe->pool.binary_params_p[m]);
+               map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 0);
+               vmem0 = map->vaddr;
+       }
+
+       /* Get new DMEM0 only if needed, or none yet */
+       m = IMGU_ABI_MEM_ISP_DMEM0;
+       map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 0);
+       if (!map->vaddr || (set_params && (set_params->use.tnr3_dmem_params ||
+                                          set_params->use.xnr3_dmem_params))) {
+               ipu3_css_pool_get(&css_pipe->pool.binary_params_p[m]);
+               map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 0);
+               dmem0 = map->vaddr;
+       }
+
+       /* Configure acc parameter cluster */
+       if (acc) {
+               /* get acc_old */
+               map = ipu3_css_pool_last(&css_pipe->pool.acc, 1);
+               /* user acc */
+               r = ipu3_css_cfg_acc(css, pipe, use, acc, map->vaddr,
+                       set_params ? &set_params->acc_param : NULL);
+               if (r < 0)
+                       goto fail;
+       }
+
+       /* Configure late binding parameters */
+       if (vmem0) {
+               m = IMGU_ABI_MEM_ISP_VMEM0;
+               map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 1);
+               r = ipu3_css_cfg_vmem0(css, pipe, use, vmem0,
+                                      map->vaddr, set_params);
+               if (r < 0)
+                       goto fail;
+       }
+
+       if (dmem0) {
+               m = IMGU_ABI_MEM_ISP_DMEM0;
+               map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 1);
+               r = ipu3_css_cfg_dmem0(css, pipe, use, dmem0,
+                                      map->vaddr, set_params);
+               if (r < 0)
+                       goto fail;
+       }
+
+       /* Get a new gdc only if a new gdc is given, or none yet */
+       if (bi->info.isp.sp.enable.dvs_6axis) {
+               unsigned int a = IPU3_CSS_AUX_FRAME_REF;
+               unsigned int g = IPU3_CSS_RECT_GDC;
+               unsigned int e = IPU3_CSS_RECT_ENVELOPE;
+
+               map = ipu3_css_pool_last(&css_pipe->pool.gdc, 0);
+               if (!map->vaddr) {
+                       ipu3_css_pool_get(&css_pipe->pool.gdc);
+                       map = ipu3_css_pool_last(&css_pipe->pool.gdc, 0);
+                       gdc = map->vaddr;
+                       ipu3_css_cfg_gdc_table(map->vaddr,
+                               css_pipe->aux_frames[a].bytesperline /
+                               css_pipe->aux_frames[a].bytesperpixel,
+                               css_pipe->aux_frames[a].height,
+                               css_pipe->rect[g].width,
+                               css_pipe->rect[g].height,
+                               css_pipe->rect[e].width + FILTER_SIZE,
+                               css_pipe->rect[e].height +
+                               FILTER_SIZE);
+               }
+       }
+
+       /* Get a new obgrid only if a new obgrid is given, or none yet */
+       map = ipu3_css_pool_last(&css_pipe->pool.obgrid, 0);
+       if (!map->vaddr || (set_params && set_params->use.obgrid_param)) {
+               ipu3_css_pool_get(&css_pipe->pool.obgrid);
+               map = ipu3_css_pool_last(&css_pipe->pool.obgrid, 0);
+               obgrid = map->vaddr;
+
+               /* Configure optical black level grid (obgrid) */
+               if (set_params && set_params->use.obgrid_param)
+                       for (i = 0; i < obgrid_size / sizeof(*obgrid); i++)
+                               obgrid[i] = set_params->obgrid_param;
+               else
+                       memset(obgrid, 0, obgrid_size);
+       }
+
+       /* Configure parameter set info, queued to `queue_id' */
+
+       memset(param_set, 0, sizeof(*param_set));
+       map = ipu3_css_pool_last(&css_pipe->pool.acc, 0);
+       param_set->mem_map.acc_cluster_params_for_sp = map->daddr;
+
+       map = ipu3_css_pool_last(&css_pipe->pool.gdc, 0);
+       param_set->mem_map.dvs_6axis_params_y = map->daddr;
+
+       for (i = 0; i < stripes; i++) {
+               map = ipu3_css_pool_last(&css_pipe->pool.obgrid, 0);
+               param_set->mem_map.obgrid_tbl[i] =
+                       map->daddr + (obgrid_size / stripes) * i;
+       }
+
+       for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++) {
+               map = ipu3_css_pool_last(&css_pipe->pool.binary_params_p[m], 0);
+               param_set->mem_map.isp_mem_param[stage][m] = map->daddr;
+       }
+
+       /* Then queue the new parameter buffer */
+       map = ipu3_css_pool_last(&css_pipe->pool.parameter_set_info, 0);
+       r = ipu3_css_queue_data(css, queue_id, pipe, map->daddr);
+       if (r < 0)
+               goto fail;
+
+       r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe,
+                               IMGU_ABI_EVENT_BUFFER_ENQUEUED(pipe,
+                                                              queue_id));
+       if (r < 0)
+               goto fail_no_put;
+
+       /* Finally dequeue all old parameter buffers */
+
+       do {
+               u32 daddr;
+
+               r = ipu3_css_dequeue_data(css, queue_id, &daddr);
+               if (r == -EBUSY)
+                       break;
+               if (r)
+                       goto fail_no_put;
+               r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, pipe,
+                                       IMGU_ABI_EVENT_BUFFER_DEQUEUED
+                                       (queue_id));
+               if (r < 0) {
+                       dev_err(css->dev, "failed to queue parameter event\n");
+                       goto fail_no_put;
+               }
+       } while (1);
+
+       return 0;
+
+fail:
+       /*
+        * A failure, most likely the parameter queue was full.
+        * Return error but continue streaming. User can try submitting new
+        * parameters again later.
+        */
+
+       ipu3_css_pool_put(&css_pipe->pool.parameter_set_info);
+       if (acc)
+               ipu3_css_pool_put(&css_pipe->pool.acc);
+       if (gdc)
+               ipu3_css_pool_put(&css_pipe->pool.gdc);
+       if (obgrid)
+               ipu3_css_pool_put(&css_pipe->pool.obgrid);
+       if (vmem0)
+               ipu3_css_pool_put(
+                       &css_pipe->pool.binary_params_p
+                       [IMGU_ABI_MEM_ISP_VMEM0]);
+       if (dmem0)
+               ipu3_css_pool_put(
+                       &css_pipe->pool.binary_params_p
+                       [IMGU_ABI_MEM_ISP_DMEM0]);
+
+fail_no_put:
+       return r;
+}
+
+int ipu3_css_irq_ack(struct ipu3_css *css)
+{
+       static const int NUM_SWIRQS = 3;
+       struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]];
+       void __iomem *const base = css->base;
+       u32 irq_status[IMGU_IRQCTRL_NUM];
+       int i;
+
+       u32 imgu_status = readl(base + IMGU_REG_INT_STATUS);
+
+       writel(imgu_status, base + IMGU_REG_INT_STATUS);
+       for (i = 0; i < IMGU_IRQCTRL_NUM; i++)
+               irq_status[i] = readl(base + IMGU_REG_IRQCTRL_STATUS(i));
+
+       for (i = 0; i < NUM_SWIRQS; i++) {
+               if (irq_status[IMGU_IRQCTRL_SP0] & IMGU_IRQCTRL_IRQ_SW_PIN(i)) {
+                       /* SP SW interrupt */
+                       u32 cnt = readl(base + IMGU_REG_SP_DMEM_BASE(0) +
+                                       bi->info.sp.output);
+                       u32 val = readl(base + IMGU_REG_SP_DMEM_BASE(0) +
+                                       bi->info.sp.output + 4 + 4 * i);
+
+                       dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
+                               __func__, i, cnt, val);
+               }
+       }
+
+       for (i = IMGU_IRQCTRL_NUM - 1; i >= 0; i--)
+               if (irq_status[i]) {
+                       writel(irq_status[i], base + IMGU_REG_IRQCTRL_CLEAR(i));
+                       /* Wait for write to complete */
+                       readl(base + IMGU_REG_IRQCTRL_ENABLE(i));
+               }
+
+       dev_dbg(css->dev, "%s: imgu 0x%x main 0x%x sp0 0x%x sp1 0x%x\n",
+               __func__, imgu_status, irq_status[IMGU_IRQCTRL_MAIN],
+               irq_status[IMGU_IRQCTRL_SP0], irq_status[IMGU_IRQCTRL_SP1]);
+
+       if (!imgu_status && !irq_status[IMGU_IRQCTRL_MAIN])
+               return -ENOMSG;
+
+       return 0;
+}
diff --git a/drivers/staging/media/ipu3/ipu3-css.h b/drivers/staging/media/ipu3/ipu3-css.h
new file mode 100644 (file)
index 0000000..e88d60f
--- /dev/null
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_CSS_H
+#define __IPU3_CSS_H
+
+#include <linux/videodev2.h>
+#include <linux/types.h>
+
+#include "ipu3-abi.h"
+#include "ipu3-css-pool.h"
+
+/* 2 stages for split isp pipeline, 1 for scaling */
+#define IMGU_NUM_SP                    2
+#define IMGU_MAX_PIPELINE_NUM          20
+#define IMGU_MAX_PIPE_NUM              2
+
+/* For DVS etc., format FRAME_FMT_YUV420_16 */
+#define IPU3_CSS_AUX_FRAME_REF         0
+/* For temporal noise reduction DVS etc., format FRAME_FMT_YUV_LINE */
+#define IPU3_CSS_AUX_FRAME_TNR         1
+#define IPU3_CSS_AUX_FRAME_TYPES       2       /* REF and TNR */
+#define IPU3_CSS_AUX_FRAMES            2       /* 2 for REF and 2 for TNR */
+
+#define IPU3_CSS_QUEUE_IN              0
+#define IPU3_CSS_QUEUE_PARAMS          1
+#define IPU3_CSS_QUEUE_OUT             2
+#define IPU3_CSS_QUEUE_VF              3
+#define IPU3_CSS_QUEUE_STAT_3A         4
+#define IPU3_CSS_QUEUES                        5
+
+#define IPU3_CSS_RECT_EFFECTIVE                0       /* Effective resolution */
+#define IPU3_CSS_RECT_BDS              1       /* Resolution after BDS */
+#define IPU3_CSS_RECT_ENVELOPE         2       /* DVS envelope size */
+#define IPU3_CSS_RECT_GDC              3       /* gdc output res */
+#define IPU3_CSS_RECTS                 4       /* number of rects */
+
+#define IA_CSS_BINARY_MODE_PRIMARY     2
+#define IA_CSS_BINARY_MODE_VIDEO       3
+#define IPU3_CSS_DEFAULT_BINARY                3       /* default binary index */
+
+/*
+ * The pipe id type, distinguishes the kind of pipes that
+ * can be run in parallel.
+ */
+enum ipu3_css_pipe_id {
+       IPU3_CSS_PIPE_ID_PREVIEW,
+       IPU3_CSS_PIPE_ID_COPY,
+       IPU3_CSS_PIPE_ID_VIDEO,
+       IPU3_CSS_PIPE_ID_CAPTURE,
+       IPU3_CSS_PIPE_ID_YUVPP,
+       IPU3_CSS_PIPE_ID_ACC,
+       IPU3_CSS_PIPE_ID_NUM
+};
+
+struct ipu3_css_resolution {
+       u32 w;
+       u32 h;
+};
+
+enum ipu3_css_buffer_state {
+       IPU3_CSS_BUFFER_NEW,    /* Not yet queued */
+       IPU3_CSS_BUFFER_QUEUED, /* Queued, waiting to be filled */
+       IPU3_CSS_BUFFER_DONE,   /* Finished processing, removed from queue */
+       IPU3_CSS_BUFFER_FAILED, /* Was not processed, removed from queue */
+};
+
+struct ipu3_css_buffer {
+       /* Private fields: user doesn't touch */
+       dma_addr_t daddr;
+       unsigned int queue;
+       enum ipu3_css_buffer_state state;
+       struct list_head list;
+       u8 queue_pos;
+       unsigned int pipe;
+};
+
+struct ipu3_css_format {
+       u32 pixelformat;
+       enum v4l2_colorspace colorspace;
+       enum imgu_abi_frame_format frame_format;
+       enum imgu_abi_bayer_order bayer_order;
+       enum imgu_abi_osys_format osys_format;
+       enum imgu_abi_osys_tiling osys_tiling;
+       u32 bytesperpixel_num;  /* Bytes per pixel in first plane * 50 */
+       u8 bit_depth;           /* Effective bits per pixel */
+       u8 chroma_decim;        /* Chroma plane decimation, 0=no chroma plane */
+       u8 width_align;         /* Alignment requirement for width_pad */
+       u8 flags;
+};
+
+struct ipu3_css_queue {
+       union {
+               struct v4l2_pix_format_mplane mpix;
+               struct v4l2_meta_format meta;
+
+       } fmt;
+       const struct ipu3_css_format *css_fmt;
+       unsigned int width_pad;
+       struct list_head bufs;
+};
+
+struct ipu3_css_pipe {
+       enum ipu3_css_pipe_id pipe_id;
+       unsigned int bindex;
+
+       struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
+       struct v4l2_rect rect[IPU3_CSS_RECTS];
+
+       bool vf_output_en;
+       /* Protect access to queue[IPU3_CSS_QUEUES] */
+       spinlock_t qlock;
+
+       /* Data structures shared with IMGU and driver, always allocated */
+       struct ipu3_css_map sp_ddr_ptrs;
+       struct ipu3_css_map xmem_sp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
+                                           [IMGU_ABI_MAX_STAGES];
+       struct ipu3_css_map xmem_isp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
+                                           [IMGU_ABI_MAX_STAGES];
+
+       /*
+        * Data structures shared with IMGU and driver, binary specific.
+        * PARAM_CLASS_CONFIG and PARAM_CLASS_STATE parameters.
+        */
+       struct ipu3_css_map binary_params_cs[IMGU_ABI_PARAM_CLASS_NUM - 1]
+                                           [IMGU_ABI_NUM_MEMORIES];
+
+       struct {
+               struct ipu3_css_map mem[IPU3_CSS_AUX_FRAMES];
+               unsigned int width;
+               unsigned int height;
+               unsigned int bytesperline;
+               unsigned int bytesperpixel;
+       } aux_frames[IPU3_CSS_AUX_FRAME_TYPES];
+
+       struct {
+               struct ipu3_css_pool parameter_set_info;
+               struct ipu3_css_pool acc;
+               struct ipu3_css_pool gdc;
+               struct ipu3_css_pool obgrid;
+               /* PARAM_CLASS_PARAM parameters for binding while streaming */
+               struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
+       } pool;
+
+       struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
+                                   [IMGU_ABI_HOST2SP_BUFQ_SIZE];
+};
+
+/* IPU3 Camera Sub System structure */
+struct ipu3_css {
+       struct device *dev;
+       void __iomem *base;
+       const struct firmware *fw;
+       struct imgu_fw_header *fwp;
+       int iomem_length;
+       int fw_bl, fw_sp[IMGU_NUM_SP];  /* Indices of bl and SP binaries */
+       struct ipu3_css_map *binary;    /* fw binaries mapped to device */
+       bool streaming;         /* true when streaming is enabled */
+
+       struct ipu3_css_pipe pipes[IMGU_MAX_PIPE_NUM];
+       struct ipu3_css_map xmem_sp_group_ptrs;
+
+       /* enabled pipe(s) */
+       DECLARE_BITMAP(enabled_pipes, IMGU_MAX_PIPE_NUM);
+};
+
+/******************* css v4l *******************/
+int ipu3_css_init(struct device *dev, struct ipu3_css *css,
+                 void __iomem *base, int length);
+void ipu3_css_cleanup(struct ipu3_css *css);
+int ipu3_css_fmt_try(struct ipu3_css *css,
+                    struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+                    struct v4l2_rect *rects[IPU3_CSS_RECTS],
+                    unsigned int pipe);
+int ipu3_css_fmt_set(struct ipu3_css *css,
+                    struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+                    struct v4l2_rect *rects[IPU3_CSS_RECTS],
+                    unsigned int pipe);
+int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
+int ipu3_css_buf_queue(struct ipu3_css *css, unsigned int pipe,
+                      struct ipu3_css_buffer *b);
+struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
+int ipu3_css_start_streaming(struct ipu3_css *css);
+void ipu3_css_stop_streaming(struct ipu3_css *css);
+bool ipu3_css_queue_empty(struct ipu3_css *css);
+bool ipu3_css_is_streaming(struct ipu3_css *css);
+bool ipu3_css_pipe_queue_empty(struct ipu3_css *css, unsigned int pipe);
+
+/******************* css hw *******************/
+int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
+void ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
+int ipu3_css_irq_ack(struct ipu3_css *css);
+
+/******************* set parameters ************/
+int ipu3_css_set_parameters(struct ipu3_css *css, unsigned int pipe,
+                           struct ipu3_uapi_params *set_params);
+
+/******************* auxiliary helpers *******************/
+static inline enum ipu3_css_buffer_state
+ipu3_css_buf_state(struct ipu3_css_buffer *b)
+{
+       return b->state;
+}
+
+/* Initialize given buffer. May be called several times. */
+static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
+                                    unsigned int queue, dma_addr_t daddr)
+{
+       b->state = IPU3_CSS_BUFFER_NEW;
+       b->queue = queue;
+       b->daddr = daddr;
+}
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.c b/drivers/staging/media/ipu3/ipu3-dmamap.c
new file mode 100644 (file)
index 0000000..93a393d
--- /dev/null
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Intel Corporation
+ * Copyright 2018 Google LLC.
+ *
+ * Author: Tomasz Figa <tfiga@chromium.org>
+ * Author: Yong Zhi <yong.zhi@intel.com>
+ */
+
+#include <linux/vmalloc.h>
+
+#include "ipu3.h"
+#include "ipu3-css-pool.h"
+#include "ipu3-mmu.h"
+
+/*
+ * Free a buffer allocated by ipu3_dmamap_alloc_buffer()
+ */
+static void ipu3_dmamap_free_buffer(struct page **pages,
+                                   size_t size)
+{
+       int count = size >> PAGE_SHIFT;
+
+       while (count--)
+               __free_page(pages[count]);
+       kvfree(pages);
+}
+
+/*
+ * Based on the implementation of __iommu_dma_alloc_pages()
+ * defined in drivers/iommu/dma-iommu.c
+ */
+static struct page **ipu3_dmamap_alloc_buffer(size_t size,
+                                             unsigned long order_mask,
+                                             gfp_t gfp)
+{
+       struct page **pages;
+       unsigned int i = 0, count = size >> PAGE_SHIFT;
+       const gfp_t high_order_gfp = __GFP_NOWARN | __GFP_NORETRY;
+
+       /* Allocate mem for array of page ptrs */
+       pages = kvmalloc_array(count, sizeof(*pages), GFP_KERNEL);
+
+       if (!pages)
+               return NULL;
+
+       order_mask &= (2U << MAX_ORDER) - 1;
+       if (!order_mask)
+               return NULL;
+
+       gfp |= __GFP_HIGHMEM | __GFP_ZERO;
+
+       while (count) {
+               struct page *page = NULL;
+               unsigned int order_size;
+
+               for (order_mask &= (2U << __fls(count)) - 1;
+                    order_mask; order_mask &= ~order_size) {
+                       unsigned int order = __fls(order_mask);
+
+                       order_size = 1U << order;
+                       page = alloc_pages((order_mask - order_size) ?
+                                          gfp | high_order_gfp : gfp, order);
+                       if (!page)
+                               continue;
+                       if (!order)
+                               break;
+                       if (!PageCompound(page)) {
+                               split_page(page, order);
+                               break;
+                       }
+
+                       __free_pages(page, order);
+               }
+               if (!page) {
+                       ipu3_dmamap_free_buffer(pages, i << PAGE_SHIFT);
+                       return NULL;
+               }
+               count -= order_size;
+               while (order_size--)
+                       pages[i++] = page++;
+       }
+
+       return pages;
+}
+
+/**
+ * ipu3_dmamap_alloc - allocate and map a buffer into KVA
+ * @imgu: struct device pointer
+ * @map: struct to store mapping variables
+ * @len: size required
+ *
+ * Returns:
+ *  KVA on success
+ *  %NULL on failure
+ */
+void *ipu3_dmamap_alloc(struct imgu_device *imgu, struct ipu3_css_map *map,
+                       size_t len)
+{
+       unsigned long shift = iova_shift(&imgu->iova_domain);
+       unsigned int alloc_sizes = imgu->mmu->pgsize_bitmap;
+       struct device *dev = &imgu->pci_dev->dev;
+       size_t size = PAGE_ALIGN(len);
+       struct page **pages;
+       dma_addr_t iovaddr;
+       struct iova *iova;
+       int i, rval;
+
+       dev_dbg(dev, "%s: allocating %zu\n", __func__, size);
+
+       iova = alloc_iova(&imgu->iova_domain, size >> shift,
+                         imgu->mmu->aperture_end >> shift, 0);
+       if (!iova)
+               return NULL;
+
+       pages = ipu3_dmamap_alloc_buffer(size, alloc_sizes >> PAGE_SHIFT,
+                                        GFP_KERNEL);
+       if (!pages)
+               goto out_free_iova;
+
+       /* Call IOMMU driver to setup pgt */
+       iovaddr = iova_dma_addr(&imgu->iova_domain, iova);
+       for (i = 0; i < size / PAGE_SIZE; ++i) {
+               rval = ipu3_mmu_map(imgu->mmu, iovaddr,
+                                   page_to_phys(pages[i]), PAGE_SIZE);
+               if (rval)
+                       goto out_unmap;
+
+               iovaddr += PAGE_SIZE;
+       }
+
+       /* Now grab a virtual region */
+       map->vma = __get_vm_area(size, VM_USERMAP, VMALLOC_START, VMALLOC_END);
+       if (!map->vma)
+               goto out_unmap;
+
+       map->vma->pages = pages;
+       /* And map it in KVA */
+       if (map_vm_area(map->vma, PAGE_KERNEL, pages))
+               goto out_vunmap;
+
+       map->size = size;
+       map->daddr = iova_dma_addr(&imgu->iova_domain, iova);
+       map->vaddr = map->vma->addr;
+
+       dev_dbg(dev, "%s: allocated %zu @ IOVA %pad @ VA %p\n", __func__,
+               size, &map->daddr, map->vma->addr);
+
+       return map->vma->addr;
+
+out_vunmap:
+       vunmap(map->vma->addr);
+
+out_unmap:
+       ipu3_dmamap_free_buffer(pages, size);
+       ipu3_mmu_unmap(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
+                      i * PAGE_SIZE);
+       map->vma = NULL;
+
+out_free_iova:
+       __free_iova(&imgu->iova_domain, iova);
+
+       return NULL;
+}
+
+void ipu3_dmamap_unmap(struct imgu_device *imgu, struct ipu3_css_map *map)
+{
+       struct iova *iova;
+
+       iova = find_iova(&imgu->iova_domain,
+                        iova_pfn(&imgu->iova_domain, map->daddr));
+       if (WARN_ON(!iova))
+               return;
+
+       ipu3_mmu_unmap(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
+                      iova_size(iova) << iova_shift(&imgu->iova_domain));
+
+       __free_iova(&imgu->iova_domain, iova);
+}
+
+/*
+ * Counterpart of ipu3_dmamap_alloc
+ */
+void ipu3_dmamap_free(struct imgu_device *imgu, struct ipu3_css_map *map)
+{
+       struct vm_struct *area = map->vma;
+
+       dev_dbg(&imgu->pci_dev->dev, "%s: freeing %zu @ IOVA %pad @ VA %p\n",
+               __func__, map->size, &map->daddr, map->vaddr);
+
+       if (!map->vaddr)
+               return;
+
+       ipu3_dmamap_unmap(imgu, map);
+
+       if (WARN_ON(!area) || WARN_ON(!area->pages))
+               return;
+
+       ipu3_dmamap_free_buffer(area->pages, map->size);
+       vunmap(map->vaddr);
+       map->vaddr = NULL;
+}
+
+int ipu3_dmamap_map_sg(struct imgu_device *imgu, struct scatterlist *sglist,
+                      int nents, struct ipu3_css_map *map)
+{
+       unsigned long shift = iova_shift(&imgu->iova_domain);
+       struct scatterlist *sg;
+       struct iova *iova;
+       size_t size = 0;
+       int i;
+
+       for_each_sg(sglist, sg, nents, i) {
+               if (sg->offset)
+                       return -EINVAL;
+
+               if (i != nents - 1 && !PAGE_ALIGNED(sg->length))
+                       return -EINVAL;
+
+               size += sg->length;
+       }
+
+       size = iova_align(&imgu->iova_domain, size);
+       dev_dbg(&imgu->pci_dev->dev, "dmamap: mapping sg %d entries, %zu pages\n",
+               nents, size >> shift);
+
+       iova = alloc_iova(&imgu->iova_domain, size >> shift,
+                         imgu->mmu->aperture_end >> shift, 0);
+       if (!iova)
+               return -ENOMEM;
+
+       dev_dbg(&imgu->pci_dev->dev, "dmamap: iova low pfn %lu, high pfn %lu\n",
+               iova->pfn_lo, iova->pfn_hi);
+
+       if (ipu3_mmu_map_sg(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
+                           sglist, nents) < size)
+               goto out_fail;
+
+       memset(map, 0, sizeof(*map));
+       map->daddr = iova_dma_addr(&imgu->iova_domain, iova);
+       map->size = size;
+
+       return 0;
+
+out_fail:
+       __free_iova(&imgu->iova_domain, iova);
+
+       return -EFAULT;
+}
+
+int ipu3_dmamap_init(struct imgu_device *imgu)
+{
+       unsigned long order, base_pfn;
+       int ret = iova_cache_get();
+
+       if (ret)
+               return ret;
+
+       order = __ffs(imgu->mmu->pgsize_bitmap);
+       base_pfn = max_t(unsigned long, 1, imgu->mmu->aperture_start >> order);
+       init_iova_domain(&imgu->iova_domain, 1UL << order, base_pfn);
+
+       return 0;
+}
+
+void ipu3_dmamap_exit(struct imgu_device *imgu)
+{
+       put_iova_domain(&imgu->iova_domain);
+       iova_cache_put();
+}
diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.h b/drivers/staging/media/ipu3/ipu3-dmamap.h
new file mode 100644 (file)
index 0000000..b9d224a
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+/* Copyright 2018 Google LLC. */
+
+#ifndef __IPU3_DMAMAP_H
+#define __IPU3_DMAMAP_H
+
+struct imgu_device;
+struct scatterlist;
+
+void *ipu3_dmamap_alloc(struct imgu_device *imgu, struct ipu3_css_map *map,
+                       size_t len);
+void ipu3_dmamap_free(struct imgu_device *imgu, struct ipu3_css_map *map);
+
+int ipu3_dmamap_map_sg(struct imgu_device *imgu, struct scatterlist *sglist,
+                      int nents, struct ipu3_css_map *map);
+void ipu3_dmamap_unmap(struct imgu_device *imgu, struct ipu3_css_map *map);
+
+int ipu3_dmamap_init(struct imgu_device *imgu);
+void ipu3_dmamap_exit(struct imgu_device *imgu);
+
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-mmu.c b/drivers/staging/media/ipu3/ipu3-mmu.c
new file mode 100644 (file)
index 0000000..b9f2095
--- /dev/null
@@ -0,0 +1,561 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Intel Corporation.
+ * Copyright 2018 Google LLC.
+ *
+ * Author: Tuukka Toivonen <tuukka.toivonen@intel.com>
+ * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
+ * Author: Samu Onkalo <samu.onkalo@intel.com>
+ * Author: Tomasz Figa <tfiga@chromium.org>
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/set_memory.h>
+
+#include "ipu3-mmu.h"
+
+#define IPU3_PAGE_SHIFT                12
+#define IPU3_PAGE_SIZE         (1UL << IPU3_PAGE_SHIFT)
+
+#define IPU3_PT_BITS           10
+#define IPU3_PT_PTES           (1UL << IPU3_PT_BITS)
+#define IPU3_PT_SIZE           (IPU3_PT_PTES << 2)
+#define IPU3_PT_ORDER          (IPU3_PT_SIZE >> PAGE_SHIFT)
+
+#define IPU3_ADDR2PTE(addr)    ((addr) >> IPU3_PAGE_SHIFT)
+#define IPU3_PTE2ADDR(pte)     ((phys_addr_t)(pte) << IPU3_PAGE_SHIFT)
+
+#define IPU3_L2PT_SHIFT                IPU3_PT_BITS
+#define IPU3_L2PT_MASK         ((1UL << IPU3_L2PT_SHIFT) - 1)
+
+#define IPU3_L1PT_SHIFT                IPU3_PT_BITS
+#define IPU3_L1PT_MASK         ((1UL << IPU3_L1PT_SHIFT) - 1)
+
+#define IPU3_MMU_ADDRESS_BITS  (IPU3_PAGE_SHIFT + \
+                                IPU3_L2PT_SHIFT + \
+                                IPU3_L1PT_SHIFT)
+
+#define IMGU_REG_BASE          0x4000
+#define REG_TLB_INVALIDATE     (IMGU_REG_BASE + 0x300)
+#define TLB_INVALIDATE         1
+#define REG_L1_PHYS            (IMGU_REG_BASE + 0x304) /* 27-bit pfn */
+#define REG_GP_HALT            (IMGU_REG_BASE + 0x5dc)
+#define REG_GP_HALTED          (IMGU_REG_BASE + 0x5e0)
+
+struct ipu3_mmu {
+       struct device *dev;
+       void __iomem *base;
+       /* protect access to l2pts, l1pt */
+       spinlock_t lock;
+
+       void *dummy_page;
+       u32 dummy_page_pteval;
+
+       u32 *dummy_l2pt;
+       u32 dummy_l2pt_pteval;
+
+       u32 **l2pts;
+       u32 *l1pt;
+
+       struct ipu3_mmu_info geometry;
+};
+
+static inline struct ipu3_mmu *to_ipu3_mmu(struct ipu3_mmu_info *info)
+{
+       return container_of(info, struct ipu3_mmu, geometry);
+}
+
+/**
+ * ipu3_mmu_tlb_invalidate - invalidate translation look-aside buffer
+ * @mmu: MMU to perform the invalidate operation on
+ *
+ * This function invalidates the whole TLB. Must be called when the hardware
+ * is powered on.
+ */
+static void ipu3_mmu_tlb_invalidate(struct ipu3_mmu *mmu)
+{
+       writel(TLB_INVALIDATE, mmu->base + REG_TLB_INVALIDATE);
+}
+
+static void call_if_ipu3_is_powered(struct ipu3_mmu *mmu,
+                                   void (*func)(struct ipu3_mmu *mmu))
+{
+       if (!pm_runtime_get_if_in_use(mmu->dev))
+               return;
+
+       func(mmu);
+       pm_runtime_put(mmu->dev);
+}
+
+/**
+ * ipu3_mmu_set_halt - set CIO gate halt bit
+ * @mmu: MMU to set the CIO gate bit in.
+ * @halt: Desired state of the gate bit.
+ *
+ * This function sets the CIO gate bit that controls whether external memory
+ * accesses are allowed. Must be called when the hardware is powered on.
+ */
+static void ipu3_mmu_set_halt(struct ipu3_mmu *mmu, bool halt)
+{
+       int ret;
+       u32 val;
+
+       writel(halt, mmu->base + REG_GP_HALT);
+       ret = readl_poll_timeout(mmu->base + REG_GP_HALTED,
+                                val, (val & 1) == halt, 1000, 100000);
+
+       if (ret)
+               dev_err(mmu->dev, "failed to %s CIO gate halt\n",
+                       halt ? "set" : "clear");
+}
+
+/**
+ * ipu3_mmu_alloc_page_table - allocate a pre-filled page table
+ * @pteval: Value to initialize for page table entries with.
+ *
+ * Return: Pointer to allocated page table or NULL on failure.
+ */
+static u32 *ipu3_mmu_alloc_page_table(u32 pteval)
+{
+       u32 *pt;
+       int pte;
+
+       pt = (u32 *)__get_free_page(GFP_KERNEL);
+       if (!pt)
+               return NULL;
+
+       for (pte = 0; pte < IPU3_PT_PTES; pte++)
+               pt[pte] = pteval;
+
+       set_memory_uc((unsigned long int)pt, IPU3_PT_ORDER);
+
+       return pt;
+}
+
+/**
+ * ipu3_mmu_free_page_table - free page table
+ * @pt: Page table to free.
+ */
+static void ipu3_mmu_free_page_table(u32 *pt)
+{
+       set_memory_wb((unsigned long int)pt, IPU3_PT_ORDER);
+       free_page((unsigned long)pt);
+}
+
+/**
+ * address_to_pte_idx - split IOVA into L1 and L2 page table indices
+ * @iova: IOVA to split.
+ * @l1pt_idx: Output for the L1 page table index.
+ * @l2pt_idx: Output for the L2 page index.
+ */
+static inline void address_to_pte_idx(unsigned long iova, u32 *l1pt_idx,
+                                     u32 *l2pt_idx)
+{
+       iova >>= IPU3_PAGE_SHIFT;
+
+       if (l2pt_idx)
+               *l2pt_idx = iova & IPU3_L2PT_MASK;
+
+       iova >>= IPU3_L2PT_SHIFT;
+
+       if (l1pt_idx)
+               *l1pt_idx = iova & IPU3_L1PT_MASK;
+}
+
+static u32 *ipu3_mmu_get_l2pt(struct ipu3_mmu *mmu, u32 l1pt_idx)
+{
+       unsigned long flags;
+       u32 *l2pt, *new_l2pt;
+       u32 pteval;
+
+       spin_lock_irqsave(&mmu->lock, flags);
+
+       l2pt = mmu->l2pts[l1pt_idx];
+       if (l2pt)
+               goto done;
+
+       spin_unlock_irqrestore(&mmu->lock, flags);
+
+       new_l2pt = ipu3_mmu_alloc_page_table(mmu->dummy_page_pteval);
+       if (!new_l2pt)
+               return NULL;
+
+       spin_lock_irqsave(&mmu->lock, flags);
+
+       dev_dbg(mmu->dev, "allocated page table %p for l1pt_idx %u\n",
+               new_l2pt, l1pt_idx);
+
+       l2pt = mmu->l2pts[l1pt_idx];
+       if (l2pt) {
+               ipu3_mmu_free_page_table(new_l2pt);
+               goto done;
+       }
+
+       l2pt = new_l2pt;
+       mmu->l2pts[l1pt_idx] = new_l2pt;
+
+       pteval = IPU3_ADDR2PTE(virt_to_phys(new_l2pt));
+       mmu->l1pt[l1pt_idx] = pteval;
+
+done:
+       spin_unlock_irqrestore(&mmu->lock, flags);
+       return l2pt;
+}
+
+static int __ipu3_mmu_map(struct ipu3_mmu *mmu, unsigned long iova,
+                         phys_addr_t paddr)
+{
+       u32 l1pt_idx, l2pt_idx;
+       unsigned long flags;
+       u32 *l2pt;
+
+       if (!mmu)
+               return -ENODEV;
+
+       address_to_pte_idx(iova, &l1pt_idx, &l2pt_idx);
+
+       l2pt = ipu3_mmu_get_l2pt(mmu, l1pt_idx);
+       if (!l2pt)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&mmu->lock, flags);
+
+       if (l2pt[l2pt_idx] != mmu->dummy_page_pteval) {
+               spin_unlock_irqrestore(&mmu->lock, flags);
+               return -EBUSY;
+       }
+
+       l2pt[l2pt_idx] = IPU3_ADDR2PTE(paddr);
+
+       spin_unlock_irqrestore(&mmu->lock, flags);
+
+       return 0;
+}
+
+/**
+ * The following four functions are implemented based on iommu.c
+ * drivers/iommu/iommu.c/iommu_pgsize().
+ */
+static size_t ipu3_mmu_pgsize(unsigned long pgsize_bitmap,
+                             unsigned long addr_merge, size_t size)
+{
+       unsigned int pgsize_idx;
+       size_t pgsize;
+
+       /* Max page size that still fits into 'size' */
+       pgsize_idx = __fls(size);
+
+       /* need to consider alignment requirements ? */
+       if (likely(addr_merge)) {
+               /* Max page size allowed by address */
+               unsigned int align_pgsize_idx = __ffs(addr_merge);
+
+               pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+       }
+
+       /* build a mask of acceptable page sizes */
+       pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+       /* throw away page sizes not supported by the hardware */
+       pgsize &= pgsize_bitmap;
+
+       /* make sure we're still sane */
+       WARN_ON(!pgsize);
+
+       /* pick the biggest page */
+       pgsize_idx = __fls(pgsize);
+       pgsize = 1UL << pgsize_idx;
+
+       return pgsize;
+}
+
+/* drivers/iommu/iommu.c/iommu_map() */
+int ipu3_mmu_map(struct ipu3_mmu_info *info, unsigned long iova,
+                phys_addr_t paddr, size_t size)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+       unsigned int min_pagesz;
+       int ret = 0;
+
+       /* find out the minimum page size supported */
+       min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
+
+       /*
+        * both the virtual address and the physical one, as well as
+        * the size of the mapping, must be aligned (at least) to the
+        * size of the smallest page supported by the hardware
+        */
+       if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
+               dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n",
+                       iova, &paddr, size, min_pagesz);
+               return -EINVAL;
+       }
+
+       dev_dbg(mmu->dev, "map: iova 0x%lx pa %pa size 0x%zx\n",
+               iova, &paddr, size);
+
+       while (size) {
+               size_t pgsize = ipu3_mmu_pgsize(mmu->geometry.pgsize_bitmap,
+                                               iova | paddr, size);
+
+               dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
+                       iova, &paddr, pgsize);
+
+               ret = __ipu3_mmu_map(mmu, iova, paddr);
+               if (ret)
+                       break;
+
+               iova += pgsize;
+               paddr += pgsize;
+               size -= pgsize;
+       }
+
+       call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
+
+       return ret;
+}
+
+/* drivers/iommu/iommu.c/default_iommu_map_sg() */
+size_t ipu3_mmu_map_sg(struct ipu3_mmu_info *info, unsigned long iova,
+                      struct scatterlist *sg, unsigned int nents)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+       struct scatterlist *s;
+       size_t s_length, mapped = 0;
+       unsigned int i, min_pagesz;
+       int ret;
+
+       min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
+
+       for_each_sg(sg, s, nents, i) {
+               phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
+
+               s_length = s->length;
+
+               if (!IS_ALIGNED(s->offset, min_pagesz))
+                       goto out_err;
+
+               /* must be min_pagesz aligned to be mapped singlely */
+               if (i == nents - 1 && !IS_ALIGNED(s->length, min_pagesz))
+                       s_length = PAGE_ALIGN(s->length);
+
+               ret = ipu3_mmu_map(info, iova + mapped, phys, s_length);
+               if (ret)
+                       goto out_err;
+
+               mapped += s_length;
+       }
+
+       call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
+
+       return mapped;
+
+out_err:
+       /* undo mappings already done */
+       ipu3_mmu_unmap(info, iova, mapped);
+
+       return 0;
+}
+
+static size_t __ipu3_mmu_unmap(struct ipu3_mmu *mmu,
+                              unsigned long iova, size_t size)
+{
+       u32 l1pt_idx, l2pt_idx;
+       unsigned long flags;
+       size_t unmap = size;
+       u32 *l2pt;
+
+       if (!mmu)
+               return 0;
+
+       address_to_pte_idx(iova, &l1pt_idx, &l2pt_idx);
+
+       spin_lock_irqsave(&mmu->lock, flags);
+
+       l2pt = mmu->l2pts[l1pt_idx];
+       if (!l2pt) {
+               spin_unlock_irqrestore(&mmu->lock, flags);
+               return 0;
+       }
+
+       if (l2pt[l2pt_idx] == mmu->dummy_page_pteval)
+               unmap = 0;
+
+       l2pt[l2pt_idx] = mmu->dummy_page_pteval;
+
+       spin_unlock_irqrestore(&mmu->lock, flags);
+
+       return unmap;
+}
+
+/* drivers/iommu/iommu.c/iommu_unmap() */
+size_t ipu3_mmu_unmap(struct ipu3_mmu_info *info, unsigned long iova,
+                     size_t size)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+       size_t unmapped_page, unmapped = 0;
+       unsigned int min_pagesz;
+
+       /* find out the minimum page size supported */
+       min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
+
+       /*
+        * The virtual address, as well as the size of the mapping, must be
+        * aligned (at least) to the size of the smallest page supported
+        * by the hardware
+        */
+       if (!IS_ALIGNED(iova | size, min_pagesz)) {
+               dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
+                       iova, size, min_pagesz);
+               return -EINVAL;
+       }
+
+       dev_dbg(mmu->dev, "unmap this: iova 0x%lx size 0x%zx\n", iova, size);
+
+       /*
+        * Keep iterating until we either unmap 'size' bytes (or more)
+        * or we hit an area that isn't mapped.
+        */
+       while (unmapped < size) {
+               size_t pgsize = ipu3_mmu_pgsize(mmu->geometry.pgsize_bitmap,
+                                               iova, size - unmapped);
+
+               unmapped_page = __ipu3_mmu_unmap(mmu, iova, pgsize);
+               if (!unmapped_page)
+                       break;
+
+               dev_dbg(mmu->dev, "unmapped: iova 0x%lx size 0x%zx\n",
+                       iova, unmapped_page);
+
+               iova += unmapped_page;
+               unmapped += unmapped_page;
+       }
+
+       call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
+
+       return unmapped;
+}
+
+/**
+ * ipu3_mmu_init() - initialize IPU3 MMU block
+ * @base:      IOMEM base of hardware registers.
+ *
+ * Return: Pointer to IPU3 MMU private data pointer or ERR_PTR() on error.
+ */
+struct ipu3_mmu_info *ipu3_mmu_init(struct device *parent, void __iomem *base)
+{
+       struct ipu3_mmu *mmu;
+       u32 pteval;
+
+       mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
+       if (!mmu)
+               return ERR_PTR(-ENOMEM);
+
+       mmu->dev = parent;
+       mmu->base = base;
+       spin_lock_init(&mmu->lock);
+
+       /* Disallow external memory access when having no valid page tables. */
+       ipu3_mmu_set_halt(mmu, true);
+
+       /*
+        * The MMU does not have a "valid" bit, so we have to use a dummy
+        * page for invalid entries.
+        */
+       mmu->dummy_page = (void *)__get_free_page(GFP_KERNEL);
+       if (!mmu->dummy_page)
+               goto fail_group;
+       pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->dummy_page));
+       mmu->dummy_page_pteval = pteval;
+
+       /*
+        * Allocate a dummy L2 page table with all entries pointing to
+        * the dummy page.
+        */
+       mmu->dummy_l2pt = ipu3_mmu_alloc_page_table(pteval);
+       if (!mmu->dummy_l2pt)
+               goto fail_dummy_page;
+       pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->dummy_l2pt));
+       mmu->dummy_l2pt_pteval = pteval;
+
+       /*
+        * Allocate the array of L2PT CPU pointers, initialized to zero,
+        * which means the dummy L2PT allocated above.
+        */
+       mmu->l2pts = vzalloc(IPU3_PT_PTES * sizeof(*mmu->l2pts));
+       if (!mmu->l2pts)
+               goto fail_l2pt;
+
+       /* Allocate the L1 page table. */
+       mmu->l1pt = ipu3_mmu_alloc_page_table(mmu->dummy_l2pt_pteval);
+       if (!mmu->l1pt)
+               goto fail_l2pts;
+
+       pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->l1pt));
+       writel(pteval, mmu->base + REG_L1_PHYS);
+       ipu3_mmu_tlb_invalidate(mmu);
+       ipu3_mmu_set_halt(mmu, false);
+
+       mmu->geometry.aperture_start = 0;
+       mmu->geometry.aperture_end = DMA_BIT_MASK(IPU3_MMU_ADDRESS_BITS);
+       mmu->geometry.pgsize_bitmap = IPU3_PAGE_SIZE;
+
+       return &mmu->geometry;
+
+fail_l2pts:
+       vfree(mmu->l2pts);
+fail_l2pt:
+       ipu3_mmu_free_page_table(mmu->dummy_l2pt);
+fail_dummy_page:
+       free_page((unsigned long)mmu->dummy_page);
+fail_group:
+       kfree(mmu);
+
+       return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * ipu3_mmu_exit() - clean up IPU3 MMU block
+ * @mmu: IPU3 MMU private data
+ */
+void ipu3_mmu_exit(struct ipu3_mmu_info *info)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+
+       /* We are going to free our page tables, no more memory access. */
+       ipu3_mmu_set_halt(mmu, true);
+       ipu3_mmu_tlb_invalidate(mmu);
+
+       ipu3_mmu_free_page_table(mmu->l1pt);
+       vfree(mmu->l2pts);
+       ipu3_mmu_free_page_table(mmu->dummy_l2pt);
+       free_page((unsigned long)mmu->dummy_page);
+       kfree(mmu);
+}
+
+void ipu3_mmu_suspend(struct ipu3_mmu_info *info)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+
+       ipu3_mmu_set_halt(mmu, true);
+}
+
+void ipu3_mmu_resume(struct ipu3_mmu_info *info)
+{
+       struct ipu3_mmu *mmu = to_ipu3_mmu(info);
+       u32 pteval;
+
+       ipu3_mmu_set_halt(mmu, true);
+
+       pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->l1pt));
+       writel(pteval, mmu->base + REG_L1_PHYS);
+
+       ipu3_mmu_tlb_invalidate(mmu);
+       ipu3_mmu_set_halt(mmu, false);
+}
diff --git a/drivers/staging/media/ipu3/ipu3-mmu.h b/drivers/staging/media/ipu3/ipu3-mmu.h
new file mode 100644 (file)
index 0000000..8fe63b4
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+/* Copyright 2018 Google LLC. */
+
+#ifndef __IPU3_MMU_H
+#define __IPU3_MMU_H
+
+/**
+ * struct ipu3_mmu_info - Describes mmu geometry
+ *
+ * @aperture_start:    First address that can be mapped
+ * @aperture_end:      Last address that can be mapped
+ * @pgsize_bitmap:     Bitmap of page sizes in use
+ */
+struct ipu3_mmu_info {
+       dma_addr_t aperture_start;
+       dma_addr_t aperture_end;
+       unsigned long pgsize_bitmap;
+};
+
+struct device;
+struct scatterlist;
+
+struct ipu3_mmu_info *ipu3_mmu_init(struct device *parent, void __iomem *base);
+void ipu3_mmu_exit(struct ipu3_mmu_info *info);
+void ipu3_mmu_suspend(struct ipu3_mmu_info *info);
+void ipu3_mmu_resume(struct ipu3_mmu_info *info);
+
+int ipu3_mmu_map(struct ipu3_mmu_info *info, unsigned long iova,
+                phys_addr_t paddr, size_t size);
+size_t ipu3_mmu_unmap(struct ipu3_mmu_info *info, unsigned long iova,
+                     size_t size);
+size_t ipu3_mmu_map_sg(struct ipu3_mmu_info *info, unsigned long iova,
+                      struct scatterlist *sg, unsigned int nents);
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-tables.c b/drivers/staging/media/ipu3/ipu3-tables.c
new file mode 100644 (file)
index 0000000..3345179
--- /dev/null
@@ -0,0 +1,9609 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include "ipu3-tables.h"
+
+#define X                                      0       /*  Don't care value */
+
+const struct ipu3_css_bds_config
+                       ipu3_css_bds_configs[IMGU_BDS_CONFIG_LEN] = { {
+       /* Scale factor 32 / (32 + 0) = 1 */
+       .hor_phase_arr = {
+               .even = { { 0, 0, 64, 6, 0, 0, 0 } },
+               .odd = { { 0, 0, 64, 6, 0, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 0, 64, 6, 0, 0, 0 } },
+               .odd = { { 0, 0, 64, 6, 0, 0, 0 } } },
+       .ptrn_arr = { { 0x3 } },
+       .sample_patrn_length = 2,
+       .hor_ds_en = 0,
+       .ver_ds_en = 0
+}, {
+       /* Scale factor 32 / (32 + 1) = 0.969697 */
+       .hor_phase_arr = {
+               .even = { { 0, 3, 122, 7, 3, 0, 0 },
+                        { 0, 0, 122, 7, 7, -1, 0 },
+                        { 0, -3, 122, 7, 10, -1, 0 },
+                        { 0, -5, 121, 7, 14, -2, 0 },
+                        { 0, -7, 120, 7, 18, -3, 0 },
+                        { 0, -9, 118, 7, 23, -4, 0 },
+                        { 0, -11, 116, 7, 27, -4, 0 },
+                        { 0, -12, 113, 7, 32, -5, 0 },
+                        { 0, -13, 110, 7, 37, -6, 0 },
+                        { 0, -14, 107, 7, 42, -7, 0 },
+                        { 0, -14, 103, 7, 47, -8, 0 },
+                        { 0, -15, 100, 7, 52, -9, 0 },
+                        { 0, -15, 96, 7, 57, -10, 0 },
+                        { 0, -15, 92, 7, 62, -11, 0 },
+                        { 0, -14, 86, 7, 68, -12, 0 },
+                        { 0, -14, 82, 7, 73, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 73, 7, 82, -14, 0 },
+                        { 0, -12, 68, 7, 86, -14, 0 },
+                        { 0, -11, 62, 7, 92, -15, 0 },
+                        { 0, -10, 57, 7, 96, -15, 0 },
+                        { 0, -9, 52, 7, 100, -15, 0 },
+                        { 0, -8, 47, 7, 103, -14, 0 },
+                        { 0, -7, 42, 7, 107, -14, 0 },
+                        { 0, -6, 37, 7, 110, -13, 0 },
+                        { 0, -5, 32, 7, 113, -12, 0 },
+                        { 0, -4, 27, 7, 116, -11, 0 },
+                        { 0, -4, 23, 7, 118, -9, 0 },
+                        { 0, -3, 18, 7, 120, -7, 0 },
+                        { 0, -2, 14, 7, 121, -5, 0 },
+                        { 0, -1, 10, 7, 122, -3, 0 },
+                        { 0, -1, 7, 7, 122, 0, 0 } },
+               .odd = { { 0, 2, 122, 7, 5, -1, 0 },
+                        { 0, -1, 122, 7, 8, -1, 0 },
+                        { 0, -4, 122, 7, 12, -2, 0 },
+                        { 0, -6, 120, 7, 16, -2, 0 },
+                        { 0, -8, 118, 7, 21, -3, 0 },
+                        { 0, -10, 117, 7, 25, -4, 0 },
+                        { 0, -11, 114, 7, 30, -5, 0 },
+                        { 0, -13, 112, 7, 35, -6, 0 },
+                        { 0, -14, 109, 7, 40, -7, 0 },
+                        { 0, -14, 105, 7, 45, -8, 0 },
+                        { 0, -15, 102, 7, 50, -9, 0 },
+                        { 0, -15, 98, 7, 55, -10, 0 },
+                        { 0, -15, 94, 7, 60, -11, 0 },
+                        { 0, -15, 90, 7, 65, -12, 0 },
+                        { 0, -14, 85, 7, 70, -13, 0 },
+                        { 0, -14, 80, 7, 75, -13, 0 },
+                        { 0, -13, 75, 7, 80, -14, 0 },
+                        { 0, -13, 70, 7, 85, -14, 0 },
+                        { 0, -12, 65, 7, 90, -15, 0 },
+                        { 0, -11, 60, 7, 94, -15, 0 },
+                        { 0, -10, 55, 7, 98, -15, 0 },
+                        { 0, -9, 50, 7, 102, -15, 0 },
+                        { 0, -8, 45, 7, 105, -14, 0 },
+                        { 0, -7, 40, 7, 109, -14, 0 },
+                        { 0, -6, 35, 7, 112, -13, 0 },
+                        { 0, -5, 30, 7, 114, -11, 0 },
+                        { 0, -4, 25, 7, 117, -10, 0 },
+                        { 0, -3, 21, 7, 118, -8, 0 },
+                        { 0, -2, 16, 7, 120, -6, 0 },
+                        { 0, -2, 12, 7, 122, -4, 0 },
+                        { 0, -1, 8, 7, 122, -1, 0 },
+                        { 0, -1, 5, 7, 122, 2, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 3, 122, 7, 3, 0, 0 },
+                        { 0, 0, 122, 7, 7, -1, 0 },
+                        { 0, -3, 122, 7, 10, -1, 0 },
+                        { 0, -5, 121, 7, 14, -2, 0 },
+                        { 0, -7, 120, 7, 18, -3, 0 },
+                        { 0, -9, 118, 7, 23, -4, 0 },
+                        { 0, -11, 116, 7, 27, -4, 0 },
+                        { 0, -12, 113, 7, 32, -5, 0 },
+                        { 0, -13, 110, 7, 37, -6, 0 },
+                        { 0, -14, 107, 7, 42, -7, 0 },
+                        { 0, -14, 103, 7, 47, -8, 0 },
+                        { 0, -15, 100, 7, 52, -9, 0 },
+                        { 0, -15, 96, 7, 57, -10, 0 },
+                        { 0, -15, 92, 7, 62, -11, 0 },
+                        { 0, -14, 86, 7, 68, -12, 0 },
+                        { 0, -14, 82, 7, 73, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 73, 7, 82, -14, 0 },
+                        { 0, -12, 68, 7, 86, -14, 0 },
+                        { 0, -11, 62, 7, 92, -15, 0 },
+                        { 0, -10, 57, 7, 96, -15, 0 },
+                        { 0, -9, 52, 7, 100, -15, 0 },
+                        { 0, -8, 47, 7, 103, -14, 0 },
+                        { 0, -7, 42, 7, 107, -14, 0 },
+                        { 0, -6, 37, 7, 110, -13, 0 },
+                        { 0, -5, 32, 7, 113, -12, 0 },
+                        { 0, -4, 27, 7, 116, -11, 0 },
+                        { 0, -4, 23, 7, 118, -9, 0 },
+                        { 0, -3, 18, 7, 120, -7, 0 },
+                        { 0, -2, 14, 7, 121, -5, 0 },
+                        { 0, -1, 10, 7, 122, -3, 0 },
+                        { 0, -1, 7, 7, 122, 0, 0 } },
+               .odd = { { 0, 2, 122, 7, 5, -1, 0 },
+                        { 0, -1, 122, 7, 8, -1, 0 },
+                        { 0, -4, 122, 7, 12, -2, 0 },
+                        { 0, -6, 120, 7, 16, -2, 0 },
+                        { 0, -8, 118, 7, 21, -3, 0 },
+                        { 0, -10, 117, 7, 25, -4, 0 },
+                        { 0, -11, 114, 7, 30, -5, 0 },
+                        { 0, -13, 112, 7, 35, -6, 0 },
+                        { 0, -14, 109, 7, 40, -7, 0 },
+                        { 0, -14, 105, 7, 45, -8, 0 },
+                        { 0, -15, 102, 7, 50, -9, 0 },
+                        { 0, -15, 98, 7, 55, -10, 0 },
+                        { 0, -15, 94, 7, 60, -11, 0 },
+                        { 0, -15, 90, 7, 65, -12, 0 },
+                        { 0, -14, 85, 7, 70, -13, 0 },
+                        { 0, -14, 80, 7, 75, -13, 0 },
+                        { 0, -13, 75, 7, 80, -14, 0 },
+                        { 0, -13, 70, 7, 85, -14, 0 },
+                        { 0, -12, 65, 7, 90, -15, 0 },
+                        { 0, -11, 60, 7, 94, -15, 0 },
+                        { 0, -10, 55, 7, 98, -15, 0 },
+                        { 0, -9, 50, 7, 102, -15, 0 },
+                        { 0, -8, 45, 7, 105, -14, 0 },
+                        { 0, -7, 40, 7, 109, -14, 0 },
+                        { 0, -6, 35, 7, 112, -13, 0 },
+                        { 0, -5, 30, 7, 114, -11, 0 },
+                        { 0, -4, 25, 7, 117, -10, 0 },
+                        { 0, -3, 21, 7, 118, -8, 0 },
+                        { 0, -2, 16, 7, 120, -6, 0 },
+                        { 0, -2, 12, 7, 122, -4, 0 },
+                        { 0, -1, 8, 7, 122, -1, 0 },
+                        { 0, -1, 5, 7, 122, 2, 0 } } },
+       .ptrn_arr = { { 0xffffffff, 0xffffffff } },
+       .sample_patrn_length = 66,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 2) = 0.941176 */
+       .hor_phase_arr = {
+               .even = { { -1, 6, 118, 7, 6, -1, 0 },
+                        { 0, 0, 117, 7, 13, -2, 0 },
+                        { 0, -5, 116, 7, 21, -4, 0 },
+                        { 0, -9, 113, 7, 30, -6, 0 },
+                        { 0, -12, 109, 7, 39, -8, 0 },
+                        { 0, -13, 102, 7, 49, -10, 0 },
+                        { 0, -14, 94, 7, 59, -11, 0 },
+                        { 0, -14, 86, 7, 69, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 69, 7, 86, -14, 0 },
+                        { 0, -11, 59, 7, 94, -14, 0 },
+                        { 0, -10, 49, 7, 102, -13, 0 },
+                        { 0, -8, 39, 7, 109, -12, 0 },
+                        { 0, -6, 30, 7, 113, -9, 0 },
+                        { 0, -4, 21, 7, 116, -5, 0 },
+                        { 0, -2, 13, 7, 117, 0, 0 } },
+               .odd = { { -1, 3, 118, 7, 10, -2, 0 },
+                        { 0, -3, 117, 7, 17, -3, 0 },
+                        { 0, -7, 114, 7, 26, -5, 0 },
+                        { 0, -10, 110, 7, 35, -7, 0 },
+                        { 0, -13, 106, 7, 44, -9, 0 },
+                        { 0, -14, 99, 7, 54, -11, 0 },
+                        { 0, -14, 90, 7, 64, -12, 0 },
+                        { 0, -14, 82, 7, 73, -13, 0 },
+                        { 0, -13, 73, 7, 82, -14, 0 },
+                        { 0, -12, 64, 7, 90, -14, 0 },
+                        { 0, -11, 54, 7, 99, -14, 0 },
+                        { 0, -9, 44, 7, 106, -13, 0 },
+                        { 0, -7, 35, 7, 110, -10, 0 },
+                        { 0, -5, 26, 7, 114, -7, 0 },
+                        { 0, -3, 17, 7, 117, -3, 0 },
+                        { 0, -2, 10, 7, 118, 3, -1 } } },
+       .ver_phase_arr = {
+               .even = { { -1, 6, 118, 7, 6, -1, 0 },
+                        { 0, 0, 117, 7, 13, -2, 0 },
+                        { 0, -5, 116, 7, 21, -4, 0 },
+                        { 0, -9, 113, 7, 30, -6, 0 },
+                        { 0, -12, 109, 7, 39, -8, 0 },
+                        { 0, -13, 102, 7, 49, -10, 0 },
+                        { 0, -14, 94, 7, 59, -11, 0 },
+                        { 0, -14, 86, 7, 69, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 69, 7, 86, -14, 0 },
+                        { 0, -11, 59, 7, 94, -14, 0 },
+                        { 0, -10, 49, 7, 102, -13, 0 },
+                        { 0, -8, 39, 7, 109, -12, 0 },
+                        { 0, -6, 30, 7, 113, -9, 0 },
+                        { 0, -4, 21, 7, 116, -5, 0 },
+                        { 0, -2, 13, 7, 117, 0, 0 } },
+               .odd = { { -1, 3, 118, 7, 10, -2, 0 },
+                        { 0, -3, 117, 7, 17, -3, 0 },
+                        { 0, -7, 114, 7, 26, -5, 0 },
+                        { 0, -10, 110, 7, 35, -7, 0 },
+                        { 0, -13, 106, 7, 44, -9, 0 },
+                        { 0, -14, 99, 7, 54, -11, 0 },
+                        { 0, -14, 90, 7, 64, -12, 0 },
+                        { 0, -14, 82, 7, 73, -13, 0 },
+                        { 0, -13, 73, 7, 82, -14, 0 },
+                        { 0, -12, 64, 7, 90, -14, 0 },
+                        { 0, -11, 54, 7, 99, -14, 0 },
+                        { 0, -9, 44, 7, 106, -13, 0 },
+                        { 0, -7, 35, 7, 110, -10, 0 },
+                        { 0, -5, 26, 7, 114, -7, 0 },
+                        { 0, -3, 17, 7, 117, -3, 0 },
+                        { 0, -2, 10, 7, 118, 3, -1 } } },
+       .ptrn_arr = { { 0xffffffff } },
+       .sample_patrn_length = 34,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 3) = 0.914286 */
+       .hor_phase_arr = {
+               .even = { { -2, 9, 114, 7, 9, -2, 0 },
+                        { -1, 0, 114, 7, 20, -5, 0 },
+                        { 0, -7, 110, 7, 32, -7, 0 },
+                        { 0, -11, 103, 7, 46, -10, 0 },
+                        { 0, -13, 93, 7, 60, -12, 0 },
+                        { 0, -14, 82, 7, 74, -14, 0 },
+                        { 0, -13, 69, 7, 86, -14, 0 },
+                        { 0, -11, 55, 7, 97, -13, 0 },
+                        { 0, -9, 41, 7, 106, -10, 0 },
+                        { 0, -6, 28, 7, 111, -5, 0 },
+                        { 0, -4, 16, 7, 114, 3, -1 },
+                        { -2, 6, 115, 7, 12, -3, 0 },
+                        { 0, -2, 111, 7, 24, -5, 0 },
+                        { 0, -8, 107, 7, 37, -8, 0 },
+                        { 0, -12, 100, 7, 51, -11, 0 },
+                        { 0, -14, 90, 7, 65, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 65, 7, 90, -14, 0 },
+                        { 0, -11, 51, 7, 100, -12, 0 },
+                        { 0, -8, 37, 7, 107, -8, 0 },
+                        { 0, -5, 24, 7, 111, -2, 0 },
+                        { 0, -3, 12, 7, 115, 6, -2 },
+                        { -1, 3, 114, 7, 16, -4, 0 },
+                        { 0, -5, 111, 7, 28, -6, 0 },
+                        { 0, -10, 106, 7, 41, -9, 0 },
+                        { 0, -13, 97, 7, 55, -11, 0 },
+                        { 0, -14, 86, 7, 69, -13, 0 },
+                        { 0, -14, 74, 7, 82, -14, 0 },
+                        { 0, -12, 60, 7, 93, -13, 0 },
+                        { 0, -10, 46, 7, 103, -11, 0 },
+                        { 0, -7, 32, 7, 110, -7, 0 },
+                        { 0, -5, 20, 7, 114, 0, -1 } },
+               .odd = { { -1, 4, 114, 7, 14, -3, 0 },
+                        { 0, -4, 112, 7, 26, -6, 0 },
+                        { 0, -9, 107, 7, 39, -9, 0 },
+                        { 0, -13, 99, 7, 53, -11, 0 },
+                        { 0, -14, 88, 7, 67, -13, 0 },
+                        { 0, -14, 76, 7, 80, -14, 0 },
+                        { 0, -13, 62, 7, 93, -14, 0 },
+                        { 0, -10, 48, 7, 102, -12, 0 },
+                        { 0, -8, 35, 7, 109, -8, 0 },
+                        { 0, -5, 22, 7, 112, -1, 0 },
+                        { 0, -3, 11, 7, 115, 7, -2 },
+                        { -1, 1, 114, 7, 18, -4, 0 },
+                        { 0, -6, 111, 7, 30, -7, 0 },
+                        { 0, -10, 103, 7, 44, -9, 0 },
+                        { 0, -13, 95, 7, 58, -12, 0 },
+                        { 0, -14, 85, 7, 71, -14, 0 },
+                        { 0, -14, 71, 7, 85, -14, 0 },
+                        { 0, -12, 58, 7, 95, -13, 0 },
+                        { 0, -9, 44, 7, 103, -10, 0 },
+                        { 0, -7, 30, 7, 111, -6, 0 },
+                        { 0, -4, 18, 7, 114, 1, -1 },
+                        { -2, 7, 115, 7, 11, -3, 0 },
+                        { 0, -1, 112, 7, 22, -5, 0 },
+                        { 0, -8, 109, 7, 35, -8, 0 },
+                        { 0, -12, 102, 7, 48, -10, 0 },
+                        { 0, -14, 93, 7, 62, -13, 0 },
+                        { 0, -14, 80, 7, 76, -14, 0 },
+                        { 0, -13, 67, 7, 88, -14, 0 },
+                        { 0, -11, 53, 7, 99, -13, 0 },
+                        { 0, -9, 39, 7, 107, -9, 0 },
+                        { 0, -6, 26, 7, 112, -4, 0 },
+                        { 0, -3, 14, 7, 114, 4, -1 } } },
+       .ver_phase_arr = {
+               .even = { { -2, 9, 114, 7, 9, -2, 0 },
+                        { -1, 0, 114, 7, 20, -5, 0 },
+                        { 0, -7, 110, 7, 32, -7, 0 },
+                        { 0, -11, 103, 7, 46, -10, 0 },
+                        { 0, -13, 93, 7, 60, -12, 0 },
+                        { 0, -14, 82, 7, 74, -14, 0 },
+                        { 0, -13, 69, 7, 86, -14, 0 },
+                        { 0, -11, 55, 7, 97, -13, 0 },
+                        { 0, -9, 41, 7, 106, -10, 0 },
+                        { 0, -6, 28, 7, 111, -5, 0 },
+                        { 0, -4, 16, 7, 114, 3, -1 },
+                        { -2, 6, 115, 7, 12, -3, 0 },
+                        { 0, -2, 111, 7, 24, -5, 0 },
+                        { 0, -8, 107, 7, 37, -8, 0 },
+                        { 0, -12, 100, 7, 51, -11, 0 },
+                        { 0, -14, 90, 7, 65, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 65, 7, 90, -14, 0 },
+                        { 0, -11, 51, 7, 100, -12, 0 },
+                        { 0, -8, 37, 7, 107, -8, 0 },
+                        { 0, -5, 24, 7, 111, -2, 0 },
+                        { 0, -3, 12, 7, 115, 6, -2 },
+                        { -1, 3, 114, 7, 16, -4, 0 },
+                        { 0, -5, 111, 7, 28, -6, 0 },
+                        { 0, -10, 106, 7, 41, -9, 0 },
+                        { 0, -13, 97, 7, 55, -11, 0 },
+                        { 0, -14, 86, 7, 69, -13, 0 },
+                        { 0, -14, 74, 7, 82, -14, 0 },
+                        { 0, -12, 60, 7, 93, -13, 0 },
+                        { 0, -10, 46, 7, 103, -11, 0 },
+                        { 0, -7, 32, 7, 110, -7, 0 },
+                        { 0, -5, 20, 7, 114, 0, -1 } },
+               .odd = { { -1, 4, 114, 7, 14, -3, 0 },
+                        { 0, -4, 112, 7, 26, -6, 0 },
+                        { 0, -9, 107, 7, 39, -9, 0 },
+                        { 0, -13, 99, 7, 53, -11, 0 },
+                        { 0, -14, 88, 7, 67, -13, 0 },
+                        { 0, -14, 76, 7, 80, -14, 0 },
+                        { 0, -13, 62, 7, 93, -14, 0 },
+                        { 0, -10, 48, 7, 102, -12, 0 },
+                        { 0, -8, 35, 7, 109, -8, 0 },
+                        { 0, -5, 22, 7, 112, -1, 0 },
+                        { 0, -3, 11, 7, 115, 7, -2 },
+                        { -1, 1, 114, 7, 18, -4, 0 },
+                        { 0, -6, 111, 7, 30, -7, 0 },
+                        { 0, -10, 103, 7, 44, -9, 0 },
+                        { 0, -13, 95, 7, 58, -12, 0 },
+                        { 0, -14, 85, 7, 71, -14, 0 },
+                        { 0, -14, 71, 7, 85, -14, 0 },
+                        { 0, -12, 58, 7, 95, -13, 0 },
+                        { 0, -9, 44, 7, 103, -10, 0 },
+                        { 0, -7, 30, 7, 111, -6, 0 },
+                        { 0, -4, 18, 7, 114, 1, -1 },
+                        { -2, 7, 115, 7, 11, -3, 0 },
+                        { 0, -1, 112, 7, 22, -5, 0 },
+                        { 0, -8, 109, 7, 35, -8, 0 },
+                        { 0, -12, 102, 7, 48, -10, 0 },
+                        { 0, -14, 93, 7, 62, -13, 0 },
+                        { 0, -14, 80, 7, 76, -14, 0 },
+                        { 0, -13, 67, 7, 88, -14, 0 },
+                        { 0, -11, 53, 7, 99, -13, 0 },
+                        { 0, -9, 39, 7, 107, -9, 0 },
+                        { 0, -6, 26, 7, 112, -4, 0 },
+                        { 0, -3, 14, 7, 114, 4, -1 } } },
+       .ptrn_arr = { { 0xff3fffff, 0xffff9fff, 0xf } },
+       .sample_patrn_length = 70,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 4) = 0.888889 */
+       .hor_phase_arr = {
+               .even = { { -3, 12, 110, 7, 12, -3, 0 },
+                        { -1, 0, 110, 7, 26, -7, 0 },
+                        { 0, -8, 103, 7, 43, -10, 0 },
+                        { 0, -12, 92, 7, 61, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 61, 7, 92, -12, 0 },
+                        { 0, -10, 43, 7, 103, -8, 0 },
+                        { 0, -7, 26, 7, 110, 0, -1 } },
+               .odd = { { -2, 5, 111, 7, 19, -5, 0 },
+                        { 0, -4, 106, 7, 34, -8, 0 },
+                        { 0, -11, 98, 7, 52, -11, 0 },
+                        { 0, -13, 85, 7, 69, -13, 0 },
+                        { 0, -13, 69, 7, 85, -13, 0 },
+                        { 0, -11, 52, 7, 98, -11, 0 },
+                        { 0, -8, 34, 7, 106, -4, 0 },
+                        { 0, -5, 19, 7, 111, 5, -2 } } },
+       .ver_phase_arr = {
+               .even = { { -3, 12, 110, 7, 12, -3, 0 },
+                        { -1, 0, 110, 7, 26, -7, 0 },
+                        { 0, -8, 103, 7, 43, -10, 0 },
+                        { 0, -12, 92, 7, 61, -13, 0 },
+                        { 0, -14, 78, 7, 78, -14, 0 },
+                        { 0, -13, 61, 7, 92, -12, 0 },
+                        { 0, -10, 43, 7, 103, -8, 0 },
+                        { 0, -7, 26, 7, 110, 0, -1 } },
+               .odd = { { -2, 5, 111, 7, 19, -5, 0 },
+                        { 0, -4, 106, 7, 34, -8, 0 },
+                        { 0, -11, 98, 7, 52, -11, 0 },
+                        { 0, -13, 85, 7, 69, -13, 0 },
+                        { 0, -13, 69, 7, 85, -13, 0 },
+                        { 0, -11, 52, 7, 98, -11, 0 },
+                        { 0, -8, 34, 7, 106, -4, 0 },
+                        { 0, -5, 19, 7, 111, 5, -2 } } },
+       .ptrn_arr = { { 0xffff } },
+       .sample_patrn_length = 18,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 5) = 0.864865 */
+       .hor_phase_arr = {
+               .even = { { -5, 14, 110, 7, 14, -5, 0 },
+                        { -1, 0, 106, 7, 32, -9, 0 },
+                        { 0, -9, 96, 7, 53, -12, 0 },
+                        { 0, -13, 81, 7, 73, -13, 0 },
+                        { 0, -13, 61, 7, 91, -11, 0 },
+                        { 0, -10, 40, 7, 103, -4, -1 },
+                        { 0, -6, 21, 7, 108, 8, -3 },
+                        { -3, 5, 108, 7, 25, -7, 0 },
+                        { 0, -6, 101, 7, 44, -11, 0 },
+                        { 0, -12, 88, 7, 65, -13, 0 },
+                        { 0, -13, 69, 7, 85, -13, 0 },
+                        { 0, -11, 49, 7, 98, -8, 0 },
+                        { 0, -8, 28, 7, 108, 2, -2 },
+                        { -4, 11, 108, 7, 18, -5, 0 },
+                        { -1, -2, 104, 7, 36, -9, 0 },
+                        { 0, -10, 93, 7, 57, -12, 0 },
+                        { 0, -13, 77, 7, 77, -13, 0 },
+                        { 0, -12, 57, 7, 93, -10, 0 },
+                        { 0, -9, 36, 7, 104, -2, -1 },
+                        { 0, -5, 18, 7, 108, 11, -4 },
+                        { -2, 2, 108, 7, 28, -8, 0 },
+                        { 0, -8, 98, 7, 49, -11, 0 },
+                        { 0, -13, 85, 7, 69, -13, 0 },
+                        { 0, -13, 65, 7, 88, -12, 0 },
+                        { 0, -11, 44, 7, 101, -6, 0 },
+                        { 0, -7, 25, 7, 108, 5, -3 },
+                        { -3, 8, 108, 7, 21, -6, 0 },
+                        { -1, -4, 103, 7, 40, -10, 0 },
+                        { 0, -11, 91, 7, 61, -13, 0 },
+                        { 0, -13, 73, 7, 81, -13, 0 },
+                        { 0, -12, 53, 7, 96, -9, 0 },
+                        { 0, -9, 32, 7, 106, 0, -1 } },
+               .odd = { { -3, 7, 108, 7, 23, -7, 0 },
+                        { 0, -5, 101, 7, 42, -10, 0 },
+                        { 0, -12, 90, 7, 63, -13, 0 },
+                        { 0, -13, 71, 7, 83, -13, 0 },
+                        { 0, -12, 51, 7, 97, -8, 0 },
+                        { 0, -8, 30, 7, 107, 1, -2 },
+                        { -4, 13, 108, 7, 16, -5, 0 },
+                        { -1, -1, 105, 7, 34, -9, 0 },
+                        { 0, -10, 95, 7, 55, -12, 0 },
+                        { 0, -13, 79, 7, 75, -13, 0 },
+                        { 0, -13, 59, 7, 93, -11, 0 },
+                        { 0, -10, 38, 7, 104, -3, -1 },
+                        { 0, -6, 19, 7, 110, 9, -4 },
+                        { -2, 4, 106, 7, 27, -7, 0 },
+                        { 0, -7, 99, 7, 47, -11, 0 },
+                        { 0, -12, 86, 7, 67, -13, 0 },
+                        { 0, -13, 67, 7, 86, -12, 0 },
+                        { 0, -11, 47, 7, 99, -7, 0 },
+                        { 0, -7, 27, 7, 106, 4, -2 },
+                        { -4, 9, 110, 7, 19, -6, 0 },
+                        { -1, -3, 104, 7, 38, -10, 0 },
+                        { 0, -11, 93, 7, 59, -13, 0 },
+                        { 0, -13, 75, 7, 79, -13, 0 },
+                        { 0, -12, 55, 7, 95, -10, 0 },
+                        { 0, -9, 34, 7, 105, -1, -1 },
+                        { 0, -5, 16, 7, 108, 13, -4 },
+                        { -2, 1, 107, 7, 30, -8, 0 },
+                        { 0, -8, 97, 7, 51, -12, 0 },
+                        { 0, -13, 83, 7, 71, -13, 0 },
+                        { 0, -13, 63, 7, 90, -12, 0 },
+                        { 0, -10, 42, 7, 101, -5, 0 },
+                        { 0, -7, 23, 7, 108, 7, -3 } } },
+       .ver_phase_arr = {
+               .even = { { -5, 14, 110, 7, 14, -5, 0 },
+                        { -1, 0, 106, 7, 32, -9, 0 },
+                        { 0, -9, 96, 7, 53, -12, 0 },
+                        { 0, -13, 81, 7, 73, -13, 0 },
+                        { 0, -13, 61, 7, 91, -11, 0 },
+                        { 0, -10, 40, 7, 103, -4, -1 },
+                        { 0, -6, 21, 7, 108, 8, -3 },
+                        { -3, 5, 108, 7, 25, -7, 0 },
+                        { 0, -6, 101, 7, 44, -11, 0 },
+                        { 0, -12, 88, 7, 65, -13, 0 },
+                        { 0, -13, 69, 7, 85, -13, 0 },
+                        { 0, -11, 49, 7, 98, -8, 0 },
+                        { 0, -8, 28, 7, 108, 2, -2 },
+                        { -4, 11, 108, 7, 18, -5, 0 },
+                        { -1, -2, 104, 7, 36, -9, 0 },
+                        { 0, -10, 93, 7, 57, -12, 0 },
+                        { 0, -13, 77, 7, 77, -13, 0 },
+                        { 0, -12, 57, 7, 93, -10, 0 },
+                        { 0, -9, 36, 7, 104, -2, -1 },
+                        { 0, -5, 18, 7, 108, 11, -4 },
+                        { -2, 2, 108, 7, 28, -8, 0 },
+                        { 0, -8, 98, 7, 49, -11, 0 },
+                        { 0, -13, 85, 7, 69, -13, 0 },
+                        { 0, -13, 65, 7, 88, -12, 0 },
+                        { 0, -11, 44, 7, 101, -6, 0 },
+                        { 0, -7, 25, 7, 108, 5, -3 },
+                        { -3, 8, 108, 7, 21, -6, 0 },
+                        { -1, -4, 103, 7, 40, -10, 0 },
+                        { 0, -11, 91, 7, 61, -13, 0 },
+                        { 0, -13, 73, 7, 81, -13, 0 },
+                        { 0, -12, 53, 7, 96, -9, 0 },
+                        { 0, -9, 32, 7, 106, 0, -1 } },
+               .odd = { { -3, 7, 108, 7, 23, -7, 0 },
+                        { 0, -5, 101, 7, 42, -10, 0 },
+                        { 0, -12, 90, 7, 63, -13, 0 },
+                        { 0, -13, 71, 7, 83, -13, 0 },
+                        { 0, -12, 51, 7, 97, -8, 0 },
+                        { 0, -8, 30, 7, 107, 1, -2 },
+                        { -4, 13, 108, 7, 16, -5, 0 },
+                        { -1, -1, 105, 7, 34, -9, 0 },
+                        { 0, -10, 95, 7, 55, -12, 0 },
+                        { 0, -13, 79, 7, 75, -13, 0 },
+                        { 0, -13, 59, 7, 93, -11, 0 },
+                        { 0, -10, 38, 7, 104, -3, -1 },
+                        { 0, -6, 19, 7, 110, 9, -4 },
+                        { -2, 4, 106, 7, 27, -7, 0 },
+                        { 0, -7, 99, 7, 47, -11, 0 },
+                        { 0, -12, 86, 7, 67, -13, 0 },
+                        { 0, -13, 67, 7, 86, -12, 0 },
+                        { 0, -11, 47, 7, 99, -7, 0 },
+                        { 0, -7, 27, 7, 106, 4, -2 },
+                        { -4, 9, 110, 7, 19, -6, 0 },
+                        { -1, -3, 104, 7, 38, -10, 0 },
+                        { 0, -11, 93, 7, 59, -13, 0 },
+                        { 0, -13, 75, 7, 79, -13, 0 },
+                        { 0, -12, 55, 7, 95, -10, 0 },
+                        { 0, -9, 34, 7, 105, -1, -1 },
+                        { 0, -5, 16, 7, 108, 13, -4 },
+                        { -2, 1, 107, 7, 30, -8, 0 },
+                        { 0, -8, 97, 7, 51, -12, 0 },
+                        { 0, -13, 83, 7, 71, -13, 0 },
+                        { 0, -13, 63, 7, 90, -12, 0 },
+                        { 0, -10, 42, 7, 101, -5, 0 },
+                        { 0, -7, 23, 7, 108, 7, -3 } } },
+       .ptrn_arr = { { 0xcfff9fff, 0xf3ffe7ff, 0xff } },
+       .sample_patrn_length = 74,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 6) = 0.842105 */
+       .hor_phase_arr = {
+               .even = { { -6, 17, 106, 7, 17, -6, 0 },
+                        { -2, 0, 102, 7, 38, -10, 0 },
+                        { 0, -10, 89, 7, 62, -13, 0 },
+                        { 0, -13, 69, 7, 83, -11, 0 },
+                        { 0, -11, 46, 7, 98, -4, -1 },
+                        { 0, -7, 23, 7, 106, 10, -4 },
+                        { -3, 5, 104, 7, 31, -9, 0 },
+                        { 0, -7, 93, 7, 54, -12, 0 },
+                        { 0, -12, 76, 7, 76, -12, 0 },
+                        { 0, -12, 54, 7, 93, -7, 0 },
+                        { 0, -9, 31, 7, 104, 5, -3 },
+                        { -4, 10, 106, 7, 23, -7, 0 },
+                        { -1, -4, 98, 7, 46, -11, 0 },
+                        { 0, -11, 83, 7, 69, -13, 0 },
+                        { 0, -13, 62, 7, 89, -10, 0 },
+                        { 0, -10, 38, 7, 102, 0, -2 } },
+               .odd = { { -4, 8, 105, 7, 27, -8, 0 },
+                        { 0, -6, 96, 7, 50, -12, 0 },
+                        { 0, -12, 80, 7, 73, -13, 0 },
+                        { 0, -13, 58, 7, 92, -9, 0 },
+                        { 0, -9, 34, 7, 103, 2, -2 },
+                        { -5, 13, 107, 7, 20, -7, 0 },
+                        { -1, -2, 100, 7, 42, -11, 0 },
+                        { 0, -11, 87, 7, 65, -13, 0 },
+                        { 0, -13, 65, 7, 87, -11, 0 },
+                        { 0, -11, 42, 7, 100, -2, -1 },
+                        { 0, -7, 20, 7, 107, 13, -5 },
+                        { -2, 2, 103, 7, 34, -9, 0 },
+                        { 0, -9, 92, 7, 58, -13, 0 },
+                        { 0, -13, 73, 7, 80, -12, 0 },
+                        { 0, -12, 50, 7, 96, -6, 0 },
+                        { 0, -8, 27, 7, 105, 8, -4 } } },
+       .ver_phase_arr = {
+               .even = { { -6, 17, 106, 7, 17, -6, 0 },
+                        { -2, 0, 102, 7, 38, -10, 0 },
+                        { 0, -10, 89, 7, 62, -13, 0 },
+                        { 0, -13, 69, 7, 83, -11, 0 },
+                        { 0, -11, 46, 7, 98, -4, -1 },
+                        { 0, -7, 23, 7, 106, 10, -4 },
+                        { -3, 5, 104, 7, 31, -9, 0 },
+                        { 0, -7, 93, 7, 54, -12, 0 },
+                        { 0, -12, 76, 7, 76, -12, 0 },
+                        { 0, -12, 54, 7, 93, -7, 0 },
+                        { 0, -9, 31, 7, 104, 5, -3 },
+                        { -4, 10, 106, 7, 23, -7, 0 },
+                        { -1, -4, 98, 7, 46, -11, 0 },
+                        { 0, -11, 83, 7, 69, -13, 0 },
+                        { 0, -13, 62, 7, 89, -10, 0 },
+                        { 0, -10, 38, 7, 102, 0, -2 } },
+               .odd = { { -4, 8, 105, 7, 27, -8, 0 },
+                        { 0, -6, 96, 7, 50, -12, 0 },
+                        { 0, -12, 80, 7, 73, -13, 0 },
+                        { 0, -13, 58, 7, 92, -9, 0 },
+                        { 0, -9, 34, 7, 103, 2, -2 },
+                        { -5, 13, 107, 7, 20, -7, 0 },
+                        { -1, -2, 100, 7, 42, -11, 0 },
+                        { 0, -11, 87, 7, 65, -13, 0 },
+                        { 0, -13, 65, 7, 87, -11, 0 },
+                        { 0, -11, 42, 7, 100, -2, -1 },
+                        { 0, -7, 20, 7, 107, 13, -5 },
+                        { -2, 2, 103, 7, 34, -9, 0 },
+                        { 0, -9, 92, 7, 58, -13, 0 },
+                        { 0, -13, 73, 7, 80, -12, 0 },
+                        { 0, -12, 50, 7, 96, -6, 0 },
+                        { 0, -8, 27, 7, 105, 8, -4 } } },
+       .ptrn_arr = { { 0xfcffe7ff, 0xf } },
+       .sample_patrn_length = 38,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 7) = 0.820513 */
+       .hor_phase_arr = {
+               .even = { { -7, 19, 104, 7, 19, -7, 0 },
+                        { -2, 0, 98, 7, 43, -11, 0 },
+                        { 0, -10, 81, 7, 69, -12, 0 },
+                        { 0, -12, 58, 7, 89, -7, 0 },
+                        { 0, -10, 32, 7, 103, 7, -4 },
+                        { -5, 10, 103, 7, 29, -9, 0 },
+                        { -1, -6, 93, 7, 54, -12, 0 },
+                        { 0, -12, 72, 7, 79, -11, 0 },
+                        { 0, -12, 47, 7, 97, -2, -2 },
+                        { 0, -8, 22, 7, 104, 16, -6 },
+                        { -3, 2, 100, 7, 40, -11, 0 },
+                        { 0, -9, 84, 7, 65, -12, 0 },
+                        { 0, -13, 62, 7, 87, -8, 0 },
+                        { 0, -10, 36, 7, 100, 5, -3 },
+                        { -5, 13, 103, 7, 25, -8, 0 },
+                        { -1, -4, 94, 7, 51, -12, 0 },
+                        { 0, -12, 76, 7, 76, -12, 0 },
+                        { 0, -12, 51, 7, 94, -4, -1 },
+                        { 0, -8, 25, 7, 103, 13, -5 },
+                        { -3, 5, 100, 7, 36, -10, 0 },
+                        { 0, -8, 87, 7, 62, -13, 0 },
+                        { 0, -12, 65, 7, 84, -9, 0 },
+                        { 0, -11, 40, 7, 100, 2, -3 },
+                        { -6, 16, 104, 7, 22, -8, 0 },
+                        { -2, -2, 97, 7, 47, -12, 0 },
+                        { 0, -11, 79, 7, 72, -12, 0 },
+                        { 0, -12, 54, 7, 93, -6, -1 },
+                        { 0, -9, 29, 7, 103, 10, -5 },
+                        { -4, 7, 103, 7, 32, -10, 0 },
+                        { 0, -7, 89, 7, 58, -12, 0 },
+                        { 0, -12, 69, 7, 81, -10, 0 },
+                        { 0, -11, 43, 7, 98, 0, -2 } },
+               .odd = { { -4, 9, 101, 7, 31, -9, 0 },
+                        { -1, -6, 91, 7, 56, -12, 0 },
+                        { 0, -12, 71, 7, 80, -11, 0 },
+                        { 0, -11, 45, 7, 97, -1, -2 },
+                        { 0, -7, 20, 7, 105, 17, -7 },
+                        { -3, 1, 100, 7, 41, -11, 0 },
+                        { 0, -10, 83, 7, 67, -12, 0 },
+                        { 0, -13, 60, 7, 89, -8, 0 },
+                        { 0, -10, 34, 7, 102, 6, -4 },
+                        { -5, 11, 104, 7, 27, -9, 0 },
+                        { -1, -5, 94, 7, 52, -12, 0 },
+                        { 0, -12, 74, 7, 77, -11, 0 },
+                        { 0, -12, 49, 7, 95, -3, -1 },
+                        { 0, -8, 24, 7, 104, 14, -6 },
+                        { -3, 3, 100, 7, 38, -10, 0 },
+                        { 0, -9, 87, 7, 63, -13, 0 },
+                        { 0, -13, 63, 7, 87, -9, 0 },
+                        { 0, -10, 38, 7, 100, 3, -3 },
+                        { -6, 14, 104, 7, 24, -8, 0 },
+                        { -1, -3, 95, 7, 49, -12, 0 },
+                        { 0, -11, 77, 7, 74, -12, 0 },
+                        { 0, -12, 52, 7, 94, -5, -1 },
+                        { 0, -9, 27, 7, 104, 11, -5 },
+                        { -4, 6, 102, 7, 34, -10, 0 },
+                        { 0, -8, 89, 7, 60, -13, 0 },
+                        { 0, -12, 67, 7, 83, -10, 0 },
+                        { 0, -11, 41, 7, 100, 1, -3 },
+                        { -7, 17, 105, 7, 20, -7, 0 },
+                        { -2, -1, 97, 7, 45, -11, 0 },
+                        { 0, -11, 80, 7, 71, -12, 0 },
+                        { 0, -12, 56, 7, 91, -6, -1 },
+                        { 0, -9, 31, 7, 101, 9, -4 } } },
+       .ver_phase_arr = {
+               .even = { { -7, 19, 104, 7, 19, -7, 0 },
+                        { -2, 0, 98, 7, 43, -11, 0 },
+                        { 0, -10, 81, 7, 69, -12, 0 },
+                        { 0, -12, 58, 7, 89, -7, 0 },
+                        { 0, -10, 32, 7, 103, 7, -4 },
+                        { -5, 10, 103, 7, 29, -9, 0 },
+                        { -1, -6, 93, 7, 54, -12, 0 },
+                        { 0, -12, 72, 7, 79, -11, 0 },
+                        { 0, -12, 47, 7, 97, -2, -2 },
+                        { 0, -8, 22, 7, 104, 16, -6 },
+                        { -3, 2, 100, 7, 40, -11, 0 },
+                        { 0, -9, 84, 7, 65, -12, 0 },
+                        { 0, -13, 62, 7, 87, -8, 0 },
+                        { 0, -10, 36, 7, 100, 5, -3 },
+                        { -5, 13, 103, 7, 25, -8, 0 },
+                        { -1, -4, 94, 7, 51, -12, 0 },
+                        { 0, -12, 76, 7, 76, -12, 0 },
+                        { 0, -12, 51, 7, 94, -4, -1 },
+                        { 0, -8, 25, 7, 103, 13, -5 },
+                        { -3, 5, 100, 7, 36, -10, 0 },
+                        { 0, -8, 87, 7, 62, -13, 0 },
+                        { 0, -12, 65, 7, 84, -9, 0 },
+                        { 0, -11, 40, 7, 100, 2, -3 },
+                        { -6, 16, 104, 7, 22, -8, 0 },
+                        { -2, -2, 97, 7, 47, -12, 0 },
+                        { 0, -11, 79, 7, 72, -12, 0 },
+                        { 0, -12, 54, 7, 93, -6, -1 },
+                        { 0, -9, 29, 7, 103, 10, -5 },
+                        { -4, 7, 103, 7, 32, -10, 0 },
+                        { 0, -7, 89, 7, 58, -12, 0 },
+                        { 0, -12, 69, 7, 81, -10, 0 },
+                        { 0, -11, 43, 7, 98, 0, -2 } },
+               .odd = { { -4, 9, 101, 7, 31, -9, 0 },
+                        { -1, -6, 91, 7, 56, -12, 0 },
+                        { 0, -12, 71, 7, 80, -11, 0 },
+                        { 0, -11, 45, 7, 97, -1, -2 },
+                        { 0, -7, 20, 7, 105, 17, -7 },
+                        { -3, 1, 100, 7, 41, -11, 0 },
+                        { 0, -10, 83, 7, 67, -12, 0 },
+                        { 0, -13, 60, 7, 89, -8, 0 },
+                        { 0, -10, 34, 7, 102, 6, -4 },
+                        { -5, 11, 104, 7, 27, -9, 0 },
+                        { -1, -5, 94, 7, 52, -12, 0 },
+                        { 0, -12, 74, 7, 77, -11, 0 },
+                        { 0, -12, 49, 7, 95, -3, -1 },
+                        { 0, -8, 24, 7, 104, 14, -6 },
+                        { -3, 3, 100, 7, 38, -10, 0 },
+                        { 0, -9, 87, 7, 63, -13, 0 },
+                        { 0, -13, 63, 7, 87, -9, 0 },
+                        { 0, -10, 38, 7, 100, 3, -3 },
+                        { -6, 14, 104, 7, 24, -8, 0 },
+                        { -1, -3, 95, 7, 49, -12, 0 },
+                        { 0, -11, 77, 7, 74, -12, 0 },
+                        { 0, -12, 52, 7, 94, -5, -1 },
+                        { 0, -9, 27, 7, 104, 11, -5 },
+                        { -4, 6, 102, 7, 34, -10, 0 },
+                        { 0, -8, 89, 7, 60, -13, 0 },
+                        { 0, -12, 67, 7, 83, -10, 0 },
+                        { 0, -11, 41, 7, 100, 1, -3 },
+                        { -7, 17, 105, 7, 20, -7, 0 },
+                        { -2, -1, 97, 7, 45, -11, 0 },
+                        { 0, -11, 80, 7, 71, -12, 0 },
+                        { 0, -12, 56, 7, 91, -6, -1 },
+                        { 0, -9, 31, 7, 101, 9, -4 } } },
+       .ptrn_arr = { { 0xff9ff3ff, 0xff3fe7fc, 0xff9 } },
+       .sample_patrn_length = 78,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 8) = 0.8 */
+       .hor_phase_arr = {
+               .even = { { -8, 21, 102, 7, 21, -8, 0 },
+                        { -3, 0, 95, 7, 48, -12, 0 },
+                        { 0, -11, 75, 7, 75, -11, 0 },
+                        { 0, -12, 48, 7, 95, 0, -3 } },
+               .odd = { { -5, 9, 100, 7, 34, -10, 0 },
+                        { -1, -7, 86, 7, 62, -12, 0 },
+                        { 0, -12, 62, 7, 86, -7, -1 },
+                        { 0, -10, 34, 7, 100, 9, -5 } } },
+       .ver_phase_arr = {
+               .even = { { -8, 21, 102, 7, 21, -8, 0 },
+                        { -3, 0, 95, 7, 48, -12, 0 },
+                        { 0, -11, 75, 7, 75, -11, 0 },
+                        { 0, -12, 48, 7, 95, 0, -3 } },
+               .odd = { { -5, 9, 100, 7, 34, -10, 0 },
+                        { -1, -7, 86, 7, 62, -12, 0 },
+                        { 0, -12, 62, 7, 86, -7, -1 },
+                        { 0, -10, 34, 7, 100, 9, -5 } } },
+       .ptrn_arr = { { 0xff } },
+       .sample_patrn_length = 10,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 9) = 0.780488 */
+       .hor_phase_arr = {
+               .even = { { -9, 23, 100, 7, 23, -9, 0 },
+                        { -3, 0, 91, 7, 52, -12, 0 },
+                        { 0, -11, 68, 7, 80, -8, -1 },
+                        { 0, -11, 39, 7, 96, 9, -5 },
+                        { -6, 12, 98, 7, 35, -11, 0 },
+                        { -1, -6, 81, 7, 65, -11, 0 },
+                        { 0, -12, 55, 7, 89, -2, -2 },
+                        { 0, -9, 26, 7, 99, 20, -8 },
+                        { -4, 2, 93, 7, 49, -12, 0 },
+                        { 0, -10, 71, 7, 76, -9, 0 },
+                        { 0, -11, 42, 7, 95, 7, -5 },
+                        { -7, 14, 99, 7, 32, -10, 0 },
+                        { -1, -5, 84, 7, 62, -12, 0 },
+                        { 0, -12, 59, 7, 87, -4, -2 },
+                        { 0, -10, 29, 7, 99, 17, -7 },
+                        { -4, 4, 95, 7, 45, -12, 0 },
+                        { 0, -9, 72, 7, 74, -9, 0 },
+                        { 0, -12, 45, 7, 95, 4, -4 },
+                        { -7, 17, 99, 7, 29, -10, 0 },
+                        { -2, -4, 87, 7, 59, -12, 0 },
+                        { 0, -12, 62, 7, 84, -5, -1 },
+                        { 0, -10, 32, 7, 99, 14, -7 },
+                        { -5, 7, 95, 7, 42, -11, 0 },
+                        { 0, -9, 76, 7, 71, -10, 0 },
+                        { 0, -12, 49, 7, 93, 2, -4 },
+                        { -8, 20, 99, 7, 26, -9, 0 },
+                        { -2, -2, 89, 7, 55, -12, 0 },
+                        { 0, -11, 65, 7, 81, -6, -1 },
+                        { 0, -11, 35, 7, 98, 12, -6 },
+                        { -5, 9, 96, 7, 39, -11, 0 },
+                        { -1, -8, 80, 7, 68, -11, 0 },
+                        { 0, -12, 52, 7, 91, 0, -3 } },
+               .odd = { { -6, 10, 98, 7, 37, -11, 0 },
+                        { -1, -7, 81, 7, 66, -11, 0 },
+                        { 0, -12, 54, 7, 90, -1, -3 },
+                        { 0, -9, 24, 7, 100, 21, -8 },
+                        { -3, 1, 92, 7, 50, -12, 0 },
+                        { 0, -10, 69, 7, 78, -8, -1 },
+                        { 0, -11, 40, 7, 96, 8, -5 },
+                        { -6, 13, 97, 7, 34, -10, 0 },
+                        { -1, -6, 83, 7, 63, -11, 0 },
+                        { 0, -12, 57, 7, 88, -3, -2 },
+                        { 0, -9, 27, 7, 100, 18, -8 },
+                        { -4, 3, 94, 7, 47, -12, 0 },
+                        { 0, -10, 72, 7, 75, -9, 0 },
+                        { 0, -11, 44, 7, 95, 5, -5 },
+                        { -7, 16, 98, 7, 31, -10, 0 },
+                        { -2, -4, 86, 7, 60, -12, 0 },
+                        { 0, -12, 60, 7, 86, -4, -2 },
+                        { 0, -10, 31, 7, 98, 16, -7 },
+                        { -5, 5, 95, 7, 44, -11, 0 },
+                        { 0, -9, 75, 7, 72, -10, 0 },
+                        { 0, -12, 47, 7, 94, 3, -4 },
+                        { -8, 18, 100, 7, 27, -9, 0 },
+                        { -2, -3, 88, 7, 57, -12, 0 },
+                        { 0, -11, 63, 7, 83, -6, -1 },
+                        { 0, -10, 34, 7, 97, 13, -6 },
+                        { -5, 8, 96, 7, 40, -11, 0 },
+                        { -1, -8, 78, 7, 69, -10, 0 },
+                        { 0, -12, 50, 7, 92, 1, -3 },
+                        { -8, 21, 100, 7, 24, -9, 0 },
+                        { -3, -1, 90, 7, 54, -12, 0 },
+                        { 0, -11, 66, 7, 81, -7, -1 },
+                        { 0, -11, 37, 7, 98, 10, -6 } } },
+       .ver_phase_arr = {
+               .even = { { -9, 23, 100, 7, 23, -9, 0 },
+                        { -3, 0, 91, 7, 52, -12, 0 },
+                        { 0, -11, 68, 7, 80, -8, -1 },
+                        { 0, -11, 39, 7, 96, 9, -5 },
+                        { -6, 12, 98, 7, 35, -11, 0 },
+                        { -1, -6, 81, 7, 65, -11, 0 },
+                        { 0, -12, 55, 7, 89, -2, -2 },
+                        { 0, -9, 26, 7, 99, 20, -8 },
+                        { -4, 2, 93, 7, 49, -12, 0 },
+                        { 0, -10, 71, 7, 76, -9, 0 },
+                        { 0, -11, 42, 7, 95, 7, -5 },
+                        { -7, 14, 99, 7, 32, -10, 0 },
+                        { -1, -5, 84, 7, 62, -12, 0 },
+                        { 0, -12, 59, 7, 87, -4, -2 },
+                        { 0, -10, 29, 7, 99, 17, -7 },
+                        { -4, 4, 95, 7, 45, -12, 0 },
+                        { 0, -9, 72, 7, 74, -9, 0 },
+                        { 0, -12, 45, 7, 95, 4, -4 },
+                        { -7, 17, 99, 7, 29, -10, 0 },
+                        { -2, -4, 87, 7, 59, -12, 0 },
+                        { 0, -12, 62, 7, 84, -5, -1 },
+                        { 0, -10, 32, 7, 99, 14, -7 },
+                        { -5, 7, 95, 7, 42, -11, 0 },
+                        { 0, -9, 76, 7, 71, -10, 0 },
+                        { 0, -12, 49, 7, 93, 2, -4 },
+                        { -8, 20, 99, 7, 26, -9, 0 },
+                        { -2, -2, 89, 7, 55, -12, 0 },
+                        { 0, -11, 65, 7, 81, -6, -1 },
+                        { 0, -11, 35, 7, 98, 12, -6 },
+                        { -5, 9, 96, 7, 39, -11, 0 },
+                        { -1, -8, 80, 7, 68, -11, 0 },
+                        { 0, -12, 52, 7, 91, 0, -3 } },
+               .odd = { { -6, 10, 98, 7, 37, -11, 0 },
+                        { -1, -7, 81, 7, 66, -11, 0 },
+                        { 0, -12, 54, 7, 90, -1, -3 },
+                        { 0, -9, 24, 7, 100, 21, -8 },
+                        { -3, 1, 92, 7, 50, -12, 0 },
+                        { 0, -10, 69, 7, 78, -8, -1 },
+                        { 0, -11, 40, 7, 96, 8, -5 },
+                        { -6, 13, 97, 7, 34, -10, 0 },
+                        { -1, -6, 83, 7, 63, -11, 0 },
+                        { 0, -12, 57, 7, 88, -3, -2 },
+                        { 0, -9, 27, 7, 100, 18, -8 },
+                        { -4, 3, 94, 7, 47, -12, 0 },
+                        { 0, -10, 72, 7, 75, -9, 0 },
+                        { 0, -11, 44, 7, 95, 5, -5 },
+                        { -7, 16, 98, 7, 31, -10, 0 },
+                        { -2, -4, 86, 7, 60, -12, 0 },
+                        { 0, -12, 60, 7, 86, -4, -2 },
+                        { 0, -10, 31, 7, 98, 16, -7 },
+                        { -5, 5, 95, 7, 44, -11, 0 },
+                        { 0, -9, 75, 7, 72, -10, 0 },
+                        { 0, -12, 47, 7, 94, 3, -4 },
+                        { -8, 18, 100, 7, 27, -9, 0 },
+                        { -2, -3, 88, 7, 57, -12, 0 },
+                        { 0, -11, 63, 7, 83, -6, -1 },
+                        { 0, -10, 34, 7, 97, 13, -6 },
+                        { -5, 8, 96, 7, 40, -11, 0 },
+                        { -1, -8, 78, 7, 69, -10, 0 },
+                        { 0, -12, 50, 7, 92, 1, -3 },
+                        { -8, 21, 100, 7, 24, -9, 0 },
+                        { -3, -1, 90, 7, 54, -12, 0 },
+                        { 0, -11, 66, 7, 81, -7, -1 },
+                        { 0, -11, 37, 7, 98, 10, -6 } } },
+       .ptrn_arr = { { 0xf3f9fcff, 0x3f9fcfe7, 0xfe7f } },
+       .sample_patrn_length = 82,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 10) = 0.761905 */
+       .hor_phase_arr = {
+               .even = { { -9, 25, 96, 7, 25, -9, 0 },
+                        { -3, 0, 86, 7, 56, -11, 0 },
+                        { 0, -11, 62, 7, 82, -3, -2 },
+                        { 0, -10, 31, 7, 96, 19, -8 },
+                        { -5, 4, 92, 7, 49, -12, 0 },
+                        { 0, -10, 67, 7, 78, -6, -1 },
+                        { 0, -11, 37, 7, 95, 14, -7 },
+                        { -6, 9, 93, 7, 43, -11, 0 },
+                        { -1, -8, 73, 7, 73, -8, -1 },
+                        { 0, -11, 43, 7, 93, 9, -6 },
+                        { -7, 14, 95, 7, 37, -11, 0 },
+                        { -1, -6, 78, 7, 67, -10, 0 },
+                        { 0, -12, 49, 7, 92, 4, -5 },
+                        { -8, 19, 96, 7, 31, -10, 0 },
+                        { -2, -3, 82, 7, 62, -11, 0 },
+                        { 0, -11, 56, 7, 86, 0, -3 } },
+               .odd = { { -6, 11, 94, 7, 40, -11, 0 },
+                        { -1, -7, 75, 7, 70, -9, 0 },
+                        { 0, -12, 46, 7, 93, 6, -5 },
+                        { -8, 16, 97, 7, 34, -11, 0 },
+                        { -2, -5, 81, 7, 64, -10, 0 },
+                        { 0, -12, 53, 7, 89, 2, -4 },
+                        { -9, 22, 97, 7, 28, -10, 0 },
+                        { -3, -2, 85, 7, 59, -11, 0 },
+                        { 0, -11, 59, 7, 85, -2, -3 },
+                        { 0, -10, 28, 7, 97, 22, -9 },
+                        { -4, 2, 89, 7, 53, -12, 0 },
+                        { 0, -10, 64, 7, 81, -5, -2 },
+                        { 0, -11, 34, 7, 97, 16, -8 },
+                        { -5, 6, 93, 7, 46, -12, 0 },
+                        { 0, -9, 70, 7, 75, -7, -1 },
+                        { 0, -11, 40, 7, 94, 11, -6 } } },
+       .ver_phase_arr = {
+               .even = { { -9, 25, 96, 7, 25, -9, 0 },
+                        { -3, 0, 86, 7, 56, -11, 0 },
+                        { 0, -11, 62, 7, 82, -3, -2 },
+                        { 0, -10, 31, 7, 96, 19, -8 },
+                        { -5, 4, 92, 7, 49, -12, 0 },
+                        { 0, -10, 67, 7, 78, -6, -1 },
+                        { 0, -11, 37, 7, 95, 14, -7 },
+                        { -6, 9, 93, 7, 43, -11, 0 },
+                        { -1, -8, 73, 7, 73, -8, -1 },
+                        { 0, -11, 43, 7, 93, 9, -6 },
+                        { -7, 14, 95, 7, 37, -11, 0 },
+                        { -1, -6, 78, 7, 67, -10, 0 },
+                        { 0, -12, 49, 7, 92, 4, -5 },
+                        { -8, 19, 96, 7, 31, -10, 0 },
+                        { -2, -3, 82, 7, 62, -11, 0 },
+                        { 0, -11, 56, 7, 86, 0, -3 } },
+               .odd = { { -6, 11, 94, 7, 40, -11, 0 },
+                        { -1, -7, 75, 7, 70, -9, 0 },
+                        { 0, -12, 46, 7, 93, 6, -5 },
+                        { -8, 16, 97, 7, 34, -11, 0 },
+                        { -2, -5, 81, 7, 64, -10, 0 },
+                        { 0, -12, 53, 7, 89, 2, -4 },
+                        { -9, 22, 97, 7, 28, -10, 0 },
+                        { -3, -2, 85, 7, 59, -11, 0 },
+                        { 0, -11, 59, 7, 85, -2, -3 },
+                        { 0, -10, 28, 7, 97, 22, -9 },
+                        { -4, 2, 89, 7, 53, -12, 0 },
+                        { 0, -10, 64, 7, 81, -5, -2 },
+                        { 0, -11, 34, 7, 97, 16, -8 },
+                        { -5, 6, 93, 7, 46, -12, 0 },
+                        { 0, -9, 70, 7, 75, -7, -1 },
+                        { 0, -11, 40, 7, 94, 11, -6 } } },
+       .ptrn_arr = { { 0xfcfe7e7f, 0xfc } },
+       .sample_patrn_length = 42,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 11) = 0.744186 */
+       .hor_phase_arr = {
+               .even = { { -10, 26, 96, 7, 26, -10, 0 },
+                        { -4, 0, 83, 7, 59, -10, 0 },
+                        { 0, -11, 56, 7, 85, 2, -4 },
+                        { -9, 23, 95, 7, 29, -10, 0 },
+                        { -3, -2, 82, 7, 61, -10, 0 },
+                        { 0, -11, 53, 7, 87, 4, -5 },
+                        { -9, 21, 94, 7, 32, -10, 0 },
+                        { -3, -3, 79, 7, 64, -9, 0 },
+                        { 0, -11, 50, 7, 88, 6, -5 },
+                        { -8, 18, 94, 7, 35, -11, 0 },
+                        { -2, -5, 78, 7, 67, -9, -1 },
+                        { 0, -11, 47, 7, 90, 8, -6 },
+                        { -8, 15, 94, 7, 38, -11, 0 },
+                        { -2, -6, 75, 7, 70, -8, -1 },
+                        { 0, -11, 44, 7, 92, 10, -7 },
+                        { -7, 13, 92, 7, 41, -11, 0 },
+                        { -1, -7, 72, 7, 72, -7, -1 },
+                        { 0, -11, 41, 7, 92, 13, -7 },
+                        { -7, 10, 92, 7, 44, -11, 0 },
+                        { -1, -8, 70, 7, 75, -6, -2 },
+                        { 0, -11, 38, 7, 94, 15, -8 },
+                        { -6, 8, 90, 7, 47, -11, 0 },
+                        { -1, -9, 67, 7, 78, -5, -2 },
+                        { 0, -11, 35, 7, 94, 18, -8 },
+                        { -5, 6, 88, 7, 50, -11, 0 },
+                        { 0, -9, 64, 7, 79, -3, -3 },
+                        { 0, -10, 32, 7, 94, 21, -9 },
+                        { -5, 4, 87, 7, 53, -11, 0 },
+                        { 0, -10, 61, 7, 82, -2, -3 },
+                        { 0, -10, 29, 7, 95, 23, -9 },
+                        { -4, 2, 85, 7, 56, -11, 0 },
+                        { 0, -10, 59, 7, 83, 0, -4 } },
+               .odd = { { -7, 12, 92, 7, 42, -11, 0 },
+                        { -1, -7, 71, 7, 72, -6, -1 },
+                        { 0, -11, 39, 7, 93, 14, -7 },
+                        { -6, 9, 91, 7, 45, -11, 0 },
+                        { -1, -8, 68, 7, 76, -5, -2 },
+                        { 0, -11, 36, 7, 94, 17, -8 },
+                        { -6, 7, 90, 7, 48, -11, 0 },
+                        { 0, -9, 66, 7, 77, -4, -2 },
+                        { 0, -11, 33, 7, 96, 19, -9 },
+                        { -5, 5, 88, 7, 51, -11, 0 },
+                        { 0, -10, 63, 7, 80, -2, -3 },
+                        { 0, -10, 31, 7, 94, 22, -9 },
+                        { -5, 3, 87, 7, 54, -11, 0 },
+                        { 0, -10, 60, 7, 82, -1, -3 },
+                        { 0, -10, 28, 7, 94, 25, -9 },
+                        { -4, 1, 85, 7, 57, -11, 0 },
+                        { 0, -11, 57, 7, 85, 1, -4 },
+                        { -9, 25, 94, 7, 28, -10, 0 },
+                        { -3, -1, 82, 7, 60, -10, 0 },
+                        { 0, -11, 54, 7, 87, 3, -5 },
+                        { -9, 22, 94, 7, 31, -10, 0 },
+                        { -3, -2, 80, 7, 63, -10, 0 },
+                        { 0, -11, 51, 7, 88, 5, -5 },
+                        { -9, 19, 96, 7, 33, -11, 0 },
+                        { -2, -4, 77, 7, 66, -9, 0 },
+                        { 0, -11, 48, 7, 90, 7, -6 },
+                        { -8, 17, 94, 7, 36, -11, 0 },
+                        { -2, -5, 76, 7, 68, -8, -1 },
+                        { 0, -11, 45, 7, 91, 9, -6 },
+                        { -7, 14, 93, 7, 39, -11, 0 },
+                        { -1, -6, 72, 7, 71, -7, -1 },
+                        { 0, -11, 42, 7, 92, 12, -7 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 26, 96, 7, 26, -10, 0 },
+                        { -4, 0, 83, 7, 59, -10, 0 },
+                        { 0, -11, 56, 7, 85, 2, -4 },
+                        { -9, 23, 95, 7, 29, -10, 0 },
+                        { -3, -2, 82, 7, 61, -10, 0 },
+                        { 0, -11, 53, 7, 87, 4, -5 },
+                        { -9, 21, 94, 7, 32, -10, 0 },
+                        { -3, -3, 79, 7, 64, -9, 0 },
+                        { 0, -11, 50, 7, 88, 6, -5 },
+                        { -8, 18, 94, 7, 35, -11, 0 },
+                        { -2, -5, 78, 7, 67, -9, -1 },
+                        { 0, -11, 47, 7, 90, 8, -6 },
+                        { -8, 15, 94, 7, 38, -11, 0 },
+                        { -2, -6, 75, 7, 70, -8, -1 },
+                        { 0, -11, 44, 7, 92, 10, -7 },
+                        { -7, 13, 92, 7, 41, -11, 0 },
+                        { -1, -7, 72, 7, 72, -7, -1 },
+                        { 0, -11, 41, 7, 92, 13, -7 },
+                        { -7, 10, 92, 7, 44, -11, 0 },
+                        { -1, -8, 70, 7, 75, -6, -2 },
+                        { 0, -11, 38, 7, 94, 15, -8 },
+                        { -6, 8, 90, 7, 47, -11, 0 },
+                        { -1, -9, 67, 7, 78, -5, -2 },
+                        { 0, -11, 35, 7, 94, 18, -8 },
+                        { -5, 6, 88, 7, 50, -11, 0 },
+                        { 0, -9, 64, 7, 79, -3, -3 },
+                        { 0, -10, 32, 7, 94, 21, -9 },
+                        { -5, 4, 87, 7, 53, -11, 0 },
+                        { 0, -10, 61, 7, 82, -2, -3 },
+                        { 0, -10, 29, 7, 95, 23, -9 },
+                        { -4, 2, 85, 7, 56, -11, 0 },
+                        { 0, -10, 59, 7, 83, 0, -4 } },
+               .odd = { { -7, 12, 92, 7, 42, -11, 0 },
+                        { -1, -7, 71, 7, 72, -6, -1 },
+                        { 0, -11, 39, 7, 93, 14, -7 },
+                        { -6, 9, 91, 7, 45, -11, 0 },
+                        { -1, -8, 68, 7, 76, -5, -2 },
+                        { 0, -11, 36, 7, 94, 17, -8 },
+                        { -6, 7, 90, 7, 48, -11, 0 },
+                        { 0, -9, 66, 7, 77, -4, -2 },
+                        { 0, -11, 33, 7, 96, 19, -9 },
+                        { -5, 5, 88, 7, 51, -11, 0 },
+                        { 0, -10, 63, 7, 80, -2, -3 },
+                        { 0, -10, 31, 7, 94, 22, -9 },
+                        { -5, 3, 87, 7, 54, -11, 0 },
+                        { 0, -10, 60, 7, 82, -1, -3 },
+                        { 0, -10, 28, 7, 94, 25, -9 },
+                        { -4, 1, 85, 7, 57, -11, 0 },
+                        { 0, -11, 57, 7, 85, 1, -4 },
+                        { -9, 25, 94, 7, 28, -10, 0 },
+                        { -3, -1, 82, 7, 60, -10, 0 },
+                        { 0, -11, 54, 7, 87, 3, -5 },
+                        { -9, 22, 94, 7, 31, -10, 0 },
+                        { -3, -2, 80, 7, 63, -10, 0 },
+                        { 0, -11, 51, 7, 88, 5, -5 },
+                        { -9, 19, 96, 7, 33, -11, 0 },
+                        { -2, -4, 77, 7, 66, -9, 0 },
+                        { 0, -11, 48, 7, 90, 7, -6 },
+                        { -8, 17, 94, 7, 36, -11, 0 },
+                        { -2, -5, 76, 7, 68, -8, -1 },
+                        { 0, -11, 45, 7, 91, 9, -6 },
+                        { -7, 14, 93, 7, 39, -11, 0 },
+                        { -1, -6, 72, 7, 71, -7, -1 },
+                        { 0, -11, 42, 7, 92, 12, -7 } } },
+       .ptrn_arr = { { 0x3f3f3f3f, 0x9f9f9f3f, 0xf9f9f } },
+       .sample_patrn_length = 86,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 12) = 0.727273 */
+       .hor_phase_arr = {
+               .even = { { -10, 28, 92, 7, 28, -10, 0 },
+                        { -4, 0, 81, 7, 61, -9, -1 },
+                        { 0, -11, 50, 7, 87, 8, -6 },
+                        { -8, 17, 91, 7, 39, -11, 0 },
+                        { -2, -6, 72, 7, 72, -6, -2 },
+                        { 0, -11, 39, 7, 91, 17, -8 },
+                        { -6, 8, 87, 7, 50, -11, 0 },
+                        { -1, -9, 61, 7, 81, 0, -4 } },
+               .odd = { { -7, 12, 89, 7, 45, -11, 0 },
+                        { -1, -8, 67, 7, 76, -3, -3 },
+                        { 0, -11, 33, 7, 93, 22, -9 },
+                        { -5, 4, 83, 7, 56, -10, 0 },
+                        { 0, -10, 56, 7, 83, 4, -5 },
+                        { -9, 22, 93, 7, 33, -11, 0 },
+                        { -3, -3, 76, 7, 67, -8, -1 },
+                        { 0, -11, 45, 7, 89, 12, -7 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 28, 92, 7, 28, -10, 0 },
+                        { -4, 0, 81, 7, 61, -9, -1 },
+                        { 0, -11, 50, 7, 87, 8, -6 },
+                        { -8, 17, 91, 7, 39, -11, 0 },
+                        { -2, -6, 72, 7, 72, -6, -2 },
+                        { 0, -11, 39, 7, 91, 17, -8 },
+                        { -6, 8, 87, 7, 50, -11, 0 },
+                        { -1, -9, 61, 7, 81, 0, -4 } },
+               .odd = { { -7, 12, 89, 7, 45, -11, 0 },
+                        { -1, -8, 67, 7, 76, -3, -3 },
+                        { 0, -11, 33, 7, 93, 22, -9 },
+                        { -5, 4, 83, 7, 56, -10, 0 },
+                        { 0, -10, 56, 7, 83, 4, -5 },
+                        { -9, 22, 93, 7, 33, -11, 0 },
+                        { -3, -3, 76, 7, 67, -8, -1 },
+                        { 0, -11, 45, 7, 89, 12, -7 } } },
+       .ptrn_arr = { { 0xf9f3f } },
+       .sample_patrn_length = 22,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 13) = 0.711111 */
+       .hor_phase_arr = {
+               .even = { { -10, 29, 90, 7, 29, -10, 0 },
+                        { -4, 0, 76, 7, 64, -7, -1 },
+                        { 0, -11, 45, 7, 88, 14, -8 },
+                        { -7, 12, 85, 7, 48, -10, 0 },
+                        { -1, -8, 61, 7, 79, 2, -5 },
+                        { -10, 26, 90, 7, 32, -10, 0 },
+                        { -4, -2, 76, 7, 66, -6, -2 },
+                        { 0, -11, 42, 7, 89, 16, -8 },
+                        { -7, 10, 84, 7, 51, -10, 0 },
+                        { -1, -9, 59, 7, 81, 3, -5 },
+                        { -10, 24, 91, 7, 34, -11, 0 },
+                        { -3, -3, 72, 7, 69, -5, -2 },
+                        { 0, -11, 40, 7, 89, 19, -9 },
+                        { -6, 7, 84, 7, 53, -10, 0 },
+                        { -1, -9, 56, 7, 83, 5, -6 },
+                        { -9, 21, 90, 7, 37, -11, 0 },
+                        { -3, -4, 71, 7, 71, -4, -3 },
+                        { 0, -11, 37, 7, 90, 21, -9 },
+                        { -6, 5, 83, 7, 56, -9, -1 },
+                        { 0, -10, 53, 7, 84, 7, -6 },
+                        { -9, 19, 89, 7, 40, -11, 0 },
+                        { -2, -5, 69, 7, 72, -3, -3 },
+                        { 0, -11, 34, 7, 91, 24, -10 },
+                        { -5, 3, 81, 7, 59, -9, -1 },
+                        { 0, -10, 51, 7, 84, 10, -7 },
+                        { -8, 16, 89, 7, 42, -11, 0 },
+                        { -2, -6, 66, 7, 76, -2, -4 },
+                        { 0, -10, 32, 7, 90, 26, -10 },
+                        { -5, 2, 79, 7, 61, -8, -1 },
+                        { 0, -10, 48, 7, 85, 12, -7 },
+                        { -8, 14, 88, 7, 45, -11, 0 },
+                        { -1, -7, 64, 7, 76, 0, -4 } },
+               .odd = { { -8, 13, 88, 7, 46, -11, 0 },
+                        { -1, -8, 63, 7, 78, 1, -5 },
+                        { -10, 28, 90, 7, 30, -10, 0 },
+                        { -4, -1, 77, 7, 65, -7, -2 },
+                        { 0, -11, 44, 7, 88, 15, -8 },
+                        { -7, 11, 85, 7, 49, -10, 0 },
+                        { -1, -8, 60, 7, 79, 3, -5 },
+                        { -10, 25, 91, 7, 33, -11, 0 },
+                        { -4, -2, 74, 7, 68, -6, -2 },
+                        { 0, -11, 41, 7, 89, 18, -9 },
+                        { -7, 8, 85, 7, 52, -10, 0 },
+                        { -1, -9, 57, 7, 83, 4, -6 },
+                        { -9, 22, 90, 7, 36, -11, 0 },
+                        { -3, -4, 73, 7, 70, -5, -3 },
+                        { 0, -11, 38, 7, 90, 20, -9 },
+                        { -6, 6, 83, 7, 55, -10, 0 },
+                        { 0, -10, 55, 7, 83, 6, -6 },
+                        { -9, 20, 90, 7, 38, -11, 0 },
+                        { -3, -5, 70, 7, 73, -4, -3 },
+                        { 0, -11, 36, 7, 90, 22, -9 },
+                        { -6, 4, 83, 7, 57, -9, -1 },
+                        { 0, -10, 52, 7, 85, 8, -7 },
+                        { -9, 18, 89, 7, 41, -11, 0 },
+                        { -2, -6, 68, 7, 74, -2, -4 },
+                        { 0, -11, 33, 7, 91, 25, -10 },
+                        { -5, 3, 79, 7, 60, -8, -1 },
+                        { 0, -10, 49, 7, 85, 11, -7 },
+                        { -8, 15, 88, 7, 44, -11, 0 },
+                        { -2, -7, 65, 7, 77, -1, -4 },
+                        { 0, -10, 30, 7, 90, 28, -10 },
+                        { -5, 1, 78, 7, 63, -8, -1 },
+                        { 0, -11, 46, 7, 88, 13, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 29, 90, 7, 29, -10, 0 },
+                        { -4, 0, 76, 7, 64, -7, -1 },
+                        { 0, -11, 45, 7, 88, 14, -8 },
+                        { -7, 12, 85, 7, 48, -10, 0 },
+                        { -1, -8, 61, 7, 79, 2, -5 },
+                        { -10, 26, 90, 7, 32, -10, 0 },
+                        { -4, -2, 76, 7, 66, -6, -2 },
+                        { 0, -11, 42, 7, 89, 16, -8 },
+                        { -7, 10, 84, 7, 51, -10, 0 },
+                        { -1, -9, 59, 7, 81, 3, -5 },
+                        { -10, 24, 91, 7, 34, -11, 0 },
+                        { -3, -3, 72, 7, 69, -5, -2 },
+                        { 0, -11, 40, 7, 89, 19, -9 },
+                        { -6, 7, 84, 7, 53, -10, 0 },
+                        { -1, -9, 56, 7, 83, 5, -6 },
+                        { -9, 21, 90, 7, 37, -11, 0 },
+                        { -3, -4, 71, 7, 71, -4, -3 },
+                        { 0, -11, 37, 7, 90, 21, -9 },
+                        { -6, 5, 83, 7, 56, -9, -1 },
+                        { 0, -10, 53, 7, 84, 7, -6 },
+                        { -9, 19, 89, 7, 40, -11, 0 },
+                        { -2, -5, 69, 7, 72, -3, -3 },
+                        { 0, -11, 34, 7, 91, 24, -10 },
+                        { -5, 3, 81, 7, 59, -9, -1 },
+                        { 0, -10, 51, 7, 84, 10, -7 },
+                        { -8, 16, 89, 7, 42, -11, 0 },
+                        { -2, -6, 66, 7, 76, -2, -4 },
+                        { 0, -10, 32, 7, 90, 26, -10 },
+                        { -5, 2, 79, 7, 61, -8, -1 },
+                        { 0, -10, 48, 7, 85, 12, -7 },
+                        { -8, 14, 88, 7, 45, -11, 0 },
+                        { -1, -7, 64, 7, 76, 0, -4 } },
+               .odd = { { -8, 13, 88, 7, 46, -11, 0 },
+                        { -1, -8, 63, 7, 78, 1, -5 },
+                        { -10, 28, 90, 7, 30, -10, 0 },
+                        { -4, -1, 77, 7, 65, -7, -2 },
+                        { 0, -11, 44, 7, 88, 15, -8 },
+                        { -7, 11, 85, 7, 49, -10, 0 },
+                        { -1, -8, 60, 7, 79, 3, -5 },
+                        { -10, 25, 91, 7, 33, -11, 0 },
+                        { -4, -2, 74, 7, 68, -6, -2 },
+                        { 0, -11, 41, 7, 89, 18, -9 },
+                        { -7, 8, 85, 7, 52, -10, 0 },
+                        { -1, -9, 57, 7, 83, 4, -6 },
+                        { -9, 22, 90, 7, 36, -11, 0 },
+                        { -3, -4, 73, 7, 70, -5, -3 },
+                        { 0, -11, 38, 7, 90, 20, -9 },
+                        { -6, 6, 83, 7, 55, -10, 0 },
+                        { 0, -10, 55, 7, 83, 6, -6 },
+                        { -9, 20, 90, 7, 38, -11, 0 },
+                        { -3, -5, 70, 7, 73, -4, -3 },
+                        { 0, -11, 36, 7, 90, 22, -9 },
+                        { -6, 4, 83, 7, 57, -9, -1 },
+                        { 0, -10, 52, 7, 85, 8, -7 },
+                        { -9, 18, 89, 7, 41, -11, 0 },
+                        { -2, -6, 68, 7, 74, -2, -4 },
+                        { 0, -11, 33, 7, 91, 25, -10 },
+                        { -5, 3, 79, 7, 60, -8, -1 },
+                        { 0, -10, 49, 7, 85, 11, -7 },
+                        { -8, 15, 88, 7, 44, -11, 0 },
+                        { -2, -7, 65, 7, 77, -1, -4 },
+                        { 0, -10, 30, 7, 90, 28, -10 },
+                        { -5, 1, 78, 7, 63, -8, -1 },
+                        { 0, -11, 46, 7, 88, 13, -8 } } },
+       .ptrn_arr = { { 0xf3e7cf9f, 0x9f3e7cf9, 0xf3e7cf } },
+       .sample_patrn_length = 90,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 14) = 0.695652 */
+       .hor_phase_arr = {
+               .even = { { -10, 30, 88, 7, 30, -10, 0 },
+                        { -5, 0, 75, 7, 66, -5, -3 },
+                        { 0, -10, 40, 7, 87, 20, -9 },
+                        { -7, 7, 81, 7, 56, -8, -1 },
+                        { 0, -9, 51, 7, 83, 11, -8 },
+                        { -8, 16, 84, 7, 46, -10, 0 },
+                        { -2, -7, 61, 7, 79, 3, -6 },
+                        { -10, 25, 88, 7, 35, -10, 0 },
+                        { -4, -3, 72, 7, 70, -3, -4 },
+                        { 0, -10, 35, 7, 88, 25, -10 },
+                        { -6, 3, 79, 7, 61, -7, -2 },
+                        { 0, -10, 46, 7, 84, 16, -8 },
+                        { -8, 11, 83, 7, 51, -9, 0 },
+                        { -1, -8, 56, 7, 81, 7, -7 },
+                        { -9, 20, 87, 7, 40, -10, 0 },
+                        { -3, -5, 66, 7, 75, 0, -5 } },
+               .odd = { { -8, 13, 85, 7, 48, -10, 0 },
+                        { -1, -8, 59, 7, 79, 5, -6 },
+                        { -10, 23, 87, 7, 38, -10, 0 },
+                        { -3, -4, 68, 7, 72, -1, -4 },
+                        { 0, -10, 33, 7, 87, 28, -10 },
+                        { -5, 2, 75, 7, 64, -6, -2 },
+                        { 0, -10, 43, 7, 86, 18, -9 },
+                        { -7, 9, 83, 7, 53, -9, -1 },
+                        { -1, -9, 53, 7, 83, 9, -7 },
+                        { -9, 18, 86, 7, 43, -10, 0 },
+                        { -2, -6, 64, 7, 75, 2, -5 },
+                        { -10, 28, 87, 7, 33, -10, 0 },
+                        { -4, -1, 72, 7, 68, -4, -3 },
+                        { 0, -10, 38, 7, 87, 23, -10 },
+                        { -6, 5, 79, 7, 59, -8, -1 },
+                        { 0, -10, 48, 7, 85, 13, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 30, 88, 7, 30, -10, 0 },
+                        { -5, 0, 75, 7, 66, -5, -3 },
+                        { 0, -10, 40, 7, 87, 20, -9 },
+                        { -7, 7, 81, 7, 56, -8, -1 },
+                        { 0, -9, 51, 7, 83, 11, -8 },
+                        { -8, 16, 84, 7, 46, -10, 0 },
+                        { -2, -7, 61, 7, 79, 3, -6 },
+                        { -10, 25, 88, 7, 35, -10, 0 },
+                        { -4, -3, 72, 7, 70, -3, -4 },
+                        { 0, -10, 35, 7, 88, 25, -10 },
+                        { -6, 3, 79, 7, 61, -7, -2 },
+                        { 0, -10, 46, 7, 84, 16, -8 },
+                        { -8, 11, 83, 7, 51, -9, 0 },
+                        { -1, -8, 56, 7, 81, 7, -7 },
+                        { -9, 20, 87, 7, 40, -10, 0 },
+                        { -3, -5, 66, 7, 75, 0, -5 } },
+               .odd = { { -8, 13, 85, 7, 48, -10, 0 },
+                        { -1, -8, 59, 7, 79, 5, -6 },
+                        { -10, 23, 87, 7, 38, -10, 0 },
+                        { -3, -4, 68, 7, 72, -1, -4 },
+                        { 0, -10, 33, 7, 87, 28, -10 },
+                        { -5, 2, 75, 7, 64, -6, -2 },
+                        { 0, -10, 43, 7, 86, 18, -9 },
+                        { -7, 9, 83, 7, 53, -9, -1 },
+                        { -1, -9, 53, 7, 83, 9, -7 },
+                        { -9, 18, 86, 7, 43, -10, 0 },
+                        { -2, -6, 64, 7, 75, 2, -5 },
+                        { -10, 28, 87, 7, 33, -10, 0 },
+                        { -4, -1, 72, 7, 68, -4, -3 },
+                        { 0, -10, 38, 7, 87, 23, -10 },
+                        { -6, 5, 79, 7, 59, -8, -1 },
+                        { 0, -10, 48, 7, 85, 13, -8 } } },
+       .ptrn_arr = { { 0x79f3cf9f, 0xf3e } },
+       .sample_patrn_length = 46,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 15) = 0.680851 */
+       .hor_phase_arr = {
+               .even = { { -10, 31, 86, 7, 31, -10, 0 },
+                        { -5, 0, 72, 7, 68, -3, -4 },
+                        { 0, -10, 36, 7, 86, 26, -10 },
+                        { -6, 3, 76, 7, 63, -5, -3 },
+                        { 0, -10, 41, 7, 85, 21, -9 },
+                        { -7, 7, 78, 7, 59, -7, -2 },
+                        { 0, -10, 46, 7, 84, 17, -9 },
+                        { -8, 11, 80, 7, 54, -8, -1 },
+                        { -1, -9, 51, 7, 82, 13, -8 },
+                        { -9, 15, 83, 7, 49, -9, -1 },
+                        { -2, -8, 56, 7, 80, 9, -7 },
+                        { -9, 19, 85, 7, 43, -10, 0 },
+                        { -3, -6, 61, 7, 77, 5, -6 },
+                        { -10, 24, 86, 7, 38, -10, 0 },
+                        { -3, -4, 66, 7, 72, 2, -5 },
+                        { -10, 29, 86, 7, 33, -10, 0 },
+                        { -4, -1, 68, 7, 70, -1, -4 },
+                        { 0, -10, 33, 7, 86, 29, -10 },
+                        { -5, 2, 72, 7, 66, -4, -3 },
+                        { 0, -10, 38, 7, 86, 24, -10 },
+                        { -6, 5, 77, 7, 61, -6, -3 },
+                        { 0, -10, 43, 7, 85, 19, -9 },
+                        { -7, 9, 80, 7, 56, -8, -2 },
+                        { -1, -9, 49, 7, 83, 15, -9 },
+                        { -8, 13, 82, 7, 51, -9, -1 },
+                        { -1, -8, 54, 7, 80, 11, -8 },
+                        { -9, 17, 84, 7, 46, -10, 0 },
+                        { -2, -7, 59, 7, 78, 7, -7 },
+                        { -9, 21, 85, 7, 41, -10, 0 },
+                        { -3, -5, 63, 7, 76, 3, -6 },
+                        { -10, 26, 86, 7, 36, -10, 0 },
+                        { -4, -3, 68, 7, 72, 0, -5 } },
+               .odd = { { -8, 14, 82, 7, 50, -9, -1 },
+                        { -1, -8, 55, 7, 79, 10, -7 },
+                        { -9, 18, 84, 7, 45, -10, 0 },
+                        { -2, -6, 60, 7, 77, 6, -7 },
+                        { -10, 23, 85, 7, 40, -10, 0 },
+                        { -3, -4, 64, 7, 75, 2, -6 },
+                        { -10, 27, 86, 7, 35, -10, 0 },
+                        { -4, -2, 69, 7, 71, -1, -5 },
+                        { 0, -10, 32, 7, 86, 30, -10 },
+                        { -5, 1, 72, 7, 67, -3, -4 },
+                        { 0, -10, 37, 7, 86, 25, -10 },
+                        { -6, 4, 77, 7, 62, -6, -3 },
+                        { 0, -10, 42, 7, 85, 20, -9 },
+                        { -7, 8, 79, 7, 57, -7, -2 },
+                        { -1, -9, 47, 7, 84, 16, -9 },
+                        { -8, 12, 81, 7, 52, -8, -1 },
+                        { -1, -8, 52, 7, 81, 12, -8 },
+                        { -9, 16, 84, 7, 47, -9, -1 },
+                        { -2, -7, 57, 7, 79, 8, -7 },
+                        { -9, 20, 85, 7, 42, -10, 0 },
+                        { -3, -6, 62, 7, 77, 4, -6 },
+                        { -10, 25, 86, 7, 37, -10, 0 },
+                        { -4, -3, 67, 7, 72, 1, -5 },
+                        { -10, 30, 86, 7, 32, -10, 0 },
+                        { -5, -1, 71, 7, 69, -2, -4 },
+                        { 0, -10, 35, 7, 86, 27, -10 },
+                        { -6, 2, 75, 7, 64, -4, -3 },
+                        { 0, -10, 40, 7, 85, 23, -10 },
+                        { -7, 6, 77, 7, 60, -6, -2 },
+                        { 0, -10, 45, 7, 84, 18, -9 },
+                        { -7, 10, 79, 7, 55, -8, -1 },
+                        { -1, -9, 50, 7, 82, 14, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 31, 86, 7, 31, -10, 0 },
+                        { -5, 0, 72, 7, 68, -3, -4 },
+                        { 0, -10, 36, 7, 86, 26, -10 },
+                        { -6, 3, 76, 7, 63, -5, -3 },
+                        { 0, -10, 41, 7, 85, 21, -9 },
+                        { -7, 7, 78, 7, 59, -7, -2 },
+                        { 0, -10, 46, 7, 84, 17, -9 },
+                        { -8, 11, 80, 7, 54, -8, -1 },
+                        { -1, -9, 51, 7, 82, 13, -8 },
+                        { -9, 15, 83, 7, 49, -9, -1 },
+                        { -2, -8, 56, 7, 80, 9, -7 },
+                        { -9, 19, 85, 7, 43, -10, 0 },
+                        { -3, -6, 61, 7, 77, 5, -6 },
+                        { -10, 24, 86, 7, 38, -10, 0 },
+                        { -3, -4, 66, 7, 72, 2, -5 },
+                        { -10, 29, 86, 7, 33, -10, 0 },
+                        { -4, -1, 68, 7, 70, -1, -4 },
+                        { 0, -10, 33, 7, 86, 29, -10 },
+                        { -5, 2, 72, 7, 66, -4, -3 },
+                        { 0, -10, 38, 7, 86, 24, -10 },
+                        { -6, 5, 77, 7, 61, -6, -3 },
+                        { 0, -10, 43, 7, 85, 19, -9 },
+                        { -7, 9, 80, 7, 56, -8, -2 },
+                        { -1, -9, 49, 7, 83, 15, -9 },
+                        { -8, 13, 82, 7, 51, -9, -1 },
+                        { -1, -8, 54, 7, 80, 11, -8 },
+                        { -9, 17, 84, 7, 46, -10, 0 },
+                        { -2, -7, 59, 7, 78, 7, -7 },
+                        { -9, 21, 85, 7, 41, -10, 0 },
+                        { -3, -5, 63, 7, 76, 3, -6 },
+                        { -10, 26, 86, 7, 36, -10, 0 },
+                        { -4, -3, 68, 7, 72, 0, -5 } },
+               .odd = { { -8, 14, 82, 7, 50, -9, -1 },
+                        { -1, -8, 55, 7, 79, 10, -7 },
+                        { -9, 18, 84, 7, 45, -10, 0 },
+                        { -2, -6, 60, 7, 77, 6, -7 },
+                        { -10, 23, 85, 7, 40, -10, 0 },
+                        { -3, -4, 64, 7, 75, 2, -6 },
+                        { -10, 27, 86, 7, 35, -10, 0 },
+                        { -4, -2, 69, 7, 71, -1, -5 },
+                        { 0, -10, 32, 7, 86, 30, -10 },
+                        { -5, 1, 72, 7, 67, -3, -4 },
+                        { 0, -10, 37, 7, 86, 25, -10 },
+                        { -6, 4, 77, 7, 62, -6, -3 },
+                        { 0, -10, 42, 7, 85, 20, -9 },
+                        { -7, 8, 79, 7, 57, -7, -2 },
+                        { -1, -9, 47, 7, 84, 16, -9 },
+                        { -8, 12, 81, 7, 52, -8, -1 },
+                        { -1, -8, 52, 7, 81, 12, -8 },
+                        { -9, 16, 84, 7, 47, -9, -1 },
+                        { -2, -7, 57, 7, 79, 8, -7 },
+                        { -9, 20, 85, 7, 42, -10, 0 },
+                        { -3, -6, 62, 7, 77, 4, -6 },
+                        { -10, 25, 86, 7, 37, -10, 0 },
+                        { -4, -3, 67, 7, 72, 1, -5 },
+                        { -10, 30, 86, 7, 32, -10, 0 },
+                        { -5, -1, 71, 7, 69, -2, -4 },
+                        { 0, -10, 35, 7, 86, 27, -10 },
+                        { -6, 2, 75, 7, 64, -4, -3 },
+                        { 0, -10, 40, 7, 85, 23, -10 },
+                        { -7, 6, 77, 7, 60, -6, -2 },
+                        { 0, -10, 45, 7, 84, 18, -9 },
+                        { -7, 10, 79, 7, 55, -8, -1 },
+                        { -1, -9, 50, 7, 82, 14, -8 } } },
+       .ptrn_arr = { { 0x3cf9e79f, 0x9e79f3cf, 0xf3cf3e7 } },
+       .sample_patrn_length = 94,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 16) = 0.666667 */
+       .hor_phase_arr = {
+               .even = { { -10, 32, 84, 7, 32, -10, 0 },
+                        { -5, 0, 69, 7, 69, 0, -5 } },
+               .odd = { { -9, 14, 82, 7, 51, -8, -2 },
+                        { -2, -8, 51, 7, 82, 14, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 32, 84, 7, 32, -10, 0 },
+                        { -5, 0, 69, 7, 69, 0, -5 } },
+               .odd = { { -9, 14, 82, 7, 51, -8, -2 },
+                        { -2, -8, 51, 7, 82, 14, -9 } } },
+       .ptrn_arr = { { 0xf } },
+       .sample_patrn_length = 6,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 17) = 0.653061 */
+       .hor_phase_arr = {
+               .even = { { -10, 33, 82, 7, 33, -10, 0 },
+                        { -5, 0, 66, 7, 70, 3, -6 },
+                        { -10, 28, 82, 7, 37, -9, 0 },
+                        { -4, -3, 62, 7, 74, 6, -7 },
+                        { -10, 24, 82, 7, 42, -9, -1 },
+                        { -3, -5, 58, 7, 76, 10, -8 },
+                        { -9, 20, 79, 7, 47, -8, -1 },
+                        { -3, -6, 54, 7, 78, 14, -9 },
+                        { -9, 16, 79, 7, 51, -7, -2 },
+                        { -2, -8, 49, 7, 80, 18, -9 },
+                        { -8, 12, 77, 7, 56, -6, -3 },
+                        { -1, -9, 44, 7, 81, 22, -9 },
+                        { -7, 8, 75, 7, 60, -4, -4 },
+                        { -1, -9, 40, 7, 82, 26, -10 },
+                        { -7, 5, 71, 7, 65, -1, -5 },
+                        { 0, -10, 35, 7, 83, 30, -10 },
+                        { -6, 1, 70, 7, 68, 1, -6 },
+                        { -10, 30, 83, 7, 35, -10, 0 },
+                        { -5, -1, 65, 7, 71, 5, -7 },
+                        { -10, 26, 82, 7, 40, -9, -1 },
+                        { -4, -4, 60, 7, 75, 8, -7 },
+                        { -9, 22, 81, 7, 44, -9, -1 },
+                        { -3, -6, 56, 7, 77, 12, -8 },
+                        { -9, 18, 80, 7, 49, -8, -2 },
+                        { -2, -7, 51, 7, 79, 16, -9 },
+                        { -9, 14, 78, 7, 54, -6, -3 },
+                        { -1, -8, 47, 7, 79, 20, -9 },
+                        { -8, 10, 76, 7, 58, -5, -3 },
+                        { -1, -9, 42, 7, 82, 24, -10 },
+                        { -7, 6, 74, 7, 62, -3, -4 },
+                        { 0, -9, 37, 7, 82, 28, -10 },
+                        { -6, 3, 70, 7, 66, 0, -5 } },
+               .odd = { { -9, 15, 79, 7, 52, -7, -2 },
+                        { -2, -8, 48, 7, 80, 19, -9 },
+                        { -8, 11, 76, 7, 57, -5, -3 },
+                        { -1, -9, 43, 7, 82, 23, -10 },
+                        { -7, 7, 74, 7, 61, -3, -4 },
+                        { -1, -9, 38, 7, 83, 27, -10 },
+                        { -6, 4, 70, 7, 66, -1, -5 },
+                        { 0, -10, 34, 7, 83, 31, -10 },
+                        { -6, 1, 67, 7, 70, 2, -6 },
+                        { -10, 29, 83, 7, 36, -10, 0 },
+                        { -5, -2, 64, 7, 73, 5, -7 },
+                        { -10, 25, 82, 7, 41, -9, -1 },
+                        { -4, -4, 59, 7, 76, 9, -8 },
+                        { -9, 21, 80, 7, 45, -8, -1 },
+                        { -3, -6, 55, 7, 77, 13, -8 },
+                        { -9, 17, 79, 7, 50, -7, -2 },
+                        { -2, -7, 50, 7, 79, 17, -9 },
+                        { -8, 13, 77, 7, 55, -6, -3 },
+                        { -1, -8, 45, 7, 80, 21, -9 },
+                        { -8, 9, 76, 7, 59, -4, -4 },
+                        { -1, -9, 41, 7, 82, 25, -10 },
+                        { -7, 5, 73, 7, 64, -2, -5 },
+                        { 0, -10, 36, 7, 83, 29, -10 },
+                        { -6, 2, 70, 7, 67, 1, -6 },
+                        { -10, 31, 83, 7, 34, -10, 0 },
+                        { -5, -1, 66, 7, 70, 4, -6 },
+                        { -10, 27, 83, 7, 38, -9, -1 },
+                        { -4, -3, 61, 7, 74, 7, -7 },
+                        { -10, 23, 82, 7, 43, -9, -1 },
+                        { -3, -5, 57, 7, 76, 11, -8 },
+                        { -9, 19, 80, 7, 48, -8, -2 },
+                        { -2, -7, 52, 7, 79, 15, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -10, 33, 82, 7, 33, -10, 0 },
+                        { -5, 0, 66, 7, 70, 3, -6 },
+                        { -10, 28, 82, 7, 37, -9, 0 },
+                        { -4, -3, 62, 7, 74, 6, -7 },
+                        { -10, 24, 82, 7, 42, -9, -1 },
+                        { -3, -5, 58, 7, 76, 10, -8 },
+                        { -9, 20, 79, 7, 47, -8, -1 },
+                        { -3, -6, 54, 7, 78, 14, -9 },
+                        { -9, 16, 79, 7, 51, -7, -2 },
+                        { -2, -8, 49, 7, 80, 18, -9 },
+                        { -8, 12, 77, 7, 56, -6, -3 },
+                        { -1, -9, 44, 7, 81, 22, -9 },
+                        { -7, 8, 75, 7, 60, -4, -4 },
+                        { -1, -9, 40, 7, 82, 26, -10 },
+                        { -7, 5, 71, 7, 65, -1, -5 },
+                        { 0, -10, 35, 7, 83, 30, -10 },
+                        { -6, 1, 70, 7, 68, 1, -6 },
+                        { -10, 30, 83, 7, 35, -10, 0 },
+                        { -5, -1, 65, 7, 71, 5, -7 },
+                        { -10, 26, 82, 7, 40, -9, -1 },
+                        { -4, -4, 60, 7, 75, 8, -7 },
+                        { -9, 22, 81, 7, 44, -9, -1 },
+                        { -3, -6, 56, 7, 77, 12, -8 },
+                        { -9, 18, 80, 7, 49, -8, -2 },
+                        { -2, -7, 51, 7, 79, 16, -9 },
+                        { -9, 14, 78, 7, 54, -6, -3 },
+                        { -1, -8, 47, 7, 79, 20, -9 },
+                        { -8, 10, 76, 7, 58, -5, -3 },
+                        { -1, -9, 42, 7, 82, 24, -10 },
+                        { -7, 6, 74, 7, 62, -3, -4 },
+                        { 0, -9, 37, 7, 82, 28, -10 },
+                        { -6, 3, 70, 7, 66, 0, -5 } },
+               .odd = { { -9, 15, 79, 7, 52, -7, -2 },
+                        { -2, -8, 48, 7, 80, 19, -9 },
+                        { -8, 11, 76, 7, 57, -5, -3 },
+                        { -1, -9, 43, 7, 82, 23, -10 },
+                        { -7, 7, 74, 7, 61, -3, -4 },
+                        { -1, -9, 38, 7, 83, 27, -10 },
+                        { -6, 4, 70, 7, 66, -1, -5 },
+                        { 0, -10, 34, 7, 83, 31, -10 },
+                        { -6, 1, 67, 7, 70, 2, -6 },
+                        { -10, 29, 83, 7, 36, -10, 0 },
+                        { -5, -2, 64, 7, 73, 5, -7 },
+                        { -10, 25, 82, 7, 41, -9, -1 },
+                        { -4, -4, 59, 7, 76, 9, -8 },
+                        { -9, 21, 80, 7, 45, -8, -1 },
+                        { -3, -6, 55, 7, 77, 13, -8 },
+                        { -9, 17, 79, 7, 50, -7, -2 },
+                        { -2, -7, 50, 7, 79, 17, -9 },
+                        { -8, 13, 77, 7, 55, -6, -3 },
+                        { -1, -8, 45, 7, 80, 21, -9 },
+                        { -8, 9, 76, 7, 59, -4, -4 },
+                        { -1, -9, 41, 7, 82, 25, -10 },
+                        { -7, 5, 73, 7, 64, -2, -5 },
+                        { 0, -10, 36, 7, 83, 29, -10 },
+                        { -6, 2, 70, 7, 67, 1, -6 },
+                        { -10, 31, 83, 7, 34, -10, 0 },
+                        { -5, -1, 66, 7, 70, 4, -6 },
+                        { -10, 27, 83, 7, 38, -9, -1 },
+                        { -4, -3, 61, 7, 74, 7, -7 },
+                        { -10, 23, 82, 7, 43, -9, -1 },
+                        { -3, -5, 57, 7, 76, 11, -8 },
+                        { -9, 19, 80, 7, 48, -8, -2 },
+                        { -2, -7, 52, 7, 79, 15, -9 } } },
+       .ptrn_arr = { { 0xe73cf3cf, 0x3cf39e79, 0xe79e79cf } },
+       .sample_patrn_length = 98,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 18) = 0.64 */
+       .hor_phase_arr = {
+               .even = { { -9, 33, 80, 7, 33, -9, 0 },
+                        { -6, 0, 64, 7, 71, 6, -7 },
+                        { -10, 25, 80, 7, 42, -8, -1 },
+                        { -4, -4, 56, 7, 76, 13, -9 },
+                        { -9, 17, 78, 7, 51, -6, -3 },
+                        { -2, -7, 47, 7, 78, 21, -9 },
+                        { -8, 9, 74, 7, 60, -2, -5 },
+                        { -1, -9, 38, 7, 81, 29, -10 },
+                        { -6, 3, 66, 7, 68, 3, -6 },
+                        { -10, 29, 81, 7, 38, -9, -1 },
+                        { -5, -2, 60, 7, 74, 9, -8 },
+                        { -9, 21, 78, 7, 47, -7, -2 },
+                        { -3, -6, 51, 7, 78, 17, -9 },
+                        { -9, 13, 76, 7, 56, -4, -4 },
+                        { -1, -8, 42, 7, 80, 25, -10 },
+                        { -7, 6, 71, 7, 64, 0, -6 } },
+               .odd = { { -9, 15, 76, 7, 54, -5, -3 },
+                        { -2, -8, 45, 7, 80, 23, -10 },
+                        { -8, 8, 72, 7, 62, -1, -5 },
+                        { -1, -9, 36, 7, 80, 31, -9 },
+                        { -6, 1, 66, 7, 70, 4, -7 },
+                        { -10, 27, 81, 7, 40, -9, -1 },
+                        { -4, -4, 58, 7, 75, 11, -8 },
+                        { -9, 19, 78, 7, 49, -7, -2 },
+                        { -2, -7, 49, 7, 78, 19, -9 },
+                        { -8, 11, 75, 7, 58, -4, -4 },
+                        { -1, -9, 40, 7, 81, 27, -10 },
+                        { -7, 4, 70, 7, 66, 1, -6 },
+                        { -9, 31, 80, 7, 36, -9, -1 },
+                        { -5, -1, 62, 7, 72, 8, -8 },
+                        { -10, 23, 80, 7, 45, -8, -2 },
+                        { -3, -5, 54, 7, 76, 15, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -9, 33, 80, 7, 33, -9, 0 },
+                        { -6, 0, 64, 7, 71, 6, -7 },
+                        { -10, 25, 80, 7, 42, -8, -1 },
+                        { -4, -4, 56, 7, 76, 13, -9 },
+                        { -9, 17, 78, 7, 51, -6, -3 },
+                        { -2, -7, 47, 7, 78, 21, -9 },
+                        { -8, 9, 74, 7, 60, -2, -5 },
+                        { -1, -9, 38, 7, 81, 29, -10 },
+                        { -6, 3, 66, 7, 68, 3, -6 },
+                        { -10, 29, 81, 7, 38, -9, -1 },
+                        { -5, -2, 60, 7, 74, 9, -8 },
+                        { -9, 21, 78, 7, 47, -7, -2 },
+                        { -3, -6, 51, 7, 78, 17, -9 },
+                        { -9, 13, 76, 7, 56, -4, -4 },
+                        { -1, -8, 42, 7, 80, 25, -10 },
+                        { -7, 6, 71, 7, 64, 0, -6 } },
+               .odd = { { -9, 15, 76, 7, 54, -5, -3 },
+                        { -2, -8, 45, 7, 80, 23, -10 },
+                        { -8, 8, 72, 7, 62, -1, -5 },
+                        { -1, -9, 36, 7, 80, 31, -9 },
+                        { -6, 1, 66, 7, 70, 4, -7 },
+                        { -10, 27, 81, 7, 40, -9, -1 },
+                        { -4, -4, 58, 7, 75, 11, -8 },
+                        { -9, 19, 78, 7, 49, -7, -2 },
+                        { -2, -7, 49, 7, 78, 19, -9 },
+                        { -8, 11, 75, 7, 58, -4, -4 },
+                        { -1, -9, 40, 7, 81, 27, -10 },
+                        { -7, 4, 70, 7, 66, 1, -6 },
+                        { -9, 31, 80, 7, 36, -9, -1 },
+                        { -5, -1, 62, 7, 72, 8, -8 },
+                        { -10, 23, 80, 7, 45, -8, -2 },
+                        { -3, -5, 54, 7, 76, 15, -9 } } },
+       .ptrn_arr = { { 0xf39e73cf, 0xe79c } },
+       .sample_patrn_length = 50,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 19) = 0.627451 */
+       .hor_phase_arr = {
+               .even = { { -9, 34, 79, 7, 34, -9, -1 },
+                        { -6, 0, 61, 7, 72, 9, -8 },
+                        { -9, 22, 78, 7, 47, -7, -3 },
+                        { -3, -6, 49, 7, 77, 20, -9 },
+                        { -8, 11, 72, 7, 59, -1, -5 },
+                        { -1, -9, 36, 7, 79, 32, -9 },
+                        { -6, 1, 63, 7, 71, 7, -8 },
+                        { -9, 24, 77, 7, 45, -7, -2 },
+                        { -4, -5, 51, 7, 77, 18, -9 },
+                        { -9, 13, 73, 7, 58, -2, -5 },
+                        { -1, -8, 38, 7, 78, 30, -9 },
+                        { -6, 3, 65, 7, 67, 6, -7 },
+                        { -9, 26, 78, 7, 43, -8, -2 },
+                        { -4, -4, 53, 7, 76, 16, -9 },
+                        { -9, 14, 75, 7, 55, -3, -4 },
+                        { -2, -8, 40, 7, 79, 28, -9 },
+                        { -7, 4, 67, 7, 67, 4, -7 },
+                        { -9, 28, 79, 7, 40, -8, -2 },
+                        { -4, -3, 55, 7, 75, 14, -9 },
+                        { -9, 16, 76, 7, 53, -4, -4 },
+                        { -2, -8, 43, 7, 78, 26, -9 },
+                        { -7, 6, 67, 7, 65, 3, -6 },
+                        { -9, 30, 78, 7, 38, -8, -1 },
+                        { -5, -2, 58, 7, 73, 13, -9 },
+                        { -9, 18, 77, 7, 51, -5, -4 },
+                        { -2, -7, 45, 7, 77, 24, -9 },
+                        { -8, 7, 71, 7, 63, 1, -6 },
+                        { -9, 32, 79, 7, 36, -9, -1 },
+                        { -5, -1, 59, 7, 72, 11, -8 },
+                        { -9, 20, 77, 7, 49, -6, -3 },
+                        { -3, -7, 47, 7, 78, 22, -9 },
+                        { -8, 9, 72, 7, 61, 0, -6 } },
+               .odd = { { -9, 15, 76, 7, 54, -4, -4 },
+                        { -2, -8, 41, 7, 79, 27, -9 },
+                        { -7, 5, 68, 7, 66, 3, -7 },
+                        { -9, 29, 78, 7, 39, -8, -1 },
+                        { -5, -3, 56, 7, 76, 13, -9 },
+                        { -9, 17, 77, 7, 52, -5, -4 },
+                        { -2, -7, 44, 7, 77, 25, -9 },
+                        { -7, 7, 68, 7, 64, 2, -6 },
+                        { -9, 31, 79, 7, 37, -9, -1 },
+                        { -5, -2, 59, 7, 72, 12, -8 },
+                        { -9, 19, 77, 7, 50, -6, -3 },
+                        { -3, -7, 46, 7, 78, 23, -9 },
+                        { -8, 8, 71, 7, 62, 1, -6 },
+                        { -9, 33, 79, 7, 35, -9, -1 },
+                        { -5, -1, 60, 7, 72, 10, -8 },
+                        { -9, 21, 77, 7, 48, -6, -3 },
+                        { -3, -6, 48, 7, 77, 21, -9 },
+                        { -8, 10, 72, 7, 60, -1, -5 },
+                        { -1, -9, 35, 7, 79, 33, -9 },
+                        { -6, 1, 62, 7, 71, 8, -8 },
+                        { -9, 23, 78, 7, 46, -7, -3 },
+                        { -3, -6, 50, 7, 77, 19, -9 },
+                        { -8, 12, 72, 7, 59, -2, -5 },
+                        { -1, -9, 37, 7, 79, 31, -9 },
+                        { -6, 2, 64, 7, 68, 7, -7 },
+                        { -9, 25, 77, 7, 44, -7, -2 },
+                        { -4, -5, 52, 7, 77, 17, -9 },
+                        { -9, 13, 76, 7, 56, -3, -5 },
+                        { -1, -8, 39, 7, 78, 29, -9 },
+                        { -7, 3, 66, 7, 68, 5, -7 },
+                        { -9, 27, 79, 7, 41, -8, -2 },
+                        { -4, -4, 54, 7, 76, 15, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -9, 34, 79, 7, 34, -9, -1 },
+                        { -6, 0, 61, 7, 72, 9, -8 },
+                        { -9, 22, 78, 7, 47, -7, -3 },
+                        { -3, -6, 49, 7, 77, 20, -9 },
+                        { -8, 11, 72, 7, 59, -1, -5 },
+                        { -1, -9, 36, 7, 79, 32, -9 },
+                        { -6, 1, 63, 7, 71, 7, -8 },
+                        { -9, 24, 77, 7, 45, -7, -2 },
+                        { -4, -5, 51, 7, 77, 18, -9 },
+                        { -9, 13, 73, 7, 58, -2, -5 },
+                        { -1, -8, 38, 7, 78, 30, -9 },
+                        { -6, 3, 65, 7, 67, 6, -7 },
+                        { -9, 26, 78, 7, 43, -8, -2 },
+                        { -4, -4, 53, 7, 76, 16, -9 },
+                        { -9, 14, 75, 7, 55, -3, -4 },
+                        { -2, -8, 40, 7, 79, 28, -9 },
+                        { -7, 4, 67, 7, 67, 4, -7 },
+                        { -9, 28, 79, 7, 40, -8, -2 },
+                        { -4, -3, 55, 7, 75, 14, -9 },
+                        { -9, 16, 76, 7, 53, -4, -4 },
+                        { -2, -8, 43, 7, 78, 26, -9 },
+                        { -7, 6, 67, 7, 65, 3, -6 },
+                        { -9, 30, 78, 7, 38, -8, -1 },
+                        { -5, -2, 58, 7, 73, 13, -9 },
+                        { -9, 18, 77, 7, 51, -5, -4 },
+                        { -2, -7, 45, 7, 77, 24, -9 },
+                        { -8, 7, 71, 7, 63, 1, -6 },
+                        { -9, 32, 79, 7, 36, -9, -1 },
+                        { -5, -1, 59, 7, 72, 11, -8 },
+                        { -9, 20, 77, 7, 49, -6, -3 },
+                        { -3, -7, 47, 7, 78, 22, -9 },
+                        { -8, 9, 72, 7, 61, 0, -6 } },
+               .odd = { { -9, 15, 76, 7, 54, -4, -4 },
+                        { -2, -8, 41, 7, 79, 27, -9 },
+                        { -7, 5, 68, 7, 66, 3, -7 },
+                        { -9, 29, 78, 7, 39, -8, -1 },
+                        { -5, -3, 56, 7, 76, 13, -9 },
+                        { -9, 17, 77, 7, 52, -5, -4 },
+                        { -2, -7, 44, 7, 77, 25, -9 },
+                        { -7, 7, 68, 7, 64, 2, -6 },
+                        { -9, 31, 79, 7, 37, -9, -1 },
+                        { -5, -2, 59, 7, 72, 12, -8 },
+                        { -9, 19, 77, 7, 50, -6, -3 },
+                        { -3, -7, 46, 7, 78, 23, -9 },
+                        { -8, 8, 71, 7, 62, 1, -6 },
+                        { -9, 33, 79, 7, 35, -9, -1 },
+                        { -5, -1, 60, 7, 72, 10, -8 },
+                        { -9, 21, 77, 7, 48, -6, -3 },
+                        { -3, -6, 48, 7, 77, 21, -9 },
+                        { -8, 10, 72, 7, 60, -1, -5 },
+                        { -1, -9, 35, 7, 79, 33, -9 },
+                        { -6, 1, 62, 7, 71, 8, -8 },
+                        { -9, 23, 78, 7, 46, -7, -3 },
+                        { -3, -6, 50, 7, 77, 19, -9 },
+                        { -8, 12, 72, 7, 59, -2, -5 },
+                        { -1, -9, 37, 7, 79, 31, -9 },
+                        { -6, 2, 64, 7, 68, 7, -7 },
+                        { -9, 25, 77, 7, 44, -7, -2 },
+                        { -4, -5, 52, 7, 77, 17, -9 },
+                        { -9, 13, 76, 7, 56, -3, -5 },
+                        { -1, -8, 39, 7, 78, 29, -9 },
+                        { -7, 3, 66, 7, 68, 5, -7 },
+                        { -9, 27, 79, 7, 41, -8, -2 },
+                        { -4, -4, 54, 7, 76, 15, -9 } } },
+       .ptrn_arr = { { 0x79ce79cf, 0x73ce79ce, 0x73ce73ce, 0xe } },
+       .sample_patrn_length = 102,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 20) = 0.615385 */
+       .hor_phase_arr = {
+               .even = { { -8, 34, 77, 7, 34, -8, -1 },
+                        { -6, 0, 59, 7, 71, 12, -8 },
+                        { -9, 19, 75, 7, 51, -4, -4 },
+                        { -3, -7, 43, 7, 77, 27, -9 },
+                        { -7, 6, 64, 7, 66, 6, -7 },
+                        { -9, 27, 77, 7, 43, -7, -3 },
+                        { -4, -4, 51, 7, 75, 19, -9 },
+                        { -8, 12, 71, 7, 59, 0, -6 } },
+               .odd = { { -9, 16, 73, 7, 55, -2, -5 },
+                        { -2, -8, 39, 7, 77, 31, -9 },
+                        { -7, 3, 63, 7, 68, 9, -8 },
+                        { -9, 23, 76, 7, 47, -6, -3 },
+                        { -3, -6, 47, 7, 76, 23, -9 },
+                        { -8, 9, 68, 7, 63, 3, -7 },
+                        { -9, 31, 77, 7, 39, -8, -2 },
+                        { -5, -2, 55, 7, 73, 16, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -8, 34, 77, 7, 34, -8, -1 },
+                        { -6, 0, 59, 7, 71, 12, -8 },
+                        { -9, 19, 75, 7, 51, -4, -4 },
+                        { -3, -7, 43, 7, 77, 27, -9 },
+                        { -7, 6, 64, 7, 66, 6, -7 },
+                        { -9, 27, 77, 7, 43, -7, -3 },
+                        { -4, -4, 51, 7, 75, 19, -9 },
+                        { -8, 12, 71, 7, 59, 0, -6 } },
+               .odd = { { -9, 16, 73, 7, 55, -2, -5 },
+                        { -2, -8, 39, 7, 77, 31, -9 },
+                        { -7, 3, 63, 7, 68, 9, -8 },
+                        { -9, 23, 76, 7, 47, -6, -3 },
+                        { -3, -6, 47, 7, 76, 23, -9 },
+                        { -8, 9, 68, 7, 63, 3, -7 },
+                        { -9, 31, 77, 7, 39, -8, -2 },
+                        { -5, -2, 55, 7, 73, 16, -9 } } },
+       .ptrn_arr = { { 0xe739cf } },
+       .sample_patrn_length = 26,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 21) = 0.603774 */
+       .hor_phase_arr = {
+               .even = { { -8, 35, 76, 7, 35, -8, -2 },
+                        { -6, 0, 57, 7, 71, 15, -9 },
+                        { -9, 17, 71, 7, 55, -1, -5 },
+                        { -2, -8, 37, 7, 76, 33, -8 },
+                        { -6, 1, 58, 7, 71, 13, -9 },
+                        { -9, 18, 73, 7, 53, -2, -5 },
+                        { -2, -7, 39, 7, 75, 31, -8 },
+                        { -7, 2, 60, 7, 69, 12, -8 },
+                        { -9, 20, 74, 7, 51, -3, -5 },
+                        { -3, -7, 41, 7, 77, 29, -9 },
+                        { -7, 4, 62, 7, 67, 10, -8 },
+                        { -9, 22, 74, 7, 49, -4, -4 },
+                        { -3, -6, 43, 7, 75, 28, -9 },
+                        { -7, 5, 63, 7, 67, 8, -8 },
+                        { -9, 24, 75, 7, 47, -5, -4 },
+                        { -4, -5, 45, 7, 75, 26, -9 },
+                        { -8, 7, 65, 7, 65, 7, -8 },
+                        { -9, 26, 75, 7, 45, -5, -4 },
+                        { -4, -5, 47, 7, 75, 24, -9 },
+                        { -8, 8, 67, 7, 63, 5, -7 },
+                        { -9, 28, 75, 7, 43, -6, -3 },
+                        { -4, -4, 49, 7, 74, 22, -9 },
+                        { -8, 10, 67, 7, 62, 4, -7 },
+                        { -9, 29, 77, 7, 41, -7, -3 },
+                        { -5, -3, 51, 7, 74, 20, -9 },
+                        { -8, 12, 69, 7, 60, 2, -7 },
+                        { -8, 31, 75, 7, 39, -7, -2 },
+                        { -5, -2, 53, 7, 73, 18, -9 },
+                        { -9, 13, 71, 7, 58, 1, -6 },
+                        { -8, 33, 76, 7, 37, -8, -2 },
+                        { -5, -1, 55, 7, 71, 17, -9 },
+                        { -9, 15, 71, 7, 57, 0, -6 } },
+               .odd = { { -9, 16, 72, 7, 56, -1, -6 },
+                        { -2, -8, 36, 7, 76, 34, -8 },
+                        { -6, 1, 58, 7, 70, 14, -9 },
+                        { -9, 18, 72, 7, 54, -2, -5 },
+                        { -2, -7, 38, 7, 75, 32, -8 },
+                        { -6, 2, 59, 7, 70, 12, -9 },
+                        { -9, 19, 74, 7, 52, -3, -5 },
+                        { -3, -7, 40, 7, 77, 30, -9 },
+                        { -7, 3, 61, 7, 68, 11, -8 },
+                        { -9, 21, 75, 7, 50, -4, -5 },
+                        { -3, -6, 42, 7, 75, 29, -9 },
+                        { -7, 5, 63, 7, 66, 9, -8 },
+                        { -9, 23, 74, 7, 48, -4, -4 },
+                        { -3, -6, 44, 7, 75, 27, -9 },
+                        { -7, 6, 64, 7, 65, 8, -8 },
+                        { -9, 25, 75, 7, 46, -5, -4 },
+                        { -4, -5, 46, 7, 75, 25, -9 },
+                        { -8, 8, 65, 7, 64, 6, -7 },
+                        { -9, 27, 75, 7, 44, -6, -3 },
+                        { -4, -4, 48, 7, 74, 23, -9 },
+                        { -8, 9, 66, 7, 63, 5, -7 },
+                        { -9, 29, 75, 7, 42, -6, -3 },
+                        { -5, -4, 50, 7, 75, 21, -9 },
+                        { -8, 11, 68, 7, 61, 3, -7 },
+                        { -9, 30, 77, 7, 40, -7, -3 },
+                        { -5, -3, 52, 7, 74, 19, -9 },
+                        { -9, 12, 70, 7, 59, 2, -6 },
+                        { -8, 32, 75, 7, 38, -7, -2 },
+                        { -5, -2, 54, 7, 72, 18, -9 },
+                        { -9, 14, 70, 7, 58, 1, -6 },
+                        { -8, 34, 76, 7, 36, -8, -2 },
+                        { -6, -1, 56, 7, 72, 16, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -8, 35, 76, 7, 35, -8, -2 },
+                        { -6, 0, 57, 7, 71, 15, -9 },
+                        { -9, 17, 71, 7, 55, -1, -5 },
+                        { -2, -8, 37, 7, 76, 33, -8 },
+                        { -6, 1, 58, 7, 71, 13, -9 },
+                        { -9, 18, 73, 7, 53, -2, -5 },
+                        { -2, -7, 39, 7, 75, 31, -8 },
+                        { -7, 2, 60, 7, 69, 12, -8 },
+                        { -9, 20, 74, 7, 51, -3, -5 },
+                        { -3, -7, 41, 7, 77, 29, -9 },
+                        { -7, 4, 62, 7, 67, 10, -8 },
+                        { -9, 22, 74, 7, 49, -4, -4 },
+                        { -3, -6, 43, 7, 75, 28, -9 },
+                        { -7, 5, 63, 7, 67, 8, -8 },
+                        { -9, 24, 75, 7, 47, -5, -4 },
+                        { -4, -5, 45, 7, 75, 26, -9 },
+                        { -8, 7, 65, 7, 65, 7, -8 },
+                        { -9, 26, 75, 7, 45, -5, -4 },
+                        { -4, -5, 47, 7, 75, 24, -9 },
+                        { -8, 8, 67, 7, 63, 5, -7 },
+                        { -9, 28, 75, 7, 43, -6, -3 },
+                        { -4, -4, 49, 7, 74, 22, -9 },
+                        { -8, 10, 67, 7, 62, 4, -7 },
+                        { -9, 29, 77, 7, 41, -7, -3 },
+                        { -5, -3, 51, 7, 74, 20, -9 },
+                        { -8, 12, 69, 7, 60, 2, -7 },
+                        { -8, 31, 75, 7, 39, -7, -2 },
+                        { -5, -2, 53, 7, 73, 18, -9 },
+                        { -9, 13, 71, 7, 58, 1, -6 },
+                        { -8, 33, 76, 7, 37, -8, -2 },
+                        { -5, -1, 55, 7, 71, 17, -9 },
+                        { -9, 15, 71, 7, 57, 0, -6 } },
+               .odd = { { -9, 16, 72, 7, 56, -1, -6 },
+                        { -2, -8, 36, 7, 76, 34, -8 },
+                        { -6, 1, 58, 7, 70, 14, -9 },
+                        { -9, 18, 72, 7, 54, -2, -5 },
+                        { -2, -7, 38, 7, 75, 32, -8 },
+                        { -6, 2, 59, 7, 70, 12, -9 },
+                        { -9, 19, 74, 7, 52, -3, -5 },
+                        { -3, -7, 40, 7, 77, 30, -9 },
+                        { -7, 3, 61, 7, 68, 11, -8 },
+                        { -9, 21, 75, 7, 50, -4, -5 },
+                        { -3, -6, 42, 7, 75, 29, -9 },
+                        { -7, 5, 63, 7, 66, 9, -8 },
+                        { -9, 23, 74, 7, 48, -4, -4 },
+                        { -3, -6, 44, 7, 75, 27, -9 },
+                        { -7, 6, 64, 7, 65, 8, -8 },
+                        { -9, 25, 75, 7, 46, -5, -4 },
+                        { -4, -5, 46, 7, 75, 25, -9 },
+                        { -8, 8, 65, 7, 64, 6, -7 },
+                        { -9, 27, 75, 7, 44, -6, -3 },
+                        { -4, -4, 48, 7, 74, 23, -9 },
+                        { -8, 9, 66, 7, 63, 5, -7 },
+                        { -9, 29, 75, 7, 42, -6, -3 },
+                        { -5, -4, 50, 7, 75, 21, -9 },
+                        { -8, 11, 68, 7, 61, 3, -7 },
+                        { -9, 30, 77, 7, 40, -7, -3 },
+                        { -5, -3, 52, 7, 74, 19, -9 },
+                        { -9, 12, 70, 7, 59, 2, -6 },
+                        { -8, 32, 75, 7, 38, -7, -2 },
+                        { -5, -2, 54, 7, 72, 18, -9 },
+                        { -9, 14, 70, 7, 58, 1, -6 },
+                        { -8, 34, 76, 7, 36, -8, -2 },
+                        { -6, -1, 56, 7, 72, 16, -9 } } },
+       .ptrn_arr = { { 0x9ce739cf, 0xe739ce73, 0x39ce739c, 0xe7 } },
+       .sample_patrn_length = 106,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 22) = 0.592593 */
+       .hor_phase_arr = {
+               .even = { { -7, 35, 74, 7, 35, -7, -2 },
+                        { -6, 0, 54, 7, 71, 18, -9 },
+                        { -9, 14, 70, 7, 58, 2, -7 },
+                        { -8, 32, 74, 7, 39, -6, -3 },
+                        { -5, -2, 51, 7, 72, 21, -9 },
+                        { -8, 11, 66, 7, 61, 5, -7 },
+                        { -9, 28, 75, 7, 43, -5, -4 },
+                        { -4, -4, 47, 7, 73, 25, -9 },
+                        { -8, 8, 64, 7, 64, 8, -8 },
+                        { -9, 25, 73, 7, 47, -4, -4 },
+                        { -4, -5, 43, 7, 75, 28, -9 },
+                        { -7, 5, 61, 7, 66, 11, -8 },
+                        { -9, 21, 72, 7, 51, -2, -5 },
+                        { -3, -6, 39, 7, 74, 32, -8 },
+                        { -7, 2, 58, 7, 70, 14, -9 },
+                        { -9, 18, 71, 7, 54, 0, -6 } },
+               .odd = { { -9, 16, 70, 7, 56, 1, -6 },
+                        { -8, 34, 75, 7, 37, -7, -3 },
+                        { -6, -1, 53, 7, 72, 19, -9 },
+                        { -9, 13, 68, 7, 59, 4, -7 },
+                        { -8, 30, 74, 7, 41, -6, -3 },
+                        { -5, -3, 49, 7, 73, 23, -9 },
+                        { -8, 10, 66, 7, 62, 6, -8 },
+                        { -9, 27, 74, 7, 45, -5, -4 },
+                        { -4, -5, 45, 7, 74, 27, -9 },
+                        { -8, 6, 62, 7, 66, 10, -8 },
+                        { -9, 23, 73, 7, 49, -3, -5 },
+                        { -3, -6, 41, 7, 74, 30, -8 },
+                        { -7, 4, 59, 7, 68, 13, -9 },
+                        { -9, 19, 72, 7, 53, -1, -6 },
+                        { -3, -7, 37, 7, 75, 34, -8 },
+                        { -6, 1, 56, 7, 70, 16, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -7, 35, 74, 7, 35, -7, -2 },
+                        { -6, 0, 54, 7, 71, 18, -9 },
+                        { -9, 14, 70, 7, 58, 2, -7 },
+                        { -8, 32, 74, 7, 39, -6, -3 },
+                        { -5, -2, 51, 7, 72, 21, -9 },
+                        { -8, 11, 66, 7, 61, 5, -7 },
+                        { -9, 28, 75, 7, 43, -5, -4 },
+                        { -4, -4, 47, 7, 73, 25, -9 },
+                        { -8, 8, 64, 7, 64, 8, -8 },
+                        { -9, 25, 73, 7, 47, -4, -4 },
+                        { -4, -5, 43, 7, 75, 28, -9 },
+                        { -7, 5, 61, 7, 66, 11, -8 },
+                        { -9, 21, 72, 7, 51, -2, -5 },
+                        { -3, -6, 39, 7, 74, 32, -8 },
+                        { -7, 2, 58, 7, 70, 14, -9 },
+                        { -9, 18, 71, 7, 54, 0, -6 } },
+               .odd = { { -9, 16, 70, 7, 56, 1, -6 },
+                        { -8, 34, 75, 7, 37, -7, -3 },
+                        { -6, -1, 53, 7, 72, 19, -9 },
+                        { -9, 13, 68, 7, 59, 4, -7 },
+                        { -8, 30, 74, 7, 41, -6, -3 },
+                        { -5, -3, 49, 7, 73, 23, -9 },
+                        { -8, 10, 66, 7, 62, 6, -8 },
+                        { -9, 27, 74, 7, 45, -5, -4 },
+                        { -4, -5, 45, 7, 74, 27, -9 },
+                        { -8, 6, 62, 7, 66, 10, -8 },
+                        { -9, 23, 73, 7, 49, -3, -5 },
+                        { -3, -6, 41, 7, 74, 30, -8 },
+                        { -7, 4, 59, 7, 68, 13, -9 },
+                        { -9, 19, 72, 7, 53, -1, -6 },
+                        { -3, -7, 37, 7, 75, 34, -8 },
+                        { -6, 1, 56, 7, 70, 16, -9 } } },
+       .ptrn_arr = { { 0xce739ce7, 0xce739 } },
+       .sample_patrn_length = 54,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 23) = 0.581818 */
+       .hor_phase_arr = {
+               .even = { { -7, 36, 73, 7, 36, -7, -3 },
+                        { -6, 0, 52, 7, 71, 20, -9 },
+                        { -8, 12, 66, 7, 60, 6, -8 },
+                        { -8, 27, 73, 7, 45, -4, -5 },
+                        { -4, -4, 43, 7, 72, 29, -8 },
+                        { -7, 5, 59, 7, 66, 14, -9 },
+                        { -9, 19, 69, 7, 54, 1, -6 },
+                        { -7, 34, 72, 7, 38, -6, -3 },
+                        { -6, -1, 50, 7, 72, 22, -9 },
+                        { -8, 11, 63, 7, 62, 8, -8 },
+                        { -9, 26, 72, 7, 47, -3, -5 },
+                        { -4, -5, 41, 7, 73, 31, -8 },
+                        { -7, 4, 57, 7, 68, 15, -9 },
+                        { -9, 17, 69, 7, 56, 2, -7 },
+                        { -7, 32, 74, 7, 39, -6, -4 },
+                        { -5, -2, 49, 7, 71, 24, -9 },
+                        { -8, 9, 63, 7, 63, 9, -8 },
+                        { -9, 24, 71, 7, 49, -2, -5 },
+                        { -4, -6, 39, 7, 74, 32, -7 },
+                        { -7, 2, 56, 7, 69, 17, -9 },
+                        { -9, 15, 68, 7, 57, 4, -7 },
+                        { -8, 31, 73, 7, 41, -5, -4 },
+                        { -5, -3, 47, 7, 72, 26, -9 },
+                        { -8, 8, 62, 7, 63, 11, -8 },
+                        { -9, 22, 72, 7, 50, -1, -6 },
+                        { -3, -6, 38, 7, 72, 34, -7 },
+                        { -6, 1, 54, 7, 69, 19, -9 },
+                        { -9, 14, 66, 7, 59, 5, -7 },
+                        { -8, 29, 72, 7, 43, -4, -4 },
+                        { -5, -4, 45, 7, 73, 27, -8 },
+                        { -8, 6, 60, 7, 66, 12, -8 },
+                        { -9, 20, 71, 7, 52, 0, -6 } },
+               .odd = { { -9, 16, 69, 7, 56, 3, -7 },
+                        { -8, 31, 74, 7, 40, -5, -4 },
+                        { -5, -2, 48, 7, 71, 25, -9 },
+                        { -8, 8, 62, 7, 64, 10, -8 },
+                        { -9, 23, 72, 7, 50, -2, -6 },
+                        { -3, -6, 39, 7, 72, 33, -7 },
+                        { -7, 2, 55, 7, 69, 18, -9 },
+                        { -9, 15, 67, 7, 58, 4, -7 },
+                        { -8, 30, 73, 7, 42, -5, -4 },
+                        { -5, -3, 46, 7, 72, 26, -8 },
+                        { -8, 7, 61, 7, 65, 11, -8 },
+                        { -9, 21, 72, 7, 51, -1, -6 },
+                        { -3, -6, 37, 7, 72, 35, -7 },
+                        { -6, 1, 53, 7, 69, 20, -9 },
+                        { -9, 13, 66, 7, 59, 6, -7 },
+                        { -8, 28, 72, 7, 44, -4, -4 },
+                        { -4, -4, 44, 7, 72, 28, -8 },
+                        { -7, 6, 59, 7, 66, 13, -9 },
+                        { -9, 20, 69, 7, 53, 1, -6 },
+                        { -7, 35, 72, 7, 37, -6, -3 },
+                        { -6, -1, 51, 7, 72, 21, -9 },
+                        { -8, 11, 65, 7, 61, 7, -8 },
+                        { -8, 26, 72, 7, 46, -3, -5 },
+                        { -4, -5, 42, 7, 73, 30, -8 },
+                        { -7, 4, 58, 7, 67, 15, -9 },
+                        { -9, 18, 69, 7, 55, 2, -7 },
+                        { -7, 33, 72, 7, 39, -6, -3 },
+                        { -6, -2, 50, 7, 72, 23, -9 },
+                        { -8, 10, 64, 7, 62, 8, -8 },
+                        { -9, 25, 71, 7, 48, -2, -5 },
+                        { -4, -5, 40, 7, 74, 31, -8 },
+                        { -7, 3, 56, 7, 69, 16, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -7, 36, 73, 7, 36, -7, -3 },
+                        { -6, 0, 52, 7, 71, 20, -9 },
+                        { -8, 12, 66, 7, 60, 6, -8 },
+                        { -8, 27, 73, 7, 45, -4, -5 },
+                        { -4, -4, 43, 7, 72, 29, -8 },
+                        { -7, 5, 59, 7, 66, 14, -9 },
+                        { -9, 19, 69, 7, 54, 1, -6 },
+                        { -7, 34, 72, 7, 38, -6, -3 },
+                        { -6, -1, 50, 7, 72, 22, -9 },
+                        { -8, 11, 63, 7, 62, 8, -8 },
+                        { -9, 26, 72, 7, 47, -3, -5 },
+                        { -4, -5, 41, 7, 73, 31, -8 },
+                        { -7, 4, 57, 7, 68, 15, -9 },
+                        { -9, 17, 69, 7, 56, 2, -7 },
+                        { -7, 32, 74, 7, 39, -6, -4 },
+                        { -5, -2, 49, 7, 71, 24, -9 },
+                        { -8, 9, 63, 7, 63, 9, -8 },
+                        { -9, 24, 71, 7, 49, -2, -5 },
+                        { -4, -6, 39, 7, 74, 32, -7 },
+                        { -7, 2, 56, 7, 69, 17, -9 },
+                        { -9, 15, 68, 7, 57, 4, -7 },
+                        { -8, 31, 73, 7, 41, -5, -4 },
+                        { -5, -3, 47, 7, 72, 26, -9 },
+                        { -8, 8, 62, 7, 63, 11, -8 },
+                        { -9, 22, 72, 7, 50, -1, -6 },
+                        { -3, -6, 38, 7, 72, 34, -7 },
+                        { -6, 1, 54, 7, 69, 19, -9 },
+                        { -9, 14, 66, 7, 59, 5, -7 },
+                        { -8, 29, 72, 7, 43, -4, -4 },
+                        { -5, -4, 45, 7, 73, 27, -8 },
+                        { -8, 6, 60, 7, 66, 12, -8 },
+                        { -9, 20, 71, 7, 52, 0, -6 } },
+               .odd = { { -9, 16, 69, 7, 56, 3, -7 },
+                        { -8, 31, 74, 7, 40, -5, -4 },
+                        { -5, -2, 48, 7, 71, 25, -9 },
+                        { -8, 8, 62, 7, 64, 10, -8 },
+                        { -9, 23, 72, 7, 50, -2, -6 },
+                        { -3, -6, 39, 7, 72, 33, -7 },
+                        { -7, 2, 55, 7, 69, 18, -9 },
+                        { -9, 15, 67, 7, 58, 4, -7 },
+                        { -8, 30, 73, 7, 42, -5, -4 },
+                        { -5, -3, 46, 7, 72, 26, -8 },
+                        { -8, 7, 61, 7, 65, 11, -8 },
+                        { -9, 21, 72, 7, 51, -1, -6 },
+                        { -3, -6, 37, 7, 72, 35, -7 },
+                        { -6, 1, 53, 7, 69, 20, -9 },
+                        { -9, 13, 66, 7, 59, 6, -7 },
+                        { -8, 28, 72, 7, 44, -4, -4 },
+                        { -4, -4, 44, 7, 72, 28, -8 },
+                        { -7, 6, 59, 7, 66, 13, -9 },
+                        { -9, 20, 69, 7, 53, 1, -6 },
+                        { -7, 35, 72, 7, 37, -6, -3 },
+                        { -6, -1, 51, 7, 72, 21, -9 },
+                        { -8, 11, 65, 7, 61, 7, -8 },
+                        { -8, 26, 72, 7, 46, -3, -5 },
+                        { -4, -5, 42, 7, 73, 30, -8 },
+                        { -7, 4, 58, 7, 67, 15, -9 },
+                        { -9, 18, 69, 7, 55, 2, -7 },
+                        { -7, 33, 72, 7, 39, -6, -3 },
+                        { -6, -2, 50, 7, 72, 23, -9 },
+                        { -8, 10, 64, 7, 62, 8, -8 },
+                        { -9, 25, 71, 7, 48, -2, -5 },
+                        { -4, -5, 40, 7, 74, 31, -8 },
+                        { -7, 3, 56, 7, 69, 16, -9 } } },
+       .ptrn_arr = { { 0xe7339ce7, 0x9ce7339c, 0x399ce739, 0xce7 } },
+       .sample_patrn_length = 110,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 24) = 0.571429 */
+       .hor_phase_arr = {
+               .even = { { -6, 36, 71, 7, 36, -6, -3 },
+                        { -6, 0, 50, 7, 69, 23, -8 },
+                        { -8, 10, 62, 7, 62, 10, -8 },
+                        { -8, 23, 69, 7, 50, 0, -6 } },
+               .odd = { { -9, 16, 67, 7, 56, 5, -7 },
+                        { -8, 29, 73, 7, 43, -4, -5 },
+                        { -5, -4, 43, 7, 73, 29, -8 },
+                        { -7, 5, 56, 7, 67, 16, -9 } } },
+       .ver_phase_arr = {
+               .even = { { -6, 36, 71, 7, 36, -6, -3 },
+                        { -6, 0, 50, 7, 69, 23, -8 },
+                        { -8, 10, 62, 7, 62, 10, -8 },
+                        { -8, 23, 69, 7, 50, 0, -6 } },
+               .odd = { { -9, 16, 67, 7, 56, 5, -7 },
+                        { -8, 29, 73, 7, 43, -4, -5 },
+                        { -5, -4, 43, 7, 73, 29, -8 },
+                        { -7, 5, 56, 7, 67, 16, -9 } } },
+       .ptrn_arr = { { 0xce7 } },
+       .sample_patrn_length = 14,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 25) = 0.561404 */
+       .hor_phase_arr = {
+               .even = { { -5, 36, 70, 7, 36, -5, -4 },
+                        { -6, 0, 48, 7, 69, 25, -8 },
+                        { -8, 8, 59, 7, 63, 14, -8 },
+                        { -8, 19, 66, 7, 54, 4, -7 },
+                        { -7, 30, 70, 7, 43, -3, -5 },
+                        { -5, -3, 41, 7, 70, 32, -7 },
+                        { -7, 3, 53, 7, 67, 20, -8 },
+                        { -8, 13, 61, 7, 60, 10, -8 },
+                        { -8, 24, 67, 7, 50, 1, -6 },
+                        { -6, 35, 70, 7, 38, -5, -4 },
+                        { -6, -1, 46, 7, 70, 27, -8 },
+                        { -8, 7, 57, 7, 64, 16, -8 },
+                        { -8, 17, 64, 7, 56, 6, -7 },
+                        { -7, 28, 69, 7, 45, -2, -5 },
+                        { -4, -4, 40, 7, 69, 33, -6 },
+                        { -7, 2, 51, 7, 68, 22, -8 },
+                        { -8, 11, 61, 7, 61, 11, -8 },
+                        { -8, 22, 68, 7, 51, 2, -7 },
+                        { -6, 33, 69, 7, 40, -4, -4 },
+                        { -5, -2, 45, 7, 69, 28, -7 },
+                        { -7, 6, 56, 7, 64, 17, -8 },
+                        { -8, 16, 64, 7, 57, 7, -8 },
+                        { -8, 27, 70, 7, 46, -1, -6 },
+                        { -4, -5, 38, 7, 70, 35, -6 },
+                        { -6, 1, 50, 7, 67, 24, -8 },
+                        { -8, 10, 60, 7, 61, 13, -8 },
+                        { -8, 20, 67, 7, 53, 3, -7 },
+                        { -7, 32, 70, 7, 41, -3, -5 },
+                        { -5, -3, 43, 7, 70, 30, -7 },
+                        { -7, 4, 54, 7, 66, 19, -8 },
+                        { -8, 14, 63, 7, 59, 8, -8 },
+                        { -8, 25, 69, 7, 48, 0, -6 } },
+               .odd = { { -8, 16, 66, 7, 56, 6, -8 },
+                        { -8, 28, 69, 7, 46, -1, -6 },
+                        { -4, -4, 39, 7, 69, 34, -6 },
+                        { -7, 2, 51, 7, 67, 23, -8 },
+                        { -8, 10, 60, 7, 62, 12, -8 },
+                        { -8, 21, 67, 7, 52, 3, -7 },
+                        { -7, 32, 71, 7, 41, -4, -5 },
+                        { -5, -2, 44, 7, 69, 29, -7 },
+                        { -7, 5, 55, 7, 65, 18, -8 },
+                        { -8, 15, 63, 7, 58, 8, -8 },
+                        { -8, 26, 69, 7, 47, 0, -6 },
+                        { -4, -5, 37, 7, 71, 35, -6 },
+                        { -6, 1, 49, 7, 68, 24, -8 },
+                        { -8, 9, 59, 7, 63, 13, -8 },
+                        { -8, 20, 65, 7, 54, 4, -7 },
+                        { -7, 31, 70, 7, 42, -3, -5 },
+                        { -5, -3, 42, 7, 70, 31, -7 },
+                        { -7, 4, 54, 7, 65, 20, -8 },
+                        { -8, 13, 63, 7, 59, 9, -8 },
+                        { -8, 24, 68, 7, 49, 1, -6 },
+                        { -6, 35, 71, 7, 37, -5, -4 },
+                        { -6, 0, 47, 7, 69, 26, -8 },
+                        { -8, 8, 58, 7, 63, 15, -8 },
+                        { -8, 18, 65, 7, 55, 5, -7 },
+                        { -7, 29, 69, 7, 44, -2, -5 },
+                        { -5, -4, 41, 7, 71, 32, -7 },
+                        { -7, 3, 52, 7, 67, 21, -8 },
+                        { -8, 12, 62, 7, 60, 10, -8 },
+                        { -8, 23, 67, 7, 51, 2, -7 },
+                        { -6, 34, 69, 7, 39, -4, -4 },
+                        { -6, -1, 46, 7, 69, 28, -8 },
+                        { -8, 6, 56, 7, 66, 16, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -5, 36, 70, 7, 36, -5, -4 },
+                        { -6, 0, 48, 7, 69, 25, -8 },
+                        { -8, 8, 59, 7, 63, 14, -8 },
+                        { -8, 19, 66, 7, 54, 4, -7 },
+                        { -7, 30, 70, 7, 43, -3, -5 },
+                        { -5, -3, 41, 7, 70, 32, -7 },
+                        { -7, 3, 53, 7, 67, 20, -8 },
+                        { -8, 13, 61, 7, 60, 10, -8 },
+                        { -8, 24, 67, 7, 50, 1, -6 },
+                        { -6, 35, 70, 7, 38, -5, -4 },
+                        { -6, -1, 46, 7, 70, 27, -8 },
+                        { -8, 7, 57, 7, 64, 16, -8 },
+                        { -8, 17, 64, 7, 56, 6, -7 },
+                        { -7, 28, 69, 7, 45, -2, -5 },
+                        { -4, -4, 40, 7, 69, 33, -6 },
+                        { -7, 2, 51, 7, 68, 22, -8 },
+                        { -8, 11, 61, 7, 61, 11, -8 },
+                        { -8, 22, 68, 7, 51, 2, -7 },
+                        { -6, 33, 69, 7, 40, -4, -4 },
+                        { -5, -2, 45, 7, 69, 28, -7 },
+                        { -7, 6, 56, 7, 64, 17, -8 },
+                        { -8, 16, 64, 7, 57, 7, -8 },
+                        { -8, 27, 70, 7, 46, -1, -6 },
+                        { -4, -5, 38, 7, 70, 35, -6 },
+                        { -6, 1, 50, 7, 67, 24, -8 },
+                        { -8, 10, 60, 7, 61, 13, -8 },
+                        { -8, 20, 67, 7, 53, 3, -7 },
+                        { -7, 32, 70, 7, 41, -3, -5 },
+                        { -5, -3, 43, 7, 70, 30, -7 },
+                        { -7, 4, 54, 7, 66, 19, -8 },
+                        { -8, 14, 63, 7, 59, 8, -8 },
+                        { -8, 25, 69, 7, 48, 0, -6 } },
+               .odd = { { -8, 16, 66, 7, 56, 6, -8 },
+                        { -8, 28, 69, 7, 46, -1, -6 },
+                        { -4, -4, 39, 7, 69, 34, -6 },
+                        { -7, 2, 51, 7, 67, 23, -8 },
+                        { -8, 10, 60, 7, 62, 12, -8 },
+                        { -8, 21, 67, 7, 52, 3, -7 },
+                        { -7, 32, 71, 7, 41, -4, -5 },
+                        { -5, -2, 44, 7, 69, 29, -7 },
+                        { -7, 5, 55, 7, 65, 18, -8 },
+                        { -8, 15, 63, 7, 58, 8, -8 },
+                        { -8, 26, 69, 7, 47, 0, -6 },
+                        { -4, -5, 37, 7, 71, 35, -6 },
+                        { -6, 1, 49, 7, 68, 24, -8 },
+                        { -8, 9, 59, 7, 63, 13, -8 },
+                        { -8, 20, 65, 7, 54, 4, -7 },
+                        { -7, 31, 70, 7, 42, -3, -5 },
+                        { -5, -3, 42, 7, 70, 31, -7 },
+                        { -7, 4, 54, 7, 65, 20, -8 },
+                        { -8, 13, 63, 7, 59, 9, -8 },
+                        { -8, 24, 68, 7, 49, 1, -6 },
+                        { -6, 35, 71, 7, 37, -5, -4 },
+                        { -6, 0, 47, 7, 69, 26, -8 },
+                        { -8, 8, 58, 7, 63, 15, -8 },
+                        { -8, 18, 65, 7, 55, 5, -7 },
+                        { -7, 29, 69, 7, 44, -2, -5 },
+                        { -5, -4, 41, 7, 71, 32, -7 },
+                        { -7, 3, 52, 7, 67, 21, -8 },
+                        { -8, 12, 62, 7, 60, 10, -8 },
+                        { -8, 23, 67, 7, 51, 2, -7 },
+                        { -6, 34, 69, 7, 39, -4, -4 },
+                        { -6, -1, 46, 7, 69, 28, -8 },
+                        { -8, 6, 56, 7, 66, 16, -8 } } },
+       .ptrn_arr = { { 0x3399cce7, 0x3399cce7, 0x3399ce67, 0xce67 } },
+       .sample_patrn_length = 114,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 26) = 0.551724 */
+       .hor_phase_arr = {
+               .even = { { -5, 36, 70, 7, 36, -5, -4 },
+                        { -6, 0, 46, 7, 68, 27, -7 },
+                        { -8, 7, 55, 7, 64, 18, -8 },
+                        { -8, 15, 62, 7, 58, 9, -8 },
+                        { -8, 24, 68, 7, 49, 2, -7 },
+                        { -6, 33, 69, 7, 40, -3, -5 },
+                        { -6, -2, 43, 7, 70, 30, -7 },
+                        { -7, 4, 52, 7, 66, 21, -8 },
+                        { -8, 12, 60, 7, 60, 12, -8 },
+                        { -8, 21, 66, 7, 52, 4, -7 },
+                        { -7, 30, 70, 7, 43, -2, -6 },
+                        { -5, -3, 40, 7, 69, 33, -6 },
+                        { -7, 2, 49, 7, 68, 24, -8 },
+                        { -8, 9, 58, 7, 62, 15, -8 },
+                        { -8, 18, 64, 7, 55, 7, -8 },
+                        { -7, 27, 68, 7, 46, 0, -6 } },
+               .odd = { { -8, 17, 63, 7, 56, 8, -8 },
+                        { -8, 26, 67, 7, 48, 1, -6 },
+                        { -5, 35, 69, 7, 38, -4, -5 },
+                        { -6, -1, 45, 7, 68, 29, -7 },
+                        { -7, 5, 54, 7, 64, 20, -8 },
+                        { -8, 14, 60, 7, 59, 11, -8 },
+                        { -8, 23, 66, 7, 51, 3, -7 },
+                        { -6, 32, 69, 7, 41, -3, -5 },
+                        { -5, -3, 41, 7, 69, 32, -6 },
+                        { -7, 3, 51, 7, 66, 23, -8 },
+                        { -8, 11, 59, 7, 60, 14, -8 },
+                        { -8, 20, 64, 7, 54, 5, -7 },
+                        { -7, 29, 68, 7, 45, -1, -6 },
+                        { -5, -4, 38, 7, 69, 35, -5 },
+                        { -6, 1, 48, 7, 67, 26, -8 },
+                        { -8, 8, 56, 7, 63, 17, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -5, 36, 70, 7, 36, -5, -4 },
+                        { -6, 0, 46, 7, 68, 27, -7 },
+                        { -8, 7, 55, 7, 64, 18, -8 },
+                        { -8, 15, 62, 7, 58, 9, -8 },
+                        { -8, 24, 68, 7, 49, 2, -7 },
+                        { -6, 33, 69, 7, 40, -3, -5 },
+                        { -6, -2, 43, 7, 70, 30, -7 },
+                        { -7, 4, 52, 7, 66, 21, -8 },
+                        { -8, 12, 60, 7, 60, 12, -8 },
+                        { -8, 21, 66, 7, 52, 4, -7 },
+                        { -7, 30, 70, 7, 43, -2, -6 },
+                        { -5, -3, 40, 7, 69, 33, -6 },
+                        { -7, 2, 49, 7, 68, 24, -8 },
+                        { -8, 9, 58, 7, 62, 15, -8 },
+                        { -8, 18, 64, 7, 55, 7, -8 },
+                        { -7, 27, 68, 7, 46, 0, -6 } },
+               .odd = { { -8, 17, 63, 7, 56, 8, -8 },
+                        { -8, 26, 67, 7, 48, 1, -6 },
+                        { -5, 35, 69, 7, 38, -4, -5 },
+                        { -6, -1, 45, 7, 68, 29, -7 },
+                        { -7, 5, 54, 7, 64, 20, -8 },
+                        { -8, 14, 60, 7, 59, 11, -8 },
+                        { -8, 23, 66, 7, 51, 3, -7 },
+                        { -6, 32, 69, 7, 41, -3, -5 },
+                        { -5, -3, 41, 7, 69, 32, -6 },
+                        { -7, 3, 51, 7, 66, 23, -8 },
+                        { -8, 11, 59, 7, 60, 14, -8 },
+                        { -8, 20, 64, 7, 54, 5, -7 },
+                        { -7, 29, 68, 7, 45, -1, -6 },
+                        { -5, -4, 38, 7, 69, 35, -5 },
+                        { -6, 1, 48, 7, 67, 26, -8 },
+                        { -8, 8, 56, 7, 63, 17, -8 } } },
+       .ptrn_arr = { { 0x399cce67, 0xcce673 } },
+       .sample_patrn_length = 58,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 27) = 0.542373 */
+       .hor_phase_arr = {
+               .even = { { -4, 37, 67, 7, 37, -4, -5 },
+                        { -6, 0, 44, 7, 67, 29, -6 },
+                        { -7, 5, 52, 7, 64, 22, -8 },
+                        { -8, 12, 58, 7, 60, 14, -8 },
+                        { -8, 19, 63, 7, 54, 8, -8 },
+                        { -7, 26, 67, 7, 47, 2, -7 },
+                        { -5, 34, 66, 7, 40, -2, -5 },
+                        { -6, -2, 41, 7, 68, 32, -5 },
+                        { -7, 3, 49, 7, 65, 25, -7 },
+                        { -8, 9, 56, 7, 62, 17, -8 },
+                        { -8, 16, 61, 7, 57, 10, -8 },
+                        { -8, 23, 66, 7, 50, 4, -7 },
+                        { -6, 31, 67, 7, 43, -1, -6 },
+                        { -5, -3, 38, 7, 67, 35, -4 },
+                        { -6, 1, 46, 7, 66, 28, -7 },
+                        { -8, 6, 53, 7, 65, 20, -8 },
+                        { -8, 13, 59, 7, 59, 13, -8 },
+                        { -8, 20, 65, 7, 53, 6, -8 },
+                        { -7, 28, 66, 7, 46, 1, -6 },
+                        { -4, 35, 67, 7, 38, -3, -5 },
+                        { -6, -1, 43, 7, 67, 31, -6 },
+                        { -7, 4, 50, 7, 66, 23, -8 },
+                        { -8, 10, 57, 7, 61, 16, -8 },
+                        { -8, 17, 62, 7, 56, 9, -8 },
+                        { -7, 25, 65, 7, 49, 3, -7 },
+                        { -5, 32, 68, 7, 41, -2, -6 },
+                        { -5, -2, 40, 7, 66, 34, -5 },
+                        { -7, 2, 47, 7, 67, 26, -7 },
+                        { -8, 8, 54, 7, 63, 19, -8 },
+                        { -8, 14, 60, 7, 58, 12, -8 },
+                        { -8, 22, 64, 7, 52, 5, -7 },
+                        { -6, 29, 67, 7, 44, 0, -6 } },
+               .odd = { { -8, 17, 61, 7, 56, 10, -8 },
+                        { -7, 24, 64, 7, 50, 4, -7 },
+                        { -6, 31, 68, 7, 42, -1, -6 },
+                        { -5, -3, 39, 7, 68, 34, -5 },
+                        { -7, 1, 47, 7, 67, 27, -7 },
+                        { -8, 7, 54, 7, 64, 19, -8 },
+                        { -8, 14, 59, 7, 59, 12, -8 },
+                        { -8, 21, 64, 7, 52, 6, -7 },
+                        { -7, 28, 68, 7, 45, 0, -6 },
+                        { -4, 36, 68, 7, 37, -4, -5 },
+                        { -6, 0, 44, 7, 66, 30, -6 },
+                        { -7, 5, 51, 7, 65, 22, -8 },
+                        { -8, 11, 57, 7, 61, 15, -8 },
+                        { -8, 18, 63, 7, 55, 8, -8 },
+                        { -7, 25, 67, 7, 48, 2, -7 },
+                        { -5, 33, 66, 7, 41, -2, -5 },
+                        { -5, -2, 41, 7, 66, 33, -5 },
+                        { -7, 2, 48, 7, 67, 25, -7 },
+                        { -8, 8, 55, 7, 63, 18, -8 },
+                        { -8, 15, 61, 7, 57, 11, -8 },
+                        { -8, 22, 65, 7, 51, 5, -7 },
+                        { -6, 30, 66, 7, 44, 0, -6 },
+                        { -5, -4, 37, 7, 68, 36, -4 },
+                        { -6, 0, 45, 7, 68, 28, -7 },
+                        { -7, 6, 52, 7, 64, 21, -8 },
+                        { -8, 12, 59, 7, 59, 14, -8 },
+                        { -8, 19, 64, 7, 54, 7, -8 },
+                        { -7, 27, 67, 7, 47, 1, -7 },
+                        { -5, 34, 68, 7, 39, -3, -5 },
+                        { -6, -1, 42, 7, 68, 31, -6 },
+                        { -7, 4, 50, 7, 64, 24, -7 },
+                        { -8, 10, 56, 7, 61, 17, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -4, 37, 67, 7, 37, -4, -5 },
+                        { -6, 0, 44, 7, 67, 29, -6 },
+                        { -7, 5, 52, 7, 64, 22, -8 },
+                        { -8, 12, 58, 7, 60, 14, -8 },
+                        { -8, 19, 63, 7, 54, 8, -8 },
+                        { -7, 26, 67, 7, 47, 2, -7 },
+                        { -5, 34, 66, 7, 40, -2, -5 },
+                        { -6, -2, 41, 7, 68, 32, -5 },
+                        { -7, 3, 49, 7, 65, 25, -7 },
+                        { -8, 9, 56, 7, 62, 17, -8 },
+                        { -8, 16, 61, 7, 57, 10, -8 },
+                        { -8, 23, 66, 7, 50, 4, -7 },
+                        { -6, 31, 67, 7, 43, -1, -6 },
+                        { -5, -3, 38, 7, 67, 35, -4 },
+                        { -6, 1, 46, 7, 66, 28, -7 },
+                        { -8, 6, 53, 7, 65, 20, -8 },
+                        { -8, 13, 59, 7, 59, 13, -8 },
+                        { -8, 20, 65, 7, 53, 6, -8 },
+                        { -7, 28, 66, 7, 46, 1, -6 },
+                        { -4, 35, 67, 7, 38, -3, -5 },
+                        { -6, -1, 43, 7, 67, 31, -6 },
+                        { -7, 4, 50, 7, 66, 23, -8 },
+                        { -8, 10, 57, 7, 61, 16, -8 },
+                        { -8, 17, 62, 7, 56, 9, -8 },
+                        { -7, 25, 65, 7, 49, 3, -7 },
+                        { -5, 32, 68, 7, 41, -2, -6 },
+                        { -5, -2, 40, 7, 66, 34, -5 },
+                        { -7, 2, 47, 7, 67, 26, -7 },
+                        { -8, 8, 54, 7, 63, 19, -8 },
+                        { -8, 14, 60, 7, 58, 12, -8 },
+                        { -8, 22, 64, 7, 52, 5, -7 },
+                        { -6, 29, 67, 7, 44, 0, -6 } },
+               .odd = { { -8, 17, 61, 7, 56, 10, -8 },
+                        { -7, 24, 64, 7, 50, 4, -7 },
+                        { -6, 31, 68, 7, 42, -1, -6 },
+                        { -5, -3, 39, 7, 68, 34, -5 },
+                        { -7, 1, 47, 7, 67, 27, -7 },
+                        { -8, 7, 54, 7, 64, 19, -8 },
+                        { -8, 14, 59, 7, 59, 12, -8 },
+                        { -8, 21, 64, 7, 52, 6, -7 },
+                        { -7, 28, 68, 7, 45, 0, -6 },
+                        { -4, 36, 68, 7, 37, -4, -5 },
+                        { -6, 0, 44, 7, 66, 30, -6 },
+                        { -7, 5, 51, 7, 65, 22, -8 },
+                        { -8, 11, 57, 7, 61, 15, -8 },
+                        { -8, 18, 63, 7, 55, 8, -8 },
+                        { -7, 25, 67, 7, 48, 2, -7 },
+                        { -5, 33, 66, 7, 41, -2, -5 },
+                        { -5, -2, 41, 7, 66, 33, -5 },
+                        { -7, 2, 48, 7, 67, 25, -7 },
+                        { -8, 8, 55, 7, 63, 18, -8 },
+                        { -8, 15, 61, 7, 57, 11, -8 },
+                        { -8, 22, 65, 7, 51, 5, -7 },
+                        { -6, 30, 66, 7, 44, 0, -6 },
+                        { -5, -4, 37, 7, 68, 36, -4 },
+                        { -6, 0, 45, 7, 68, 28, -7 },
+                        { -7, 6, 52, 7, 64, 21, -8 },
+                        { -8, 12, 59, 7, 59, 14, -8 },
+                        { -8, 19, 64, 7, 54, 7, -8 },
+                        { -7, 27, 67, 7, 47, 1, -7 },
+                        { -5, 34, 68, 7, 39, -3, -5 },
+                        { -6, -1, 42, 7, 68, 31, -6 },
+                        { -7, 4, 50, 7, 64, 24, -7 },
+                        { -8, 10, 56, 7, 61, 17, -8 } } },
+       .ptrn_arr = { { 0x99ccce67, 0xce667339, 0x733399cc, 0xcce66 } },
+       .sample_patrn_length = 118,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 28) = 0.533333 */
+       .hor_phase_arr = {
+               .even = { { -3, 37, 65, 7, 37, -3, -5 },
+                        { -6, 0, 43, 7, 65, 31, -5 },
+                        { -7, 4, 48, 7, 65, 25, -7 },
+                        { -8, 9, 54, 7, 62, 19, -8 },
+                        { -8, 14, 58, 7, 58, 14, -8 },
+                        { -8, 19, 62, 7, 54, 9, -8 },
+                        { -7, 25, 65, 7, 48, 4, -7 },
+                        { -5, 31, 65, 7, 43, 0, -6 } },
+               .odd = { { -8, 17, 60, 7, 56, 11, -8 },
+                        { -7, 22, 63, 7, 51, 6, -7 },
+                        { -6, 28, 65, 7, 46, 2, -7 },
+                        { -4, 34, 66, 7, 40, -2, -6 },
+                        { -6, -2, 40, 7, 66, 34, -4 },
+                        { -7, 2, 46, 7, 65, 28, -6 },
+                        { -7, 6, 51, 7, 63, 22, -7 },
+                        { -8, 11, 56, 7, 60, 17, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -3, 37, 65, 7, 37, -3, -5 },
+                        { -6, 0, 43, 7, 65, 31, -5 },
+                        { -7, 4, 48, 7, 65, 25, -7 },
+                        { -8, 9, 54, 7, 62, 19, -8 },
+                        { -8, 14, 58, 7, 58, 14, -8 },
+                        { -8, 19, 62, 7, 54, 9, -8 },
+                        { -7, 25, 65, 7, 48, 4, -7 },
+                        { -5, 31, 65, 7, 43, 0, -6 } },
+               .odd = { { -8, 17, 60, 7, 56, 11, -8 },
+                        { -7, 22, 63, 7, 51, 6, -7 },
+                        { -6, 28, 65, 7, 46, 2, -7 },
+                        { -4, 34, 66, 7, 40, -2, -6 },
+                        { -6, -2, 40, 7, 66, 34, -4 },
+                        { -7, 2, 46, 7, 65, 28, -6 },
+                        { -7, 6, 51, 7, 63, 22, -7 },
+                        { -8, 11, 56, 7, 60, 17, -8 } } },
+       .ptrn_arr = { { 0xccce667 } },
+       .sample_patrn_length = 30,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 29) = 0.52459 */
+       .hor_phase_arr = {
+               .even = { { -2, 37, 63, 7, 37, -2, -5 },
+                        { -6, 0, 41, 7, 64, 33, -4 },
+                        { -7, 3, 45, 7, 65, 28, -6 },
+                        { -7, 6, 49, 7, 63, 24, -7 },
+                        { -8, 9, 53, 7, 61, 20, -7 },
+                        { -8, 13, 56, 7, 59, 16, -8 },
+                        { -8, 17, 60, 7, 55, 12, -8 },
+                        { -7, 21, 62, 7, 52, 8, -8 },
+                        { -6, 26, 62, 7, 48, 5, -7 },
+                        { -5, 30, 64, 7, 44, 2, -7 },
+                        { -4, 34, 65, 7, 40, -1, -6 },
+                        { -6, -2, 38, 7, 66, 35, -3 },
+                        { -6, 1, 42, 7, 65, 31, -5 },
+                        { -7, 4, 47, 7, 63, 27, -6 },
+                        { -7, 7, 50, 7, 62, 23, -7 },
+                        { -8, 11, 54, 7, 59, 19, -7 },
+                        { -8, 15, 57, 7, 57, 15, -8 },
+                        { -7, 19, 59, 7, 54, 11, -8 },
+                        { -7, 23, 62, 7, 50, 7, -7 },
+                        { -6, 27, 63, 7, 47, 4, -7 },
+                        { -5, 31, 65, 7, 42, 1, -6 },
+                        { -3, 35, 66, 7, 38, -2, -6 },
+                        { -6, -1, 40, 7, 65, 34, -4 },
+                        { -7, 2, 44, 7, 64, 30, -5 },
+                        { -7, 5, 48, 7, 62, 26, -6 },
+                        { -8, 8, 52, 7, 62, 21, -7 },
+                        { -8, 12, 55, 7, 60, 17, -8 },
+                        { -8, 16, 59, 7, 56, 13, -8 },
+                        { -7, 20, 61, 7, 53, 9, -8 },
+                        { -7, 24, 63, 7, 49, 6, -7 },
+                        { -6, 28, 65, 7, 45, 3, -7 },
+                        { -4, 33, 64, 7, 41, 0, -6 } },
+               .odd = { { -8, 17, 58, 7, 56, 13, -8 },
+                        { -7, 21, 61, 7, 52, 9, -8 },
+                        { -6, 25, 62, 7, 49, 5, -7 },
+                        { -5, 29, 64, 7, 45, 2, -7 },
+                        { -4, 33, 65, 7, 40, 0, -6 },
+                        { -6, -2, 37, 7, 66, 36, -3 },
+                        { -6, 0, 42, 7, 64, 32, -4 },
+                        { -7, 3, 46, 7, 64, 28, -6 },
+                        { -7, 7, 50, 7, 61, 24, -7 },
+                        { -8, 10, 53, 7, 61, 19, -7 },
+                        { -8, 14, 57, 7, 58, 15, -8 },
+                        { -8, 18, 60, 7, 55, 11, -8 },
+                        { -7, 22, 62, 7, 51, 8, -8 },
+                        { -6, 26, 64, 7, 47, 4, -7 },
+                        { -5, 31, 65, 7, 43, 1, -7 },
+                        { -3, 35, 64, 7, 39, -1, -6 },
+                        { -6, -1, 39, 7, 64, 35, -3 },
+                        { -7, 1, 43, 7, 65, 31, -5 },
+                        { -7, 4, 47, 7, 64, 26, -6 },
+                        { -8, 8, 51, 7, 62, 22, -7 },
+                        { -8, 11, 55, 7, 60, 18, -8 },
+                        { -8, 15, 58, 7, 57, 14, -8 },
+                        { -7, 19, 61, 7, 53, 10, -8 },
+                        { -7, 24, 61, 7, 50, 7, -7 },
+                        { -6, 28, 64, 7, 46, 3, -7 },
+                        { -4, 32, 64, 7, 42, 0, -6 },
+                        { -3, 36, 66, 7, 37, -2, -6 },
+                        { -6, 0, 40, 7, 65, 33, -4 },
+                        { -7, 2, 45, 7, 64, 29, -5 },
+                        { -7, 5, 49, 7, 62, 25, -6 },
+                        { -8, 9, 52, 7, 61, 21, -7 },
+                        { -8, 13, 56, 7, 58, 17, -8 } } },
+       .ver_phase_arr = {
+               .even = { { -2, 37, 63, 7, 37, -2, -5 },
+                        { -6, 0, 41, 7, 64, 33, -4 },
+                        { -7, 3, 45, 7, 65, 28, -6 },
+                        { -7, 6, 49, 7, 63, 24, -7 },
+                        { -8, 9, 53, 7, 61, 20, -7 },
+                        { -8, 13, 56, 7, 59, 16, -8 },
+                        { -8, 17, 60, 7, 55, 12, -8 },
+                        { -7, 21, 62, 7, 52, 8, -8 },
+                        { -6, 26, 62, 7, 48, 5, -7 },
+                        { -5, 30, 64, 7, 44, 2, -7 },
+                        { -4, 34, 65, 7, 40, -1, -6 },
+                        { -6, -2, 38, 7, 66, 35, -3 },
+                        { -6, 1, 42, 7, 65, 31, -5 },
+                        { -7, 4, 47, 7, 63, 27, -6 },
+                        { -7, 7, 50, 7, 62, 23, -7 },
+                        { -8, 11, 54, 7, 59, 19, -7 },
+                        { -8, 15, 57, 7, 57, 15, -8 },
+                        { -7, 19, 59, 7, 54, 11, -8 },
+                        { -7, 23, 62, 7, 50, 7, -7 },
+                        { -6, 27, 63, 7, 47, 4, -7 },
+                        { -5, 31, 65, 7, 42, 1, -6 },
+                        { -3, 35, 66, 7, 38, -2, -6 },
+                        { -6, -1, 40, 7, 65, 34, -4 },
+                        { -7, 2, 44, 7, 64, 30, -5 },
+                        { -7, 5, 48, 7, 62, 26, -6 },
+                        { -8, 8, 52, 7, 62, 21, -7 },
+                        { -8, 12, 55, 7, 60, 17, -8 },
+                        { -8, 16, 59, 7, 56, 13, -8 },
+                        { -7, 20, 61, 7, 53, 9, -8 },
+                        { -7, 24, 63, 7, 49, 6, -7 },
+                        { -6, 28, 65, 7, 45, 3, -7 },
+                        { -4, 33, 64, 7, 41, 0, -6 } },
+               .odd = { { -8, 17, 58, 7, 56, 13, -8 },
+                        { -7, 21, 61, 7, 52, 9, -8 },
+                        { -6, 25, 62, 7, 49, 5, -7 },
+                        { -5, 29, 64, 7, 45, 2, -7 },
+                        { -4, 33, 65, 7, 40, 0, -6 },
+                        { -6, -2, 37, 7, 66, 36, -3 },
+                        { -6, 0, 42, 7, 64, 32, -4 },
+                        { -7, 3, 46, 7, 64, 28, -6 },
+                        { -7, 7, 50, 7, 61, 24, -7 },
+                        { -8, 10, 53, 7, 61, 19, -7 },
+                        { -8, 14, 57, 7, 58, 15, -8 },
+                        { -8, 18, 60, 7, 55, 11, -8 },
+                        { -7, 22, 62, 7, 51, 8, -8 },
+                        { -6, 26, 64, 7, 47, 4, -7 },
+                        { -5, 31, 65, 7, 43, 1, -7 },
+                        { -3, 35, 64, 7, 39, -1, -6 },
+                        { -6, -1, 39, 7, 64, 35, -3 },
+                        { -7, 1, 43, 7, 65, 31, -5 },
+                        { -7, 4, 47, 7, 64, 26, -6 },
+                        { -8, 8, 51, 7, 62, 22, -7 },
+                        { -8, 11, 55, 7, 60, 18, -8 },
+                        { -8, 15, 58, 7, 57, 14, -8 },
+                        { -7, 19, 61, 7, 53, 10, -8 },
+                        { -7, 24, 61, 7, 50, 7, -7 },
+                        { -6, 28, 64, 7, 46, 3, -7 },
+                        { -4, 32, 64, 7, 42, 0, -6 },
+                        { -3, 36, 66, 7, 37, -2, -6 },
+                        { -6, 0, 40, 7, 65, 33, -4 },
+                        { -7, 2, 45, 7, 64, 29, -5 },
+                        { -7, 5, 49, 7, 62, 25, -6 },
+                        { -8, 9, 52, 7, 61, 21, -7 },
+                        { -8, 13, 56, 7, 58, 17, -8 } } },
+       .ptrn_arr = { { 0xccce6667, 0x399999cc, 0x66673333, 0xcccce6 } },
+       .sample_patrn_length = 122,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 30) = 0.516129 */
+       .hor_phase_arr = {
+               .even = { { -2, 37, 64, 7, 37, -2, -6 },
+                        { -6, 0, 39, 7, 64, 34, -3 },
+                        { -7, 2, 42, 7, 64, 31, -4 },
+                        { -7, 4, 45, 7, 62, 29, -5 },
+                        { -7, 6, 47, 7, 62, 26, -6 },
+                        { -7, 8, 50, 7, 60, 23, -6 },
+                        { -8, 10, 52, 7, 60, 21, -7 },
+                        { -8, 13, 54, 7, 58, 18, -7 },
+                        { -8, 15, 58, 7, 56, 15, -8 },
+                        { -7, 18, 58, 7, 54, 13, -8 },
+                        { -7, 21, 60, 7, 52, 10, -8 },
+                        { -6, 23, 60, 7, 50, 8, -7 },
+                        { -6, 26, 62, 7, 47, 6, -7 },
+                        { -5, 29, 62, 7, 45, 4, -7 },
+                        { -4, 31, 64, 7, 42, 2, -7 },
+                        { -3, 34, 64, 7, 39, 0, -6 } },
+               .odd = { { -7, 17, 57, 7, 55, 14, -8 },
+                        { -7, 19, 59, 7, 53, 12, -8 },
+                        { -7, 22, 61, 7, 51, 9, -8 },
+                        { -6, 25, 60, 7, 49, 7, -7 },
+                        { -5, 27, 62, 7, 46, 5, -7 },
+                        { -5, 30, 63, 7, 44, 3, -7 },
+                        { -3, 33, 62, 7, 41, 1, -6 },
+                        { -2, 35, 64, 7, 38, -1, -6 },
+                        { -6, -1, 38, 7, 64, 35, -2 },
+                        { -6, 1, 41, 7, 62, 33, -3 },
+                        { -7, 3, 44, 7, 63, 30, -5 },
+                        { -7, 5, 46, 7, 62, 27, -5 },
+                        { -7, 7, 49, 7, 60, 25, -6 },
+                        { -8, 9, 51, 7, 61, 22, -7 },
+                        { -8, 12, 53, 7, 59, 19, -7 },
+                        { -8, 14, 55, 7, 57, 17, -7 } } },
+       .ver_phase_arr = {
+               .even = { { -2, 37, 64, 7, 37, -2, -6 },
+                        { -6, 0, 39, 7, 64, 34, -3 },
+                        { -7, 2, 42, 7, 64, 31, -4 },
+                        { -7, 4, 45, 7, 62, 29, -5 },
+                        { -7, 6, 47, 7, 62, 26, -6 },
+                        { -7, 8, 50, 7, 60, 23, -6 },
+                        { -8, 10, 52, 7, 60, 21, -7 },
+                        { -8, 13, 54, 7, 58, 18, -7 },
+                        { -8, 15, 58, 7, 56, 15, -8 },
+                        { -7, 18, 58, 7, 54, 13, -8 },
+                        { -7, 21, 60, 7, 52, 10, -8 },
+                        { -6, 23, 60, 7, 50, 8, -7 },
+                        { -6, 26, 62, 7, 47, 6, -7 },
+                        { -5, 29, 62, 7, 45, 4, -7 },
+                        { -4, 31, 64, 7, 42, 2, -7 },
+                        { -3, 34, 64, 7, 39, 0, -6 } },
+               .odd = { { -7, 17, 57, 7, 55, 14, -8 },
+                        { -7, 19, 59, 7, 53, 12, -8 },
+                        { -7, 22, 61, 7, 51, 9, -8 },
+                        { -6, 25, 60, 7, 49, 7, -7 },
+                        { -5, 27, 62, 7, 46, 5, -7 },
+                        { -5, 30, 63, 7, 44, 3, -7 },
+                        { -3, 33, 62, 7, 41, 1, -6 },
+                        { -2, 35, 64, 7, 38, -1, -6 },
+                        { -6, -1, 38, 7, 64, 35, -2 },
+                        { -6, 1, 41, 7, 62, 33, -3 },
+                        { -7, 3, 44, 7, 63, 30, -5 },
+                        { -7, 5, 46, 7, 62, 27, -5 },
+                        { -7, 7, 49, 7, 60, 25, -6 },
+                        { -8, 9, 51, 7, 61, 22, -7 },
+                        { -8, 12, 53, 7, 59, 19, -7 },
+                        { -8, 14, 55, 7, 57, 17, -7 } } },
+       .ptrn_arr = { { 0xe6666667, 0xccccccc } },
+       .sample_patrn_length = 62,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 31) = 0.507937 */
+       .hor_phase_arr = {
+               .even = { { -1, 37, 62, 7, 37, -1, -6 },
+                        { -6, 0, 38, 7, 62, 35, -1 },
+                        { -6, 1, 39, 7, 62, 34, -2 },
+                        { -7, 2, 41, 7, 62, 33, -3 },
+                        { -7, 3, 42, 7, 61, 32, -3 },
+                        { -7, 4, 43, 7, 62, 30, -4 },
+                        { -7, 4, 44, 7, 62, 29, -4 },
+                        { -7, 6, 46, 7, 60, 28, -5 },
+                        { -7, 7, 47, 7, 60, 26, -5 },
+                        { -7, 8, 48, 7, 60, 25, -6 },
+                        { -7, 9, 49, 7, 59, 24, -6 },
+                        { -7, 10, 50, 7, 59, 22, -6 },
+                        { -7, 11, 51, 7, 59, 21, -7 },
+                        { -7, 12, 52, 7, 58, 20, -7 },
+                        { -7, 13, 53, 7, 57, 19, -7 },
+                        { -7, 15, 54, 7, 56, 17, -7 },
+                        { -7, 16, 55, 7, 55, 16, -7 },
+                        { -7, 17, 56, 7, 54, 15, -7 },
+                        { -7, 19, 57, 7, 53, 13, -7 },
+                        { -7, 20, 58, 7, 52, 12, -7 },
+                        { -7, 21, 59, 7, 51, 11, -7 },
+                        { -6, 22, 59, 7, 50, 10, -7 },
+                        { -6, 24, 59, 7, 49, 9, -7 },
+                        { -6, 25, 60, 7, 48, 8, -7 },
+                        { -5, 26, 60, 7, 47, 7, -7 },
+                        { -5, 28, 60, 7, 46, 6, -7 },
+                        { -4, 29, 62, 7, 44, 4, -7 },
+                        { -4, 30, 62, 7, 43, 4, -7 },
+                        { -3, 32, 61, 7, 42, 3, -7 },
+                        { -3, 33, 62, 7, 41, 2, -7 },
+                        { -2, 34, 62, 7, 39, 1, -6 },
+                        { -1, 35, 62, 7, 38, 0, -6 } },
+               .odd = { { -7, 17, 55, 7, 55, 15, -7 },
+                        { -7, 18, 56, 7, 54, 14, -7 },
+                        { -7, 19, 57, 7, 53, 13, -7 },
+                        { -7, 20, 58, 7, 52, 12, -7 },
+                        { -6, 22, 58, 7, 51, 10, -7 },
+                        { -6, 23, 59, 7, 50, 9, -7 },
+                        { -6, 24, 60, 7, 49, 8, -7 },
+                        { -5, 26, 60, 7, 47, 7, -7 },
+                        { -5, 27, 61, 7, 46, 6, -7 },
+                        { -5, 28, 62, 7, 45, 5, -7 },
+                        { -4, 30, 61, 7, 44, 4, -7 },
+                        { -4, 31, 62, 7, 43, 3, -7 },
+                        { -3, 32, 63, 7, 41, 2, -7 },
+                        { -2, 34, 61, 7, 40, 1, -6 },
+                        { -2, 35, 62, 7, 39, 0, -6 },
+                        { -1, 36, 62, 7, 37, 0, -6 },
+                        { -6, 0, 37, 7, 62, 36, -1 },
+                        { -6, 0, 39, 7, 62, 35, -2 },
+                        { -6, 1, 40, 7, 61, 34, -2 },
+                        { -7, 2, 41, 7, 63, 32, -3 },
+                        { -7, 3, 43, 7, 62, 31, -4 },
+                        { -7, 4, 44, 7, 61, 30, -4 },
+                        { -7, 5, 45, 7, 62, 28, -5 },
+                        { -7, 6, 46, 7, 61, 27, -5 },
+                        { -7, 7, 47, 7, 60, 26, -5 },
+                        { -7, 8, 49, 7, 60, 24, -6 },
+                        { -7, 9, 50, 7, 59, 23, -6 },
+                        { -7, 10, 51, 7, 58, 22, -6 },
+                        { -7, 12, 52, 7, 58, 20, -7 },
+                        { -7, 13, 53, 7, 57, 19, -7 },
+                        { -7, 14, 54, 7, 56, 18, -7 },
+                        { -7, 15, 55, 7, 55, 17, -7 } } },
+       .ver_phase_arr = {
+               .even = { { -1, 37, 62, 7, 37, -1, -6 },
+                        { -6, 0, 38, 7, 62, 35, -1 },
+                        { -6, 1, 39, 7, 62, 34, -2 },
+                        { -7, 2, 41, 7, 62, 33, -3 },
+                        { -7, 3, 42, 7, 61, 32, -3 },
+                        { -7, 4, 43, 7, 62, 30, -4 },
+                        { -7, 4, 44, 7, 62, 29, -4 },
+                        { -7, 6, 46, 7, 60, 28, -5 },
+                        { -7, 7, 47, 7, 60, 26, -5 },
+                        { -7, 8, 48, 7, 60, 25, -6 },
+                        { -7, 9, 49, 7, 59, 24, -6 },
+                        { -7, 10, 50, 7, 59, 22, -6 },
+                        { -7, 11, 51, 7, 59, 21, -7 },
+                        { -7, 12, 52, 7, 58, 20, -7 },
+                        { -7, 13, 53, 7, 57, 19, -7 },
+                        { -7, 15, 54, 7, 56, 17, -7 },
+                        { -7, 16, 55, 7, 55, 16, -7 },
+                        { -7, 17, 56, 7, 54, 15, -7 },
+                        { -7, 19, 57, 7, 53, 13, -7 },
+                        { -7, 20, 58, 7, 52, 12, -7 },
+                        { -7, 21, 59, 7, 51, 11, -7 },
+                        { -6, 22, 59, 7, 50, 10, -7 },
+                        { -6, 24, 59, 7, 49, 9, -7 },
+                        { -6, 25, 60, 7, 48, 8, -7 },
+                        { -5, 26, 60, 7, 47, 7, -7 },
+                        { -5, 28, 60, 7, 46, 6, -7 },
+                        { -4, 29, 62, 7, 44, 4, -7 },
+                        { -4, 30, 62, 7, 43, 4, -7 },
+                        { -3, 32, 61, 7, 42, 3, -7 },
+                        { -3, 33, 62, 7, 41, 2, -7 },
+                        { -2, 34, 62, 7, 39, 1, -6 },
+                        { -1, 35, 62, 7, 38, 0, -6 } },
+               .odd = { { -7, 17, 55, 7, 55, 15, -7 },
+                        { -7, 18, 56, 7, 54, 14, -7 },
+                        { -7, 19, 57, 7, 53, 13, -7 },
+                        { -7, 20, 58, 7, 52, 12, -7 },
+                        { -6, 22, 58, 7, 51, 10, -7 },
+                        { -6, 23, 59, 7, 50, 9, -7 },
+                        { -6, 24, 60, 7, 49, 8, -7 },
+                        { -5, 26, 60, 7, 47, 7, -7 },
+                        { -5, 27, 61, 7, 46, 6, -7 },
+                        { -5, 28, 62, 7, 45, 5, -7 },
+                        { -4, 30, 61, 7, 44, 4, -7 },
+                        { -4, 31, 62, 7, 43, 3, -7 },
+                        { -3, 32, 63, 7, 41, 2, -7 },
+                        { -2, 34, 61, 7, 40, 1, -6 },
+                        { -2, 35, 62, 7, 39, 0, -6 },
+                        { -1, 36, 62, 7, 37, 0, -6 },
+                        { -6, 0, 37, 7, 62, 36, -1 },
+                        { -6, 0, 39, 7, 62, 35, -2 },
+                        { -6, 1, 40, 7, 61, 34, -2 },
+                        { -7, 2, 41, 7, 63, 32, -3 },
+                        { -7, 3, 43, 7, 62, 31, -4 },
+                        { -7, 4, 44, 7, 61, 30, -4 },
+                        { -7, 5, 45, 7, 62, 28, -5 },
+                        { -7, 6, 46, 7, 61, 27, -5 },
+                        { -7, 7, 47, 7, 60, 26, -5 },
+                        { -7, 8, 49, 7, 60, 24, -6 },
+                        { -7, 9, 50, 7, 59, 23, -6 },
+                        { -7, 10, 51, 7, 58, 22, -6 },
+                        { -7, 12, 52, 7, 58, 20, -7 },
+                        { -7, 13, 53, 7, 57, 19, -7 },
+                        { -7, 14, 54, 7, 56, 18, -7 },
+                        { -7, 15, 55, 7, 55, 17, -7 } } },
+       .ptrn_arr = { { 0x66666667, 0xe6666666, 0xcccccccc, 0xccccccc } },
+       .sample_patrn_length = 126,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 32) = 0.5 */
+       .hor_phase_arr = {
+               .even = { { 0, 8, 112, 7, 8, 0, 0 } },
+               .odd = { { 0, 0, 64, 7, 64, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 8, 112, 7, 8, 0, 0 } },
+               .odd = { { 0, 0, 64, 7, 64, 0, 0 } } },
+       .ptrn_arr = { { 0x3 } },
+       .sample_patrn_length = 4,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 33) = 0.492308 */
+       .hor_phase_arr = {
+               .even = { { 0, 9, 110, 7, 9, 0, 0 },
+                        { 0, 8, 109, 7, 11, 0, 0 },
+                        { 0, 7, 109, 7, 12, 0, 0 },
+                        { 0, 6, 108, 7, 14, 0, 0 },
+                        { 0, 5, 107, 7, 16, 0, 0 },
+                        { 0, 4, 105, 7, 19, 0, 0 },
+                        { 0, 3, 103, 7, 22, 0, 0 },
+                        { 0, 3, 100, 7, 25, 0, 0 },
+                        { 0, 2, 98, 7, 28, 0, 0 },
+                        { 0, 2, 94, 7, 32, 0, 0 },
+                        { 0, 2, 90, 7, 36, 0, 0 },
+                        { 0, 1, 87, 7, 40, 0, 0 },
+                        { 0, 1, 83, 7, 44, 0, 0 },
+                        { 0, 1, 78, 7, 49, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 },
+                        { 0, 0, 64, 7, 64, 0, 0 },
+                        { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 49, 7, 78, 1, 0 },
+                        { 0, 0, 44, 7, 83, 1, 0 },
+                        { 0, 0, 40, 7, 87, 1, 0 },
+                        { 0, 0, 36, 7, 90, 2, 0 },
+                        { 0, 0, 32, 7, 94, 2, 0 },
+                        { 0, 0, 28, 7, 98, 2, 0 },
+                        { 0, 0, 25, 7, 100, 3, 0 },
+                        { 0, 0, 22, 7, 103, 3, 0 },
+                        { 0, 0, 19, 7, 105, 4, 0 },
+                        { 0, 0, 16, 7, 107, 5, 0 },
+                        { 0, 0, 14, 7, 108, 6, 0 },
+                        { 0, 0, 12, 7, 109, 7, 0 },
+                        { 0, 0, 11, 7, 109, 8, 0 } },
+               .odd = { { 0, 0, 61, 7, 67, 0, 0 },
+                        { 0, 0, 56, 7, 71, 1, 0 },
+                        { 0, 0, 51, 7, 76, 1, 0 },
+                        { 0, 0, 46, 7, 81, 1, 0 },
+                        { 0, 0, 42, 7, 85, 1, 0 },
+                        { 0, 0, 38, 7, 89, 1, 0 },
+                        { 0, 0, 34, 7, 92, 2, 0 },
+                        { 0, 0, 30, 7, 96, 2, 0 },
+                        { 0, 0, 26, 7, 99, 3, 0 },
+                        { 0, 0, 23, 7, 102, 3, 0 },
+                        { 0, 0, 20, 7, 104, 4, 0 },
+                        { 0, 0, 18, 7, 106, 4, 0 },
+                        { 0, 0, 15, 7, 108, 5, 0 },
+                        { 0, 0, 13, 7, 109, 6, 0 },
+                        { 0, 0, 11, 7, 110, 7, 0 },
+                        { 0, 0, 10, 7, 110, 8, 0 },
+                        { 0, 8, 110, 7, 10, 0, 0 },
+                        { 0, 7, 110, 7, 11, 0, 0 },
+                        { 0, 6, 109, 7, 13, 0, 0 },
+                        { 0, 5, 108, 7, 15, 0, 0 },
+                        { 0, 4, 106, 7, 18, 0, 0 },
+                        { 0, 4, 104, 7, 20, 0, 0 },
+                        { 0, 3, 102, 7, 23, 0, 0 },
+                        { 0, 3, 99, 7, 26, 0, 0 },
+                        { 0, 2, 96, 7, 30, 0, 0 },
+                        { 0, 2, 92, 7, 34, 0, 0 },
+                        { 0, 1, 89, 7, 38, 0, 0 },
+                        { 0, 1, 85, 7, 42, 0, 0 },
+                        { 0, 1, 81, 7, 46, 0, 0 },
+                        { 0, 1, 76, 7, 51, 0, 0 },
+                        { 0, 1, 71, 7, 56, 0, 0 },
+                        { 0, 0, 67, 7, 61, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 9, 110, 7, 9, 0, 0 },
+                        { 0, 8, 109, 7, 11, 0, 0 },
+                        { 0, 7, 109, 7, 12, 0, 0 },
+                        { 0, 6, 108, 7, 14, 0, 0 },
+                        { 0, 5, 107, 7, 16, 0, 0 },
+                        { 0, 4, 105, 7, 19, 0, 0 },
+                        { 0, 3, 103, 7, 22, 0, 0 },
+                        { 0, 3, 100, 7, 25, 0, 0 },
+                        { 0, 2, 98, 7, 28, 0, 0 },
+                        { 0, 2, 94, 7, 32, 0, 0 },
+                        { 0, 2, 90, 7, 36, 0, 0 },
+                        { 0, 1, 87, 7, 40, 0, 0 },
+                        { 0, 1, 83, 7, 44, 0, 0 },
+                        { 0, 1, 78, 7, 49, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 },
+                        { 0, 0, 64, 7, 64, 0, 0 },
+                        { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 49, 7, 78, 1, 0 },
+                        { 0, 0, 44, 7, 83, 1, 0 },
+                        { 0, 0, 40, 7, 87, 1, 0 },
+                        { 0, 0, 36, 7, 90, 2, 0 },
+                        { 0, 0, 32, 7, 94, 2, 0 },
+                        { 0, 0, 28, 7, 98, 2, 0 },
+                        { 0, 0, 25, 7, 100, 3, 0 },
+                        { 0, 0, 22, 7, 103, 3, 0 },
+                        { 0, 0, 19, 7, 105, 4, 0 },
+                        { 0, 0, 16, 7, 107, 5, 0 },
+                        { 0, 0, 14, 7, 108, 6, 0 },
+                        { 0, 0, 12, 7, 109, 7, 0 },
+                        { 0, 0, 11, 7, 109, 8, 0 } },
+               .odd = { { 0, 0, 61, 7, 67, 0, 0 },
+                        { 0, 0, 56, 7, 71, 1, 0 },
+                        { 0, 0, 51, 7, 76, 1, 0 },
+                        { 0, 0, 46, 7, 81, 1, 0 },
+                        { 0, 0, 42, 7, 85, 1, 0 },
+                        { 0, 0, 38, 7, 89, 1, 0 },
+                        { 0, 0, 34, 7, 92, 2, 0 },
+                        { 0, 0, 30, 7, 96, 2, 0 },
+                        { 0, 0, 26, 7, 99, 3, 0 },
+                        { 0, 0, 23, 7, 102, 3, 0 },
+                        { 0, 0, 20, 7, 104, 4, 0 },
+                        { 0, 0, 18, 7, 106, 4, 0 },
+                        { 0, 0, 15, 7, 108, 5, 0 },
+                        { 0, 0, 13, 7, 109, 6, 0 },
+                        { 0, 0, 11, 7, 110, 7, 0 },
+                        { 0, 0, 10, 7, 110, 8, 0 },
+                        { 0, 8, 110, 7, 10, 0, 0 },
+                        { 0, 7, 110, 7, 11, 0, 0 },
+                        { 0, 6, 109, 7, 13, 0, 0 },
+                        { 0, 5, 108, 7, 15, 0, 0 },
+                        { 0, 4, 106, 7, 18, 0, 0 },
+                        { 0, 4, 104, 7, 20, 0, 0 },
+                        { 0, 3, 102, 7, 23, 0, 0 },
+                        { 0, 3, 99, 7, 26, 0, 0 },
+                        { 0, 2, 96, 7, 30, 0, 0 },
+                        { 0, 2, 92, 7, 34, 0, 0 },
+                        { 0, 1, 89, 7, 38, 0, 0 },
+                        { 0, 1, 85, 7, 42, 0, 0 },
+                        { 0, 1, 81, 7, 46, 0, 0 },
+                        { 0, 1, 76, 7, 51, 0, 0 },
+                        { 0, 1, 71, 7, 56, 0, 0 },
+                        { 0, 0, 67, 7, 61, 0, 0 } } },
+       .ptrn_arr = { { 0x33333333, 0x33333333, 0x99999999, 0x99999999 } },
+       .sample_patrn_length = 130,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 34) = 0.484848 */
+       .hor_phase_arr = {
+               .even = { { 0, 10, 108, 7, 10, 0, 0 },
+                        { 0, 7, 108, 7, 13, 0, 0 },
+                        { 0, 5, 106, 7, 17, 0, 0 },
+                        { 0, 4, 102, 7, 22, 0, 0 },
+                        { 0, 3, 96, 7, 29, 0, 0 },
+                        { 0, 2, 90, 7, 36, 0, 0 },
+                        { 0, 1, 82, 7, 45, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 64, 7, 64, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 45, 7, 82, 1, 0 },
+                        { 0, 0, 36, 7, 90, 2, 0 },
+                        { 0, 0, 29, 7, 96, 3, 0 },
+                        { 0, 0, 22, 7, 102, 4, 0 },
+                        { 0, 0, 17, 7, 106, 5, 0 },
+                        { 0, 0, 13, 7, 108, 7, 0 } },
+               .odd = { { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 49, 7, 78, 1, 0 },
+                        { 0, 0, 40, 7, 87, 1, 0 },
+                        { 0, 0, 32, 7, 94, 2, 0 },
+                        { 0, 0, 25, 7, 100, 3, 0 },
+                        { 0, 0, 20, 7, 104, 4, 0 },
+                        { 0, 0, 15, 7, 107, 6, 0 },
+                        { 0, 0, 11, 7, 109, 8, 0 },
+                        { 0, 8, 109, 7, 11, 0, 0 },
+                        { 0, 6, 107, 7, 15, 0, 0 },
+                        { 0, 4, 104, 7, 20, 0, 0 },
+                        { 0, 3, 100, 7, 25, 0, 0 },
+                        { 0, 2, 94, 7, 32, 0, 0 },
+                        { 0, 1, 87, 7, 40, 0, 0 },
+                        { 0, 1, 78, 7, 49, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 10, 108, 7, 10, 0, 0 },
+                        { 0, 7, 108, 7, 13, 0, 0 },
+                        { 0, 5, 106, 7, 17, 0, 0 },
+                        { 0, 4, 102, 7, 22, 0, 0 },
+                        { 0, 3, 96, 7, 29, 0, 0 },
+                        { 0, 2, 90, 7, 36, 0, 0 },
+                        { 0, 1, 82, 7, 45, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 64, 7, 64, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 45, 7, 82, 1, 0 },
+                        { 0, 0, 36, 7, 90, 2, 0 },
+                        { 0, 0, 29, 7, 96, 3, 0 },
+                        { 0, 0, 22, 7, 102, 4, 0 },
+                        { 0, 0, 17, 7, 106, 5, 0 },
+                        { 0, 0, 13, 7, 108, 7, 0 } },
+               .odd = { { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 49, 7, 78, 1, 0 },
+                        { 0, 0, 40, 7, 87, 1, 0 },
+                        { 0, 0, 32, 7, 94, 2, 0 },
+                        { 0, 0, 25, 7, 100, 3, 0 },
+                        { 0, 0, 20, 7, 104, 4, 0 },
+                        { 0, 0, 15, 7, 107, 6, 0 },
+                        { 0, 0, 11, 7, 109, 8, 0 },
+                        { 0, 8, 109, 7, 11, 0, 0 },
+                        { 0, 6, 107, 7, 15, 0, 0 },
+                        { 0, 4, 104, 7, 20, 0, 0 },
+                        { 0, 3, 100, 7, 25, 0, 0 },
+                        { 0, 2, 94, 7, 32, 0, 0 },
+                        { 0, 1, 87, 7, 40, 0, 0 },
+                        { 0, 1, 78, 7, 49, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 } } },
+       .ptrn_arr = { { 0x33333333, 0x99999999 } },
+       .sample_patrn_length = 66,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 35) = 0.477612 */
+       .hor_phase_arr = {
+               .even = { { 0, 10, 108, 7, 10, 0, 0 },
+                        { 0, 6, 106, 7, 16, 0, 0 },
+                        { 0, 4, 101, 7, 23, 0, 0 },
+                        { 0, 2, 93, 7, 33, 0, 0 },
+                        { 0, 1, 82, 7, 45, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 41, 7, 85, 2, 0 },
+                        { 0, 0, 29, 7, 96, 3, 0 },
+                        { 0, 0, 20, 7, 103, 5, 0 },
+                        { 0, 0, 14, 7, 106, 8, 0 },
+                        { 0, 9, 107, 7, 12, 0, 0 },
+                        { 0, 5, 105, 7, 18, 0, 0 },
+                        { 0, 3, 99, 7, 26, 0, 0 },
+                        { 0, 2, 89, 7, 37, 0, 0 },
+                        { 0, 1, 77, 7, 50, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 50, 7, 77, 1, 0 },
+                        { 0, 0, 37, 7, 89, 2, 0 },
+                        { 0, 0, 26, 7, 99, 3, 0 },
+                        { 0, 0, 18, 7, 105, 5, 0 },
+                        { 0, 0, 12, 7, 107, 9, 0 },
+                        { 0, 8, 106, 7, 14, 0, 0 },
+                        { 0, 5, 103, 7, 20, 0, 0 },
+                        { 0, 3, 96, 7, 29, 0, 0 },
+                        { 0, 2, 85, 7, 41, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 45, 7, 82, 1, 0 },
+                        { 0, 0, 33, 7, 93, 2, 0 },
+                        { 0, 0, 23, 7, 101, 4, 0 },
+                        { 0, 0, 16, 7, 106, 6, 0 } },
+               .odd = { { 0, 0, 56, 7, 71, 1, 0 },
+                        { 0, 0, 43, 7, 84, 1, 0 },
+                        { 0, 0, 31, 7, 94, 3, 0 },
+                        { 0, 0, 22, 7, 102, 4, 0 },
+                        { 0, 0, 15, 7, 106, 7, 0 },
+                        { 0, 9, 108, 7, 11, 0, 0 },
+                        { 0, 6, 105, 7, 17, 0, 0 },
+                        { 0, 4, 99, 7, 25, 0, 0 },
+                        { 0, 2, 91, 7, 35, 0, 0 },
+                        { 0, 1, 80, 7, 47, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 52, 7, 75, 1, 0 },
+                        { 0, 0, 39, 7, 87, 2, 0 },
+                        { 0, 0, 28, 7, 97, 3, 0 },
+                        { 0, 0, 19, 7, 104, 5, 0 },
+                        { 0, 0, 13, 7, 107, 8, 0 },
+                        { 0, 8, 107, 7, 13, 0, 0 },
+                        { 0, 5, 104, 7, 19, 0, 0 },
+                        { 0, 3, 97, 7, 28, 0, 0 },
+                        { 0, 2, 87, 7, 39, 0, 0 },
+                        { 0, 1, 75, 7, 52, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 47, 7, 80, 1, 0 },
+                        { 0, 0, 35, 7, 91, 2, 0 },
+                        { 0, 0, 25, 7, 99, 4, 0 },
+                        { 0, 0, 17, 7, 105, 6, 0 },
+                        { 0, 0, 11, 7, 108, 9, 0 },
+                        { 0, 7, 106, 7, 15, 0, 0 },
+                        { 0, 4, 102, 7, 22, 0, 0 },
+                        { 0, 3, 94, 7, 31, 0, 0 },
+                        { 0, 1, 84, 7, 43, 0, 0 },
+                        { 0, 1, 71, 7, 56, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 10, 108, 7, 10, 0, 0 },
+                        { 0, 6, 106, 7, 16, 0, 0 },
+                        { 0, 4, 101, 7, 23, 0, 0 },
+                        { 0, 2, 93, 7, 33, 0, 0 },
+                        { 0, 1, 82, 7, 45, 0, 0 },
+                        { 0, 1, 68, 7, 59, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 41, 7, 85, 2, 0 },
+                        { 0, 0, 29, 7, 96, 3, 0 },
+                        { 0, 0, 20, 7, 103, 5, 0 },
+                        { 0, 0, 14, 7, 106, 8, 0 },
+                        { 0, 9, 107, 7, 12, 0, 0 },
+                        { 0, 5, 105, 7, 18, 0, 0 },
+                        { 0, 3, 99, 7, 26, 0, 0 },
+                        { 0, 2, 89, 7, 37, 0, 0 },
+                        { 0, 1, 77, 7, 50, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 50, 7, 77, 1, 0 },
+                        { 0, 0, 37, 7, 89, 2, 0 },
+                        { 0, 0, 26, 7, 99, 3, 0 },
+                        { 0, 0, 18, 7, 105, 5, 0 },
+                        { 0, 0, 12, 7, 107, 9, 0 },
+                        { 0, 8, 106, 7, 14, 0, 0 },
+                        { 0, 5, 103, 7, 20, 0, 0 },
+                        { 0, 3, 96, 7, 29, 0, 0 },
+                        { 0, 2, 85, 7, 41, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 59, 7, 68, 1, 0 },
+                        { 0, 0, 45, 7, 82, 1, 0 },
+                        { 0, 0, 33, 7, 93, 2, 0 },
+                        { 0, 0, 23, 7, 101, 4, 0 },
+                        { 0, 0, 16, 7, 106, 6, 0 } },
+               .odd = { { 0, 0, 56, 7, 71, 1, 0 },
+                        { 0, 0, 43, 7, 84, 1, 0 },
+                        { 0, 0, 31, 7, 94, 3, 0 },
+                        { 0, 0, 22, 7, 102, 4, 0 },
+                        { 0, 0, 15, 7, 106, 7, 0 },
+                        { 0, 9, 108, 7, 11, 0, 0 },
+                        { 0, 6, 105, 7, 17, 0, 0 },
+                        { 0, 4, 99, 7, 25, 0, 0 },
+                        { 0, 2, 91, 7, 35, 0, 0 },
+                        { 0, 1, 80, 7, 47, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 52, 7, 75, 1, 0 },
+                        { 0, 0, 39, 7, 87, 2, 0 },
+                        { 0, 0, 28, 7, 97, 3, 0 },
+                        { 0, 0, 19, 7, 104, 5, 0 },
+                        { 0, 0, 13, 7, 107, 8, 0 },
+                        { 0, 8, 107, 7, 13, 0, 0 },
+                        { 0, 5, 104, 7, 19, 0, 0 },
+                        { 0, 3, 97, 7, 28, 0, 0 },
+                        { 0, 2, 87, 7, 39, 0, 0 },
+                        { 0, 1, 75, 7, 52, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 47, 7, 80, 1, 0 },
+                        { 0, 0, 35, 7, 91, 2, 0 },
+                        { 0, 0, 25, 7, 99, 4, 0 },
+                        { 0, 0, 17, 7, 105, 6, 0 },
+                        { 0, 0, 11, 7, 108, 9, 0 },
+                        { 0, 7, 106, 7, 15, 0, 0 },
+                        { 0, 4, 102, 7, 22, 0, 0 },
+                        { 0, 3, 94, 7, 31, 0, 0 },
+                        { 0, 1, 84, 7, 43, 0, 0 },
+                        { 0, 1, 71, 7, 56, 0, 0 } } },
+       .ptrn_arr = { { 0x99933333, 0xccccc999, 0x32666664, 0x99993333,
+                        0x9 } },
+       .sample_patrn_length = 134,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 36) = 0.470588 */
+       .hor_phase_arr = {
+               .even = { { 0, 11, 106, 7, 11, 0, 0 },
+                        { 0, 6, 103, 7, 19, 0, 0 },
+                        { 0, 3, 95, 7, 30, 0, 0 },
+                        { 0, 1, 81, 7, 46, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 46, 7, 81, 1, 0 },
+                        { 0, 0, 30, 7, 95, 3, 0 },
+                        { 0, 0, 19, 7, 103, 6, 0 } },
+               .odd = { { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 37, 7, 89, 2, 0 },
+                        { 0, 0, 24, 7, 100, 4, 0 },
+                        { 0, 0, 14, 7, 106, 8, 0 },
+                        { 0, 8, 106, 7, 14, 0, 0 },
+                        { 0, 4, 100, 7, 24, 0, 0 },
+                        { 0, 2, 89, 7, 37, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 11, 106, 7, 11, 0, 0 },
+                        { 0, 6, 103, 7, 19, 0, 0 },
+                        { 0, 3, 95, 7, 30, 0, 0 },
+                        { 0, 1, 81, 7, 46, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 46, 7, 81, 1, 0 },
+                        { 0, 0, 30, 7, 95, 3, 0 },
+                        { 0, 0, 19, 7, 103, 6, 0 } },
+               .odd = { { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 37, 7, 89, 2, 0 },
+                        { 0, 0, 24, 7, 100, 4, 0 },
+                        { 0, 0, 14, 7, 106, 8, 0 },
+                        { 0, 8, 106, 7, 14, 0, 0 },
+                        { 0, 4, 100, 7, 24, 0, 0 },
+                        { 0, 2, 89, 7, 37, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 } } },
+       .ptrn_arr = { { 0x99993333 } },
+       .sample_patrn_length = 34,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 37) = 0.463768 */
+       .hor_phase_arr = {
+               .even = { { 0, 11, 106, 7, 11, 0, 0 },
+                        { 0, 5, 101, 7, 22, 0, 0 },
+                        { 0, 2, 88, 7, 38, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 46, 7, 80, 2, 0 },
+                        { 0, 0, 28, 7, 96, 4, 0 },
+                        { 0, 0, 15, 7, 104, 9, 0 },
+                        { 0, 7, 104, 7, 17, 0, 0 },
+                        { 0, 3, 94, 7, 31, 0, 0 },
+                        { 0, 1, 77, 7, 50, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 34, 7, 91, 3, 0 },
+                        { 0, 0, 19, 7, 103, 6, 0 },
+                        { 0, 10, 105, 7, 13, 0, 0 },
+                        { 0, 5, 98, 7, 25, 0, 0 },
+                        { 0, 2, 84, 7, 42, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 42, 7, 84, 2, 0 },
+                        { 0, 0, 25, 7, 98, 5, 0 },
+                        { 0, 0, 13, 7, 105, 10, 0 },
+                        { 0, 6, 103, 7, 19, 0, 0 },
+                        { 0, 3, 91, 7, 34, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 50, 7, 77, 1, 0 },
+                        { 0, 0, 31, 7, 94, 3, 0 },
+                        { 0, 0, 17, 7, 104, 7, 0 },
+                        { 0, 9, 104, 7, 15, 0, 0 },
+                        { 0, 4, 96, 7, 28, 0, 0 },
+                        { 0, 2, 80, 7, 46, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 38, 7, 88, 2, 0 },
+                        { 0, 0, 22, 7, 101, 5, 0 } },
+               .odd = { { 0, 0, 52, 7, 75, 1, 0 },
+                        { 0, 0, 33, 7, 92, 3, 0 },
+                        { 0, 0, 18, 7, 103, 7, 0 },
+                        { 0, 9, 105, 7, 14, 0, 0 },
+                        { 0, 4, 98, 7, 26, 0, 0 },
+                        { 0, 2, 82, 7, 44, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 40, 7, 86, 2, 0 },
+                        { 0, 0, 23, 7, 100, 5, 0 },
+                        { 0, 0, 12, 7, 105, 11, 0 },
+                        { 0, 6, 101, 7, 21, 0, 0 },
+                        { 0, 3, 89, 7, 36, 0, 0 },
+                        { 0, 1, 69, 7, 57, 1, 0 },
+                        { 0, 0, 48, 7, 79, 1, 0 },
+                        { 0, 0, 29, 7, 95, 4, 0 },
+                        { 0, 0, 16, 7, 104, 8, 0 },
+                        { 0, 8, 104, 7, 16, 0, 0 },
+                        { 0, 4, 95, 7, 29, 0, 0 },
+                        { 0, 1, 79, 7, 48, 0, 0 },
+                        { 0, 1, 57, 7, 69, 1, 0 },
+                        { 0, 0, 36, 7, 89, 3, 0 },
+                        { 0, 0, 21, 7, 101, 6, 0 },
+                        { 0, 11, 105, 7, 12, 0, 0 },
+                        { 0, 5, 100, 7, 23, 0, 0 },
+                        { 0, 2, 86, 7, 40, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 44, 7, 82, 2, 0 },
+                        { 0, 0, 26, 7, 98, 4, 0 },
+                        { 0, 0, 14, 7, 105, 9, 0 },
+                        { 0, 7, 103, 7, 18, 0, 0 },
+                        { 0, 3, 92, 7, 33, 0, 0 },
+                        { 0, 1, 75, 7, 52, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 11, 106, 7, 11, 0, 0 },
+                        { 0, 5, 101, 7, 22, 0, 0 },
+                        { 0, 2, 88, 7, 38, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 46, 7, 80, 2, 0 },
+                        { 0, 0, 28, 7, 96, 4, 0 },
+                        { 0, 0, 15, 7, 104, 9, 0 },
+                        { 0, 7, 104, 7, 17, 0, 0 },
+                        { 0, 3, 94, 7, 31, 0, 0 },
+                        { 0, 1, 77, 7, 50, 0, 0 },
+                        { 0, 0, 54, 7, 73, 1, 0 },
+                        { 0, 0, 34, 7, 91, 3, 0 },
+                        { 0, 0, 19, 7, 103, 6, 0 },
+                        { 0, 10, 105, 7, 13, 0, 0 },
+                        { 0, 5, 98, 7, 25, 0, 0 },
+                        { 0, 2, 84, 7, 42, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 42, 7, 84, 2, 0 },
+                        { 0, 0, 25, 7, 98, 5, 0 },
+                        { 0, 0, 13, 7, 105, 10, 0 },
+                        { 0, 6, 103, 7, 19, 0, 0 },
+                        { 0, 3, 91, 7, 34, 0, 0 },
+                        { 0, 1, 73, 7, 54, 0, 0 },
+                        { 0, 0, 50, 7, 77, 1, 0 },
+                        { 0, 0, 31, 7, 94, 3, 0 },
+                        { 0, 0, 17, 7, 104, 7, 0 },
+                        { 0, 9, 104, 7, 15, 0, 0 },
+                        { 0, 4, 96, 7, 28, 0, 0 },
+                        { 0, 2, 80, 7, 46, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 38, 7, 88, 2, 0 },
+                        { 0, 0, 22, 7, 101, 5, 0 } },
+               .odd = { { 0, 0, 52, 7, 75, 1, 0 },
+                        { 0, 0, 33, 7, 92, 3, 0 },
+                        { 0, 0, 18, 7, 103, 7, 0 },
+                        { 0, 9, 105, 7, 14, 0, 0 },
+                        { 0, 4, 98, 7, 26, 0, 0 },
+                        { 0, 2, 82, 7, 44, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 40, 7, 86, 2, 0 },
+                        { 0, 0, 23, 7, 100, 5, 0 },
+                        { 0, 0, 12, 7, 105, 11, 0 },
+                        { 0, 6, 101, 7, 21, 0, 0 },
+                        { 0, 3, 89, 7, 36, 0, 0 },
+                        { 0, 1, 69, 7, 57, 1, 0 },
+                        { 0, 0, 48, 7, 79, 1, 0 },
+                        { 0, 0, 29, 7, 95, 4, 0 },
+                        { 0, 0, 16, 7, 104, 8, 0 },
+                        { 0, 8, 104, 7, 16, 0, 0 },
+                        { 0, 4, 95, 7, 29, 0, 0 },
+                        { 0, 1, 79, 7, 48, 0, 0 },
+                        { 0, 1, 57, 7, 69, 1, 0 },
+                        { 0, 0, 36, 7, 89, 3, 0 },
+                        { 0, 0, 21, 7, 101, 6, 0 },
+                        { 0, 11, 105, 7, 12, 0, 0 },
+                        { 0, 5, 100, 7, 23, 0, 0 },
+                        { 0, 2, 86, 7, 40, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 44, 7, 82, 2, 0 },
+                        { 0, 0, 26, 7, 98, 4, 0 },
+                        { 0, 0, 14, 7, 105, 9, 0 },
+                        { 0, 7, 103, 7, 18, 0, 0 },
+                        { 0, 3, 92, 7, 33, 0, 0 },
+                        { 0, 1, 75, 7, 52, 0, 0 } } },
+       .ptrn_arr = { { 0xc9999333, 0x332664cc, 0x4cc99993, 0x93332666,
+                        0x99 } },
+       .sample_patrn_length = 138,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 38) = 0.457143 */
+       .hor_phase_arr = {
+               .even = { { 0, 12, 104, 7, 12, 0, 0 },
+                        { 0, 5, 98, 7, 25, 0, 0 },
+                        { 0, 2, 80, 7, 46, 0, 0 },
+                        { 0, 1, 55, 7, 71, 1, 0 },
+                        { 0, 0, 32, 7, 92, 4, 0 },
+                        { 0, 0, 16, 7, 103, 9, 0 },
+                        { 0, 7, 101, 7, 20, 0, 0 },
+                        { 0, 3, 86, 7, 39, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 39, 7, 86, 3, 0 },
+                        { 0, 0, 20, 7, 101, 7, 0 },
+                        { 0, 9, 103, 7, 16, 0, 0 },
+                        { 0, 4, 92, 7, 32, 0, 0 },
+                        { 0, 1, 71, 7, 55, 1, 0 },
+                        { 0, 0, 46, 7, 80, 2, 0 },
+                        { 0, 0, 25, 7, 98, 5, 0 } },
+               .odd = { { 0, 0, 50, 7, 76, 2, 0 },
+                        { 0, 0, 28, 7, 96, 4, 0 },
+                        { 0, 0, 14, 7, 104, 10, 0 },
+                        { 0, 6, 99, 7, 23, 0, 0 },
+                        { 0, 2, 84, 7, 42, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 35, 7, 90, 3, 0 },
+                        { 0, 0, 18, 7, 102, 8, 0 },
+                        { 0, 8, 102, 7, 18, 0, 0 },
+                        { 0, 3, 90, 7, 35, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 42, 7, 84, 2, 0 },
+                        { 0, 0, 23, 7, 99, 6, 0 },
+                        { 0, 10, 104, 7, 14, 0, 0 },
+                        { 0, 4, 96, 7, 28, 0, 0 },
+                        { 0, 2, 76, 7, 50, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 12, 104, 7, 12, 0, 0 },
+                        { 0, 5, 98, 7, 25, 0, 0 },
+                        { 0, 2, 80, 7, 46, 0, 0 },
+                        { 0, 1, 55, 7, 71, 1, 0 },
+                        { 0, 0, 32, 7, 92, 4, 0 },
+                        { 0, 0, 16, 7, 103, 9, 0 },
+                        { 0, 7, 101, 7, 20, 0, 0 },
+                        { 0, 3, 86, 7, 39, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 39, 7, 86, 3, 0 },
+                        { 0, 0, 20, 7, 101, 7, 0 },
+                        { 0, 9, 103, 7, 16, 0, 0 },
+                        { 0, 4, 92, 7, 32, 0, 0 },
+                        { 0, 1, 71, 7, 55, 1, 0 },
+                        { 0, 0, 46, 7, 80, 2, 0 },
+                        { 0, 0, 25, 7, 98, 5, 0 } },
+               .odd = { { 0, 0, 50, 7, 76, 2, 0 },
+                        { 0, 0, 28, 7, 96, 4, 0 },
+                        { 0, 0, 14, 7, 104, 10, 0 },
+                        { 0, 6, 99, 7, 23, 0, 0 },
+                        { 0, 2, 84, 7, 42, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 35, 7, 90, 3, 0 },
+                        { 0, 0, 18, 7, 102, 8, 0 },
+                        { 0, 8, 102, 7, 18, 0, 0 },
+                        { 0, 3, 90, 7, 35, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 42, 7, 84, 2, 0 },
+                        { 0, 0, 23, 7, 99, 6, 0 },
+                        { 0, 10, 104, 7, 14, 0, 0 },
+                        { 0, 4, 96, 7, 28, 0, 0 },
+                        { 0, 2, 76, 7, 50, 0, 0 } } },
+       .ptrn_arr = { { 0xcc999333, 0x99332664, 0x9 } },
+       .sample_patrn_length = 70,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 39) = 0.450704 */
+       .hor_phase_arr = {
+               .even = { { 0, 13, 102, 7, 13, 0, 0 },
+                        { 0, 5, 94, 7, 29, 0, 0 },
+                        { 0, 1, 71, 7, 55, 1, 0 },
+                        { 0, 0, 43, 7, 83, 2, 0 },
+                        { 0, 0, 21, 7, 100, 7, 0 },
+                        { 0, 8, 102, 7, 18, 0, 0 },
+                        { 0, 3, 86, 7, 39, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 32, 7, 92, 4, 0 },
+                        { 0, 0, 14, 7, 103, 11, 0 },
+                        { 0, 5, 97, 7, 26, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 47, 7, 79, 2, 0 },
+                        { 0, 0, 23, 7, 99, 6, 0 },
+                        { 0, 10, 102, 7, 16, 0, 0 },
+                        { 0, 3, 89, 7, 36, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 36, 7, 89, 3, 0 },
+                        { 0, 0, 16, 7, 102, 10, 0 },
+                        { 0, 6, 99, 7, 23, 0, 0 },
+                        { 0, 2, 79, 7, 47, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 26, 7, 97, 5, 0 },
+                        { 0, 11, 103, 7, 14, 0, 0 },
+                        { 0, 4, 92, 7, 32, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 39, 7, 86, 3, 0 },
+                        { 0, 0, 18, 7, 102, 8, 0 },
+                        { 0, 7, 100, 7, 21, 0, 0 },
+                        { 0, 2, 83, 7, 43, 0, 0 },
+                        { 0, 1, 55, 7, 71, 1, 0 },
+                        { 0, 0, 29, 7, 94, 5, 0 } },
+               .odd = { { 0, 0, 49, 7, 77, 2, 0 },
+                        { 0, 0, 25, 7, 97, 6, 0 },
+                        { 0, 10, 103, 7, 15, 0, 0 },
+                        { 0, 4, 90, 7, 34, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 37, 7, 88, 3, 0 },
+                        { 0, 0, 17, 7, 102, 9, 0 },
+                        { 0, 7, 99, 7, 22, 0, 0 },
+                        { 0, 2, 81, 7, 45, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 27, 7, 96, 5, 0 },
+                        { 0, 12, 103, 7, 13, 0, 0 },
+                        { 0, 4, 93, 7, 31, 0, 0 },
+                        { 0, 1, 69, 7, 57, 1, 0 },
+                        { 0, 0, 41, 7, 84, 3, 0 },
+                        { 0, 0, 20, 7, 100, 8, 0 },
+                        { 0, 8, 100, 7, 20, 0, 0 },
+                        { 0, 3, 84, 7, 41, 0, 0 },
+                        { 0, 1, 57, 7, 69, 1, 0 },
+                        { 0, 0, 31, 7, 93, 4, 0 },
+                        { 0, 0, 13, 7, 103, 12, 0 },
+                        { 0, 5, 96, 7, 27, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 45, 7, 81, 2, 0 },
+                        { 0, 0, 22, 7, 99, 7, 0 },
+                        { 0, 9, 102, 7, 17, 0, 0 },
+                        { 0, 3, 88, 7, 37, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 34, 7, 90, 4, 0 },
+                        { 0, 0, 15, 7, 103, 10, 0 },
+                        { 0, 6, 97, 7, 25, 0, 0 },
+                        { 0, 2, 77, 7, 49, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 13, 102, 7, 13, 0, 0 },
+                        { 0, 5, 94, 7, 29, 0, 0 },
+                        { 0, 1, 71, 7, 55, 1, 0 },
+                        { 0, 0, 43, 7, 83, 2, 0 },
+                        { 0, 0, 21, 7, 100, 7, 0 },
+                        { 0, 8, 102, 7, 18, 0, 0 },
+                        { 0, 3, 86, 7, 39, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 32, 7, 92, 4, 0 },
+                        { 0, 0, 14, 7, 103, 11, 0 },
+                        { 0, 5, 97, 7, 26, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 47, 7, 79, 2, 0 },
+                        { 0, 0, 23, 7, 99, 6, 0 },
+                        { 0, 10, 102, 7, 16, 0, 0 },
+                        { 0, 3, 89, 7, 36, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 36, 7, 89, 3, 0 },
+                        { 0, 0, 16, 7, 102, 10, 0 },
+                        { 0, 6, 99, 7, 23, 0, 0 },
+                        { 0, 2, 79, 7, 47, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 26, 7, 97, 5, 0 },
+                        { 0, 11, 103, 7, 14, 0, 0 },
+                        { 0, 4, 92, 7, 32, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 39, 7, 86, 3, 0 },
+                        { 0, 0, 18, 7, 102, 8, 0 },
+                        { 0, 7, 100, 7, 21, 0, 0 },
+                        { 0, 2, 83, 7, 43, 0, 0 },
+                        { 0, 1, 55, 7, 71, 1, 0 },
+                        { 0, 0, 29, 7, 94, 5, 0 } },
+               .odd = { { 0, 0, 49, 7, 77, 2, 0 },
+                        { 0, 0, 25, 7, 97, 6, 0 },
+                        { 0, 10, 103, 7, 15, 0, 0 },
+                        { 0, 4, 90, 7, 34, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 37, 7, 88, 3, 0 },
+                        { 0, 0, 17, 7, 102, 9, 0 },
+                        { 0, 7, 99, 7, 22, 0, 0 },
+                        { 0, 2, 81, 7, 45, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 27, 7, 96, 5, 0 },
+                        { 0, 12, 103, 7, 13, 0, 0 },
+                        { 0, 4, 93, 7, 31, 0, 0 },
+                        { 0, 1, 69, 7, 57, 1, 0 },
+                        { 0, 0, 41, 7, 84, 3, 0 },
+                        { 0, 0, 20, 7, 100, 8, 0 },
+                        { 0, 8, 100, 7, 20, 0, 0 },
+                        { 0, 3, 84, 7, 41, 0, 0 },
+                        { 0, 1, 57, 7, 69, 1, 0 },
+                        { 0, 0, 31, 7, 93, 4, 0 },
+                        { 0, 0, 13, 7, 103, 12, 0 },
+                        { 0, 5, 96, 7, 27, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 45, 7, 81, 2, 0 },
+                        { 0, 0, 22, 7, 99, 7, 0 },
+                        { 0, 9, 102, 7, 17, 0, 0 },
+                        { 0, 3, 88, 7, 37, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 34, 7, 90, 4, 0 },
+                        { 0, 0, 15, 7, 103, 10, 0 },
+                        { 0, 6, 97, 7, 25, 0, 0 },
+                        { 0, 2, 77, 7, 49, 0, 0 } } },
+       .ptrn_arr = { { 0x4cc99933, 0xc9993266, 0x9332664c, 0x32664cc9,
+                        0x993 } },
+       .sample_patrn_length = 142,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 40) = 0.444444 */
+       .hor_phase_arr = {
+               .even = { { 0, 13, 102, 7, 13, 0, 0 },
+                        { 0, 4, 91, 7, 33, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 33, 7, 91, 4, 0 } },
+               .odd = { { 0, 0, 47, 7, 79, 2, 0 },
+                        { 0, 0, 21, 7, 99, 8, 0 },
+                        { 0, 8, 99, 7, 21, 0, 0 },
+                        { 0, 2, 79, 7, 47, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 13, 102, 7, 13, 0, 0 },
+                        { 0, 4, 91, 7, 33, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 33, 7, 91, 4, 0 } },
+               .odd = { { 0, 0, 47, 7, 79, 2, 0 },
+                        { 0, 0, 21, 7, 99, 8, 0 },
+                        { 0, 8, 99, 7, 21, 0, 0 },
+                        { 0, 2, 79, 7, 47, 0, 0 } } },
+       .ptrn_arr = { { 0x9933 } },
+       .sample_patrn_length = 18,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 41) = 0.438356 */
+       .hor_phase_arr = {
+               .even = { { 0, 14, 100, 7, 14, 0, 0 },
+                        { 0, 4, 87, 7, 37, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 25, 7, 96, 7, 0 },
+                        { 0, 8, 98, 7, 22, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 40, 7, 85, 3, 0 },
+                        { 0, 0, 16, 7, 100, 12, 0 },
+                        { 0, 5, 90, 7, 33, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 27, 7, 95, 6, 0 },
+                        { 0, 9, 99, 7, 20, 0, 0 },
+                        { 0, 2, 78, 7, 47, 1, 0 },
+                        { 0, 0, 44, 7, 81, 3, 0 },
+                        { 0, 0, 18, 7, 99, 11, 0 },
+                        { 0, 5, 93, 7, 30, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 30, 7, 93, 5, 0 },
+                        { 0, 11, 99, 7, 18, 0, 0 },
+                        { 0, 3, 81, 7, 44, 0, 0 },
+                        { 0, 1, 47, 7, 78, 2, 0 },
+                        { 0, 0, 20, 7, 99, 9, 0 },
+                        { 0, 6, 95, 7, 27, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 33, 7, 90, 5, 0 },
+                        { 0, 12, 100, 7, 16, 0, 0 },
+                        { 0, 3, 85, 7, 40, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 22, 7, 98, 8, 0 },
+                        { 0, 7, 96, 7, 25, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 37, 7, 87, 4, 0 } },
+               .odd = { { 0, 0, 45, 7, 80, 3, 0 },
+                        { 0, 0, 19, 7, 99, 10, 0 },
+                        { 0, 6, 93, 7, 29, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 32, 7, 91, 5, 0 },
+                        { 0, 11, 100, 7, 17, 0, 0 },
+                        { 0, 3, 83, 7, 42, 0, 0 },
+                        { 0, 1, 49, 7, 76, 2, 0 },
+                        { 0, 0, 21, 7, 98, 9, 0 },
+                        { 0, 7, 95, 7, 26, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 35, 7, 89, 4, 0 },
+                        { 0, 13, 100, 7, 15, 0, 0 },
+                        { 0, 4, 86, 7, 38, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 23, 7, 97, 8, 0 },
+                        { 0, 8, 97, 7, 23, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 38, 7, 86, 4, 0 },
+                        { 0, 0, 15, 7, 100, 13, 0 },
+                        { 0, 4, 89, 7, 35, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 26, 7, 95, 7, 0 },
+                        { 0, 9, 98, 7, 21, 0, 0 },
+                        { 0, 2, 76, 7, 49, 1, 0 },
+                        { 0, 0, 42, 7, 83, 3, 0 },
+                        { 0, 0, 17, 7, 100, 11, 0 },
+                        { 0, 5, 91, 7, 32, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 29, 7, 93, 6, 0 },
+                        { 0, 10, 99, 7, 19, 0, 0 },
+                        { 0, 3, 80, 7, 45, 0, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 14, 100, 7, 14, 0, 0 },
+                        { 0, 4, 87, 7, 37, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 25, 7, 96, 7, 0 },
+                        { 0, 8, 98, 7, 22, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 40, 7, 85, 3, 0 },
+                        { 0, 0, 16, 7, 100, 12, 0 },
+                        { 0, 5, 90, 7, 33, 0, 0 },
+                        { 0, 1, 59, 7, 67, 1, 0 },
+                        { 0, 0, 27, 7, 95, 6, 0 },
+                        { 0, 9, 99, 7, 20, 0, 0 },
+                        { 0, 2, 78, 7, 47, 1, 0 },
+                        { 0, 0, 44, 7, 81, 3, 0 },
+                        { 0, 0, 18, 7, 99, 11, 0 },
+                        { 0, 5, 93, 7, 30, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 30, 7, 93, 5, 0 },
+                        { 0, 11, 99, 7, 18, 0, 0 },
+                        { 0, 3, 81, 7, 44, 0, 0 },
+                        { 0, 1, 47, 7, 78, 2, 0 },
+                        { 0, 0, 20, 7, 99, 9, 0 },
+                        { 0, 6, 95, 7, 27, 0, 0 },
+                        { 0, 1, 67, 7, 59, 1, 0 },
+                        { 0, 0, 33, 7, 90, 5, 0 },
+                        { 0, 12, 100, 7, 16, 0, 0 },
+                        { 0, 3, 85, 7, 40, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 22, 7, 98, 8, 0 },
+                        { 0, 7, 96, 7, 25, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 37, 7, 87, 4, 0 } },
+               .odd = { { 0, 0, 45, 7, 80, 3, 0 },
+                        { 0, 0, 19, 7, 99, 10, 0 },
+                        { 0, 6, 93, 7, 29, 0, 0 },
+                        { 0, 1, 65, 7, 61, 1, 0 },
+                        { 0, 0, 32, 7, 91, 5, 0 },
+                        { 0, 11, 100, 7, 17, 0, 0 },
+                        { 0, 3, 83, 7, 42, 0, 0 },
+                        { 0, 1, 49, 7, 76, 2, 0 },
+                        { 0, 0, 21, 7, 98, 9, 0 },
+                        { 0, 7, 95, 7, 26, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 35, 7, 89, 4, 0 },
+                        { 0, 13, 100, 7, 15, 0, 0 },
+                        { 0, 4, 86, 7, 38, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 23, 7, 97, 8, 0 },
+                        { 0, 8, 97, 7, 23, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 38, 7, 86, 4, 0 },
+                        { 0, 0, 15, 7, 100, 13, 0 },
+                        { 0, 4, 89, 7, 35, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 26, 7, 95, 7, 0 },
+                        { 0, 9, 98, 7, 21, 0, 0 },
+                        { 0, 2, 76, 7, 49, 1, 0 },
+                        { 0, 0, 42, 7, 83, 3, 0 },
+                        { 0, 0, 17, 7, 100, 11, 0 },
+                        { 0, 5, 91, 7, 32, 0, 0 },
+                        { 0, 1, 61, 7, 65, 1, 0 },
+                        { 0, 0, 29, 7, 93, 6, 0 },
+                        { 0, 10, 99, 7, 19, 0, 0 },
+                        { 0, 3, 80, 7, 45, 0, 0 } } },
+       .ptrn_arr = { { 0x664c9933, 0x664c9932, 0x64cc9932, 0x64cc9932,
+                        0x9932 } },
+       .sample_patrn_length = 146,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 42) = 0.432432 */
+       .hor_phase_arr = {
+               .even = { { 0, 14, 100, 7, 14, 0, 0 },
+                        { 0, 4, 84, 7, 40, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 0, 18, 7, 99, 11, 0 },
+                        { 0, 5, 89, 7, 34, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 23, 7, 96, 9, 0 },
+                        { 0, 7, 93, 7, 28, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 28, 7, 93, 7, 0 },
+                        { 0, 9, 96, 7, 23, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 34, 7, 89, 5, 0 },
+                        { 0, 11, 99, 7, 18, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 40, 7, 84, 4, 0 } },
+               .odd = { { 0, 1, 44, 7, 80, 3, 0 },
+                        { 0, 0, 16, 7, 99, 13, 0 },
+                        { 0, 4, 87, 7, 37, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 20, 7, 98, 10, 0 },
+                        { 0, 6, 91, 7, 31, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 25, 7, 95, 8, 0 },
+                        { 0, 8, 95, 7, 25, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 31, 7, 91, 6, 0 },
+                        { 0, 10, 98, 7, 20, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 37, 7, 87, 4, 0 },
+                        { 0, 13, 99, 7, 16, 0, 0 },
+                        { 0, 3, 80, 7, 44, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 14, 100, 7, 14, 0, 0 },
+                        { 0, 4, 84, 7, 40, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 0, 18, 7, 99, 11, 0 },
+                        { 0, 5, 89, 7, 34, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 23, 7, 96, 9, 0 },
+                        { 0, 7, 93, 7, 28, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 28, 7, 93, 7, 0 },
+                        { 0, 9, 96, 7, 23, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 34, 7, 89, 5, 0 },
+                        { 0, 11, 99, 7, 18, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 40, 7, 84, 4, 0 } },
+               .odd = { { 0, 1, 44, 7, 80, 3, 0 },
+                        { 0, 0, 16, 7, 99, 13, 0 },
+                        { 0, 4, 87, 7, 37, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 20, 7, 98, 10, 0 },
+                        { 0, 6, 91, 7, 31, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 25, 7, 95, 8, 0 },
+                        { 0, 8, 95, 7, 25, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 31, 7, 91, 6, 0 },
+                        { 0, 10, 98, 7, 20, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 37, 7, 87, 4, 0 },
+                        { 0, 13, 99, 7, 16, 0, 0 },
+                        { 0, 3, 80, 7, 44, 1, 0 } } },
+       .ptrn_arr = { { 0x264c9933, 0x3264c993, 0x99 } },
+       .sample_patrn_length = 74,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 43) = 0.426667 */
+       .hor_phase_arr = {
+               .even = { { 0, 15, 98, 7, 15, 0, 0 },
+                        { 0, 3, 80, 7, 44, 1, 0 },
+                        { 0, 0, 41, 7, 83, 4, 0 },
+                        { 0, 13, 98, 7, 17, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 38, 7, 85, 5, 0 },
+                        { 0, 12, 97, 7, 19, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 34, 7, 89, 5, 0 },
+                        { 0, 10, 97, 7, 21, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 31, 7, 91, 6, 0 },
+                        { 0, 9, 96, 7, 23, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 29, 7, 92, 7, 0 },
+                        { 0, 8, 94, 7, 26, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 26, 7, 94, 8, 0 },
+                        { 0, 7, 92, 7, 29, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 23, 7, 96, 9, 0 },
+                        { 0, 6, 91, 7, 31, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 21, 7, 97, 10, 0 },
+                        { 0, 5, 89, 7, 34, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 19, 7, 97, 12, 0 },
+                        { 0, 5, 85, 7, 38, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 0, 17, 7, 98, 13, 0 },
+                        { 0, 4, 83, 7, 41, 0, 0 },
+                        { 0, 1, 44, 7, 80, 3, 0 } },
+               .odd = { { 0, 1, 43, 7, 80, 4, 0 },
+                        { 0, 14, 98, 7, 16, 0, 0 },
+                        { 0, 3, 78, 7, 46, 1, 0 },
+                        { 0, 0, 39, 7, 85, 4, 0 },
+                        { 0, 12, 98, 7, 18, 0, 0 },
+                        { 0, 3, 74, 7, 50, 1, 0 },
+                        { 0, 0, 36, 7, 87, 5, 0 },
+                        { 0, 11, 97, 7, 20, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 33, 7, 89, 6, 0 },
+                        { 0, 10, 96, 7, 22, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 30, 7, 92, 6, 0 },
+                        { 0, 9, 94, 7, 25, 0, 0 },
+                        { 0, 2, 64, 7, 61, 1, 0 },
+                        { 0, 0, 27, 7, 94, 7, 0 },
+                        { 0, 7, 94, 7, 27, 0, 0 },
+                        { 0, 1, 61, 7, 64, 2, 0 },
+                        { 0, 0, 25, 7, 94, 9, 0 },
+                        { 0, 6, 92, 7, 30, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 22, 7, 96, 10, 0 },
+                        { 0, 6, 89, 7, 33, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 20, 7, 97, 11, 0 },
+                        { 0, 5, 87, 7, 36, 0, 0 },
+                        { 0, 1, 50, 7, 74, 3, 0 },
+                        { 0, 0, 18, 7, 98, 12, 0 },
+                        { 0, 4, 85, 7, 39, 0, 0 },
+                        { 0, 1, 46, 7, 78, 3, 0 },
+                        { 0, 0, 16, 7, 98, 14, 0 },
+                        { 0, 4, 80, 7, 43, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 15, 98, 7, 15, 0, 0 },
+                        { 0, 3, 80, 7, 44, 1, 0 },
+                        { 0, 0, 41, 7, 83, 4, 0 },
+                        { 0, 13, 98, 7, 17, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 38, 7, 85, 5, 0 },
+                        { 0, 12, 97, 7, 19, 0, 0 },
+                        { 0, 2, 74, 7, 51, 1, 0 },
+                        { 0, 0, 34, 7, 89, 5, 0 },
+                        { 0, 10, 97, 7, 21, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 31, 7, 91, 6, 0 },
+                        { 0, 9, 96, 7, 23, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 29, 7, 92, 7, 0 },
+                        { 0, 8, 94, 7, 26, 0, 0 },
+                        { 0, 1, 63, 7, 63, 1, 0 },
+                        { 0, 0, 26, 7, 94, 8, 0 },
+                        { 0, 7, 92, 7, 29, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 23, 7, 96, 9, 0 },
+                        { 0, 6, 91, 7, 31, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 21, 7, 97, 10, 0 },
+                        { 0, 5, 89, 7, 34, 0, 0 },
+                        { 0, 1, 51, 7, 74, 2, 0 },
+                        { 0, 0, 19, 7, 97, 12, 0 },
+                        { 0, 5, 85, 7, 38, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 0, 17, 7, 98, 13, 0 },
+                        { 0, 4, 83, 7, 41, 0, 0 },
+                        { 0, 1, 44, 7, 80, 3, 0 } },
+               .odd = { { 0, 1, 43, 7, 80, 4, 0 },
+                        { 0, 14, 98, 7, 16, 0, 0 },
+                        { 0, 3, 78, 7, 46, 1, 0 },
+                        { 0, 0, 39, 7, 85, 4, 0 },
+                        { 0, 12, 98, 7, 18, 0, 0 },
+                        { 0, 3, 74, 7, 50, 1, 0 },
+                        { 0, 0, 36, 7, 87, 5, 0 },
+                        { 0, 11, 97, 7, 20, 0, 0 },
+                        { 0, 2, 72, 7, 53, 1, 0 },
+                        { 0, 0, 33, 7, 89, 6, 0 },
+                        { 0, 10, 96, 7, 22, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 30, 7, 92, 6, 0 },
+                        { 0, 9, 94, 7, 25, 0, 0 },
+                        { 0, 2, 64, 7, 61, 1, 0 },
+                        { 0, 0, 27, 7, 94, 7, 0 },
+                        { 0, 7, 94, 7, 27, 0, 0 },
+                        { 0, 1, 61, 7, 64, 2, 0 },
+                        { 0, 0, 25, 7, 94, 9, 0 },
+                        { 0, 6, 92, 7, 30, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 22, 7, 96, 10, 0 },
+                        { 0, 6, 89, 7, 33, 0, 0 },
+                        { 0, 1, 53, 7, 72, 2, 0 },
+                        { 0, 0, 20, 7, 97, 11, 0 },
+                        { 0, 5, 87, 7, 36, 0, 0 },
+                        { 0, 1, 50, 7, 74, 3, 0 },
+                        { 0, 0, 18, 7, 98, 12, 0 },
+                        { 0, 4, 85, 7, 39, 0, 0 },
+                        { 0, 1, 46, 7, 78, 3, 0 },
+                        { 0, 0, 16, 7, 98, 14, 0 },
+                        { 0, 4, 80, 7, 43, 1, 0 } } },
+       .ptrn_arr = { { 0x3264c993, 0x93264c99, 0x993264c9, 0xc993264c,
+                        0x93264 } },
+       .sample_patrn_length = 150,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 44) = 0.421053 */
+       .hor_phase_arr = {
+               .even = { { 0, 16, 96, 7, 16, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 35, 7, 87, 6, 0 },
+                        { 0, 10, 94, 7, 24, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 24, 7, 94, 10, 0 },
+                        { 0, 6, 87, 7, 35, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 } },
+               .odd = { { 0, 1, 41, 7, 82, 4, 0 },
+                        { 0, 12, 97, 7, 19, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 29, 7, 92, 7, 0 },
+                        { 0, 7, 92, 7, 29, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 19, 7, 97, 12, 0 },
+                        { 0, 4, 82, 7, 41, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 16, 96, 7, 16, 0, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 35, 7, 87, 6, 0 },
+                        { 0, 10, 94, 7, 24, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 24, 7, 94, 10, 0 },
+                        { 0, 6, 87, 7, 35, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 } },
+               .odd = { { 0, 1, 41, 7, 82, 4, 0 },
+                        { 0, 12, 97, 7, 19, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 29, 7, 92, 7, 0 },
+                        { 0, 7, 92, 7, 29, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 19, 7, 97, 12, 0 },
+                        { 0, 4, 82, 7, 41, 1, 0 } } },
+       .ptrn_arr = { { 0x3264c993, 0x9 } },
+       .sample_patrn_length = 38,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 45) = 0.415584 */
+       .hor_phase_arr = {
+               .even = { { 0, 16, 96, 7, 16, 0, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 30, 7, 90, 8, 0 },
+                        { 0, 7, 89, 7, 32, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 14, 96, 7, 18, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 27, 7, 92, 9, 0 },
+                        { 0, 6, 87, 7, 35, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 13, 95, 7, 20, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 24, 7, 94, 10, 0 },
+                        { 0, 5, 85, 7, 38, 0, 0 },
+                        { 0, 1, 42, 7, 81, 4, 0 },
+                        { 0, 11, 95, 7, 22, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 22, 7, 95, 11, 0 },
+                        { 0, 4, 81, 7, 42, 1, 0 },
+                        { 0, 0, 38, 7, 85, 5, 0 },
+                        { 0, 10, 94, 7, 24, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 20, 7, 95, 13, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 35, 7, 87, 6, 0 },
+                        { 0, 9, 92, 7, 27, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 18, 7, 96, 14, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 32, 7, 89, 7, 0 },
+                        { 0, 8, 90, 7, 30, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 } },
+               .odd = { { 0, 1, 40, 7, 82, 5, 0 },
+                        { 0, 11, 94, 7, 23, 0, 0 },
+                        { 0, 2, 61, 7, 63, 2, 0 },
+                        { 0, 0, 21, 7, 95, 12, 0 },
+                        { 0, 4, 80, 7, 43, 1, 0 },
+                        { 0, 0, 37, 7, 85, 6, 0 },
+                        { 0, 9, 93, 7, 26, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 19, 7, 95, 14, 0 },
+                        { 0, 4, 76, 7, 47, 1, 0 },
+                        { 0, 0, 34, 7, 88, 6, 0 },
+                        { 0, 8, 92, 7, 28, 0, 0 },
+                        { 0, 1, 54, 7, 70, 3, 0 },
+                        { 0, 0, 17, 7, 96, 15, 0 },
+                        { 0, 3, 74, 7, 50, 1, 0 },
+                        { 0, 0, 31, 7, 90, 7, 0 },
+                        { 0, 7, 90, 7, 31, 0, 0 },
+                        { 0, 1, 50, 7, 74, 3, 0 },
+                        { 0, 15, 96, 7, 17, 0, 0 },
+                        { 0, 3, 70, 7, 54, 1, 0 },
+                        { 0, 0, 28, 7, 92, 8, 0 },
+                        { 0, 6, 88, 7, 34, 0, 0 },
+                        { 0, 1, 47, 7, 76, 4, 0 },
+                        { 0, 14, 95, 7, 19, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 26, 7, 93, 9, 0 },
+                        { 0, 6, 85, 7, 37, 0, 0 },
+                        { 0, 1, 43, 7, 80, 4, 0 },
+                        { 0, 12, 95, 7, 21, 0, 0 },
+                        { 0, 2, 63, 7, 61, 2, 0 },
+                        { 0, 0, 23, 7, 94, 11, 0 },
+                        { 0, 5, 82, 7, 40, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 16, 96, 7, 16, 0, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 30, 7, 90, 8, 0 },
+                        { 0, 7, 89, 7, 32, 0, 0 },
+                        { 0, 1, 48, 7, 76, 3, 0 },
+                        { 0, 14, 96, 7, 18, 0, 0 },
+                        { 0, 2, 70, 7, 55, 1, 0 },
+                        { 0, 0, 27, 7, 92, 9, 0 },
+                        { 0, 6, 87, 7, 35, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 13, 95, 7, 20, 0, 0 },
+                        { 0, 2, 66, 7, 59, 1, 0 },
+                        { 0, 0, 24, 7, 94, 10, 0 },
+                        { 0, 5, 85, 7, 38, 0, 0 },
+                        { 0, 1, 42, 7, 81, 4, 0 },
+                        { 0, 11, 95, 7, 22, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 22, 7, 95, 11, 0 },
+                        { 0, 4, 81, 7, 42, 1, 0 },
+                        { 0, 0, 38, 7, 85, 5, 0 },
+                        { 0, 10, 94, 7, 24, 0, 0 },
+                        { 0, 1, 59, 7, 66, 2, 0 },
+                        { 0, 0, 20, 7, 95, 13, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 35, 7, 87, 6, 0 },
+                        { 0, 9, 92, 7, 27, 0, 0 },
+                        { 0, 1, 55, 7, 70, 2, 0 },
+                        { 0, 0, 18, 7, 96, 14, 0 },
+                        { 0, 3, 76, 7, 48, 1, 0 },
+                        { 0, 0, 32, 7, 89, 7, 0 },
+                        { 0, 8, 90, 7, 30, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 } },
+               .odd = { { 0, 1, 40, 7, 82, 5, 0 },
+                        { 0, 11, 94, 7, 23, 0, 0 },
+                        { 0, 2, 61, 7, 63, 2, 0 },
+                        { 0, 0, 21, 7, 95, 12, 0 },
+                        { 0, 4, 80, 7, 43, 1, 0 },
+                        { 0, 0, 37, 7, 85, 6, 0 },
+                        { 0, 9, 93, 7, 26, 0, 0 },
+                        { 0, 1, 57, 7, 68, 2, 0 },
+                        { 0, 0, 19, 7, 95, 14, 0 },
+                        { 0, 4, 76, 7, 47, 1, 0 },
+                        { 0, 0, 34, 7, 88, 6, 0 },
+                        { 0, 8, 92, 7, 28, 0, 0 },
+                        { 0, 1, 54, 7, 70, 3, 0 },
+                        { 0, 0, 17, 7, 96, 15, 0 },
+                        { 0, 3, 74, 7, 50, 1, 0 },
+                        { 0, 0, 31, 7, 90, 7, 0 },
+                        { 0, 7, 90, 7, 31, 0, 0 },
+                        { 0, 1, 50, 7, 74, 3, 0 },
+                        { 0, 15, 96, 7, 17, 0, 0 },
+                        { 0, 3, 70, 7, 54, 1, 0 },
+                        { 0, 0, 28, 7, 92, 8, 0 },
+                        { 0, 6, 88, 7, 34, 0, 0 },
+                        { 0, 1, 47, 7, 76, 4, 0 },
+                        { 0, 14, 95, 7, 19, 0, 0 },
+                        { 0, 2, 68, 7, 57, 1, 0 },
+                        { 0, 0, 26, 7, 93, 9, 0 },
+                        { 0, 6, 85, 7, 37, 0, 0 },
+                        { 0, 1, 43, 7, 80, 4, 0 },
+                        { 0, 12, 95, 7, 21, 0, 0 },
+                        { 0, 2, 63, 7, 61, 2, 0 },
+                        { 0, 0, 23, 7, 94, 11, 0 },
+                        { 0, 5, 82, 7, 40, 1, 0 } } },
+       .ptrn_arr = { { 0x9324c993, 0xc99324c9, 0x26499324, 0x93264993,
+                        0x932649 } },
+       .sample_patrn_length = 154,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 46) = 0.410256 */
+       .hor_phase_arr = {
+               .even = { { 0, 17, 94, 7, 17, 0, 0 },
+                        { 0, 3, 69, 7, 55, 1, 0 },
+                        { 0, 0, 25, 7, 93, 10, 0 },
+                        { 0, 5, 80, 7, 42, 1, 0 },
+                        { 0, 0, 36, 7, 86, 6, 0 },
+                        { 0, 8, 90, 7, 30, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 13, 94, 7, 21, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 21, 7, 94, 13, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 30, 7, 90, 8, 0 },
+                        { 0, 6, 86, 7, 36, 0, 0 },
+                        { 0, 1, 42, 7, 80, 5, 0 },
+                        { 0, 10, 93, 7, 25, 0, 0 },
+                        { 0, 1, 55, 7, 69, 3, 0 } },
+               .odd = { { 0, 1, 39, 7, 83, 5, 0 },
+                        { 0, 9, 91, 7, 28, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 },
+                        { 0, 15, 94, 7, 19, 0, 0 },
+                        { 0, 2, 65, 7, 59, 2, 0 },
+                        { 0, 0, 23, 7, 93, 12, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 33, 7, 88, 7, 0 },
+                        { 0, 7, 88, 7, 33, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 12, 93, 7, 23, 0, 0 },
+                        { 0, 2, 59, 7, 65, 2, 0 },
+                        { 0, 0, 19, 7, 94, 15, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 28, 7, 91, 9, 0 },
+                        { 0, 5, 83, 7, 39, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 17, 94, 7, 17, 0, 0 },
+                        { 0, 3, 69, 7, 55, 1, 0 },
+                        { 0, 0, 25, 7, 93, 10, 0 },
+                        { 0, 5, 80, 7, 42, 1, 0 },
+                        { 0, 0, 36, 7, 86, 6, 0 },
+                        { 0, 8, 90, 7, 30, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 13, 94, 7, 21, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 21, 7, 94, 13, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 30, 7, 90, 8, 0 },
+                        { 0, 6, 86, 7, 36, 0, 0 },
+                        { 0, 1, 42, 7, 80, 5, 0 },
+                        { 0, 10, 93, 7, 25, 0, 0 },
+                        { 0, 1, 55, 7, 69, 3, 0 } },
+               .odd = { { 0, 1, 39, 7, 83, 5, 0 },
+                        { 0, 9, 91, 7, 28, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 },
+                        { 0, 15, 94, 7, 19, 0, 0 },
+                        { 0, 2, 65, 7, 59, 2, 0 },
+                        { 0, 0, 23, 7, 93, 12, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 33, 7, 88, 7, 0 },
+                        { 0, 7, 88, 7, 33, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 12, 93, 7, 23, 0, 0 },
+                        { 0, 2, 59, 7, 65, 2, 0 },
+                        { 0, 0, 19, 7, 94, 15, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 28, 7, 91, 9, 0 },
+                        { 0, 5, 83, 7, 39, 1, 0 } } },
+       .ptrn_arr = { { 0x93264993, 0x4c99264c, 0x932 } },
+       .sample_patrn_length = 78,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 47) = 0.405063 */
+       .hor_phase_arr = {
+               .even = { { 0, 17, 94, 7, 17, 0, 0 },
+                        { 0, 2, 65, 7, 59, 2, 0 },
+                        { 0, 0, 21, 7, 93, 14, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 26, 7, 91, 11, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 31, 7, 88, 9, 0 },
+                        { 0, 6, 82, 7, 39, 1, 0 },
+                        { 0, 1, 36, 7, 84, 7, 0 },
+                        { 0, 8, 87, 7, 33, 0, 0 },
+                        { 0, 1, 42, 7, 80, 5, 0 },
+                        { 0, 10, 90, 7, 28, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 12, 93, 7, 23, 0, 0 },
+                        { 0, 2, 55, 7, 68, 3, 0 },
+                        { 0, 15, 94, 7, 19, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 19, 7, 94, 15, 0 },
+                        { 0, 3, 68, 7, 55, 2, 0 },
+                        { 0, 0, 23, 7, 93, 12, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 28, 7, 90, 10, 0 },
+                        { 0, 5, 80, 7, 42, 1, 0 },
+                        { 0, 0, 33, 7, 87, 8, 0 },
+                        { 0, 7, 84, 7, 36, 1, 0 },
+                        { 0, 1, 39, 7, 82, 6, 0 },
+                        { 0, 9, 88, 7, 31, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 11, 91, 7, 26, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 },
+                        { 0, 14, 93, 7, 21, 0, 0 },
+                        { 0, 2, 59, 7, 65, 2, 0 } },
+               .odd = { { 0, 1, 38, 7, 83, 6, 0 },
+                        { 0, 8, 88, 7, 32, 0, 0 },
+                        { 0, 1, 44, 7, 78, 5, 0 },
+                        { 0, 10, 91, 7, 27, 0, 0 },
+                        { 0, 1, 50, 7, 73, 4, 0 },
+                        { 0, 13, 93, 7, 22, 0, 0 },
+                        { 0, 2, 57, 7, 66, 3, 0 },
+                        { 0, 16, 94, 7, 18, 0, 0 },
+                        { 0, 2, 64, 7, 60, 2, 0 },
+                        { 0, 0, 20, 7, 93, 15, 0 },
+                        { 0, 3, 70, 7, 54, 1, 0 },
+                        { 0, 0, 24, 7, 92, 12, 0 },
+                        { 0, 4, 76, 7, 47, 1, 0 },
+                        { 0, 0, 29, 7, 90, 9, 0 },
+                        { 0, 5, 81, 7, 41, 1, 0 },
+                        { 0, 0, 35, 7, 86, 7, 0 },
+                        { 0, 7, 86, 7, 35, 0, 0 },
+                        { 0, 1, 41, 7, 81, 5, 0 },
+                        { 0, 9, 90, 7, 29, 0, 0 },
+                        { 0, 1, 47, 7, 76, 4, 0 },
+                        { 0, 12, 92, 7, 24, 0, 0 },
+                        { 0, 1, 54, 7, 70, 3, 0 },
+                        { 0, 15, 93, 7, 20, 0, 0 },
+                        { 0, 2, 60, 7, 64, 2, 0 },
+                        { 0, 0, 18, 7, 94, 16, 0 },
+                        { 0, 3, 66, 7, 57, 2, 0 },
+                        { 0, 0, 22, 7, 93, 13, 0 },
+                        { 0, 4, 73, 7, 50, 1, 0 },
+                        { 0, 0, 27, 7, 91, 10, 0 },
+                        { 0, 5, 78, 7, 44, 1, 0 },
+                        { 0, 0, 32, 7, 88, 8, 0 },
+                        { 0, 6, 83, 7, 38, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 17, 94, 7, 17, 0, 0 },
+                        { 0, 2, 65, 7, 59, 2, 0 },
+                        { 0, 0, 21, 7, 93, 14, 0 },
+                        { 0, 3, 72, 7, 52, 1, 0 },
+                        { 0, 0, 26, 7, 91, 11, 0 },
+                        { 0, 4, 78, 7, 45, 1, 0 },
+                        { 0, 0, 31, 7, 88, 9, 0 },
+                        { 0, 6, 82, 7, 39, 1, 0 },
+                        { 0, 1, 36, 7, 84, 7, 0 },
+                        { 0, 8, 87, 7, 33, 0, 0 },
+                        { 0, 1, 42, 7, 80, 5, 0 },
+                        { 0, 10, 90, 7, 28, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 12, 93, 7, 23, 0, 0 },
+                        { 0, 2, 55, 7, 68, 3, 0 },
+                        { 0, 15, 94, 7, 19, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 0, 19, 7, 94, 15, 0 },
+                        { 0, 3, 68, 7, 55, 2, 0 },
+                        { 0, 0, 23, 7, 93, 12, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 28, 7, 90, 10, 0 },
+                        { 0, 5, 80, 7, 42, 1, 0 },
+                        { 0, 0, 33, 7, 87, 8, 0 },
+                        { 0, 7, 84, 7, 36, 1, 0 },
+                        { 0, 1, 39, 7, 82, 6, 0 },
+                        { 0, 9, 88, 7, 31, 0, 0 },
+                        { 0, 1, 45, 7, 78, 4, 0 },
+                        { 0, 11, 91, 7, 26, 0, 0 },
+                        { 0, 1, 52, 7, 72, 3, 0 },
+                        { 0, 14, 93, 7, 21, 0, 0 },
+                        { 0, 2, 59, 7, 65, 2, 0 } },
+               .odd = { { 0, 1, 38, 7, 83, 6, 0 },
+                        { 0, 8, 88, 7, 32, 0, 0 },
+                        { 0, 1, 44, 7, 78, 5, 0 },
+                        { 0, 10, 91, 7, 27, 0, 0 },
+                        { 0, 1, 50, 7, 73, 4, 0 },
+                        { 0, 13, 93, 7, 22, 0, 0 },
+                        { 0, 2, 57, 7, 66, 3, 0 },
+                        { 0, 16, 94, 7, 18, 0, 0 },
+                        { 0, 2, 64, 7, 60, 2, 0 },
+                        { 0, 0, 20, 7, 93, 15, 0 },
+                        { 0, 3, 70, 7, 54, 1, 0 },
+                        { 0, 0, 24, 7, 92, 12, 0 },
+                        { 0, 4, 76, 7, 47, 1, 0 },
+                        { 0, 0, 29, 7, 90, 9, 0 },
+                        { 0, 5, 81, 7, 41, 1, 0 },
+                        { 0, 0, 35, 7, 86, 7, 0 },
+                        { 0, 7, 86, 7, 35, 0, 0 },
+                        { 0, 1, 41, 7, 81, 5, 0 },
+                        { 0, 9, 90, 7, 29, 0, 0 },
+                        { 0, 1, 47, 7, 76, 4, 0 },
+                        { 0, 12, 92, 7, 24, 0, 0 },
+                        { 0, 1, 54, 7, 70, 3, 0 },
+                        { 0, 15, 93, 7, 20, 0, 0 },
+                        { 0, 2, 60, 7, 64, 2, 0 },
+                        { 0, 0, 18, 7, 94, 16, 0 },
+                        { 0, 3, 66, 7, 57, 2, 0 },
+                        { 0, 0, 22, 7, 93, 13, 0 },
+                        { 0, 4, 73, 7, 50, 1, 0 },
+                        { 0, 0, 27, 7, 91, 10, 0 },
+                        { 0, 5, 78, 7, 44, 1, 0 },
+                        { 0, 0, 32, 7, 88, 8, 0 },
+                        { 0, 6, 83, 7, 38, 1, 0 } } },
+       .ptrn_arr = { { 0x99264993, 0x24c93264, 0x99264c93, 0x24c99264,
+                        0x9324c93 } },
+       .sample_patrn_length = 158,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 48) = 0.4 */
+       .hor_phase_arr = {
+               .even = { { 0, 18, 92, 7, 18, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 } },
+               .odd = { { 0, 1, 37, 7, 83, 7, 0 },
+                        { 0, 7, 83, 7, 37, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 18, 92, 7, 18, 0, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 } },
+               .odd = { { 0, 1, 37, 7, 83, 7, 0 },
+                        { 0, 7, 83, 7, 37, 1, 0 } } },
+       .ptrn_arr = { { 0x93 } },
+       .sample_patrn_length = 10,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 49) = 0.395062 */
+       .hor_phase_arr = {
+               .even = { { 0, 18, 92, 7, 18, 0, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 15, 91, 7, 22, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 12, 89, 7, 27, 0, 0 },
+                        { 0, 1, 46, 7, 76, 5, 0 },
+                        { 0, 9, 87, 7, 32, 0, 0 },
+                        { 0, 1, 40, 7, 80, 7, 0 },
+                        { 0, 7, 83, 7, 37, 1, 0 },
+                        { 0, 1, 34, 7, 85, 8, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 29, 7, 88, 11, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 24, 7, 91, 13, 0 },
+                        { 0, 3, 68, 7, 55, 2, 0 },
+                        { 0, 0, 20, 7, 92, 16, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 16, 92, 7, 20, 0, 0 },
+                        { 0, 2, 55, 7, 68, 3, 0 },
+                        { 0, 13, 91, 7, 24, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 11, 88, 7, 29, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 8, 85, 7, 34, 1, 0 },
+                        { 0, 1, 37, 7, 83, 7, 0 },
+                        { 0, 7, 80, 7, 40, 1, 0 },
+                        { 0, 0, 32, 7, 87, 9, 0 },
+                        { 0, 5, 76, 7, 46, 1, 0 },
+                        { 0, 0, 27, 7, 89, 12, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 },
+                        { 0, 0, 22, 7, 91, 15, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 } },
+               .odd = { { 0, 1, 36, 7, 83, 8, 0 },
+                        { 0, 6, 80, 7, 41, 1, 0 },
+                        { 0, 0, 30, 7, 88, 10, 0 },
+                        { 0, 5, 75, 7, 47, 1, 0 },
+                        { 0, 0, 25, 7, 90, 13, 0 },
+                        { 0, 4, 68, 7, 54, 2, 0 },
+                        { 0, 0, 21, 7, 91, 16, 0 },
+                        { 0, 3, 63, 7, 60, 2, 0 },
+                        { 0, 17, 92, 7, 19, 0, 0 },
+                        { 0, 2, 57, 7, 66, 3, 0 },
+                        { 0, 14, 91, 7, 23, 0, 0 },
+                        { 0, 1, 51, 7, 72, 4, 0 },
+                        { 0, 11, 89, 7, 28, 0, 0 },
+                        { 0, 1, 44, 7, 78, 5, 0 },
+                        { 0, 9, 85, 7, 33, 1, 0 },
+                        { 0, 1, 38, 7, 82, 7, 0 },
+                        { 0, 7, 82, 7, 38, 1, 0 },
+                        { 0, 1, 33, 7, 85, 9, 0 },
+                        { 0, 5, 78, 7, 44, 1, 0 },
+                        { 0, 0, 28, 7, 89, 11, 0 },
+                        { 0, 4, 72, 7, 51, 1, 0 },
+                        { 0, 0, 23, 7, 91, 14, 0 },
+                        { 0, 3, 66, 7, 57, 2, 0 },
+                        { 0, 0, 19, 7, 92, 17, 0 },
+                        { 0, 2, 60, 7, 63, 3, 0 },
+                        { 0, 16, 91, 7, 21, 0, 0 },
+                        { 0, 2, 54, 7, 68, 4, 0 },
+                        { 0, 13, 90, 7, 25, 0, 0 },
+                        { 0, 1, 47, 7, 75, 5, 0 },
+                        { 0, 10, 88, 7, 30, 0, 0 },
+                        { 0, 1, 41, 7, 80, 6, 0 },
+                        { 0, 8, 83, 7, 36, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 18, 92, 7, 18, 0, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 15, 91, 7, 22, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 12, 89, 7, 27, 0, 0 },
+                        { 0, 1, 46, 7, 76, 5, 0 },
+                        { 0, 9, 87, 7, 32, 0, 0 },
+                        { 0, 1, 40, 7, 80, 7, 0 },
+                        { 0, 7, 83, 7, 37, 1, 0 },
+                        { 0, 1, 34, 7, 85, 8, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 29, 7, 88, 11, 0 },
+                        { 0, 4, 74, 7, 49, 1, 0 },
+                        { 0, 0, 24, 7, 91, 13, 0 },
+                        { 0, 3, 68, 7, 55, 2, 0 },
+                        { 0, 0, 20, 7, 92, 16, 0 },
+                        { 0, 2, 62, 7, 62, 2, 0 },
+                        { 0, 16, 92, 7, 20, 0, 0 },
+                        { 0, 2, 55, 7, 68, 3, 0 },
+                        { 0, 13, 91, 7, 24, 0, 0 },
+                        { 0, 1, 49, 7, 74, 4, 0 },
+                        { 0, 11, 88, 7, 29, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 8, 85, 7, 34, 1, 0 },
+                        { 0, 1, 37, 7, 83, 7, 0 },
+                        { 0, 7, 80, 7, 40, 1, 0 },
+                        { 0, 0, 32, 7, 87, 9, 0 },
+                        { 0, 5, 76, 7, 46, 1, 0 },
+                        { 0, 0, 27, 7, 89, 12, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 },
+                        { 0, 0, 22, 7, 91, 15, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 } },
+               .odd = { { 0, 1, 36, 7, 83, 8, 0 },
+                        { 0, 6, 80, 7, 41, 1, 0 },
+                        { 0, 0, 30, 7, 88, 10, 0 },
+                        { 0, 5, 75, 7, 47, 1, 0 },
+                        { 0, 0, 25, 7, 90, 13, 0 },
+                        { 0, 4, 68, 7, 54, 2, 0 },
+                        { 0, 0, 21, 7, 91, 16, 0 },
+                        { 0, 3, 63, 7, 60, 2, 0 },
+                        { 0, 17, 92, 7, 19, 0, 0 },
+                        { 0, 2, 57, 7, 66, 3, 0 },
+                        { 0, 14, 91, 7, 23, 0, 0 },
+                        { 0, 1, 51, 7, 72, 4, 0 },
+                        { 0, 11, 89, 7, 28, 0, 0 },
+                        { 0, 1, 44, 7, 78, 5, 0 },
+                        { 0, 9, 85, 7, 33, 1, 0 },
+                        { 0, 1, 38, 7, 82, 7, 0 },
+                        { 0, 7, 82, 7, 38, 1, 0 },
+                        { 0, 1, 33, 7, 85, 9, 0 },
+                        { 0, 5, 78, 7, 44, 1, 0 },
+                        { 0, 0, 28, 7, 89, 11, 0 },
+                        { 0, 4, 72, 7, 51, 1, 0 },
+                        { 0, 0, 23, 7, 91, 14, 0 },
+                        { 0, 3, 66, 7, 57, 2, 0 },
+                        { 0, 0, 19, 7, 92, 17, 0 },
+                        { 0, 2, 60, 7, 63, 3, 0 },
+                        { 0, 16, 91, 7, 21, 0, 0 },
+                        { 0, 2, 54, 7, 68, 4, 0 },
+                        { 0, 13, 90, 7, 25, 0, 0 },
+                        { 0, 1, 47, 7, 75, 5, 0 },
+                        { 0, 10, 88, 7, 30, 0, 0 },
+                        { 0, 1, 41, 7, 80, 6, 0 },
+                        { 0, 8, 83, 7, 36, 1, 0 } } },
+       .ptrn_arr = { { 0xc9324c93, 0x92649924, 0x24c92649, 0x49324c93,
+                        0x92649926 } },
+       .sample_patrn_length = 162,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 50) = 0.390244 */
+       .hor_phase_arr = {
+               .even = { { 0, 19, 90, 7, 19, 0, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 12, 89, 7, 27, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 8, 82, 7, 37, 1, 0 },
+                        { 0, 1, 32, 7, 85, 10, 0 },
+                        { 0, 5, 73, 7, 49, 1, 0 },
+                        { 0, 0, 23, 7, 90, 15, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 15, 90, 7, 23, 0, 0 },
+                        { 0, 1, 49, 7, 73, 5, 0 },
+                        { 0, 10, 85, 7, 32, 1, 0 },
+                        { 0, 1, 37, 7, 82, 8, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 27, 7, 89, 12, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 } },
+               .odd = { { 0, 1, 35, 7, 83, 9, 0 },
+                        { 0, 5, 76, 7, 46, 1, 0 },
+                        { 0, 0, 25, 7, 89, 14, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 },
+                        { 0, 17, 90, 7, 21, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 11, 88, 7, 29, 0, 0 },
+                        { 0, 1, 40, 7, 80, 7, 0 },
+                        { 0, 7, 80, 7, 40, 1, 0 },
+                        { 0, 0, 29, 7, 88, 11, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 },
+                        { 0, 0, 21, 7, 90, 17, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 14, 89, 7, 25, 0, 0 },
+                        { 0, 1, 46, 7, 76, 5, 0 },
+                        { 0, 9, 83, 7, 35, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 19, 90, 7, 19, 0, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 12, 89, 7, 27, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 8, 82, 7, 37, 1, 0 },
+                        { 0, 1, 32, 7, 85, 10, 0 },
+                        { 0, 5, 73, 7, 49, 1, 0 },
+                        { 0, 0, 23, 7, 90, 15, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 15, 90, 7, 23, 0, 0 },
+                        { 0, 1, 49, 7, 73, 5, 0 },
+                        { 0, 10, 85, 7, 32, 1, 0 },
+                        { 0, 1, 37, 7, 82, 8, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 27, 7, 89, 12, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 } },
+               .odd = { { 0, 1, 35, 7, 83, 9, 0 },
+                        { 0, 5, 76, 7, 46, 1, 0 },
+                        { 0, 0, 25, 7, 89, 14, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 },
+                        { 0, 17, 90, 7, 21, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 11, 88, 7, 29, 0, 0 },
+                        { 0, 1, 40, 7, 80, 7, 0 },
+                        { 0, 7, 80, 7, 40, 1, 0 },
+                        { 0, 0, 29, 7, 88, 11, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 },
+                        { 0, 0, 21, 7, 90, 17, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 14, 89, 7, 25, 0, 0 },
+                        { 0, 1, 46, 7, 76, 5, 0 },
+                        { 0, 9, 83, 7, 35, 1, 0 } } },
+       .ptrn_arr = { { 0x49924c93, 0x9324c926, 0x9264 } },
+       .sample_patrn_length = 82,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 51) = 0.385542 */
+       .hor_phase_arr = {
+               .even = { { 0, 19, 90, 7, 19, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 10, 85, 7, 32, 1, 0 },
+                        { 0, 1, 35, 7, 83, 9, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 },
+                        { 0, 0, 21, 7, 90, 17, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 11, 87, 7, 30, 0, 0 },
+                        { 0, 1, 38, 7, 81, 8, 0 },
+                        { 0, 6, 75, 7, 46, 1, 0 },
+                        { 0, 0, 23, 7, 89, 16, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 13, 87, 7, 28, 0, 0 },
+                        { 0, 1, 41, 7, 79, 7, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 25, 7, 89, 14, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 14, 89, 7, 25, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 7, 79, 7, 41, 1, 0 },
+                        { 0, 0, 28, 7, 87, 13, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 },
+                        { 0, 16, 89, 7, 23, 0, 0 },
+                        { 0, 1, 46, 7, 75, 6, 0 },
+                        { 0, 8, 81, 7, 38, 1, 0 },
+                        { 0, 0, 30, 7, 87, 11, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 17, 90, 7, 21, 0, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 9, 83, 7, 35, 1, 0 },
+                        { 0, 1, 32, 7, 85, 10, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 } },
+               .odd = { { 0, 1, 34, 7, 83, 10, 0 },
+                        { 0, 5, 70, 7, 51, 2, 0 },
+                        { 0, 0, 20, 7, 90, 18, 0 },
+                        { 0, 2, 54, 7, 68, 4, 0 },
+                        { 0, 11, 85, 7, 31, 1, 0 },
+                        { 0, 1, 36, 7, 82, 9, 0 },
+                        { 0, 5, 74, 7, 48, 1, 0 },
+                        { 0, 0, 22, 7, 89, 17, 0 },
+                        { 0, 2, 57, 7, 65, 4, 0 },
+                        { 0, 12, 87, 7, 29, 0, 0 },
+                        { 0, 1, 39, 7, 80, 8, 0 },
+                        { 0, 6, 76, 7, 45, 1, 0 },
+                        { 0, 0, 24, 7, 89, 15, 0 },
+                        { 0, 3, 60, 7, 62, 3, 0 },
+                        { 0, 13, 89, 7, 26, 0, 0 },
+                        { 0, 1, 42, 7, 78, 7, 0 },
+                        { 0, 7, 78, 7, 42, 1, 0 },
+                        { 0, 0, 26, 7, 89, 13, 0 },
+                        { 0, 3, 62, 7, 60, 3, 0 },
+                        { 0, 15, 89, 7, 24, 0, 0 },
+                        { 0, 1, 45, 7, 76, 6, 0 },
+                        { 0, 8, 80, 7, 39, 1, 0 },
+                        { 0, 0, 29, 7, 87, 12, 0 },
+                        { 0, 4, 65, 7, 57, 2, 0 },
+                        { 0, 17, 89, 7, 22, 0, 0 },
+                        { 0, 1, 48, 7, 74, 5, 0 },
+                        { 0, 9, 82, 7, 36, 1, 0 },
+                        { 0, 1, 31, 7, 85, 11, 0 },
+                        { 0, 4, 68, 7, 54, 2, 0 },
+                        { 0, 18, 90, 7, 20, 0, 0 },
+                        { 0, 2, 51, 7, 70, 5, 0 },
+                        { 0, 10, 83, 7, 34, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 19, 90, 7, 19, 0, 0 },
+                        { 0, 2, 52, 7, 70, 4, 0 },
+                        { 0, 10, 85, 7, 32, 1, 0 },
+                        { 0, 1, 35, 7, 83, 9, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 },
+                        { 0, 0, 21, 7, 90, 17, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 11, 87, 7, 30, 0, 0 },
+                        { 0, 1, 38, 7, 81, 8, 0 },
+                        { 0, 6, 75, 7, 46, 1, 0 },
+                        { 0, 0, 23, 7, 89, 16, 0 },
+                        { 0, 2, 58, 7, 65, 3, 0 },
+                        { 0, 13, 87, 7, 28, 0, 0 },
+                        { 0, 1, 41, 7, 79, 7, 0 },
+                        { 0, 6, 78, 7, 43, 1, 0 },
+                        { 0, 0, 25, 7, 89, 14, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 14, 89, 7, 25, 0, 0 },
+                        { 0, 1, 43, 7, 78, 6, 0 },
+                        { 0, 7, 79, 7, 41, 1, 0 },
+                        { 0, 0, 28, 7, 87, 13, 0 },
+                        { 0, 3, 65, 7, 58, 2, 0 },
+                        { 0, 16, 89, 7, 23, 0, 0 },
+                        { 0, 1, 46, 7, 75, 6, 0 },
+                        { 0, 8, 81, 7, 38, 1, 0 },
+                        { 0, 0, 30, 7, 87, 11, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 17, 90, 7, 21, 0, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 9, 83, 7, 35, 1, 0 },
+                        { 0, 1, 32, 7, 85, 10, 0 },
+                        { 0, 4, 70, 7, 52, 2, 0 } },
+               .odd = { { 0, 1, 34, 7, 83, 10, 0 },
+                        { 0, 5, 70, 7, 51, 2, 0 },
+                        { 0, 0, 20, 7, 90, 18, 0 },
+                        { 0, 2, 54, 7, 68, 4, 0 },
+                        { 0, 11, 85, 7, 31, 1, 0 },
+                        { 0, 1, 36, 7, 82, 9, 0 },
+                        { 0, 5, 74, 7, 48, 1, 0 },
+                        { 0, 0, 22, 7, 89, 17, 0 },
+                        { 0, 2, 57, 7, 65, 4, 0 },
+                        { 0, 12, 87, 7, 29, 0, 0 },
+                        { 0, 1, 39, 7, 80, 8, 0 },
+                        { 0, 6, 76, 7, 45, 1, 0 },
+                        { 0, 0, 24, 7, 89, 15, 0 },
+                        { 0, 3, 60, 7, 62, 3, 0 },
+                        { 0, 13, 89, 7, 26, 0, 0 },
+                        { 0, 1, 42, 7, 78, 7, 0 },
+                        { 0, 7, 78, 7, 42, 1, 0 },
+                        { 0, 0, 26, 7, 89, 13, 0 },
+                        { 0, 3, 62, 7, 60, 3, 0 },
+                        { 0, 15, 89, 7, 24, 0, 0 },
+                        { 0, 1, 45, 7, 76, 6, 0 },
+                        { 0, 8, 80, 7, 39, 1, 0 },
+                        { 0, 0, 29, 7, 87, 12, 0 },
+                        { 0, 4, 65, 7, 57, 2, 0 },
+                        { 0, 17, 89, 7, 22, 0, 0 },
+                        { 0, 1, 48, 7, 74, 5, 0 },
+                        { 0, 9, 82, 7, 36, 1, 0 },
+                        { 0, 1, 31, 7, 85, 11, 0 },
+                        { 0, 4, 68, 7, 54, 2, 0 },
+                        { 0, 18, 90, 7, 20, 0, 0 },
+                        { 0, 2, 51, 7, 70, 5, 0 },
+                        { 0, 10, 83, 7, 34, 1, 0 } } },
+       .ptrn_arr = { { 0x49924c93, 0xc9264932, 0x93249924, 0x924c9264,
+                        0x26493249, 0x9 } },
+       .sample_patrn_length = 166,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 52) = 0.380952 */
+       .hor_phase_arr = {
+               .even = { { 0, 20, 88, 7, 20, 0, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 8, 81, 7, 38, 1, 0 },
+                        { 0, 0, 28, 7, 87, 13, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 13, 87, 7, 28, 0, 0 },
+                        { 0, 1, 38, 7, 81, 8, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 } },
+               .odd = { { 0, 1, 33, 7, 83, 11, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 16, 88, 7, 24, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 },
+                        { 0, 0, 24, 7, 88, 16, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 11, 83, 7, 33, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 20, 88, 7, 20, 0, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 8, 81, 7, 38, 1, 0 },
+                        { 0, 0, 28, 7, 87, 13, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 13, 87, 7, 28, 0, 0 },
+                        { 0, 1, 38, 7, 81, 8, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 } },
+               .odd = { { 0, 1, 33, 7, 83, 11, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 16, 88, 7, 24, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 },
+                        { 0, 0, 24, 7, 88, 16, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 11, 83, 7, 33, 1, 0 } } },
+       .ptrn_arr = { { 0x4c926493, 0x92 } },
+       .sample_patrn_length = 42,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 53) = 0.376471 */
+       .hor_phase_arr = {
+               .even = { { 0, 20, 88, 7, 20, 0, 0 },
+                        { 0, 2, 47, 7, 73, 6, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 },
+                        { 0, 0, 22, 7, 88, 18, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 8, 78, 7, 41, 1, 0 },
+                        { 0, 0, 24, 7, 87, 17, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 9, 80, 7, 38, 1, 0 },
+                        { 0, 0, 26, 7, 87, 15, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 10, 81, 7, 36, 1, 0 },
+                        { 0, 1, 28, 7, 85, 14, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 11, 83, 7, 33, 1, 0 },
+                        { 0, 1, 31, 7, 84, 12, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 12, 84, 7, 31, 1, 0 },
+                        { 0, 1, 33, 7, 83, 11, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 14, 85, 7, 28, 1, 0 },
+                        { 0, 1, 36, 7, 81, 10, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 15, 87, 7, 26, 0, 0 },
+                        { 0, 1, 38, 7, 80, 9, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 17, 87, 7, 24, 0, 0 },
+                        { 0, 1, 41, 7, 78, 8, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 },
+                        { 0, 18, 88, 7, 22, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 6, 73, 7, 47, 2, 0 } },
+               .odd = { { 0, 1, 32, 7, 83, 12, 0 },
+                        { 0, 3, 63, 7, 59, 3, 0 },
+                        { 0, 13, 84, 7, 30, 1, 0 },
+                        { 0, 1, 34, 7, 83, 10, 0 },
+                        { 0, 4, 64, 7, 57, 3, 0 },
+                        { 0, 14, 87, 7, 27, 0, 0 },
+                        { 0, 1, 37, 7, 81, 9, 0 },
+                        { 0, 5, 67, 7, 54, 2, 0 },
+                        { 0, 16, 87, 7, 25, 0, 0 },
+                        { 0, 1, 40, 7, 79, 8, 0 },
+                        { 0, 5, 70, 7, 51, 2, 0 },
+                        { 0, 18, 87, 7, 23, 0, 0 },
+                        { 0, 1, 42, 7, 78, 7, 0 },
+                        { 0, 6, 72, 7, 48, 2, 0 },
+                        { 0, 19, 88, 7, 21, 0, 0 },
+                        { 0, 1, 45, 7, 75, 7, 0 },
+                        { 0, 7, 75, 7, 45, 1, 0 },
+                        { 0, 0, 21, 7, 88, 19, 0 },
+                        { 0, 2, 48, 7, 72, 6, 0 },
+                        { 0, 7, 78, 7, 42, 1, 0 },
+                        { 0, 0, 23, 7, 87, 18, 0 },
+                        { 0, 2, 51, 7, 70, 5, 0 },
+                        { 0, 8, 79, 7, 40, 1, 0 },
+                        { 0, 0, 25, 7, 87, 16, 0 },
+                        { 0, 2, 54, 7, 67, 5, 0 },
+                        { 0, 9, 81, 7, 37, 1, 0 },
+                        { 0, 0, 27, 7, 87, 14, 0 },
+                        { 0, 3, 57, 7, 64, 4, 0 },
+                        { 0, 10, 83, 7, 34, 1, 0 },
+                        { 0, 1, 30, 7, 84, 13, 0 },
+                        { 0, 3, 59, 7, 63, 3, 0 },
+                        { 0, 12, 83, 7, 32, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 20, 88, 7, 20, 0, 0 },
+                        { 0, 2, 47, 7, 73, 6, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 },
+                        { 0, 0, 22, 7, 88, 18, 0 },
+                        { 0, 2, 49, 7, 72, 5, 0 },
+                        { 0, 8, 78, 7, 41, 1, 0 },
+                        { 0, 0, 24, 7, 87, 17, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 9, 80, 7, 38, 1, 0 },
+                        { 0, 0, 26, 7, 87, 15, 0 },
+                        { 0, 2, 55, 7, 67, 4, 0 },
+                        { 0, 10, 81, 7, 36, 1, 0 },
+                        { 0, 1, 28, 7, 85, 14, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 11, 83, 7, 33, 1, 0 },
+                        { 0, 1, 31, 7, 84, 12, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 12, 84, 7, 31, 1, 0 },
+                        { 0, 1, 33, 7, 83, 11, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 14, 85, 7, 28, 1, 0 },
+                        { 0, 1, 36, 7, 81, 10, 0 },
+                        { 0, 4, 67, 7, 55, 2, 0 },
+                        { 0, 15, 87, 7, 26, 0, 0 },
+                        { 0, 1, 38, 7, 80, 9, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 17, 87, 7, 24, 0, 0 },
+                        { 0, 1, 41, 7, 78, 8, 0 },
+                        { 0, 5, 72, 7, 49, 2, 0 },
+                        { 0, 18, 88, 7, 22, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 6, 73, 7, 47, 2, 0 } },
+               .odd = { { 0, 1, 32, 7, 83, 12, 0 },
+                        { 0, 3, 63, 7, 59, 3, 0 },
+                        { 0, 13, 84, 7, 30, 1, 0 },
+                        { 0, 1, 34, 7, 83, 10, 0 },
+                        { 0, 4, 64, 7, 57, 3, 0 },
+                        { 0, 14, 87, 7, 27, 0, 0 },
+                        { 0, 1, 37, 7, 81, 9, 0 },
+                        { 0, 5, 67, 7, 54, 2, 0 },
+                        { 0, 16, 87, 7, 25, 0, 0 },
+                        { 0, 1, 40, 7, 79, 8, 0 },
+                        { 0, 5, 70, 7, 51, 2, 0 },
+                        { 0, 18, 87, 7, 23, 0, 0 },
+                        { 0, 1, 42, 7, 78, 7, 0 },
+                        { 0, 6, 72, 7, 48, 2, 0 },
+                        { 0, 19, 88, 7, 21, 0, 0 },
+                        { 0, 1, 45, 7, 75, 7, 0 },
+                        { 0, 7, 75, 7, 45, 1, 0 },
+                        { 0, 0, 21, 7, 88, 19, 0 },
+                        { 0, 2, 48, 7, 72, 6, 0 },
+                        { 0, 7, 78, 7, 42, 1, 0 },
+                        { 0, 0, 23, 7, 87, 18, 0 },
+                        { 0, 2, 51, 7, 70, 5, 0 },
+                        { 0, 8, 79, 7, 40, 1, 0 },
+                        { 0, 0, 25, 7, 87, 16, 0 },
+                        { 0, 2, 54, 7, 67, 5, 0 },
+                        { 0, 9, 81, 7, 37, 1, 0 },
+                        { 0, 0, 27, 7, 87, 14, 0 },
+                        { 0, 3, 57, 7, 64, 4, 0 },
+                        { 0, 10, 83, 7, 34, 1, 0 },
+                        { 0, 1, 30, 7, 84, 13, 0 },
+                        { 0, 3, 59, 7, 63, 3, 0 },
+                        { 0, 12, 83, 7, 32, 1, 0 } } },
+       .ptrn_arr = { { 0x64926493, 0x64926492, 0x4c926492, 0x4c924c92,
+                        0x4c924c92, 0x92 } },
+       .sample_patrn_length = 170,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 54) = 0.372093 */
+       .hor_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 6, 71, 7, 49, 2, 0 },
+                        { 0, 17, 86, 7, 25, 0, 0 },
+                        { 0, 1, 39, 7, 79, 9, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 14, 84, 7, 29, 1, 0 },
+                        { 0, 1, 34, 7, 82, 11, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 11, 82, 7, 34, 1, 0 },
+                        { 0, 1, 29, 7, 84, 14, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 9, 79, 7, 39, 1, 0 },
+                        { 0, 0, 25, 7, 86, 17, 0 },
+                        { 0, 2, 49, 7, 71, 6, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 } },
+               .odd = { { 0, 1, 31, 7, 83, 13, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 10, 81, 7, 36, 1, 0 },
+                        { 0, 0, 27, 7, 85, 16, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 8, 78, 7, 41, 1, 0 },
+                        { 0, 0, 23, 7, 86, 19, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 19, 86, 7, 23, 0, 0 },
+                        { 0, 1, 41, 7, 78, 8, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 16, 85, 7, 27, 0, 0 },
+                        { 0, 1, 36, 7, 81, 10, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 13, 83, 7, 31, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 },
+                        { 0, 1, 44, 7, 76, 7, 0 },
+                        { 0, 6, 71, 7, 49, 2, 0 },
+                        { 0, 17, 86, 7, 25, 0, 0 },
+                        { 0, 1, 39, 7, 79, 9, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 14, 84, 7, 29, 1, 0 },
+                        { 0, 1, 34, 7, 82, 11, 0 },
+                        { 0, 3, 61, 7, 61, 3, 0 },
+                        { 0, 11, 82, 7, 34, 1, 0 },
+                        { 0, 1, 29, 7, 84, 14, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 9, 79, 7, 39, 1, 0 },
+                        { 0, 0, 25, 7, 86, 17, 0 },
+                        { 0, 2, 49, 7, 71, 6, 0 },
+                        { 0, 7, 76, 7, 44, 1, 0 } },
+               .odd = { { 0, 1, 31, 7, 83, 13, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 10, 81, 7, 36, 1, 0 },
+                        { 0, 0, 27, 7, 85, 16, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 8, 78, 7, 41, 1, 0 },
+                        { 0, 0, 23, 7, 86, 19, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 19, 86, 7, 23, 0, 0 },
+                        { 0, 1, 41, 7, 78, 8, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 16, 85, 7, 27, 0, 0 },
+                        { 0, 1, 36, 7, 81, 10, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 13, 83, 7, 31, 1, 0 } } },
+       .ptrn_arr = { { 0x24932493, 0x24992493, 0x92499 } },
+       .sample_patrn_length = 86,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 55) = 0.367816 */
+       .hor_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 },
+                        { 0, 1, 41, 7, 77, 9, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 13, 82, 7, 32, 1, 0 },
+                        { 0, 1, 29, 7, 83, 15, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 19, 86, 7, 23, 0, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 12, 81, 7, 34, 1, 0 },
+                        { 0, 1, 27, 7, 84, 16, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 18, 85, 7, 25, 0, 0 },
+                        { 0, 1, 36, 7, 80, 11, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 11, 80, 7, 36, 1, 0 },
+                        { 0, 0, 25, 7, 85, 18, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 16, 84, 7, 27, 1, 0 },
+                        { 0, 1, 34, 7, 81, 12, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 0, 23, 7, 86, 19, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 15, 83, 7, 29, 1, 0 },
+                        { 0, 1, 32, 7, 82, 13, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 9, 77, 7, 41, 1, 0 } },
+               .odd = { { 0, 1, 30, 7, 83, 14, 0 },
+                        { 0, 3, 54, 7, 66, 5, 0 },
+                        { 0, 8, 76, 7, 43, 1, 0 },
+                        { 0, 20, 86, 7, 22, 0, 0 },
+                        { 0, 1, 40, 7, 78, 9, 0 },
+                        { 0, 4, 65, 7, 56, 3, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 1, 28, 7, 84, 15, 0 },
+                        { 0, 2, 51, 7, 69, 6, 0 },
+                        { 0, 7, 74, 7, 45, 2, 0 },
+                        { 0, 18, 86, 7, 24, 0, 0 },
+                        { 0, 1, 38, 7, 79, 10, 0 },
+                        { 0, 4, 62, 7, 59, 3, 0 },
+                        { 0, 11, 81, 7, 35, 1, 0 },
+                        { 0, 0, 26, 7, 85, 17, 0 },
+                        { 0, 2, 48, 7, 72, 6, 0 },
+                        { 0, 6, 72, 7, 48, 2, 0 },
+                        { 0, 17, 85, 7, 26, 0, 0 },
+                        { 0, 1, 35, 7, 81, 11, 0 },
+                        { 0, 3, 59, 7, 62, 4, 0 },
+                        { 0, 10, 79, 7, 38, 1, 0 },
+                        { 0, 0, 24, 7, 86, 18, 0 },
+                        { 0, 2, 45, 7, 74, 7, 0 },
+                        { 0, 6, 69, 7, 51, 2, 0 },
+                        { 0, 15, 84, 7, 28, 1, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 3, 56, 7, 65, 4, 0 },
+                        { 0, 9, 78, 7, 40, 1, 0 },
+                        { 0, 0, 22, 7, 86, 20, 0 },
+                        { 0, 1, 43, 7, 76, 8, 0 },
+                        { 0, 5, 66, 7, 54, 3, 0 },
+                        { 0, 14, 83, 7, 30, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 },
+                        { 0, 1, 41, 7, 77, 9, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 13, 82, 7, 32, 1, 0 },
+                        { 0, 1, 29, 7, 83, 15, 0 },
+                        { 0, 2, 52, 7, 69, 5, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 19, 86, 7, 23, 0, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 63, 7, 58, 3, 0 },
+                        { 0, 12, 81, 7, 34, 1, 0 },
+                        { 0, 1, 27, 7, 84, 16, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 18, 85, 7, 25, 0, 0 },
+                        { 0, 1, 36, 7, 80, 11, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 11, 80, 7, 36, 1, 0 },
+                        { 0, 0, 25, 7, 85, 18, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 16, 84, 7, 27, 1, 0 },
+                        { 0, 1, 34, 7, 81, 12, 0 },
+                        { 0, 3, 58, 7, 63, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 0, 23, 7, 86, 19, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 5, 69, 7, 52, 2, 0 },
+                        { 0, 15, 83, 7, 29, 1, 0 },
+                        { 0, 1, 32, 7, 82, 13, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 9, 77, 7, 41, 1, 0 } },
+               .odd = { { 0, 1, 30, 7, 83, 14, 0 },
+                        { 0, 3, 54, 7, 66, 5, 0 },
+                        { 0, 8, 76, 7, 43, 1, 0 },
+                        { 0, 20, 86, 7, 22, 0, 0 },
+                        { 0, 1, 40, 7, 78, 9, 0 },
+                        { 0, 4, 65, 7, 56, 3, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 1, 28, 7, 84, 15, 0 },
+                        { 0, 2, 51, 7, 69, 6, 0 },
+                        { 0, 7, 74, 7, 45, 2, 0 },
+                        { 0, 18, 86, 7, 24, 0, 0 },
+                        { 0, 1, 38, 7, 79, 10, 0 },
+                        { 0, 4, 62, 7, 59, 3, 0 },
+                        { 0, 11, 81, 7, 35, 1, 0 },
+                        { 0, 0, 26, 7, 85, 17, 0 },
+                        { 0, 2, 48, 7, 72, 6, 0 },
+                        { 0, 6, 72, 7, 48, 2, 0 },
+                        { 0, 17, 85, 7, 26, 0, 0 },
+                        { 0, 1, 35, 7, 81, 11, 0 },
+                        { 0, 3, 59, 7, 62, 4, 0 },
+                        { 0, 10, 79, 7, 38, 1, 0 },
+                        { 0, 0, 24, 7, 86, 18, 0 },
+                        { 0, 2, 45, 7, 74, 7, 0 },
+                        { 0, 6, 69, 7, 51, 2, 0 },
+                        { 0, 15, 84, 7, 28, 1, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 3, 56, 7, 65, 4, 0 },
+                        { 0, 9, 78, 7, 40, 1, 0 },
+                        { 0, 0, 22, 7, 86, 20, 0 },
+                        { 0, 1, 43, 7, 76, 8, 0 },
+                        { 0, 5, 66, 7, 54, 3, 0 },
+                        { 0, 14, 83, 7, 30, 1, 0 } } },
+       .ptrn_arr = { { 0x24992493, 0x264924c9, 0x92493249, 0x924c9249,
+                        0x93249264, 0x924 } },
+       .sample_patrn_length = 174,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 56) = 0.363636 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 } },
+               .odd = { { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 } },
+               .odd = { { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 } } },
+       .ptrn_arr = { { 0x92493 } },
+       .sample_patrn_length = 22,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 57) = 0.359551 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 37, 7, 79, 11, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 20, 84, 7, 24, 0, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 7, 69, 7, 50, 2, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 1, 26, 7, 83, 18, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 18, 83, 7, 26, 1, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 2, 50, 7, 69, 7, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 0, 24, 7, 84, 20, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 11, 79, 7, 37, 1, 0 } },
+               .odd = { { 0, 1, 29, 7, 82, 16, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 5, 64, 7, 56, 3, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 1, 36, 7, 79, 12, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 15, 81, 7, 31, 1, 0 },
+                        { 0, 1, 27, 7, 82, 18, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 4, 61, 7, 59, 4, 0 },
+                        { 0, 10, 75, 7, 41, 2, 0 },
+                        { 0, 19, 83, 7, 25, 1, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 3, 51, 7, 68, 6, 0 },
+                        { 0, 6, 68, 7, 51, 3, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 1, 25, 7, 83, 19, 0 },
+                        { 0, 2, 41, 7, 75, 10, 0 },
+                        { 0, 4, 59, 7, 61, 4, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 18, 82, 7, 27, 1, 0 },
+                        { 0, 1, 31, 7, 81, 15, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 12, 79, 7, 36, 1, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 3, 56, 7, 64, 5, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 16, 82, 7, 29, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 37, 7, 79, 11, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 20, 84, 7, 24, 0, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 7, 69, 7, 50, 2, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 1, 26, 7, 83, 18, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 18, 83, 7, 26, 1, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 2, 50, 7, 69, 7, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 0, 24, 7, 84, 20, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 11, 79, 7, 37, 1, 0 } },
+               .odd = { { 0, 1, 29, 7, 82, 16, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 5, 64, 7, 56, 3, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 1, 36, 7, 79, 12, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 15, 81, 7, 31, 1, 0 },
+                        { 0, 1, 27, 7, 82, 18, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 4, 61, 7, 59, 4, 0 },
+                        { 0, 10, 75, 7, 41, 2, 0 },
+                        { 0, 19, 83, 7, 25, 1, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 3, 51, 7, 68, 6, 0 },
+                        { 0, 6, 68, 7, 51, 3, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 1, 25, 7, 83, 19, 0 },
+                        { 0, 2, 41, 7, 75, 10, 0 },
+                        { 0, 4, 59, 7, 61, 4, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 18, 82, 7, 27, 1, 0 },
+                        { 0, 1, 31, 7, 81, 15, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 12, 79, 7, 36, 1, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 3, 56, 7, 64, 5, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 16, 82, 7, 29, 1, 0 } } },
+       .ptrn_arr = { { 0x26492493, 0x924c9249, 0x49249924, 0x64924932,
+                        0x24c92492, 0x9249 } },
+       .sample_patrn_length = 178,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 58) = 0.355556 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 6, 64, 7, 55, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 19, 82, 7, 26, 1, 0 },
+                        { 0, 1, 30, 7, 81, 16, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 16, 81, 7, 30, 1, 0 },
+                        { 0, 1, 26, 7, 82, 19, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 55, 7, 64, 6, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 } },
+               .odd = { { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 14, 80, 7, 33, 1, 0 },
+                        { 0, 1, 24, 7, 82, 21, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 21, 82, 7, 24, 1, 0 },
+                        { 0, 1, 33, 7, 80, 14, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 6, 64, 7, 55, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 19, 82, 7, 26, 1, 0 },
+                        { 0, 1, 30, 7, 81, 16, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 16, 81, 7, 30, 1, 0 },
+                        { 0, 1, 26, 7, 82, 19, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 55, 7, 64, 6, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 } },
+               .odd = { { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 14, 80, 7, 33, 1, 0 },
+                        { 0, 1, 24, 7, 82, 21, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 21, 82, 7, 24, 1, 0 },
+                        { 0, 1, 33, 7, 80, 14, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 } } },
+       .ptrn_arr = { { 0x32492493, 0x99249249, 0x924924 } },
+       .sample_patrn_length = 90,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 59) = 0.351648 */
+       .hor_phase_arr = {
+               .even = { { 0, 23, 82, 7, 23, 0, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 19, 81, 7, 27, 1, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 52, 7, 66, 7, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 16, 80, 7, 31, 1, 0 },
+                        { 0, 1, 25, 7, 81, 21, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 21, 81, 7, 25, 1, 0 },
+                        { 0, 1, 31, 7, 80, 16, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 7, 66, 7, 52, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 1, 27, 7, 81, 19, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 } },
+               .odd = { { 0, 1, 28, 7, 81, 18, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 6, 62, 7, 56, 4, 0 },
+                        { 0, 10, 73, 7, 43, 2, 0 },
+                        { 0, 15, 80, 7, 32, 1, 0 },
+                        { 0, 1, 24, 7, 81, 22, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 2, 46, 7, 71, 9, 0 },
+                        { 0, 4, 58, 7, 61, 5, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 13, 78, 7, 36, 1, 0 },
+                        { 0, 20, 81, 7, 26, 1, 0 },
+                        { 0, 1, 30, 7, 80, 17, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 17, 80, 7, 30, 1, 0 },
+                        { 0, 1, 26, 7, 81, 20, 0 },
+                        { 0, 1, 36, 7, 78, 13, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 5, 61, 7, 58, 4, 0 },
+                        { 0, 9, 71, 7, 46, 2, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 22, 81, 7, 24, 1, 0 },
+                        { 0, 1, 32, 7, 80, 15, 0 },
+                        { 0, 2, 43, 7, 73, 10, 0 },
+                        { 0, 4, 56, 7, 62, 6, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 18, 81, 7, 28, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 23, 82, 7, 23, 0, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 19, 81, 7, 27, 1, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 52, 7, 66, 7, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 16, 80, 7, 31, 1, 0 },
+                        { 0, 1, 25, 7, 81, 21, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 21, 81, 7, 25, 1, 0 },
+                        { 0, 1, 31, 7, 80, 16, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 7, 66, 7, 52, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 1, 27, 7, 81, 19, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 } },
+               .odd = { { 0, 1, 28, 7, 81, 18, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 6, 62, 7, 56, 4, 0 },
+                        { 0, 10, 73, 7, 43, 2, 0 },
+                        { 0, 15, 80, 7, 32, 1, 0 },
+                        { 0, 1, 24, 7, 81, 22, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 2, 46, 7, 71, 9, 0 },
+                        { 0, 4, 58, 7, 61, 5, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 13, 78, 7, 36, 1, 0 },
+                        { 0, 20, 81, 7, 26, 1, 0 },
+                        { 0, 1, 30, 7, 80, 17, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 17, 80, 7, 30, 1, 0 },
+                        { 0, 1, 26, 7, 81, 20, 0 },
+                        { 0, 1, 36, 7, 78, 13, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 5, 61, 7, 58, 4, 0 },
+                        { 0, 9, 71, 7, 46, 2, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 22, 81, 7, 24, 1, 0 },
+                        { 0, 1, 32, 7, 80, 15, 0 },
+                        { 0, 2, 43, 7, 73, 10, 0 },
+                        { 0, 4, 56, 7, 62, 6, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 18, 81, 7, 28, 1, 0 } } },
+       .ptrn_arr = { { 0x92492493, 0x4924924c, 0x24924992, 0x92493249,
+                        0x49264924, 0x92492 } },
+       .sample_patrn_length = 182,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 60) = 0.347826 */
+       .hor_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 } },
+               .odd = { { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 1, 35, 7, 78, 14, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 14, 78, 7, 35, 1, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 } },
+               .odd = { { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 1, 35, 7, 78, 14, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 14, 78, 7, 35, 1, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 } } },
+       .ptrn_arr = { { 0x92492493, 0x924 } },
+       .sample_patrn_length = 46,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 61) = 0.344086 */
+       .hor_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 1, 36, 7, 77, 14, 0 },
+                        { 0, 2, 42, 7, 73, 11, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 16, 78, 7, 33, 1, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 1, 25, 7, 79, 22, 1 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 2, 45, 7, 71, 10, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 10, 71, 7, 45, 2, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 1, 22, 79, 7, 25, 1, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 1, 33, 7, 78, 16, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 11, 73, 7, 42, 2, 0 },
+                        { 0, 14, 77, 7, 36, 1, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 } },
+               .odd = { { 0, 1, 26, 7, 80, 21, 0 },
+                        { 0, 1, 32, 7, 79, 16, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 3, 46, 7, 70, 9, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 8, 66, 7, 51, 3, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 18, 79, 7, 30, 1, 0 },
+                        { 1, 23, 79, 7, 24, 1, 0 },
+                        { 0, 1, 28, 7, 80, 19, 0 },
+                        { 0, 1, 35, 7, 77, 15, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 15, 77, 7, 35, 1, 0 },
+                        { 0, 19, 80, 7, 28, 1, 0 },
+                        { 0, 1, 24, 7, 79, 23, 1 },
+                        { 0, 1, 30, 7, 79, 18, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 3, 51, 7, 66, 8, 0 },
+                        { 0, 5, 58, 7, 60, 5, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 9, 70, 7, 46, 3, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 16, 79, 7, 32, 1, 0 },
+                        { 0, 21, 80, 7, 26, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 1, 36, 7, 77, 14, 0 },
+                        { 0, 2, 42, 7, 73, 11, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 16, 78, 7, 33, 1, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 1, 25, 7, 79, 22, 1 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 2, 45, 7, 71, 10, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 10, 71, 7, 45, 2, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 1, 22, 79, 7, 25, 1, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 1, 33, 7, 78, 16, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 11, 73, 7, 42, 2, 0 },
+                        { 0, 14, 77, 7, 36, 1, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 } },
+               .odd = { { 0, 1, 26, 7, 80, 21, 0 },
+                        { 0, 1, 32, 7, 79, 16, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 3, 46, 7, 70, 9, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 8, 66, 7, 51, 3, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 18, 79, 7, 30, 1, 0 },
+                        { 1, 23, 79, 7, 24, 1, 0 },
+                        { 0, 1, 28, 7, 80, 19, 0 },
+                        { 0, 1, 35, 7, 77, 15, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 15, 77, 7, 35, 1, 0 },
+                        { 0, 19, 80, 7, 28, 1, 0 },
+                        { 0, 1, 24, 7, 79, 23, 1 },
+                        { 0, 1, 30, 7, 79, 18, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 3, 51, 7, 66, 8, 0 },
+                        { 0, 5, 58, 7, 60, 5, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 9, 70, 7, 46, 3, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 16, 79, 7, 32, 1, 0 },
+                        { 0, 21, 80, 7, 26, 1, 0 } } },
+       .ptrn_arr = { { 0x92492493, 0x64924924, 0x92492492, 0x4c924924,
+                        0x92492492, 0x924924 } },
+       .sample_patrn_length = 186,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 62) = 0.340426 */
+       .hor_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 1, 28, 7, 79, 20, 0 },
+                        { 0, 1, 32, 7, 78, 17, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 17, 78, 7, 32, 1, 0 },
+                        { 0, 20, 79, 7, 28, 1, 0 } },
+               .odd = { { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 1, 28, 7, 79, 20, 0 },
+                        { 0, 1, 32, 7, 78, 17, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 17, 78, 7, 32, 1, 0 },
+                        { 0, 20, 79, 7, 28, 1, 0 } },
+               .odd = { { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 } } },
+       .ptrn_arr = { { 0x92492493, 0x24924924, 0x9249249 } },
+       .sample_patrn_length = 94,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 63) = 0.336842 */
+       .hor_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 0, 2, 40, 7, 73, 13, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 13, 73, 7, 40, 2, 0 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 } },
+               .odd = { { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 1, 27, 7, 77, 22, 1 },
+                        { 0, 1, 29, 7, 78, 20, 0 },
+                        { 0, 1, 31, 7, 78, 18, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 0, 2, 42, 7, 72, 12, 0 },
+                        { 0, 3, 44, 7, 70, 11, 0 },
+                        { 0, 3, 46, 7, 69, 10, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 10, 69, 7, 46, 3, 0 },
+                        { 0, 11, 70, 7, 44, 3, 0 },
+                        { 0, 12, 72, 7, 42, 2, 0 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 18, 78, 7, 31, 1, 0 },
+                        { 0, 20, 78, 7, 29, 1, 0 },
+                        { 1, 22, 77, 7, 27, 1, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 0, 2, 40, 7, 73, 13, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 13, 73, 7, 40, 2, 0 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 } },
+               .odd = { { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 1, 27, 7, 77, 22, 1 },
+                        { 0, 1, 29, 7, 78, 20, 0 },
+                        { 0, 1, 31, 7, 78, 18, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 0, 2, 42, 7, 72, 12, 0 },
+                        { 0, 3, 44, 7, 70, 11, 0 },
+                        { 0, 3, 46, 7, 69, 10, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 10, 69, 7, 46, 3, 0 },
+                        { 0, 11, 70, 7, 44, 3, 0 },
+                        { 0, 12, 72, 7, 42, 2, 0 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 18, 78, 7, 31, 1, 0 },
+                        { 0, 20, 78, 7, 29, 1, 0 },
+                        { 1, 22, 77, 7, 27, 1, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 } } },
+       .ptrn_arr = { { 0x92492493, 0x24924924, 0x49249249, 0x92492492,
+                        0x24924924, 0x9249249 } },
+       .sample_patrn_length = 190,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 64) = 0.333333 */
+       .hor_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 } },
+               .odd = { { 0, 4, 60, 7, 60, 4, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 21, 86, 7, 21, 0, 0 } },
+               .odd = { { 0, 4, 60, 7, 60, 4, 0 } } },
+       .ptrn_arr = { { 0x9 } },
+       .sample_patrn_length = 6,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 65) = 0.329897 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 20, 85, 7, 23, 0, 0 },
+                        { 0, 18, 84, 7, 25, 1, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 12, 81, 7, 34, 1, 0 },
+                        { 0, 11, 79, 7, 37, 1, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 4, 64, 7, 57, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 57, 7, 64, 4, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 1, 37, 7, 79, 11, 0 },
+                        { 0, 1, 34, 7, 81, 12, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 1, 25, 7, 84, 18, 0 },
+                        { 0, 0, 23, 7, 85, 20, 0 } },
+               .odd = { { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 19, 85, 7, 24, 0, 0 },
+                        { 0, 17, 84, 7, 26, 1, 0 },
+                        { 0, 16, 82, 7, 29, 1, 0 },
+                        { 0, 14, 82, 7, 31, 1, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 12, 80, 7, 35, 1, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 10, 77, 7, 40, 1, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 6, 69, 7, 51, 2, 0 },
+                        { 0, 5, 66, 7, 54, 3, 0 },
+                        { 0, 5, 64, 7, 56, 3, 0 },
+                        { 0, 4, 61, 7, 59, 4, 0 },
+                        { 0, 4, 59, 7, 61, 4, 0 },
+                        { 0, 3, 56, 7, 64, 5, 0 },
+                        { 0, 3, 54, 7, 66, 5, 0 },
+                        { 0, 2, 51, 7, 69, 6, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 1, 40, 7, 77, 10, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 1, 35, 7, 80, 12, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 1, 31, 7, 82, 14, 0 },
+                        { 0, 1, 29, 7, 82, 16, 0 },
+                        { 0, 1, 26, 7, 84, 17, 0 },
+                        { 0, 0, 24, 7, 85, 19, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 20, 85, 7, 23, 0, 0 },
+                        { 0, 18, 84, 7, 25, 1, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 12, 81, 7, 34, 1, 0 },
+                        { 0, 11, 79, 7, 37, 1, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 7, 72, 7, 47, 2, 0 },
+                        { 0, 6, 70, 7, 50, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 4, 64, 7, 57, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 57, 7, 64, 4, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 50, 7, 70, 6, 0 },
+                        { 0, 2, 47, 7, 72, 7, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 1, 37, 7, 79, 11, 0 },
+                        { 0, 1, 34, 7, 81, 12, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 1, 25, 7, 84, 18, 0 },
+                        { 0, 0, 23, 7, 85, 20, 0 } },
+               .odd = { { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 19, 85, 7, 24, 0, 0 },
+                        { 0, 17, 84, 7, 26, 1, 0 },
+                        { 0, 16, 82, 7, 29, 1, 0 },
+                        { 0, 14, 82, 7, 31, 1, 0 },
+                        { 0, 13, 81, 7, 33, 1, 0 },
+                        { 0, 12, 80, 7, 35, 1, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 10, 77, 7, 40, 1, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 6, 69, 7, 51, 2, 0 },
+                        { 0, 5, 66, 7, 54, 3, 0 },
+                        { 0, 5, 64, 7, 56, 3, 0 },
+                        { 0, 4, 61, 7, 59, 4, 0 },
+                        { 0, 4, 59, 7, 61, 4, 0 },
+                        { 0, 3, 56, 7, 64, 5, 0 },
+                        { 0, 3, 54, 7, 66, 5, 0 },
+                        { 0, 2, 51, 7, 69, 6, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 1, 40, 7, 77, 10, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 1, 35, 7, 80, 12, 0 },
+                        { 0, 1, 33, 7, 81, 13, 0 },
+                        { 0, 1, 31, 7, 82, 14, 0 },
+                        { 0, 1, 29, 7, 82, 16, 0 },
+                        { 0, 1, 26, 7, 84, 17, 0 },
+                        { 0, 0, 24, 7, 85, 19, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x92492492, 0x24924924, 0x49249249,
+                        0x92492492, 0x24924924 } },
+       .sample_patrn_length = 194,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 66) = 0.326531 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 18, 83, 7, 26, 1, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 7, 69, 7, 50, 2, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 2, 50, 7, 69, 7, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 1, 26, 7, 83, 18, 0 } },
+               .odd = { { 0, 20, 84, 7, 24, 0, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 0, 24, 7, 84, 20, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 18, 83, 7, 26, 1, 0 },
+                        { 0, 15, 82, 7, 30, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 10, 78, 7, 39, 1, 0 },
+                        { 0, 8, 74, 7, 44, 2, 0 },
+                        { 0, 7, 69, 7, 50, 2, 0 },
+                        { 0, 5, 65, 7, 55, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 55, 7, 65, 5, 0 },
+                        { 0, 2, 50, 7, 69, 7, 0 },
+                        { 0, 2, 44, 7, 74, 8, 0 },
+                        { 0, 1, 39, 7, 78, 10, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 30, 7, 82, 15, 0 },
+                        { 0, 1, 26, 7, 83, 18, 0 } },
+               .odd = { { 0, 20, 84, 7, 24, 0, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 14, 81, 7, 32, 1, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 9, 75, 7, 42, 2, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 2, 42, 7, 75, 9, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 1, 32, 7, 81, 14, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 },
+                        { 0, 0, 24, 7, 84, 20, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x92492492, 0x24924924 } },
+       .sample_patrn_length = 98,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 67) = 0.323232 */
+       .hor_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 3, 55, 7, 64, 6, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 33, 7, 80, 14, 0 },
+                        { 0, 1, 26, 7, 82, 19, 0 },
+                        { 0, 21, 82, 7, 24, 1, 0 },
+                        { 0, 16, 81, 7, 30, 1, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 1, 30, 7, 81, 16, 0 },
+                        { 0, 1, 24, 7, 82, 21, 0 },
+                        { 0, 19, 82, 7, 26, 1, 0 },
+                        { 0, 14, 80, 7, 33, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 6, 64, 7, 55, 3, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 } },
+               .odd = { { 0, 20, 82, 7, 25, 1, 0 },
+                        { 0, 15, 81, 7, 31, 1, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 4, 58, 7, 61, 5, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 1, 36, 7, 79, 12, 0 },
+                        { 0, 1, 29, 7, 81, 17, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 },
+                        { 0, 18, 82, 7, 27, 1, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 10, 75, 7, 41, 2, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 5, 63, 7, 56, 4, 0 },
+                        { 0, 4, 56, 7, 63, 5, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 2, 41, 7, 75, 10, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 1, 27, 7, 82, 18, 0 },
+                        { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 17, 81, 7, 29, 1, 0 },
+                        { 0, 12, 79, 7, 36, 1, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 5, 61, 7, 58, 4, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 1, 31, 7, 81, 15, 0 },
+                        { 0, 1, 25, 7, 82, 20, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 22, 84, 7, 22, 0, 0 },
+                        { 0, 17, 82, 7, 28, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 3, 55, 7, 64, 6, 0 },
+                        { 0, 2, 47, 7, 71, 8, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 33, 7, 80, 14, 0 },
+                        { 0, 1, 26, 7, 82, 19, 0 },
+                        { 0, 21, 82, 7, 24, 1, 0 },
+                        { 0, 16, 81, 7, 30, 1, 0 },
+                        { 0, 12, 78, 7, 37, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 6, 67, 7, 52, 3, 0 },
+                        { 0, 4, 60, 7, 60, 4, 0 },
+                        { 0, 3, 52, 7, 67, 6, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 37, 7, 78, 12, 0 },
+                        { 0, 1, 30, 7, 81, 16, 0 },
+                        { 0, 1, 24, 7, 82, 21, 0 },
+                        { 0, 19, 82, 7, 26, 1, 0 },
+                        { 0, 14, 80, 7, 33, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 8, 71, 7, 47, 2, 0 },
+                        { 0, 6, 64, 7, 55, 3, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 28, 7, 82, 17, 0 } },
+               .odd = { { 0, 20, 82, 7, 25, 1, 0 },
+                        { 0, 15, 81, 7, 31, 1, 0 },
+                        { 0, 11, 78, 7, 38, 1, 0 },
+                        { 0, 8, 72, 7, 46, 2, 0 },
+                        { 0, 6, 66, 7, 53, 3, 0 },
+                        { 0, 4, 58, 7, 61, 5, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 2, 43, 7, 74, 9, 0 },
+                        { 0, 1, 36, 7, 79, 12, 0 },
+                        { 0, 1, 29, 7, 81, 17, 0 },
+                        { 0, 0, 23, 7, 84, 21, 0 },
+                        { 0, 18, 82, 7, 27, 1, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 10, 75, 7, 41, 2, 0 },
+                        { 0, 7, 71, 7, 48, 2, 0 },
+                        { 0, 5, 63, 7, 56, 4, 0 },
+                        { 0, 4, 56, 7, 63, 5, 0 },
+                        { 0, 2, 48, 7, 71, 7, 0 },
+                        { 0, 2, 41, 7, 75, 10, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 1, 27, 7, 82, 18, 0 },
+                        { 0, 21, 84, 7, 23, 0, 0 },
+                        { 0, 17, 81, 7, 29, 1, 0 },
+                        { 0, 12, 79, 7, 36, 1, 0 },
+                        { 0, 9, 74, 7, 43, 2, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 5, 61, 7, 58, 4, 0 },
+                        { 0, 3, 53, 7, 66, 6, 0 },
+                        { 0, 2, 46, 7, 72, 8, 0 },
+                        { 0, 1, 38, 7, 78, 11, 0 },
+                        { 0, 1, 31, 7, 81, 15, 0 },
+                        { 0, 1, 25, 7, 82, 20, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x92492492, 0x92492490, 0x24924924,
+                        0x24924921, 0x49249249, 0x2 } },
+       .sample_patrn_length = 198,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 68) = 0.32 */
+       .hor_phase_arr = {
+               .even = { { 0, 23, 82, 7, 23, 0, 0 },
+                        { 0, 16, 80, 7, 31, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 31, 7, 80, 16, 0 } },
+               .odd = { { 0, 19, 81, 7, 27, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 27, 7, 81, 19, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 0, 23, 82, 7, 23, 0, 0 },
+                        { 0, 16, 80, 7, 31, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 7, 68, 7, 50, 3, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 3, 50, 7, 68, 7, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 31, 7, 80, 16, 0 } },
+               .odd = { { 0, 19, 81, 7, 27, 1, 0 },
+                        { 0, 13, 79, 7, 35, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 35, 7, 79, 13, 0 },
+                        { 0, 1, 27, 7, 81, 19, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x2492 } },
+       .sample_patrn_length = 50,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 69) = 0.316832 */
+       .hor_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 7, 66, 7, 52, 3, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 21, 81, 7, 25, 1, 0 },
+                        { 0, 14, 78, 7, 35, 1, 0 },
+                        { 0, 8, 70, 7, 47, 3, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 3, 47, 7, 70, 8, 0 },
+                        { 0, 1, 35, 7, 78, 14, 0 },
+                        { 0, 1, 25, 7, 81, 21, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 3, 52, 7, 66, 7, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 } },
+               .odd = { { 0, 19, 80, 7, 28, 1, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 4, 56, 7, 62, 6, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 1, 32, 7, 79, 16, 0 },
+                        { 0, 22, 81, 7, 24, 1, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 9, 71, 7, 46, 2, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 1, 36, 7, 78, 13, 0 },
+                        { 0, 1, 26, 7, 81, 20, 0 },
+                        { 0, 17, 80, 7, 30, 1, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 6, 65, 7, 53, 4, 0 },
+                        { 0, 4, 53, 7, 65, 6, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 1, 30, 7, 80, 17, 0 },
+                        { 0, 20, 81, 7, 26, 1, 0 },
+                        { 0, 13, 78, 7, 36, 1, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 5, 58, 7, 60, 5, 0 },
+                        { 0, 2, 46, 7, 71, 9, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 1, 24, 7, 81, 22, 0 },
+                        { 0, 16, 79, 7, 32, 1, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 6, 62, 7, 56, 4, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 1, 28, 7, 80, 19, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 },
+                        { 0, 9, 72, 7, 45, 2, 0 },
+                        { 0, 5, 62, 7, 57, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 11, 75, 7, 40, 2, 0 },
+                        { 0, 7, 66, 7, 52, 3, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 2, 42, 7, 74, 10, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 21, 81, 7, 25, 1, 0 },
+                        { 0, 14, 78, 7, 35, 1, 0 },
+                        { 0, 8, 70, 7, 47, 3, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 3, 47, 7, 70, 8, 0 },
+                        { 0, 1, 35, 7, 78, 14, 0 },
+                        { 0, 1, 25, 7, 81, 21, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 10, 74, 7, 42, 2, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 3, 52, 7, 66, 7, 0 },
+                        { 0, 2, 40, 7, 75, 11, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 57, 7, 62, 5, 0 },
+                        { 0, 2, 45, 7, 72, 9, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 } },
+               .odd = { { 0, 19, 80, 7, 28, 1, 0 },
+                        { 0, 12, 75, 7, 39, 2, 0 },
+                        { 0, 7, 67, 7, 51, 3, 0 },
+                        { 0, 4, 56, 7, 62, 6, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 1, 32, 7, 79, 16, 0 },
+                        { 0, 22, 81, 7, 24, 1, 0 },
+                        { 0, 14, 79, 7, 34, 1, 0 },
+                        { 0, 9, 71, 7, 46, 2, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 3, 48, 7, 69, 8, 0 },
+                        { 0, 1, 36, 7, 78, 13, 0 },
+                        { 0, 1, 26, 7, 81, 20, 0 },
+                        { 0, 17, 80, 7, 30, 1, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 6, 65, 7, 53, 4, 0 },
+                        { 0, 4, 53, 7, 65, 6, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 1, 30, 7, 80, 17, 0 },
+                        { 0, 20, 81, 7, 26, 1, 0 },
+                        { 0, 13, 78, 7, 36, 1, 0 },
+                        { 0, 8, 69, 7, 48, 3, 0 },
+                        { 0, 5, 58, 7, 60, 5, 0 },
+                        { 0, 2, 46, 7, 71, 9, 0 },
+                        { 0, 1, 34, 7, 79, 14, 0 },
+                        { 0, 1, 24, 7, 81, 22, 0 },
+                        { 0, 16, 79, 7, 32, 1, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 6, 62, 7, 56, 4, 0 },
+                        { 0, 3, 51, 7, 67, 7, 0 },
+                        { 0, 2, 39, 7, 75, 12, 0 },
+                        { 0, 1, 28, 7, 80, 19, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x49249212, 0x49242492, 0x48492492,
+                        0x92492492, 0x92492490, 0x24 } },
+       .sample_patrn_length = 202,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 70) = 0.313725 */
+       .hor_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 14, 77, 7, 36, 1, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 10, 71, 7, 45, 2, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 2, 45, 7, 71, 10, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 1, 36, 7, 77, 14, 0 } },
+               .odd = { { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 11, 73, 7, 42, 2, 0 },
+                        { 0, 6, 61, 7, 57, 4, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 },
+                        { 0, 22, 80, 7, 25, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 1, 25, 7, 80, 22, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 4, 57, 7, 61, 6, 0 },
+                        { 0, 2, 42, 7, 73, 11, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 23, 80, 7, 23, 1, 0 },
+                        { 0, 14, 77, 7, 36, 1, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 54, 7, 64, 6, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 10, 71, 7, 45, 2, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 2, 45, 7, 71, 10, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 6, 64, 7, 54, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 1, 36, 7, 77, 14, 0 } },
+               .odd = { { 0, 18, 80, 7, 29, 1, 0 },
+                        { 0, 11, 73, 7, 42, 2, 0 },
+                        { 0, 6, 61, 7, 57, 4, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 1, 33, 7, 79, 15, 0 },
+                        { 0, 22, 80, 7, 25, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 },
+                        { 0, 1, 25, 7, 80, 22, 0 },
+                        { 0, 15, 79, 7, 33, 1, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 4, 57, 7, 61, 6, 0 },
+                        { 0, 2, 42, 7, 73, 11, 0 },
+                        { 0, 1, 29, 7, 80, 18, 0 } } },
+       .ptrn_arr = { { 0x49249249, 0x49249248, 0x49249242, 0x2 } },
+       .sample_patrn_length = 102,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 71) = 0.31068 */
+       .hor_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 19, 79, 7, 29, 1, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 14, 76, 7, 36, 2, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 2, 36, 7, 76, 14, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 1, 29, 7, 79, 19, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 } },
+               .odd = { { 0, 18, 79, 7, 30, 1, 0 },
+                        { 0, 9, 70, 7, 46, 3, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 },
+                        { 0, 20, 79, 7, 28, 1, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 5, 58, 7, 59, 6, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 1, 26, 7, 79, 21, 1 },
+                        { 0, 15, 77, 7, 35, 1, 0 },
+                        { 0, 8, 66, 7, 51, 3, 0 },
+                        { 0, 3, 51, 7, 66, 8, 0 },
+                        { 0, 1, 35, 7, 77, 15, 0 },
+                        { 1, 21, 79, 7, 26, 1, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 6, 59, 7, 58, 5, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 1, 28, 7, 79, 20, 0 },
+                        { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 3, 46, 7, 70, 9, 0 },
+                        { 0, 1, 30, 7, 79, 18, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 13, 75, 7, 38, 2, 0 },
+                        { 0, 7, 63, 7, 54, 4, 0 },
+                        { 0, 3, 47, 7, 69, 9, 0 },
+                        { 0, 1, 31, 7, 79, 17, 0 },
+                        { 0, 19, 79, 7, 29, 1, 0 },
+                        { 0, 10, 70, 7, 45, 3, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 },
+                        { 0, 1, 26, 7, 78, 22, 1 },
+                        { 0, 14, 76, 7, 36, 2, 0 },
+                        { 0, 7, 65, 7, 52, 4, 0 },
+                        { 0, 3, 50, 7, 67, 8, 0 },
+                        { 0, 1, 34, 7, 77, 16, 0 },
+                        { 0, 20, 80, 7, 27, 1, 0 },
+                        { 0, 11, 72, 7, 43, 2, 0 },
+                        { 0, 5, 59, 7, 59, 5, 0 },
+                        { 0, 2, 43, 7, 72, 11, 0 },
+                        { 0, 1, 27, 7, 80, 20, 0 },
+                        { 0, 16, 77, 7, 34, 1, 0 },
+                        { 0, 8, 67, 7, 50, 3, 0 },
+                        { 0, 4, 52, 7, 65, 7, 0 },
+                        { 0, 2, 36, 7, 76, 14, 0 },
+                        { 1, 22, 78, 7, 26, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 3, 45, 7, 70, 10, 0 },
+                        { 0, 1, 29, 7, 79, 19, 0 },
+                        { 0, 17, 79, 7, 31, 1, 0 },
+                        { 0, 9, 69, 7, 47, 3, 0 },
+                        { 0, 4, 54, 7, 63, 7, 0 },
+                        { 0, 2, 38, 7, 75, 13, 0 } },
+               .odd = { { 0, 18, 79, 7, 30, 1, 0 },
+                        { 0, 9, 70, 7, 46, 3, 0 },
+                        { 0, 4, 55, 7, 63, 6, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 },
+                        { 0, 20, 79, 7, 28, 1, 0 },
+                        { 0, 10, 72, 7, 44, 2, 0 },
+                        { 0, 5, 58, 7, 59, 6, 0 },
+                        { 0, 2, 41, 7, 74, 11, 0 },
+                        { 0, 1, 26, 7, 79, 21, 1 },
+                        { 0, 15, 77, 7, 35, 1, 0 },
+                        { 0, 8, 66, 7, 51, 3, 0 },
+                        { 0, 3, 51, 7, 66, 8, 0 },
+                        { 0, 1, 35, 7, 77, 15, 0 },
+                        { 1, 21, 79, 7, 26, 1, 0 },
+                        { 0, 11, 74, 7, 41, 2, 0 },
+                        { 0, 6, 59, 7, 58, 5, 0 },
+                        { 0, 2, 44, 7, 72, 10, 0 },
+                        { 0, 1, 28, 7, 79, 20, 0 },
+                        { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 6, 63, 7, 55, 4, 0 },
+                        { 0, 3, 46, 7, 70, 9, 0 },
+                        { 0, 1, 30, 7, 79, 18, 0 } } },
+       .ptrn_arr = { { 0x9249249, 0x21249249, 0x24249249, 0x24849249,
+                        0x24909249, 0x24921249, 0x249 } },
+       .sample_patrn_length = 206,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 72) = 0.307692 */
+       .hor_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 } },
+               .odd = { { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 8, 68, 7, 49, 3, 0 },
+                        { 0, 3, 49, 7, 68, 8, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 12, 74, 7, 40, 2, 0 },
+                        { 0, 5, 60, 7, 58, 5, 0 },
+                        { 0, 2, 40, 7, 74, 12, 0 } },
+               .odd = { { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 8, 68, 7, 49, 3, 0 },
+                        { 0, 3, 49, 7, 68, 8, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 } } },
+       .ptrn_arr = { { 0x249249 } },
+       .sample_patrn_length = 26,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 73) = 0.304762 */
+       .hor_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 5, 54, 7, 62, 7, 0 },
+                        { 0, 2, 34, 7, 76, 16, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 0, 1, 26, 7, 77, 23, 1 },
+                        { 0, 13, 73, 7, 40, 2, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 47, 7, 68, 10, 0 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 0, 10, 68, 7, 47, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 2, 40, 7, 73, 13, 0 },
+                        { 1, 23, 77, 7, 26, 1, 0 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 16, 76, 7, 34, 2, 0 },
+                        { 0, 7, 62, 7, 54, 5, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 } },
+               .odd = { { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 3, 44, 7, 70, 11, 0 },
+                        { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 12, 72, 7, 42, 2, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 },
+                        { 0, 19, 77, 7, 31, 1, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 3, 46, 7, 69, 10, 0 },
+                        { 0, 1, 27, 7, 77, 22, 1 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 1, 20, 77, 7, 29, 1, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 1, 29, 7, 77, 20, 1 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 1, 22, 77, 7, 27, 1, 0 },
+                        { 0, 10, 69, 7, 46, 3, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 1, 31, 7, 77, 19, 0 },
+                        { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 2, 42, 7, 72, 12, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 },
+                        { 0, 11, 70, 7, 44, 3, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 24, 78, 7, 24, 1, 0 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 5, 54, 7, 62, 7, 0 },
+                        { 0, 2, 34, 7, 76, 16, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 0, 1, 26, 7, 77, 23, 1 },
+                        { 0, 13, 73, 7, 40, 2, 0 },
+                        { 0, 5, 56, 7, 61, 6, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 19, 78, 7, 30, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 47, 7, 68, 10, 0 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 0, 10, 68, 7, 47, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 30, 7, 78, 19, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 6, 61, 7, 56, 5, 0 },
+                        { 0, 2, 40, 7, 73, 13, 0 },
+                        { 1, 23, 77, 7, 26, 1, 0 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 16, 76, 7, 34, 2, 0 },
+                        { 0, 7, 62, 7, 54, 5, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 } },
+               .odd = { { 0, 17, 77, 7, 33, 1, 0 },
+                        { 0, 7, 64, 7, 53, 4, 0 },
+                        { 0, 3, 44, 7, 70, 11, 0 },
+                        { 0, 1, 25, 7, 78, 23, 1 },
+                        { 0, 12, 72, 7, 42, 2, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 },
+                        { 0, 19, 77, 7, 31, 1, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 3, 46, 7, 69, 10, 0 },
+                        { 0, 1, 27, 7, 77, 22, 1 },
+                        { 0, 13, 74, 7, 39, 2, 0 },
+                        { 0, 5, 57, 7, 60, 6, 0 },
+                        { 0, 2, 37, 7, 75, 14, 0 },
+                        { 1, 20, 77, 7, 29, 1, 0 },
+                        { 0, 9, 68, 7, 48, 3, 0 },
+                        { 0, 3, 48, 7, 68, 9, 0 },
+                        { 0, 1, 29, 7, 77, 20, 1 },
+                        { 0, 14, 75, 7, 37, 2, 0 },
+                        { 0, 6, 60, 7, 57, 5, 0 },
+                        { 0, 2, 39, 7, 74, 13, 0 },
+                        { 1, 22, 77, 7, 27, 1, 0 },
+                        { 0, 10, 69, 7, 46, 3, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 1, 31, 7, 77, 19, 0 },
+                        { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 2, 42, 7, 72, 12, 0 },
+                        { 1, 23, 78, 7, 25, 1, 0 },
+                        { 0, 11, 70, 7, 44, 3, 0 },
+                        { 0, 4, 53, 7, 64, 7, 0 },
+                        { 0, 1, 33, 7, 77, 17, 0 } } },
+       .ptrn_arr = { { 0x24249249, 0x24921249, 0x84924909, 0x92424924,
+                        0x92492124, 0x48492490, 0x2492 } },
+       .sample_patrn_length = 210,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 74) = 0.301887 */
+       .hor_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 13, 72, 7, 41, 2, 0 },
+                        { 0, 5, 54, 7, 62, 7, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 7, 62, 7, 54, 5, 0 },
+                        { 0, 2, 41, 7, 72, 13, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 } },
+               .odd = { { 0, 17, 75, 7, 34, 2, 0 },
+                        { 0, 7, 60, 7, 56, 5, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 1, 20, 76, 7, 30, 1, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 },
+                        { 1, 23, 77, 7, 26, 1, 0 },
+                        { 0, 10, 68, 7, 47, 3, 0 },
+                        { 0, 3, 47, 7, 68, 10, 0 },
+                        { 0, 1, 26, 7, 77, 23, 1 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 1, 30, 7, 76, 20, 1 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 5, 56, 7, 60, 7, 0 },
+                        { 0, 2, 34, 7, 75, 17, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 28, 7, 77, 21, 1 },
+                        { 0, 13, 72, 7, 41, 2, 0 },
+                        { 0, 5, 54, 7, 62, 7, 0 },
+                        { 0, 1, 32, 7, 77, 18, 0 },
+                        { 0, 15, 75, 7, 36, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 36, 7, 75, 15, 0 },
+                        { 0, 18, 77, 7, 32, 1, 0 },
+                        { 0, 7, 62, 7, 54, 5, 0 },
+                        { 0, 2, 41, 7, 72, 13, 0 },
+                        { 1, 21, 77, 7, 28, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 } },
+               .odd = { { 0, 17, 75, 7, 34, 2, 0 },
+                        { 0, 7, 60, 7, 56, 5, 0 },
+                        { 0, 2, 38, 7, 74, 14, 0 },
+                        { 1, 20, 76, 7, 30, 1, 0 },
+                        { 0, 8, 64, 7, 52, 4, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 },
+                        { 1, 23, 77, 7, 26, 1, 0 },
+                        { 0, 10, 68, 7, 47, 3, 0 },
+                        { 0, 3, 47, 7, 68, 10, 0 },
+                        { 0, 1, 26, 7, 77, 23, 1 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 4, 52, 7, 64, 8, 0 },
+                        { 0, 1, 30, 7, 76, 20, 1 },
+                        { 0, 14, 74, 7, 38, 2, 0 },
+                        { 0, 5, 56, 7, 60, 7, 0 },
+                        { 0, 2, 34, 7, 75, 17, 0 } } },
+       .ptrn_arr = { { 0x24849249, 0x24924849, 0x92424924, 0x24 } },
+       .sample_patrn_length = 106,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 75) = 0.299065 */
+       .hor_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 10, 67, 7, 47, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 1, 23, 76, 7, 27, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 2, 41, 7, 72, 13, 0 },
+                        { 1, 20, 76, 7, 30, 1, 0 },
+                        { 0, 8, 61, 7, 54, 5, 0 },
+                        { 0, 2, 39, 7, 72, 15, 0 },
+                        { 0, 19, 76, 7, 32, 1, 0 },
+                        { 0, 7, 59, 7, 56, 6, 0 },
+                        { 0, 2, 36, 7, 74, 16, 0 },
+                        { 0, 17, 75, 7, 34, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 34, 7, 75, 17, 0 },
+                        { 0, 16, 74, 7, 36, 2, 0 },
+                        { 0, 6, 56, 7, 59, 7, 0 },
+                        { 0, 1, 32, 7, 76, 19, 0 },
+                        { 0, 15, 72, 7, 39, 2, 0 },
+                        { 0, 5, 54, 7, 61, 8, 0 },
+                        { 0, 1, 30, 7, 76, 20, 1 },
+                        { 0, 13, 72, 7, 41, 2, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 27, 7, 76, 23, 1 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 47, 7, 67, 10, 0 } },
+               .odd = { { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 6, 57, 7, 58, 7, 0 },
+                        { 0, 2, 33, 7, 75, 18, 0 },
+                        { 0, 15, 73, 7, 38, 2, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 1, 31, 7, 76, 19, 1 },
+                        { 0, 14, 72, 7, 40, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 30, 7, 75, 21, 1 },
+                        { 0, 13, 70, 7, 42, 3, 0 },
+                        { 0, 4, 50, 7, 65, 9, 0 },
+                        { 0, 1, 28, 7, 76, 22, 1 },
+                        { 0, 12, 69, 7, 44, 3, 0 },
+                        { 0, 4, 48, 7, 66, 10, 0 },
+                        { 0, 1, 26, 7, 76, 24, 1 },
+                        { 0, 11, 68, 7, 46, 3, 0 },
+                        { 0, 3, 46, 7, 68, 11, 0 },
+                        { 1, 24, 76, 7, 26, 1, 0 },
+                        { 0, 10, 66, 7, 48, 4, 0 },
+                        { 0, 3, 44, 7, 69, 12, 0 },
+                        { 1, 22, 76, 7, 28, 1, 0 },
+                        { 0, 9, 65, 7, 50, 4, 0 },
+                        { 0, 3, 42, 7, 70, 13, 0 },
+                        { 1, 21, 75, 7, 30, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 40, 7, 72, 14, 0 },
+                        { 1, 19, 76, 7, 31, 1, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 2, 38, 7, 73, 15, 0 },
+                        { 0, 18, 75, 7, 33, 2, 0 },
+                        { 0, 7, 58, 7, 57, 6, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 10, 67, 7, 47, 4, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 1, 23, 76, 7, 27, 1, 0 },
+                        { 0, 9, 66, 7, 49, 4, 0 },
+                        { 0, 3, 43, 7, 70, 12, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 8, 65, 7, 51, 4, 0 },
+                        { 0, 2, 41, 7, 72, 13, 0 },
+                        { 1, 20, 76, 7, 30, 1, 0 },
+                        { 0, 8, 61, 7, 54, 5, 0 },
+                        { 0, 2, 39, 7, 72, 15, 0 },
+                        { 0, 19, 76, 7, 32, 1, 0 },
+                        { 0, 7, 59, 7, 56, 6, 0 },
+                        { 0, 2, 36, 7, 74, 16, 0 },
+                        { 0, 17, 75, 7, 34, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 34, 7, 75, 17, 0 },
+                        { 0, 16, 74, 7, 36, 2, 0 },
+                        { 0, 6, 56, 7, 59, 7, 0 },
+                        { 0, 1, 32, 7, 76, 19, 0 },
+                        { 0, 15, 72, 7, 39, 2, 0 },
+                        { 0, 5, 54, 7, 61, 8, 0 },
+                        { 0, 1, 30, 7, 76, 20, 1 },
+                        { 0, 13, 72, 7, 41, 2, 0 },
+                        { 0, 4, 51, 7, 65, 8, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 12, 70, 7, 43, 3, 0 },
+                        { 0, 4, 49, 7, 66, 9, 0 },
+                        { 0, 1, 27, 7, 76, 23, 1 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 4, 47, 7, 67, 10, 0 } },
+               .odd = { { 0, 16, 75, 7, 35, 2, 0 },
+                        { 0, 6, 57, 7, 58, 7, 0 },
+                        { 0, 2, 33, 7, 75, 18, 0 },
+                        { 0, 15, 73, 7, 38, 2, 0 },
+                        { 0, 5, 55, 7, 61, 7, 0 },
+                        { 0, 1, 31, 7, 76, 19, 1 },
+                        { 0, 14, 72, 7, 40, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 30, 7, 75, 21, 1 },
+                        { 0, 13, 70, 7, 42, 3, 0 },
+                        { 0, 4, 50, 7, 65, 9, 0 },
+                        { 0, 1, 28, 7, 76, 22, 1 },
+                        { 0, 12, 69, 7, 44, 3, 0 },
+                        { 0, 4, 48, 7, 66, 10, 0 },
+                        { 0, 1, 26, 7, 76, 24, 1 },
+                        { 0, 11, 68, 7, 46, 3, 0 },
+                        { 0, 3, 46, 7, 68, 11, 0 },
+                        { 1, 24, 76, 7, 26, 1, 0 },
+                        { 0, 10, 66, 7, 48, 4, 0 },
+                        { 0, 3, 44, 7, 69, 12, 0 },
+                        { 1, 22, 76, 7, 28, 1, 0 },
+                        { 0, 9, 65, 7, 50, 4, 0 },
+                        { 0, 3, 42, 7, 70, 13, 0 },
+                        { 1, 21, 75, 7, 30, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 40, 7, 72, 14, 0 },
+                        { 1, 19, 76, 7, 31, 1, 0 },
+                        { 0, 7, 61, 7, 55, 5, 0 },
+                        { 0, 2, 38, 7, 73, 15, 0 },
+                        { 0, 18, 75, 7, 33, 2, 0 },
+                        { 0, 7, 58, 7, 57, 6, 0 },
+                        { 0, 2, 35, 7, 75, 16, 0 } } },
+       .ptrn_arr = { { 0x24909249, 0x90924909, 0x92490924, 0x49212490,
+                        0x21249212, 0x24921249, 0x24921 } },
+       .sample_patrn_length = 214,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 76) = 0.296296 */
+       .hor_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 10, 65, 7, 49, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 49, 7, 65, 10, 0 } },
+               .odd = { { 0, 16, 73, 7, 37, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 37, 7, 73, 16, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 25, 76, 7, 25, 1, 0 },
+                        { 0, 10, 65, 7, 49, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 58, 7, 58, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 49, 7, 65, 10, 0 } },
+               .odd = { { 0, 16, 73, 7, 37, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 11, 69, 7, 45, 3, 0 },
+                        { 0, 3, 45, 7, 69, 11, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 37, 7, 73, 16, 0 } } },
+       .ptrn_arr = { { 0x24909249, 0x24921 } },
+       .sample_patrn_length = 54,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 77) = 0.293578 */
+       .hor_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 37, 7, 73, 16, 0 },
+                        { 0, 15, 72, 7, 39, 2, 0 },
+                        { 0, 4, 49, 7, 65, 10, 0 },
+                        { 1, 24, 75, 7, 27, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 7, 60, 7, 55, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 45, 7, 68, 12, 0 },
+                        { 1, 21, 74, 7, 31, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 31, 7, 74, 21, 1 },
+                        { 0, 12, 68, 7, 45, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 55, 7, 60, 7, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 27, 7, 75, 24, 1 },
+                        { 0, 10, 65, 7, 49, 4, 0 },
+                        { 0, 2, 39, 7, 72, 15, 0 },
+                        { 0, 16, 73, 7, 37, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 } },
+               .odd = { { 0, 16, 72, 7, 38, 2, 0 },
+                        { 0, 5, 50, 7, 64, 9, 0 },
+                        { 1, 25, 75, 7, 26, 1, 0 },
+                        { 0, 8, 63, 7, 52, 5, 0 },
+                        { 0, 2, 36, 7, 73, 17, 0 },
+                        { 0, 15, 70, 7, 40, 3, 0 },
+                        { 0, 4, 48, 7, 66, 10, 0 },
+                        { 1, 23, 75, 7, 28, 1, 0 },
+                        { 0, 8, 60, 7, 54, 6, 0 },
+                        { 0, 2, 34, 7, 73, 18, 1 },
+                        { 0, 13, 70, 7, 42, 3, 0 },
+                        { 0, 4, 46, 7, 67, 11, 0 },
+                        { 1, 21, 75, 7, 30, 1, 0 },
+                        { 0, 7, 59, 7, 56, 6, 0 },
+                        { 0, 2, 32, 7, 73, 20, 1 },
+                        { 0, 12, 69, 7, 44, 3, 0 },
+                        { 0, 3, 44, 7, 69, 12, 0 },
+                        { 1, 20, 73, 7, 32, 2, 0 },
+                        { 0, 6, 56, 7, 59, 7, 0 },
+                        { 0, 1, 30, 7, 75, 21, 1 },
+                        { 0, 11, 67, 7, 46, 4, 0 },
+                        { 0, 3, 42, 7, 70, 13, 0 },
+                        { 1, 18, 73, 7, 34, 2, 0 },
+                        { 0, 6, 54, 7, 60, 8, 0 },
+                        { 0, 1, 28, 7, 75, 23, 1 },
+                        { 0, 10, 66, 7, 48, 4, 0 },
+                        { 0, 3, 40, 7, 70, 15, 0 },
+                        { 0, 17, 73, 7, 36, 2, 0 },
+                        { 0, 5, 52, 7, 63, 8, 0 },
+                        { 0, 1, 26, 7, 75, 25, 1 },
+                        { 0, 9, 64, 7, 50, 5, 0 },
+                        { 0, 2, 38, 7, 72, 16, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 37, 7, 73, 16, 0 },
+                        { 0, 15, 72, 7, 39, 2, 0 },
+                        { 0, 4, 49, 7, 65, 10, 0 },
+                        { 1, 24, 75, 7, 27, 1, 0 },
+                        { 0, 8, 62, 7, 53, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 7, 60, 7, 55, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 45, 7, 68, 12, 0 },
+                        { 1, 21, 74, 7, 31, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 31, 7, 74, 21, 1 },
+                        { 0, 12, 68, 7, 45, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 55, 7, 60, 7, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 53, 7, 62, 8, 0 },
+                        { 0, 1, 27, 7, 75, 24, 1 },
+                        { 0, 10, 65, 7, 49, 4, 0 },
+                        { 0, 2, 39, 7, 72, 15, 0 },
+                        { 0, 16, 73, 7, 37, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 } },
+               .odd = { { 0, 16, 72, 7, 38, 2, 0 },
+                        { 0, 5, 50, 7, 64, 9, 0 },
+                        { 1, 25, 75, 7, 26, 1, 0 },
+                        { 0, 8, 63, 7, 52, 5, 0 },
+                        { 0, 2, 36, 7, 73, 17, 0 },
+                        { 0, 15, 70, 7, 40, 3, 0 },
+                        { 0, 4, 48, 7, 66, 10, 0 },
+                        { 1, 23, 75, 7, 28, 1, 0 },
+                        { 0, 8, 60, 7, 54, 6, 0 },
+                        { 0, 2, 34, 7, 73, 18, 1 },
+                        { 0, 13, 70, 7, 42, 3, 0 },
+                        { 0, 4, 46, 7, 67, 11, 0 },
+                        { 1, 21, 75, 7, 30, 1, 0 },
+                        { 0, 7, 59, 7, 56, 6, 0 },
+                        { 0, 2, 32, 7, 73, 20, 1 },
+                        { 0, 12, 69, 7, 44, 3, 0 },
+                        { 0, 3, 44, 7, 69, 12, 0 },
+                        { 1, 20, 73, 7, 32, 2, 0 },
+                        { 0, 6, 56, 7, 59, 7, 0 },
+                        { 0, 1, 30, 7, 75, 21, 1 },
+                        { 0, 11, 67, 7, 46, 4, 0 },
+                        { 0, 3, 42, 7, 70, 13, 0 },
+                        { 1, 18, 73, 7, 34, 2, 0 },
+                        { 0, 6, 54, 7, 60, 8, 0 },
+                        { 0, 1, 28, 7, 75, 23, 1 },
+                        { 0, 10, 66, 7, 48, 4, 0 },
+                        { 0, 3, 40, 7, 70, 15, 0 },
+                        { 0, 17, 73, 7, 36, 2, 0 },
+                        { 0, 5, 52, 7, 63, 8, 0 },
+                        { 0, 1, 26, 7, 75, 25, 1 },
+                        { 0, 9, 64, 7, 50, 5, 0 },
+                        { 0, 2, 38, 7, 72, 16, 0 } } },
+       .ptrn_arr = { { 0x24921249, 0x92484924, 0x49212490, 0x24849242,
+                        0x92124909, 0x48492424, 0x249092 } },
+       .sample_patrn_length = 218,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 78) = 0.290909 */
+       .hor_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 8, 61, 7, 53, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 12, 67, 7, 45, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 0, 17, 72, 7, 37, 2, 0 },
+                        { 0, 5, 49, 7, 64, 10, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 10, 64, 7, 49, 5, 0 },
+                        { 0, 2, 37, 7, 72, 17, 0 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 45, 7, 67, 12, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 53, 7, 61, 8, 0 } },
+               .odd = { { 0, 15, 71, 7, 39, 3, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 21, 73, 7, 31, 2, 0 },
+                        { 0, 6, 55, 7, 59, 8, 0 },
+                        { 0, 1, 28, 7, 74, 24, 1 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 },
+                        { 1, 24, 74, 7, 28, 1, 0 },
+                        { 0, 8, 59, 7, 55, 6, 0 },
+                        { 0, 2, 31, 7, 73, 21, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 3, 39, 7, 71, 15, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 8, 61, 7, 53, 6, 0 },
+                        { 0, 2, 33, 7, 73, 19, 1 },
+                        { 0, 12, 67, 7, 45, 4, 0 },
+                        { 0, 3, 41, 7, 70, 14, 0 },
+                        { 0, 17, 72, 7, 37, 2, 0 },
+                        { 0, 5, 49, 7, 64, 10, 0 },
+                        { 1, 22, 75, 7, 29, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 29, 7, 75, 22, 1 },
+                        { 0, 10, 64, 7, 49, 5, 0 },
+                        { 0, 2, 37, 7, 72, 17, 0 },
+                        { 0, 14, 70, 7, 41, 3, 0 },
+                        { 0, 4, 45, 7, 67, 12, 0 },
+                        { 1, 19, 73, 7, 33, 2, 0 },
+                        { 0, 6, 53, 7, 61, 8, 0 } },
+               .odd = { { 0, 15, 71, 7, 39, 3, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 21, 73, 7, 31, 2, 0 },
+                        { 0, 6, 55, 7, 59, 8, 0 },
+                        { 0, 1, 28, 7, 74, 24, 1 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 },
+                        { 1, 24, 74, 7, 28, 1, 0 },
+                        { 0, 8, 59, 7, 55, 6, 0 },
+                        { 0, 2, 31, 7, 73, 21, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 3, 39, 7, 71, 15, 0 } } },
+       .ptrn_arr = { { 0x24921249, 0x12490924, 0x9248492, 0x249 } },
+       .sample_patrn_length = 110,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 79) = 0.288288 */
+       .hor_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 8, 59, 7, 55, 6, 0 },
+                        { 0, 1, 30, 7, 73, 23, 1 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 33, 7, 72, 20, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 2, 37, 7, 71, 17, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 },
+                        { 0, 16, 70, 7, 39, 3, 0 },
+                        { 0, 4, 45, 7, 67, 12, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 49, 7, 64, 10, 0 },
+                        { 1, 21, 73, 7, 31, 2, 0 },
+                        { 0, 6, 53, 7, 60, 9, 0 },
+                        { 1, 24, 74, 7, 28, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 28, 7, 74, 24, 1 },
+                        { 0, 9, 60, 7, 53, 6, 0 },
+                        { 0, 2, 31, 7, 73, 21, 1 },
+                        { 0, 10, 64, 7, 49, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 12, 67, 7, 45, 4, 0 },
+                        { 0, 3, 39, 7, 70, 16, 0 },
+                        { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 17, 71, 7, 37, 2, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 20, 72, 7, 33, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 },
+                        { 1, 23, 73, 7, 30, 1, 0 },
+                        { 0, 6, 55, 7, 59, 8, 0 } },
+               .odd = { { 0, 15, 70, 7, 40, 3, 0 },
+                        { 0, 4, 44, 7, 67, 13, 0 },
+                        { 1, 18, 71, 7, 36, 2, 0 },
+                        { 0, 4, 48, 7, 65, 11, 0 },
+                        { 1, 20, 73, 7, 32, 2, 0 },
+                        { 0, 6, 52, 7, 61, 9, 0 },
+                        { 1, 24, 73, 7, 29, 1, 0 },
+                        { 0, 7, 56, 7, 58, 7, 0 },
+                        { 0, 1, 27, 7, 74, 25, 1 },
+                        { 0, 8, 60, 7, 54, 6, 0 },
+                        { 0, 2, 30, 7, 73, 22, 1 },
+                        { 0, 10, 63, 7, 50, 5, 0 },
+                        { 0, 2, 34, 7, 72, 19, 1 },
+                        { 0, 12, 66, 7, 46, 4, 0 },
+                        { 0, 3, 38, 7, 71, 16, 0 },
+                        { 0, 14, 69, 7, 42, 3, 0 },
+                        { 0, 3, 42, 7, 69, 14, 0 },
+                        { 0, 16, 71, 7, 38, 3, 0 },
+                        { 0, 4, 46, 7, 66, 12, 0 },
+                        { 1, 19, 72, 7, 34, 2, 0 },
+                        { 0, 5, 50, 7, 63, 10, 0 },
+                        { 1, 22, 73, 7, 30, 2, 0 },
+                        { 0, 6, 54, 7, 60, 8, 0 },
+                        { 1, 25, 74, 7, 27, 1, 0 },
+                        { 0, 7, 58, 7, 56, 7, 0 },
+                        { 0, 1, 29, 7, 73, 24, 1 },
+                        { 0, 9, 61, 7, 52, 6, 0 },
+                        { 0, 2, 32, 7, 73, 20, 1 },
+                        { 0, 11, 65, 7, 48, 4, 0 },
+                        { 0, 2, 36, 7, 71, 18, 1 },
+                        { 0, 13, 67, 7, 44, 4, 0 },
+                        { 0, 3, 40, 7, 70, 15, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 8, 59, 7, 55, 6, 0 },
+                        { 0, 1, 30, 7, 73, 23, 1 },
+                        { 0, 9, 63, 7, 51, 5, 0 },
+                        { 0, 2, 33, 7, 72, 20, 1 },
+                        { 0, 11, 66, 7, 47, 4, 0 },
+                        { 0, 2, 37, 7, 71, 17, 1 },
+                        { 0, 13, 69, 7, 43, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 },
+                        { 0, 16, 70, 7, 39, 3, 0 },
+                        { 0, 4, 45, 7, 67, 12, 0 },
+                        { 1, 18, 72, 7, 35, 2, 0 },
+                        { 0, 5, 49, 7, 64, 10, 0 },
+                        { 1, 21, 73, 7, 31, 2, 0 },
+                        { 0, 6, 53, 7, 60, 9, 0 },
+                        { 1, 24, 74, 7, 28, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 },
+                        { 0, 1, 28, 7, 74, 24, 1 },
+                        { 0, 9, 60, 7, 53, 6, 0 },
+                        { 0, 2, 31, 7, 73, 21, 1 },
+                        { 0, 10, 64, 7, 49, 5, 0 },
+                        { 0, 2, 35, 7, 72, 18, 1 },
+                        { 0, 12, 67, 7, 45, 4, 0 },
+                        { 0, 3, 39, 7, 70, 16, 0 },
+                        { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 43, 7, 69, 13, 0 },
+                        { 1, 17, 71, 7, 37, 2, 0 },
+                        { 0, 4, 47, 7, 66, 11, 0 },
+                        { 1, 20, 72, 7, 33, 2, 0 },
+                        { 0, 5, 51, 7, 63, 9, 0 },
+                        { 1, 23, 73, 7, 30, 1, 0 },
+                        { 0, 6, 55, 7, 59, 8, 0 } },
+               .odd = { { 0, 15, 70, 7, 40, 3, 0 },
+                        { 0, 4, 44, 7, 67, 13, 0 },
+                        { 1, 18, 71, 7, 36, 2, 0 },
+                        { 0, 4, 48, 7, 65, 11, 0 },
+                        { 1, 20, 73, 7, 32, 2, 0 },
+                        { 0, 6, 52, 7, 61, 9, 0 },
+                        { 1, 24, 73, 7, 29, 1, 0 },
+                        { 0, 7, 56, 7, 58, 7, 0 },
+                        { 0, 1, 27, 7, 74, 25, 1 },
+                        { 0, 8, 60, 7, 54, 6, 0 },
+                        { 0, 2, 30, 7, 73, 22, 1 },
+                        { 0, 10, 63, 7, 50, 5, 0 },
+                        { 0, 2, 34, 7, 72, 19, 1 },
+                        { 0, 12, 66, 7, 46, 4, 0 },
+                        { 0, 3, 38, 7, 71, 16, 0 },
+                        { 0, 14, 69, 7, 42, 3, 0 },
+                        { 0, 3, 42, 7, 69, 14, 0 },
+                        { 0, 16, 71, 7, 38, 3, 0 },
+                        { 0, 4, 46, 7, 66, 12, 0 },
+                        { 1, 19, 72, 7, 34, 2, 0 },
+                        { 0, 5, 50, 7, 63, 10, 0 },
+                        { 1, 22, 73, 7, 30, 2, 0 },
+                        { 0, 6, 54, 7, 60, 8, 0 },
+                        { 1, 25, 74, 7, 27, 1, 0 },
+                        { 0, 7, 58, 7, 56, 7, 0 },
+                        { 0, 1, 29, 7, 73, 24, 1 },
+                        { 0, 9, 61, 7, 52, 6, 0 },
+                        { 0, 2, 32, 7, 73, 20, 1 },
+                        { 0, 11, 65, 7, 48, 4, 0 },
+                        { 0, 2, 36, 7, 71, 18, 1 },
+                        { 0, 13, 67, 7, 44, 4, 0 },
+                        { 0, 3, 40, 7, 70, 15, 0 } } },
+       .ptrn_arr = { { 0x84921249, 0x42492124, 0x24249092, 0x92124909,
+                        0x49212484, 0x24909248, 0x2490924 } },
+       .sample_patrn_length = 222,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 80) = 0.285714 */
+       .hor_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 } },
+               .odd = { { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 26, 74, 7, 26, 1, 0 },
+                        { 0, 7, 57, 7, 57, 7, 0 } },
+               .odd = { { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 } } },
+       .ptrn_arr = { { 0x249 } },
+       .sample_patrn_length = 14,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 81) = 0.283186 */
+       .hor_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 7, 54, 7, 59, 8, 0 },
+                        { 1, 23, 72, 7, 30, 2, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 20, 71, 7, 34, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 18, 69, 7, 37, 3, 0 },
+                        { 0, 4, 43, 7, 67, 14, 0 },
+                        { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 39, 7, 69, 16, 1 },
+                        { 0, 13, 66, 7, 45, 4, 0 },
+                        { 0, 2, 35, 7, 71, 19, 1 },
+                        { 0, 11, 63, 7, 49, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 9, 60, 7, 53, 6, 0 },
+                        { 0, 1, 28, 7, 73, 25, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 25, 73, 7, 28, 1, 0 },
+                        { 0, 6, 53, 7, 60, 9, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 49, 7, 63, 11, 0 },
+                        { 1, 19, 71, 7, 35, 2, 0 },
+                        { 0, 4, 45, 7, 66, 13, 0 },
+                        { 1, 16, 69, 7, 39, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 },
+                        { 0, 14, 67, 7, 43, 4, 0 },
+                        { 0, 3, 37, 7, 69, 18, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 34, 7, 71, 20, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 0, 2, 30, 7, 72, 23, 1 },
+                        { 0, 8, 59, 7, 54, 7, 0 } },
+               .odd = { { 0, 15, 67, 7, 42, 4, 0 },
+                        { 0, 3, 38, 7, 69, 17, 1 },
+                        { 0, 12, 66, 7, 46, 4, 0 },
+                        { 0, 2, 34, 7, 71, 20, 1 },
+                        { 0, 10, 63, 7, 50, 5, 0 },
+                        { 0, 2, 31, 7, 71, 23, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 0, 1, 27, 7, 73, 26, 1 },
+                        { 0, 7, 55, 7, 58, 8, 0 },
+                        { 1, 24, 72, 7, 29, 2, 0 },
+                        { 0, 6, 52, 7, 60, 10, 0 },
+                        { 1, 21, 71, 7, 33, 2, 0 },
+                        { 0, 5, 48, 7, 64, 11, 0 },
+                        { 1, 18, 70, 7, 36, 3, 0 },
+                        { 0, 4, 44, 7, 67, 13, 0 },
+                        { 0, 16, 69, 7, 40, 3, 0 },
+                        { 0, 3, 40, 7, 69, 16, 0 },
+                        { 0, 13, 67, 7, 44, 4, 0 },
+                        { 0, 3, 36, 7, 70, 18, 1 },
+                        { 0, 11, 64, 7, 48, 5, 0 },
+                        { 0, 2, 33, 7, 71, 21, 1 },
+                        { 0, 10, 60, 7, 52, 6, 0 },
+                        { 0, 2, 29, 7, 72, 24, 1 },
+                        { 0, 8, 58, 7, 55, 7, 0 },
+                        { 1, 26, 73, 7, 27, 1, 0 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 23, 71, 7, 31, 2, 0 },
+                        { 0, 5, 50, 7, 63, 10, 0 },
+                        { 1, 20, 71, 7, 34, 2, 0 },
+                        { 0, 4, 46, 7, 66, 12, 0 },
+                        { 1, 17, 69, 7, 38, 3, 0 },
+                        { 0, 4, 42, 7, 67, 15, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 7, 54, 7, 59, 8, 0 },
+                        { 1, 23, 72, 7, 30, 2, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 20, 71, 7, 34, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 18, 69, 7, 37, 3, 0 },
+                        { 0, 4, 43, 7, 67, 14, 0 },
+                        { 0, 15, 69, 7, 41, 3, 0 },
+                        { 0, 3, 39, 7, 69, 16, 1 },
+                        { 0, 13, 66, 7, 45, 4, 0 },
+                        { 0, 2, 35, 7, 71, 19, 1 },
+                        { 0, 11, 63, 7, 49, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 9, 60, 7, 53, 6, 0 },
+                        { 0, 1, 28, 7, 73, 25, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 25, 73, 7, 28, 1, 0 },
+                        { 0, 6, 53, 7, 60, 9, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 49, 7, 63, 11, 0 },
+                        { 1, 19, 71, 7, 35, 2, 0 },
+                        { 0, 4, 45, 7, 66, 13, 0 },
+                        { 1, 16, 69, 7, 39, 3, 0 },
+                        { 0, 3, 41, 7, 69, 15, 0 },
+                        { 0, 14, 67, 7, 43, 4, 0 },
+                        { 0, 3, 37, 7, 69, 18, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 34, 7, 71, 20, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 0, 2, 30, 7, 72, 23, 1 },
+                        { 0, 8, 59, 7, 54, 7, 0 } },
+               .odd = { { 0, 15, 67, 7, 42, 4, 0 },
+                        { 0, 3, 38, 7, 69, 17, 1 },
+                        { 0, 12, 66, 7, 46, 4, 0 },
+                        { 0, 2, 34, 7, 71, 20, 1 },
+                        { 0, 10, 63, 7, 50, 5, 0 },
+                        { 0, 2, 31, 7, 71, 23, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 0, 1, 27, 7, 73, 26, 1 },
+                        { 0, 7, 55, 7, 58, 8, 0 },
+                        { 1, 24, 72, 7, 29, 2, 0 },
+                        { 0, 6, 52, 7, 60, 10, 0 },
+                        { 1, 21, 71, 7, 33, 2, 0 },
+                        { 0, 5, 48, 7, 64, 11, 0 },
+                        { 1, 18, 70, 7, 36, 3, 0 },
+                        { 0, 4, 44, 7, 67, 13, 0 },
+                        { 0, 16, 69, 7, 40, 3, 0 },
+                        { 0, 3, 40, 7, 69, 16, 0 },
+                        { 0, 13, 67, 7, 44, 4, 0 },
+                        { 0, 3, 36, 7, 70, 18, 1 },
+                        { 0, 11, 64, 7, 48, 5, 0 },
+                        { 0, 2, 33, 7, 71, 21, 1 },
+                        { 0, 10, 60, 7, 52, 6, 0 },
+                        { 0, 2, 29, 7, 72, 24, 1 },
+                        { 0, 8, 58, 7, 55, 7, 0 },
+                        { 1, 26, 73, 7, 27, 1, 0 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 23, 71, 7, 31, 2, 0 },
+                        { 0, 5, 50, 7, 63, 10, 0 },
+                        { 1, 20, 71, 7, 34, 2, 0 },
+                        { 0, 4, 46, 7, 66, 12, 0 },
+                        { 1, 17, 69, 7, 38, 3, 0 },
+                        { 0, 4, 42, 7, 67, 15, 0 } } },
+       .ptrn_arr = { { 0x90924249, 0x49092424, 0x84921248, 0x49092124,
+                        0x24909242, 0x48492124, 0x24849212 } },
+       .sample_patrn_length = 226,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 82) = 0.280702 */
+       .hor_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 6, 52, 7, 61, 9, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 45, 7, 66, 13, 0 },
+                        { 0, 15, 68, 7, 41, 4, 0 },
+                        { 0, 3, 37, 7, 69, 18, 1 },
+                        { 0, 11, 63, 7, 49, 5, 0 },
+                        { 0, 2, 30, 7, 71, 24, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 24, 71, 7, 30, 2, 0 },
+                        { 0, 5, 49, 7, 63, 11, 0 },
+                        { 1, 18, 69, 7, 37, 3, 0 },
+                        { 0, 4, 41, 7, 68, 15, 0 },
+                        { 0, 13, 66, 7, 45, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 9, 61, 7, 52, 6, 0 } },
+               .odd = { { 0, 14, 67, 7, 43, 4, 0 },
+                        { 0, 3, 36, 7, 69, 19, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 0, 2, 28, 7, 72, 25, 1 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 17, 68, 7, 39, 3, 0 },
+                        { 0, 3, 39, 7, 68, 17, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 1, 25, 72, 7, 28, 2, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 19, 69, 7, 36, 3, 0 },
+                        { 0, 4, 43, 7, 67, 14, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 6, 52, 7, 61, 9, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 45, 7, 66, 13, 0 },
+                        { 0, 15, 68, 7, 41, 4, 0 },
+                        { 0, 3, 37, 7, 69, 18, 1 },
+                        { 0, 11, 63, 7, 49, 5, 0 },
+                        { 0, 2, 30, 7, 71, 24, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 24, 71, 7, 30, 2, 0 },
+                        { 0, 5, 49, 7, 63, 11, 0 },
+                        { 1, 18, 69, 7, 37, 3, 0 },
+                        { 0, 4, 41, 7, 68, 15, 0 },
+                        { 0, 13, 66, 7, 45, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 9, 61, 7, 52, 6, 0 } },
+               .odd = { { 0, 14, 67, 7, 43, 4, 0 },
+                        { 0, 3, 36, 7, 69, 19, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 0, 2, 28, 7, 72, 25, 1 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 17, 68, 7, 39, 3, 0 },
+                        { 0, 3, 39, 7, 68, 17, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 1, 25, 72, 7, 28, 2, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 19, 69, 7, 36, 3, 0 },
+                        { 0, 4, 43, 7, 67, 14, 0 } } },
+       .ptrn_arr = { { 0x90924249, 0x9212484, 0x92124249, 0x2484 } },
+       .sample_patrn_length = 114,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 83) = 0.278261 */
+       .hor_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 39, 7, 68, 17, 1 },
+                        { 0, 11, 62, 7, 49, 6, 0 },
+                        { 0, 2, 29, 7, 71, 25, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 19, 69, 7, 36, 3, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 30, 7, 71, 24, 1 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 43, 7, 66, 15, 0 },
+                        { 0, 13, 65, 7, 45, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 45, 7, 65, 13, 0 },
+                        { 0, 15, 66, 7, 43, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 1, 24, 71, 7, 30, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 3, 36, 7, 69, 19, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 25, 71, 7, 29, 2, 0 },
+                        { 0, 6, 49, 7, 62, 11, 0 },
+                        { 1, 17, 68, 7, 39, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 } },
+               .odd = { { 0, 14, 66, 7, 44, 4, 0 },
+                        { 0, 2, 33, 7, 70, 22, 1 },
+                        { 0, 8, 57, 7, 55, 8, 0 },
+                        { 1, 23, 71, 7, 31, 2, 0 },
+                        { 0, 5, 46, 7, 64, 13, 0 },
+                        { 0, 15, 67, 7, 42, 4, 0 },
+                        { 0, 3, 35, 7, 69, 20, 1 },
+                        { 0, 9, 59, 7, 53, 7, 0 },
+                        { 1, 25, 71, 7, 29, 2, 0 },
+                        { 0, 5, 48, 7, 63, 12, 0 },
+                        { 1, 16, 68, 7, 40, 3, 0 },
+                        { 0, 3, 37, 7, 68, 19, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 1, 26, 71, 7, 28, 2, 0 },
+                        { 0, 6, 50, 7, 61, 11, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 11, 61, 7, 50, 6, 0 },
+                        { 0, 2, 28, 7, 71, 26, 1 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 19, 68, 7, 37, 3, 0 },
+                        { 0, 3, 40, 7, 68, 16, 1 },
+                        { 0, 12, 63, 7, 48, 5, 0 },
+                        { 0, 2, 29, 7, 71, 25, 1 },
+                        { 0, 7, 53, 7, 59, 9, 0 },
+                        { 1, 20, 69, 7, 35, 3, 0 },
+                        { 0, 4, 42, 7, 67, 15, 0 },
+                        { 0, 13, 64, 7, 46, 5, 0 },
+                        { 0, 2, 31, 7, 71, 23, 1 },
+                        { 0, 8, 55, 7, 57, 8, 0 },
+                        { 1, 22, 70, 7, 33, 2, 0 },
+                        { 0, 4, 44, 7, 66, 14, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 1, 27, 72, 7, 27, 1, 0 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 39, 7, 68, 17, 1 },
+                        { 0, 11, 62, 7, 49, 6, 0 },
+                        { 0, 2, 29, 7, 71, 25, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 19, 69, 7, 36, 3, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 12, 64, 7, 47, 5, 0 },
+                        { 0, 2, 30, 7, 71, 24, 1 },
+                        { 0, 7, 54, 7, 58, 9, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 43, 7, 66, 15, 0 },
+                        { 0, 13, 65, 7, 45, 5, 0 },
+                        { 0, 2, 32, 7, 71, 22, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 22, 71, 7, 32, 2, 0 },
+                        { 0, 5, 45, 7, 65, 13, 0 },
+                        { 0, 15, 66, 7, 43, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 9, 58, 7, 54, 7, 0 },
+                        { 1, 24, 71, 7, 30, 2, 0 },
+                        { 0, 5, 47, 7, 64, 12, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 3, 36, 7, 69, 19, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 25, 71, 7, 29, 2, 0 },
+                        { 0, 6, 49, 7, 62, 11, 0 },
+                        { 1, 17, 68, 7, 39, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 } },
+               .odd = { { 0, 14, 66, 7, 44, 4, 0 },
+                        { 0, 2, 33, 7, 70, 22, 1 },
+                        { 0, 8, 57, 7, 55, 8, 0 },
+                        { 1, 23, 71, 7, 31, 2, 0 },
+                        { 0, 5, 46, 7, 64, 13, 0 },
+                        { 0, 15, 67, 7, 42, 4, 0 },
+                        { 0, 3, 35, 7, 69, 20, 1 },
+                        { 0, 9, 59, 7, 53, 7, 0 },
+                        { 1, 25, 71, 7, 29, 2, 0 },
+                        { 0, 5, 48, 7, 63, 12, 0 },
+                        { 1, 16, 68, 7, 40, 3, 0 },
+                        { 0, 3, 37, 7, 68, 19, 1 },
+                        { 0, 10, 61, 7, 51, 6, 0 },
+                        { 1, 26, 71, 7, 28, 2, 0 },
+                        { 0, 6, 50, 7, 61, 11, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 11, 61, 7, 50, 6, 0 },
+                        { 0, 2, 28, 7, 71, 26, 1 },
+                        { 0, 6, 51, 7, 61, 10, 0 },
+                        { 1, 19, 68, 7, 37, 3, 0 },
+                        { 0, 3, 40, 7, 68, 16, 1 },
+                        { 0, 12, 63, 7, 48, 5, 0 },
+                        { 0, 2, 29, 7, 71, 25, 1 },
+                        { 0, 7, 53, 7, 59, 9, 0 },
+                        { 1, 20, 69, 7, 35, 3, 0 },
+                        { 0, 4, 42, 7, 67, 15, 0 },
+                        { 0, 13, 64, 7, 46, 5, 0 },
+                        { 0, 2, 31, 7, 71, 23, 1 },
+                        { 0, 8, 55, 7, 57, 8, 0 },
+                        { 1, 22, 70, 7, 33, 2, 0 },
+                        { 0, 4, 44, 7, 66, 14, 0 } } },
+       .ptrn_arr = { { 0x92124249, 0x21242484, 0x12424849, 0x24248492,
+                        0x42484909, 0x24849092, 0x48490924, 0x2 } },
+       .sample_patrn_length = 230,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 84) = 0.275862 */
+       .hor_phase_arr = {
+               .even = { { 2, 27, 70, 7, 27, 2, 0 },
+                        { 0, 6, 49, 7, 61, 12, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 12, 61, 7, 49, 6, 0 } },
+               .odd = { { 0, 14, 64, 7, 45, 5, 0 },
+                        { 0, 2, 31, 7, 70, 24, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 24, 70, 7, 31, 2, 0 },
+                        { 0, 5, 45, 7, 64, 14, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 27, 70, 7, 27, 2, 0 },
+                        { 0, 6, 49, 7, 61, 12, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 34, 7, 70, 21, 1 },
+                        { 0, 8, 56, 7, 56, 8, 0 },
+                        { 1, 21, 70, 7, 34, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 12, 61, 7, 49, 6, 0 } },
+               .odd = { { 0, 14, 64, 7, 45, 5, 0 },
+                        { 0, 2, 31, 7, 70, 24, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 18, 68, 7, 38, 3, 0 },
+                        { 0, 3, 38, 7, 68, 18, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 24, 70, 7, 31, 2, 0 },
+                        { 0, 5, 45, 7, 64, 14, 0 } } },
+       .ptrn_arr = { { 0x92124249, 0x248490 } },
+       .sample_patrn_length = 58,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 85) = 0.273504 */
+       .hor_phase_arr = {
+               .even = { { 2, 27, 70, 7, 27, 2, 0 },
+                        { 0, 5, 47, 7, 63, 13, 0 },
+                        { 0, 14, 64, 7, 45, 5, 0 },
+                        { 0, 2, 29, 7, 70, 26, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 15, 65, 7, 43, 4, 0 },
+                        { 0, 2, 31, 7, 70, 24, 1 },
+                        { 0, 6, 50, 7, 61, 11, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 32, 7, 70, 23, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 17, 67, 7, 39, 4, 0 },
+                        { 0, 3, 34, 7, 69, 21, 1 },
+                        { 0, 8, 54, 7, 57, 9, 0 },
+                        { 1, 19, 67, 7, 38, 3, 0 },
+                        { 0, 3, 36, 7, 68, 20, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 20, 68, 7, 36, 3, 0 },
+                        { 0, 3, 38, 7, 67, 19, 1 },
+                        { 0, 9, 57, 7, 54, 8, 0 },
+                        { 1, 21, 69, 7, 34, 3, 0 },
+                        { 0, 4, 39, 7, 67, 17, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 23, 70, 7, 32, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 11, 61, 7, 50, 6, 0 },
+                        { 1, 24, 70, 7, 31, 2, 0 },
+                        { 0, 4, 43, 7, 65, 15, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 26, 70, 7, 29, 2, 0 },
+                        { 0, 5, 45, 7, 64, 14, 0 },
+                        { 0, 13, 63, 7, 47, 5, 0 } },
+               .odd = { { 0, 13, 64, 7, 46, 5, 0 },
+                        { 0, 2, 28, 7, 69, 27, 2 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 14, 64, 7, 44, 5, 0 },
+                        { 0, 2, 30, 7, 70, 25, 1 },
+                        { 0, 6, 49, 7, 62, 11, 0 },
+                        { 1, 16, 65, 7, 42, 4, 0 },
+                        { 0, 2, 32, 7, 69, 24, 1 },
+                        { 0, 7, 51, 7, 59, 11, 0 },
+                        { 1, 17, 66, 7, 40, 4, 0 },
+                        { 0, 2, 33, 7, 70, 22, 1 },
+                        { 0, 7, 53, 7, 58, 10, 0 },
+                        { 1, 18, 67, 7, 39, 3, 0 },
+                        { 0, 3, 35, 7, 68, 21, 1 },
+                        { 0, 8, 54, 7, 57, 9, 0 },
+                        { 1, 19, 68, 7, 37, 3, 0 },
+                        { 0, 3, 37, 7, 68, 19, 1 },
+                        { 0, 9, 57, 7, 54, 8, 0 },
+                        { 1, 21, 68, 7, 35, 3, 0 },
+                        { 0, 3, 39, 7, 67, 18, 1 },
+                        { 0, 10, 58, 7, 53, 7, 0 },
+                        { 1, 22, 70, 7, 33, 2, 0 },
+                        { 0, 4, 40, 7, 66, 17, 1 },
+                        { 0, 11, 59, 7, 51, 7, 0 },
+                        { 1, 24, 69, 7, 32, 2, 0 },
+                        { 0, 4, 42, 7, 65, 16, 1 },
+                        { 0, 11, 62, 7, 49, 6, 0 },
+                        { 1, 25, 70, 7, 30, 2, 0 },
+                        { 0, 5, 44, 7, 64, 14, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 2, 27, 69, 7, 28, 2, 0 },
+                        { 0, 5, 46, 7, 64, 13, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 27, 70, 7, 27, 2, 0 },
+                        { 0, 5, 47, 7, 63, 13, 0 },
+                        { 0, 14, 64, 7, 45, 5, 0 },
+                        { 0, 2, 29, 7, 70, 26, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 15, 65, 7, 43, 4, 0 },
+                        { 0, 2, 31, 7, 70, 24, 1 },
+                        { 0, 6, 50, 7, 61, 11, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 32, 7, 70, 23, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 17, 67, 7, 39, 4, 0 },
+                        { 0, 3, 34, 7, 69, 21, 1 },
+                        { 0, 8, 54, 7, 57, 9, 0 },
+                        { 1, 19, 67, 7, 38, 3, 0 },
+                        { 0, 3, 36, 7, 68, 20, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 20, 68, 7, 36, 3, 0 },
+                        { 0, 3, 38, 7, 67, 19, 1 },
+                        { 0, 9, 57, 7, 54, 8, 0 },
+                        { 1, 21, 69, 7, 34, 3, 0 },
+                        { 0, 4, 39, 7, 67, 17, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 23, 70, 7, 32, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 11, 61, 7, 50, 6, 0 },
+                        { 1, 24, 70, 7, 31, 2, 0 },
+                        { 0, 4, 43, 7, 65, 15, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 26, 70, 7, 29, 2, 0 },
+                        { 0, 5, 45, 7, 64, 14, 0 },
+                        { 0, 13, 63, 7, 47, 5, 0 } },
+               .odd = { { 0, 13, 64, 7, 46, 5, 0 },
+                        { 0, 2, 28, 7, 69, 27, 2 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 14, 64, 7, 44, 5, 0 },
+                        { 0, 2, 30, 7, 70, 25, 1 },
+                        { 0, 6, 49, 7, 62, 11, 0 },
+                        { 1, 16, 65, 7, 42, 4, 0 },
+                        { 0, 2, 32, 7, 69, 24, 1 },
+                        { 0, 7, 51, 7, 59, 11, 0 },
+                        { 1, 17, 66, 7, 40, 4, 0 },
+                        { 0, 2, 33, 7, 70, 22, 1 },
+                        { 0, 7, 53, 7, 58, 10, 0 },
+                        { 1, 18, 67, 7, 39, 3, 0 },
+                        { 0, 3, 35, 7, 68, 21, 1 },
+                        { 0, 8, 54, 7, 57, 9, 0 },
+                        { 1, 19, 68, 7, 37, 3, 0 },
+                        { 0, 3, 37, 7, 68, 19, 1 },
+                        { 0, 9, 57, 7, 54, 8, 0 },
+                        { 1, 21, 68, 7, 35, 3, 0 },
+                        { 0, 3, 39, 7, 67, 18, 1 },
+                        { 0, 10, 58, 7, 53, 7, 0 },
+                        { 1, 22, 70, 7, 33, 2, 0 },
+                        { 0, 4, 40, 7, 66, 17, 1 },
+                        { 0, 11, 59, 7, 51, 7, 0 },
+                        { 1, 24, 69, 7, 32, 2, 0 },
+                        { 0, 4, 42, 7, 65, 16, 1 },
+                        { 0, 11, 62, 7, 49, 6, 0 },
+                        { 1, 25, 70, 7, 30, 2, 0 },
+                        { 0, 5, 44, 7, 64, 14, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 2, 27, 69, 7, 28, 2, 0 },
+                        { 0, 5, 46, 7, 64, 13, 0 } } },
+       .ptrn_arr = { { 0x92124249, 0x24248490, 0x48490921, 0x90921242,
+                        0x21242484, 0x42484909, 0x84909212, 0x24 } },
+       .sample_patrn_length = 234,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 86) = 0.271186 */
+       .hor_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 5, 45, 7, 63, 14, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 25, 69, 7, 31, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 38, 7, 67, 19, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 19, 67, 7, 38, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 31, 7, 69, 25, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 14, 63, 7, 45, 5, 0 } },
+               .odd = { { 0, 13, 62, 7, 47, 6, 0 },
+                        { 2, 26, 69, 7, 29, 2, 0 },
+                        { 0, 5, 43, 7, 64, 15, 1 },
+                        { 0, 11, 60, 7, 50, 7, 0 },
+                        { 1, 23, 69, 7, 33, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 10, 57, 7, 53, 8, 0 },
+                        { 1, 20, 68, 7, 36, 3, 0 },
+                        { 0, 3, 36, 7, 68, 20, 1 },
+                        { 0, 8, 53, 7, 57, 10, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 0, 2, 33, 7, 69, 23, 1 },
+                        { 0, 7, 50, 7, 60, 11, 0 },
+                        { 1, 15, 64, 7, 43, 5, 0 },
+                        { 0, 2, 29, 7, 69, 26, 2 },
+                        { 0, 6, 47, 7, 62, 13, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 5, 45, 7, 63, 14, 1 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 25, 69, 7, 31, 2, 0 },
+                        { 0, 4, 41, 7, 66, 16, 1 },
+                        { 0, 10, 59, 7, 52, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 38, 7, 67, 19, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 19, 67, 7, 38, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 52, 7, 59, 10, 0 },
+                        { 1, 16, 66, 7, 41, 4, 0 },
+                        { 0, 2, 31, 7, 69, 25, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 1, 14, 63, 7, 45, 5, 0 } },
+               .odd = { { 0, 13, 62, 7, 47, 6, 0 },
+                        { 2, 26, 69, 7, 29, 2, 0 },
+                        { 0, 5, 43, 7, 64, 15, 1 },
+                        { 0, 11, 60, 7, 50, 7, 0 },
+                        { 1, 23, 69, 7, 33, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 10, 57, 7, 53, 8, 0 },
+                        { 1, 20, 68, 7, 36, 3, 0 },
+                        { 0, 3, 36, 7, 68, 20, 1 },
+                        { 0, 8, 53, 7, 57, 10, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 0, 2, 33, 7, 69, 23, 1 },
+                        { 0, 7, 50, 7, 60, 11, 0 },
+                        { 1, 15, 64, 7, 43, 5, 0 },
+                        { 0, 2, 29, 7, 69, 26, 2 },
+                        { 0, 6, 47, 7, 62, 13, 0 } } },
+       .ptrn_arr = { { 0x12424849, 0x24849092, 0x49092124, 0x24248 } },
+       .sample_patrn_length = 118,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 87) = 0.268908 */
+       .hor_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 11, 57, 7, 52, 8, 0 },
+                        { 1, 21, 67, 7, 36, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 50, 7, 60, 11, 0 },
+                        { 1, 14, 63, 7, 45, 5, 0 },
+                        { 2, 26, 69, 7, 29, 2, 0 },
+                        { 0, 4, 41, 7, 65, 17, 1 },
+                        { 0, 10, 57, 7, 53, 8, 0 },
+                        { 1, 19, 66, 7, 38, 4, 0 },
+                        { 0, 3, 33, 7, 68, 23, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 0, 13, 62, 7, 47, 6, 0 },
+                        { 1, 25, 69, 7, 31, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 0, 2, 31, 7, 69, 25, 1 },
+                        { 0, 6, 47, 7, 62, 13, 0 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 23, 68, 7, 33, 3, 0 },
+                        { 0, 4, 38, 7, 66, 19, 1 },
+                        { 0, 8, 53, 7, 57, 10, 0 },
+                        { 1, 17, 65, 7, 41, 4, 0 },
+                        { 0, 2, 29, 7, 69, 26, 2 },
+                        { 0, 5, 45, 7, 63, 14, 1 },
+                        { 0, 11, 60, 7, 50, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 36, 7, 67, 21, 1 },
+                        { 0, 8, 52, 7, 57, 11, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 } },
+               .odd = { { 0, 13, 62, 7, 47, 6, 0 },
+                        { 1, 24, 69, 7, 32, 2, 0 },
+                        { 0, 4, 39, 7, 65, 19, 1 },
+                        { 0, 9, 54, 7, 56, 9, 0 },
+                        { 1, 17, 66, 7, 40, 4, 0 },
+                        { 0, 2, 30, 7, 69, 25, 2 },
+                        { 0, 5, 46, 7, 62, 14, 1 },
+                        { 0, 12, 60, 7, 49, 7, 0 },
+                        { 1, 23, 67, 7, 34, 3, 0 },
+                        { 0, 3, 37, 7, 67, 20, 1 },
+                        { 0, 8, 52, 7, 58, 10, 0 },
+                        { 1, 16, 64, 7, 42, 5, 0 },
+                        { 0, 2, 29, 7, 68, 27, 2 },
+                        { 0, 5, 44, 7, 63, 15, 1 },
+                        { 0, 11, 59, 7, 51, 7, 0 },
+                        { 1, 21, 68, 7, 35, 3, 0 },
+                        { 0, 3, 35, 7, 68, 21, 1 },
+                        { 0, 7, 51, 7, 59, 11, 0 },
+                        { 1, 15, 63, 7, 44, 5, 0 },
+                        { 2, 27, 68, 7, 29, 2, 0 },
+                        { 0, 5, 42, 7, 64, 16, 1 },
+                        { 0, 10, 58, 7, 52, 8, 0 },
+                        { 1, 20, 67, 7, 37, 3, 0 },
+                        { 0, 3, 34, 7, 67, 23, 1 },
+                        { 0, 7, 49, 7, 60, 12, 0 },
+                        { 1, 14, 62, 7, 46, 5, 0 },
+                        { 2, 25, 69, 7, 30, 2, 0 },
+                        { 0, 4, 40, 7, 66, 17, 1 },
+                        { 0, 9, 56, 7, 54, 9, 0 },
+                        { 1, 19, 65, 7, 39, 4, 0 },
+                        { 0, 2, 32, 7, 69, 24, 1 },
+                        { 0, 6, 47, 7, 62, 13, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 11, 57, 7, 52, 8, 0 },
+                        { 1, 21, 67, 7, 36, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 50, 7, 60, 11, 0 },
+                        { 1, 14, 63, 7, 45, 5, 0 },
+                        { 2, 26, 69, 7, 29, 2, 0 },
+                        { 0, 4, 41, 7, 65, 17, 1 },
+                        { 0, 10, 57, 7, 53, 8, 0 },
+                        { 1, 19, 66, 7, 38, 4, 0 },
+                        { 0, 3, 33, 7, 68, 23, 1 },
+                        { 0, 6, 48, 7, 62, 12, 0 },
+                        { 0, 13, 62, 7, 47, 6, 0 },
+                        { 1, 25, 69, 7, 31, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 0, 2, 31, 7, 69, 25, 1 },
+                        { 0, 6, 47, 7, 62, 13, 0 },
+                        { 0, 12, 62, 7, 48, 6, 0 },
+                        { 1, 23, 68, 7, 33, 3, 0 },
+                        { 0, 4, 38, 7, 66, 19, 1 },
+                        { 0, 8, 53, 7, 57, 10, 0 },
+                        { 1, 17, 65, 7, 41, 4, 0 },
+                        { 0, 2, 29, 7, 69, 26, 2 },
+                        { 0, 5, 45, 7, 63, 14, 1 },
+                        { 0, 11, 60, 7, 50, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 36, 7, 67, 21, 1 },
+                        { 0, 8, 52, 7, 57, 11, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 } },
+               .odd = { { 0, 13, 62, 7, 47, 6, 0 },
+                        { 1, 24, 69, 7, 32, 2, 0 },
+                        { 0, 4, 39, 7, 65, 19, 1 },
+                        { 0, 9, 54, 7, 56, 9, 0 },
+                        { 1, 17, 66, 7, 40, 4, 0 },
+                        { 0, 2, 30, 7, 69, 25, 2 },
+                        { 0, 5, 46, 7, 62, 14, 1 },
+                        { 0, 12, 60, 7, 49, 7, 0 },
+                        { 1, 23, 67, 7, 34, 3, 0 },
+                        { 0, 3, 37, 7, 67, 20, 1 },
+                        { 0, 8, 52, 7, 58, 10, 0 },
+                        { 1, 16, 64, 7, 42, 5, 0 },
+                        { 0, 2, 29, 7, 68, 27, 2 },
+                        { 0, 5, 44, 7, 63, 15, 1 },
+                        { 0, 11, 59, 7, 51, 7, 0 },
+                        { 1, 21, 68, 7, 35, 3, 0 },
+                        { 0, 3, 35, 7, 68, 21, 1 },
+                        { 0, 7, 51, 7, 59, 11, 0 },
+                        { 1, 15, 63, 7, 44, 5, 0 },
+                        { 2, 27, 68, 7, 29, 2, 0 },
+                        { 0, 5, 42, 7, 64, 16, 1 },
+                        { 0, 10, 58, 7, 52, 8, 0 },
+                        { 1, 20, 67, 7, 37, 3, 0 },
+                        { 0, 3, 34, 7, 67, 23, 1 },
+                        { 0, 7, 49, 7, 60, 12, 0 },
+                        { 1, 14, 62, 7, 46, 5, 0 },
+                        { 2, 25, 69, 7, 30, 2, 0 },
+                        { 0, 4, 40, 7, 66, 17, 1 },
+                        { 0, 9, 56, 7, 54, 9, 0 },
+                        { 1, 19, 65, 7, 39, 4, 0 },
+                        { 0, 2, 32, 7, 69, 24, 1 },
+                        { 0, 6, 47, 7, 62, 13, 0 } } },
+       .ptrn_arr = { { 0x12424849, 0x84909092, 0x9212424, 0x42484909,
+                        0x90921212, 0x21242484, 0x48490921, 0x242 } },
+       .sample_patrn_length = 238,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 88) = 0.266667 */
+       .hor_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 41, 7, 65, 17, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 17, 65, 7, 41, 4, 0 } },
+               .odd = { { 0, 13, 60, 7, 48, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 48, 7, 60, 13, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 41, 7, 65, 17, 1 },
+                        { 0, 9, 55, 7, 55, 9, 0 },
+                        { 1, 17, 65, 7, 41, 4, 0 } },
+               .odd = { { 0, 13, 60, 7, 48, 7, 0 },
+                        { 1, 22, 68, 7, 34, 3, 0 },
+                        { 0, 3, 34, 7, 68, 22, 1 },
+                        { 0, 7, 48, 7, 60, 13, 0 } } },
+       .ptrn_arr = { { 0x2424849 } },
+       .sample_patrn_length = 30,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 89) = 0.264463 */
+       .hor_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 8, 51, 7, 58, 11, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 22, 67, 7, 35, 3, 0 },
+                        { 0, 3, 33, 7, 67, 24, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 56, 7, 53, 9, 0 },
+                        { 1, 17, 64, 7, 41, 5, 0 },
+                        { 2, 27, 67, 7, 30, 2, 0 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 50, 7, 59, 12, 0 },
+                        { 0, 13, 60, 7, 48, 7, 0 },
+                        { 1, 21, 67, 7, 36, 3, 0 },
+                        { 0, 3, 31, 7, 67, 25, 2 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 9, 56, 7, 54, 9, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 },
+                        { 2, 25, 67, 7, 31, 3, 0 },
+                        { 0, 3, 36, 7, 67, 21, 1 },
+                        { 0, 7, 48, 7, 60, 13, 0 },
+                        { 0, 12, 59, 7, 50, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 0, 2, 30, 7, 67, 27, 2 },
+                        { 0, 5, 41, 7, 64, 17, 1 },
+                        { 0, 9, 53, 7, 56, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 24, 67, 7, 33, 3, 0 },
+                        { 0, 3, 35, 7, 67, 22, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 11, 58, 7, 51, 8, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 } },
+               .odd = { { 0, 12, 60, 7, 49, 7, 0 },
+                        { 1, 20, 66, 7, 37, 4, 0 },
+                        { 0, 2, 31, 7, 67, 26, 2 },
+                        { 0, 5, 42, 7, 63, 17, 1 },
+                        { 0, 9, 54, 7, 55, 10, 0 },
+                        { 1, 16, 62, 7, 44, 5, 0 },
+                        { 2, 24, 67, 7, 32, 3, 0 },
+                        { 0, 3, 35, 7, 67, 22, 1 },
+                        { 0, 6, 47, 7, 61, 13, 1 },
+                        { 0, 12, 58, 7, 50, 8, 0 },
+                        { 1, 19, 65, 7, 39, 4, 0 },
+                        { 0, 2, 29, 7, 68, 27, 2 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 8, 52, 7, 57, 11, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 23, 67, 7, 34, 3, 0 },
+                        { 0, 3, 34, 7, 67, 23, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 11, 57, 7, 52, 8, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 2, 27, 68, 7, 29, 2, 0 },
+                        { 0, 4, 39, 7, 65, 19, 1 },
+                        { 0, 8, 50, 7, 58, 12, 0 },
+                        { 1, 13, 61, 7, 47, 6, 0 },
+                        { 1, 22, 67, 7, 35, 3, 0 },
+                        { 0, 3, 32, 7, 67, 24, 2 },
+                        { 0, 5, 44, 7, 62, 16, 1 },
+                        { 0, 10, 55, 7, 54, 9, 0 },
+                        { 1, 17, 63, 7, 42, 5, 0 },
+                        { 2, 26, 67, 7, 31, 2, 0 },
+                        { 0, 4, 37, 7, 66, 20, 1 },
+                        { 0, 7, 49, 7, 60, 12, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 8, 51, 7, 58, 11, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 22, 67, 7, 35, 3, 0 },
+                        { 0, 3, 33, 7, 67, 24, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 56, 7, 53, 9, 0 },
+                        { 1, 17, 64, 7, 41, 5, 0 },
+                        { 2, 27, 67, 7, 30, 2, 0 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 50, 7, 59, 12, 0 },
+                        { 0, 13, 60, 7, 48, 7, 0 },
+                        { 1, 21, 67, 7, 36, 3, 0 },
+                        { 0, 3, 31, 7, 67, 25, 2 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 9, 56, 7, 54, 9, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 },
+                        { 2, 25, 67, 7, 31, 3, 0 },
+                        { 0, 3, 36, 7, 67, 21, 1 },
+                        { 0, 7, 48, 7, 60, 13, 0 },
+                        { 0, 12, 59, 7, 50, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 0, 2, 30, 7, 67, 27, 2 },
+                        { 0, 5, 41, 7, 64, 17, 1 },
+                        { 0, 9, 53, 7, 56, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 24, 67, 7, 33, 3, 0 },
+                        { 0, 3, 35, 7, 67, 22, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 11, 58, 7, 51, 8, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 } },
+               .odd = { { 0, 12, 60, 7, 49, 7, 0 },
+                        { 1, 20, 66, 7, 37, 4, 0 },
+                        { 0, 2, 31, 7, 67, 26, 2 },
+                        { 0, 5, 42, 7, 63, 17, 1 },
+                        { 0, 9, 54, 7, 55, 10, 0 },
+                        { 1, 16, 62, 7, 44, 5, 0 },
+                        { 2, 24, 67, 7, 32, 3, 0 },
+                        { 0, 3, 35, 7, 67, 22, 1 },
+                        { 0, 6, 47, 7, 61, 13, 1 },
+                        { 0, 12, 58, 7, 50, 8, 0 },
+                        { 1, 19, 65, 7, 39, 4, 0 },
+                        { 0, 2, 29, 7, 68, 27, 2 },
+                        { 0, 4, 40, 7, 65, 18, 1 },
+                        { 0, 8, 52, 7, 57, 11, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 23, 67, 7, 34, 3, 0 },
+                        { 0, 3, 34, 7, 67, 23, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 11, 57, 7, 52, 8, 0 },
+                        { 1, 18, 65, 7, 40, 4, 0 },
+                        { 2, 27, 68, 7, 29, 2, 0 },
+                        { 0, 4, 39, 7, 65, 19, 1 },
+                        { 0, 8, 50, 7, 58, 12, 0 },
+                        { 1, 13, 61, 7, 47, 6, 0 },
+                        { 1, 22, 67, 7, 35, 3, 0 },
+                        { 0, 3, 32, 7, 67, 24, 2 },
+                        { 0, 5, 44, 7, 62, 16, 1 },
+                        { 0, 10, 55, 7, 54, 9, 0 },
+                        { 1, 17, 63, 7, 42, 5, 0 },
+                        { 2, 26, 67, 7, 31, 2, 0 },
+                        { 0, 4, 37, 7, 66, 20, 1 },
+                        { 0, 7, 49, 7, 60, 12, 0 } } },
+       .ptrn_arr = { { 0x42424849, 0x90921212, 0x24248490, 0x9212124,
+                        0x48484909, 0x92121242, 0x84849090, 0x2424 } },
+       .sample_patrn_length = 242,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 90) = 0.262295 */
+       .hor_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 48, 7, 59, 13, 1 },
+                        { 0, 11, 58, 7, 51, 8, 0 },
+                        { 1, 17, 64, 7, 41, 5, 0 },
+                        { 2, 25, 67, 7, 31, 3, 0 },
+                        { 0, 3, 35, 7, 66, 23, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 23, 66, 7, 35, 3, 0 },
+                        { 0, 3, 31, 7, 67, 25, 2 },
+                        { 0, 5, 41, 7, 64, 17, 1 },
+                        { 0, 8, 51, 7, 58, 11, 0 },
+                        { 1, 13, 59, 7, 48, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 } },
+               .odd = { { 0, 12, 59, 7, 49, 8, 0 },
+                        { 1, 19, 64, 7, 40, 4, 0 },
+                        { 2, 27, 67, 7, 30, 2, 0 },
+                        { 0, 4, 36, 7, 66, 21, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 10, 56, 7, 53, 9, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 },
+                        { 2, 24, 66, 7, 33, 3, 0 },
+                        { 0, 3, 33, 7, 66, 24, 2 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 9, 53, 7, 56, 10, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 21, 66, 7, 36, 4, 0 },
+                        { 0, 2, 30, 7, 67, 27, 2 },
+                        { 0, 4, 40, 7, 64, 19, 1 },
+                        { 0, 8, 49, 7, 59, 12, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 28, 68, 7, 28, 2, 0 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 48, 7, 59, 13, 1 },
+                        { 0, 11, 58, 7, 51, 8, 0 },
+                        { 1, 17, 64, 7, 41, 5, 0 },
+                        { 2, 25, 67, 7, 31, 3, 0 },
+                        { 0, 3, 35, 7, 66, 23, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 23, 66, 7, 35, 3, 0 },
+                        { 0, 3, 31, 7, 67, 25, 2 },
+                        { 0, 5, 41, 7, 64, 17, 1 },
+                        { 0, 8, 51, 7, 58, 11, 0 },
+                        { 1, 13, 59, 7, 48, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 } },
+               .odd = { { 0, 12, 59, 7, 49, 8, 0 },
+                        { 1, 19, 64, 7, 40, 4, 0 },
+                        { 2, 27, 67, 7, 30, 2, 0 },
+                        { 0, 4, 36, 7, 66, 21, 1 },
+                        { 0, 6, 46, 7, 61, 14, 1 },
+                        { 0, 10, 56, 7, 53, 9, 0 },
+                        { 1, 16, 63, 7, 43, 5, 0 },
+                        { 2, 24, 66, 7, 33, 3, 0 },
+                        { 0, 3, 33, 7, 66, 24, 2 },
+                        { 0, 5, 43, 7, 63, 16, 1 },
+                        { 0, 9, 53, 7, 56, 10, 0 },
+                        { 1, 14, 61, 7, 46, 6, 0 },
+                        { 1, 21, 66, 7, 36, 4, 0 },
+                        { 0, 2, 30, 7, 67, 27, 2 },
+                        { 0, 4, 40, 7, 64, 19, 1 },
+                        { 0, 8, 49, 7, 59, 12, 0 } } },
+       .ptrn_arr = { { 0x42484849, 0x92121242, 0x84849090, 0x242424 } },
+       .sample_patrn_length = 122,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 91) = 0.260163 */
+       .hor_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 4, 36, 7, 66, 21, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 9, 52, 7, 56, 11, 0 },
+                        { 1, 13, 59, 7, 48, 7, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 33, 7, 66, 24, 2 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 8, 49, 7, 59, 12, 0 },
+                        { 0, 12, 57, 7, 51, 8, 0 },
+                        { 1, 17, 62, 7, 43, 5, 0 },
+                        { 1, 23, 66, 7, 35, 3, 0 },
+                        { 0, 3, 30, 7, 66, 27, 2 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 46, 7, 60, 14, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 14, 60, 7, 46, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 2, 27, 66, 7, 30, 3, 0 },
+                        { 0, 3, 35, 7, 66, 23, 1 },
+                        { 0, 5, 43, 7, 62, 17, 1 },
+                        { 0, 8, 51, 7, 57, 12, 0 },
+                        { 0, 12, 59, 7, 49, 8, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 2, 24, 66, 7, 33, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 7, 48, 7, 59, 13, 1 },
+                        { 0, 11, 56, 7, 52, 9, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 21, 66, 7, 36, 4, 0 } },
+               .odd = { { 0, 12, 58, 7, 50, 8, 0 },
+                        { 1, 17, 63, 7, 42, 5, 0 },
+                        { 2, 23, 66, 7, 34, 3, 0 },
+                        { 0, 3, 31, 7, 66, 26, 2 },
+                        { 0, 4, 39, 7, 64, 20, 1 },
+                        { 0, 7, 47, 7, 59, 14, 1 },
+                        { 0, 10, 55, 7, 53, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 21, 65, 7, 37, 4, 0 },
+                        { 2, 28, 67, 7, 29, 2, 0 },
+                        { 0, 4, 36, 7, 65, 22, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 9, 52, 7, 56, 11, 0 },
+                        { 1, 13, 58, 7, 49, 7, 0 },
+                        { 1, 18, 64, 7, 40, 5, 0 },
+                        { 2, 25, 66, 7, 32, 3, 0 },
+                        { 0, 3, 32, 7, 66, 25, 2 },
+                        { 0, 5, 40, 7, 64, 18, 1 },
+                        { 0, 7, 49, 7, 58, 13, 1 },
+                        { 0, 11, 56, 7, 52, 9, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 22, 65, 7, 36, 4, 0 },
+                        { 0, 2, 29, 7, 67, 28, 2 },
+                        { 0, 4, 37, 7, 65, 21, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 53, 7, 55, 10, 0 },
+                        { 1, 14, 59, 7, 47, 7, 0 },
+                        { 1, 20, 64, 7, 39, 4, 0 },
+                        { 2, 26, 66, 7, 31, 3, 0 },
+                        { 0, 3, 34, 7, 66, 23, 2 },
+                        { 0, 5, 42, 7, 63, 17, 1 },
+                        { 0, 8, 50, 7, 58, 12, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 4, 36, 7, 66, 21, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 9, 52, 7, 56, 11, 0 },
+                        { 1, 13, 59, 7, 48, 7, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 33, 7, 66, 24, 2 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 8, 49, 7, 59, 12, 0 },
+                        { 0, 12, 57, 7, 51, 8, 0 },
+                        { 1, 17, 62, 7, 43, 5, 0 },
+                        { 1, 23, 66, 7, 35, 3, 0 },
+                        { 0, 3, 30, 7, 66, 27, 2 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 7, 46, 7, 60, 14, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 14, 60, 7, 46, 7, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 2, 27, 66, 7, 30, 3, 0 },
+                        { 0, 3, 35, 7, 66, 23, 1 },
+                        { 0, 5, 43, 7, 62, 17, 1 },
+                        { 0, 8, 51, 7, 57, 12, 0 },
+                        { 0, 12, 59, 7, 49, 8, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 2, 24, 66, 7, 33, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 7, 48, 7, 59, 13, 1 },
+                        { 0, 11, 56, 7, 52, 9, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 21, 66, 7, 36, 4, 0 } },
+               .odd = { { 0, 12, 58, 7, 50, 8, 0 },
+                        { 1, 17, 63, 7, 42, 5, 0 },
+                        { 2, 23, 66, 7, 34, 3, 0 },
+                        { 0, 3, 31, 7, 66, 26, 2 },
+                        { 0, 4, 39, 7, 64, 20, 1 },
+                        { 0, 7, 47, 7, 59, 14, 1 },
+                        { 0, 10, 55, 7, 53, 10, 0 },
+                        { 1, 15, 61, 7, 45, 6, 0 },
+                        { 1, 21, 65, 7, 37, 4, 0 },
+                        { 2, 28, 67, 7, 29, 2, 0 },
+                        { 0, 4, 36, 7, 65, 22, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 9, 52, 7, 56, 11, 0 },
+                        { 1, 13, 58, 7, 49, 7, 0 },
+                        { 1, 18, 64, 7, 40, 5, 0 },
+                        { 2, 25, 66, 7, 32, 3, 0 },
+                        { 0, 3, 32, 7, 66, 25, 2 },
+                        { 0, 5, 40, 7, 64, 18, 1 },
+                        { 0, 7, 49, 7, 58, 13, 1 },
+                        { 0, 11, 56, 7, 52, 9, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 22, 65, 7, 36, 4, 0 },
+                        { 0, 2, 29, 7, 67, 28, 2 },
+                        { 0, 4, 37, 7, 65, 21, 1 },
+                        { 0, 6, 45, 7, 61, 15, 1 },
+                        { 0, 10, 53, 7, 55, 10, 0 },
+                        { 1, 14, 59, 7, 47, 7, 0 },
+                        { 1, 20, 64, 7, 39, 4, 0 },
+                        { 2, 26, 66, 7, 31, 3, 0 },
+                        { 0, 3, 34, 7, 66, 23, 2 },
+                        { 0, 5, 42, 7, 63, 17, 1 },
+                        { 0, 8, 50, 7, 58, 12, 0 } } },
+       .ptrn_arr = { { 0x42484849, 0x12124242, 0x90909212, 0x24848484,
+                        0x21242424, 0x9090921, 0x48484849, 0x24242 } },
+       .sample_patrn_length = 246,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 92) = 0.258065 */
+       .hor_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 48, 7, 58, 14, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 14, 58, 7, 48, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 } },
+               .odd = { { 0, 12, 56, 7, 51, 9, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 9, 51, 7, 56, 12, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 48, 7, 58, 14, 1 },
+                        { 0, 10, 54, 7, 54, 10, 0 },
+                        { 1, 14, 58, 7, 48, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 } },
+               .odd = { { 0, 12, 56, 7, 51, 9, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 20, 65, 7, 38, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 38, 7, 65, 20, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 9, 51, 7, 56, 12, 0 } } },
+       .ptrn_arr = { { 0x48484849, 0x2424242 } },
+       .sample_patrn_length = 62,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 93) = 0.256 */
+       .hor_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 38, 7, 64, 21, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 1, 22, 65, 7, 36, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 30, 7, 66, 27, 2 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 8, 49, 7, 57, 13, 1 },
+                        { 0, 10, 55, 7, 53, 10, 0 },
+                        { 1, 13, 57, 7, 49, 8, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 },
+                        { 2, 27, 66, 7, 30, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 36, 7, 65, 22, 1 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 21, 64, 7, 38, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 } },
+               .odd = { { 0, 12, 56, 7, 51, 9, 0 },
+                        { 1, 14, 59, 7, 47, 7, 0 },
+                        { 1, 18, 61, 7, 42, 6, 0 },
+                        { 1, 21, 65, 7, 37, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 },
+                        { 0, 3, 30, 7, 65, 28, 2 },
+                        { 0, 3, 34, 7, 65, 24, 2 },
+                        { 0, 5, 39, 7, 63, 20, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 8, 48, 7, 58, 13, 1 },
+                        { 0, 10, 53, 7, 54, 11, 0 },
+                        { 1, 12, 57, 7, 50, 8, 0 },
+                        { 1, 15, 60, 7, 45, 7, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 23, 63, 7, 36, 4, 0 },
+                        { 2, 27, 65, 7, 31, 3, 0 },
+                        { 0, 3, 31, 7, 65, 27, 2 },
+                        { 0, 4, 36, 7, 63, 23, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 7, 45, 7, 60, 15, 1 },
+                        { 0, 8, 50, 7, 57, 12, 1 },
+                        { 0, 11, 54, 7, 53, 10, 0 },
+                        { 1, 13, 58, 7, 48, 8, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 20, 63, 7, 39, 5, 0 },
+                        { 2, 24, 65, 7, 34, 3, 0 },
+                        { 2, 28, 65, 7, 30, 3, 0 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 37, 7, 65, 21, 1 },
+                        { 0, 6, 42, 7, 61, 18, 1 },
+                        { 0, 7, 47, 7, 59, 14, 1 },
+                        { 0, 9, 51, 7, 56, 12, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 2, 29, 66, 7, 29, 2, 0 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 38, 7, 64, 21, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 1, 22, 65, 7, 36, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 0, 3, 30, 7, 66, 27, 2 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 8, 49, 7, 57, 13, 1 },
+                        { 0, 10, 55, 7, 53, 10, 0 },
+                        { 1, 13, 57, 7, 49, 8, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 },
+                        { 2, 27, 66, 7, 30, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 36, 7, 65, 22, 1 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 21, 64, 7, 38, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 } },
+               .odd = { { 0, 12, 56, 7, 51, 9, 0 },
+                        { 1, 14, 59, 7, 47, 7, 0 },
+                        { 1, 18, 61, 7, 42, 6, 0 },
+                        { 1, 21, 65, 7, 37, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 },
+                        { 0, 3, 30, 7, 65, 28, 2 },
+                        { 0, 3, 34, 7, 65, 24, 2 },
+                        { 0, 5, 39, 7, 63, 20, 1 },
+                        { 0, 6, 44, 7, 61, 16, 1 },
+                        { 0, 8, 48, 7, 58, 13, 1 },
+                        { 0, 10, 53, 7, 54, 11, 0 },
+                        { 1, 12, 57, 7, 50, 8, 0 },
+                        { 1, 15, 60, 7, 45, 7, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 2, 23, 63, 7, 36, 4, 0 },
+                        { 2, 27, 65, 7, 31, 3, 0 },
+                        { 0, 3, 31, 7, 65, 27, 2 },
+                        { 0, 4, 36, 7, 63, 23, 2 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 7, 45, 7, 60, 15, 1 },
+                        { 0, 8, 50, 7, 57, 12, 1 },
+                        { 0, 11, 54, 7, 53, 10, 0 },
+                        { 1, 13, 58, 7, 48, 8, 0 },
+                        { 1, 16, 61, 7, 44, 6, 0 },
+                        { 1, 20, 63, 7, 39, 5, 0 },
+                        { 2, 24, 65, 7, 34, 3, 0 },
+                        { 2, 28, 65, 7, 30, 3, 0 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 37, 7, 65, 21, 1 },
+                        { 0, 6, 42, 7, 61, 18, 1 },
+                        { 0, 7, 47, 7, 59, 14, 1 },
+                        { 0, 9, 51, 7, 56, 12, 0 } } },
+       .ptrn_arr = { { 0x48484849, 0x42424248, 0x12124242, 0x92121212,
+                        0x90909090, 0x84848490, 0x24248484, 0x242424 } },
+       .sample_patrn_length = 250,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 94) = 0.253968 */
+       .hor_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 38, 7, 63, 21, 1 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 44, 7, 60, 16, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 11, 53, 7, 53, 11, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 16, 60, 7, 44, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 1, 21, 63, 7, 38, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 } },
+               .odd = { { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 13, 57, 7, 49, 8, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 20, 62, 7, 40, 5, 0 },
+                        { 2, 22, 63, 7, 37, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 },
+                        { 2, 28, 65, 7, 30, 3, 0 },
+                        { 0, 3, 30, 7, 65, 28, 2 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 37, 7, 63, 22, 2 },
+                        { 0, 5, 40, 7, 62, 20, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 8, 49, 7, 57, 13, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 35, 7, 64, 23, 2 },
+                        { 0, 5, 38, 7, 63, 21, 1 },
+                        { 0, 5, 41, 7, 63, 18, 1 },
+                        { 0, 7, 44, 7, 60, 16, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 11, 53, 7, 53, 11, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 16, 60, 7, 44, 7, 0 },
+                        { 1, 18, 63, 7, 41, 5, 0 },
+                        { 1, 21, 63, 7, 38, 5, 0 },
+                        { 2, 23, 64, 7, 35, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 } },
+               .odd = { { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 13, 57, 7, 49, 8, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 20, 62, 7, 40, 5, 0 },
+                        { 2, 22, 63, 7, 37, 4, 0 },
+                        { 2, 25, 65, 7, 33, 3, 0 },
+                        { 2, 28, 65, 7, 30, 3, 0 },
+                        { 0, 3, 30, 7, 65, 28, 2 },
+                        { 0, 3, 33, 7, 65, 25, 2 },
+                        { 0, 4, 37, 7, 63, 22, 2 },
+                        { 0, 5, 40, 7, 62, 20, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 8, 49, 7, 57, 13, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 } } },
+       .ptrn_arr = { { 0x48484849, 0x48484848, 0x42424242, 0x2424242 } },
+       .sample_patrn_length = 126,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 95) = 0.251969 */
+       .hor_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 },
+                        { 0, 3, 31, 7, 64, 28, 2 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 34, 7, 63, 25, 2 },
+                        { 0, 4, 35, 7, 63, 24, 2 },
+                        { 0, 4, 37, 7, 63, 22, 2 },
+                        { 0, 5, 38, 7, 63, 21, 1 },
+                        { 0, 5, 40, 7, 62, 20, 1 },
+                        { 0, 6, 41, 7, 61, 19, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 44, 7, 60, 16, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 9, 49, 7, 56, 13, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 10, 51, 7, 54, 12, 1 },
+                        { 0, 11, 53, 7, 53, 11, 0 },
+                        { 1, 12, 54, 7, 51, 10, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 13, 56, 7, 49, 9, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 16, 60, 7, 44, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 19, 61, 7, 41, 6, 0 },
+                        { 1, 20, 62, 7, 40, 5, 0 },
+                        { 1, 21, 63, 7, 38, 5, 0 },
+                        { 2, 22, 63, 7, 37, 4, 0 },
+                        { 2, 24, 63, 7, 35, 4, 0 },
+                        { 2, 25, 63, 7, 34, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 2, 28, 64, 7, 31, 3, 0 } },
+               .odd = { { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 12, 54, 7, 51, 10, 0 },
+                        { 1, 13, 56, 7, 49, 9, 0 },
+                        { 1, 14, 57, 7, 48, 8, 0 },
+                        { 1, 15, 58, 7, 46, 8, 0 },
+                        { 1, 16, 59, 7, 45, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 18, 61, 7, 42, 6, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 1, 20, 63, 7, 39, 5, 0 },
+                        { 2, 22, 62, 7, 37, 5, 0 },
+                        { 2, 23, 63, 7, 36, 4, 0 },
+                        { 2, 24, 64, 7, 34, 4, 0 },
+                        { 2, 26, 64, 7, 33, 3, 0 },
+                        { 2, 27, 65, 7, 31, 3, 0 },
+                        { 3, 28, 64, 7, 30, 3, 0 },
+                        { 0, 3, 30, 7, 64, 28, 3 },
+                        { 0, 3, 31, 7, 65, 27, 2 },
+                        { 0, 3, 33, 7, 64, 26, 2 },
+                        { 0, 4, 34, 7, 64, 24, 2 },
+                        { 0, 4, 36, 7, 63, 23, 2 },
+                        { 0, 5, 37, 7, 62, 22, 2 },
+                        { 0, 5, 39, 7, 63, 20, 1 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 6, 42, 7, 61, 18, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 45, 7, 59, 16, 1 },
+                        { 0, 8, 46, 7, 58, 15, 1 },
+                        { 0, 8, 48, 7, 57, 14, 1 },
+                        { 0, 9, 49, 7, 56, 13, 1 },
+                        { 0, 10, 51, 7, 54, 12, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 },
+                        { 0, 3, 31, 7, 64, 28, 2 },
+                        { 0, 3, 32, 7, 65, 26, 2 },
+                        { 0, 4, 34, 7, 63, 25, 2 },
+                        { 0, 4, 35, 7, 63, 24, 2 },
+                        { 0, 4, 37, 7, 63, 22, 2 },
+                        { 0, 5, 38, 7, 63, 21, 1 },
+                        { 0, 5, 40, 7, 62, 20, 1 },
+                        { 0, 6, 41, 7, 61, 19, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 44, 7, 60, 16, 1 },
+                        { 0, 7, 46, 7, 59, 15, 1 },
+                        { 0, 8, 47, 7, 58, 14, 1 },
+                        { 0, 9, 49, 7, 56, 13, 1 },
+                        { 0, 9, 50, 7, 56, 12, 1 },
+                        { 0, 10, 51, 7, 54, 12, 1 },
+                        { 0, 11, 53, 7, 53, 11, 0 },
+                        { 1, 12, 54, 7, 51, 10, 0 },
+                        { 1, 12, 56, 7, 50, 9, 0 },
+                        { 1, 13, 56, 7, 49, 9, 0 },
+                        { 1, 14, 58, 7, 47, 8, 0 },
+                        { 1, 15, 59, 7, 46, 7, 0 },
+                        { 1, 16, 60, 7, 44, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 19, 61, 7, 41, 6, 0 },
+                        { 1, 20, 62, 7, 40, 5, 0 },
+                        { 1, 21, 63, 7, 38, 5, 0 },
+                        { 2, 22, 63, 7, 37, 4, 0 },
+                        { 2, 24, 63, 7, 35, 4, 0 },
+                        { 2, 25, 63, 7, 34, 4, 0 },
+                        { 2, 26, 65, 7, 32, 3, 0 },
+                        { 2, 28, 64, 7, 31, 3, 0 } },
+               .odd = { { 0, 11, 55, 7, 52, 10, 0 },
+                        { 1, 12, 54, 7, 51, 10, 0 },
+                        { 1, 13, 56, 7, 49, 9, 0 },
+                        { 1, 14, 57, 7, 48, 8, 0 },
+                        { 1, 15, 58, 7, 46, 8, 0 },
+                        { 1, 16, 59, 7, 45, 7, 0 },
+                        { 1, 17, 61, 7, 43, 6, 0 },
+                        { 1, 18, 61, 7, 42, 6, 0 },
+                        { 1, 19, 63, 7, 40, 5, 0 },
+                        { 1, 20, 63, 7, 39, 5, 0 },
+                        { 2, 22, 62, 7, 37, 5, 0 },
+                        { 2, 23, 63, 7, 36, 4, 0 },
+                        { 2, 24, 64, 7, 34, 4, 0 },
+                        { 2, 26, 64, 7, 33, 3, 0 },
+                        { 2, 27, 65, 7, 31, 3, 0 },
+                        { 3, 28, 64, 7, 30, 3, 0 },
+                        { 0, 3, 30, 7, 64, 28, 3 },
+                        { 0, 3, 31, 7, 65, 27, 2 },
+                        { 0, 3, 33, 7, 64, 26, 2 },
+                        { 0, 4, 34, 7, 64, 24, 2 },
+                        { 0, 4, 36, 7, 63, 23, 2 },
+                        { 0, 5, 37, 7, 62, 22, 2 },
+                        { 0, 5, 39, 7, 63, 20, 1 },
+                        { 0, 5, 40, 7, 63, 19, 1 },
+                        { 0, 6, 42, 7, 61, 18, 1 },
+                        { 0, 6, 43, 7, 61, 17, 1 },
+                        { 0, 7, 45, 7, 59, 16, 1 },
+                        { 0, 8, 46, 7, 58, 15, 1 },
+                        { 0, 8, 48, 7, 57, 14, 1 },
+                        { 0, 9, 49, 7, 56, 13, 1 },
+                        { 0, 10, 51, 7, 54, 12, 1 },
+                        { 0, 10, 52, 7, 55, 11, 0 } } },
+       .ptrn_arr = { { 0x48484849, 0x48484848, 0x48484848, 0x48484848,
+                        0x42424242, 0x42424242, 0x42424242, 0x2424242 } },
+       .sample_patrn_length = 254,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+}, {
+       /* Scale factor 32 / (32 + 96) = 0.25 */
+       .hor_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 } },
+               .odd = { { 0, 11, 53, 7, 53, 11, 0 } } },
+       .ver_phase_arr = {
+               .even = { { 3, 29, 64, 7, 29, 3, 0 } },
+               .odd = { { 0, 11, 53, 7, 53, 11, 0 } } },
+       .ptrn_arr = { { 0x9 } },
+       .sample_patrn_length = 8,
+       .hor_ds_en = 1,
+       .ver_ds_en = 1
+} };
+
+const s32 ipu3_css_downscale_4taps[IMGU_SCALER_DOWNSCALE_4TAPS_LEN] = {
+       IMGU_SCALER_FP * -0.000000000000000,
+       IMGU_SCALER_FP * -0.000249009327023,
+       IMGU_SCALER_FP * -0.001022241683322,
+       IMGU_SCALER_FP * -0.002352252699175,
+       IMGU_SCALER_FP * -0.004261594242362,
+       IMGU_SCALER_FP * -0.006761648795689,
+       IMGU_SCALER_FP * -0.009851589454154,
+       IMGU_SCALER_FP * -0.013517488475013,
+       IMGU_SCALER_FP * -0.017731595701026,
+       IMGU_SCALER_FP * -0.022451806160682,
+       IMGU_SCALER_FP * -0.027621333752351,
+       IMGU_SCALER_FP * -0.033168605172067,
+       IMGU_SCALER_FP * -0.039007385183627,
+       IMGU_SCALER_FP * -0.045037140997445,
+       IMGU_SCALER_FP * -0.051143649969349,
+       IMGU_SCALER_FP * -0.057199851105019,
+       IMGU_SCALER_FP * -0.063066937016941,
+       IMGU_SCALER_FP * -0.068595679088417,
+       IMGU_SCALER_FP * -0.073627974715370,
+       IMGU_SCALER_FP * -0.077998601684588,
+       IMGU_SCALER_FP * -0.081537161069780,
+       IMGU_SCALER_FP * -0.084070186546763,
+       IMGU_SCALER_FP * -0.085423394806327,
+       IMGU_SCALER_FP * -0.085424048835192,
+       IMGU_SCALER_FP * -0.083903403294908,
+       IMGU_SCALER_FP * -0.080699199103829,
+       IMGU_SCALER_FP * -0.075658172660608,
+       IMGU_SCALER_FP * -0.068638543974523,
+       IMGU_SCALER_FP * -0.059512447316781,
+       IMGU_SCALER_FP * -0.048168267897836,
+       IMGU_SCALER_FP * -0.034512848520921,
+       IMGU_SCALER_FP * -0.018473531164409,
+       IMGU_SCALER_FP * 0.000000000000000,
+       IMGU_SCALER_FP * 0.020934105554674,
+       IMGU_SCALER_FP * 0.044329836544650,
+       IMGU_SCALER_FP * 0.070161864654994,
+       IMGU_SCALER_FP * 0.098377719033862,
+       IMGU_SCALER_FP * 0.128897348012514,
+       IMGU_SCALER_FP * 0.161613019706978,
+       IMGU_SCALER_FP * 0.196389570939079,
+       IMGU_SCALER_FP * 0.233065009152522,
+       IMGU_SCALER_FP * 0.271451467092549,
+       IMGU_SCALER_FP * 0.311336505037934,
+       IMGU_SCALER_FP * 0.352484750396743,
+       IMGU_SCALER_FP * 0.394639859577736,
+       IMGU_SCALER_FP * 0.437526782302744,
+       IMGU_SCALER_FP * 0.480854304005320,
+       IMGU_SCALER_FP * 0.524317837738108,
+       IMGU_SCALER_FP * 0.567602433152471,
+       IMGU_SCALER_FP * 0.610385966680669,
+       IMGU_SCALER_FP * 0.652342474098843,
+       IMGU_SCALER_FP * 0.693145584226952,
+       IMGU_SCALER_FP * 0.732472010670320,
+       IMGU_SCALER_FP * 0.770005057258970,
+       IMGU_SCALER_FP * 0.805438092218553,
+       IMGU_SCALER_FP * 0.838477946124244,
+       IMGU_SCALER_FP * 0.868848189350256,
+       IMGU_SCALER_FP * 0.896292246026874,
+       IMGU_SCALER_FP * 0.920576303438191,
+       IMGU_SCALER_FP * 0.941491978311745,
+       IMGU_SCALER_FP * 0.958858704531378,
+       IMGU_SCALER_FP * 0.972525810403401,
+       IMGU_SCALER_FP * 0.982374257672165,
+       IMGU_SCALER_FP * 0.988318018955586,
+       IMGU_SCALER_FP * 0.990305075088925,
+       IMGU_SCALER_FP * 0.988318018955586,
+       IMGU_SCALER_FP * 0.982374257672165,
+       IMGU_SCALER_FP * 0.972525810403401,
+       IMGU_SCALER_FP * 0.958858704531378,
+       IMGU_SCALER_FP * 0.941491978311745,
+       IMGU_SCALER_FP * 0.920576303438191,
+       IMGU_SCALER_FP * 0.896292246026874,
+       IMGU_SCALER_FP * 0.868848189350256,
+       IMGU_SCALER_FP * 0.838477946124244,
+       IMGU_SCALER_FP * 0.805438092218553,
+       IMGU_SCALER_FP * 0.770005057258970,
+       IMGU_SCALER_FP * 0.732472010670320,
+       IMGU_SCALER_FP * 0.693145584226952,
+       IMGU_SCALER_FP * 0.652342474098843,
+       IMGU_SCALER_FP * 0.610385966680669,
+       IMGU_SCALER_FP * 0.567602433152471,
+       IMGU_SCALER_FP * 0.524317837738108,
+       IMGU_SCALER_FP * 0.480854304005320,
+       IMGU_SCALER_FP * 0.437526782302744,
+       IMGU_SCALER_FP * 0.394639859577736,
+       IMGU_SCALER_FP * 0.352484750396743,
+       IMGU_SCALER_FP * 0.311336505037934,
+       IMGU_SCALER_FP * 0.271451467092549,
+       IMGU_SCALER_FP * 0.233065009152522,
+       IMGU_SCALER_FP * 0.196389570939079,
+       IMGU_SCALER_FP * 0.161613019706978,
+       IMGU_SCALER_FP * 0.128897348012514,
+       IMGU_SCALER_FP * 0.098377719033862,
+       IMGU_SCALER_FP * 0.070161864654994,
+       IMGU_SCALER_FP * 0.044329836544650,
+       IMGU_SCALER_FP * 0.020934105554674,
+       IMGU_SCALER_FP * 0.000000000000000,
+       IMGU_SCALER_FP * -0.018473531164409,
+       IMGU_SCALER_FP * -0.034512848520921,
+       IMGU_SCALER_FP * -0.048168267897836,
+       IMGU_SCALER_FP * -0.059512447316781,
+       IMGU_SCALER_FP * -0.068638543974523,
+       IMGU_SCALER_FP * -0.075658172660608,
+       IMGU_SCALER_FP * -0.080699199103829,
+       IMGU_SCALER_FP * -0.083903403294908,
+       IMGU_SCALER_FP * -0.085424048835192,
+       IMGU_SCALER_FP * -0.085423394806327,
+       IMGU_SCALER_FP * -0.084070186546763,
+       IMGU_SCALER_FP * -0.081537161069780,
+       IMGU_SCALER_FP * -0.077998601684588,
+       IMGU_SCALER_FP * -0.073627974715370,
+       IMGU_SCALER_FP * -0.068595679088417,
+       IMGU_SCALER_FP * -0.063066937016941,
+       IMGU_SCALER_FP * -0.057199851105019,
+       IMGU_SCALER_FP * -0.051143649969349,
+       IMGU_SCALER_FP * -0.045037140997445,
+       IMGU_SCALER_FP * -0.039007385183627,
+       IMGU_SCALER_FP * -0.033168605172067,
+       IMGU_SCALER_FP * -0.027621333752351,
+       IMGU_SCALER_FP * -0.022451806160682,
+       IMGU_SCALER_FP * -0.017731595701026,
+       IMGU_SCALER_FP * -0.013517488475013,
+       IMGU_SCALER_FP * -0.009851589454154,
+       IMGU_SCALER_FP * -0.006761648795689,
+       IMGU_SCALER_FP * -0.004261594242362,
+       IMGU_SCALER_FP * -0.002352252699175,
+       IMGU_SCALER_FP * -0.001022241683322,
+       IMGU_SCALER_FP * -0.000249009327023
+};
+
+const s32 ipu3_css_downscale_2taps[IMGU_SCALER_DOWNSCALE_2TAPS_LEN] = {
+       IMGU_SCALER_FP * 0.074300676367033,
+       IMGU_SCALER_FP * 0.094030234498392,
+       IMGU_SCALER_FP * 0.115522859526596,
+       IMGU_SCALER_FP * 0.138778551451644,
+       IMGU_SCALER_FP * 0.163629399140505,
+       IMGU_SCALER_FP * 0.190075402593178,
+       IMGU_SCALER_FP * 0.217864695110113,
+       IMGU_SCALER_FP * 0.247081232257828,
+       IMGU_SCALER_FP * 0.277389191770256,
+       IMGU_SCALER_FP * 0.308704618080881,
+       IMGU_SCALER_FP * 0.340859600056670,
+       IMGU_SCALER_FP * 0.373602270998074,
+       IMGU_SCALER_FP * 0.406848675338577,
+       IMGU_SCALER_FP * 0.440346946378629,
+       IMGU_SCALER_FP * 0.473845217418681,
+       IMGU_SCALER_FP * 0.507091621759184,
+       IMGU_SCALER_FP * 0.540002203833621,
+       IMGU_SCALER_FP * 0.572157185809410,
+       IMGU_SCALER_FP * 0.603472612120036,
+       IMGU_SCALER_FP * 0.633612660499431,
+       IMGU_SCALER_FP * 0.662493375381080,
+       IMGU_SCALER_FP * 0.689778934498917,
+       IMGU_SCALER_FP * 0.715301426719909,
+       IMGU_SCALER_FP * 0.738892940911023,
+       IMGU_SCALER_FP * 0.760385565939227,
+       IMGU_SCALER_FP * 0.779527435104971,
+       IMGU_SCALER_FP * 0.796234592841739,
+       IMGU_SCALER_FP * 0.810339128016497,
+       IMGU_SCALER_FP * 0.821841040629247,
+       IMGU_SCALER_FP * 0.830488463980438,
+       IMGU_SCALER_FP * 0.836281398070072,
+       IMGU_SCALER_FP * 0.839219842898146,
+       IMGU_SCALER_FP * 0.839219842898146,
+       IMGU_SCALER_FP * 0.836281398070072,
+       IMGU_SCALER_FP * 0.830488463980438,
+       IMGU_SCALER_FP * 0.821841040629247,
+       IMGU_SCALER_FP * 0.810339128016497,
+       IMGU_SCALER_FP * 0.796234592841739,
+       IMGU_SCALER_FP * 0.779527435104971,
+       IMGU_SCALER_FP * 0.760385565939227,
+       IMGU_SCALER_FP * 0.738892940911023,
+       IMGU_SCALER_FP * 0.715301426719909,
+       IMGU_SCALER_FP * 0.689778934498917,
+       IMGU_SCALER_FP * 0.662493375381080,
+       IMGU_SCALER_FP * 0.633612660499431,
+       IMGU_SCALER_FP * 0.603472612120036,
+       IMGU_SCALER_FP * 0.572157185809410,
+       IMGU_SCALER_FP * 0.540002203833621,
+       IMGU_SCALER_FP * 0.507091621759184,
+       IMGU_SCALER_FP * 0.473845217418681,
+       IMGU_SCALER_FP * 0.440346946378629,
+       IMGU_SCALER_FP * 0.406848675338577,
+       IMGU_SCALER_FP * 0.373602270998074,
+       IMGU_SCALER_FP * 0.340859600056670,
+       IMGU_SCALER_FP * 0.308704618080881,
+       IMGU_SCALER_FP * 0.277389191770256,
+       IMGU_SCALER_FP * 0.247081232257828,
+       IMGU_SCALER_FP * 0.217864695110113,
+       IMGU_SCALER_FP * 0.190075402593178,
+       IMGU_SCALER_FP * 0.163629399140505,
+       IMGU_SCALER_FP * 0.138778551451644,
+       IMGU_SCALER_FP * 0.115522859526596,
+       IMGU_SCALER_FP * 0.094030234498392,
+       IMGU_SCALER_FP * 0.074300676367033
+};
+
+/* settings for Geometric Distortion Correction */
+const s16 ipu3_css_gdc_lut[4][256] = { {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2,
+       -2, -3, -3, -3, -4, -4, -4, -5, -5, -5, -6, -6, -7, -7, -7, -8, -8,
+       -9, -9, -10, -10, -11, -11, -12, -12, -13, -13, -14, -14, -15, -15,
+       -16, -16, -17, -17, -18, -19, -19, -20, -20, -21, -22, -22, -23, -24,
+       -24, -25, -25, -26, -27, -27, -28, -29, -29, -30, -31, -31, -32, -33,
+       -33, -34, -35, -35, -36, -37, -37, -38, -39, -39, -40,  -41, -41, -42,
+       -43, -43, -44, -45, -45, -46, -46, -47, -48, -48, -49, -50, -50, -51,
+       -52, -52, -53, -53, -54, -55, -55, -56, -56, -57, -58, -58, -59, -59,
+       -60, -60, -61, -61, -62, -62, -63, -64, -64, -64, -65,  -65, -66, -66,
+       -67, -67, -68, -68, -68, -69, -69, -70, -70, -70, -71, -71, -71, -72,
+       -72, -72, -73, -73, -73, -73, -74, -74, -74, -74, -74, -75, -75, -75,
+       -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,  -75, -75, -75,
+       -75, -75, -75, -75, -74, -74, -74, -74, -74, -73, -73, -73, -73, -72,
+       -72, -72, -71, -71, -70, -70, -69, -69, -68, -68, -67, -67, -66, -66,
+       -65, -64, -64, -63, -62, -61, -61, -60, -59, -58, -57,  -56, -56, -55,
+       -54, -53, -52, -51, -50, -49, -47, -46, -45, -44, -43, -41, -40, -39,
+       -38, -36, -35, -33, -32, -31, -29, -28, -26, -25, -23, -21, -20, -18,
+       -16, -15, -13, -11, -9, -7, -5, -3, -1
+}, {
+       0, 2, 4, 6, 8, 10, 13, 15, 17, 20, 23, 25, 28, 31, 33, 36, 39, 42, 45,
+       48, 51, 54, 58, 61, 64, 68, 71, 74, 78, 82, 85, 89, 93, 96, 100, 104,
+       108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 162,
+       166, 171, 175, 180, 184, 189, 193, 198, 203, 207, 212, 217, 222, 227,
+       232, 236, 241, 246, 251, 256, 261, 266, 271, 276, 282, 287, 292, 297,
+       302, 307, 313, 318, 323, 328, 334, 339, 344, 350, 355, 360, 366, 371,
+       377, 382, 388, 393, 399, 404, 409, 415, 420, 426, 431, 437, 443, 448,
+       454, 459, 465, 470, 476, 481, 487, 492, 498, 504, 509, 515, 520, 526,
+       531, 537, 542, 548, 553, 559, 564, 570, 576, 581, 586, 592, 597, 603,
+       608, 614, 619, 625, 630, 635, 641, 646, 651, 657, 662, 667, 673, 678,
+       683, 688, 694, 699, 704, 709, 714, 719, 724, 729, 735, 740, 745, 749,
+       754, 759, 764, 769, 774, 779, 783, 788, 793, 797, 802, 807, 811, 816,
+       820, 825, 829, 834, 838, 842, 847, 851, 855, 859, 863, 868, 872, 876,
+       880, 884, 888, 891, 895, 899, 903, 906, 910, 914, 917, 921, 924, 927,
+       931, 934, 937, 940, 944, 947, 950, 953, 956, 959, 961, 964, 967, 970,
+       972, 975, 977, 980, 982, 984, 987, 989, 991, 993, 995, 997, 999, 1001,
+       1002, 1004, 1006, 1007, 1009, 1010, 1011, 1013, 1014, 1015, 1016, 1017,
+       1018, 1019, 1020, 1020, 1021, 1022, 1022, 1023, 1023, 1023, 1023, 1023
+}, {
+       1024, 1023, 1023, 1023, 1023, 1023, 1022, 1022, 1021, 1020, 1020, 1019,
+       1018, 1017, 1016, 1015, 1014, 1013, 1011, 1010, 1009, 1007, 1006, 1004,
+       1002, 1001, 999, 997, 995, 993, 991, 989, 987, 984, 982, 980, 977, 975,
+       972, 970, 967, 964, 961, 959, 956, 953, 950, 947, 944, 940, 937, 934,
+       931, 927, 924, 921, 917, 914, 910, 906, 903, 899, 895, 891, 888, 884,
+       880, 876, 872, 868, 863, 859, 855, 851, 847, 842, 838, 834, 829, 825,
+       820, 816, 811, 807, 802, 797, 793, 788, 783, 779, 774, 769, 764, 759,
+       754, 749, 745, 740, 735, 729, 724, 719, 714, 709, 704, 699, 694, 688,
+       683, 678, 673, 667, 662, 657, 651, 646, 641, 635, 630, 625, 619, 614,
+       608, 603, 597, 592, 586, 581, 576, 570, 564, 559, 553, 548, 542, 537,
+       531, 526, 520, 515, 509, 504, 498, 492, 487, 481, 476, 470, 465, 459,
+       454, 448, 443, 437, 431, 426, 420, 415, 409, 404, 399, 393, 388, 382,
+       377, 371, 366, 360, 355, 350, 344, 339, 334, 328, 323, 318, 313, 307,
+       302, 297, 292, 287, 282, 276, 271, 266, 261, 256, 251, 246, 241, 236,
+       232, 227, 222, 217, 212, 207, 203, 198, 193, 189, 184, 180, 175, 171,
+       166, 162, 157, 153, 149, 144, 140, 136, 132, 128, 124, 120, 116, 112,
+       108, 104, 100, 96, 93, 89, 85, 82, 78, 74, 71, 68, 64, 61, 58, 54, 51,
+       48, 45, 42, 39, 36, 33, 31, 28, 25, 23, 20, 17, 15, 13, 10, 8, 6, 4, 2
+}, {
+       0, -1, -3, -5, -7, -9, -11, -13, -14, -16, -19, -20, -21, -23, -24, -26,
+       -28, -29, -30, -32, -34, -34, -37, -38, -38, -41, -42, -42, -44, -46,
+       -46, -48, -49, -49, -51, -52, -53, -54, -55, -56, -57, -57, -58, -59,
+       -60, -60, -62, -62, -63, -63, -64, -65, -66, -66, -67, -68, -67, -69,
+       -69, -69, -70, -70, -71, -71, -72, -72, -72, -73, -73, -73, -73, -73,
+       -73, -74, -75, -74, -75, -75, -74, -75, -75, -75, -75, -75, -75, -75,
+       -75, -75, -75, -75, -75, -75, -75, -74, -75, -74, -75, -75, -74, -74,
+       -73, -73, -73, -73, -73, -73, -73, -71, -72, -71, -72, -70, -70, -70,
+       -69, -70, -69, -68, -68, -68, -67, -67, -66, -66, -65, -65, -64, -64,
+       -64, -63, -62, -62, -61, -61, -60, -60, -59, -59, -58, -58, -57, -57,
+       -55, -55, -55, -53, -54, -53, -52, -51, -52, -50, -50, -49, -48, -47,
+       -46, -46, -46, -46, -45, -43, -43, -42, -42, -41, -41, -40, -39, -39,
+       -38, -37, -37, -36, -35, -35, -34, -33, -32, -32, -31, -31, -31, -29,
+       -28, -27, -27, -27, -26, -25, -25, -24, -24, -23, -22, -22, -21, -20,
+       -20, -20, -18, -19, -17, -17, -16, -16, -15, -14, -14, -14, -14, -12,
+       -12, -12, -11, -11, -11, -10, -9, -9, -8, -8, -7, -6, -7, -7, -6, -6,
+       -5, -4, -5, -5, -3, -3, -4, -2, -3, -2, -1, -2, -1, -1, 0, -1, -1, 0,
+       -1, 0, 1, 0, 0, 0, 0, 0, 0, 0
+} };
+
+const struct ipu3_css_xnr3_vmem_defaults ipu3_css_xnr3_vmem_defaults = {
+       .x = {
+               1024, 1164, 1320, 1492, 1680, 1884, 2108, 2352,
+               2616, 2900, 3208, 3540, 3896, 4276, 4684, 5120
+       },
+       .a = {
+               -7213, -5580, -4371, -3421, -2722, -2159, -6950, -5585,
+               -4529, -3697, -3010, -2485, -2070, -1727, -1428, 0
+       },
+       .b = {
+               4096, 3603, 3178, 2811, 2497, 2226, 1990, 1783,
+               1603, 1446, 1307, 1185, 1077, 981, 895, 819
+       },
+       .c = {
+               1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+       },
+};
+
+/* settings for Bayer Noise Reduction */
+const struct ipu3_uapi_bnr_static_config ipu3_css_bnr_defaults = {
+       { 16, 16, 16, 16 },                     /* wb_gains */
+       { 16, 16, 16, 16 },                     /* wb_gains_thr */
+       { 0, X, 8, 6, X, 14 },                  /* thr_coeffs */
+       { 0, 0, 0, 0 },                         /* thr_ctrl_shd */
+       { -128, X, -128, X },                   /* opt_center */
+       {                                       /* lut */
+               { 17, 23, 28, 32, 36, 39, 42, 45,
+                 48, 51, 53, 55, 58, 60, 62, 64,
+                 66, 68, 70, 72, 73, 75, 77, 78,
+                 80, 82, 83, 85, 86, 88, 89, 90 }
+       },
+       { 4, X, 1, 8, X, 8, X, 8, X },          /* bp_ctrl */
+       { 8, 4, 4, X, 8, X, 1, 1, 1, 1 },       /* dn_detect_ctrl */
+};
+
+const struct ipu3_uapi_dm_config ipu3_css_dm_defaults = {
+       1, 1, 1, X, X, 8, X, 7, X, 8, X, 8, X, 4, X
+};
+
+const struct ipu3_uapi_ccm_mat_config ipu3_css_ccm_defaults = {
+        9775, -2671,  1087, 0,
+       -1071,  8303,   815, 0,
+         -23, -7887, 16103, 0
+};
+
+/* settings for Gamma correction */
+const struct ipu3_uapi_gamma_corr_lut ipu3_css_gamma_lut = { {
+       63, 79, 95, 111, 127, 143, 159, 175, 191, 207, 223, 239, 255, 271, 287,
+       303, 319, 335, 351, 367, 383, 399, 415, 431, 447, 463, 479, 495, 511,
+       527, 543, 559, 575, 591, 607, 623, 639, 655, 671, 687, 703, 719, 735,
+       751, 767, 783, 799, 815, 831, 847, 863, 879, 895, 911, 927, 943, 959,
+       975, 991, 1007, 1023, 1039, 1055, 1071, 1087, 1103, 1119, 1135, 1151,
+       1167, 1183, 1199, 1215, 1231, 1247, 1263, 1279, 1295, 1311, 1327, 1343,
+       1359, 1375, 1391, 1407, 1423, 1439, 1455, 1471, 1487, 1503, 1519, 1535,
+       1551, 1567, 1583, 1599, 1615, 1631, 1647, 1663, 1679, 1695, 1711, 1727,
+       1743, 1759, 1775, 1791, 1807, 1823, 1839, 1855, 1871, 1887, 1903, 1919,
+       1935, 1951, 1967, 1983, 1999, 2015, 2031, 2047, 2063, 2079, 2095, 2111,
+       2143, 2175, 2207, 2239, 2271, 2303, 2335, 2367, 2399, 2431, 2463, 2495,
+       2527, 2559, 2591, 2623, 2655, 2687, 2719, 2751, 2783, 2815, 2847, 2879,
+       2911, 2943, 2975, 3007, 3039, 3071, 3103, 3135, 3167, 3199, 3231, 3263,
+       3295, 3327, 3359, 3391, 3423, 3455, 3487, 3519, 3551, 3583, 3615, 3647,
+       3679, 3711, 3743, 3775, 3807, 3839, 3871, 3903, 3935, 3967, 3999, 4031,
+       4063, 4095, 4127, 4159, 4223, 4287, 4351, 4415, 4479, 4543, 4607, 4671,
+       4735, 4799, 4863, 4927, 4991, 5055, 5119, 5183, 5247, 5311, 5375, 5439,
+       5503, 5567, 5631, 5695, 5759, 5823, 5887, 5951, 6015, 6079, 6143, 6207,
+       6271, 6335, 6399, 6463, 6527, 6591, 6655, 6719, 6783, 6847, 6911, 6975,
+       7039, 7103, 7167, 7231, 7295, 7359, 7423, 7487, 7551, 7615, 7679, 7743,
+       7807, 7871, 7935, 7999, 8063, 8127, 8191
+} };
+
+const struct ipu3_uapi_csc_mat_config ipu3_css_csc_defaults = {
+        4898,  9617,  1867, 0,
+       -2410, -4732,  7143, 0,
+       10076, -8437, -1638, 0
+};
+
+const struct ipu3_uapi_cds_params ipu3_css_cds_defaults = {
+       1, 3, 3, 1,
+       1, 3, 3, 1,
+       4, X,                                   /* ds_nf */
+       1,                                      /* csc_en */
+       0, X                                    /* uv_bin_output */
+};
+
+const struct ipu3_uapi_shd_config_static ipu3_css_shd_defaults = {
+       .grid = {
+               .width = 73,
+               .height = 55,
+               .block_width_log2 = 7,
+               .block_height_log2 = 7,
+               .x_start = 0,
+               .y_start = 0,
+       },
+       .general = {
+               .shd_enable = 1,
+               .gain_factor = 0,
+       },
+       .black_level = {
+               .bl_r = 0,
+               .bl_gr = 0 | (0 << IPU3_UAPI_SHD_BLGR_NF_SHIFT),
+               .bl_gb = 0,
+               .bl_b = 0,
+       },
+};
+
+const struct ipu3_uapi_yuvp1_iefd_config ipu3_css_iefd_defaults = {
+       .units = {
+               .cu_1 = { 0, 150, 7, 0 },
+               .cu_ed = { 7, 110, 244, X, 307, 409, 511, X,
+                          184, 255, 255, X, 0, 0, X,
+                          7, 81, 255, X, 255, 255, X },
+               .cu_3 = { 148, 251, 10, 0 },
+               .cu_5 = { 25, 70, 501, X, 32, X },
+               .cu_6 = { 32, 63, 183, X, 397,
+                         33, 0, X, 0,
+                         0, 64, X, 64, X },
+               .cu_7 = { 200, 303,
+                         10, 0 },
+               .cu_unsharp = { 10, 64, 110, X, 511,
+                               66, 12, X, 0,
+                               0, 56, X, 64, X },
+               .cu_radial = { 6, 203, 255, 255, 255, 255, X,
+                             84, 444, 397, 288, 300, X,
+                              4, 69, 207, X, 369, 448, X },
+               .cu_vssnlm = { 61, 100, 25, 0}
+       },
+       .config = { 45, X, 0, X, 16, X, 45, X },
+       .control = { 1, 1, 1, 1, 1, X },
+       .sharp = { { 50, X, 511, X, 50, X, 50, X },
+                  { 64, X, 0, X, 0, X},
+                  { 56, X, 56, X } },
+       .unsharp = { { 36, 17, 8, X },
+                    { 13, 7, 3, X } },
+       .rad = { { -2104, X, -1559, X },
+                { 4426816, X },
+                { 2430481, X },
+                { 6, X, 79, X },
+                { 64, 0, 0, X },
+                { 1, X, 2, X, 0, X, 0, X },
+                { 40, X, 62, X } },
+       .vsslnm = { { 16, 32, 64, X },
+                   { 1, X, 2, X,  8, X } },
+};
+
+const struct ipu3_uapi_yuvp1_yds_config ipu3_css_yds_defaults = {
+       0, 1, 1, 0, 0, 1, 1, 0, 2, X, 0, X
+};
+
+const struct ipu3_uapi_yuvp1_chnr_config ipu3_css_chnr_defaults = {
+       .coring = { 0, X, 0, X },
+       .sense_gain = { 6, 6, 6, X, 4, 4, 4, X },
+       .iir_fir = { 8, X, 12, X, 0, 256 - 127, X },
+};
+
+const struct ipu3_uapi_yuvp1_y_ee_nr_config ipu3_css_y_ee_nr_defaults = {
+       .lpf = { 4, X, 8, X, 16, X,  0 },
+       .sense = { 8191, X, 0, X, 8191, X, 0, X },
+       .gain = { 8, X, 0, X, 8, X, 0, X },
+       .clip = { 8, X, 0, X, 8, X, 0, X },
+       .frng = { 2, X, 200, X, 2, X, 1, 1, X },
+       .diag = { 1, X, 4, 1, 1, 4, X },
+       .fc_coring = { 0, X, 0, X, 0, X, 0, X }
+};
+
+const struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config
+                                       ipu3_css_tcc_gain_pcwl_lut = { {
+       1024, 1032, 1040, 1048, 1057, 1065, 1073, 1081, 1089, 1097, 1105, 1113,
+       1122, 1130, 1138, 1146, 1154, 1162, 1170, 1178, 1187, 1195, 1203, 1211,
+       1219, 1227, 1235, 1243, 1252, 1260, 1268, 1276, 1284, 1292, 1300, 1308,
+       1317, 1325, 1333, 1341, 1349, 1357, 1365, 1373, 1382, 1390, 1398, 1406,
+       1414, 1422, 1430, 1438, 1447, 1455, 1463, 1471, 1479, 1487, 1495, 1503,
+       1512, 1520, 1528, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536,
+       1536, 1536, 1528, 1520, 1512, 1503, 1495, 1487, 1479, 1471, 1463, 1455,
+       1447, 1438, 1430, 1422, 1414, 1406, 1398, 1390, 1382, 1373, 1365, 1357,
+       1349, 1341, 1333, 1325, 1317, 1308, 1300, 1292, 1284, 1276, 1268, 1260,
+       1252, 1243, 1235, 1227, 1219, 1211, 1203, 1195, 1187, 1178, 1170, 1162,
+       1154, 1146, 1138, 1130, 1122, 1113, 1105, 1097, 1089, 1081, 1073, 1065,
+       1057, 1048, 1040, 1032, 1024
+} };
+
+const struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config
+                                       ipu3_css_tcc_r_sqr_lut = { {
+       32, 44, 64, 92, 128, 180, 256, 364, 512, 628, 724, 808, 888,
+       956, 1024, 1088, 1144, 1200, 1256, 1304, 1356, 1404, 1448
+} };
+
+const struct imgu_abi_anr_config ipu3_css_anr_defaults = {
+       .transform = {
+               .adaptive_treshhold_en = 1,
+               .alpha = { { 13, 13, 13, 13, 0, 0, 0, 0},
+                          { 11, 11, 11, 11, 0, 0, 0, 0},
+                          { 14,  14, 14, 14, 0, 0, 0, 0} },
+               .beta = { { 24, 24, 24, 24},
+                         { 21, 20, 20, 21},
+                         { 25, 25, 25, 25} },
+               .color = { { { 166, 173, 149, 166, 161, 146, 145, 173,
+                              145, 150, 141, 149, 145, 141, 142 },
+                            { 166, 173, 149, 165, 161, 145, 145, 173,
+                              145, 150, 141, 149, 145, 141, 142 },
+                            { 166, 174, 149, 166, 162, 146, 146, 173,
+                              145, 150, 141, 149, 145, 141, 142 },
+                            { 166, 173, 149, 165, 161, 145, 145, 173,
+                              146, 150, 141, 149, 145, 141, 142 } },
+                          { { 141, 131, 140, 141, 144, 143, 144, 131,
+                              143, 137, 140, 140, 144, 140, 141 },
+                            { 141, 131, 140, 141, 143, 143, 144, 131,
+                              143, 137, 140, 140, 144, 140, 141 },
+                            { 141, 131, 141, 141, 144, 144, 144, 131,
+                              143, 137, 140, 140, 144, 140, 141 },
+                            { 140, 131, 140, 141, 143, 143, 144, 131,
+                              143, 137, 140, 140, 144, 140, 141 } },
+                          { { 184, 173, 188, 184, 182, 182, 181, 173,
+                              182, 179, 182, 188, 181, 182, 180 },
+                            { 184, 173, 188, 184, 183, 182, 181, 173,
+                              182, 178, 182, 188, 181, 182, 180 },
+                            { 184, 173, 188, 184, 182, 182, 181, 173,
+                              182, 178, 182, 188, 181, 182, 181 },
+                            { 184, 172, 188, 184, 182, 182, 181, 173,
+                              182, 178, 182, 188, 182, 182, 180 } } },
+               .sqrt_lut = { 724, 768, 810, 849, 887, 923, 958, 991, 1024,
+                             1056, 1086, 1116, 1145, 1173, 1201, 1228, 1254,
+                             1280, 1305, 1330, 1355, 1379, 1402, 1425, 1448 },
+               .xreset = -1632,
+               .yreset = -1224,
+               .x_sqr_reset = 2663424,
+               .r_normfactor = 14,
+               .y_sqr_reset = 1498176,
+               .gain_scale = 115
+       },
+       .stitch = {
+               .anr_stitch_en = 1,
+               .pyramid = { { 1, 3, 5 }, { 7, 7, 5 }, { 3, 1, 3 },
+                            { 9, 15, 21 }, { 21, 15, 9 }, { 3, 5, 15 },
+                            { 25, 35, 35 }, { 25, 15, 5 }, { 7, 21, 35 },
+                            { 49, 49, 35 }, { 21, 7, 7 }, { 21, 35, 49 },
+                            { 49, 35, 21 }, { 7, 5, 15 }, { 25, 35, 35 },
+                            { 25, 15, 5 }, { 3, 9, 15 }, { 21, 21, 15 },
+                            { 9, 3, 1 }, { 3, 5, 7 }, { 7, 5, 3}, { 1 }
+               }
+       }
+};
+
+/* frame settings for Auto White Balance */
+const struct ipu3_uapi_awb_fr_config_s ipu3_css_awb_fr_defaults = {
+       .grid_cfg = {
+               .width = 16,
+               .height = 16,
+               .block_width_log2 = 3,
+               .block_height_log2 = 3,
+               .x_start = 10,
+               .y_start = 2 | IPU3_UAPI_GRID_Y_START_EN,
+       },
+       .bayer_coeff = { 0, 0, 0, 0, 0, 128 },
+       .bayer_sign = 0,
+       .bayer_nf = 7
+};
+
+/* settings for Auto Exposure */
+const struct ipu3_uapi_ae_grid_config ipu3_css_ae_grid_defaults = {
+       .width = 16,
+       .height = 16,
+       .block_width_log2 = 3,
+       .block_height_log2 = 3,
+       .ae_en = 1,
+       .x_start = 0,
+       .y_start = 0,
+};
+
+/* settings for Auto Exposure color correction matrix */
+const struct ipu3_uapi_ae_ccm ipu3_css_ae_ccm_defaults = {
+       256, 256, 256, 256,             /* gain_gr/r/b/gb */
+       .mat = { 128, 0, 0, 0, 0, 128, 0, 0, 0, 0, 128, 0, 0, 0, 0, 128 },
+};
+
+/* settings for Auto Focus */
+const struct ipu3_uapi_af_config_s ipu3_css_af_defaults = {
+       .filter_config = {
+               { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 128 }, 0,
+               { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 128 }, 0,
+               .y_calc = { 8, 8, 8, 8 },
+               .nf = { X, 7, X, 7 },
+       },
+       .grid_cfg = {
+               .width = 16,
+               .height = 16,
+               .block_width_log2 = 3,
+               .block_height_log2 = 3,
+               .x_start = 10,
+               .y_start = 2 | IPU3_UAPI_GRID_Y_START_EN,
+       },
+};
+
+/* settings for Auto White Balance */
+const struct ipu3_uapi_awb_config_s ipu3_css_awb_defaults = {
+       8191, 8191, 8191, 8191 |        /* rgbs_thr_gr/r/gb/b */
+       IPU3_UAPI_AWB_RGBS_THR_B_EN | IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT,
+       .grid = {
+               .width = 16,
+               .height = 16,
+               .block_width_log2 = 3,
+               .block_height_log2 = 3,
+               .x_start = 0,
+               .y_start = 0,
+       },
+};
diff --git a/drivers/staging/media/ipu3/ipu3-tables.h b/drivers/staging/media/ipu3/ipu3-tables.h
new file mode 100644 (file)
index 0000000..6563782
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_TABLES_H
+#define __IPU3_TABLES_H
+
+#include "ipu3-abi.h"
+
+#define IMGU_BDS_GRANULARITY           32      /* Downscaling granularity */
+#define IMGU_BDS_MIN_SF_INV            IMGU_BDS_GRANULARITY
+#define IMGU_BDS_CONFIG_LEN            97
+
+#define IMGU_SCALER_DOWNSCALE_4TAPS_LEN        128
+#define IMGU_SCALER_DOWNSCALE_2TAPS_LEN        64
+#define IMGU_SCALER_FP                 ((u32)1 << 31) /* 1.0 in fixed point */
+
+#define IMGU_XNR3_VMEM_LUT_LEN         16
+
+#define IMGU_GDC_LUT_UNIT              4
+#define IMGU_GDC_LUT_LEN               256
+
+struct ipu3_css_bds_config {
+       struct imgu_abi_bds_phase_arr hor_phase_arr;
+       struct imgu_abi_bds_phase_arr ver_phase_arr;
+       struct imgu_abi_bds_ptrn_arr ptrn_arr;
+       u16 sample_patrn_length;
+       u8 hor_ds_en;
+       u8 ver_ds_en;
+};
+
+struct ipu3_css_xnr3_vmem_defaults {
+       s16 x[IMGU_XNR3_VMEM_LUT_LEN];
+       s16 a[IMGU_XNR3_VMEM_LUT_LEN];
+       s16 b[IMGU_XNR3_VMEM_LUT_LEN];
+       s16 c[IMGU_XNR3_VMEM_LUT_LEN];
+};
+
+extern const struct ipu3_css_bds_config
+                       ipu3_css_bds_configs[IMGU_BDS_CONFIG_LEN];
+extern const s32 ipu3_css_downscale_4taps[IMGU_SCALER_DOWNSCALE_4TAPS_LEN];
+extern const s32 ipu3_css_downscale_2taps[IMGU_SCALER_DOWNSCALE_2TAPS_LEN];
+extern const s16 ipu3_css_gdc_lut[IMGU_GDC_LUT_UNIT][IMGU_GDC_LUT_LEN];
+extern const struct ipu3_css_xnr3_vmem_defaults ipu3_css_xnr3_vmem_defaults;
+extern const struct ipu3_uapi_bnr_static_config ipu3_css_bnr_defaults;
+extern const struct ipu3_uapi_dm_config ipu3_css_dm_defaults;
+extern const struct ipu3_uapi_ccm_mat_config ipu3_css_ccm_defaults;
+extern const struct ipu3_uapi_gamma_corr_lut ipu3_css_gamma_lut;
+extern const struct ipu3_uapi_csc_mat_config ipu3_css_csc_defaults;
+extern const struct ipu3_uapi_cds_params ipu3_css_cds_defaults;
+extern const struct ipu3_uapi_shd_config_static ipu3_css_shd_defaults;
+extern const struct ipu3_uapi_yuvp1_iefd_config ipu3_css_iefd_defaults;
+extern const struct ipu3_uapi_yuvp1_yds_config ipu3_css_yds_defaults;
+extern const struct ipu3_uapi_yuvp1_chnr_config ipu3_css_chnr_defaults;
+extern const struct ipu3_uapi_yuvp1_y_ee_nr_config ipu3_css_y_ee_nr_defaults;
+extern const struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config
+                                               ipu3_css_tcc_gain_pcwl_lut;
+extern const struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config
+                                               ipu3_css_tcc_r_sqr_lut;
+extern const struct imgu_abi_anr_config ipu3_css_anr_defaults;
+extern const struct ipu3_uapi_awb_fr_config_s ipu3_css_awb_fr_defaults;
+extern const struct ipu3_uapi_ae_grid_config ipu3_css_ae_grid_defaults;
+extern const struct ipu3_uapi_ae_ccm ipu3_css_ae_ccm_defaults;
+extern const struct ipu3_uapi_af_config_s ipu3_css_af_defaults;
+extern const struct ipu3_uapi_awb_config_s ipu3_css_awb_defaults;
+
+#endif
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
new file mode 100644 (file)
index 0000000..c793603
--- /dev/null
@@ -0,0 +1,1419 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "ipu3.h"
+#include "ipu3-dmamap.h"
+
+/******************** v4l2_subdev_ops ********************/
+
+static int ipu3_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[imgu_sd->pipe];
+       struct v4l2_rect try_crop = {
+               .top = 0,
+               .left = 0,
+       };
+       unsigned int i;
+
+       try_crop.width =
+               imgu_pipe->nodes[IMGU_NODE_IN].vdev_fmt.fmt.pix_mp.width;
+       try_crop.height =
+               imgu_pipe->nodes[IMGU_NODE_IN].vdev_fmt.fmt.pix_mp.height;
+
+       /* Initialize try_fmt */
+       for (i = 0; i < IMGU_NODE_NUM; i++) {
+               struct v4l2_mbus_framefmt *try_fmt =
+                       v4l2_subdev_get_try_format(sd, fh->pad, i);
+
+               try_fmt->width = try_crop.width;
+               try_fmt->height = try_crop.height;
+               try_fmt->code = imgu_pipe->nodes[i].pad_fmt.code;
+               try_fmt->field = V4L2_FIELD_NONE;
+       }
+
+       *v4l2_subdev_get_try_crop(sd, fh->pad, IMGU_NODE_IN) = try_crop;
+       *v4l2_subdev_get_try_compose(sd, fh->pad, IMGU_NODE_IN) = try_crop;
+
+       return 0;
+}
+
+static int ipu3_subdev_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       int i;
+       unsigned int node;
+       int r = 0;
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+       unsigned int pipe = imgu_sd->pipe;
+       struct device *dev = &imgu->pci_dev->dev;
+       struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
+       struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
+       struct ipu3_css_pipe *css_pipe = &imgu->css.pipes[pipe];
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       dev_dbg(dev, "%s %d for pipe %d", __func__, enable, pipe);
+       /* grab ctrl after streamon and return after off */
+       v4l2_ctrl_grab(imgu_sd->ctrl, enable);
+
+       if (!enable) {
+               imgu_sd->active = false;
+               return 0;
+       }
+
+       for (i = 0; i < IMGU_NODE_NUM; i++)
+               imgu_pipe->queue_enabled[i] = imgu_pipe->nodes[i].enabled;
+
+       /* This is handled specially */
+       imgu_pipe->queue_enabled[IPU3_CSS_QUEUE_PARAMS] = false;
+
+       /* Initialize CSS formats */
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               node = imgu_map_node(imgu, i);
+               /* No need to reconfig meta nodes */
+               if (node == IMGU_NODE_STAT_3A || node == IMGU_NODE_PARAMS)
+                       continue;
+               fmts[i] = imgu_pipe->queue_enabled[node] ?
+                       &imgu_pipe->nodes[node].vdev_fmt.fmt.pix_mp : NULL;
+       }
+
+       /* Enable VF output only when VF queue requested by user */
+       css_pipe->vf_output_en = false;
+       if (imgu_pipe->nodes[IMGU_NODE_VF].enabled)
+               css_pipe->vf_output_en = true;
+
+       if (atomic_read(&imgu_sd->running_mode) == IPU3_RUNNING_MODE_VIDEO)
+               css_pipe->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
+       else
+               css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
+
+       dev_dbg(dev, "IPU3 pipe %d pipe_id %d", pipe, css_pipe->pipe_id);
+
+       rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_sd->rect.eff;
+       rects[IPU3_CSS_RECT_BDS] = &imgu_sd->rect.bds;
+       rects[IPU3_CSS_RECT_GDC] = &imgu_sd->rect.gdc;
+
+       r = ipu3_css_fmt_set(&imgu->css, fmts, rects, pipe);
+       if (r) {
+               dev_err(dev, "failed to set initial formats pipe %d with (%d)",
+                       pipe, r);
+               return r;
+       }
+
+       imgu_sd->active = true;
+
+       return 0;
+}
+
+static int ipu3_subdev_get_fmt(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_format *fmt)
+{
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *mf;
+       struct imgu_media_pipe *imgu_pipe;
+       u32 pad = fmt->pad;
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+       unsigned int pipe = imgu_sd->pipe;
+
+       imgu_pipe = &imgu->imgu_pipe[pipe];
+       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               fmt->format = imgu_pipe->nodes[pad].pad_fmt;
+       } else {
+               mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+               fmt->format = *mf;
+       }
+
+       return 0;
+}
+
+static int ipu3_subdev_set_fmt(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_format *fmt)
+{
+       struct imgu_media_pipe *imgu_pipe;
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+
+       struct v4l2_mbus_framefmt *mf;
+       u32 pad = fmt->pad;
+       unsigned int pipe = imgu_sd->pipe;
+
+       dev_dbg(&imgu->pci_dev->dev, "set subdev %d pad %d fmt to [%dx%d]",
+               pipe, pad, fmt->format.width, fmt->format.height);
+
+       imgu_pipe = &imgu->imgu_pipe[pipe];
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+               mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+       else
+               mf = &imgu_pipe->nodes[pad].pad_fmt;
+
+       fmt->format.code = mf->code;
+       /* Clamp the w and h based on the hardware capabilities */
+       if (imgu_sd->subdev_pads[pad].flags & MEDIA_PAD_FL_SOURCE) {
+               fmt->format.width = clamp(fmt->format.width,
+                                         IPU3_OUTPUT_MIN_WIDTH,
+                                         IPU3_OUTPUT_MAX_WIDTH);
+               fmt->format.height = clamp(fmt->format.height,
+                                          IPU3_OUTPUT_MIN_HEIGHT,
+                                          IPU3_OUTPUT_MAX_HEIGHT);
+       } else {
+               fmt->format.width = clamp(fmt->format.width,
+                                         IPU3_INPUT_MIN_WIDTH,
+                                         IPU3_INPUT_MAX_WIDTH);
+               fmt->format.height = clamp(fmt->format.height,
+                                          IPU3_INPUT_MIN_HEIGHT,
+                                          IPU3_INPUT_MAX_HEIGHT);
+       }
+
+       *mf = fmt->format;
+
+       return 0;
+}
+
+static int ipu3_subdev_get_selection(struct v4l2_subdev *sd,
+                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_selection *sel)
+{
+       struct v4l2_rect *try_sel, *r;
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+
+       if (sel->pad != IMGU_NODE_IN)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               r = &imgu_sd->rect.eff;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               r = &imgu_sd->rect.bds;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+               sel->r = *try_sel;
+       else
+               sel->r = *r;
+
+       return 0;
+}
+
+static int ipu3_subdev_set_selection(struct v4l2_subdev *sd,
+                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_selection *sel)
+{
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+       struct v4l2_rect *rect, *try_sel;
+
+       dev_dbg(&imgu->pci_dev->dev,
+                "set subdev %d sel which %d target 0x%4x rect [%dx%d]",
+                imgu_sd->pipe, sel->which, sel->target,
+                sel->r.width, sel->r.height);
+
+       if (sel->pad != IMGU_NODE_IN)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               rect = &imgu_sd->rect.eff;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               rect = &imgu_sd->rect.bds;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+               *try_sel = sel->r;
+       else
+               *rect = sel->r;
+
+       return 0;
+}
+
+/******************** media_entity_operations ********************/
+
+static int ipu3_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct imgu_media_pipe *imgu_pipe;
+       struct v4l2_subdev *sd = container_of(entity, struct v4l2_subdev,
+                                             entity);
+       struct imgu_device *imgu = v4l2_get_subdevdata(sd);
+       struct imgu_v4l2_subdev *imgu_sd = container_of(sd,
+                                                       struct imgu_v4l2_subdev,
+                                                       subdev);
+       unsigned int pipe = imgu_sd->pipe;
+       u32 pad = local->index;
+
+       WARN_ON(pad >= IMGU_NODE_NUM);
+
+       dev_dbg(&imgu->pci_dev->dev, "pipe %d pad %d is %s", pipe, pad,
+                flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled");
+
+       imgu_pipe = &imgu->imgu_pipe[pipe];
+       imgu_pipe->nodes[pad].enabled = flags & MEDIA_LNK_FL_ENABLED;
+
+       /* enable input node to enable the pipe */
+       if (pad != IMGU_NODE_IN)
+               return 0;
+
+       if (flags & MEDIA_LNK_FL_ENABLED)
+               __set_bit(pipe, imgu->css.enabled_pipes);
+       else
+               __clear_bit(pipe, imgu->css.enabled_pipes);
+
+       dev_dbg(&imgu->pci_dev->dev, "pipe %d is %s", pipe,
+                flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled");
+
+       return 0;
+}
+
+/******************** vb2_ops ********************/
+
+static int ipu3_vb2_buf_init(struct vb2_buffer *vb)
+{
+       struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+       struct imgu_device *imgu = vb2_get_drv_priv(vb->vb2_queue);
+       struct imgu_buffer *buf = container_of(vb,
+               struct imgu_buffer, vid_buf.vbb.vb2_buf);
+       struct imgu_video_device *node =
+               container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+       unsigned int queue = imgu_node_to_queue(node->id);
+
+       if (queue == IPU3_CSS_QUEUE_PARAMS)
+               return 0;
+
+       return ipu3_dmamap_map_sg(imgu, sg->sgl, sg->nents, &buf->map);
+}
+
+/* Called when each buffer is freed */
+static void ipu3_vb2_buf_cleanup(struct vb2_buffer *vb)
+{
+       struct imgu_device *imgu = vb2_get_drv_priv(vb->vb2_queue);
+       struct imgu_buffer *buf = container_of(vb,
+               struct imgu_buffer, vid_buf.vbb.vb2_buf);
+       struct imgu_video_device *node =
+               container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+       unsigned int queue = imgu_node_to_queue(node->id);
+
+       if (queue == IPU3_CSS_QUEUE_PARAMS)
+               return;
+
+       ipu3_dmamap_unmap(imgu, &buf->map);
+}
+
+/* Transfer buffer ownership to me */
+static void ipu3_vb2_buf_queue(struct vb2_buffer *vb)
+{
+       struct imgu_device *imgu = vb2_get_drv_priv(vb->vb2_queue);
+       struct imgu_video_device *node =
+               container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+       unsigned int queue = imgu_node_to_queue(node->id);
+       unsigned long need_bytes;
+       unsigned int pipe = node->pipe;
+
+       if (vb->vb2_queue->type == V4L2_BUF_TYPE_META_CAPTURE ||
+           vb->vb2_queue->type == V4L2_BUF_TYPE_META_OUTPUT)
+               need_bytes = node->vdev_fmt.fmt.meta.buffersize;
+       else
+               need_bytes = node->vdev_fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+       if (queue == IPU3_CSS_QUEUE_PARAMS) {
+               unsigned long payload = vb2_get_plane_payload(vb, 0);
+               struct vb2_v4l2_buffer *buf =
+                       container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+               int r = -EINVAL;
+
+               if (payload == 0) {
+                       payload = need_bytes;
+                       vb2_set_plane_payload(vb, 0, payload);
+               }
+               if (payload >= need_bytes)
+                       r = ipu3_css_set_parameters(&imgu->css, pipe,
+                                                   vb2_plane_vaddr(vb, 0));
+               buf->flags = V4L2_BUF_FLAG_DONE;
+               vb2_buffer_done(vb, r == 0 ? VB2_BUF_STATE_DONE
+                                          : VB2_BUF_STATE_ERROR);
+
+       } else {
+               struct imgu_buffer *buf = container_of(vb, struct imgu_buffer,
+                                                      vid_buf.vbb.vb2_buf);
+
+               mutex_lock(&imgu->lock);
+               ipu3_css_buf_init(&buf->css_buf, queue, buf->map.daddr);
+               list_add_tail(&buf->vid_buf.list,
+                             &node->buffers);
+               mutex_unlock(&imgu->lock);
+
+               vb2_set_plane_payload(&buf->vid_buf.vbb.vb2_buf, 0, need_bytes);
+
+               if (imgu->streaming)
+                       imgu_queue_buffers(imgu, false, pipe);
+       }
+
+       dev_dbg(&imgu->pci_dev->dev, "%s for pipe %d node %d", __func__,
+               node->pipe, node->id);
+
+}
+
+static int ipu3_vb2_queue_setup(struct vb2_queue *vq,
+                               unsigned int *num_buffers,
+                               unsigned int *num_planes,
+                               unsigned int sizes[],
+                               struct device *alloc_devs[])
+{
+       struct imgu_device *imgu = vb2_get_drv_priv(vq);
+       struct imgu_video_device *node =
+               container_of(vq, struct imgu_video_device, vbq);
+       const struct v4l2_format *fmt = &node->vdev_fmt;
+       unsigned int size;
+
+       *num_buffers = clamp_val(*num_buffers, 1, VB2_MAX_FRAME);
+       alloc_devs[0] = &imgu->pci_dev->dev;
+
+       if (vq->type == V4L2_BUF_TYPE_META_CAPTURE ||
+           vq->type == V4L2_BUF_TYPE_META_OUTPUT)
+               size = fmt->fmt.meta.buffersize;
+       else
+               size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+       if (*num_planes) {
+               if (sizes[0] < size)
+                       return -EINVAL;
+               size = sizes[0];
+       }
+
+       *num_planes = 1;
+       sizes[0] = size;
+
+       /* Initialize buffer queue */
+       INIT_LIST_HEAD(&node->buffers);
+
+       return 0;
+}
+
+/* Check if all enabled video nodes are streaming, exception ignored */
+static bool ipu3_all_nodes_streaming(struct imgu_device *imgu,
+                                    struct imgu_video_device *except)
+{
+       unsigned int i, pipe, p;
+       struct imgu_video_device *node;
+       struct device *dev = &imgu->pci_dev->dev;
+
+       pipe = except->pipe;
+       if (!test_bit(pipe, imgu->css.enabled_pipes)) {
+               dev_warn(&imgu->pci_dev->dev,
+                        "pipe %d link is not ready yet", pipe);
+               return false;
+       }
+
+       for_each_set_bit(p, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               for (i = 0; i < IMGU_NODE_NUM; i++) {
+                       node = &imgu->imgu_pipe[p].nodes[i];
+                       dev_dbg(dev, "%s pipe %u queue %u name %s enabled = %u",
+                               __func__, p, i, node->name, node->enabled);
+                       if (node == except)
+                               continue;
+                       if (node->enabled && !vb2_start_streaming_called(&node->vbq))
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+static void ipu3_return_all_buffers(struct imgu_device *imgu,
+                                   struct imgu_video_device *node,
+                                   enum vb2_buffer_state state)
+{
+       struct ipu3_vb2_buffer *b, *b0;
+
+       /* Return all buffers */
+       mutex_lock(&imgu->lock);
+       list_for_each_entry_safe(b, b0, &node->buffers, list) {
+               list_del(&b->list);
+               vb2_buffer_done(&b->vbb.vb2_buf, state);
+       }
+       mutex_unlock(&imgu->lock);
+}
+
+static int ipu3_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct imgu_media_pipe *imgu_pipe;
+       struct imgu_device *imgu = vb2_get_drv_priv(vq);
+       struct device *dev = &imgu->pci_dev->dev;
+       struct imgu_video_device *node =
+               container_of(vq, struct imgu_video_device, vbq);
+       int r;
+       unsigned int pipe;
+
+       dev_dbg(dev, "%s node name %s pipe %d id %u", __func__,
+               node->name, node->pipe, node->id);
+
+       if (imgu->streaming) {
+               r = -EBUSY;
+               goto fail_return_bufs;
+       }
+
+       if (!node->enabled) {
+               dev_err(dev, "IMGU node is not enabled");
+               r = -EINVAL;
+               goto fail_return_bufs;
+       }
+
+       pipe = node->pipe;
+       imgu_pipe = &imgu->imgu_pipe[pipe];
+       r = media_pipeline_start(&node->vdev.entity, &imgu_pipe->pipeline);
+       if (r < 0)
+               goto fail_return_bufs;
+
+
+       if (!ipu3_all_nodes_streaming(imgu, node))
+               return 0;
+
+       for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = v4l2_subdev_call(&imgu->imgu_pipe[pipe].imgu_sd.subdev,
+                                    video, s_stream, 1);
+               if (r < 0)
+                       goto fail_stop_pipeline;
+       }
+
+       /* Start streaming of the whole pipeline now */
+       dev_dbg(dev, "IMGU streaming is ready to start");
+       r = imgu_s_stream(imgu, true);
+       if (!r)
+               imgu->streaming = true;
+
+       return 0;
+
+fail_stop_pipeline:
+       media_pipeline_stop(&node->vdev.entity);
+fail_return_bufs:
+       ipu3_return_all_buffers(imgu, node, VB2_BUF_STATE_QUEUED);
+
+       return r;
+}
+
+static void ipu3_vb2_stop_streaming(struct vb2_queue *vq)
+{
+       struct imgu_media_pipe *imgu_pipe;
+       struct imgu_device *imgu = vb2_get_drv_priv(vq);
+       struct device *dev = &imgu->pci_dev->dev;
+       struct imgu_video_device *node =
+               container_of(vq, struct imgu_video_device, vbq);
+       int r;
+       unsigned int pipe;
+
+       WARN_ON(!node->enabled);
+
+       pipe = node->pipe;
+       dev_dbg(dev, "Try to stream off node [%d][%d]", pipe, node->id);
+       imgu_pipe = &imgu->imgu_pipe[pipe];
+       r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0);
+       if (r)
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to stop subdev streaming\n");
+
+       /* Was this the first node with streaming disabled? */
+       if (imgu->streaming && ipu3_all_nodes_streaming(imgu, node)) {
+               /* Yes, really stop streaming now */
+               dev_dbg(dev, "IMGU streaming is ready to stop");
+               r = imgu_s_stream(imgu, false);
+               if (!r)
+                       imgu->streaming = false;
+       }
+
+       ipu3_return_all_buffers(imgu, node, VB2_BUF_STATE_ERROR);
+       media_pipeline_stop(&node->vdev.entity);
+}
+
+/******************** v4l2_ioctl_ops ********************/
+
+#define VID_CAPTURE    0
+#define VID_OUTPUT     1
+#define DEF_VID_CAPTURE        0
+#define DEF_VID_OUTPUT 1
+
+struct ipu3_fmt {
+       u32     fourcc;
+       u16     type; /* VID_CAPTURE or VID_OUTPUT not both */
+};
+
+/* format descriptions for capture and preview */
+static const struct ipu3_fmt formats[] = {
+       { V4L2_PIX_FMT_NV12, VID_CAPTURE },
+       { V4L2_PIX_FMT_IPU3_SGRBG10, VID_OUTPUT },
+       { V4L2_PIX_FMT_IPU3_SBGGR10, VID_OUTPUT },
+       { V4L2_PIX_FMT_IPU3_SGBRG10, VID_OUTPUT },
+       { V4L2_PIX_FMT_IPU3_SRGGB10, VID_OUTPUT },
+};
+
+/* Find the first matched format, return default if not found */
+static const struct ipu3_fmt *find_format(struct v4l2_format *f, u32 type)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(formats); i++) {
+               if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+                   formats[i].type == type)
+                       return &formats[i];
+       }
+
+       return type == VID_CAPTURE ? &formats[DEF_VID_CAPTURE] :
+                                    &formats[DEF_VID_OUTPUT];
+}
+
+static int ipu3_vidioc_querycap(struct file *file, void *fh,
+                               struct v4l2_capability *cap)
+{
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+       strscpy(cap->driver, IMGU_NAME, sizeof(cap->driver));
+       strscpy(cap->card, IMGU_NAME, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", node->name);
+
+       return 0;
+}
+
+static int enum_fmts(struct v4l2_fmtdesc *f, u32 type)
+{
+       unsigned int i, j;
+
+       for (i = j = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].type == type) {
+                       if (j == f->index)
+                               break;
+                       ++j;
+               }
+       }
+
+       if (i < ARRAY_SIZE(formats)) {
+               f->pixelformat = formats[i].fourcc;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return -EINVAL;
+
+       return enum_fmts(f, VID_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       return enum_fmts(f, VID_OUTPUT);
+}
+
+/* Propagate forward always the format from the CIO2 subdev */
+static int ipu3_vidioc_g_fmt(struct file *file, void *fh,
+                            struct v4l2_format *f)
+{
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+       f->fmt = node->vdev_fmt.fmt;
+
+       return 0;
+}
+
+/*
+ * Set input/output format. Unless it is just a try, this also resets
+ * selections (ie. effective and BDS resolutions) to defaults.
+ */
+static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
+                   struct v4l2_format *f, bool try)
+{
+       struct device *dev = &imgu->pci_dev->dev;
+       struct v4l2_pix_format_mplane try_fmts[IPU3_CSS_QUEUES];
+       struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
+       struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
+       struct v4l2_mbus_framefmt pad_fmt;
+       unsigned int i, css_q;
+       int r;
+       struct ipu3_css_pipe *css_pipe = &imgu->css.pipes[pipe];
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+       struct imgu_v4l2_subdev *imgu_sd = &imgu_pipe->imgu_sd;
+
+       dev_dbg(dev, "set fmt node [%u][%u](try = %d)", pipe, node, try);
+
+       for (i = 0; i < IMGU_NODE_NUM; i++)
+               dev_dbg(dev, "IMGU pipe %d node %d enabled = %d",
+                       pipe, i, imgu_pipe->nodes[i].enabled);
+
+       if (imgu_pipe->nodes[IMGU_NODE_VF].enabled)
+               css_pipe->vf_output_en = true;
+
+       if (atomic_read(&imgu_sd->running_mode) == IPU3_RUNNING_MODE_VIDEO)
+               css_pipe->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
+       else
+               css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
+
+       dev_dbg(dev, "IPU3 pipe %d pipe_id = %d", pipe, css_pipe->pipe_id);
+
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               unsigned int inode = imgu_map_node(imgu, i);
+
+               /* Skip the meta node */
+               if (inode == IMGU_NODE_STAT_3A || inode == IMGU_NODE_PARAMS)
+                       continue;
+
+               if (try) {
+                       try_fmts[i] =
+                               imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp;
+                       fmts[i] = &try_fmts[i];
+               } else {
+                       fmts[i] = &imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp;
+               }
+
+               /* CSS expects some format on OUT queue */
+               if (i != IPU3_CSS_QUEUE_OUT &&
+                   !imgu_pipe->nodes[inode].enabled)
+                       fmts[i] = NULL;
+       }
+
+       if (!try) {
+               /* eff and bds res got by imgu_s_sel */
+               struct imgu_v4l2_subdev *imgu_sd = &imgu_pipe->imgu_sd;
+
+               rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_sd->rect.eff;
+               rects[IPU3_CSS_RECT_BDS] = &imgu_sd->rect.bds;
+               rects[IPU3_CSS_RECT_GDC] = &imgu_sd->rect.gdc;
+
+               /* suppose that pad fmt was set by subdev s_fmt before */
+               pad_fmt = imgu_pipe->nodes[IMGU_NODE_IN].pad_fmt;
+               rects[IPU3_CSS_RECT_GDC]->width = pad_fmt.width;
+               rects[IPU3_CSS_RECT_GDC]->height = pad_fmt.height;
+       }
+
+       /*
+        * imgu doesn't set the node to the value given by user
+        * before we return success from this function, so set it here.
+        */
+       css_q = imgu_node_to_queue(node);
+       if (fmts[css_q])
+               *fmts[css_q] = f->fmt.pix_mp;
+       else
+               return -EINVAL;
+
+       if (try)
+               r = ipu3_css_fmt_try(&imgu->css, fmts, rects, pipe);
+       else
+               r = ipu3_css_fmt_set(&imgu->css, fmts, rects, pipe);
+
+       /* r is the binary number in the firmware blob */
+       if (r < 0)
+               return r;
+
+       if (try)
+               f->fmt.pix_mp = *fmts[css_q];
+       else
+               f->fmt = imgu_pipe->nodes[node].vdev_fmt.fmt;
+
+       return 0;
+}
+
+static int ipu3_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+       const struct ipu3_fmt *fmt;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               fmt = find_format(f, VID_CAPTURE);
+       else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               fmt = find_format(f, VID_OUTPUT);
+       else
+               return -EINVAL;
+
+       pixm->pixelformat = fmt->fourcc;
+
+       memset(pixm->plane_fmt[0].reserved, 0,
+              sizeof(pixm->plane_fmt[0].reserved));
+
+       return 0;
+}
+
+static int ipu3_vidioc_try_fmt(struct file *file, void *fh,
+                              struct v4l2_format *f)
+{
+       struct imgu_device *imgu = video_drvdata(file);
+       struct device *dev = &imgu->pci_dev->dev;
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       int r;
+
+       dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__,
+               pix_mp->width, pix_mp->height, node->id);
+
+       r = ipu3_try_fmt(file, fh, f);
+       if (r)
+               return r;
+
+       return imgu_fmt(imgu, node->pipe, node->id, f, true);
+}
+
+static int ipu3_vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct imgu_device *imgu = video_drvdata(file);
+       struct device *dev = &imgu->pci_dev->dev;
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       int r;
+
+       dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__,
+               pix_mp->width, pix_mp->height, node->id);
+
+       r = ipu3_try_fmt(file, fh, f);
+       if (r)
+               return r;
+
+       return imgu_fmt(imgu, node->pipe, node->id, f, false);
+}
+
+struct ipu3_meta_fmt {
+       __u32 fourcc;
+       char *name;
+};
+
+/* From drivers/media/v4l2-core/v4l2-ioctl.c */
+static const struct ipu3_meta_fmt meta_fmts[] = {
+       { V4L2_META_FMT_IPU3_PARAMS, "IPU3 processing parameters" },
+       { V4L2_META_FMT_IPU3_STAT_3A, "IPU3 3A statistics" },
+};
+
+static int ipu3_meta_enum_format(struct file *file, void *fh,
+                                struct v4l2_fmtdesc *fmt)
+{
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+       unsigned int i = fmt->type == V4L2_BUF_TYPE_META_OUTPUT ? 0 : 1;
+
+       /* Each node is dedicated to only one meta format */
+       if (fmt->index > 0 || fmt->type != node->vbq.type)
+               return -EINVAL;
+
+       strscpy(fmt->description, meta_fmts[i].name, sizeof(fmt->description));
+       fmt->pixelformat = meta_fmts[i].fourcc;
+
+       return 0;
+}
+
+static int ipu3_vidioc_g_meta_fmt(struct file *file, void *fh,
+                                 struct v4l2_format *f)
+{
+       struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+       if (f->type != node->vbq.type)
+               return -EINVAL;
+
+       f->fmt = node->vdev_fmt.fmt;
+
+       return 0;
+}
+
+static int ipu3_vidioc_enum_input(struct file *file, void *fh,
+                                 struct v4l2_input *input)
+{
+       if (input->index > 0)
+               return -EINVAL;
+       strscpy(input->name, "camera", sizeof(input->name));
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int ipu3_vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       *input = 0;
+
+       return 0;
+}
+
+static int ipu3_vidioc_s_input(struct file *file, void *fh, unsigned int input)
+{
+       return input == 0 ? 0 : -EINVAL;
+}
+
+static int ipu3_vidioc_enum_output(struct file *file, void *fh,
+                                  struct v4l2_output *output)
+{
+       if (output->index > 0)
+               return -EINVAL;
+       strscpy(output->name, "camera", sizeof(output->name));
+       output->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int ipu3_vidioc_g_output(struct file *file, void *fh,
+                               unsigned int *output)
+{
+       *output = 0;
+
+       return 0;
+}
+
+static int ipu3_vidioc_s_output(struct file *file, void *fh,
+                               unsigned int output)
+{
+       return output == 0 ? 0 : -EINVAL;
+}
+
+/******************** function pointers ********************/
+
+static struct v4l2_subdev_internal_ops ipu3_subdev_internal_ops = {
+       .open = ipu3_subdev_open,
+};
+
+static const struct v4l2_subdev_core_ops ipu3_subdev_core_ops = {
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops ipu3_subdev_video_ops = {
+       .s_stream = ipu3_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ipu3_subdev_pad_ops = {
+       .link_validate = v4l2_subdev_link_validate_default,
+       .get_fmt = ipu3_subdev_get_fmt,
+       .set_fmt = ipu3_subdev_set_fmt,
+       .get_selection = ipu3_subdev_get_selection,
+       .set_selection = ipu3_subdev_set_selection,
+};
+
+static const struct v4l2_subdev_ops ipu3_subdev_ops = {
+       .core = &ipu3_subdev_core_ops,
+       .video = &ipu3_subdev_video_ops,
+       .pad = &ipu3_subdev_pad_ops,
+};
+
+static const struct media_entity_operations ipu3_media_ops = {
+       .link_setup = ipu3_link_setup,
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+/****************** vb2_ops of the Q ********************/
+
+static const struct vb2_ops ipu3_vb2_ops = {
+       .buf_init = ipu3_vb2_buf_init,
+       .buf_cleanup = ipu3_vb2_buf_cleanup,
+       .buf_queue = ipu3_vb2_buf_queue,
+       .queue_setup = ipu3_vb2_queue_setup,
+       .start_streaming = ipu3_vb2_start_streaming,
+       .stop_streaming = ipu3_vb2_stop_streaming,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+};
+
+/****************** v4l2_file_operations *****************/
+
+static const struct v4l2_file_operations ipu3_v4l2_fops = {
+       .unlocked_ioctl = video_ioctl2,
+       .open = v4l2_fh_open,
+       .release = vb2_fop_release,
+       .poll = vb2_fop_poll,
+       .mmap = vb2_fop_mmap,
+};
+
+/******************** v4l2_ioctl_ops ********************/
+
+static const struct v4l2_ioctl_ops ipu3_v4l2_ioctl_ops = {
+       .vidioc_querycap = ipu3_vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap_mplane = ipu3_vidioc_g_fmt,
+       .vidioc_s_fmt_vid_cap_mplane = ipu3_vidioc_s_fmt,
+       .vidioc_try_fmt_vid_cap_mplane = ipu3_vidioc_try_fmt,
+
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out_mplane = ipu3_vidioc_g_fmt,
+       .vidioc_s_fmt_vid_out_mplane = ipu3_vidioc_s_fmt,
+       .vidioc_try_fmt_vid_out_mplane = ipu3_vidioc_try_fmt,
+
+       .vidioc_enum_output = ipu3_vidioc_enum_output,
+       .vidioc_g_output = ipu3_vidioc_g_output,
+       .vidioc_s_output = ipu3_vidioc_s_output,
+
+       .vidioc_enum_input = ipu3_vidioc_enum_input,
+       .vidioc_g_input = ipu3_vidioc_g_input,
+       .vidioc_s_input = ipu3_vidioc_s_input,
+
+       /* buffer queue management */
+       .vidioc_reqbufs = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf = vb2_ioctl_querybuf,
+       .vidioc_qbuf = vb2_ioctl_qbuf,
+       .vidioc_dqbuf = vb2_ioctl_dqbuf,
+       .vidioc_streamon = vb2_ioctl_streamon,
+       .vidioc_streamoff = vb2_ioctl_streamoff,
+       .vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static const struct v4l2_ioctl_ops ipu3_v4l2_meta_ioctl_ops = {
+       .vidioc_querycap = ipu3_vidioc_querycap,
+
+       /* meta capture */
+       .vidioc_enum_fmt_meta_cap = ipu3_meta_enum_format,
+       .vidioc_g_fmt_meta_cap = ipu3_vidioc_g_meta_fmt,
+       .vidioc_s_fmt_meta_cap = ipu3_vidioc_g_meta_fmt,
+       .vidioc_try_fmt_meta_cap = ipu3_vidioc_g_meta_fmt,
+
+       /* meta output */
+       .vidioc_enum_fmt_meta_out = ipu3_meta_enum_format,
+       .vidioc_g_fmt_meta_out = ipu3_vidioc_g_meta_fmt,
+       .vidioc_s_fmt_meta_out = ipu3_vidioc_g_meta_fmt,
+       .vidioc_try_fmt_meta_out = ipu3_vidioc_g_meta_fmt,
+
+       .vidioc_reqbufs = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf = vb2_ioctl_querybuf,
+       .vidioc_qbuf = vb2_ioctl_qbuf,
+       .vidioc_dqbuf = vb2_ioctl_dqbuf,
+       .vidioc_streamon = vb2_ioctl_streamon,
+       .vidioc_streamoff = vb2_ioctl_streamoff,
+       .vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static int ipu3_sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct imgu_v4l2_subdev *imgu_sd =
+               container_of(ctrl->handler, struct imgu_v4l2_subdev, ctrl_handler);
+       struct imgu_device *imgu = v4l2_get_subdevdata(&imgu_sd->subdev);
+       struct device *dev = &imgu->pci_dev->dev;
+
+       dev_dbg(dev, "set val %d to ctrl 0x%8x for subdev %d",
+               ctrl->val, ctrl->id, imgu_sd->pipe);
+
+       switch (ctrl->id) {
+       case V4L2_CID_INTEL_IPU3_MODE:
+               atomic_set(&imgu_sd->running_mode, ctrl->val);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct v4l2_ctrl_ops ipu3_subdev_ctrl_ops = {
+       .s_ctrl = ipu3_sd_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config ipu3_subdev_ctrl_mode = {
+       .ops = &ipu3_subdev_ctrl_ops,
+       .id = V4L2_CID_INTEL_IPU3_MODE,
+       .name = "IPU3 Pipe Mode",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = IPU3_RUNNING_MODE_VIDEO,
+       .max = IPU3_RUNNING_MODE_STILL,
+       .step = 1,
+       .def = IPU3_RUNNING_MODE_VIDEO,
+};
+
+/******************** Framework registration ********************/
+
+/* helper function to config node's video properties */
+static void ipu3_node_to_v4l2(u32 node, struct video_device *vdev,
+                             struct v4l2_format *f)
+{
+       u32 cap;
+
+       /* Should not happen */
+       WARN_ON(node >= IMGU_NODE_NUM);
+
+       switch (node) {
+       case IMGU_NODE_IN:
+               cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+               f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+               vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
+               break;
+       case IMGU_NODE_PARAMS:
+               cap = V4L2_CAP_META_OUTPUT;
+               f->type = V4L2_BUF_TYPE_META_OUTPUT;
+               f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_PARAMS;
+               vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+               ipu3_css_meta_fmt_set(&f->fmt.meta);
+               break;
+       case IMGU_NODE_STAT_3A:
+               cap = V4L2_CAP_META_CAPTURE;
+               f->type = V4L2_BUF_TYPE_META_CAPTURE;
+               f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_3A;
+               vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+               ipu3_css_meta_fmt_set(&f->fmt.meta);
+               break;
+       default:
+               cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+               vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
+       }
+
+       vdev->device_caps = V4L2_CAP_STREAMING | cap;
+}
+
+static int ipu3_v4l2_subdev_register(struct imgu_device *imgu,
+                                    struct imgu_v4l2_subdev *imgu_sd,
+                                    unsigned int pipe)
+{
+       int i, r;
+       struct v4l2_ctrl_handler *hdl = &imgu_sd->ctrl_handler;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       /* Initialize subdev media entity */
+       r = media_entity_pads_init(&imgu_sd->subdev.entity, IMGU_NODE_NUM,
+                                  imgu_sd->subdev_pads);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed initialize subdev media entity (%d)\n", r);
+               return r;
+       }
+       imgu_sd->subdev.entity.ops = &ipu3_media_ops;
+       for (i = 0; i < IMGU_NODE_NUM; i++) {
+               imgu_sd->subdev_pads[i].flags = imgu_pipe->nodes[i].output ?
+                       MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+       }
+
+       /* Initialize subdev */
+       v4l2_subdev_init(&imgu_sd->subdev, &ipu3_subdev_ops);
+       imgu_sd->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_STATISTICS;
+       imgu_sd->subdev.internal_ops = &ipu3_subdev_internal_ops;
+       imgu_sd->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
+                               V4L2_SUBDEV_FL_HAS_EVENTS;
+       snprintf(imgu_sd->subdev.name, sizeof(imgu_sd->subdev.name),
+                "%s %d", IMGU_NAME, pipe);
+       v4l2_set_subdevdata(&imgu_sd->subdev, imgu);
+       atomic_set(&imgu_sd->running_mode, IPU3_RUNNING_MODE_VIDEO);
+       v4l2_ctrl_handler_init(hdl, 1);
+       imgu_sd->subdev.ctrl_handler = hdl;
+       imgu_sd->ctrl = v4l2_ctrl_new_custom(hdl, &ipu3_subdev_ctrl_mode, NULL);
+       if (hdl->error) {
+               r = hdl->error;
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to create subdev v4l2 ctrl with err %d", r);
+               goto fail_subdev;
+       }
+       r = v4l2_device_register_subdev(&imgu->v4l2_dev, &imgu_sd->subdev);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed initialize subdev (%d)\n", r);
+               goto fail_subdev;
+       }
+
+       imgu_sd->pipe = pipe;
+       return 0;
+
+fail_subdev:
+       v4l2_ctrl_handler_free(imgu_sd->subdev.ctrl_handler);
+       media_entity_cleanup(&imgu_sd->subdev.entity);
+
+       return r;
+}
+
+static int ipu3_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe,
+                               int node_num)
+{
+       int r;
+       u32 flags;
+       struct v4l2_mbus_framefmt def_bus_fmt = { 0 };
+       struct v4l2_pix_format_mplane def_pix_fmt = { 0 };
+       struct device *dev = &imgu->pci_dev->dev;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+       struct v4l2_subdev *sd = &imgu_pipe->imgu_sd.subdev;
+       struct imgu_video_device *node = &imgu_pipe->nodes[node_num];
+       struct video_device *vdev = &node->vdev;
+       struct vb2_queue *vbq = &node->vbq;
+
+       /* Initialize formats to default values */
+       def_bus_fmt.width = 1920;
+       def_bus_fmt.height = 1080;
+       def_bus_fmt.code = MEDIA_BUS_FMT_FIXED;
+       def_bus_fmt.field = V4L2_FIELD_NONE;
+       def_bus_fmt.colorspace = V4L2_COLORSPACE_RAW;
+       def_bus_fmt.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       def_bus_fmt.quantization = V4L2_QUANTIZATION_DEFAULT;
+       def_bus_fmt.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       def_pix_fmt.width = def_bus_fmt.width;
+       def_pix_fmt.height = def_bus_fmt.height;
+       def_pix_fmt.field = def_bus_fmt.field;
+       def_pix_fmt.num_planes = 1;
+       def_pix_fmt.plane_fmt[0].bytesperline = def_pix_fmt.width * 2;
+       def_pix_fmt.plane_fmt[0].sizeimage =
+               def_pix_fmt.height * def_pix_fmt.plane_fmt[0].bytesperline;
+       def_pix_fmt.flags = 0;
+       def_pix_fmt.colorspace = def_bus_fmt.colorspace;
+       def_pix_fmt.ycbcr_enc = def_bus_fmt.ycbcr_enc;
+       def_pix_fmt.quantization = def_bus_fmt.quantization;
+       def_pix_fmt.xfer_func = def_bus_fmt.xfer_func;
+
+       /* Initialize miscellaneous variables */
+       mutex_init(&node->lock);
+       INIT_LIST_HEAD(&node->buffers);
+
+       /* Initialize formats to default values */
+       node->pad_fmt = def_bus_fmt;
+       node->id = node_num;
+       node->pipe = pipe;
+       ipu3_node_to_v4l2(node_num, vdev, &node->vdev_fmt);
+       if (node->vdev_fmt.type ==
+           V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
+           node->vdev_fmt.type ==
+           V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               def_pix_fmt.pixelformat = node->output ?
+                       V4L2_PIX_FMT_IPU3_SGRBG10 :
+                       V4L2_PIX_FMT_NV12;
+               node->vdev_fmt.fmt.pix_mp = def_pix_fmt;
+       }
+
+       /* Initialize media entities */
+       r = media_entity_pads_init(&vdev->entity, 1, &node->vdev_pad);
+       if (r) {
+               dev_err(dev, "failed initialize media entity (%d)\n", r);
+               mutex_destroy(&node->lock);
+               return r;
+       }
+       node->vdev_pad.flags = node->output ?
+               MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
+       vdev->entity.ops = NULL;
+
+       /* Initialize vbq */
+       vbq->type = node->vdev_fmt.type;
+       vbq->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF;
+       vbq->ops = &ipu3_vb2_ops;
+       vbq->mem_ops = &vb2_dma_sg_memops;
+       if (imgu->buf_struct_size <= 0)
+               imgu->buf_struct_size =
+                       sizeof(struct ipu3_vb2_buffer);
+       vbq->buf_struct_size = imgu->buf_struct_size;
+       vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       /* can streamon w/o buffers */
+       vbq->min_buffers_needed = 0;
+       vbq->drv_priv = imgu;
+       vbq->lock = &node->lock;
+       r = vb2_queue_init(vbq);
+       if (r) {
+               dev_err(dev, "failed to initialize video queue (%d)", r);
+               media_entity_cleanup(&vdev->entity);
+               return r;
+       }
+
+       /* Initialize vdev */
+       snprintf(vdev->name, sizeof(vdev->name), "%s %d %s",
+                IMGU_NAME, pipe, node->name);
+       vdev->release = video_device_release_empty;
+       vdev->fops = &ipu3_v4l2_fops;
+       vdev->lock = &node->lock;
+       vdev->v4l2_dev = &imgu->v4l2_dev;
+       vdev->queue = &node->vbq;
+       vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX;
+       video_set_drvdata(vdev, imgu);
+       r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (r) {
+               dev_err(dev, "failed to register video device (%d)", r);
+               media_entity_cleanup(&vdev->entity);
+               return r;
+       }
+
+       /* Create link between video node and the subdev pad */
+       flags = 0;
+       if (node->enabled)
+               flags |= MEDIA_LNK_FL_ENABLED;
+       if (node->output) {
+               r = media_create_pad_link(&vdev->entity, 0, &sd->entity,
+                                         node_num, flags);
+       } else {
+               r = media_create_pad_link(&sd->entity, node_num, &vdev->entity,
+                                         0, flags);
+       }
+       if (r) {
+               dev_err(dev, "failed to create pad link (%d)", r);
+               video_unregister_device(vdev);
+               return r;
+       }
+
+       return 0;
+}
+
+static void ipu3_v4l2_nodes_cleanup_pipe(struct imgu_device *imgu,
+                                        unsigned int pipe, int node)
+{
+       int i;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       for (i = 0; i < node; i++) {
+               video_unregister_device(&imgu_pipe->nodes[i].vdev);
+               media_entity_cleanup(&imgu_pipe->nodes[i].vdev.entity);
+               mutex_destroy(&imgu_pipe->nodes[i].lock);
+       }
+}
+
+static int ipu3_v4l2_nodes_setup_pipe(struct imgu_device *imgu, int pipe)
+{
+       int i, r;
+
+       for (i = 0; i < IMGU_NODE_NUM; i++) {
+               r = ipu3_v4l2_node_setup(imgu, pipe, i);
+               if (r)
+                       goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       ipu3_v4l2_nodes_cleanup_pipe(imgu, pipe, i);
+       return r;
+}
+
+static void ipu3_v4l2_subdev_cleanup(struct imgu_device *imgu, unsigned int i)
+{
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[i];
+
+       v4l2_device_unregister_subdev(&imgu_pipe->imgu_sd.subdev);
+       v4l2_ctrl_handler_free(imgu_pipe->imgu_sd.subdev.ctrl_handler);
+       media_entity_cleanup(&imgu_pipe->imgu_sd.subdev.entity);
+}
+
+static void ipu3_v4l2_cleanup_pipes(struct imgu_device *imgu, unsigned int pipe)
+{
+       int i;
+
+       for (i = 0; i < pipe; i++) {
+               ipu3_v4l2_nodes_cleanup_pipe(imgu, i, IMGU_NODE_NUM);
+               ipu3_v4l2_subdev_cleanup(imgu, i);
+       }
+}
+
+static int imgu_v4l2_register_pipes(struct imgu_device *imgu)
+{
+       struct imgu_media_pipe *imgu_pipe;
+       int i, r;
+
+       for (i = 0; i < IMGU_MAX_PIPE_NUM; i++) {
+               imgu_pipe = &imgu->imgu_pipe[i];
+               r = ipu3_v4l2_subdev_register(imgu, &imgu_pipe->imgu_sd, i);
+               if (r) {
+                       dev_err(&imgu->pci_dev->dev,
+                               "failed to register subdev%d ret (%d)\n", i, r);
+                       goto pipes_cleanup;
+               }
+               r = ipu3_v4l2_nodes_setup_pipe(imgu, i);
+               if (r) {
+                       ipu3_v4l2_subdev_cleanup(imgu, i);
+                       goto pipes_cleanup;
+               }
+       }
+
+       return 0;
+
+pipes_cleanup:
+       ipu3_v4l2_cleanup_pipes(imgu, i);
+       return r;
+}
+
+int imgu_v4l2_register(struct imgu_device *imgu)
+{
+       int r;
+
+       /* Initialize miscellaneous variables */
+       imgu->streaming = false;
+
+       /* Set up media device */
+       media_device_pci_init(&imgu->media_dev, imgu->pci_dev, IMGU_NAME);
+
+       /* Set up v4l2 device */
+       imgu->v4l2_dev.mdev = &imgu->media_dev;
+       imgu->v4l2_dev.ctrl_handler = NULL;
+       r = v4l2_device_register(&imgu->pci_dev->dev, &imgu->v4l2_dev);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to register V4L2 device (%d)\n", r);
+               goto fail_v4l2_dev;
+       }
+
+       r = imgu_v4l2_register_pipes(imgu);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to register pipes (%d)\n", r);
+               goto fail_v4l2_pipes;
+       }
+
+       r = v4l2_device_register_subdev_nodes(&imgu->v4l2_dev);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to register subdevs (%d)\n", r);
+               goto fail_subdevs;
+       }
+
+       r = media_device_register(&imgu->media_dev);
+       if (r) {
+               dev_err(&imgu->pci_dev->dev,
+                       "failed to register media device (%d)\n", r);
+               goto fail_subdevs;
+       }
+
+       return 0;
+
+fail_subdevs:
+       ipu3_v4l2_cleanup_pipes(imgu, IMGU_MAX_PIPE_NUM);
+fail_v4l2_pipes:
+       v4l2_device_unregister(&imgu->v4l2_dev);
+fail_v4l2_dev:
+       media_device_cleanup(&imgu->media_dev);
+
+       return r;
+}
+
+int imgu_v4l2_unregister(struct imgu_device *imgu)
+{
+       media_device_unregister(&imgu->media_dev);
+       ipu3_v4l2_cleanup_pipes(imgu, IMGU_MAX_PIPE_NUM);
+       v4l2_device_unregister(&imgu->v4l2_dev);
+       media_device_cleanup(&imgu->media_dev);
+
+       return 0;
+}
+
+void imgu_v4l2_buffer_done(struct vb2_buffer *vb,
+                          enum vb2_buffer_state state)
+{
+       struct ipu3_vb2_buffer *b =
+               container_of(vb, struct ipu3_vb2_buffer, vbb.vb2_buf);
+
+       list_del(&b->list);
+       vb2_buffer_done(&b->vbb.vb2_buf, state);
+}
diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c
new file mode 100644 (file)
index 0000000..d521b3a
--- /dev/null
@@ -0,0 +1,830 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 - 2018 Intel Corporation
+ * Copyright 2017 Google LLC
+ *
+ * Based on Intel IPU4 driver.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "ipu3.h"
+#include "ipu3-dmamap.h"
+#include "ipu3-mmu.h"
+
+#define IMGU_PCI_ID                    0x1919
+#define IMGU_PCI_BAR                   0
+#define IMGU_DMA_MASK                  DMA_BIT_MASK(39)
+#define IMGU_MAX_QUEUE_DEPTH           (2 + 2)
+
+/*
+ * pre-allocated buffer size for IMGU dummy buffers. Those
+ * values should be tuned to big enough to avoid buffer
+ * re-allocation when streaming to lower streaming latency.
+ */
+#define CSS_QUEUE_IN_BUF_SIZE          0
+#define CSS_QUEUE_PARAMS_BUF_SIZE      0
+#define CSS_QUEUE_OUT_BUF_SIZE         (4160 * 3120 * 12 / 8)
+#define CSS_QUEUE_VF_BUF_SIZE          (1920 * 1080 * 12 / 8)
+#define CSS_QUEUE_STAT_3A_BUF_SIZE     sizeof(struct ipu3_uapi_stats_3a)
+
+static const size_t css_queue_buf_size_map[IPU3_CSS_QUEUES] = {
+       [IPU3_CSS_QUEUE_IN] = CSS_QUEUE_IN_BUF_SIZE,
+       [IPU3_CSS_QUEUE_PARAMS] = CSS_QUEUE_PARAMS_BUF_SIZE,
+       [IPU3_CSS_QUEUE_OUT] = CSS_QUEUE_OUT_BUF_SIZE,
+       [IPU3_CSS_QUEUE_VF] = CSS_QUEUE_VF_BUF_SIZE,
+       [IPU3_CSS_QUEUE_STAT_3A] = CSS_QUEUE_STAT_3A_BUF_SIZE,
+};
+
+static const struct imgu_node_mapping imgu_node_map[IMGU_NODE_NUM] = {
+       [IMGU_NODE_IN] = {IPU3_CSS_QUEUE_IN, "input"},
+       [IMGU_NODE_PARAMS] = {IPU3_CSS_QUEUE_PARAMS, "parameters"},
+       [IMGU_NODE_OUT] = {IPU3_CSS_QUEUE_OUT, "output"},
+       [IMGU_NODE_VF] = {IPU3_CSS_QUEUE_VF, "viewfinder"},
+       [IMGU_NODE_STAT_3A] = {IPU3_CSS_QUEUE_STAT_3A, "3a stat"},
+};
+
+unsigned int imgu_node_to_queue(unsigned int node)
+{
+       return imgu_node_map[node].css_queue;
+}
+
+unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue)
+{
+       unsigned int i;
+
+       for (i = 0; i < IMGU_NODE_NUM; i++)
+               if (imgu_node_map[i].css_queue == css_queue)
+                       break;
+
+       return i;
+}
+
+/**************** Dummy buffers ****************/
+
+static void imgu_dummybufs_cleanup(struct imgu_device *imgu, unsigned int pipe)
+{
+       unsigned int i;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       for (i = 0; i < IPU3_CSS_QUEUES; i++)
+               ipu3_dmamap_free(imgu,
+                                &imgu_pipe->queues[i].dmap);
+}
+
+static int imgu_dummybufs_preallocate(struct imgu_device *imgu,
+                                     unsigned int pipe)
+{
+       unsigned int i;
+       size_t size;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               size = css_queue_buf_size_map[i];
+               /*
+                * Do not enable dummy buffers for master queue,
+                * always require that real buffers from user are
+                * available.
+                */
+               if (i == IMGU_QUEUE_MASTER || size == 0)
+                       continue;
+
+               if (!ipu3_dmamap_alloc(imgu,
+                                      &imgu_pipe->queues[i].dmap, size)) {
+                       imgu_dummybufs_cleanup(imgu, pipe);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static int imgu_dummybufs_init(struct imgu_device *imgu, unsigned int pipe)
+{
+       const struct v4l2_pix_format_mplane *mpix;
+       const struct v4l2_meta_format   *meta;
+       unsigned int i, k, node;
+       size_t size;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       /* Allocate a dummy buffer for each queue where buffer is optional */
+       for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+               node = imgu_map_node(imgu, i);
+               if (!imgu_pipe->queue_enabled[node] || i == IMGU_QUEUE_MASTER)
+                       continue;
+
+               if (!imgu_pipe->nodes[IMGU_NODE_VF].enabled &&
+                   i == IPU3_CSS_QUEUE_VF)
+                       /*
+                        * Do not enable dummy buffers for VF if it is not
+                        * requested by the user.
+                        */
+                       continue;
+
+               meta = &imgu_pipe->nodes[node].vdev_fmt.fmt.meta;
+               mpix = &imgu_pipe->nodes[node].vdev_fmt.fmt.pix_mp;
+
+               if (node == IMGU_NODE_STAT_3A || node == IMGU_NODE_PARAMS)
+                       size = meta->buffersize;
+               else
+                       size = mpix->plane_fmt[0].sizeimage;
+
+               if (ipu3_css_dma_buffer_resize(imgu,
+                                              &imgu_pipe->queues[i].dmap,
+                                              size)) {
+                       imgu_dummybufs_cleanup(imgu, pipe);
+                       return -ENOMEM;
+               }
+
+               for (k = 0; k < IMGU_MAX_QUEUE_DEPTH; k++)
+                       ipu3_css_buf_init(&imgu_pipe->queues[i].dummybufs[k], i,
+                                         imgu_pipe->queues[i].dmap.daddr);
+       }
+
+       return 0;
+}
+
+/* May be called from atomic context */
+static struct ipu3_css_buffer *imgu_dummybufs_get(struct imgu_device *imgu,
+                                                  int queue, unsigned int pipe)
+{
+       unsigned int i;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       /* dummybufs are not allocated for master q */
+       if (queue == IPU3_CSS_QUEUE_IN)
+               return NULL;
+
+       if (WARN_ON(!imgu_pipe->queues[queue].dmap.vaddr))
+               /* Buffer should not be allocated here */
+               return NULL;
+
+       for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
+               if (ipu3_css_buf_state(&imgu_pipe->queues[queue].dummybufs[i]) !=
+                       IPU3_CSS_BUFFER_QUEUED)
+                       break;
+
+       if (i == IMGU_MAX_QUEUE_DEPTH)
+               return NULL;
+
+       ipu3_css_buf_init(&imgu_pipe->queues[queue].dummybufs[i], queue,
+                         imgu_pipe->queues[queue].dmap.daddr);
+
+       return &imgu_pipe->queues[queue].dummybufs[i];
+}
+
+/* Check if given buffer is a dummy buffer */
+static bool imgu_dummybufs_check(struct imgu_device *imgu,
+                                struct ipu3_css_buffer *buf,
+                                unsigned int pipe)
+{
+       unsigned int i;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
+               if (buf == &imgu_pipe->queues[buf->queue].dummybufs[i])
+                       break;
+
+       return i < IMGU_MAX_QUEUE_DEPTH;
+}
+
+static void imgu_buffer_done(struct imgu_device *imgu, struct vb2_buffer *vb,
+                            enum vb2_buffer_state state)
+{
+       mutex_lock(&imgu->lock);
+       imgu_v4l2_buffer_done(vb, state);
+       mutex_unlock(&imgu->lock);
+}
+
+static struct ipu3_css_buffer *imgu_queue_getbuf(struct imgu_device *imgu,
+                                                unsigned int node,
+                                                unsigned int pipe)
+{
+       struct imgu_buffer *buf;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       if (WARN_ON(node >= IMGU_NODE_NUM))
+               return NULL;
+
+       /* Find first free buffer from the node */
+       list_for_each_entry(buf, &imgu_pipe->nodes[node].buffers, vid_buf.list) {
+               if (ipu3_css_buf_state(&buf->css_buf) == IPU3_CSS_BUFFER_NEW)
+                       return &buf->css_buf;
+       }
+
+       /* There were no free buffers, try to return a dummy buffer */
+       return imgu_dummybufs_get(imgu, imgu_node_map[node].css_queue, pipe);
+}
+
+/*
+ * Queue as many buffers to CSS as possible. If all buffers don't fit into
+ * CSS buffer queues, they remain unqueued and will be queued later.
+ */
+int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe)
+{
+       unsigned int node;
+       int r = 0;
+       struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
+
+       if (!ipu3_css_is_streaming(&imgu->css))
+               return 0;
+
+       dev_dbg(&imgu->pci_dev->dev, "Queue buffers to pipe %d", pipe);
+       mutex_lock(&imgu->lock);
+
+       /* Buffer set is queued to FW only when input buffer is ready */
+       for (node = IMGU_NODE_NUM - 1;
+            imgu_queue_getbuf(imgu, IMGU_NODE_IN, pipe);
+            node = node ? node - 1 : IMGU_NODE_NUM - 1) {
+
+               if (node == IMGU_NODE_VF &&
+                   !imgu_pipe->nodes[IMGU_NODE_VF].enabled) {
+                       dev_warn(&imgu->pci_dev->dev,
+                                "Vf not enabled, ignore queue");
+                       continue;
+               } else if (imgu_pipe->queue_enabled[node]) {
+                       struct ipu3_css_buffer *buf =
+                               imgu_queue_getbuf(imgu, node, pipe);
+                       struct imgu_buffer *ibuf = NULL;
+                       bool dummy;
+
+                       if (!buf)
+                               break;
+
+                       r = ipu3_css_buf_queue(&imgu->css, pipe, buf);
+                       if (r)
+                               break;
+                       dummy = imgu_dummybufs_check(imgu, buf, pipe);
+                       if (!dummy)
+                               ibuf = container_of(buf, struct imgu_buffer,
+                                                   css_buf);
+                       dev_dbg(&imgu->pci_dev->dev,
+                               "queue %s %s buffer %u to css da: 0x%08x\n",
+                               dummy ? "dummy" : "user",
+                               imgu_node_map[node].name,
+                               dummy ? 0 : ibuf->vid_buf.vbb.vb2_buf.index,
+                               (u32)buf->daddr);
+               }
+       }
+       mutex_unlock(&imgu->lock);
+
+       if (r && r != -EBUSY)
+               goto failed;
+
+       return 0;
+
+failed:
+       /*
+        * On error, mark all buffers as failed which are not
+        * yet queued to CSS
+        */
+       dev_err(&imgu->pci_dev->dev,
+               "failed to queue buffer to CSS on queue %i (%d)\n",
+               node, r);
+
+       if (initial)
+               /* If we were called from streamon(), no need to finish bufs */
+               return r;
+
+       for (node = 0; node < IMGU_NODE_NUM; node++) {
+               struct imgu_buffer *buf, *buf0;
+
+               if (!imgu_pipe->queue_enabled[node])
+                       continue;       /* Skip disabled queues */
+
+               mutex_lock(&imgu->lock);
+               list_for_each_entry_safe(buf, buf0,
+                                        &imgu_pipe->nodes[node].buffers,
+                                        vid_buf.list) {
+                       if (ipu3_css_buf_state(&buf->css_buf) ==
+                           IPU3_CSS_BUFFER_QUEUED)
+                               continue;       /* Was already queued, skip */
+
+                       imgu_v4l2_buffer_done(&buf->vid_buf.vbb.vb2_buf,
+                                             VB2_BUF_STATE_ERROR);
+               }
+               mutex_unlock(&imgu->lock);
+       }
+
+       return r;
+}
+
+static int imgu_powerup(struct imgu_device *imgu)
+{
+       int r;
+
+       r = ipu3_css_set_powerup(&imgu->pci_dev->dev, imgu->base);
+       if (r)
+               return r;
+
+       ipu3_mmu_resume(imgu->mmu);
+       return 0;
+}
+
+static void imgu_powerdown(struct imgu_device *imgu)
+{
+       ipu3_mmu_suspend(imgu->mmu);
+       ipu3_css_set_powerdown(&imgu->pci_dev->dev, imgu->base);
+}
+
+int imgu_s_stream(struct imgu_device *imgu, int enable)
+{
+       struct device *dev = &imgu->pci_dev->dev;
+       int r, pipe;
+
+       if (!enable) {
+               /* Stop streaming */
+               dev_dbg(dev, "stream off\n");
+               /* Block new buffers to be queued to CSS. */
+               atomic_set(&imgu->qbuf_barrier, 1);
+               ipu3_css_stop_streaming(&imgu->css);
+               synchronize_irq(imgu->pci_dev->irq);
+               atomic_set(&imgu->qbuf_barrier, 0);
+               imgu_powerdown(imgu);
+               pm_runtime_put(&imgu->pci_dev->dev);
+
+               return 0;
+       }
+
+       /* Set Power */
+       r = pm_runtime_get_sync(dev);
+       if (r < 0) {
+               dev_err(dev, "failed to set imgu power\n");
+               pm_runtime_put(dev);
+               return r;
+       }
+
+       r = imgu_powerup(imgu);
+       if (r) {
+               dev_err(dev, "failed to power up imgu\n");
+               pm_runtime_put(dev);
+               return r;
+       }
+
+       /* Start CSS streaming */
+       r = ipu3_css_start_streaming(&imgu->css);
+       if (r) {
+               dev_err(dev, "failed to start css streaming (%d)", r);
+               goto fail_start_streaming;
+       }
+
+       for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               /* Initialize dummy buffers */
+               r = imgu_dummybufs_init(imgu, pipe);
+               if (r) {
+                       dev_err(dev, "failed to initialize dummy buffers (%d)", r);
+                       goto fail_dummybufs;
+               }
+
+               /* Queue as many buffers from queue as possible */
+               r = imgu_queue_buffers(imgu, true, pipe);
+               if (r) {
+                       dev_err(dev, "failed to queue initial buffers (%d)", r);
+                       goto fail_queueing;
+               }
+       }
+
+       return 0;
+fail_queueing:
+       for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
+               imgu_dummybufs_cleanup(imgu, pipe);
+fail_dummybufs:
+       ipu3_css_stop_streaming(&imgu->css);
+fail_start_streaming:
+       pm_runtime_put(dev);
+
+       return r;
+}
+
+static int imgu_video_nodes_init(struct imgu_device *imgu)
+{
+       struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
+       struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
+       struct imgu_media_pipe *imgu_pipe;
+       unsigned int i, j;
+       int r;
+
+       imgu->buf_struct_size = sizeof(struct imgu_buffer);
+
+       for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
+               imgu_pipe = &imgu->imgu_pipe[j];
+
+               for (i = 0; i < IMGU_NODE_NUM; i++) {
+                       imgu_pipe->nodes[i].name = imgu_node_map[i].name;
+                       imgu_pipe->nodes[i].output = i < IMGU_QUEUE_FIRST_INPUT;
+                       imgu_pipe->nodes[i].enabled = false;
+
+                       if (i != IMGU_NODE_PARAMS && i != IMGU_NODE_STAT_3A)
+                               fmts[imgu_node_map[i].css_queue] =
+                                       &imgu_pipe->nodes[i].vdev_fmt.fmt.pix_mp;
+                       atomic_set(&imgu_pipe->nodes[i].sequence, 0);
+               }
+       }
+
+       r = imgu_v4l2_register(imgu);
+       if (r)
+               return r;
+
+       /* Set initial formats and initialize formats of video nodes */
+       for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
+               imgu_pipe = &imgu->imgu_pipe[j];
+
+               rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_pipe->imgu_sd.rect.eff;
+               rects[IPU3_CSS_RECT_BDS] = &imgu_pipe->imgu_sd.rect.bds;
+               ipu3_css_fmt_set(&imgu->css, fmts, rects, j);
+
+               /* Pre-allocate dummy buffers */
+               r = imgu_dummybufs_preallocate(imgu, j);
+               if (r) {
+                       dev_err(&imgu->pci_dev->dev,
+                               "failed to pre-allocate dummy buffers (%d)", r);
+                       goto out_cleanup;
+               }
+       }
+
+       return 0;
+
+out_cleanup:
+       for (j = 0; j < IMGU_MAX_PIPE_NUM; j++)
+               imgu_dummybufs_cleanup(imgu, j);
+
+       imgu_v4l2_unregister(imgu);
+
+       return r;
+}
+
+static void imgu_video_nodes_exit(struct imgu_device *imgu)
+{
+       int i;
+
+       for (i = 0; i < IMGU_MAX_PIPE_NUM; i++)
+               imgu_dummybufs_cleanup(imgu, i);
+
+       imgu_v4l2_unregister(imgu);
+}
+
+/**************** PCI interface ****************/
+
+static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr)
+{
+       struct imgu_device *imgu = imgu_ptr;
+       struct imgu_media_pipe *imgu_pipe;
+       int p;
+
+       /* Dequeue / queue buffers */
+       do {
+               u64 ns = ktime_get_ns();
+               struct ipu3_css_buffer *b;
+               struct imgu_buffer *buf = NULL;
+               unsigned int node, pipe;
+               bool dummy;
+
+               do {
+                       mutex_lock(&imgu->lock);
+                       b = ipu3_css_buf_dequeue(&imgu->css);
+                       mutex_unlock(&imgu->lock);
+               } while (PTR_ERR(b) == -EAGAIN);
+
+               if (IS_ERR_OR_NULL(b)) {
+                       if (!b || PTR_ERR(b) == -EBUSY) /* All done */
+                               break;
+                       dev_err(&imgu->pci_dev->dev,
+                               "failed to dequeue buffers (%ld)\n",
+                               PTR_ERR(b));
+                       break;
+               }
+
+               node = imgu_map_node(imgu, b->queue);
+               pipe = b->pipe;
+               dummy = imgu_dummybufs_check(imgu, b, pipe);
+               if (!dummy)
+                       buf = container_of(b, struct imgu_buffer, css_buf);
+               dev_dbg(&imgu->pci_dev->dev,
+                       "dequeue %s %s buffer %d daddr 0x%x from css\n",
+                       dummy ? "dummy" : "user",
+                       imgu_node_map[node].name,
+                       dummy ? 0 : buf->vid_buf.vbb.vb2_buf.index,
+                       (u32)b->daddr);
+
+               if (dummy)
+                       /* It was a dummy buffer, skip it */
+                       continue;
+
+               /* Fill vb2 buffer entries and tell it's ready */
+               imgu_pipe = &imgu->imgu_pipe[pipe];
+               if (!imgu_pipe->nodes[node].output) {
+                       buf->vid_buf.vbb.vb2_buf.timestamp = ns;
+                       buf->vid_buf.vbb.field = V4L2_FIELD_NONE;
+                       buf->vid_buf.vbb.sequence =
+                               atomic_inc_return(
+                               &imgu_pipe->nodes[node].sequence);
+                       dev_dbg(&imgu->pci_dev->dev, "vb2 buffer sequence %d",
+                               buf->vid_buf.vbb.sequence);
+               }
+               imgu_buffer_done(imgu, &buf->vid_buf.vbb.vb2_buf,
+                                ipu3_css_buf_state(&buf->css_buf) ==
+                                                   IPU3_CSS_BUFFER_DONE ?
+                                                   VB2_BUF_STATE_DONE :
+                                                   VB2_BUF_STATE_ERROR);
+               mutex_lock(&imgu->lock);
+               if (ipu3_css_queue_empty(&imgu->css))
+                       wake_up_all(&imgu->buf_drain_wq);
+               mutex_unlock(&imgu->lock);
+       } while (1);
+
+       /*
+        * Try to queue more buffers for CSS.
+        * qbuf_barrier is used to disable new buffers
+        * to be queued to CSS.
+        */
+       if (!atomic_read(&imgu->qbuf_barrier))
+               for_each_set_bit(p, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
+                       imgu_queue_buffers(imgu, false, p);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imgu_isr(int irq, void *imgu_ptr)
+{
+       struct imgu_device *imgu = imgu_ptr;
+
+       /* acknowledge interruption */
+       if (ipu3_css_irq_ack(&imgu->css) < 0)
+               return IRQ_NONE;
+
+       return IRQ_WAKE_THREAD;
+}
+
+static int imgu_pci_config_setup(struct pci_dev *dev)
+{
+       u16 pci_command;
+       int r = pci_enable_msi(dev);
+
+       if (r) {
+               dev_err(&dev->dev, "failed to enable MSI (%d)\n", r);
+               return r;
+       }
+
+       pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+       pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+                       PCI_COMMAND_INTX_DISABLE;
+       pci_write_config_word(dev, PCI_COMMAND, pci_command);
+
+       return 0;
+}
+
+static int imgu_pci_probe(struct pci_dev *pci_dev,
+                         const struct pci_device_id *id)
+{
+       struct imgu_device *imgu;
+       phys_addr_t phys;
+       unsigned long phys_len;
+       void __iomem *const *iomap;
+       int r;
+
+       imgu = devm_kzalloc(&pci_dev->dev, sizeof(*imgu), GFP_KERNEL);
+       if (!imgu)
+               return -ENOMEM;
+
+       imgu->pci_dev = pci_dev;
+
+       r = pcim_enable_device(pci_dev);
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to enable device (%d)\n", r);
+               return r;
+       }
+
+       dev_info(&pci_dev->dev, "device 0x%x (rev: 0x%x)\n",
+                pci_dev->device, pci_dev->revision);
+
+       phys = pci_resource_start(pci_dev, IMGU_PCI_BAR);
+       phys_len = pci_resource_len(pci_dev, IMGU_PCI_BAR);
+
+       r = pcim_iomap_regions(pci_dev, 1 << IMGU_PCI_BAR, pci_name(pci_dev));
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to remap I/O memory (%d)\n", r);
+               return r;
+       }
+       dev_info(&pci_dev->dev, "physical base address %pap, %lu bytes\n",
+                &phys, phys_len);
+
+       iomap = pcim_iomap_table(pci_dev);
+       if (!iomap) {
+               dev_err(&pci_dev->dev, "failed to iomap table\n");
+               return -ENODEV;
+       }
+
+       imgu->base = iomap[IMGU_PCI_BAR];
+
+       pci_set_drvdata(pci_dev, imgu);
+
+       pci_set_master(pci_dev);
+
+       r = dma_coerce_mask_and_coherent(&pci_dev->dev, IMGU_DMA_MASK);
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to set DMA mask (%d)\n", r);
+               return -ENODEV;
+       }
+
+       r = imgu_pci_config_setup(pci_dev);
+       if (r)
+               return r;
+
+       mutex_init(&imgu->lock);
+       atomic_set(&imgu->qbuf_barrier, 0);
+       init_waitqueue_head(&imgu->buf_drain_wq);
+
+       r = ipu3_css_set_powerup(&pci_dev->dev, imgu->base);
+       if (r) {
+               dev_err(&pci_dev->dev,
+                       "failed to power up CSS (%d)\n", r);
+               goto out_mutex_destroy;
+       }
+
+       imgu->mmu = ipu3_mmu_init(&pci_dev->dev, imgu->base);
+       if (IS_ERR(imgu->mmu)) {
+               r = PTR_ERR(imgu->mmu);
+               dev_err(&pci_dev->dev, "failed to initialize MMU (%d)\n", r);
+               goto out_css_powerdown;
+       }
+
+       r = ipu3_dmamap_init(imgu);
+       if (r) {
+               dev_err(&pci_dev->dev,
+                       "failed to initialize DMA mapping (%d)\n", r);
+               goto out_mmu_exit;
+       }
+
+       /* ISP programming */
+       r = ipu3_css_init(&pci_dev->dev, &imgu->css, imgu->base, phys_len);
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to initialize CSS (%d)\n", r);
+               goto out_dmamap_exit;
+       }
+
+       /* v4l2 sub-device registration */
+       r = imgu_video_nodes_init(imgu);
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to create V4L2 devices (%d)\n",
+                       r);
+               goto out_css_cleanup;
+       }
+
+       r = devm_request_threaded_irq(&pci_dev->dev, pci_dev->irq,
+                                     imgu_isr, imgu_isr_threaded,
+                                     IRQF_SHARED, IMGU_NAME, imgu);
+       if (r) {
+               dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r);
+               goto out_video_exit;
+       }
+
+       pm_runtime_put_noidle(&pci_dev->dev);
+       pm_runtime_allow(&pci_dev->dev);
+
+       return 0;
+
+out_video_exit:
+       imgu_video_nodes_exit(imgu);
+out_css_cleanup:
+       ipu3_css_cleanup(&imgu->css);
+out_dmamap_exit:
+       ipu3_dmamap_exit(imgu);
+out_mmu_exit:
+       ipu3_mmu_exit(imgu->mmu);
+out_css_powerdown:
+       ipu3_css_set_powerdown(&pci_dev->dev, imgu->base);
+out_mutex_destroy:
+       mutex_destroy(&imgu->lock);
+
+       return r;
+}
+
+static void imgu_pci_remove(struct pci_dev *pci_dev)
+{
+       struct imgu_device *imgu = pci_get_drvdata(pci_dev);
+
+       pm_runtime_forbid(&pci_dev->dev);
+       pm_runtime_get_noresume(&pci_dev->dev);
+
+       imgu_video_nodes_exit(imgu);
+       ipu3_css_cleanup(&imgu->css);
+       ipu3_css_set_powerdown(&pci_dev->dev, imgu->base);
+       ipu3_dmamap_exit(imgu);
+       ipu3_mmu_exit(imgu->mmu);
+       mutex_destroy(&imgu->lock);
+}
+
+static int __maybe_unused imgu_suspend(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct imgu_device *imgu = pci_get_drvdata(pci_dev);
+
+       dev_dbg(dev, "enter %s\n", __func__);
+       imgu->suspend_in_stream = ipu3_css_is_streaming(&imgu->css);
+       if (!imgu->suspend_in_stream)
+               goto out;
+       /* Block new buffers to be queued to CSS. */
+       atomic_set(&imgu->qbuf_barrier, 1);
+       /*
+        * Wait for currently running irq handler to be done so that
+        * no new buffers will be queued to fw later.
+        */
+       synchronize_irq(pci_dev->irq);
+       /* Wait until all buffers in CSS are done. */
+       if (!wait_event_timeout(imgu->buf_drain_wq,
+           ipu3_css_queue_empty(&imgu->css), msecs_to_jiffies(1000)))
+               dev_err(dev, "wait buffer drain timeout.\n");
+
+       ipu3_css_stop_streaming(&imgu->css);
+       atomic_set(&imgu->qbuf_barrier, 0);
+       imgu_powerdown(imgu);
+       pm_runtime_force_suspend(dev);
+out:
+       dev_dbg(dev, "leave %s\n", __func__);
+       return 0;
+}
+
+static int __maybe_unused imgu_resume(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct imgu_device *imgu = pci_get_drvdata(pci_dev);
+       int r = 0;
+       unsigned int pipe;
+
+       dev_dbg(dev, "enter %s\n", __func__);
+
+       if (!imgu->suspend_in_stream)
+               goto out;
+
+       pm_runtime_force_resume(dev);
+
+       r = imgu_powerup(imgu);
+       if (r) {
+               dev_err(dev, "failed to power up imgu\n");
+               goto out;
+       }
+
+       /* Start CSS streaming */
+       r = ipu3_css_start_streaming(&imgu->css);
+       if (r) {
+               dev_err(dev, "failed to resume css streaming (%d)", r);
+               goto out;
+       }
+
+       for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               r = imgu_queue_buffers(imgu, true, pipe);
+               if (r)
+                       dev_err(dev, "failed to queue buffers to pipe %d (%d)",
+                               pipe, r);
+       }
+
+out:
+       dev_dbg(dev, "leave %s\n", __func__);
+
+       return r;
+}
+
+/*
+ * PCI rpm framework checks the existence of driver rpm callbacks.
+ * Place a dummy callback here to avoid rpm going into error state.
+ */
+static int imgu_rpm_dummy_cb(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops imgu_pm_ops = {
+       SET_RUNTIME_PM_OPS(&imgu_rpm_dummy_cb, &imgu_rpm_dummy_cb, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(&imgu_suspend, &imgu_resume)
+};
+
+static const struct pci_device_id imgu_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, IMGU_PCI_ID) },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, imgu_pci_tbl);
+
+static struct pci_driver imgu_pci_driver = {
+       .name = IMGU_NAME,
+       .id_table = imgu_pci_tbl,
+       .probe = imgu_pci_probe,
+       .remove = imgu_pci_remove,
+       .driver = {
+               .pm = &imgu_pm_ops,
+       },
+};
+
+module_pci_driver(imgu_pci_driver);
+
+MODULE_AUTHOR("Tuukka Toivonen <tuukka.toivonen@intel.com>");
+MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
+MODULE_AUTHOR("Jian Xu Zheng <jian.xu.zheng@intel.com>");
+MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel ipu3_imgu PCI driver");
diff --git a/drivers/staging/media/ipu3/ipu3.h b/drivers/staging/media/ipu3/ipu3.h
new file mode 100644 (file)
index 0000000..04fc99f
--- /dev/null
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 Intel Corporation */
+
+#ifndef __IPU3_H
+#define __IPU3_H
+
+#include <linux/iova.h>
+#include <linux/pci.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "ipu3-css.h"
+
+#define IMGU_NAME                      "ipu3-imgu"
+
+/*
+ * The semantics of the driver is that whenever there is a buffer available in
+ * master queue, the driver queues a buffer also to all other active nodes.
+ * If user space hasn't provided a buffer to all other video nodes first,
+ * the driver gets an internal dummy buffer and queues it.
+ */
+#define IMGU_QUEUE_MASTER              IPU3_CSS_QUEUE_IN
+#define IMGU_QUEUE_FIRST_INPUT         IPU3_CSS_QUEUE_OUT
+#define IMGU_MAX_QUEUE_DEPTH           (2 + 2)
+
+#define IMGU_NODE_IN                   0 /* Input RAW image */
+#define IMGU_NODE_PARAMS               1 /* Input parameters */
+#define IMGU_NODE_OUT                  2 /* Main output for still or video */
+#define IMGU_NODE_VF                   3 /* Preview */
+#define IMGU_NODE_STAT_3A              4 /* 3A statistics */
+#define IMGU_NODE_NUM                  5
+
+#define file_to_intel_ipu3_node(__file) \
+       container_of(video_devdata(__file), struct imgu_video_device, vdev)
+
+#define IPU3_INPUT_MIN_WIDTH           0U
+#define IPU3_INPUT_MIN_HEIGHT          0U
+#define IPU3_INPUT_MAX_WIDTH           5120U
+#define IPU3_INPUT_MAX_HEIGHT          38404U
+#define IPU3_OUTPUT_MIN_WIDTH          2U
+#define IPU3_OUTPUT_MIN_HEIGHT         2U
+#define IPU3_OUTPUT_MAX_WIDTH          4480U
+#define IPU3_OUTPUT_MAX_HEIGHT         34004U
+
+struct ipu3_vb2_buffer {
+       /* Public fields */
+       struct vb2_v4l2_buffer vbb;     /* Must be the first field */
+
+       /* Private fields */
+       struct list_head list;
+};
+
+struct imgu_buffer {
+       struct ipu3_vb2_buffer vid_buf; /* Must be the first field */
+       struct ipu3_css_buffer css_buf;
+       struct ipu3_css_map map;
+};
+
+struct imgu_node_mapping {
+       unsigned int css_queue;
+       const char *name;
+};
+
+/**
+ * struct imgu_video_device
+ * each node registers as video device and maintains its
+ * own vb2_queue.
+ */
+struct imgu_video_device {
+       const char *name;
+       bool output;
+       bool enabled;
+       struct v4l2_format vdev_fmt;    /* Currently set format */
+
+       /* Private fields */
+       struct video_device vdev;
+       struct media_pad vdev_pad;
+       struct v4l2_mbus_framefmt pad_fmt;
+       struct vb2_queue vbq;
+       struct list_head buffers;
+       /* Protect vb2_queue and vdev structs*/
+       struct mutex lock;
+       atomic_t sequence;
+       unsigned int id;
+       unsigned int pipe;
+};
+
+struct imgu_v4l2_subdev {
+       unsigned int pipe;
+       struct v4l2_subdev subdev;
+       struct media_pad subdev_pads[IMGU_NODE_NUM];
+       struct {
+               struct v4l2_rect eff; /* effective resolution */
+               struct v4l2_rect bds; /* bayer-domain scaled resolution*/
+               struct v4l2_rect gdc; /* gdc output resolution */
+       } rect;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct v4l2_ctrl *ctrl;
+       atomic_t running_mode;
+       bool active;
+};
+
+struct imgu_media_pipe {
+       unsigned int pipe;
+
+       /* Internally enabled queues */
+       struct {
+               struct ipu3_css_map dmap;
+               struct ipu3_css_buffer dummybufs[IMGU_MAX_QUEUE_DEPTH];
+       } queues[IPU3_CSS_QUEUES];
+       struct imgu_video_device nodes[IMGU_NODE_NUM];
+       bool queue_enabled[IMGU_NODE_NUM];
+       struct media_pipeline pipeline;
+       struct imgu_v4l2_subdev imgu_sd;
+};
+
+/*
+ * imgu_device -- ImgU (Imaging Unit) driver
+ */
+struct imgu_device {
+       struct pci_dev *pci_dev;
+       void __iomem *base;
+
+       /* Public fields, fill before registering */
+       unsigned int buf_struct_size;
+       bool streaming;         /* Public read only */
+
+       struct imgu_media_pipe imgu_pipe[IMGU_MAX_PIPE_NUM];
+
+       /* Private fields */
+       struct v4l2_device v4l2_dev;
+       struct media_device media_dev;
+       struct v4l2_file_operations v4l2_file_ops;
+
+       /* MMU driver for css */
+       struct ipu3_mmu_info *mmu;
+       struct iova_domain iova_domain;
+
+       /* css - Camera Sub-System */
+       struct ipu3_css css;
+
+       /*
+        * Coarse-grained lock to protect
+        * vid_buf.list and css->queue
+        */
+       struct mutex lock;
+       /* Forbit streaming and buffer queuing during system suspend. */
+       atomic_t qbuf_barrier;
+       /* Indicate if system suspend take place while imgu is streaming. */
+       bool suspend_in_stream;
+       /* Used to wait for FW buffer queue drain. */
+       wait_queue_head_t buf_drain_wq;
+};
+
+unsigned int imgu_node_to_queue(unsigned int node);
+unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue);
+int imgu_queue_buffers(struct imgu_device *imgu, bool initial,
+                      unsigned int pipe);
+
+int imgu_v4l2_register(struct imgu_device *dev);
+int imgu_v4l2_unregister(struct imgu_device *dev);
+void imgu_v4l2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
+
+int imgu_s_stream(struct imgu_device *imgu, int enable);
+
+#endif
diff --git a/drivers/staging/media/rockchip/vpu/Kconfig b/drivers/staging/media/rockchip/vpu/Kconfig
new file mode 100644 (file)
index 0000000..9a6fc13
--- /dev/null
@@ -0,0 +1,13 @@
+config VIDEO_ROCKCHIP_VPU
+       tristate "Rockchip VPU driver"
+       depends on ARCH_ROCKCHIP || COMPILE_TEST
+       depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
+       select VIDEOBUF2_DMA_CONTIG
+       select VIDEOBUF2_VMALLOC
+       select V4L2_MEM2MEM_DEV
+       default n
+       help
+         Support for the Video Processing Unit present on Rockchip SoC,
+         which accelerates video and image encoding and decoding.
+         To compile this driver as a module, choose M here: the module
+         will be called rockchip-vpu.
diff --git a/drivers/staging/media/rockchip/vpu/Makefile b/drivers/staging/media/rockchip/vpu/Makefile
new file mode 100644 (file)
index 0000000..e9d733b
--- /dev/null
@@ -0,0 +1,10 @@
+obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o
+
+rockchip-vpu-y += \
+               rockchip_vpu_drv.o \
+               rockchip_vpu_enc.o \
+               rk3288_vpu_hw.o \
+               rk3288_vpu_hw_jpeg_enc.o \
+               rk3399_vpu_hw.o \
+               rk3399_vpu_hw_jpeg_enc.o \
+               rockchip_vpu_jpeg.o
diff --git a/drivers/staging/media/rockchip/vpu/TODO b/drivers/staging/media/rockchip/vpu/TODO
new file mode 100644 (file)
index 0000000..fa0c940
--- /dev/null
@@ -0,0 +1,13 @@
+* Support for VP8, VP9 and H264 is planned for this driver.
+
+  Given the V4L controls for those CODECs will be part of
+  the uABI, it will be required to have the driver in staging.
+
+  For this reason, we are keeping this driver in staging for now.
+
+* Add support for the S_SELECTION API.
+  See the comment for VEPU_REG_ENC_OVER_FILL_STRM_OFFSET.
+
+* Instead of having a DMA bounce buffer, it could be possible to use a
+  normal buffer and memmove() the payload to make space for the header.
+  This might need to use extra JPEG markers for padding reasons.
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c
new file mode 100644 (file)
index 0000000..a5e9d18
--- /dev/null
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_jpeg.h"
+#include "rk3288_vpu_regs.h"
+
+#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct rockchip_vpu_fmt rk3288_vpu_enc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUV420M,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .codec_mode = RK_VPU_MODE_JPEG_ENC,
+               .max_depth = 2,
+               .header_size = JPEG_HEADER_SIZE,
+               .frmsize = {
+                       .min_width = 96,
+                       .max_width = 8192,
+                       .step_width = JPEG_MB_DIM,
+                       .min_height = 32,
+                       .max_height = 8192,
+                       .step_height = JPEG_MB_DIM,
+               },
+       },
+};
+
+static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
+{
+       struct rockchip_vpu_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status, bytesused;
+
+       status = vepu_read(vpu, VEPU_REG_INTERRUPT);
+       bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8;
+       state = (status & VEPU_REG_INTERRUPT_FRAME_RDY) ?
+               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+
+       rockchip_vpu_irq_done(vpu, bytesused, state);
+
+       return IRQ_HANDLED;
+}
+
+static int rk3288_vpu_hw_init(struct rockchip_vpu_dev *vpu)
+{
+       /* Bump ACLK to max. possible freq. to improve performance. */
+       clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
+       return 0;
+}
+
+static void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
+{
+       struct rockchip_vpu_dev *vpu = ctx->dev;
+
+       vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_ENC_CTRL);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct rockchip_vpu_codec_ops rk3288_vpu_codec_ops[] = {
+       [RK_VPU_MODE_JPEG_ENC] = {
+               .run = rk3288_vpu_jpeg_enc_run,
+               .reset = rk3288_vpu_enc_reset,
+       },
+};
+
+/*
+ * VPU variant.
+ */
+
+const struct rockchip_vpu_variant rk3288_vpu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rk3288_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts),
+       .codec_ops = rk3288_vpu_codec_ops,
+       .codec = RK_VPU_CODEC_JPEG,
+       .vepu_irq = rk3288_vepu_irq,
+       .init = rk3288_vpu_hw_init,
+       .clk_names = {"aclk", "hclk"},
+       .num_clocks = 2
+};
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c
new file mode 100644 (file)
index 0000000..5282236
--- /dev/null
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+#include <media/v4l2-mem2mem.h>
+#include "rockchip_vpu_jpeg.h"
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_common.h"
+#include "rockchip_vpu_hw.h"
+#include "rk3288_vpu_regs.h"
+
+#define VEPU_JPEG_QUANT_TABLE_COUNT 16
+
+static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu,
+                                       struct rockchip_vpu_ctx *ctx)
+{
+       struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+       u32 reg;
+
+       reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width)
+               | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0)
+               | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0)
+               | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt);
+       vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL);
+}
+
+static void rk3288_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
+                                           struct rockchip_vpu_ctx *ctx,
+                                           struct vb2_buffer *src_buf)
+{
+       struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+       dma_addr_t src[3];
+
+       WARN_ON(pix_fmt->num_planes > 3);
+
+       vepu_write_relaxed(vpu, ctx->bounce_dma_addr,
+                          VEPU_REG_ADDR_OUTPUT_STREAM);
+       vepu_write_relaxed(vpu, ctx->bounce_size,
+                          VEPU_REG_STR_BUF_LIMIT);
+
+       if (pix_fmt->num_planes == 1) {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               /* single plane formats we supported are all interlaced */
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+       } else if (pix_fmt->num_planes == 2) {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+               vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
+       } else {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+               src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2);
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+               vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
+               vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2);
+       }
+}
+
+static void
+rk3288_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu,
+                              unsigned char *luma_qtable,
+                              unsigned char *chroma_qtable)
+{
+       u32 reg, i;
+
+       for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) {
+               reg = get_unaligned_be32(&luma_qtable[i]);
+               vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i));
+
+               reg = get_unaligned_be32(&chroma_qtable[i]);
+               vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i));
+       }
+}
+
+void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
+{
+       struct rockchip_vpu_dev *vpu = ctx->dev;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct rockchip_vpu_jpeg_ctx jpeg_ctx;
+       u32 reg;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+       memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
+       jpeg_ctx.buffer = vb2_plane_vaddr(dst_buf, 0);
+       jpeg_ctx.width = ctx->dst_fmt.width;
+       jpeg_ctx.height = ctx->dst_fmt.height;
+       jpeg_ctx.quality = ctx->jpeg_quality;
+       rockchip_vpu_jpeg_header_assemble(&jpeg_ctx);
+
+       /* Switch to JPEG encoder mode before writing registers */
+       vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_JPEG,
+                          VEPU_REG_ENC_CTRL);
+
+       rk3288_vpu_set_src_img_ctrl(vpu, ctx);
+       rk3288_vpu_jpeg_enc_set_buffers(vpu, ctx, src_buf);
+       rk3288_vpu_jpeg_enc_set_qtable(vpu,
+                                      rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0),
+                                      rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1));
+
+       reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16
+               | VEPU_REG_AXI_CTRL_INPUT_SWAP16
+               | VEPU_REG_AXI_CTRL_BURST_LEN(16)
+               | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32
+               | VEPU_REG_AXI_CTRL_INPUT_SWAP32
+               | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8
+               | VEPU_REG_AXI_CTRL_INPUT_SWAP8;
+       /* Make sure that all registers are written at this point. */
+       vepu_write(vpu, reg, VEPU_REG_AXI_CTRL);
+
+       reg = VEPU_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width))
+               | VEPU_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height))
+               | VEPU_REG_ENC_CTRL_ENC_MODE_JPEG
+               | VEPU_REG_ENC_PIC_INTRA
+               | VEPU_REG_ENC_CTRL_EN_BIT;
+       /* Kick the watchdog and start encoding */
+       schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+       vepu_write(vpu, reg, VEPU_REG_ENC_CTRL);
+}
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h
new file mode 100644 (file)
index 0000000..9d0b9bd
--- /dev/null
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ */
+
+#ifndef RK3288_VPU_REGS_H_
+#define RK3288_VPU_REGS_H_
+
+/* Encoder registers. */
+#define VEPU_REG_INTERRUPT                     0x004
+#define     VEPU_REG_INTERRUPT_FRAME_RDY       BIT(2)
+#define     VEPU_REG_INTERRUPT_DIS_BIT         BIT(1)
+#define     VEPU_REG_INTERRUPT_BIT             BIT(0)
+#define VEPU_REG_AXI_CTRL                      0x008
+#define     VEPU_REG_AXI_CTRL_OUTPUT_SWAP16    BIT(15)
+#define     VEPU_REG_AXI_CTRL_INPUT_SWAP16     BIT(14)
+#define     VEPU_REG_AXI_CTRL_BURST_LEN(x)     ((x) << 8)
+#define     VEPU_REG_AXI_CTRL_GATE_BIT         BIT(4)
+#define     VEPU_REG_AXI_CTRL_OUTPUT_SWAP32    BIT(3)
+#define     VEPU_REG_AXI_CTRL_INPUT_SWAP32     BIT(2)
+#define     VEPU_REG_AXI_CTRL_OUTPUT_SWAP8     BIT(1)
+#define     VEPU_REG_AXI_CTRL_INPUT_SWAP8      BIT(0)
+#define VEPU_REG_ADDR_OUTPUT_STREAM            0x014
+#define VEPU_REG_ADDR_OUTPUT_CTRL              0x018
+#define VEPU_REG_ADDR_REF_LUMA                 0x01c
+#define VEPU_REG_ADDR_REF_CHROMA               0x020
+#define VEPU_REG_ADDR_REC_LUMA                 0x024
+#define VEPU_REG_ADDR_REC_CHROMA               0x028
+#define VEPU_REG_ADDR_IN_PLANE_0               0x02c
+#define VEPU_REG_ADDR_IN_PLANE_1               0x030
+#define VEPU_REG_ADDR_IN_PLANE_2               0x034
+#define VEPU_REG_ENC_CTRL                      0x038
+#define     VEPU_REG_ENC_CTRL_TIMEOUT_EN       BIT(31)
+#define     VEPU_REG_ENC_CTRL_NAL_MODE_BIT     BIT(29)
+#define     VEPU_REG_ENC_CTRL_WIDTH(w)         ((w) << 19)
+#define     VEPU_REG_ENC_CTRL_HEIGHT(h)                ((h) << 10)
+#define     VEPU_REG_ENC_PIC_INTER             (0x0 << 3)
+#define     VEPU_REG_ENC_PIC_INTRA             (0x1 << 3)
+#define     VEPU_REG_ENC_PIC_MVCINTER          (0x2 << 3)
+#define     VEPU_REG_ENC_CTRL_ENC_MODE_H264    (0x3 << 1)
+#define     VEPU_REG_ENC_CTRL_ENC_MODE_JPEG    (0x2 << 1)
+#define     VEPU_REG_ENC_CTRL_ENC_MODE_VP8     (0x1 << 1)
+#define     VEPU_REG_ENC_CTRL_EN_BIT           BIT(0)
+#define VEPU_REG_IN_IMG_CTRL                   0x03c
+#define     VEPU_REG_IN_IMG_CTRL_ROW_LEN(x)    ((x) << 12)
+#define     VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x)  ((x) << 10)
+#define     VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x)  ((x) << 6)
+#define     VEPU_REG_IN_IMG_CTRL_FMT(x)                ((x) << 2)
+#define VEPU_REG_ENC_CTRL0                     0x040
+#define    VEPU_REG_ENC_CTRL0_INIT_QP(x)               ((x) << 26)
+#define    VEPU_REG_ENC_CTRL0_SLICE_ALPHA(x)           ((x) << 22)
+#define    VEPU_REG_ENC_CTRL0_SLICE_BETA(x)            ((x) << 18)
+#define    VEPU_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x)      ((x) << 13)
+#define    VEPU_REG_ENC_CTRL0_FILTER_DIS(x)            ((x) << 5)
+#define    VEPU_REG_ENC_CTRL0_IDR_PICID(x)             ((x) << 1)
+#define    VEPU_REG_ENC_CTRL0_CONSTR_INTRA_PRED        BIT(0)
+#define VEPU_REG_ENC_CTRL1                     0x044
+#define    VEPU_REG_ENC_CTRL1_PPS_ID(x)                        ((x) << 24)
+#define    VEPU_REG_ENC_CTRL1_INTRA_PRED_MODE(x)       ((x) << 16)
+#define    VEPU_REG_ENC_CTRL1_FRAME_NUM(x)             ((x))
+#define VEPU_REG_ENC_CTRL2                     0x048
+#define    VEPU_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x)       ((x) << 30)
+#define    VEPU_REG_ENC_CTRL2_H264_SLICE_SIZE(x)               ((x) << 23)
+#define    VEPU_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV            BIT(22)
+#define    VEPU_REG_ENC_CTRL2_TRANS8X8_MODE_EN                 BIT(21)
+#define    VEPU_REG_ENC_CTRL2_CABAC_INIT_IDC(x)                        ((x) << 19)
+#define    VEPU_REG_ENC_CTRL2_ENTROPY_CODING_MODE              BIT(18)
+#define    VEPU_REG_ENC_CTRL2_H264_INTER4X4_MODE               BIT(17)
+#define    VEPU_REG_ENC_CTRL2_H264_STREAM_MODE                 BIT(16)
+#define    VEPU_REG_ENC_CTRL2_INTRA16X16_MODE(x)               ((x))
+#define VEPU_REG_ENC_CTRL3                     0x04c
+#define    VEPU_REG_ENC_CTRL3_MUTIMV_EN                        BIT(30)
+#define    VEPU_REG_ENC_CTRL3_MV_PENALTY_1_4P(x)       ((x) << 20)
+#define    VEPU_REG_ENC_CTRL3_MV_PENALTY_4P(x)         ((x) << 10)
+#define    VEPU_REG_ENC_CTRL3_MV_PENALTY_1P(x)         ((x))
+#define VEPU_REG_ENC_CTRL4                     0x050
+#define    VEPU_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x)  ((x) << 20)
+#define    VEPU_REG_ENC_CTRL4_MV_PENALTY_8X8(x)                ((x) << 10)
+#define    VEPU_REG_ENC_CTRL4_8X4_4X8(x)               ((x))
+#define VEPU_REG_ENC_CTRL5                     0x054
+#define    VEPU_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x)    ((x) << 24)
+#define    VEPU_REG_ENC_CTRL5_COMPLETE_SLICES(x)       ((x) << 16)
+#define    VEPU_REG_ENC_CTRL5_INTER_MODE(x)            ((x))
+#define VEPU_REG_STR_HDR_REM_MSB               0x058
+#define VEPU_REG_STR_HDR_REM_LSB               0x05c
+#define VEPU_REG_STR_BUF_LIMIT                 0x060
+#define VEPU_REG_MAD_CTRL                      0x064
+#define    VEPU_REG_MAD_CTRL_QP_ADJUST(x)      ((x) << 28)
+#define    VEPU_REG_MAD_CTRL_MAD_THREDHOLD(x)  ((x) << 22)
+#define    VEPU_REG_MAD_CTRL_QP_SUM_DIV2(x)    ((x))
+#define VEPU_REG_ADDR_VP8_PROB_CNT             0x068
+#define VEPU_REG_QP_VAL                                0x06c
+#define    VEPU_REG_QP_VAL_LUM(x)              ((x) << 26)
+#define    VEPU_REG_QP_VAL_MAX(x)              ((x) << 20)
+#define    VEPU_REG_QP_VAL_MIN(x)              ((x) << 14)
+#define    VEPU_REG_QP_VAL_CHECKPOINT_DISTAN(x)        ((x))
+#define VEPU_REG_VP8_QP_VAL(i)                 (0x06c + ((i) * 0x4))
+#define VEPU_REG_CHECKPOINT(i)                 (0x070 + ((i) * 0x4))
+#define     VEPU_REG_CHECKPOINT_CHECK0(x)      (((x) & 0xffff))
+#define     VEPU_REG_CHECKPOINT_CHECK1(x)      (((x) & 0xffff) << 16)
+#define     VEPU_REG_CHECKPOINT_RESULT(x)      ((((x) >> (16 - 16 \
+                                                * (i & 1))) & 0xffff) \
+                                                * 32)
+#define VEPU_REG_CHKPT_WORD_ERR(i)             (0x084 + ((i) * 0x4))
+#define     VEPU_REG_CHKPT_WORD_ERR_CHK0(x)    (((x) & 0xffff))
+#define     VEPU_REG_CHKPT_WORD_ERR_CHK1(x)    (((x) & 0xffff) << 16)
+#define VEPU_REG_VP8_BOOL_ENC                  0x08c
+#define VEPU_REG_CHKPT_DELTA_QP                        0x090
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK0(x)    (((x) & 0x0f) << 0)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK1(x)    (((x) & 0x0f) << 4)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK2(x)    (((x) & 0x0f) << 8)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK3(x)    (((x) & 0x0f) << 12)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK4(x)    (((x) & 0x0f) << 16)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK5(x)    (((x) & 0x0f) << 20)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK6(x)    (((x) & 0x0f) << 24)
+#define VEPU_REG_VP8_CTRL0                     0x090
+#define VEPU_REG_RLC_CTRL                      0x094
+#define     VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT   23
+#define     VEPU_REG_RLC_CTRL_STR_OFFS_MASK    (0x3f << 23)
+#define     VEPU_REG_RLC_CTRL_RLC_SUM(x)       ((x))
+#define VEPU_REG_MB_CTRL                       0x098
+#define     VEPU_REG_MB_CNT_OUT(x)             (((x) & 0xffff))
+#define     VEPU_REG_MB_CNT_SET(x)             (((x) & 0xffff) << 16)
+#define VEPU_REG_ADDR_NEXT_PIC                 0x09c
+#define        VEPU_REG_JPEG_LUMA_QUAT(i)              (0x100 + ((i) * 0x4))
+#define        VEPU_REG_JPEG_CHROMA_QUAT(i)            (0x140 + ((i) * 0x4))
+#define VEPU_REG_STABILIZATION_OUTPUT          0x0A0
+#define VEPU_REG_ADDR_CABAC_TBL                        0x0cc
+#define VEPU_REG_ADDR_MV_OUT                   0x0d0
+#define VEPU_REG_RGB_YUV_COEFF(i)              (0x0d4 + ((i) * 0x4))
+#define VEPU_REG_RGB_MASK_MSB                  0x0dc
+#define VEPU_REG_INTRA_AREA_CTRL               0x0e0
+#define VEPU_REG_CIR_INTRA_CTRL                        0x0e4
+#define VEPU_REG_INTRA_SLICE_BITMAP(i)         (0x0e8 + ((i) * 0x4))
+#define VEPU_REG_ADDR_VP8_DCT_PART(i)          (0x0e8 + ((i) * 0x4))
+#define VEPU_REG_FIRST_ROI_AREA                        0x0f0
+#define VEPU_REG_SECOND_ROI_AREA               0x0f4
+#define VEPU_REG_MVC_CTRL                      0x0f8
+#define        VEPU_REG_MVC_CTRL_MV16X16_FAVOR(x)      ((x) << 28)
+#define VEPU_REG_VP8_INTRA_PENALTY(i)          (0x100 + ((i) * 0x4))
+#define VEPU_REG_ADDR_VP8_SEG_MAP              0x11c
+#define VEPU_REG_VP8_SEG_QP(i)                 (0x120 + ((i) * 0x4))
+#define VEPU_REG_DMV_4P_1P_PENALTY(i)          (0x180 + ((i) * 0x4))
+#define     VEPU_REG_DMV_4P_1P_PENALTY_BIT(x, i)       ((x) << (i) * 8)
+#define VEPU_REG_DMV_QPEL_PENALTY(i)           (0x200 + ((i) * 0x4))
+#define     VEPU_REG_DMV_QPEL_PENALTY_BIT(x, i)        ((x) << (i) * 8)
+#define VEPU_REG_VP8_CTRL1                     0x280
+#define VEPU_REG_VP8_BIT_COST_GOLDEN           0x284
+#define VEPU_REG_VP8_LOOP_FLT_DELTA(i)         (0x288 + ((i) * 0x4))
+
+/* Decoder registers. */
+#define VDPU_REG_INTERRUPT                     0x004
+#define     VDPU_REG_INTERRUPT_DEC_PIC_INF             BIT(24)
+#define     VDPU_REG_INTERRUPT_DEC_TIMEOUT             BIT(18)
+#define     VDPU_REG_INTERRUPT_DEC_SLICE_INT           BIT(17)
+#define     VDPU_REG_INTERRUPT_DEC_ERROR_INT           BIT(16)
+#define     VDPU_REG_INTERRUPT_DEC_ASO_INT             BIT(15)
+#define     VDPU_REG_INTERRUPT_DEC_BUFFER_INT          BIT(14)
+#define     VDPU_REG_INTERRUPT_DEC_BUS_INT             BIT(13)
+#define     VDPU_REG_INTERRUPT_DEC_RDY_INT             BIT(12)
+#define     VDPU_REG_INTERRUPT_DEC_IRQ                 BIT(8)
+#define     VDPU_REG_INTERRUPT_DEC_IRQ_DIS             BIT(4)
+#define     VDPU_REG_INTERRUPT_DEC_E                   BIT(0)
+#define VDPU_REG_CONFIG                                0x008
+#define     VDPU_REG_CONFIG_DEC_AXI_RD_ID(x)           (((x) & 0xff) << 24)
+#define     VDPU_REG_CONFIG_DEC_TIMEOUT_E              BIT(23)
+#define     VDPU_REG_CONFIG_DEC_STRSWAP32_E            BIT(22)
+#define     VDPU_REG_CONFIG_DEC_STRENDIAN_E            BIT(21)
+#define     VDPU_REG_CONFIG_DEC_INSWAP32_E             BIT(20)
+#define     VDPU_REG_CONFIG_DEC_OUTSWAP32_E            BIT(19)
+#define     VDPU_REG_CONFIG_DEC_DATA_DISC_E            BIT(18)
+#define     VDPU_REG_CONFIG_TILED_MODE_MSB             BIT(17)
+#define     VDPU_REG_CONFIG_DEC_OUT_TILED_E            BIT(17)
+#define     VDPU_REG_CONFIG_DEC_LATENCY(x)             (((x) & 0x3f) << 11)
+#define     VDPU_REG_CONFIG_DEC_CLK_GATE_E             BIT(10)
+#define     VDPU_REG_CONFIG_DEC_IN_ENDIAN              BIT(9)
+#define     VDPU_REG_CONFIG_DEC_OUT_ENDIAN             BIT(8)
+#define     VDPU_REG_CONFIG_PRIORITY_MODE(x)           (((x) & 0x7) << 5)
+#define     VDPU_REG_CONFIG_TILED_MODE_LSB             BIT(7)
+#define     VDPU_REG_CONFIG_DEC_ADV_PRE_DIS            BIT(6)
+#define     VDPU_REG_CONFIG_DEC_SCMD_DIS               BIT(5)
+#define     VDPU_REG_CONFIG_DEC_MAX_BURST(x)           (((x) & 0x1f) << 0)
+#define VDPU_REG_DEC_CTRL0                     0x00c
+#define     VDPU_REG_DEC_CTRL0_DEC_MODE(x)             (((x) & 0xf) << 28)
+#define     VDPU_REG_DEC_CTRL0_RLC_MODE_E              BIT(27)
+#define     VDPU_REG_DEC_CTRL0_SKIP_MODE               BIT(26)
+#define     VDPU_REG_DEC_CTRL0_DIVX3_E                 BIT(25)
+#define     VDPU_REG_DEC_CTRL0_PJPEG_E                 BIT(24)
+#define     VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E         BIT(23)
+#define     VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E         BIT(22)
+#define     VDPU_REG_DEC_CTRL0_PIC_B_E                 BIT(21)
+#define     VDPU_REG_DEC_CTRL0_PIC_INTER_E             BIT(20)
+#define     VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E          BIT(19)
+#define     VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E         BIT(18)
+#define     VDPU_REG_DEC_CTRL0_SORENSON_E              BIT(17)
+#define     VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E          BIT(16)
+#define     VDPU_REG_DEC_CTRL0_DEC_OUT_DIS             BIT(15)
+#define     VDPU_REG_DEC_CTRL0_FILTERING_DIS           BIT(14)
+#define     VDPU_REG_DEC_CTRL0_WEBP_E                  BIT(13)
+#define     VDPU_REG_DEC_CTRL0_MVC_E                   BIT(13)
+#define     VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT         BIT(13)
+#define     VDPU_REG_DEC_CTRL0_WRITE_MVS_E             BIT(12)
+#define     VDPU_REG_DEC_CTRL0_REFTOPFIRST_E           BIT(11)
+#define     VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E             BIT(10)
+#define     VDPU_REG_DEC_CTRL0_PICORD_COUNT_E          BIT(9)
+#define     VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E         BIT(8)
+#define     VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x)                (((x) & 0xff) << 0)
+#define VDPU_REG_DEC_CTRL1                     0x010
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x)         (((x) & 0x1ff) << 23)
+#define     VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x)         (((x) & 0xf) << 19)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x)      (((x) & 0xff) << 11)
+#define     VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x)                (((x) & 0xf) << 7)
+#define     VDPU_REG_DEC_CTRL1_ALT_SCAN_E              BIT(6)
+#define     VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E         BIT(5)
+#define     VDPU_REG_DEC_CTRL1_REF_FRAMES(x)           (((x) & 0x1f) << 0)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x)         (((x) & 0x7) << 3)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x)         (((x) & 0x7) << 0)
+#define     VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG          BIT(0)
+#define VDPU_REG_DEC_CTRL2                     0x014
+#define     VDPU_REG_DEC_CTRL2_STRM_START_BIT(x)       (((x) & 0x3f) << 26)
+#define     VDPU_REG_DEC_CTRL2_SYNC_MARKER_E           BIT(25)
+#define     VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E           BIT(24)
+#define     VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x)         (((x) & 0x1f) << 19)
+#define     VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x)                (((x) & 0x1f) << 14)
+#define     VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E         BIT(0)
+#define     VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x)      (((x) & 0x7) << 16)
+#define     VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x)                (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL2_DQ_PROFILE              BIT(24)
+#define     VDPU_REG_DEC_CTRL2_DQBI_LEVEL              BIT(23)
+#define     VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E         BIT(22)
+#define     VDPU_REG_DEC_CTRL2_FAST_UVMC_E             BIT(20)
+#define     VDPU_REG_DEC_CTRL2_TRANSDCTAB              BIT(17)
+#define     VDPU_REG_DEC_CTRL2_TRANSACFRM(x)           (((x) & 0x3) << 15)
+#define     VDPU_REG_DEC_CTRL2_TRANSACFRM2(x)          (((x) & 0x3) << 13)
+#define     VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x)          (((x) & 0x7) << 10)
+#define     VDPU_REG_DEC_CTRL2_MVTAB(x)                        (((x) & 0x7) << 7)
+#define     VDPU_REG_DEC_CTRL2_CBPTAB(x)               (((x) & 0x7) << 4)
+#define     VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x)      (((x) & 0x3) << 2)
+#define     VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x)      (((x) & 0x3) << 0)
+#define     VDPU_REG_DEC_CTRL2_QSCALE_TYPE             BIT(24)
+#define     VDPU_REG_DEC_CTRL2_CON_MV_E                        BIT(4)
+#define     VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x)                (((x) & 0x3) << 2)
+#define     VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB           BIT(1)
+#define     VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT          BIT(0)
+#define     VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x)         (((x) & 0x3) << 11)
+#define     VDPU_REG_DEC_CTRL2_JPEG_MODE(x)            (((x) & 0x7) << 8)
+#define     VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E         BIT(7)
+#define     VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL         BIT(6)
+#define     VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE          BIT(5)
+#define     VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE          BIT(4)
+#define     VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE          BIT(3)
+#define     VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE          BIT(2)
+#define     VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3         BIT(1)
+#define     VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3         BIT(0)
+#define     VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x)      (((x) & 0x3f) << 18)
+#define     VDPU_REG_DEC_CTRL2_HUFFMAN_E               BIT(17)
+#define     VDPU_REG_DEC_CTRL2_MULTISTREAM_E           BIT(16)
+#define     VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x)                (((x) & 0xff) << 8)
+#define     VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x)                (((x) & 0xff) << 0)
+#define     VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x)         (((x) & 0x1f) << 5)
+#define     VDPU_REG_DEC_CTRL2_BETA_OFFSET(x)          (((x) & 0x1f) << 0)
+#define VDPU_REG_DEC_CTRL3                     0x018
+#define     VDPU_REG_DEC_CTRL3_START_CODE_E            BIT(31)
+#define     VDPU_REG_DEC_CTRL3_INIT_QP(x)              (((x) & 0x3f) << 25)
+#define     VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E         BIT(24)
+#define     VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x)       (((x) & 0xff) << 24)
+#define     VDPU_REG_DEC_CTRL3_STREAM_LEN(x)           (((x) & 0xffffff) << 0)
+#define VDPU_REG_DEC_CTRL4                     0x01c
+#define     VDPU_REG_DEC_CTRL4_CABAC_E                 BIT(31)
+#define     VDPU_REG_DEC_CTRL4_BLACKWHITE_E            BIT(30)
+#define     VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E         BIT(29)
+#define     VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E           BIT(28)
+#define     VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x)      (((x) & 0x3) << 26)
+#define     VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT          BIT(25)
+#define     VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x)         (((x) & 0x1f) << 16)
+#define     VDPU_REG_DEC_CTRL4_FRAMENUM(x)             (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL4_BITPLANE0_E             BIT(31)
+#define     VDPU_REG_DEC_CTRL4_BITPLANE1_E             BIT(30)
+#define     VDPU_REG_DEC_CTRL4_BITPLANE2_E             BIT(29)
+#define     VDPU_REG_DEC_CTRL4_ALT_PQUANT(x)           (((x) & 0x1f) << 24)
+#define     VDPU_REG_DEC_CTRL4_DQ_EDGES(x)             (((x) & 0xf) << 20)
+#define     VDPU_REG_DEC_CTRL4_TTMBF                   BIT(19)
+#define     VDPU_REG_DEC_CTRL4_PQINDEX(x)              (((x) & 0x1f) << 14)
+#define     VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT          BIT(13)
+#define     VDPU_REG_DEC_CTRL4_BILIN_MC_E              BIT(12)
+#define     VDPU_REG_DEC_CTRL4_UNIQP_E                 BIT(11)
+#define     VDPU_REG_DEC_CTRL4_HALFQP_E                        BIT(10)
+#define     VDPU_REG_DEC_CTRL4_TTFRM(x)                        (((x) & 0x3) << 8)
+#define     VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E         BIT(7)
+#define     VDPU_REG_DEC_CTRL4_DQUANT_E                        BIT(6)
+#define     VDPU_REG_DEC_CTRL4_VC1_ADV_E               BIT(5)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E         BIT(26)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_WDIV8             BIT(25)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_HDIV8             BIT(24)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_AH(x)             (((x) & 0xf) << 20)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_AL(x)             (((x) & 0xf) << 16)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_SS(x)             (((x) & 0xff) << 8)
+#define     VDPU_REG_DEC_CTRL4_PJPEG_SE(x)             (((x) & 0xff) << 0)
+#define     VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x)       (((x) & 0x3f) << 26)
+#define     VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x)       (((x) & 0x3f) << 20)
+#define     VDPU_REG_DEC_CTRL4_CH_MV_RES               BIT(13)
+#define     VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x)       (((x) & 0x7) << 9)
+#define     VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x)       (((x) & 0x7) << 6)
+#define     VDPU_REG_DEC_CTRL4_VP7_VERSION             BIT(5)
+#define VDPU_REG_DEC_CTRL5                     0x020
+#define     VDPU_REG_DEC_CTRL5_CONST_INTRA_E           BIT(31)
+#define     VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES          BIT(30)
+#define     VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES          BIT(29)
+#define     VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E         BIT(28)
+#define     VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x)                (((x) & 0x7ff) << 17)
+#define     VDPU_REG_DEC_CTRL5_IDR_PIC_E               BIT(16)
+#define     VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x)           (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x)       (((x) & 0xff) << 24)
+#define     VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x)         (((x) & 0x1f) << 19)
+#define     VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x)         (((x) & 0x1f) << 14)
+#define     VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x)      (((x) & 0xf) << 14)
+#define     VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E         BIT(13)
+#define     VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x)         (((x) & 0x7) << 10)
+#define     VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x)                (((x) & 0x3ff) << 0)
+#define     VDPU_REG_DEC_CTRL5_DIVX_IDCT_E             BIT(8)
+#define     VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x)     (((x) & 0xff) << 0)
+#define     VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x)      (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL5_RV_PROFILE(x)           (((x) & 0x3) << 30)
+#define     VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x)         (((x) & 0x3) << 28)
+#define     VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x)         (((x) & 0x3fff) << 14)
+#define     VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x)         (((x) & 0x3fff) << 0)
+#define     VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x)                (((x) & 0xffff) << 16)
+#define     VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x)                (((x) & 0xffff) << 0)
+#define VDPU_REG_DEC_CTRL6                     0x024
+#define     VDPU_REG_DEC_CTRL6_PPS_ID(x)               (((x) & 0xff) << 24)
+#define     VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x)       (((x) & 0x1f) << 19)
+#define     VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x)       (((x) & 0x1f) << 14)
+#define     VDPU_REG_DEC_CTRL6_POC_LENGTH(x)           (((x) & 0xff) << 0)
+#define     VDPU_REG_DEC_CTRL6_ICOMP0_E                        BIT(24)
+#define     VDPU_REG_DEC_CTRL6_ISCALE0(x)              (((x) & 0xff) << 16)
+#define     VDPU_REG_DEC_CTRL6_ISHIFT0(x)              (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL6_STREAM1_LEN(x)          (((x) & 0xffffff) << 0)
+#define     VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x)         (((x) & 0x1fff) << 0)
+#define     VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x)       (((x) & 0xf) << 24)
+#define VDPU_REG_FWD_PIC(i)                    (0x028 + ((i) * 0x4))
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x)         (((x) & 0x1f) << 25)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x)         (((x) & 0x1f) << 20)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x)         (((x) & 0x1f) << 15)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x)         (((x) & 0x1f) << 10)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x)         (((x) & 0x1f) << 5)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x)         (((x) & 0x1f) << 0)
+#define     VDPU_REG_FWD_PIC1_ICOMP1_E                 BIT(24)
+#define     VDPU_REG_FWD_PIC1_ISCALE1(x)               (((x) & 0xff) << 16)
+#define     VDPU_REG_FWD_PIC1_ISHIFT1(x)               (((x) & 0xffff) << 0)
+#define     VDPU_REG_FWD_PIC1_SEGMENT_BASE(x)          ((x) << 0)
+#define     VDPU_REG_FWD_PIC1_SEGMENT_UPD_E            BIT(1)
+#define     VDPU_REG_FWD_PIC1_SEGMENT_E                        BIT(0)
+#define VDPU_REG_DEC_CTRL7                     0x02c
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x)      (((x) & 0x1f) << 25)
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x)      (((x) & 0x1f) << 20)
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x)      (((x) & 0x1f) << 0)
+#define     VDPU_REG_DEC_CTRL7_ICOMP2_E                        BIT(24)
+#define     VDPU_REG_DEC_CTRL7_ISCALE2(x)              (((x) & 0xff) << 16)
+#define     VDPU_REG_DEC_CTRL7_ISHIFT2(x)              (((x) & 0xffff) << 0)
+#define     VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x)       (((x) & 0x3f) << 24)
+#define     VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x)       (((x) & 0x3f) << 18)
+#define     VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x)       (((x) & 0x3f) << 12)
+#define     VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x)       (((x) & 0x3f) << 6)
+#define     VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x)       (((x) & 0x3f) << 0)
+#define VDPU_REG_ADDR_STR                      0x030
+#define VDPU_REG_ADDR_DST                      0x034
+#define VDPU_REG_ADDR_REF(i)                   (0x038 + ((i) * 0x4))
+#define     VDPU_REG_ADDR_REF_FIELD_E                  BIT(1)
+#define     VDPU_REG_ADDR_REF_TOPC_E                   BIT(0)
+#define VDPU_REG_REF_PIC(i)                    (0x078 + ((i) * 0x4))
+#define     VDPU_REG_REF_PIC_FILT_TYPE_E               BIT(31)
+#define     VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28)
+#define     VDPU_REG_REF_PIC_MB_ADJ_0(x)               (((x) & 0x7f) << 21)
+#define     VDPU_REG_REF_PIC_MB_ADJ_1(x)               (((x) & 0x7f) << 14)
+#define     VDPU_REG_REF_PIC_MB_ADJ_2(x)               (((x) & 0x7f) << 7)
+#define     VDPU_REG_REF_PIC_MB_ADJ_3(x)               (((x) & 0x7f) << 0)
+#define     VDPU_REG_REF_PIC_REFER1_NBR(x)             (((x) & 0xffff) << 16)
+#define     VDPU_REG_REF_PIC_REFER0_NBR(x)             (((x) & 0xffff) << 0)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_0(x)             (((x) & 0x3f) << 18)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_1(x)             (((x) & 0x3f) << 12)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_2(x)             (((x) & 0x3f) << 6)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_3(x)             (((x) & 0x3f) << 0)
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_0(x)  (((x) & 0x1f) << 27)
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_1(x)  (((x) & 0x1f) << 22)
+#define     VDPU_REG_REF_PIC_QUANT_0(x)                        (((x) & 0x7ff) << 11)
+#define     VDPU_REG_REF_PIC_QUANT_1(x)                        (((x) & 0x7ff) << 0)
+#define VDPU_REG_LT_REF                                0x098
+#define VDPU_REG_VALID_REF                     0x09c
+#define VDPU_REG_ADDR_QTABLE                   0x0a0
+#define VDPU_REG_ADDR_DIR_MV                   0x0a4
+#define VDPU_REG_BD_REF_PIC(i)                 (0x0a8 + ((i) * 0x4))
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x)      (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x)      (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x)      (((x) & 0x1f) << 0)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x)       (((x) & 0x3) << 10)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x)                (((x) & 0x3) << 8)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x)       (((x) & 0x3) << 6)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x)                (((x) & 0x3) << 4)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x)       (((x) & 0x3) << 2)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x)                (((x) & 0x3) << 0)
+#define     VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x)       (((x) & 0x1f) << 27)
+#define     VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x)       (((x) & 0x1f) << 22)
+#define     VDPU_REG_BD_REF_PIC_QUANT_2(x)             (((x) & 0x7ff) << 11)
+#define     VDPU_REG_BD_REF_PIC_QUANT_3(x)             (((x) & 0x7ff) << 0)
+#define VDPU_REG_BD_P_REF_PIC                  0x0bc
+#define     VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x)     (((x) & 0x1f) << 27)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x)    (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x)    (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x)    (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x)    (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x)   (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x)   (((x) & 0x1f) << 0)
+#define VDPU_REG_ERR_CONC                      0x0c0
+#define     VDPU_REG_ERR_CONC_STARTMB_X(x)             (((x) & 0x1ff) << 23)
+#define     VDPU_REG_ERR_CONC_STARTMB_Y(x)             (((x) & 0xff) << 15)
+#define VDPU_REG_PRED_FLT                      0x0c4
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_REF_BUF_CTRL                  0x0cc
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_E              BIT(31)
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_THR(x)         (((x) & 0xfff) << 19)
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x)       (((x) & 0x1f) << 14)
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E         BIT(13)
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E      BIT(12)
+#define     VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x)    (((x) & 0x1ff) << 0)
+#define VDPU_REG_REF_BUF_CTRL2                 0x0dc
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E                BIT(31)
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x)       (((x) & 0xfff) << 19)
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x)     (((x) & 0x1f) << 14)
+#define     VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x)    (((x) & 0x3fff) << 0)
+
+#endif /* RK3288_VPU_REGS_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c
new file mode 100644 (file)
index 0000000..6fdef61
--- /dev/null
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_jpeg.h"
+#include "rk3399_vpu_regs.h"
+
+#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct rockchip_vpu_fmt rk3399_vpu_enc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUV420M,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .codec_mode = RK_VPU_MODE_NONE,
+               .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .codec_mode = RK_VPU_MODE_JPEG_ENC,
+               .max_depth = 2,
+               .header_size = JPEG_HEADER_SIZE,
+               .frmsize = {
+                       .min_width = 96,
+                       .max_width = 8192,
+                       .step_width = JPEG_MB_DIM,
+                       .min_height = 32,
+                       .max_height = 8192,
+                       .step_height = JPEG_MB_DIM,
+               },
+       },
+};
+
+static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id)
+{
+       struct rockchip_vpu_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status, bytesused;
+
+       status = vepu_read(vpu, VEPU_REG_INTERRUPT);
+       bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8;
+       state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ?
+               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+
+       rockchip_vpu_irq_done(vpu, bytesused, state);
+
+       return IRQ_HANDLED;
+}
+
+static int rk3399_vpu_hw_init(struct rockchip_vpu_dev *vpu)
+{
+       /* Bump ACLK to max. possible freq. to improve performance. */
+       clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
+       return 0;
+}
+
+static void rk3399_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
+{
+       struct rockchip_vpu_dev *vpu = ctx->dev;
+
+       vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_ENCODE_START);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct rockchip_vpu_codec_ops rk3399_vpu_codec_ops[] = {
+       [RK_VPU_MODE_JPEG_ENC] = {
+               .run = rk3399_vpu_jpeg_enc_run,
+               .reset = rk3399_vpu_enc_reset,
+       },
+};
+
+/*
+ * VPU variant.
+ */
+
+const struct rockchip_vpu_variant rk3399_vpu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rk3399_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts),
+       .codec = RK_VPU_CODEC_JPEG,
+       .codec_ops = rk3399_vpu_codec_ops,
+       .vepu_irq = rk3399_vepu_irq,
+       .init = rk3399_vpu_hw_init,
+       .clk_names = {"aclk", "hclk"},
+       .num_clocks = 2
+};
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c
new file mode 100644 (file)
index 0000000..dbc86d9
--- /dev/null
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *
+ * JPEG encoder
+ * ------------
+ * The VPU JPEG encoder produces JPEG baseline sequential format.
+ * The quantization coefficients are 8-bit values, complying with
+ * the baseline specification. Therefore, it requires
+ * luma and chroma quantization tables. The hardware does entropy
+ * encoding using internal Huffman tables, as specified in the JPEG
+ * specification.
+ *
+ * In other words, only the luma and chroma quantization tables are
+ * required for the encoding operation.
+ *
+ * Quantization luma table values are written to registers
+ * VEPU_swreg_0-VEPU_swreg_15, and chroma table values to
+ * VEPU_swreg_16-VEPU_swreg_31.
+ *
+ * JPEG zigzag order is expected on the quantization tables.
+ */
+
+#include <asm/unaligned.h>
+#include <media/v4l2-mem2mem.h>
+#include "rockchip_vpu_jpeg.h"
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_common.h"
+#include "rockchip_vpu_hw.h"
+#include "rk3399_vpu_regs.h"
+
+#define VEPU_JPEG_QUANT_TABLE_COUNT 16
+
+static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu,
+                                       struct rockchip_vpu_ctx *ctx)
+{
+       struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+       u32 reg;
+
+       /*
+        * The pix fmt width/height are already macroblock aligned
+        * by .vidioc_s_fmt_vid_cap_mplane() callback
+        */
+       reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width);
+       vepu_write_relaxed(vpu, reg, VEPU_REG_INPUT_LUMA_INFO);
+
+       reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) |
+             VEPU_REG_IN_IMG_CTRL_OVRFLB(0);
+       /*
+        * This register controls the input crop, as the offset
+        * from the right/bottom within the last macroblock. The offset from the
+        * right must be divided by 4 and so the crop must be aligned to 4 pixels
+        * horizontally.
+        */
+       vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_OVER_FILL_STRM_OFFSET);
+
+       reg = VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt);
+       vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1);
+}
+
+static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
+                                           struct rockchip_vpu_ctx *ctx,
+                                           struct vb2_buffer *src_buf)
+{
+       struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+       dma_addr_t src[3];
+
+       WARN_ON(pix_fmt->num_planes > 3);
+
+       vepu_write_relaxed(vpu, ctx->bounce_dma_addr,
+                          VEPU_REG_ADDR_OUTPUT_STREAM);
+       vepu_write_relaxed(vpu, ctx->bounce_size,
+                          VEPU_REG_STR_BUF_LIMIT);
+
+       if (pix_fmt->num_planes == 1) {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+       } else if (pix_fmt->num_planes == 2) {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+               vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
+       } else {
+               src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+               src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+               src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2);
+               vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
+               vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
+               vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2);
+       }
+}
+
+static void
+rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu,
+                              unsigned char *luma_qtable,
+                              unsigned char *chroma_qtable)
+{
+       u32 reg, i;
+
+       for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) {
+               reg = get_unaligned_be32(&luma_qtable[i]);
+               vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i));
+
+               reg = get_unaligned_be32(&chroma_qtable[i]);
+               vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i));
+       }
+}
+
+void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
+{
+       struct rockchip_vpu_dev *vpu = ctx->dev;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct rockchip_vpu_jpeg_ctx jpeg_ctx;
+       u32 reg;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+       memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
+       jpeg_ctx.buffer = vb2_plane_vaddr(dst_buf, 0);
+       jpeg_ctx.width = ctx->dst_fmt.width;
+       jpeg_ctx.height = ctx->dst_fmt.height;
+       jpeg_ctx.quality = ctx->jpeg_quality;
+       rockchip_vpu_jpeg_header_assemble(&jpeg_ctx);
+
+       /* Switch to JPEG encoder mode before writing registers */
+       vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG,
+                          VEPU_REG_ENCODE_START);
+
+       rk3399_vpu_set_src_img_ctrl(vpu, ctx);
+       rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, src_buf);
+       rk3399_vpu_jpeg_enc_set_qtable(vpu,
+                                      rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0),
+                                      rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1));
+
+       reg = VEPU_REG_OUTPUT_SWAP32
+               | VEPU_REG_OUTPUT_SWAP16
+               | VEPU_REG_OUTPUT_SWAP8
+               | VEPU_REG_INPUT_SWAP8
+               | VEPU_REG_INPUT_SWAP16
+               | VEPU_REG_INPUT_SWAP32;
+       /* Make sure that all registers are written at this point. */
+       vepu_write(vpu, reg, VEPU_REG_DATA_ENDIAN);
+
+       reg = VEPU_REG_AXI_CTRL_BURST_LEN(16);
+       vepu_write_relaxed(vpu, reg, VEPU_REG_AXI_CTRL);
+
+       reg = VEPU_REG_MB_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width))
+               | VEPU_REG_MB_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height))
+               | VEPU_REG_FRAME_TYPE_INTRA
+               | VEPU_REG_ENCODE_FORMAT_JPEG
+               | VEPU_REG_ENCODE_ENABLE;
+
+       /* Kick the watchdog and start encoding */
+       schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+       vepu_write(vpu, reg, VEPU_REG_ENCODE_START);
+}
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h
new file mode 100644 (file)
index 0000000..fbe2941
--- /dev/null
@@ -0,0 +1,600 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Alpha Lin <alpha.lin@rock-chips.com>
+ */
+
+#ifndef RK3399_VPU_REGS_H_
+#define RK3399_VPU_REGS_H_
+
+/* Encoder registers. */
+#define VEPU_REG_VP8_QUT_1ST(i)                        (0x000 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_DC_Y2(x)                  (((x) & 0x3fff) << 16)
+#define     VEPU_REG_VP8_QUT_DC_Y1(x)                  (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_QUT_2ND(i)                        (0x004 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_AC_Y1(x)                  (((x) & 0x3fff) << 16)
+#define     VEPU_REG_VP8_QUT_DC_CHR(x)                 (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_QUT_3RD(i)                        (0x008 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_AC_CHR(x)                 (((x) & 0x3fff) << 16)
+#define     VEPU_REG_VP8_QUT_AC_Y2(x)                  (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_QUT_4TH(i)                        (0x00c + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_ZB_DC_CHR(x)              (((x) & 0x1ff) << 18)
+#define     VEPU_REG_VP8_QUT_ZB_DC_Y2(x)               (((x) & 0x1ff) << 9)
+#define     VEPU_REG_VP8_QUT_ZB_DC_Y1(x)               (((x) & 0x1ff) << 0)
+#define VEPU_REG_VP8_QUT_5TH(i)                        (0x010 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_ZB_AC_CHR(x)              (((x) & 0x1ff) << 18)
+#define     VEPU_REG_VP8_QUT_ZB_AC_Y2(x)               (((x) & 0x1ff) << 9)
+#define     VEPU_REG_VP8_QUT_ZB_AC_Y1(x)               (((x) & 0x1ff) << 0)
+#define VEPU_REG_VP8_QUT_6TH(i)                        (0x014 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_RND_DC_CHR(x)             (((x) & 0xff) << 16)
+#define     VEPU_REG_VP8_QUT_RND_DC_Y2(x)              (((x) & 0xff) << 8)
+#define     VEPU_REG_VP8_QUT_RND_DC_Y1(x)              (((x) & 0xff) << 0)
+#define VEPU_REG_VP8_QUT_7TH(i)                        (0x018 + ((i) * 0x24))
+#define     VEPU_REG_VP8_QUT_RND_AC_CHR(x)             (((x) & 0xff) << 16)
+#define     VEPU_REG_VP8_QUT_RND_AC_Y2(x)              (((x) & 0xff) << 8)
+#define     VEPU_REG_VP8_QUT_RND_AC_Y1(x)              (((x) & 0xff) << 0)
+#define VEPU_REG_VP8_QUT_8TH(i)                        (0x01c + ((i) * 0x24))
+#define     VEPU_REG_VP8_SEG_FILTER_LEVEL(x)           (((x) & 0x3f) << 25)
+#define     VEPU_REG_VP8_DEQUT_DC_CHR(x)               (((x) & 0xff) << 17)
+#define     VEPU_REG_VP8_DEQUT_DC_Y2(x)                        (((x) & 0x1ff) << 8)
+#define     VEPU_REG_VP8_DEQUT_DC_Y1(x)                        (((x) & 0xff) << 0)
+#define VEPU_REG_VP8_QUT_9TH(i)                        (0x020 + ((i) * 0x24))
+#define     VEPU_REG_VP8_DEQUT_AC_CHR(x)               (((x) & 0x1ff) << 18)
+#define     VEPU_REG_VP8_DEQUT_AC_Y2(x)                        (((x) & 0x1ff) << 9)
+#define     VEPU_REG_VP8_DEQUT_AC_Y1(x)                        (((x) & 0x1ff) << 0)
+#define VEPU_REG_ADDR_VP8_SEG_MAP              0x06c
+#define VEPU_REG_VP8_INTRA_4X4_PENALTY(i)      (0x070 + ((i) * 0x4))
+#define     VEPU_REG_VP8_INTRA_4X4_PENALTY_0(x)                (((x) & 0xfff) << 0)
+#define     VEPU_REG_VP8_INTRA_4x4_PENALTY_1(x)                (((x) & 0xfff) << 16)
+#define VEPU_REG_VP8_INTRA_16X16_PENALTY(i)    (0x084 + ((i) * 0x4))
+#define     VEPU_REG_VP8_INTRA_16X16_PENALTY_0(x)      (((x) & 0xfff) << 0)
+#define     VEPU_REG_VP8_INTRA_16X16_PENALTY_1(x)      (((x) & 0xfff) << 16)
+#define VEPU_REG_VP8_CONTROL                   0x0a0
+#define     VEPU_REG_VP8_LF_MODE_DELTA_BPRED(x)                (((x) & 0x1f) << 24)
+#define     VEPU_REG_VP8_LF_REF_DELTA_INTRA_MB(x)      (((x) & 0x7f) << 16)
+#define     VEPU_REG_VP8_INTER_TYPE_BIT_COST(x)                (((x) & 0xfff) << 0)
+#define VEPU_REG_VP8_REF_FRAME_VAL             0x0a4
+#define     VEPU_REG_VP8_COEF_DMV_PENALTY(x)           (((x) & 0xfff) << 16)
+#define     VEPU_REG_VP8_REF_FRAME(x)                  (((x) & 0xfff) << 0)
+#define VEPU_REG_VP8_LOOP_FILTER_REF_DELTA     0x0a8
+#define     VEPU_REG_VP8_LF_REF_DELTA_ALT_REF(x)       (((x) & 0x7f) << 16)
+#define     VEPU_REG_VP8_LF_REF_DELTA_LAST_REF(x)      (((x) & 0x7f) << 8)
+#define     VEPU_REG_VP8_LF_REF_DELTA_GOLDEN(x)                (((x) & 0x7f) << 0)
+#define VEPU_REG_VP8_LOOP_FILTER_MODE_DELTA    0x0ac
+#define     VEPU_REG_VP8_LF_MODE_DELTA_SPLITMV(x)      (((x) & 0x7f) << 16)
+#define     VEPU_REG_VP8_LF_MODE_DELTA_ZEROMV(x)       (((x) & 0x7f) << 8)
+#define     VEPU_REG_VP8_LF_MODE_DELTA_NEWMV(x)                (((x) & 0x7f) << 0)
+#define        VEPU_REG_JPEG_LUMA_QUAT(i)              (0x000 + ((i) * 0x4))
+#define        VEPU_REG_JPEG_CHROMA_QUAT(i)            (0x040 + ((i) * 0x4))
+#define VEPU_REG_INTRA_SLICE_BITMAP(i)         (0x0b0 + ((i) * 0x4))
+#define VEPU_REG_ADDR_VP8_DCT_PART(i)          (0x0b0 + ((i) * 0x4))
+#define VEPU_REG_INTRA_AREA_CTRL               0x0b8
+#define     VEPU_REG_INTRA_AREA_TOP(x)                 (((x) & 0xff) << 24)
+#define     VEPU_REG_INTRA_AREA_BOTTOM(x)              (((x) & 0xff) << 16)
+#define     VEPU_REG_INTRA_AREA_LEFT(x)                        (((x) & 0xff) << 8)
+#define     VEPU_REG_INTRA_AREA_RIGHT(x)               (((x) & 0xff) << 0)
+#define VEPU_REG_CIR_INTRA_CTRL                        0x0bc
+#define     VEPU_REG_CIR_INTRA_FIRST_MB(x)             (((x) & 0xffff) << 16)
+#define     VEPU_REG_CIR_INTRA_INTERVAL(x)             (((x) & 0xffff) << 0)
+#define VEPU_REG_ADDR_IN_PLANE_0               0x0c0
+#define VEPU_REG_ADDR_IN_PLANE_1               0x0c4
+#define VEPU_REG_ADDR_IN_PLANE_2               0x0c8
+#define VEPU_REG_STR_HDR_REM_MSB               0x0cc
+#define VEPU_REG_STR_HDR_REM_LSB               0x0d0
+#define VEPU_REG_STR_BUF_LIMIT                 0x0d4
+#define VEPU_REG_AXI_CTRL                      0x0d8
+#define     VEPU_REG_AXI_CTRL_READ_ID(x)               (((x) & 0xff) << 24)
+#define     VEPU_REG_AXI_CTRL_WRITE_ID(x)              (((x) & 0xff) << 16)
+#define     VEPU_REG_AXI_CTRL_BURST_LEN(x)             (((x) & 0x3f) << 8)
+#define     VEPU_REG_AXI_CTRL_INCREMENT_MODE(x)                (((x) & 0x01) << 2)
+#define     VEPU_REG_AXI_CTRL_BIRST_DISCARD(x)         (((x) & 0x01) << 1)
+#define     VEPU_REG_AXI_CTRL_BIRST_DISABLE            BIT(0)
+#define VEPU_QP_ADJUST_MAD_DELTA_ROI           0x0dc
+#define     VEPU_REG_ROI_QP_DELTA_1                    (((x) & 0xf) << 12)
+#define     VEPU_REG_ROI_QP_DELTA_2                    (((x) & 0xf) << 8)
+#define     VEPU_REG_MAD_QP_ADJUSTMENT                 (((x) & 0xf) << 0)
+#define VEPU_REG_ADDR_REF_LUMA                 0x0e0
+#define VEPU_REG_ADDR_REF_CHROMA               0x0e4
+#define VEPU_REG_QP_SUM_DIV2                   0x0e8
+#define     VEPU_REG_QP_SUM(x)                         (((x) & 0x001fffff) * 2)
+#define VEPU_REG_ENC_CTRL0                     0x0ec
+#define     VEPU_REG_DISABLE_QUARTER_PIXEL_MV          BIT(28)
+#define     VEPU_REG_DEBLOCKING_FILTER_MODE(x)         (((x) & 0x3) << 24)
+#define     VEPU_REG_CABAC_INIT_IDC(x)                 (((x) & 0x3) << 21)
+#define     VEPU_REG_ENTROPY_CODING_MODE               BIT(20)
+#define     VEPU_REG_H264_TRANS8X8_MODE                        BIT(17)
+#define     VEPU_REG_H264_INTER4X4_MODE                        BIT(16)
+#define     VEPU_REG_H264_STREAM_MODE                  BIT(15)
+#define     VEPU_REG_H264_SLICE_SIZE(x)                        (((x) & 0x7f) << 8)
+#define VEPU_REG_ENC_OVER_FILL_STRM_OFFSET     0x0f0
+#define     VEPU_REG_STREAM_START_OFFSET(x)            (((x) & 0x3f) << 16)
+#define     VEPU_REG_SKIP_MACROBLOCK_PENALTY(x)                (((x) & 0xff) << 8)
+#define     VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x)          (((x) & 0x3) << 4)
+#define     VEPU_REG_IN_IMG_CTRL_OVRFLB(x)             (((x) & 0xf) << 0)
+#define VEPU_REG_INPUT_LUMA_INFO               0x0f4
+#define     VEPU_REG_IN_IMG_CHROMA_OFFSET(x)           (((x) & 0x7) << 20)
+#define     VEPU_REG_IN_IMG_LUMA_OFFSET(x)             (((x) & 0x7) << 16)
+#define     VEPU_REG_IN_IMG_CTRL_ROW_LEN(x)            (((x) & 0x3fff) << 0)
+#define VEPU_REG_RLC_SUM                       0x0f8
+#define     VEPU_REG_RLC_SUM_OUT(x)                    (((x) & 0x007fffff) * 4)
+#define VEPU_REG_SPLIT_PENALTY_4X4             0x0f8
+#define            VEPU_REG_VP8_SPLIT_PENALTY_4X4              (((x) & 0x1ff) << 19)
+#define VEPU_REG_ADDR_REC_LUMA                 0x0fc
+#define VEPU_REG_ADDR_REC_CHROMA               0x100
+#define VEPU_REG_CHECKPOINT(i)                 (0x104 + ((i) * 0x4))
+#define     VEPU_REG_CHECKPOINT_CHECK0(x)              (((x) & 0xffff))
+#define     VEPU_REG_CHECKPOINT_CHECK1(x)              (((x) & 0xffff) << 16)
+#define     VEPU_REG_CHECKPOINT_RESULT(x) \
+               ((((x) >> (16 - 16 * ((i) & 1))) & 0xffff) * 32)
+#define VEPU_REG_VP8_SEG0_QUANT_AC_Y1          0x104
+#define     VEPU_REG_VP8_SEG0_RND_AC_Y1(x)             (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_AC_Y1(x)            (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_AC_Y1(x)             (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_DC_Y2          0x108
+#define     VEPU_REG_VP8_SEG0_RND_DC_Y2(x)             (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_DC_Y2(x)            (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_DC_Y2(x)             (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_AC_Y2          0x10c
+#define     VEPU_REG_VP8_SEG0_RND_AC_Y2(x)             (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_AC_Y2(x)            (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_AC_Y2(x)             (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_DC_CHR         0x110
+#define     VEPU_REG_VP8_SEG0_RND_DC_CHR(x)            (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_DC_CHR(x)           (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_DC_CHR(x)            (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_AC_CHR         0x114
+#define     VEPU_REG_VP8_SEG0_RND_AC_CHR(x)            (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_AC_CHR(x)           (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_AC_CHR(x)            (((x) & 0x3fff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_DQUT           0x118
+#define     VEPU_REG_VP8_MV_REF_IDX1(x)                        (((x) & 0x03) << 26)
+#define     VEPU_REG_VP8_SEG0_DQUT_DC_Y2(x)            (((x) & 0x1ff) << 17)
+#define     VEPU_REG_VP8_SEG0_DQUT_AC_Y1(x)            (((x) & 0x1ff) << 8)
+#define     VEPU_REG_VP8_SEG0_DQUT_DC_Y1(x)            (((x) & 0xff) << 0)
+#define VEPU_REG_CHKPT_WORD_ERR(i)             (0x118 + ((i) * 0x4))
+#define     VEPU_REG_CHKPT_WORD_ERR_CHK0(x)            (((x) & 0xffff))
+#define     VEPU_REG_CHKPT_WORD_ERR_CHK1(x)            (((x) & 0xffff) << 16)
+#define VEPU_REG_VP8_SEG0_QUANT_DQUT_1         0x11c
+#define     VEPU_REG_VP8_SEGMENT_MAP_UPDATE            BIT(30)
+#define     VEPU_REG_VP8_SEGMENT_EN                    BIT(29)
+#define     VEPU_REG_VP8_MV_REF_IDX2_EN                        BIT(28)
+#define     VEPU_REG_VP8_MV_REF_IDX2(x)                        (((x) & 0x03) << 26)
+#define     VEPU_REG_VP8_SEG0_DQUT_AC_CHR(x)           (((x) & 0x1ff) << 17)
+#define     VEPU_REG_VP8_SEG0_DQUT_DC_CHR(x)           (((x) & 0xff) << 9)
+#define     VEPU_REG_VP8_SEG0_DQUT_AC_Y2(x)            (((x) & 0x1ff) << 0)
+#define VEPU_REG_VP8_BOOL_ENC_VALUE            0x120
+#define VEPU_REG_CHKPT_DELTA_QP                        0x124
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK0(x)            (((x) & 0x0f) << 0)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK1(x)            (((x) & 0x0f) << 4)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK2(x)            (((x) & 0x0f) << 8)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK3(x)            (((x) & 0x0f) << 12)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK4(x)            (((x) & 0x0f) << 16)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK5(x)            (((x) & 0x0f) << 20)
+#define     VEPU_REG_CHKPT_DELTA_QP_CHK6(x)            (((x) & 0x0f) << 24)
+#define VEPU_REG_VP8_ENC_CTRL2                 0x124
+#define     VEPU_REG_VP8_ZERO_MV_PENALTY_FOR_REF2(x)   (((x) & 0xff) << 24)
+#define     VEPU_REG_VP8_FILTER_SHARPNESS(x)           (((x) & 0x07) << 21)
+#define     VEPU_REG_VP8_FILTER_LEVEL(x)               (((x) & 0x3f) << 15)
+#define     VEPU_REG_VP8_DCT_PARTITION_CNT(x)          (((x) & 0x03) << 13)
+#define     VEPU_REG_VP8_BOOL_ENC_VALUE_BITS(x)                (((x) & 0x1f) << 8)
+#define     VEPU_REG_VP8_BOOL_ENC_RANGE(x)             (((x) & 0xff) << 0)
+#define VEPU_REG_ENC_CTRL1                     0x128
+#define     VEPU_REG_MAD_THRESHOLD(x)                  (((x) & 0x3f) << 24)
+#define     VEPU_REG_COMPLETED_SLICES(x)               (((x) & 0xff) << 16)
+#define     VEPU_REG_IN_IMG_CTRL_FMT(x)                        (((x) & 0xf) << 4)
+#define     VEPU_REG_IN_IMG_ROTATE_MODE(x)             (((x) & 0x3) << 2)
+#define     VEPU_REG_SIZE_TABLE_PRESENT                        BIT(0)
+#define VEPU_REG_INTRA_INTER_MODE              0x12c
+#define     VEPU_REG_INTRA16X16_MODE(x)                        (((x) & 0xffff) << 16)
+#define     VEPU_REG_INTER_MODE(x)                     (((x) & 0xffff) << 0)
+#define VEPU_REG_ENC_CTRL2                     0x130
+#define     VEPU_REG_PPS_INIT_QP(x)                    (((x) & 0x3f) << 26)
+#define     VEPU_REG_SLICE_FILTER_ALPHA(x)             (((x) & 0xf) << 22)
+#define     VEPU_REG_SLICE_FILTER_BETA(x)              (((x) & 0xf) << 18)
+#define     VEPU_REG_CHROMA_QP_OFFSET(x)               (((x) & 0x1f) << 13)
+#define     VEPU_REG_FILTER_DISABLE                    BIT(5)
+#define     VEPU_REG_IDR_PIC_ID(x)                     (((x) & 0xf) << 1)
+#define     VEPU_REG_CONSTRAINED_INTRA_PREDICTION      BIT(0)
+#define VEPU_REG_ADDR_OUTPUT_STREAM            0x134
+#define VEPU_REG_ADDR_OUTPUT_CTRL              0x138
+#define VEPU_REG_ADDR_NEXT_PIC                 0x13c
+#define VEPU_REG_ADDR_MV_OUT                   0x140
+#define VEPU_REG_ADDR_CABAC_TBL                        0x144
+#define VEPU_REG_ROI1                          0x148
+#define     VEPU_REG_ROI1_TOP_MB(x)                    (((x) & 0xff) << 24)
+#define     VEPU_REG_ROI1_BOTTOM_MB(x)                 (((x) & 0xff) << 16)
+#define     VEPU_REG_ROI1_LEFT_MB(x)                   (((x) & 0xff) << 8)
+#define     VEPU_REG_ROI1_RIGHT_MB(x)                  (((x) & 0xff) << 0)
+#define VEPU_REG_ROI2                          0x14c
+#define     VEPU_REG_ROI2_TOP_MB(x)                    (((x) & 0xff) << 24)
+#define     VEPU_REG_ROI2_BOTTOM_MB(x)                 (((x) & 0xff) << 16)
+#define     VEPU_REG_ROI2_LEFT_MB(x)                   (((x) & 0xff) << 8)
+#define     VEPU_REG_ROI2_RIGHT_MB(x)                  (((x) & 0xff) << 0)
+#define VEPU_REG_STABLE_MATRIX(i)              (0x150 + ((i) * 0x4))
+#define VEPU_REG_STABLE_MOTION_SUM             0x174
+#define VEPU_REG_STABILIZATION_OUTPUT          0x178
+#define     VEPU_REG_STABLE_MIN_VALUE(x)               (((x) & 0xffffff) << 8)
+#define     VEPU_REG_STABLE_MODE_SEL(x)                        (((x) & 0x3) << 6)
+#define     VEPU_REG_STABLE_HOR_GMV(x)                 (((x) & 0x3f) << 0)
+#define VEPU_REG_RGB2YUV_CONVERSION_COEF1      0x17c
+#define     VEPU_REG_RGB2YUV_CONVERSION_COEFB(x)       (((x) & 0xffff) << 16)
+#define     VEPU_REG_RGB2YUV_CONVERSION_COEFA(x)       (((x) & 0xffff) << 0)
+#define VEPU_REG_RGB2YUV_CONVERSION_COEF2      0x180
+#define     VEPU_REG_RGB2YUV_CONVERSION_COEFE(x)       (((x) & 0xffff) << 16)
+#define     VEPU_REG_RGB2YUV_CONVERSION_COEFC(x)       (((x) & 0xffff) << 0)
+#define VEPU_REG_RGB2YUV_CONVERSION_COEF3      0x184
+#define     VEPU_REG_RGB2YUV_CONVERSION_COEFF(x)       (((x) & 0xffff) << 0)
+#define VEPU_REG_RGB_MASK_MSB                  0x188
+#define     VEPU_REG_RGB_MASK_B_MSB(x)                 (((x) & 0x1f) << 16)
+#define     VEPU_REG_RGB_MASK_G_MSB(x)                 (((x) & 0x1f) << 8)
+#define     VEPU_REG_RGB_MASK_R_MSB(x)                 (((x) & 0x1f) << 0)
+#define VEPU_REG_MV_PENALTY                    0x18c
+#define     VEPU_REG_1MV_PENALTY(x)                    (((x) & 0x3ff) << 21)
+#define     VEPU_REG_QMV_PENALTY(x)                    (((x) & 0x3ff) << 11)
+#define     VEPU_REG_4MV_PENALTY(x)                    (((x) & 0x3ff) << 1)
+#define     VEPU_REG_SPLIT_MV_MODE_EN                  BIT(0)
+#define VEPU_REG_QP_VAL                                0x190
+#define     VEPU_REG_H264_LUMA_INIT_QP(x)              (((x) & 0x3f) << 26)
+#define     VEPU_REG_H264_QP_MAX(x)                    (((x) & 0x3f) << 20)
+#define     VEPU_REG_H264_QP_MIN(x)                    (((x) & 0x3f) << 14)
+#define     VEPU_REG_H264_CHKPT_DISTANCE(x)            (((x) & 0xfff) << 0)
+#define VEPU_REG_VP8_SEG0_QUANT_DC_Y1          0x190
+#define     VEPU_REG_VP8_SEG0_RND_DC_Y1(x)             (((x) & 0xff) << 23)
+#define     VEPU_REG_VP8_SEG0_ZBIN_DC_Y1(x)            (((x) & 0x1ff) << 14)
+#define     VEPU_REG_VP8_SEG0_QUT_DC_Y1(x)             (((x) & 0x3fff) << 0)
+#define VEPU_REG_MVC_RELATE                    0x198
+#define     VEPU_REG_ZERO_MV_FAVOR_D2(x)               (((x) & 0xf) << 20)
+#define     VEPU_REG_PENALTY_4X4MV(x)                  (((x) & 0x1ff) << 11)
+#define     VEPU_REG_MVC_VIEW_ID(x)                    (((x) & 0x7) << 8)
+#define     VEPU_REG_MVC_ANCHOR_PIC_FLAG               BIT(7)
+#define     VEPU_REG_MVC_PRIORITY_ID(x)                        (((x) & 0x7) << 4)
+#define     VEPU_REG_MVC_TEMPORAL_ID(x)                        (((x) & 0x7) << 1)
+#define     VEPU_REG_MVC_INTER_VIEW_FLAG               BIT(0)
+#define VEPU_REG_ENCODE_START                  0x19c
+#define     VEPU_REG_MB_HEIGHT(x)                      (((x) & 0x1ff) << 20)
+#define     VEPU_REG_MB_WIDTH(x)                       (((x) & 0x1ff) << 8)
+#define     VEPU_REG_FRAME_TYPE_INTER                  (0x0 << 6)
+#define     VEPU_REG_FRAME_TYPE_INTRA                  (0x1 << 6)
+#define     VEPU_REG_FRAME_TYPE_MVCINTER               (0x2 << 6)
+#define     VEPU_REG_ENCODE_FORMAT_JPEG                        (0x2 << 4)
+#define     VEPU_REG_ENCODE_FORMAT_H264                        (0x3 << 4)
+#define     VEPU_REG_ENCODE_ENABLE                     BIT(0)
+#define VEPU_REG_MB_CTRL                       0x1a0
+#define     VEPU_REG_MB_CNT_OUT(x)                     (((x) & 0xffff) << 16)
+#define     VEPU_REG_MB_CNT_SET(x)                     (((x) & 0xffff) << 0)
+#define VEPU_REG_DATA_ENDIAN                   0x1a4
+#define     VEPU_REG_INPUT_SWAP8                       BIT(31)
+#define     VEPU_REG_INPUT_SWAP16                      BIT(30)
+#define     VEPU_REG_INPUT_SWAP32                      BIT(29)
+#define     VEPU_REG_OUTPUT_SWAP8                      BIT(28)
+#define     VEPU_REG_OUTPUT_SWAP16                     BIT(27)
+#define     VEPU_REG_OUTPUT_SWAP32                     BIT(26)
+#define     VEPU_REG_TEST_IRQ                          BIT(24)
+#define     VEPU_REG_TEST_COUNTER(x)                   (((x) & 0xf) << 20)
+#define     VEPU_REG_TEST_REG                          BIT(19)
+#define     VEPU_REG_TEST_MEMORY                       BIT(18)
+#define     VEPU_REG_TEST_LEN(x)                       (((x) & 0x3ffff) << 0)
+#define VEPU_REG_ENC_CTRL3                     0x1a8
+#define     VEPU_REG_PPS_ID(x)                         (((x) & 0xff) << 24)
+#define     VEPU_REG_INTRA_PRED_MODE(x)                        (((x) & 0xff) << 16)
+#define     VEPU_REG_FRAME_NUM(x)                      (((x) & 0xffff) << 0)
+#define VEPU_REG_ENC_CTRL4                     0x1ac
+#define     VEPU_REG_MV_PENALTY_16X8_8X16(x)           (((x) & 0x3ff) << 20)
+#define     VEPU_REG_MV_PENALTY_8X8(x)                 (((x) & 0x3ff) << 10)
+#define     VEPU_REG_MV_PENALTY_8X4_4X8(x)             (((x) & 0x3ff) << 0)
+#define VEPU_REG_ADDR_VP8_PROB_CNT             0x1b0
+#define VEPU_REG_INTERRUPT                     0x1b4
+#define     VEPU_REG_INTERRUPT_NON                     BIT(28)
+#define     VEPU_REG_MV_WRITE_EN                       BIT(24)
+#define     VEPU_REG_RECON_WRITE_DIS                   BIT(20)
+#define     VEPU_REG_INTERRUPT_SLICE_READY_EN          BIT(16)
+#define     VEPU_REG_CLK_GATING_EN                     BIT(12)
+#define     VEPU_REG_INTERRUPT_TIMEOUT_EN              BIT(10)
+#define     VEPU_REG_INTERRUPT_RESET                   BIT(9)
+#define     VEPU_REG_INTERRUPT_DIS_BIT                 BIT(8)
+#define     VEPU_REG_INTERRUPT_TIMEOUT                 BIT(6)
+#define     VEPU_REG_INTERRUPT_BUFFER_FULL             BIT(5)
+#define     VEPU_REG_INTERRUPT_BUS_ERROR               BIT(4)
+#define     VEPU_REG_INTERRUPT_FUSE                    BIT(3)
+#define     VEPU_REG_INTERRUPT_SLICE_READY             BIT(2)
+#define     VEPU_REG_INTERRUPT_FRAME_READY             BIT(1)
+#define     VEPU_REG_INTERRUPT_BIT                     BIT(0)
+#define VEPU_REG_DMV_PENALTY_TBL(i)            (0x1E0 + ((i) * 0x4))
+#define     VEPU_REG_DMV_PENALTY_TABLE_BIT(x, i)        ((x) << (i) * 8)
+#define VEPU_REG_DMV_Q_PIXEL_PENALTY_TBL(i)    (0x260 + ((i) * 0x4))
+#define     VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT(x, i)       ((x) << (i) * 8)
+
+/* vpu decoder register */
+#define VDPU_REG_DEC_CTRL0                     0x0c8 // 50
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x)     (((x) & 0x1f) << 25)
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x)       (((x) & 0xfff) << 13)
+#define     VDPU_REG_CONFIG_TILED_MODE_LSB             BIT(12)
+#define     VDPU_REG_CONFIG_DEC_ADV_PRE_DIS            BIT(11)
+#define     VDPU_REG_CONFIG_DEC_SCMD_DIS               BIT(10)
+#define     VDPU_REG_DEC_CTRL0_SKIP_MODE               BIT(9)
+#define     VDPU_REG_DEC_CTRL0_FILTERING_DIS           BIT(8)
+#define     VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT         BIT(7)
+#define     VDPU_REG_CONFIG_DEC_LATENCY(x)             (((x) & 0x3f) << 1)
+#define     VDPU_REG_CONFIG_TILED_MODE_MSB(x)          BIT(0)
+#define     VDPU_REG_CONFIG_DEC_OUT_TILED_E            BIT(0)
+#define VDPU_REG_STREAM_LEN                    0x0cc
+#define     VDPU_REG_DEC_CTRL3_INIT_QP(x)              (((x) & 0x3f) << 25)
+#define     VDPU_REG_DEC_STREAM_LEN_HI                 BIT(24)
+#define     VDPU_REG_DEC_CTRL3_STREAM_LEN(x)           (((x) & 0xffffff) << 0)
+#define VDPU_REG_ERROR_CONCEALMENT             0x0d0
+#define     VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x)    (((x) & 0x3fff) << 17)
+#define     VDPU_REG_ERR_CONC_STARTMB_X(x)             (((x) & 0x1ff) << 8)
+#define     VDPU_REG_ERR_CONC_STARTMB_Y(x)             (((x) & 0xff) << 0)
+#define VDPU_REG_DEC_FORMAT                    0x0d4
+#define     VDPU_REG_DEC_CTRL0_DEC_MODE(x)             (((x) & 0xf) << 0)
+#define VDPU_REG_DATA_ENDIAN                   0x0d8
+#define     VDPU_REG_CONFIG_DEC_STRENDIAN_E            BIT(5)
+#define     VDPU_REG_CONFIG_DEC_STRSWAP32_E            BIT(4)
+#define     VDPU_REG_CONFIG_DEC_OUTSWAP32_E            BIT(3)
+#define     VDPU_REG_CONFIG_DEC_INSWAP32_E             BIT(2)
+#define     VDPU_REG_CONFIG_DEC_OUT_ENDIAN             BIT(1)
+#define     VDPU_REG_CONFIG_DEC_IN_ENDIAN              BIT(0)
+#define VDPU_REG_INTERRUPT                     0x0dc
+#define     VDPU_REG_INTERRUPT_DEC_TIMEOUT             BIT(13)
+#define     VDPU_REG_INTERRUPT_DEC_ERROR_INT           BIT(12)
+#define     VDPU_REG_INTERRUPT_DEC_PIC_INF             BIT(10)
+#define     VDPU_REG_INTERRUPT_DEC_SLICE_INT           BIT(9)
+#define     VDPU_REG_INTERRUPT_DEC_ASO_INT             BIT(8)
+#define     VDPU_REG_INTERRUPT_DEC_BUFFER_INT          BIT(6)
+#define     VDPU_REG_INTERRUPT_DEC_BUS_INT             BIT(5)
+#define     VDPU_REG_INTERRUPT_DEC_RDY_INT             BIT(4)
+#define     VDPU_REG_INTERRUPT_DEC_IRQ_DIS             BIT(1)
+#define     VDPU_REG_INTERRUPT_DEC_IRQ                 BIT(0)
+#define VDPU_REG_AXI_CTRL                      0x0e0
+#define     VDPU_REG_AXI_DEC_SEL                       BIT(23)
+#define     VDPU_REG_CONFIG_DEC_DATA_DISC_E            BIT(22)
+#define     VDPU_REG_PARAL_BUS_E(x)                    BIT(21)
+#define     VDPU_REG_CONFIG_DEC_MAX_BURST(x)           (((x) & 0x1f) << 16)
+#define     VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x)                (((x) & 0xff) << 8)
+#define     VDPU_REG_CONFIG_DEC_AXI_RD_ID(x)           (((x) & 0xff) << 0)
+#define VDPU_REG_EN_FLAGS                      0x0e4
+#define     VDPU_REG_AHB_HLOCK_E                       BIT(31)
+#define     VDPU_REG_CACHE_E                           BIT(29)
+#define     VDPU_REG_PREFETCH_SINGLE_CHANNEL_E         BIT(28)
+#define     VDPU_REG_INTRA_3_CYCLE_ENHANCE             BIT(27)
+#define     VDPU_REG_INTRA_DOUBLE_SPEED                        BIT(26)
+#define     VDPU_REG_INTER_DOUBLE_SPEED                        BIT(25)
+#define     VDPU_REG_DEC_CTRL3_START_CODE_E            BIT(22)
+#define     VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E         BIT(21)
+#define     VDPU_REG_DEC_CTRL0_RLC_MODE_E              BIT(20)
+#define     VDPU_REG_DEC_CTRL0_DIVX3_E                 BIT(19)
+#define     VDPU_REG_DEC_CTRL0_PJPEG_E                 BIT(18)
+#define     VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E         BIT(17)
+#define     VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E         BIT(16)
+#define     VDPU_REG_DEC_CTRL0_PIC_B_E                 BIT(15)
+#define     VDPU_REG_DEC_CTRL0_PIC_INTER_E             BIT(14)
+#define     VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E          BIT(13)
+#define     VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E         BIT(12)
+#define     VDPU_REG_DEC_CTRL0_SORENSON_E              BIT(11)
+#define     VDPU_REG_DEC_CTRL0_WRITE_MVS_E             BIT(10)
+#define     VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E          BIT(9)
+#define     VDPU_REG_DEC_CTRL0_REFTOPFIRST_E           BIT(8)
+#define     VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E             BIT(7)
+#define     VDPU_REG_DEC_CTRL0_PICORD_COUNT_E          BIT(6)
+#define     VDPU_REG_CONFIG_DEC_TIMEOUT_E              BIT(5)
+#define     VDPU_REG_CONFIG_DEC_CLK_GATE_E             BIT(4)
+#define     VDPU_REG_DEC_CTRL0_DEC_OUT_DIS             BIT(2)
+#define     VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E                BIT(1)
+#define     VDPU_REG_INTERRUPT_DEC_E                   BIT(0)
+#define VDPU_REG_SOFT_RESET                    0x0e8
+#define VDPU_REG_PRED_FLT                      0x0ec
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_ADDITIONAL_CHROMA_ADDRESS     0x0f0
+#define VDPU_REG_ADDR_QTABLE                   0x0f4
+#define VDPU_REG_DIRECT_MV_ADDR                        0x0f8
+#define VDPU_REG_ADDR_DST                      0x0fc
+#define VDPU_REG_ADDR_STR                      0x100
+#define VDPU_REG_REFBUF_RELATED                        0x104
+#define VDPU_REG_FWD_PIC(i)                    (0x128 + ((i) * 0x4))
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x)         (((x) & 0x1f) << 25)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x)         (((x) & 0x1f) << 20)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x)         (((x) & 0x1f) << 15)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x)         (((x) & 0x1f) << 10)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x)         (((x) & 0x1f) << 5)
+#define     VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x)         (((x) & 0x1f) << 0)
+#define VDPU_REG_REF_PIC(i)                    (0x130 + ((i) * 0x4))
+#define     VDPU_REG_REF_PIC_REFER1_NBR(x)             (((x) & 0xffff) << 16)
+#define     VDPU_REG_REF_PIC_REFER0_NBR(x)             (((x) & 0xffff) << 0)
+#define VDPU_REG_H264_ADDR_REF(i)                      (0x150 + ((i) * 0x4))
+#define     VDPU_REG_ADDR_REF_FIELD_E                  BIT(1)
+#define     VDPU_REG_ADDR_REF_TOPC_E                   BIT(0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST0         0x190
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F5(x)      (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F4(x)      (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F3(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x)      (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST1         0x194
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F11(x)     (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F10(x)     (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F9(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F8(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F7(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F6(x)      (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST2         0x198
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F15(x)     (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F14(x)     (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F13(x)     (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_F12(x)     (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST3         0x19c
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B5(x)      (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B4(x)      (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B3(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x)      (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST4         0x1a0
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B11(x)     (((x) & 0x1f) << 25)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B10(x)     (((x) & 0x1f) << 20)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B9(x)      (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B8(x)      (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B7(x)      (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B6(x)      (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST5         0x1a4
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B15(x)     (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B14(x)     (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B13(x)     (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_REF_PIC_BINIT_RLIST_B12(x)     (((x) & 0x1f) << 0)
+#define VDPU_REG_INITIAL_REF_PIC_LIST6         0x1a8
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x)    (((x) & 0x1f) << 15)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x)    (((x) & 0x1f) << 10)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x)    (((x) & 0x1f) << 5)
+#define     VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x)    (((x) & 0x1f) << 0)
+#define VDPU_REG_LT_REF                                0x1ac
+#define VDPU_REG_VALID_REF                     0x1b0
+#define VDPU_REG_H264_PIC_MB_SIZE              0x1b8
+#define     VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x)                (((x) & 0x1f) << 22)
+#define     VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x)         (((x) & 0x1f) << 17)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x)      (((x) & 0xff) << 9)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x)         (((x) & 0x1ff) << 0)
+#define VDPU_REG_H264_CTRL                     0x1bc
+#define     VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x)      (((x) & 0x3) << 16)
+#define     VDPU_REG_DEC_CTRL1_REF_FRAMES(x)           (((x) & 0x1f) << 0)
+#define VDPU_REG_CURRENT_FRAME                 0x1c0
+#define     VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES          BIT(31)
+#define     VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES          BIT(30)
+#define     VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x)         (((x) & 0x1f) << 16)
+#define     VDPU_REG_DEC_CTRL4_FRAMENUM(x)             (((x) & 0xffff) << 0)
+#define VDPU_REG_REF_FRAME                     0x1c4
+#define     VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x)                (((x) & 0x7ff) << 16)
+#define     VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x)           (((x) & 0xffff) << 0)
+#define VDPU_REG_DEC_CTRL6                     0x1c8
+#define     VDPU_REG_DEC_CTRL6_PPS_ID(x)               (((x) & 0xff) << 24)
+#define     VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x)       (((x) & 0x1f) << 19)
+#define     VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x)       (((x) & 0x1f) << 14)
+#define     VDPU_REG_DEC_CTRL6_POC_LENGTH(x)           (((x) & 0xff) << 0)
+#define VDPU_REG_ENABLE_FLAG                   0x1cc
+#define     VDPU_REG_DEC_CTRL5_IDR_PIC_E               BIT(8)
+#define     VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E         BIT(7)
+#define     VDPU_REG_DEC_CTRL4_BLACKWHITE_E            BIT(6)
+#define     VDPU_REG_DEC_CTRL4_CABAC_E                 BIT(5)
+#define     VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E           BIT(4)
+#define     VDPU_REG_DEC_CTRL5_CONST_INTRA_E           BIT(3)
+#define     VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E         BIT(2)
+#define     VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E           BIT(1)
+#define     VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E         BIT(0)
+#define VDPU_REG_VP8_PIC_MB_SIZE               0x1e0
+#define     VDPU_REG_DEC_PIC_MB_WIDTH(x)               (((x) & 0x1ff) << 23)
+#define            VDPU_REG_DEC_MB_WIDTH_OFF(x)                (((x) & 0xf) << 19)
+#define            VDPU_REG_DEC_PIC_MB_HEIGHT_P(x)             (((x) & 0xff) << 11)
+#define     VDPU_REG_DEC_MB_HEIGHT_OFF(x)              (((x) & 0xf) << 7)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x)         (((x) & 0x7) << 3)
+#define     VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x)         (((x) & 0x7) << 0)
+#define VDPU_REG_VP8_DCT_START_BIT             0x1e4
+#define     VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x)       (((x) & 0x3f) << 26)
+#define     VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x)       (((x) & 0x3f) << 20)
+#define     VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT          BIT(13)
+#define     VDPU_REG_DEC_CTRL4_BILIN_MC_E              BIT(12)
+#define VDPU_REG_VP8_CTRL0                     0x1e8
+#define     VDPU_REG_DEC_CTRL2_STRM_START_BIT(x)       (((x) & 0x3f) << 26)
+#define     VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x)      (((x) & 0x3f) << 18)
+#define     VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x)                (((x) & 0xff) << 8)
+#define     VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x)                (((x) & 0xff) << 0)
+#define VDPU_REG_VP8_DATA_VAL                  0x1f0
+#define     VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x)       (((x) & 0xf) << 24)
+#define     VDPU_REG_DEC_CTRL6_STREAM1_LEN(x)          (((x) & 0xffffff) << 0)
+#define VDPU_REG_PRED_FLT7                     0x1f4
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_5_1(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_5_2(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_5_3(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT8                     0x1f8
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_6_0(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_6_1(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_6_2(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT9                     0x1fc
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_6_3(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_7_0(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_7_1(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT10                    0x200
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_7_2(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_7_3(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x)       (((x) & 0x3) << 10)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x)                (((x) & 0x3) << 8)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x)       (((x) & 0x3) << 6)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x)                (((x) & 0x3) << 4)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x)       (((x) & 0x3) << 2)
+#define     VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x)                (((x) & 0x3) << 0)
+#define VDPU_REG_FILTER_LEVEL                  0x204
+#define     VDPU_REG_REF_PIC_LF_LEVEL_0(x)             (((x) & 0x3f) << 18)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_1(x)             (((x) & 0x3f) << 12)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_2(x)             (((x) & 0x3f) << 6)
+#define     VDPU_REG_REF_PIC_LF_LEVEL_3(x)             (((x) & 0x3f) << 0)
+#define VDPU_REG_VP8_QUANTER0                  0x208
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_0(x)          (((x) & 0x1f) << 27)
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_1(x)          (((x) & 0x1f) << 22)
+#define     VDPU_REG_REF_PIC_QUANT_0(x)                        (((x) & 0x7ff) << 11)
+#define     VDPU_REG_REF_PIC_QUANT_1(x)                        (((x) & 0x7ff) << 0)
+#define VDPU_REG_VP8_ADDR_REF0                 0x20c
+#define VDPU_REG_FILTER_MB_ADJ                 0x210
+#define     VDPU_REG_REF_PIC_FILT_TYPE_E               BIT(31)
+#define     VDPU_REG_REF_PIC_FILT_SHARPNESS(x)         (((x) & 0x7) << 28)
+#define     VDPU_REG_FILT_MB_ADJ_0(x)                  (((x) & 0x7f) << 21)
+#define     VDPU_REG_FILT_MB_ADJ_1(x)                  (((x) & 0x7f) << 14)
+#define     VDPU_REG_FILT_MB_ADJ_2(x)                  (((x) & 0x7f) << 7)
+#define     VDPU_REG_FILT_MB_ADJ_3(x)                  (((x) & 0x7f) << 0)
+#define VDPU_REG_FILTER_REF_ADJ                        0x214
+#define     VDPU_REG_REF_PIC_ADJ_0(x)                  (((x) & 0x7f) << 21)
+#define     VDPU_REG_REF_PIC_ADJ_1(x)                  (((x) & 0x7f) << 14)
+#define     VDPU_REG_REF_PIC_ADJ_2(x)                  (((x) & 0x7f) << 7)
+#define     VDPU_REG_REF_PIC_ADJ_3(x)                  (((x) & 0x7f) << 0)
+#define VDPU_REG_VP8_ADDR_REF2_5(i)            (0x218 + ((i) * 0x4))
+#define     VDPU_REG_VP8_GREF_SIGN_BIAS                        BIT(0)
+#define     VDPU_REG_VP8_AREF_SIGN_BIAS                        BIT(0)
+#define VDPU_REG_VP8_DCT_BASE(i)               (0x230 + ((i) * 0x4))
+#define VDPU_REG_VP8_ADDR_CTRL_PART            0x244
+#define VDPU_REG_VP8_ADDR_REF1                 0x250
+#define VDPU_REG_VP8_SEGMENT_VAL               0x254
+#define     VDPU_REG_FWD_PIC1_SEGMENT_BASE(x)          ((x) << 0)
+#define     VDPU_REG_FWD_PIC1_SEGMENT_UPD_E            BIT(1)
+#define     VDPU_REG_FWD_PIC1_SEGMENT_E                        BIT(0)
+#define VDPU_REG_VP8_DCT_START_BIT2            0x258
+#define     VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x)       (((x) & 0x3f) << 24)
+#define     VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x)       (((x) & 0x3f) << 18)
+#define     VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x)       (((x) & 0x3f) << 12)
+#define     VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x)       (((x) & 0x3f) << 6)
+#define     VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x)       (((x) & 0x3f) << 0)
+#define VDPU_REG_VP8_QUANTER1                  0x25c
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_2(x)          (((x) & 0x1f) << 27)
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_3(x)          (((x) & 0x1f) << 22)
+#define     VDPU_REG_REF_PIC_QUANT_2(x)                        (((x) & 0x7ff) << 11)
+#define     VDPU_REG_REF_PIC_QUANT_3(x)                        (((x) & 0x7ff) << 0)
+#define VDPU_REG_VP8_QUANTER2                  0x260
+#define     VDPU_REG_REF_PIC_QUANT_DELTA_4(x)          (((x) & 0x1f) << 27)
+#define     VDPU_REG_REF_PIC_QUANT_4(x)                        (((x) & 0x7ff) << 11)
+#define     VDPU_REG_REF_PIC_QUANT_5(x)                        (((x) & 0x7ff) << 0)
+#define VDPU_REG_PRED_FLT1                     0x264
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_0_3(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_1_0(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_1_1(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT2                     0x268
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_1_2(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_1_3(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_2_0(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT3                     0x26c
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_2_1(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_2_2(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_2_3(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT4                     0x270
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_3_0(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_3_1(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_3_2(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT5                     0x274
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_3_3(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_4_0(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_4_1(x)       (((x) & 0x3ff) << 2)
+#define VDPU_REG_PRED_FLT6                     0x278
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_4_2(x)       (((x) & 0x3ff) << 22)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x)       (((x) & 0x3ff) << 12)
+#define     VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x)       (((x) & 0x3ff) << 2)
+
+#endif /* RK3399_VPU_REGS_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu.h
new file mode 100644 (file)
index 0000000..1ec2be4
--- /dev/null
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef ROCKCHIP_VPU_H_
+#define ROCKCHIP_VPU_H_
+
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "rockchip_vpu_hw.h"
+
+#define ROCKCHIP_VPU_MAX_CLOCKS                4
+
+#define JPEG_MB_DIM                    16
+#define JPEG_MB_WIDTH(w)               DIV_ROUND_UP(w, JPEG_MB_DIM)
+#define JPEG_MB_HEIGHT(h)              DIV_ROUND_UP(h, JPEG_MB_DIM)
+
+struct rockchip_vpu_ctx;
+struct rockchip_vpu_codec_ops;
+
+#define RK_VPU_CODEC_JPEG BIT(0)
+
+/**
+ * struct rockchip_vpu_variant - information about VPU hardware variant
+ *
+ * @enc_offset:                        Offset from VPU base to encoder registers.
+ * @enc_fmts:                  Encoder formats.
+ * @num_enc_fmts:              Number of encoder formats.
+ * @codec:                     Supported codecs
+ * @codec_ops:                 Codec ops.
+ * @init:                      Initialize hardware.
+ * @vepu_irq:                  encoder interrupt handler
+ * @clk_names:                 array of clock names
+ * @num_clocks:                        number of clocks in the array
+ */
+struct rockchip_vpu_variant {
+       unsigned int enc_offset;
+       const struct rockchip_vpu_fmt *enc_fmts;
+       unsigned int num_enc_fmts;
+       unsigned int codec;
+       const struct rockchip_vpu_codec_ops *codec_ops;
+       int (*init)(struct rockchip_vpu_dev *vpu);
+       irqreturn_t (*vepu_irq)(int irq, void *priv);
+       const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS];
+       int num_clocks;
+};
+
+/**
+ * enum rockchip_vpu_codec_mode - codec operating mode.
+ * @RK_VPU_MODE_NONE:  No operating mode. Used for RAW video formats.
+ * @RK_VPU_MODE_JPEG_ENC: JPEG encoder.
+ */
+enum rockchip_vpu_codec_mode {
+       RK_VPU_MODE_NONE = -1,
+       RK_VPU_MODE_JPEG_ENC,
+};
+
+/**
+ * struct rockchip_vpu_dev - driver data
+ * @v4l2_dev:          V4L2 device to register video devices for.
+ * @m2m_dev:           mem2mem device associated to this device.
+ * @mdev:              media device associated to this device.
+ * @vfd_enc:           Video device for encoder.
+ * @pdev:              Pointer to VPU platform device.
+ * @dev:               Pointer to device for convenient logging using
+ *                     dev_ macros.
+ * @clocks:            Array of clock handles.
+ * @base:              Mapped address of VPU registers.
+ * @enc_base:          Mapped address of VPU encoder register for convenience.
+ * @vpu_mutex:         Mutex to synchronize V4L2 calls.
+ * @irqlock:           Spinlock to synchronize access to data structures
+ *                     shared with interrupt handlers.
+ * @variant:           Hardware variant-specific parameters.
+ * @watchdog_work:     Delayed work for hardware timeout handling.
+ */
+struct rockchip_vpu_dev {
+       struct v4l2_device v4l2_dev;
+       struct v4l2_m2m_dev *m2m_dev;
+       struct media_device mdev;
+       struct video_device *vfd_enc;
+       struct platform_device *pdev;
+       struct device *dev;
+       struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS];
+       void __iomem *base;
+       void __iomem *enc_base;
+
+       struct mutex vpu_mutex; /* video_device lock */
+       spinlock_t irqlock;
+       const struct rockchip_vpu_variant *variant;
+       struct delayed_work watchdog_work;
+};
+
+/**
+ * struct rockchip_vpu_ctx - Context (instance) private data.
+ *
+ * @dev:               VPU driver data to which the context belongs.
+ * @fh:                        V4L2 file handler.
+ *
+ * @sequence_cap:       Sequence counter for capture queue
+ * @sequence_out:       Sequence counter for output queue
+ *
+ * @vpu_src_fmt:       Descriptor of active source format.
+ * @src_fmt:           V4L2 pixel format of active source format.
+ * @vpu_dst_fmt:       Descriptor of active destination format.
+ * @dst_fmt:           V4L2 pixel format of active destination format.
+ *
+ * @ctrl_handler:      Control handler used to register controls.
+ * @jpeg_quality:      User-specified JPEG compression quality.
+ *
+ * @codec_ops:         Set of operations related to codec mode.
+ *
+ * @bounce_dma_addr:   Bounce buffer bus address.
+ * @bounce_buf:                Bounce buffer pointer.
+ * @bounce_size:       Bounce buffer size.
+ */
+struct rockchip_vpu_ctx {
+       struct rockchip_vpu_dev *dev;
+       struct v4l2_fh fh;
+
+       u32 sequence_cap;
+       u32 sequence_out;
+
+       const struct rockchip_vpu_fmt *vpu_src_fmt;
+       struct v4l2_pix_format_mplane src_fmt;
+       const struct rockchip_vpu_fmt *vpu_dst_fmt;
+       struct v4l2_pix_format_mplane dst_fmt;
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       int jpeg_quality;
+
+       const struct rockchip_vpu_codec_ops *codec_ops;
+
+       dma_addr_t bounce_dma_addr;
+       void *bounce_buf;
+       size_t bounce_size;
+};
+
+/**
+ * struct rockchip_vpu_fmt - information about supported video formats.
+ * @name:      Human readable name of the format.
+ * @fourcc:    FourCC code of the format. See V4L2_PIX_FMT_*.
+ * @codec_mode:        Codec mode related to this format. See
+ *             enum rockchip_vpu_codec_mode.
+ * @header_size: Optional header size. Currently used by JPEG encoder.
+ * @max_depth: Maximum depth, for bitstream formats
+ * @enc_fmt:   Format identifier for encoder registers.
+ * @frmsize:   Supported range of frame sizes (only for bitstream formats).
+ */
+struct rockchip_vpu_fmt {
+       char *name;
+       u32 fourcc;
+       enum rockchip_vpu_codec_mode codec_mode;
+       int header_size;
+       int max_depth;
+       enum rockchip_vpu_enc_fmt enc_fmt;
+       struct v4l2_frmsize_stepwise frmsize;
+};
+
+/* Logging helpers */
+
+/**
+ * debug - Module parameter to control level of debugging messages.
+ *
+ * Level of debugging messages can be controlled by bits of
+ * module parameter called "debug". Meaning of particular
+ * bits is as follows:
+ *
+ * bit 0 - global information: mode, size, init, release
+ * bit 1 - each run start/result information
+ * bit 2 - contents of small controls from userspace
+ * bit 3 - contents of big controls from userspace
+ * bit 4 - detail fmt, ctrl, buffer q/dq information
+ * bit 5 - detail function enter/leave trace information
+ * bit 6 - register write/read information
+ */
+extern int rockchip_vpu_debug;
+
+#define vpu_debug(level, fmt, args...)                         \
+       do {                                                    \
+               if (rockchip_vpu_debug & BIT(level))            \
+                       pr_info("%s:%d: " fmt,                  \
+                                __func__, __LINE__, ##args);   \
+       } while (0)
+
+#define vpu_err(fmt, args...)                                  \
+       pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
+
+/* Structure access helpers. */
+static inline struct rockchip_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+       return container_of(fh, struct rockchip_vpu_ctx, fh);
+}
+
+/* Register accessors. */
+static inline void vepu_write_relaxed(struct rockchip_vpu_dev *vpu,
+                                     u32 val, u32 reg)
+{
+       vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+       writel_relaxed(val, vpu->enc_base + reg);
+}
+
+static inline void vepu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg)
+{
+       vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+       writel(val, vpu->enc_base + reg);
+}
+
+static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg)
+{
+       u32 val = readl(vpu->enc_base + reg);
+
+       vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+       return val;
+}
+
+#endif /* ROCKCHIP_VPU_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h
new file mode 100644 (file)
index 0000000..ca77668
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Alpha Lin <Alpha.Lin@rock-chips.com>
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef ROCKCHIP_VPU_COMMON_H_
+#define ROCKCHIP_VPU_COMMON_H_
+
+#include "rockchip_vpu.h"
+
+extern const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops;
+extern const struct vb2_ops rockchip_vpu_enc_queue_ops;
+
+void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx);
+void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx);
+
+#endif /* ROCKCHIP_VPU_COMMON_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c
new file mode 100644 (file)
index 0000000..962412c
--- /dev/null
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Collabora, Ltd.
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "rockchip_vpu_common.h"
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_hw.h"
+
+#define DRIVER_NAME "rockchip-vpu"
+
+int rockchip_vpu_debug;
+module_param_named(debug, rockchip_vpu_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+                "Debug level - higher value produces more verbose messages");
+
+static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx,
+                                   unsigned int bytesused,
+                                   enum vb2_buffer_state result)
+{
+       struct vb2_v4l2_buffer *src, *dst;
+       size_t avail_size;
+
+       pm_runtime_mark_last_busy(vpu->dev);
+       pm_runtime_put_autosuspend(vpu->dev);
+       clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
+
+       src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+       if (WARN_ON(!src))
+               return;
+       if (WARN_ON(!dst))
+               return;
+
+       src->sequence = ctx->sequence_out++;
+       dst->sequence = ctx->sequence_cap++;
+
+       dst->field = src->field;
+       if (src->flags & V4L2_BUF_FLAG_TIMECODE)
+               dst->timecode = src->timecode;
+       dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
+       dst->flags &= ~(V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
+                       V4L2_BUF_FLAG_TIMECODE);
+       dst->flags |= src->flags & (V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
+                                   V4L2_BUF_FLAG_TIMECODE);
+
+       avail_size = vb2_plane_size(&dst->vb2_buf, 0) -
+                    ctx->vpu_dst_fmt->header_size;
+       if (bytesused <= avail_size) {
+               if (ctx->bounce_buf) {
+                       memcpy(vb2_plane_vaddr(&dst->vb2_buf, 0) +
+                              ctx->vpu_dst_fmt->header_size,
+                              ctx->bounce_buf, bytesused);
+               }
+               dst->vb2_buf.planes[0].bytesused =
+                       ctx->vpu_dst_fmt->header_size + bytesused;
+       } else {
+               result = VB2_BUF_STATE_ERROR;
+       }
+
+       v4l2_m2m_buf_done(src, result);
+       v4l2_m2m_buf_done(dst, result);
+
+       v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu,
+                          unsigned int bytesused,
+                          enum vb2_buffer_state result)
+{
+       struct rockchip_vpu_ctx *ctx =
+               v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+
+       /*
+        * If cancel_delayed_work returns false
+        * the timeout expired. The watchdog is running,
+        * and will take care of finishing the job.
+        */
+       if (cancel_delayed_work(&vpu->watchdog_work))
+               rockchip_vpu_job_finish(vpu, ctx, bytesused, result);
+}
+
+void rockchip_vpu_watchdog(struct work_struct *work)
+{
+       struct rockchip_vpu_dev *vpu;
+       struct rockchip_vpu_ctx *ctx;
+
+       vpu = container_of(to_delayed_work(work),
+                          struct rockchip_vpu_dev, watchdog_work);
+       ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+       if (ctx) {
+               vpu_err("frame processing timed out!\n");
+               ctx->codec_ops->reset(ctx);
+               rockchip_vpu_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static void device_run(void *priv)
+{
+       struct rockchip_vpu_ctx *ctx = priv;
+       int ret;
+
+       ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks);
+       if (ret)
+               goto err_cancel_job;
+       ret = pm_runtime_get_sync(ctx->dev->dev);
+       if (ret < 0)
+               goto err_cancel_job;
+
+       ctx->codec_ops->run(ctx);
+       return;
+
+err_cancel_job:
+       rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR);
+}
+
+static struct v4l2_m2m_ops vpu_m2m_ops = {
+       .device_run = device_run,
+};
+
+static int
+enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+       struct rockchip_vpu_ctx *ctx = priv;
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       src_vq->drv_priv = ctx;
+       src_vq->ops = &rockchip_vpu_enc_queue_ops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       /*
+        * Driver does mostly sequential access, so sacrifice TLB efficiency
+        * for faster allocation. Also, no CPU access on the source queue,
+        * so no kernel mapping needed.
+        */
+       src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES |
+                           DMA_ATTR_NO_KERNEL_MAPPING;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->dev->vpu_mutex;
+       src_vq->dev = ctx->dev->v4l2_dev.dev;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       /*
+        * The CAPTURE queue doesn't need dma memory,
+        * as the CPU needs to create the JPEG frames,
+        * from the hardware-produced JPEG payload.
+        *
+        * For the DMA destination buffer, we use
+        * a bounce buffer.
+        */
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       dst_vq->drv_priv = ctx;
+       dst_vq->ops = &rockchip_vpu_enc_queue_ops;
+       dst_vq->mem_ops = &vb2_vmalloc_memops;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->dev->vpu_mutex;
+       dst_vq->dev = ctx->dev->v4l2_dev.dev;
+
+       return vb2_queue_init(dst_vq);
+}
+
+static int rockchip_vpu_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct rockchip_vpu_ctx *ctx;
+
+       ctx = container_of(ctrl->handler,
+                          struct rockchip_vpu_ctx, ctrl_handler);
+
+       vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+               ctx->jpeg_quality = ctrl->val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops rockchip_vpu_ctrl_ops = {
+       .s_ctrl = rockchip_vpu_s_ctrl,
+};
+
+static int rockchip_vpu_ctrls_setup(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
+       if (vpu->variant->codec & RK_VPU_CODEC_JPEG) {
+               v4l2_ctrl_new_std(&ctx->ctrl_handler, &rockchip_vpu_ctrl_ops,
+                                 V4L2_CID_JPEG_COMPRESSION_QUALITY,
+                                 5, 100, 1, 50);
+               if (ctx->ctrl_handler.error) {
+                       vpu_err("Adding JPEG control failed %d\n",
+                               ctx->ctrl_handler.error);
+                       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+                       return ctx->ctrl_handler.error;
+               }
+       }
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+/*
+ * V4L2 file operations.
+ */
+
+static int rockchip_vpu_open(struct file *filp)
+{
+       struct rockchip_vpu_dev *vpu = video_drvdata(filp);
+       struct video_device *vdev = video_devdata(filp);
+       struct rockchip_vpu_ctx *ctx;
+       int ret;
+
+       /*
+        * We do not need any extra locking here, because we operate only
+        * on local data here, except reading few fields from dev, which
+        * do not change through device's lifetime (which is guaranteed by
+        * reference on module from open()) and V4L2 internal objects (such
+        * as vdev and ctx->fh), which have proper locking done in respective
+        * helper functions used here.
+        */
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->dev = vpu;
+       if (vdev == vpu->vfd_enc)
+               ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
+                                                   &enc_queue_init);
+       else
+               ctx->fh.m2m_ctx = ERR_PTR(-ENODEV);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+               kfree(ctx);
+               return ret;
+       }
+
+       v4l2_fh_init(&ctx->fh, vdev);
+       filp->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       if (vdev == vpu->vfd_enc) {
+               rockchip_vpu_enc_reset_dst_fmt(vpu, ctx);
+               rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
+       }
+
+       ret = rockchip_vpu_ctrls_setup(vpu, ctx);
+       if (ret) {
+               vpu_err("Failed to set up controls\n");
+               goto err_fh_free;
+       }
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+       return 0;
+
+err_fh_free:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       return ret;
+}
+
+static int rockchip_vpu_release(struct file *filp)
+{
+       struct rockchip_vpu_ctx *ctx =
+               container_of(filp->private_data, struct rockchip_vpu_ctx, fh);
+
+       /*
+        * No need for extra locking because this was the last reference
+        * to this file.
+        */
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       kfree(ctx);
+
+       return 0;
+}
+
+static const struct v4l2_file_operations rockchip_vpu_fops = {
+       .owner = THIS_MODULE,
+       .open = rockchip_vpu_open,
+       .release = rockchip_vpu_release,
+       .poll = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct of_device_id of_rockchip_vpu_match[] = {
+       { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
+       { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_rockchip_vpu_match);
+
+static int rockchip_vpu_video_device_register(struct rockchip_vpu_dev *vpu)
+{
+       const struct of_device_id *match;
+       struct video_device *vfd;
+       int function, ret;
+
+       match = of_match_node(of_rockchip_vpu_match, vpu->dev->of_node);
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n");
+               return -ENOMEM;
+       }
+
+       vfd->fops = &rockchip_vpu_fops;
+       vfd->release = video_device_release;
+       vfd->lock = &vpu->vpu_mutex;
+       vfd->v4l2_dev = &vpu->v4l2_dev;
+       vfd->vfl_dir = VFL_DIR_M2M;
+       vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+       vfd->ioctl_ops = &rockchip_vpu_enc_ioctl_ops;
+       snprintf(vfd->name, sizeof(vfd->name), "%s-enc", match->compatible);
+       vpu->vfd_enc = vfd;
+       video_set_drvdata(vfd, vpu);
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n");
+               goto err_free_dev;
+       }
+       v4l2_info(&vpu->v4l2_dev, "registered as /dev/video%d\n", vfd->num);
+
+       function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
+       ret = v4l2_m2m_register_media_controller(vpu->m2m_dev, vfd, function);
+       if (ret) {
+               v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem media controller\n");
+               goto err_unreg_video;
+       }
+       return 0;
+
+err_unreg_video:
+       video_unregister_device(vfd);
+err_free_dev:
+       video_device_release(vfd);
+       return ret;
+}
+
+static int rockchip_vpu_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct rockchip_vpu_dev *vpu;
+       struct resource *res;
+       int i, ret;
+
+       vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL);
+       if (!vpu)
+               return -ENOMEM;
+
+       vpu->dev = &pdev->dev;
+       vpu->pdev = pdev;
+       mutex_init(&vpu->vpu_mutex);
+       spin_lock_init(&vpu->irqlock);
+
+       match = of_match_node(of_rockchip_vpu_match, pdev->dev.of_node);
+       vpu->variant = match->data;
+
+       INIT_DELAYED_WORK(&vpu->watchdog_work, rockchip_vpu_watchdog);
+
+       for (i = 0; i < vpu->variant->num_clocks; i++)
+               vpu->clocks[i].id = vpu->variant->clk_names[i];
+       ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks,
+                               vpu->clocks);
+       if (ret)
+               return ret;
+
+       res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0);
+       vpu->base = devm_ioremap_resource(vpu->dev, res);
+       if (IS_ERR(vpu->base))
+               return PTR_ERR(vpu->base);
+       vpu->enc_base = vpu->base + vpu->variant->enc_offset;
+
+       ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(vpu->dev, "Could not set DMA coherent mask.\n");
+               return ret;
+       }
+
+       if (vpu->variant->vepu_irq) {
+               int irq;
+
+               irq = platform_get_irq_byname(vpu->pdev, "vepu");
+               if (irq <= 0) {
+                       dev_err(vpu->dev, "Could not get vepu IRQ.\n");
+                       return -ENXIO;
+               }
+
+               ret = devm_request_irq(vpu->dev, irq, vpu->variant->vepu_irq,
+                                      0, dev_name(vpu->dev), vpu);
+               if (ret) {
+                       dev_err(vpu->dev, "Could not request vepu IRQ.\n");
+                       return ret;
+               }
+       }
+
+       ret = vpu->variant->init(vpu);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to init VPU hardware\n");
+               return ret;
+       }
+
+       pm_runtime_set_autosuspend_delay(vpu->dev, 100);
+       pm_runtime_use_autosuspend(vpu->dev);
+       pm_runtime_enable(vpu->dev);
+
+       ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to prepare clocks\n");
+               return ret;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+               goto err_clk_unprepare;
+       }
+       platform_set_drvdata(pdev, vpu);
+
+       vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
+       if (IS_ERR(vpu->m2m_dev)) {
+               v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(vpu->m2m_dev);
+               goto err_v4l2_unreg;
+       }
+
+       vpu->mdev.dev = vpu->dev;
+       strlcpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
+       media_device_init(&vpu->mdev);
+       vpu->v4l2_dev.mdev = &vpu->mdev;
+
+       ret = rockchip_vpu_video_device_register(vpu);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register encoder\n");
+               goto err_m2m_rel;
+       }
+
+       ret = media_device_register(&vpu->mdev);
+       if (ret) {
+               v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n");
+               goto err_video_dev_unreg;
+       }
+       return 0;
+err_video_dev_unreg:
+       if (vpu->vfd_enc) {
+               video_unregister_device(vpu->vfd_enc);
+               video_device_release(vpu->vfd_enc);
+       }
+err_m2m_rel:
+       v4l2_m2m_release(vpu->m2m_dev);
+err_v4l2_unreg:
+       v4l2_device_unregister(&vpu->v4l2_dev);
+err_clk_unprepare:
+       clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+       pm_runtime_disable(vpu->dev);
+       return ret;
+}
+
+static int rockchip_vpu_remove(struct platform_device *pdev)
+{
+       struct rockchip_vpu_dev *vpu = platform_get_drvdata(pdev);
+
+       v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name);
+
+       media_device_unregister(&vpu->mdev);
+       v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
+       v4l2_m2m_release(vpu->m2m_dev);
+       media_device_cleanup(&vpu->mdev);
+       if (vpu->vfd_enc) {
+               video_unregister_device(vpu->vfd_enc);
+               video_device_release(vpu->vfd_enc);
+       }
+       v4l2_device_unregister(&vpu->v4l2_dev);
+       clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+       pm_runtime_disable(vpu->dev);
+       return 0;
+}
+
+static const struct dev_pm_ops rockchip_vpu_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static struct platform_driver rockchip_vpu_driver = {
+       .probe = rockchip_vpu_probe,
+       .remove = rockchip_vpu_remove,
+       .driver = {
+                  .name = DRIVER_NAME,
+                  .of_match_table = of_match_ptr(of_rockchip_vpu_match),
+                  .pm = &rockchip_vpu_pm_ops,
+       },
+};
+module_platform_driver(rockchip_vpu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alpha Lin <Alpha.Lin@Rock-Chips.com>");
+MODULE_AUTHOR("Tomasz Figa <tfiga@chromium.org>");
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_DESCRIPTION("Rockchip VPU codec driver");
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
new file mode 100644 (file)
index 0000000..ab0fb20
--- /dev/null
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright (C) 2018 Collabora, Ltd.
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Alpha Lin <Alpha.Lin@rock-chips.com>
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "rockchip_vpu.h"
+#include "rockchip_vpu_hw.h"
+#include "rockchip_vpu_common.h"
+
+/**
+ * struct v4l2_format_info - information about a V4L2 format
+ * @format: 4CC format identifier (V4L2_PIX_FMT_*)
+ * @header_size: Size of header, optional and used by compressed formats
+ * @num_planes: Number of planes (1 to 3)
+ * @cpp: Number of bytes per pixel (per plane)
+ * @hsub: Horizontal chroma subsampling factor
+ * @vsub: Vertical chroma subsampling factor
+ * @is_compressed: Is it a compressed format?
+ * @multiplanar: Is it a multiplanar variant format? (e.g. NV12M)
+ */
+struct v4l2_format_info {
+       u32 format;
+       u32 header_size;
+       u8 num_planes;
+       u8 cpp[3];
+       u8 hsub;
+       u8 vsub;
+       u8 is_compressed;
+       u8 multiplanar;
+};
+
+static const struct v4l2_format_info *
+v4l2_format_info(u32 format)
+{
+       static const struct v4l2_format_info formats[] = {
+               { .format = V4L2_PIX_FMT_YUV420M,       .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
+               { .format = V4L2_PIX_FMT_NV12M,         .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
+               { .format = V4L2_PIX_FMT_YUYV,          .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
+               { .format = V4L2_PIX_FMT_UYVY,          .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
+       };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].format == format)
+                       return &formats[i];
+       }
+
+       vpu_err("Unsupported V4L 4CC format (%08x)\n", format);
+       return NULL;
+}
+
+static void
+fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
+              int pixelformat, int width, int height)
+{
+       const struct v4l2_format_info *info;
+       struct v4l2_plane_pix_format *plane;
+       int i;
+
+       info = v4l2_format_info(pixelformat);
+       if (!info)
+               return;
+
+       pixfmt->width = width;
+       pixfmt->height = height;
+       pixfmt->pixelformat = pixelformat;
+
+       if (!info->multiplanar) {
+               pixfmt->num_planes = 1;
+               plane = &pixfmt->plane_fmt[0];
+               plane->bytesperline = info->is_compressed ?
+                                       0 : width * info->cpp[0];
+               plane->sizeimage = info->header_size;
+               for (i = 0; i < info->num_planes; i++) {
+                       unsigned int hsub = (i == 0) ? 1 : info->hsub;
+                       unsigned int vsub = (i == 0) ? 1 : info->vsub;
+
+                       plane->sizeimage += info->cpp[i] *
+                               DIV_ROUND_UP(width, hsub) *
+                               DIV_ROUND_UP(height, vsub);
+               }
+       } else {
+               pixfmt->num_planes = info->num_planes;
+               for (i = 0; i < info->num_planes; i++) {
+                       unsigned int hsub = (i == 0) ? 1 : info->hsub;
+                       unsigned int vsub = (i == 0) ? 1 : info->vsub;
+
+                       plane = &pixfmt->plane_fmt[i];
+                       plane->bytesperline =
+                               info->cpp[i] * DIV_ROUND_UP(width, hsub);
+                       plane->sizeimage =
+                               plane->bytesperline * DIV_ROUND_UP(height, vsub);
+               }
+       }
+}
+
+static const struct rockchip_vpu_fmt *
+rockchip_vpu_find_format(struct rockchip_vpu_ctx *ctx, u32 fourcc)
+{
+       struct rockchip_vpu_dev *dev = ctx->dev;
+       const struct rockchip_vpu_fmt *formats;
+       unsigned int num_fmts, i;
+
+       formats = dev->variant->enc_fmts;
+       num_fmts = dev->variant->num_enc_fmts;
+       for (i = 0; i < num_fmts; i++)
+               if (formats[i].fourcc == fourcc)
+                       return &formats[i];
+       return NULL;
+}
+
+static const struct rockchip_vpu_fmt *
+rockchip_vpu_get_default_fmt(struct rockchip_vpu_ctx *ctx, bool bitstream)
+{
+       struct rockchip_vpu_dev *dev = ctx->dev;
+       const struct rockchip_vpu_fmt *formats;
+       unsigned int num_fmts, i;
+
+       formats = dev->variant->enc_fmts;
+       num_fmts = dev->variant->num_enc_fmts;
+       for (i = 0; i < num_fmts; i++) {
+               if (bitstream == (formats[i].codec_mode != RK_VPU_MODE_NONE))
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct rockchip_vpu_dev *vpu = video_drvdata(file);
+
+       strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
+       strscpy(cap->card, vpu->vfd_enc->name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
+                vpu->dev->driver->name);
+       return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+       const struct rockchip_vpu_fmt *fmt;
+
+       if (fsize->index != 0) {
+               vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
+                         fsize->index);
+               return -EINVAL;
+       }
+
+       fmt = rockchip_vpu_find_format(ctx, fsize->pixel_format);
+       if (!fmt) {
+               vpu_debug(0, "unsupported bitstream format (%08x)\n",
+                         fsize->pixel_format);
+               return -EINVAL;
+       }
+
+       /* This only makes sense for coded formats */
+       if (fmt->codec_mode == RK_VPU_MODE_NONE)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise = fmt->frmsize;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                         struct v4l2_fmtdesc *f)
+{
+       struct rockchip_vpu_dev *dev = video_drvdata(file);
+       const struct rockchip_vpu_fmt *fmt;
+       const struct rockchip_vpu_fmt *formats;
+       int num_fmts, i, j = 0;
+
+       formats = dev->variant->enc_fmts;
+       num_fmts = dev->variant->num_enc_fmts;
+       for (i = 0; i < num_fmts; i++) {
+               /* Skip uncompressed formats */
+               if (formats[i].codec_mode == RK_VPU_MODE_NONE)
+                       continue;
+               if (j == f->index) {
+                       fmt = &formats[i];
+                       f->pixelformat = fmt->fourcc;
+                       return 0;
+               }
+               ++j;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
+                                         struct v4l2_fmtdesc *f)
+{
+       struct rockchip_vpu_dev *dev = video_drvdata(file);
+       const struct rockchip_vpu_fmt *formats;
+       const struct rockchip_vpu_fmt *fmt;
+       int num_fmts, i, j = 0;
+
+       formats = dev->variant->enc_fmts;
+       num_fmts = dev->variant->num_enc_fmts;
+       for (i = 0; i < num_fmts; i++) {
+               if (formats[i].codec_mode != RK_VPU_MODE_NONE)
+                       continue;
+               if (j == f->index) {
+                       fmt = &formats[i];
+                       f->pixelformat = fmt->fourcc;
+                       return 0;
+               }
+               ++j;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_fmt_out_mplane(struct file *file, void *priv,
+                                  struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+
+       vpu_debug(4, "f->type = %d\n", f->type);
+
+       *pix_mp = ctx->src_fmt;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv,
+                                  struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+
+       vpu_debug(4, "f->type = %d\n", f->type);
+
+       *pix_mp = ctx->dst_fmt;
+
+       return 0;
+}
+
+static int
+vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       const struct rockchip_vpu_fmt *fmt;
+
+       vpu_debug(4, "%c%c%c%c\n",
+                 (pix_mp->pixelformat & 0x7f),
+                 (pix_mp->pixelformat >> 8) & 0x7f,
+                 (pix_mp->pixelformat >> 16) & 0x7f,
+                 (pix_mp->pixelformat >> 24) & 0x7f);
+
+       fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
+       if (!fmt) {
+               fmt = rockchip_vpu_get_default_fmt(ctx, true);
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+
+       pix_mp->num_planes = 1;
+       pix_mp->field = V4L2_FIELD_NONE;
+       pix_mp->width = clamp(pix_mp->width,
+                             fmt->frmsize.min_width,
+                             fmt->frmsize.max_width);
+       pix_mp->height = clamp(pix_mp->height,
+                              fmt->frmsize.min_height,
+                              fmt->frmsize.max_height);
+       /* Round up to macroblocks. */
+       pix_mp->width = round_up(pix_mp->width, JPEG_MB_DIM);
+       pix_mp->height = round_up(pix_mp->height, JPEG_MB_DIM);
+
+       /*
+        * For compressed formats the application can specify
+        * sizeimage. If the application passes a zero sizeimage,
+        * let's default to the maximum frame size.
+        */
+       if (!pix_mp->plane_fmt[0].sizeimage)
+               pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
+                       pix_mp->width * pix_mp->height * fmt->max_depth;
+       memset(pix_mp->plane_fmt[0].reserved, 0,
+              sizeof(pix_mp->plane_fmt[0].reserved));
+       return 0;
+}
+
+static int
+vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       const struct rockchip_vpu_fmt *fmt;
+       unsigned int width, height;
+       int i;
+
+       vpu_debug(4, "%c%c%c%c\n",
+                 (pix_mp->pixelformat & 0x7f),
+                 (pix_mp->pixelformat >> 8) & 0x7f,
+                 (pix_mp->pixelformat >> 16) & 0x7f,
+                 (pix_mp->pixelformat >> 24) & 0x7f);
+
+       fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
+       if (!fmt) {
+               fmt = rockchip_vpu_get_default_fmt(ctx, false);
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+
+       pix_mp->field = V4L2_FIELD_NONE;
+       width = clamp(pix_mp->width,
+                     ctx->vpu_dst_fmt->frmsize.min_width,
+                     ctx->vpu_dst_fmt->frmsize.max_width);
+       height = clamp(pix_mp->height,
+                      ctx->vpu_dst_fmt->frmsize.min_height,
+                      ctx->vpu_dst_fmt->frmsize.max_height);
+       /* Round up to macroblocks. */
+       width = round_up(width, JPEG_MB_DIM);
+       height = round_up(height, JPEG_MB_DIM);
+
+       /* Fill remaining fields */
+       fill_pixfmt_mp(pix_mp, fmt->fourcc, width, height);
+
+       for (i = 0; i < pix_mp->num_planes; i++) {
+               memset(pix_mp->plane_fmt[i].reserved, 0,
+                      sizeof(pix_mp->plane_fmt[i].reserved));
+       }
+       return 0;
+}
+
+void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx)
+{
+       struct v4l2_pix_format_mplane *fmt = &ctx->dst_fmt;
+
+       ctx->vpu_dst_fmt = rockchip_vpu_get_default_fmt(ctx, true);
+
+       memset(fmt, 0, sizeof(*fmt));
+
+       fmt->num_planes = 1;
+       fmt->width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
+                          ctx->vpu_dst_fmt->frmsize.max_width);
+       fmt->height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
+                           ctx->vpu_dst_fmt->frmsize.max_height);
+       fmt->pixelformat = ctx->vpu_dst_fmt->fourcc;
+       fmt->field = V4L2_FIELD_NONE;
+       fmt->colorspace = V4L2_COLORSPACE_JPEG,
+       fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+       fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       fmt->plane_fmt[0].sizeimage = ctx->vpu_dst_fmt->header_size +
+               fmt->width * fmt->height * ctx->vpu_dst_fmt->max_depth;
+}
+
+void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
+                                   struct rockchip_vpu_ctx *ctx)
+{
+       struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt;
+       unsigned int width, height;
+
+       ctx->vpu_src_fmt = rockchip_vpu_get_default_fmt(ctx, false);
+
+       memset(fmt, 0, sizeof(*fmt));
+
+       width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
+                     ctx->vpu_dst_fmt->frmsize.max_width);
+       height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
+                      ctx->vpu_dst_fmt->frmsize.max_height);
+       fmt->field = V4L2_FIELD_NONE;
+       fmt->colorspace = V4L2_COLORSPACE_JPEG,
+       fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+       fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       fill_pixfmt_mp(fmt, ctx->vpu_src_fmt->fourcc, width, height);
+}
+
+static int
+vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *vq;
+       int ret;
+
+       /* Change not allowed if queue is streaming. */
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_streaming(vq))
+               return -EBUSY;
+
+       ret = vidioc_try_fmt_out_mplane(file, priv, f);
+       if (ret)
+               return ret;
+
+       ctx->vpu_src_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
+       ctx->src_fmt = *pix_mp;
+
+       /* Propagate to the CAPTURE format */
+       ctx->dst_fmt.colorspace = pix_mp->colorspace;
+       ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
+       ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
+       ctx->dst_fmt.quantization = pix_mp->quantization;
+       ctx->dst_fmt.width = pix_mp->width;
+       ctx->dst_fmt.height = pix_mp->height;
+
+       vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
+       vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
+                 pix_mp->width, pix_mp->height,
+                 JPEG_MB_WIDTH(pix_mp->width),
+                 JPEG_MB_HEIGHT(pix_mp->height));
+       return 0;
+}
+
+static int
+vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
+       struct rockchip_vpu_dev *vpu = ctx->dev;
+       struct vb2_queue *vq, *peer_vq;
+       int ret;
+
+       /* Change not allowed if queue is streaming. */
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_streaming(vq))
+               return -EBUSY;
+
+       /*
+        * Since format change on the CAPTURE queue will reset
+        * the OUTPUT queue, we can't allow doing so
+        * when the OUTPUT queue has buffers allocated.
+        */
+       peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+                                 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       if (vb2_is_busy(peer_vq) &&
+           (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
+            pix_mp->height != ctx->dst_fmt.height ||
+            pix_mp->width != ctx->dst_fmt.width))
+               return -EBUSY;
+
+       ret = vidioc_try_fmt_cap_mplane(file, priv, f);
+       if (ret)
+               return ret;
+
+       ctx->vpu_dst_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
+       ctx->dst_fmt = *pix_mp;
+
+       vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode);
+       vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
+                 pix_mp->width, pix_mp->height,
+                 JPEG_MB_WIDTH(pix_mp->width),
+                 JPEG_MB_HEIGHT(pix_mp->height));
+
+       /*
+        * Current raw format might have become invalid with newly
+        * selected codec, so reset it to default just to be safe and
+        * keep internal driver state sane. User is mandated to set
+        * the raw format again after we return, so we don't need
+        * anything smarter.
+        */
+       rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
+       return 0;
+}
+
+const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_enum_framesizes = vidioc_enum_framesizes,
+
+       .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane,
+       .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane,
+       .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane,
+       .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane,
+       .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+
+       .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+       .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+       .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+};
+
+static int
+rockchip_vpu_queue_setup(struct vb2_queue *vq,
+                        unsigned int *num_buffers,
+                        unsigned int *num_planes,
+                        unsigned int sizes[],
+                        struct device *alloc_devs[])
+{
+       struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
+       struct v4l2_pix_format_mplane *pixfmt;
+       int i;
+
+       switch (vq->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               pixfmt = &ctx->dst_fmt;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               pixfmt = &ctx->src_fmt;
+               break;
+       default:
+               vpu_err("invalid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+
+       if (*num_planes) {
+               if (*num_planes != pixfmt->num_planes)
+                       return -EINVAL;
+               for (i = 0; i < pixfmt->num_planes; ++i)
+                       if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
+                               return -EINVAL;
+               return 0;
+       }
+
+       *num_planes = pixfmt->num_planes;
+       for (i = 0; i < pixfmt->num_planes; ++i)
+               sizes[i] = pixfmt->plane_fmt[i].sizeimage;
+       return 0;
+}
+
+static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
+       struct v4l2_pix_format_mplane *pixfmt;
+       unsigned int sz;
+       int ret = 0;
+       int i;
+
+       switch (vq->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               pixfmt = &ctx->dst_fmt;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               pixfmt = &ctx->src_fmt;
+
+               if (vbuf->field == V4L2_FIELD_ANY)
+                       vbuf->field = V4L2_FIELD_NONE;
+               if (vbuf->field != V4L2_FIELD_NONE) {
+                       vpu_debug(4, "field %d not supported\n",
+                                 vbuf->field);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               vpu_err("invalid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pixfmt->num_planes; ++i) {
+               sz = pixfmt->plane_fmt[i].sizeimage;
+               vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n",
+                         i, vb2_plane_size(vb, i), sz);
+               if (vb2_plane_size(vb, i) < sz) {
+                       vpu_err("plane %d is too small\n", i);
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static void rockchip_vpu_buf_queue(struct vb2_buffer *vb)
+{
+       struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int rockchip_vpu_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
+       enum rockchip_vpu_codec_mode codec_mode;
+
+       if (V4L2_TYPE_IS_OUTPUT(q->type))
+               ctx->sequence_out = 0;
+       else
+               ctx->sequence_cap = 0;
+
+       /* Set codec_ops for the chosen destination format */
+       codec_mode = ctx->vpu_dst_fmt->codec_mode;
+
+       vpu_debug(4, "Codec mode = %d\n", codec_mode);
+       ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode];
+
+       /* A bounce buffer is needed for the JPEG payload */
+       if (!V4L2_TYPE_IS_OUTPUT(q->type)) {
+               ctx->bounce_size = ctx->dst_fmt.plane_fmt[0].sizeimage -
+                                 ctx->vpu_dst_fmt->header_size;
+               ctx->bounce_buf = dma_alloc_attrs(ctx->dev->dev,
+                                                 ctx->bounce_size,
+                                                 &ctx->bounce_dma_addr,
+                                                 GFP_KERNEL,
+                                                 DMA_ATTR_ALLOC_SINGLE_PAGES);
+       }
+       return 0;
+}
+
+static void rockchip_vpu_stop_streaming(struct vb2_queue *q)
+{
+       struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
+
+       if (!V4L2_TYPE_IS_OUTPUT(q->type))
+               dma_free_attrs(ctx->dev->dev,
+                              ctx->bounce_size,
+                              ctx->bounce_buf,
+                              ctx->bounce_dma_addr,
+                              DMA_ATTR_ALLOC_SINGLE_PAGES);
+
+       /*
+        * The mem2mem framework calls v4l2_m2m_cancel_job before
+        * .stop_streaming, so there isn't any job running and
+        * it is safe to return all the buffers.
+        */
+       for (;;) {
+               struct vb2_v4l2_buffer *vbuf;
+
+               if (V4L2_TYPE_IS_OUTPUT(q->type))
+                       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+               else
+                       vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+               if (!vbuf)
+                       break;
+               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+       }
+}
+
+const struct vb2_ops rockchip_vpu_enc_queue_ops = {
+       .queue_setup = rockchip_vpu_queue_setup,
+       .buf_prepare = rockchip_vpu_buf_prepare,
+       .buf_queue = rockchip_vpu_buf_queue,
+       .start_streaming = rockchip_vpu_start_streaming,
+       .stop_streaming = rockchip_vpu_stop_streaming,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+};
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h
new file mode 100644 (file)
index 0000000..2b955da
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Rockchip VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ *     Tomasz Figa <tfiga@chromium.org>
+ */
+
+#ifndef ROCKCHIP_VPU_HW_H_
+#define ROCKCHIP_VPU_HW_H_
+
+#include <linux/interrupt.h>
+#include <linux/v4l2-controls.h>
+#include <media/videobuf2-core.h>
+
+struct rockchip_vpu_dev;
+struct rockchip_vpu_ctx;
+struct rockchip_vpu_buf;
+struct rockchip_vpu_variant;
+
+/**
+ * struct rockchip_vpu_codec_ops - codec mode specific operations
+ *
+ * @run:       Start single {en,de)coding job. Called from atomic context
+ *             to indicate that a pair of buffers is ready and the hardware
+ *             should be programmed and started.
+ * @done:      Read back processing results and additional data from hardware.
+ * @reset:     Reset the hardware in case of a timeout.
+ */
+struct rockchip_vpu_codec_ops {
+       void (*run)(struct rockchip_vpu_ctx *ctx);
+       void (*done)(struct rockchip_vpu_ctx *ctx, enum vb2_buffer_state);
+       void (*reset)(struct rockchip_vpu_ctx *ctx);
+};
+
+/**
+ * enum rockchip_vpu_enc_fmt - source format ID for hardware registers.
+ */
+enum rockchip_vpu_enc_fmt {
+       RK3288_VPU_ENC_FMT_YUV420P = 0,
+       RK3288_VPU_ENC_FMT_YUV420SP = 1,
+       RK3288_VPU_ENC_FMT_YUYV422 = 2,
+       RK3288_VPU_ENC_FMT_UYVY422 = 3,
+};
+
+extern const struct rockchip_vpu_variant rk3399_vpu_variant;
+extern const struct rockchip_vpu_variant rk3288_vpu_variant;
+
+void rockchip_vpu_watchdog(struct work_struct *work);
+void rockchip_vpu_run(struct rockchip_vpu_ctx *ctx);
+void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu,
+                          unsigned int bytesused,
+                          enum vb2_buffer_state result);
+
+void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx);
+void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx);
+
+#endif /* ROCKCHIP_VPU_HW_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c
new file mode 100644 (file)
index 0000000..0ff0bad
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Collabora, Ltd.
+ *
+ * Based on GSPCA and CODA drivers:
+ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2014 Philipp Zabel, Pengutronix
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include "rockchip_vpu_jpeg.h"
+
+#define LUMA_QUANT_OFF         7
+#define CHROMA_QUANT_OFF       72
+#define HEIGHT_OFF             141
+#define WIDTH_OFF              143
+
+#define HUFF_LUMA_DC_OFF       160
+#define HUFF_LUMA_AC_OFF       193
+#define HUFF_CHROMA_DC_OFF     376
+#define HUFF_CHROMA_AC_OFF     409
+
+/* Default tables from JPEG ITU-T.81
+ * (ISO/IEC 10918-1) Annex K.3, I
+ */
+static const unsigned char luma_q_table[] = {
+       0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1,
+       0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b,
+       0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c,
+       0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2,
+       0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1,
+       0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0,
+       0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65,
+       0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7,
+};
+
+static const unsigned char chroma_q_table[] = {
+       0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63,
+       0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63,
+       0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+};
+
+/* Huffman tables are shared with CODA */
+static const unsigned char luma_dc_table[] = {
+       0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char chroma_dc_table[] = {
+       0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char luma_ac_table[] = {
+       0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+       0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+       0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+       0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+       0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+       0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+       0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+       0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+       0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+       0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+       0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+       0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+       0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+       0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+       0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+       0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+       0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+       0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+       0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa,
+};
+
+static const unsigned char chroma_ac_table[] = {
+       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+       0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+       0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+       0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+       0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+       0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+       0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+       0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+       0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+       0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+       0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+       0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+       0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+       0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+       0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+       0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+       0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+       0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+       0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa,
+};
+
+/* For simplicity, we keep a pre-formatted JPEG header,
+ * and we'll use fixed offsets to change the width, height
+ * quantization tables, etc.
+ */
+static const unsigned char rockchip_vpu_jpeg_header[JPEG_HEADER_SIZE] = {
+       /* SOI */
+       0xff, 0xd8,
+
+       /* DQT */
+       0xff, 0xdb, 0x00, 0x84,
+
+       0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* SOF */
+       0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,
+       0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
+       0x03, 0x11, 0x01,
+
+       /* DHT */
+       0xff, 0xc4, 0x00, 0x1f, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       /* DHT */
+       0xff, 0xc4, 0x00, 0xb5, 0x10,
+
+       0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* DHT */
+       0xff, 0xc4, 0x00, 0x1f, 0x01,
+
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       /* DHT */
+       0xff, 0xc4, 0x00, 0xb5, 0x11,
+
+       0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* SOS */
+       0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
+       0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
+};
+
+static void
+jpeg_scale_quant_table(unsigned char *q_tab,
+                      const unsigned char *tab, int scale)
+{
+       unsigned int temp;
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100);
+               if (temp <= 0)
+                       temp = 1;
+               if (temp > 255)
+                       temp = 255;
+               q_tab[i] = (unsigned char)temp;
+       }
+}
+
+static void jpeg_set_quality(unsigned char *buffer, int quality)
+{
+       int scale;
+
+       /*
+        * Non-linear scaling factor:
+        * [5,50] -> [1000..100], [51,100] -> [98..0]
+        */
+       if (quality < 50)
+               scale = 5000 / quality;
+       else
+               scale = 200 - 2 * quality;
+
+       jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF,
+                              luma_q_table, scale);
+       jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF,
+                              chroma_q_table, scale);
+}
+
+unsigned char *
+rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index)
+{
+       if (index == 0)
+               return ctx->buffer + LUMA_QUANT_OFF;
+       return ctx->buffer + CHROMA_QUANT_OFF;
+}
+
+void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx)
+{
+       char *buf = ctx->buffer;
+
+       memcpy(buf, rockchip_vpu_jpeg_header,
+              sizeof(rockchip_vpu_jpeg_header));
+
+       buf[HEIGHT_OFF + 0] = ctx->height >> 8;
+       buf[HEIGHT_OFF + 1] = ctx->height;
+       buf[WIDTH_OFF + 0] = ctx->width >> 8;
+       buf[WIDTH_OFF + 1] = ctx->width;
+
+       memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table));
+       memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table));
+       memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table,
+              sizeof(chroma_dc_table));
+       memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table,
+              sizeof(chroma_ac_table));
+
+       jpeg_set_quality(buf, ctx->quality);
+}
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h
new file mode 100644 (file)
index 0000000..72645d8
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#define JPEG_HEADER_SIZE       601
+
+struct rockchip_vpu_jpeg_ctx {
+       int width;
+       int height;
+       int quality;
+       unsigned char *buffer;
+};
+
+unsigned char *
+rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index);
+void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx);
index c912c70b3ef77e3f9794696fb95b24171671fab7..ff11cbeba205d401b5c6bb855959160db02d9e13 100644 (file)
@@ -72,10 +72,11 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
        ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
 
        ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
-       memset(ctx->ctrls, 0, ctrl_size);
+       if (!ctx->ctrls)
+               return -ENOMEM;
 
        for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
-               struct v4l2_ctrl_config cfg = { 0 };
+               struct v4l2_ctrl_config cfg = {};
 
                cfg.elem_size = cedrus_controls[i].elem_size;
                cfg.id = cedrus_controls[i].id;
@@ -279,7 +280,6 @@ static int cedrus_probe(struct platform_device *pdev)
        dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
 
        mutex_init(&dev->dev_mutex);
-       spin_lock_init(&dev->irq_lock);
 
        ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
        if (ret) {
@@ -388,6 +388,14 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = {
        .capabilities   = CEDRUS_CAPABILITY_UNTILED,
 };
 
+static const struct cedrus_variant sun50i_a64_cedrus_variant = {
+       .capabilities   = CEDRUS_CAPABILITY_UNTILED,
+};
+
+static const struct cedrus_variant sun50i_h5_cedrus_variant = {
+       .capabilities   = CEDRUS_CAPABILITY_UNTILED,
+};
+
 static const struct of_device_id cedrus_dt_match[] = {
        {
                .compatible = "allwinner,sun4i-a10-video-engine",
@@ -409,6 +417,14 @@ static const struct of_device_id cedrus_dt_match[] = {
                .compatible = "allwinner,sun8i-h3-video-engine",
                .data = &sun8i_h3_cedrus_variant,
        },
+       {
+               .compatible = "allwinner,sun50i-a64-video-engine",
+               .data = &sun50i_a64_cedrus_variant,
+       },
+       {
+               .compatible = "allwinner,sun50i-h5-video-engine",
+               .data = &sun50i_h5_cedrus_variant,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, cedrus_dt_match);
@@ -418,7 +434,6 @@ static struct platform_driver cedrus_driver = {
        .remove         = cedrus_remove,
        .driver         = {
                .name           = CEDRUS_NAME,
-               .owner          = THIS_MODULE,
                .of_match_table = of_match_ptr(cedrus_dt_match),
        },
 };
index 3f61248c57ac1c85669d5e2aad97df4560d58268..3acfdcf8369128735f0489945389244227bca138 100644 (file)
@@ -105,8 +105,6 @@ struct cedrus_dev {
 
        /* Device file mutex */
        struct mutex            dev_mutex;
-       /* Interrupt spinlock */
-       spinlock_t              irq_lock;
 
        void __iomem            *base;
 
index e40180a33951b731a237e06f6804e4a133b34844..591d191d4286125ee8908b216869726c30836f8f 100644 (file)
@@ -26,9 +26,8 @@ void cedrus_device_run(void *priv)
 {
        struct cedrus_ctx *ctx = priv;
        struct cedrus_dev *dev = ctx->dev;
-       struct cedrus_run run = { 0 };
+       struct cedrus_run run = {};
        struct media_request *src_req;
-       unsigned long flags;
 
        run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -39,8 +38,6 @@ void cedrus_device_run(void *priv)
        if (src_req)
                v4l2_ctrl_request_setup(src_req, &ctx->hdl);
 
-       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
-
        switch (ctx->src_fmt.pixelformat) {
        case V4L2_PIX_FMT_MPEG2_SLICE:
                run.mpeg2.slice_params = cedrus_find_control_data(ctx,
@@ -55,16 +52,10 @@ void cedrus_device_run(void *priv)
 
        dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
 
-       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
-
        /* Complete request(s) controls if needed. */
 
        if (src_req)
                v4l2_ctrl_request_complete(src_req, &ctx->hdl);
 
-       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
-
        dev->dec_ops[ctx->current_codec]->trigger(ctx);
-
-       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
 }
index 07520a2ce179bc4755b2f56771f79369824d97dc..300339fee1bc67bd5abf896e44c59e3e9312eacd 100644 (file)
@@ -98,23 +98,6 @@ void cedrus_dst_format_set(struct cedrus_dev *dev,
        }
 }
 
-static irqreturn_t cedrus_bh(int irq, void *data)
-{
-       struct cedrus_dev *dev = data;
-       struct cedrus_ctx *ctx;
-
-       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
-       if (!ctx) {
-               v4l2_err(&dev->v4l2_dev,
-                        "Instance released before the end of transaction\n");
-               return IRQ_HANDLED;
-       }
-
-       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-
-       return IRQ_HANDLED;
-}
-
 static irqreturn_t cedrus_irq(int irq, void *data)
 {
        struct cedrus_dev *dev = data;
@@ -122,24 +105,17 @@ static irqreturn_t cedrus_irq(int irq, void *data)
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
        enum vb2_buffer_state state;
        enum cedrus_irq_status status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->irq_lock, flags);
 
        ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
        if (!ctx) {
                v4l2_err(&dev->v4l2_dev,
                         "Instance released before the end of transaction\n");
-               spin_unlock_irqrestore(&dev->irq_lock, flags);
-
                return IRQ_NONE;
        }
 
        status = dev->dec_ops[ctx->current_codec]->irq_status(ctx);
-       if (status == CEDRUS_IRQ_NONE) {
-               spin_unlock_irqrestore(&dev->irq_lock, flags);
+       if (status == CEDRUS_IRQ_NONE)
                return IRQ_NONE;
-       }
 
        dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
        dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
@@ -150,8 +126,6 @@ static irqreturn_t cedrus_irq(int irq, void *data)
        if (!src_buf || !dst_buf) {
                v4l2_err(&dev->v4l2_dev,
                         "Missing source and/or destination buffers\n");
-               spin_unlock_irqrestore(&dev->irq_lock, flags);
-
                return IRQ_HANDLED;
        }
 
@@ -163,9 +137,9 @@ static irqreturn_t cedrus_irq(int irq, void *data)
        v4l2_m2m_buf_done(src_buf, state);
        v4l2_m2m_buf_done(dst_buf, state);
 
-       spin_unlock_irqrestore(&dev->irq_lock, flags);
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
 
-       return IRQ_WAKE_THREAD;
+       return IRQ_HANDLED;
 }
 
 int cedrus_hw_probe(struct cedrus_dev *dev)
@@ -187,9 +161,8 @@ int cedrus_hw_probe(struct cedrus_dev *dev)
 
                return irq_dec;
        }
-       ret = devm_request_threaded_irq(dev->dev, irq_dec, cedrus_irq,
-                                       cedrus_bh, 0, dev_name(dev->dev),
-                                       dev);
+       ret = devm_request_irq(dev->dev, irq_dec, cedrus_irq,
+                              0, dev_name(dev->dev), dev);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
 
index 5c5fce678b93e45b349b7cb0cd44dfcb1530a67a..8721b4a7d4968f327e51f71d0655600bf378e2b4 100644 (file)
@@ -380,18 +380,13 @@ static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
 {
        struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
        struct vb2_v4l2_buffer *vbuf;
-       unsigned long flags;
 
        for (;;) {
-               spin_lock_irqsave(&ctx->dev->irq_lock, flags);
-
                if (V4L2_TYPE_IS_OUTPUT(vq->type))
                        vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
                else
                        vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
-               spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
-
                if (!vbuf)
                        return;
 
index 6f06061a40d9b586ee525c2091114a747e5e12b6..aa6c6bba961e029323f1f454e32671899d0d5346 100644 (file)
 #define BSE_ICMDQUE_EMPTY      BIT(3)
 #define BSE_DMA_BUSY           BIT(23)
 
-#define VDE_WR(__data, __addr)                         \
-do {                                                   \
-       dev_dbg(vde->miscdev.parent,                    \
-               "%s: %d: 0x%08X => " #__addr ")\n",     \
-               __func__, __LINE__, (u32)(__data));     \
-       writel_relaxed(__data, __addr);                 \
-} while (0)
-
 struct video_frame {
        struct dma_buf_attachment *y_dmabuf_attachment;
        struct dma_buf_attachment *cb_dmabuf_attachment;
@@ -81,12 +73,66 @@ struct tegra_vde {
        u32 *iram;
 };
 
+static __maybe_unused char const *
+tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base)
+{
+       if (vde->sxe == base)
+               return "SXE";
+
+       if (vde->bsev == base)
+               return "BSEV";
+
+       if (vde->mbe == base)
+               return "MBE";
+
+       if (vde->ppe == base)
+               return "PPE";
+
+       if (vde->mce == base)
+               return "MCE";
+
+       if (vde->tfe == base)
+               return "TFE";
+
+       if (vde->ppb == base)
+               return "PPB";
+
+       if (vde->vdma == base)
+               return "VDMA";
+
+       if (vde->frameid == base)
+               return "FRAMEID";
+
+       return "???";
+}
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+static void tegra_vde_writel(struct tegra_vde *vde,
+                            u32 value, void __iomem *base, u32 offset)
+{
+       trace_vde_writel(vde, base, offset, value);
+
+       writel_relaxed(value, base + offset);
+}
+
+static u32 tegra_vde_readl(struct tegra_vde *vde,
+                          void __iomem *base, u32 offset)
+{
+       u32 value = readl_relaxed(base + offset);
+
+       trace_vde_readl(vde, base, offset, value);
+
+       return value;
+}
+
 static void tegra_vde_set_bits(struct tegra_vde *vde,
-                              u32 mask, void __iomem *regs)
+                              u32 mask, void __iomem *base, u32 offset)
 {
-       u32 value = readl_relaxed(regs);
+       u32 value = tegra_vde_readl(vde, base, offset);
 
-       VDE_WR(value | mask, regs);
+       tegra_vde_writel(vde, value | mask, base, offset);
 }
 
 static int tegra_vde_wait_mbe(struct tegra_vde *vde)
@@ -107,8 +153,8 @@ static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde,
        unsigned int idx;
        int err;
 
-       VDE_WR(0xD0000000 | (0 << 23), vde->mbe + 0x80);
-       VDE_WR(0xD0200000 | (0 << 23), vde->mbe + 0x80);
+       tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80);
+       tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80);
 
        err = tegra_vde_wait_mbe(vde);
        if (err)
@@ -118,8 +164,10 @@ static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde,
                return 0;
 
        for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) {
-               VDE_WR(0xD0000000 | (frame_idx << 23), vde->mbe + 0x80);
-               VDE_WR(0xD0200000 | (frame_idx << 23), vde->mbe + 0x80);
+               tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23),
+                                vde->mbe, 0x80);
+               tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23),
+                                vde->mbe, 0x80);
 
                frame_idx_enb_mask |= frame_idx << (6 * (idx % 4));
 
@@ -128,7 +176,7 @@ static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde,
                        value |= (idx >> 2) << 24;
                        value |= frame_idx_enb_mask;
 
-                       VDE_WR(value, vde->mbe + 0x80);
+                       tegra_vde_writel(vde, value, vde->mbe, 0x80);
 
                        err = tegra_vde_wait_mbe(vde);
                        if (err)
@@ -143,8 +191,10 @@ static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde,
 
 static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val)
 {
-       VDE_WR(0xA0000000 | (reg << 24) | (val & 0xFFFF), vde->mbe + 0x80);
-       VDE_WR(0xA0000000 | ((reg + 1) << 24) | (val >> 16), vde->mbe + 0x80);
+       tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF),
+                        vde->mbe, 0x80);
+       tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16),
+                        vde->mbe, 0x80);
 }
 
 static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma)
@@ -183,7 +233,7 @@ static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma)
 static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde,
                                            u32 value, bool wait_dma)
 {
-       VDE_WR(value, vde->bsev + ICMDQUE_WR);
+       tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR);
 
        return tegra_vde_wait_bsev(vde, wait_dma);
 }
@@ -199,11 +249,11 @@ static void tegra_vde_setup_frameid(struct tegra_vde *vde,
        u32 value1 = frame ? ((mbs_width << 16) | mbs_height) : 0;
        u32 value2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0;
 
-       VDE_WR(y_addr  >> 8, vde->frameid + 0x000 + frameid * 4);
-       VDE_WR(cb_addr >> 8, vde->frameid + 0x100 + frameid * 4);
-       VDE_WR(cr_addr >> 8, vde->frameid + 0x180 + frameid * 4);
-       VDE_WR(value1,       vde->frameid + 0x080 + frameid * 4);
-       VDE_WR(value2,       vde->frameid + 0x280 + frameid * 4);
+       tegra_vde_writel(vde, y_addr  >> 8, vde->frameid, 0x000 + frameid * 4);
+       tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4);
+       tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4);
+       tegra_vde_writel(vde, value1,       vde->frameid, 0x080 + frameid * 4);
+       tegra_vde_writel(vde, value2,       vde->frameid, 0x280 + frameid * 4);
 }
 
 static void tegra_setup_frameidx(struct tegra_vde *vde,
@@ -228,8 +278,7 @@ static void tegra_vde_setup_iram_entry(struct tegra_vde *vde,
 {
        u32 *iram_tables = vde->iram;
 
-       dev_dbg(vde->miscdev.parent, "IRAM table %u: row %u: 0x%08X 0x%08X\n",
-               table, row, value1, value2);
+       trace_vde_setup_iram_entry(table, row, value1, value2);
 
        iram_tables[0x20 * table + row * 2] = value1;
        iram_tables[0x20 * table + row * 2 + 1] = value2;
@@ -245,10 +294,7 @@ static void tegra_vde_setup_iram_tables(struct tegra_vde *vde,
        int with_later_poc_nb;
        unsigned int i, k;
 
-       dev_dbg(vde->miscdev.parent, "DPB: Frame 0: frame_num = %d\n",
-               dpb_frames[0].frame_num);
-
-       dev_dbg(vde->miscdev.parent, "REF L0:\n");
+       trace_vde_ref_l0(dpb_frames[0].frame_num);
 
        for (i = 0; i < 16; i++) {
                if (i < ref_frames_nb) {
@@ -260,11 +306,6 @@ static void tegra_vde_setup_iram_tables(struct tegra_vde *vde,
                        value |= !(frame->flags & FLAG_B_FRAME) << 25;
                        value |= 1 << 24;
                        value |= frame->frame_num;
-
-                       dev_dbg(vde->miscdev.parent,
-                               "\tFrame %d: frame_num = %d B_frame = %d\n",
-                               i + 1, frame->frame_num,
-                               (frame->flags & FLAG_B_FRAME));
                } else {
                        aux_addr = 0x6ADEAD00;
                        value = 0;
@@ -284,9 +325,7 @@ static void tegra_vde_setup_iram_tables(struct tegra_vde *vde,
 
        with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb;
 
-       dev_dbg(vde->miscdev.parent,
-               "REF L1: with_later_poc_nb %d with_earlier_poc_nb %d\n",
-                with_later_poc_nb, with_earlier_poc_nb);
+       trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb);
 
        for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) {
                frame = &dpb_frames[k + 1];
@@ -298,10 +337,6 @@ static void tegra_vde_setup_iram_tables(struct tegra_vde *vde,
                value |= 1 << 24;
                value |= frame->frame_num;
 
-               dev_dbg(vde->miscdev.parent,
-                       "\tFrame %d: frame_num = %d\n",
-                       k + 1, frame->frame_num);
-
                tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr);
        }
 
@@ -315,10 +350,6 @@ static void tegra_vde_setup_iram_tables(struct tegra_vde *vde,
                value |= 1 << 24;
                value |= frame->frame_num;
 
-               dev_dbg(vde->miscdev.parent,
-                       "\tFrame %d: frame_num = %d\n",
-                       k + 1, frame->frame_num);
-
                tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr);
        }
 }
@@ -334,32 +365,32 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
        u32 value;
        int err;
 
-       tegra_vde_set_bits(vde, 0x000A, vde->sxe + 0xF0);
-       tegra_vde_set_bits(vde, 0x000B, vde->bsev + CMDQUE_CONTROL);
-       tegra_vde_set_bits(vde, 0x8002, vde->mbe + 0x50);
-       tegra_vde_set_bits(vde, 0x000A, vde->mbe + 0xA0);
-       tegra_vde_set_bits(vde, 0x000A, vde->ppe + 0x14);
-       tegra_vde_set_bits(vde, 0x000A, vde->ppe + 0x28);
-       tegra_vde_set_bits(vde, 0x0A00, vde->mce + 0x08);
-       tegra_vde_set_bits(vde, 0x000A, vde->tfe + 0x00);
-       tegra_vde_set_bits(vde, 0x0005, vde->vdma + 0x04);
-
-       VDE_WR(0x00000000, vde->vdma + 0x1C);
-       VDE_WR(0x00000000, vde->vdma + 0x00);
-       VDE_WR(0x00000007, vde->vdma + 0x04);
-       VDE_WR(0x00000007, vde->frameid + 0x200);
-       VDE_WR(0x00000005, vde->tfe + 0x04);
-       VDE_WR(0x00000000, vde->mbe + 0x84);
-       VDE_WR(0x00000010, vde->sxe + 0x08);
-       VDE_WR(0x00000150, vde->sxe + 0x54);
-       VDE_WR(0x0000054C, vde->sxe + 0x58);
-       VDE_WR(0x00000E34, vde->sxe + 0x5C);
-       VDE_WR(0x063C063C, vde->mce + 0x10);
-       VDE_WR(0x0003FC00, vde->bsev + INTR_STATUS);
-       VDE_WR(0x0000150D, vde->bsev + BSE_CONFIG);
-       VDE_WR(0x00000100, vde->bsev + BSE_INT_ENB);
-       VDE_WR(0x00000000, vde->bsev + 0x98);
-       VDE_WR(0x00000060, vde->bsev + 0x9C);
+       tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0);
+       tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL);
+       tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50);
+       tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0);
+       tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14);
+       tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28);
+       tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08);
+       tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00);
+       tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04);
+
+       tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C);
+       tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00);
+       tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04);
+       tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200);
+       tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04);
+       tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84);
+       tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08);
+       tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54);
+       tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58);
+       tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C);
+       tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10);
+       tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS);
+       tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG);
+       tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB);
+       tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98);
+       tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C);
 
        memset(vde->iram + 128, 0, macroblocks_nb / 2);
 
@@ -376,13 +407,13 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
         */
        wmb();
 
-       VDE_WR(0x00000000, vde->bsev + 0x8C);
-       VDE_WR(bitstream_data_addr + bitstream_data_size,
-              vde->bsev + 0x54);
+       tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C);
+       tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size,
+                        vde->bsev, 0x54);
 
        value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3;
 
-       VDE_WR(value, vde->bsev + 0x88);
+       tegra_vde_writel(vde, value, vde->bsev, 0x88);
 
        err = tegra_vde_wait_bsev(vde, false);
        if (err)
@@ -417,7 +448,7 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
        value |= ctx->pic_width_in_mbs << 11;
        value |= ctx->pic_height_in_mbs << 3;
 
-       VDE_WR(value, vde->sxe + 0x10);
+       tegra_vde_writel(vde, value, vde->sxe, 0x10);
 
        value = !ctx->baseline_profile << 17;
        value |= ctx->level_idc << 13;
@@ -425,54 +456,54 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
        value |= ctx->pic_order_cnt_type << 5;
        value |= ctx->log2_max_frame_num;
 
-       VDE_WR(value, vde->sxe + 0x40);
+       tegra_vde_writel(vde, value, vde->sxe, 0x40);
 
        value = ctx->pic_init_qp << 25;
        value |= !!(ctx->deblocking_filter_control_present_flag) << 2;
        value |= !!ctx->pic_order_present_flag;
 
-       VDE_WR(value, vde->sxe + 0x44);
+       tegra_vde_writel(vde, value, vde->sxe, 0x44);
 
        value = ctx->chroma_qp_index_offset;
        value |= ctx->num_ref_idx_l0_active_minus1 << 5;
        value |= ctx->num_ref_idx_l1_active_minus1 << 10;
        value |= !!ctx->constrained_intra_pred_flag << 15;
 
-       VDE_WR(value, vde->sxe + 0x48);
+       tegra_vde_writel(vde, value, vde->sxe, 0x48);
 
        value = 0x0C000000;
        value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24;
 
-       VDE_WR(value, vde->sxe + 0x4C);
+       tegra_vde_writel(vde, value, vde->sxe, 0x4C);
 
        value = 0x03800000;
        value |= bitstream_data_size & GENMASK(19, 15);
 
-       VDE_WR(value, vde->sxe + 0x68);
+       tegra_vde_writel(vde, value, vde->sxe, 0x68);
 
-       VDE_WR(bitstream_data_addr, vde->sxe + 0x6C);
+       tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C);
 
        value = 0x10000005;
        value |= ctx->pic_width_in_mbs << 11;
        value |= ctx->pic_height_in_mbs << 3;
 
-       VDE_WR(value, vde->mbe + 0x80);
+       tegra_vde_writel(vde, value, vde->mbe, 0x80);
 
        value = 0x26800000;
        value |= ctx->level_idc << 4;
        value |= !ctx->baseline_profile << 1;
        value |= !!ctx->direct_8x8_inference_flag;
 
-       VDE_WR(value, vde->mbe + 0x80);
+       tegra_vde_writel(vde, value, vde->mbe, 0x80);
 
-       VDE_WR(0xF4000001, vde->mbe + 0x80);
-       VDE_WR(0x20000000, vde->mbe + 0x80);
-       VDE_WR(0xF4000101, vde->mbe + 0x80);
+       tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80);
+       tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80);
+       tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80);
 
        value = 0x20000000;
        value |= ctx->chroma_qp_index_offset << 8;
 
-       VDE_WR(value, vde->mbe + 0x80);
+       tegra_vde_writel(vde, value, vde->mbe, 0x80);
 
        err = tegra_vde_setup_mbe_frame_idx(vde,
                                            ctx->dpb_frames_nb - 1,
@@ -494,7 +525,7 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
        if (!ctx->baseline_profile)
                value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1;
 
-       VDE_WR(value, vde->mbe + 0x80);
+       tegra_vde_writel(vde, value, vde->mbe, 0x80);
 
        err = tegra_vde_wait_mbe(vde);
        if (err) {
@@ -510,8 +541,9 @@ static void tegra_vde_decode_frame(struct tegra_vde *vde,
 {
        reinit_completion(&vde->decode_completion);
 
-       VDE_WR(0x00000001, vde->bsev + 0x8C);
-       VDE_WR(0x20000000 | (macroblocks_nb - 1), vde->sxe + 0x00);
+       tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C);
+       tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1),
+                        vde->sxe, 0x00);
 }
 
 static void tegra_vde_detach_and_put_dmabuf(struct dma_buf_attachment *a,
@@ -883,8 +915,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
        timeout = wait_for_completion_interruptible_timeout(
                        &vde->decode_completion, msecs_to_jiffies(1000));
        if (timeout == 0) {
-               bsev_ptr = readl_relaxed(vde->bsev + 0x10);
-               macroblocks_nb = readl_relaxed(vde->sxe + 0xC8) & 0x1FFF;
+               bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10);
+               macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF;
                read_bytes = bsev_ptr ? bsev_ptr - bitstream_data_addr : 0;
 
                dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n",
@@ -962,7 +994,7 @@ static irqreturn_t tegra_vde_isr(int irq, void *data)
        if (completion_done(&vde->decode_completion))
                return IRQ_NONE;
 
-       tegra_vde_set_bits(vde, 0, vde->frameid + 0x208);
+       tegra_vde_set_bits(vde, 0, vde->frameid, 0x208);
        complete(&vde->decode_completion);
 
        return IRQ_HANDLED;
diff --git a/drivers/staging/media/tegra-vde/trace.h b/drivers/staging/media/tegra-vde/trace.h
new file mode 100644 (file)
index 0000000..85e2f7e
--- /dev/null
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM tegra_vde
+
+#if !defined(TEGRA_VDE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define TEGRA_VDE_TRACE_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(register_access,
+       TP_PROTO(struct tegra_vde *vde, void __iomem *base,
+                u32 offset, u32 value),
+       TP_ARGS(vde, base, offset, value),
+       TP_STRUCT__entry(
+               __string(hw_name, tegra_vde_reg_base_name(vde, base))
+               __field(u32, offset)
+               __field(u32, value)
+       ),
+       TP_fast_assign(
+               __assign_str(hw_name, tegra_vde_reg_base_name(vde, base));
+               __entry->offset = offset;
+               __entry->value = value;
+       ),
+       TP_printk("%s:0x%03x 0x%08x", __get_str(hw_name), __entry->offset,
+                 __entry->value)
+);
+
+DEFINE_EVENT(register_access, vde_writel,
+       TP_PROTO(struct tegra_vde *vde, void __iomem *base,
+                u32 offset, u32 value),
+       TP_ARGS(vde, base, offset, value));
+DEFINE_EVENT(register_access, vde_readl,
+       TP_PROTO(struct tegra_vde *vde, void __iomem *base,
+                u32 offset, u32 value),
+       TP_ARGS(vde, base, offset, value));
+
+TRACE_EVENT(vde_setup_iram_entry,
+       TP_PROTO(unsigned int table, unsigned int row, u32 value, u32 aux_addr),
+       TP_ARGS(table, row, value, aux_addr),
+       TP_STRUCT__entry(
+               __field(unsigned int, table)
+               __field(unsigned int, row)
+               __field(u32, value)
+               __field(u32, aux_addr)
+       ),
+       TP_fast_assign(
+               __entry->table = table;
+               __entry->row = row;
+               __entry->value = value;
+               __entry->aux_addr = aux_addr;
+       ),
+       TP_printk("[%u][%u] = { 0x%08x (flags = \"%s\", frame_num = %u); 0x%08x }",
+                 __entry->table, __entry->row, __entry->value,
+                 __print_flags(__entry->value, " ", { (1 << 25), "B" }),
+                 __entry->value & 0x7FFFFF, __entry->aux_addr)
+);
+
+TRACE_EVENT(vde_ref_l0,
+       TP_PROTO(unsigned int frame_num),
+       TP_ARGS(frame_num),
+       TP_STRUCT__entry(
+               __field(unsigned int, frame_num)
+       ),
+       TP_fast_assign(
+               __entry->frame_num = frame_num;
+       ),
+       TP_printk("REF L0: DPB: Frame 0: frame_num = %u", __entry->frame_num)
+);
+
+TRACE_EVENT(vde_ref_l1,
+       TP_PROTO(unsigned int with_later_poc_nb,
+                unsigned int with_earlier_poc_nb),
+       TP_ARGS(with_later_poc_nb, with_earlier_poc_nb),
+       TP_STRUCT__entry(
+               __field(unsigned int, with_later_poc_nb)
+               __field(unsigned int, with_earlier_poc_nb)
+       ),
+       TP_fast_assign(
+               __entry->with_later_poc_nb = with_later_poc_nb;
+               __entry->with_earlier_poc_nb = with_earlier_poc_nb;
+       ),
+       TP_printk("REF L1: with_later_poc_nb %u, with_earlier_poc_nb %u",
+                 __entry->with_later_poc_nb, __entry->with_earlier_poc_nb)
+);
+
+#endif /* TEGRA_VDE_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/staging/media/tegra-vde
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig
deleted file mode 100644 (file)
index f3f9cb3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-config MTD_SPINAND_MT29F
-       tristate "SPINAND Device Support for Micron"
-       depends on MTD_NAND && SPI
-       help
-         This enables support for accessing Micron SPI NAND flash
-         devices.
-         If you have Micron SPI NAND chip say yes.
-
-         If unsure, say no here.
-
-config MTD_SPINAND_ONDIEECC
-       bool "Use SPINAND internal ECC"
-       depends on MTD_SPINAND_MT29F
-       help
-         Internal ECC.
-         Enables Hardware ECC support for Micron SPI NAND.
diff --git a/drivers/staging/mt29f_spinand/Makefile b/drivers/staging/mt29f_spinand/Makefile
deleted file mode 100644 (file)
index e47af0f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand.o
diff --git a/drivers/staging/mt29f_spinand/TODO b/drivers/staging/mt29f_spinand/TODO
deleted file mode 100644 (file)
index a2209b7..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-TODO:
-       - Tested on XLP platform, needs to be tested on other platforms.
-       - Checkpatch.pl cleanups
-       - Sparce fixes.
-       - Clean up coding style to meet kernel standard.
-
-Please send patches
-To:
-Kamlakant Patel <kamlakant.patel@broadcom.com>
-Cc:
-Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Mona Anonuevo <manonuevo@micron.com>
-linux-mtd@lists.infradead.org
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
deleted file mode 100644 (file)
index def8a1f..0000000
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Copyright (c) 2003-2013 Broadcom Corporation
- *
- * Copyright (c) 2009-2010 Micron Technology, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/spi/spi.h>
-
-#include "mt29f_spinand.h"
-
-#define BUFSIZE (10 * 64 * 2048)
-#define CACHE_BUF 2112
-/*
- * OOB area specification layout:  Total 32 available free bytes.
- */
-
-static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct spinand_info *info = nand_get_controller_data(chip);
-       struct spinand_state *state = info->priv;
-
-       return state;
-}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-static int enable_hw_ecc;
-static int enable_read_hw_ecc;
-
-static int spinand_ooblayout_64_ecc(struct mtd_info *mtd, int section,
-                                   struct mtd_oob_region *oobregion)
-{
-       if (section > 3)
-               return -ERANGE;
-
-       oobregion->offset = (section * 16) + 1;
-       oobregion->length = 6;
-
-       return 0;
-}
-
-static int spinand_ooblayout_64_free(struct mtd_info *mtd, int section,
-                                    struct mtd_oob_region *oobregion)
-{
-       if (section > 3)
-               return -ERANGE;
-
-       oobregion->offset = (section * 16) + 8;
-       oobregion->length = 8;
-
-       return 0;
-}
-
-static const struct mtd_ooblayout_ops spinand_oob_64_ops = {
-       .ecc = spinand_ooblayout_64_ecc,
-       .free = spinand_ooblayout_64_free,
-};
-#endif
-
-/**
- * spinand_cmd - process a command to send to the SPI Nand
- * Description:
- *    Set up the command buffer to send to the SPI controller.
- *    The command buffer has to initialized to 0.
- */
-
-static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
-{
-       struct spi_message message;
-       struct spi_transfer x[4];
-       u8 dummy = 0xff;
-
-       spi_message_init(&message);
-       memset(x, 0, sizeof(x));
-
-       x[0].len = 1;
-       x[0].tx_buf = &cmd->cmd;
-       spi_message_add_tail(&x[0], &message);
-
-       if (cmd->n_addr) {
-               x[1].len = cmd->n_addr;
-               x[1].tx_buf = cmd->addr;
-               spi_message_add_tail(&x[1], &message);
-       }
-
-       if (cmd->n_dummy) {
-               x[2].len = cmd->n_dummy;
-               x[2].tx_buf = &dummy;
-               spi_message_add_tail(&x[2], &message);
-       }
-
-       if (cmd->n_tx) {
-               x[3].len = cmd->n_tx;
-               x[3].tx_buf = cmd->tx_buf;
-               spi_message_add_tail(&x[3], &message);
-       }
-
-       if (cmd->n_rx) {
-               x[3].len = cmd->n_rx;
-               x[3].rx_buf = cmd->rx_buf;
-               spi_message_add_tail(&x[3], &message);
-       }
-
-       return spi_sync(spi, &message);
-}
-
-/**
- * spinand_read_id - Read SPI Nand ID
- * Description:
- *    read two ID bytes from the SPI Nand device
- */
-static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
-{
-       int retval;
-       u8 nand_id[3];
-       struct spinand_cmd cmd = {0};
-
-       cmd.cmd = CMD_READ_ID;
-       cmd.n_rx = 3;
-       cmd.rx_buf = &nand_id[0];
-
-       retval = spinand_cmd(spi_nand, &cmd);
-       if (retval < 0) {
-               dev_err(&spi_nand->dev, "error %d reading id\n", retval);
-               return retval;
-       }
-       id[0] = nand_id[1];
-       id[1] = nand_id[2];
-       return retval;
-}
-
-/**
- * spinand_read_status - send command 0xf to the SPI Nand status register
- * Description:
- *    After read, write, or erase, the Nand device is expected to set the
- *    busy status.
- *    This function is to allow reading the status of the command: read,
- *    write, and erase.
- *    Once the status turns to be ready, the other status bits also are
- *    valid status bits.
- */
-static int spinand_read_status(struct spi_device *spi_nand, u8 *status)
-{
-       struct spinand_cmd cmd = {0};
-       int ret;
-
-       cmd.cmd = CMD_READ_REG;
-       cmd.n_addr = 1;
-       cmd.addr[0] = REG_STATUS;
-       cmd.n_rx = 1;
-       cmd.rx_buf = status;
-
-       ret = spinand_cmd(spi_nand, &cmd);
-       if (ret < 0)
-               dev_err(&spi_nand->dev, "err: %d read status register\n", ret);
-
-       return ret;
-}
-
-#define MAX_WAIT_JIFFIES  (40 * HZ)
-static int wait_till_ready(struct spi_device *spi_nand)
-{
-       unsigned long deadline;
-       int retval;
-       u8 stat = 0;
-
-       deadline = jiffies + MAX_WAIT_JIFFIES;
-       do {
-               retval = spinand_read_status(spi_nand, &stat);
-               if (retval < 0)
-                       return -1;
-               if (!(stat & 0x1))
-                       break;
-
-               cond_resched();
-       } while (!time_after_eq(jiffies, deadline));
-
-       if ((stat & 0x1) == 0)
-               return 0;
-
-       return -1;
-}
-
-/**
- * spinand_get_otp - send command 0xf to read the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp)
-{
-       struct spinand_cmd cmd = {0};
-       int retval;
-
-       cmd.cmd = CMD_READ_REG;
-       cmd.n_addr = 1;
-       cmd.addr[0] = REG_OTP;
-       cmd.n_rx = 1;
-       cmd.rx_buf = otp;
-
-       retval = spinand_cmd(spi_nand, &cmd);
-       if (retval < 0)
-               dev_err(&spi_nand->dev, "error %d get otp\n", retval);
-       return retval;
-}
-
-/**
- * spinand_set_otp - send command 0x1f to write the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp)
-{
-       int retval;
-       struct spinand_cmd cmd = {0};
-
-       cmd.cmd = CMD_WRITE_REG;
-       cmd.n_addr = 1;
-       cmd.addr[0] = REG_OTP;
-       cmd.n_tx = 1;
-       cmd.tx_buf = otp;
-
-       retval = spinand_cmd(spi_nand, &cmd);
-       if (retval < 0)
-               dev_err(&spi_nand->dev, "error %d set otp\n", retval);
-
-       return retval;
-}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-/**
- * spinand_enable_ecc - send command 0x1f to write the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_enable_ecc(struct spi_device *spi_nand)
-{
-       int retval;
-       u8 otp = 0;
-
-       retval = spinand_get_otp(spi_nand, &otp);
-       if (retval < 0)
-               return retval;
-
-       if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
-               return 0;
-       otp |= OTP_ECC_MASK;
-       retval = spinand_set_otp(spi_nand, &otp);
-       if (retval < 0)
-               return retval;
-       return spinand_get_otp(spi_nand, &otp);
-}
-#endif
-
-static int spinand_disable_ecc(struct spi_device *spi_nand)
-{
-       int retval;
-       u8 otp = 0;
-
-       retval = spinand_get_otp(spi_nand, &otp);
-       if (retval < 0)
-               return retval;
-
-       if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
-               otp &= ~OTP_ECC_MASK;
-               retval = spinand_set_otp(spi_nand, &otp);
-               if (retval < 0)
-                       return retval;
-               return spinand_get_otp(spi_nand, &otp);
-       }
-       return 0;
-}
-
-/**
- * spinand_write_enable - send command 0x06 to enable write or erase the
- * Nand cells
- * Description:
- *   Before write and erase the Nand cells, the write enable has to be set.
- *   After the write or erase, the write enable bit is automatically
- *   cleared (status register bit 2)
- *   Set the bit 2 of the status register has the same effect
- */
-static int spinand_write_enable(struct spi_device *spi_nand)
-{
-       struct spinand_cmd cmd = {0};
-
-       cmd.cmd = CMD_WR_ENABLE;
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id)
-{
-       struct spinand_cmd cmd = {0};
-       u16 row;
-
-       row = page_id;
-       cmd.cmd = CMD_READ;
-       cmd.n_addr = 3;
-       cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
-       cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-       cmd.addr[2] = (u8)(row & 0x00ff);
-
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_read_from_cache - send command 0x03 to read out the data from the
- * cache register (2112 bytes max)
- * Description:
- *   The read can specify 1 to 2112 bytes of data read at the corresponding
- *   locations.
- *   No tRd delay.
- */
-static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id,
-                                  u16 byte_id, u16 len, u8 *rbuf)
-{
-       struct spinand_cmd cmd = {0};
-       u16 column;
-
-       column = byte_id;
-       cmd.cmd = CMD_READ_RDM;
-       cmd.n_addr = 3;
-       cmd.addr[0] = (u8)((column & 0xff00) >> 8);
-       cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
-       cmd.addr[1] = (u8)(column & 0x00ff);
-       cmd.addr[2] = (u8)(0xff);
-       cmd.n_dummy = 0;
-       cmd.n_rx = len;
-       cmd.rx_buf = rbuf;
-
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_read_page - read a page
- * @page_id: the physical page number
- * @offset:  the location from 0 to 2111
- * @len:     number of bytes to read
- * @rbuf:    read buffer to hold @len bytes
- *
- * Description:
- *   The read includes two commands to the Nand - 0x13 and 0x03 commands
- *   Poll to read status to wait for tRD time.
- */
-static int spinand_read_page(struct spi_device *spi_nand, u16 page_id,
-                            u16 offset, u16 len, u8 *rbuf)
-{
-       int ret;
-       u8 status = 0;
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       if (enable_read_hw_ecc) {
-               if (spinand_enable_ecc(spi_nand) < 0)
-                       dev_err(&spi_nand->dev, "enable HW ECC failed!");
-       }
-#endif
-       ret = spinand_read_page_to_cache(spi_nand, page_id);
-       if (ret < 0)
-               return ret;
-
-       if (wait_till_ready(spi_nand))
-               dev_err(&spi_nand->dev, "WAIT timedout!!!\n");
-
-       while (1) {
-               ret = spinand_read_status(spi_nand, &status);
-               if (ret < 0) {
-                       dev_err(&spi_nand->dev,
-                               "err %d read status register\n", ret);
-                       return ret;
-               }
-
-               if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-                       if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
-                               dev_err(&spi_nand->dev, "ecc error, page=%d\n",
-                                       page_id);
-                               return 0;
-                       }
-                       break;
-               }
-       }
-
-       ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf);
-       if (ret < 0) {
-               dev_err(&spi_nand->dev, "read from cache failed!!\n");
-               return ret;
-       }
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       if (enable_read_hw_ecc) {
-               ret = spinand_disable_ecc(spi_nand);
-               if (ret < 0) {
-                       dev_err(&spi_nand->dev, "disable ecc failed!!\n");
-                       return ret;
-               }
-               enable_read_hw_ecc = 0;
-       }
-#endif
-       return ret;
-}
-
-/**
- * spinand_program_data_to_cache - write a page to cache
- * @byte_id: the location to write to the cache
- * @len:     number of bytes to write
- * @wbuf:    write buffer holding @len bytes
- *
- * Description:
- *   The write command used here is 0x84--indicating that the cache is
- *   not cleared first.
- *   Since it is writing the data to cache, there is no tPROG time.
- */
-static int spinand_program_data_to_cache(struct spi_device *spi_nand,
-                                        u16 page_id, u16 byte_id,
-                                        u16 len, u8 *wbuf)
-{
-       struct spinand_cmd cmd = {0};
-       u16 column;
-
-       column = byte_id;
-       cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
-       cmd.n_addr = 2;
-       cmd.addr[0] = (u8)((column & 0xff00) >> 8);
-       cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
-       cmd.addr[1] = (u8)(column & 0x00ff);
-       cmd.n_tx = len;
-       cmd.tx_buf = wbuf;
-
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_program_execute - write a page from cache to the Nand array
- * @page_id: the physical page location to write the page.
- *
- * Description:
- *   The write command used here is 0x10--indicating the cache is writing to
- *   the Nand array.
- *   Need to wait for tPROG time to finish the transaction.
- */
-static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id)
-{
-       struct spinand_cmd cmd = {0};
-       u16 row;
-
-       row = page_id;
-       cmd.cmd = CMD_PROG_PAGE_EXC;
-       cmd.n_addr = 3;
-       cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
-       cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-       cmd.addr[2] = (u8)(row & 0x00ff);
-
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_program_page - write a page
- * @page_id: the physical page location to write the page.
- * @offset:  the location from the cache starting from 0 to 2111
- * @len:     the number of bytes to write
- * @buf:     the buffer holding @len bytes
- *
- * Description:
- *   The commands used here are 0x06, 0x84, and 0x10--indicating that
- *   the write enable is first sent, the write cache command, and the
- *   write execute command.
- *   Poll to wait for the tPROG time to finish the transaction.
- */
-static int spinand_program_page(struct spi_device *spi_nand,
-                               u16 page_id, u16 offset, u16 len, u8 *buf)
-{
-       int retval;
-       u8 status = 0;
-       u8 *wbuf;
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       unsigned int i, j;
-
-       wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL);
-       if (!wbuf)
-               return -ENOMEM;
-
-       enable_read_hw_ecc = 1;
-       retval = spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf);
-       if (retval < 0) {
-               dev_err(&spi_nand->dev, "ecc error on read page!!!\n");
-               return retval;
-       }
-
-       for (i = offset, j = 0; i < len; i++, j++)
-               wbuf[i] &= buf[j];
-
-       if (enable_hw_ecc) {
-               retval = spinand_enable_ecc(spi_nand);
-               if (retval < 0) {
-                       dev_err(&spi_nand->dev, "enable ecc failed!!\n");
-                       return retval;
-               }
-       }
-#else
-       wbuf = buf;
-#endif
-       retval = spinand_write_enable(spi_nand);
-       if (retval < 0) {
-               dev_err(&spi_nand->dev, "write enable failed!!\n");
-               return retval;
-       }
-       if (wait_till_ready(spi_nand))
-               dev_err(&spi_nand->dev, "wait timedout!!!\n");
-
-       retval = spinand_program_data_to_cache(spi_nand, page_id,
-                                              offset, len, wbuf);
-       if (retval < 0)
-               return retval;
-       retval = spinand_program_execute(spi_nand, page_id);
-       if (retval < 0)
-               return retval;
-       while (1) {
-               retval = spinand_read_status(spi_nand, &status);
-               if (retval < 0) {
-                       dev_err(&spi_nand->dev,
-                               "error %d reading status register\n", retval);
-                       return retval;
-               }
-
-               if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-                       if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) {
-                               dev_err(&spi_nand->dev,
-                                       "program error, page %d\n", page_id);
-                               return -1;
-                       }
-                       break;
-               }
-       }
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       if (enable_hw_ecc) {
-               retval = spinand_disable_ecc(spi_nand);
-               if (retval < 0) {
-                       dev_err(&spi_nand->dev, "disable ecc failed!!\n");
-                       return retval;
-               }
-               enable_hw_ecc = 0;
-       }
-#endif
-
-       return 0;
-}
-
-/**
- * spinand_erase_block_erase - erase a page
- * @block_id: the physical block location to erase.
- *
- * Description:
- *   The command used here is 0xd8--indicating an erase command to erase
- *   one block--64 pages
- *   Need to wait for tERS.
- */
-static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id)
-{
-       struct spinand_cmd cmd = {0};
-       u16 row;
-
-       row = block_id;
-       cmd.cmd = CMD_ERASE_BLK;
-       cmd.n_addr = 3;
-       cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
-       cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-       cmd.addr[2] = (u8)(row & 0x00ff);
-
-       return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_erase_block - erase a page
- * @block_id: the physical block location to erase.
- *
- * Description:
- *   The commands used here are 0x06 and 0xd8--indicating an erase
- *   command to erase one block--64 pages
- *   It will first to enable the write enable bit (0x06 command),
- *   and then send the 0xd8 erase command
- *   Poll to wait for the tERS time to complete the tranaction.
- */
-static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
-{
-       int retval;
-       u8 status = 0;
-
-       retval = spinand_write_enable(spi_nand);
-       if (wait_till_ready(spi_nand))
-               dev_err(&spi_nand->dev, "wait timedout!!!\n");
-
-       retval = spinand_erase_block_erase(spi_nand, block_id);
-       while (1) {
-               retval = spinand_read_status(spi_nand, &status);
-               if (retval < 0) {
-                       dev_err(&spi_nand->dev,
-                               "error %d reading status register\n", retval);
-                       return retval;
-               }
-
-               if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-                       if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) {
-                               dev_err(&spi_nand->dev,
-                                       "erase error, block %d\n", block_id);
-                               return -1;
-                       }
-                       break;
-               }
-       }
-       return 0;
-}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-static int spinand_write_page_hwecc(struct nand_chip *chip,
-                                   const u8 *buf, int oob_required,
-                                   int page)
-{
-       const u8 *p = buf;
-       int eccsize = chip->ecc.size;
-       int eccsteps = chip->ecc.steps;
-
-       enable_hw_ecc = 1;
-       return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps);
-}
-
-static int spinand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
-                                  int oob_required, int page)
-{
-       int retval;
-       u8 status;
-       u8 *p = buf;
-       int eccsize = chip->ecc.size;
-       int eccsteps = chip->ecc.steps;
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct spinand_info *info = nand_get_controller_data(chip);
-
-       enable_read_hw_ecc = 1;
-
-       nand_read_page_op(chip, page, 0, p, eccsize * eccsteps);
-       if (oob_required)
-               chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
-
-       while (1) {
-               retval = spinand_read_status(info->spi, &status);
-               if (retval < 0) {
-                       dev_err(&mtd->dev,
-                               "error %d reading status register\n", retval);
-                       return retval;
-               }
-
-               if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-                       if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
-                               pr_info("spinand: ECC error\n");
-                               mtd->ecc_stats.failed++;
-                       } else if ((status & STATUS_ECC_MASK) ==
-                                       STATUS_ECC_1BIT_CORRECTED)
-                               mtd->ecc_stats.corrected++;
-                       break;
-               }
-       }
-       return 0;
-}
-#endif
-
-static void spinand_select_chip(struct nand_chip *chip, int dev)
-{
-}
-
-static u8 spinand_read_byte(struct nand_chip *chip)
-{
-       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
-       u8 data;
-
-       data = state->buf[state->buf_ptr];
-       state->buf_ptr++;
-       return data;
-}
-
-static int spinand_wait(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct spinand_info *info = nand_get_controller_data(chip);
-
-       unsigned long timeo = jiffies;
-       int retval, state = chip->state;
-       u8 status;
-
-       if (state == FL_ERASING)
-               timeo += (HZ * 400) / 1000;
-       else
-               timeo += (HZ * 20) / 1000;
-
-       while (time_before(jiffies, timeo)) {
-               retval = spinand_read_status(info->spi, &status);
-               if (retval < 0) {
-                       dev_err(&mtd->dev,
-                               "error %d reading status register\n", retval);
-                       return retval;
-               }
-
-               if ((status & STATUS_OIP_MASK) == STATUS_READY)
-                       return 0;
-
-               cond_resched();
-       }
-       return 0;
-}
-
-static void spinand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
-{
-       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
-
-       memcpy(state->buf + state->buf_ptr, buf, len);
-       state->buf_ptr += len;
-}
-
-static void spinand_read_buf(struct nand_chip *chip, u8 *buf, int len)
-{
-       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
-
-       memcpy(buf, state->buf + state->buf_ptr, len);
-       state->buf_ptr += len;
-}
-
-/*
- * spinand_reset- send RESET command "0xff" to the Nand device.
- */
-static void spinand_reset(struct spi_device *spi_nand)
-{
-       struct spinand_cmd cmd = {0};
-
-       cmd.cmd = CMD_RESET;
-
-       if (spinand_cmd(spi_nand, &cmd) < 0)
-               pr_info("spinand reset failed!\n");
-
-       /* elapse 1ms before issuing any other command */
-       usleep_range(1000, 2000);
-
-       if (wait_till_ready(spi_nand))
-               dev_err(&spi_nand->dev, "wait timedout!\n");
-}
-
-static void spinand_cmdfunc(struct nand_chip *chip, unsigned int command,
-                           int column, int page)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct spinand_info *info = nand_get_controller_data(chip);
-       struct spinand_state *state = info->priv;
-
-       switch (command) {
-       /*
-        * READ0 - read in first  0x800 bytes
-        */
-       case NAND_CMD_READ1:
-       case NAND_CMD_READ0:
-               state->buf_ptr = 0;
-               spinand_read_page(info->spi, page, 0x0, 0x840, state->buf);
-               break;
-       /* READOOB reads only the OOB because no ECC is performed. */
-       case NAND_CMD_READOOB:
-               state->buf_ptr = 0;
-               spinand_read_page(info->spi, page, 0x800, 0x40, state->buf);
-               break;
-       case NAND_CMD_RNDOUT:
-               state->buf_ptr = column;
-               break;
-       case NAND_CMD_READID:
-               state->buf_ptr = 0;
-               spinand_read_id(info->spi, state->buf);
-               break;
-       case NAND_CMD_PARAM:
-               state->buf_ptr = 0;
-               break;
-       /* ERASE1 stores the block and page address */
-       case NAND_CMD_ERASE1:
-               spinand_erase_block(info->spi, page);
-               break;
-       /* ERASE2 uses the block and page address from ERASE1 */
-       case NAND_CMD_ERASE2:
-               break;
-       /* SEQIN sets up the addr buffer and all registers except the length */
-       case NAND_CMD_SEQIN:
-               state->col = column;
-               state->row = page;
-               state->buf_ptr = 0;
-               break;
-       /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
-       case NAND_CMD_PAGEPROG:
-               spinand_program_page(info->spi, state->row, state->col,
-                                    state->buf_ptr, state->buf);
-               break;
-       case NAND_CMD_STATUS:
-               spinand_get_otp(info->spi, state->buf);
-               if (!(state->buf[0] & 0x80))
-                       state->buf[0] = 0x80;
-               state->buf_ptr = 0;
-               break;
-       /* RESET command */
-       case NAND_CMD_RESET:
-               if (wait_till_ready(info->spi))
-                       dev_err(&info->spi->dev, "WAIT timedout!!!\n");
-               /* a minimum of 250us must elapse before issuing RESET cmd*/
-               usleep_range(250, 1000);
-               spinand_reset(info->spi);
-               break;
-       default:
-               dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command);
-       }
-}
-
-/**
- * spinand_lock_block - send write register 0x1f command to the Nand device
- *
- * Description:
- *    After power up, all the Nand blocks are locked.  This function allows
- *    one to unlock the blocks, and so it can be written or erased.
- */
-static int spinand_lock_block(struct spi_device *spi_nand, u8 lock)
-{
-       struct spinand_cmd cmd = {0};
-       int ret;
-       u8 otp = 0;
-
-       ret = spinand_get_otp(spi_nand, &otp);
-
-       cmd.cmd = CMD_WRITE_REG;
-       cmd.n_addr = 1;
-       cmd.addr[0] = REG_BLOCK_LOCK;
-       cmd.n_tx = 1;
-       cmd.tx_buf = &lock;
-
-       ret = spinand_cmd(spi_nand, &cmd);
-       if (ret < 0)
-               dev_err(&spi_nand->dev, "error %d lock block\n", ret);
-
-       return ret;
-}
-
-/**
- * spinand_probe - [spinand Interface]
- * @spi_nand: registered device driver.
- *
- * Description:
- *   Set up the device driver parameters to make the device available.
- */
-static int spinand_probe(struct spi_device *spi_nand)
-{
-       struct mtd_info *mtd;
-       struct nand_chip *chip;
-       struct spinand_info *info;
-       struct spinand_state *state;
-
-       info  = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info),
-                            GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->spi = spi_nand;
-
-       spinand_lock_block(spi_nand, BL_ALL_UNLOCKED);
-
-       state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state),
-                            GFP_KERNEL);
-       if (!state)
-               return -ENOMEM;
-
-       info->priv      = state;
-       state->buf_ptr  = 0;
-       state->buf      = devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL);
-       if (!state->buf)
-               return -ENOMEM;
-
-       chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip),
-                           GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       chip->ecc.mode  = NAND_ECC_HW;
-       chip->ecc.size  = 0x200;
-       chip->ecc.bytes = 0x6;
-       chip->ecc.steps = 0x4;
-
-       chip->ecc.strength = 1;
-       chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
-       chip->ecc.read_page = spinand_read_page_hwecc;
-       chip->ecc.write_page = spinand_write_page_hwecc;
-#else
-       chip->ecc.mode  = NAND_ECC_SOFT;
-       chip->ecc.algo  = NAND_ECC_HAMMING;
-       if (spinand_disable_ecc(spi_nand) < 0)
-               dev_info(&spi_nand->dev, "%s: disable ecc failed!\n",
-                        __func__);
-#endif
-
-       nand_set_flash_node(chip, spi_nand->dev.of_node);
-       nand_set_controller_data(chip, info);
-       chip->legacy.read_buf   = spinand_read_buf;
-       chip->legacy.write_buf  = spinand_write_buf;
-       chip->legacy.read_byte  = spinand_read_byte;
-       chip->legacy.cmdfunc    = spinand_cmdfunc;
-       chip->legacy.waitfunc   = spinand_wait;
-       chip->options   |= NAND_CACHEPRG;
-       chip->select_chip = spinand_select_chip;
-       chip->legacy.set_features = nand_get_set_features_notsupp;
-       chip->legacy.get_features = nand_get_set_features_notsupp;
-
-       mtd = nand_to_mtd(chip);
-
-       dev_set_drvdata(&spi_nand->dev, mtd);
-
-       mtd->dev.parent = &spi_nand->dev;
-       mtd->oobsize = 64;
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-       mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
-#endif
-
-       if (nand_scan(chip, 1))
-               return -ENXIO;
-
-       return mtd_device_register(mtd, NULL, 0);
-}
-
-/**
- * spinand_remove - remove the device driver
- * @spi: the spi device.
- *
- * Description:
- *   Remove the device driver parameters and free up allocated memories.
- */
-static int spinand_remove(struct spi_device *spi)
-{
-       mtd_device_unregister(dev_get_drvdata(&spi->dev));
-
-       return 0;
-}
-
-static const struct of_device_id spinand_dt[] = {
-       { .compatible = "spinand,mt29f", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, spinand_dt);
-
-/*
- * Device name structure description
- */
-static struct spi_driver spinand_driver = {
-       .driver = {
-               .name           = "mt29f",
-               .of_match_table = spinand_dt,
-       },
-       .probe          = spinand_probe,
-       .remove         = spinand_remove,
-};
-
-module_spi_driver(spinand_driver);
-
-MODULE_DESCRIPTION("SPI NAND driver for Micron");
-MODULE_AUTHOR("Henry Pan <hspan@micron.com>, Kamlakant Patel <kamlakant.patel@broadcom.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.h b/drivers/staging/mt29f_spinand/mt29f_spinand.h
deleted file mode 100644 (file)
index 457dc7f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*-
- * Copyright 2013 Broadcom Corporation
- *
- * Copyright (c) 2009-2010 Micron Technology, 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.
- *
- * Henry Pan <hspan@micron.com>
- *
- * based on nand.h
- */
-#ifndef __LINUX_MTD_SPI_NAND_H
-#define __LINUX_MTD_SPI_NAND_H
-
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mtd/mtd.h>
-
-/* cmd */
-#define CMD_READ                       0x13
-#define CMD_READ_RDM                   0x03
-#define CMD_PROG_PAGE_CLRCACHE         0x02
-#define CMD_PROG_PAGE                  0x84
-#define CMD_PROG_PAGE_EXC              0x10
-#define CMD_ERASE_BLK                  0xd8
-#define CMD_WR_ENABLE                  0x06
-#define CMD_WR_DISABLE                 0x04
-#define CMD_READ_ID                    0x9f
-#define CMD_RESET                      0xff
-#define CMD_READ_REG                   0x0f
-#define CMD_WRITE_REG                  0x1f
-
-/* feature/ status reg */
-#define REG_BLOCK_LOCK                 0xa0
-#define REG_OTP                                0xb0
-#define REG_STATUS                     0xc0/* timing */
-
-/* status */
-#define STATUS_OIP_MASK                        0x01
-#define STATUS_READY                   0
-#define STATUS_BUSY                    BIT(0)
-
-#define STATUS_E_FAIL_MASK             0x04
-#define STATUS_E_FAIL                  BIT(2)
-
-#define STATUS_P_FAIL_MASK             0x08
-#define STATUS_P_FAIL                  BIT(3)
-
-#define STATUS_ECC_MASK                        0x30
-#define STATUS_ECC_1BIT_CORRECTED      BIT(4)
-#define STATUS_ECC_ERROR               BIT(5)
-#define STATUS_ECC_RESERVED            (BIT(5) | BIT(4))
-
-/*ECC enable defines*/
-#define OTP_ECC_MASK                   0x10
-#define OTP_ECC_OFF                    0
-#define OTP_ECC_ON                     1
-
-#define ECC_DISABLED
-#define ECC_IN_NAND
-#define ECC_SOFT
-
-/* block lock */
-#define BL_ALL_LOCKED      0x38
-#define BL_1_2_LOCKED      0x30
-#define BL_1_4_LOCKED      0x28
-#define BL_1_8_LOCKED      0x20
-#define BL_1_16_LOCKED     0x18
-#define BL_1_32_LOCKED     0x10
-#define BL_1_64_LOCKED     0x08
-#define BL_ALL_UNLOCKED    0
-
-struct spinand_info {
-       struct spi_device *spi;
-       void *priv;
-};
-
-struct spinand_state {
-       u32     col;
-       u32     row;
-       int             buf_ptr;
-       u8              *buf;
-};
-
-struct spinand_cmd {
-       u8              cmd;
-       u32             n_addr;         /* Number of address */
-       u8              addr[3];        /* Reg Offset */
-       u32             n_dummy;        /* Dummy use */
-       u32             n_tx;           /* Number of tx bytes */
-       u8              *tx_buf;        /* Tx buf */
-       u32             n_rx;           /* Number of rx bytes */
-       u8              *rx_buf;        /* Rx buf */
-};
-
-int spinand_mtd(struct mtd_info *mtd);
-void spinand_mtd_release(struct mtd_info *mtd);
-
-#endif /* __LINUX_MTD_SPI_NAND_H */
index 257030460fb620dd848977c971c9a2df7c4fcec4..d3e23dd70c1b1ec75c73a850c759cd7288ac2db6 100644 (file)
@@ -279,7 +279,6 @@ static struct drm_driver driver = {
        .gem_free_object_unlocked = vbox_gem_free_object,
        .dumb_create = vbox_dumb_create,
        .dumb_map_offset = vbox_dumb_mmap_offset,
-       .dumb_destroy = drm_gem_dumb_destroy,
        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
        .gem_prime_export = drm_gem_prime_export,
index 73395a7536c5aecd8c62bc04634cb0afb4b418b6..fa933d4229518e230c09d7bed1935543b1b6de5b 100644 (file)
@@ -99,8 +99,6 @@ struct vbox_private {
        int fb_mtrr;
 
        struct {
-               struct drm_global_reference mem_global_ref;
-               struct ttm_bo_global_ref bo_global_ref;
                struct ttm_bo_device bdev;
        } ttm;
 
index 5ecfa76291733a5e01aca0edab6b7f6a40acdb94..b36ec019c33274bf4c8511b024bfeddd7965c980 100644 (file)
@@ -35,61 +35,6 @@ static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct vbox_private, ttm.bdev);
 }
 
-static int vbox_ttm_mem_global_init(struct drm_global_reference *ref)
-{
-       return ttm_mem_global_init(ref->object);
-}
-
-static void vbox_ttm_mem_global_release(struct drm_global_reference *ref)
-{
-       ttm_mem_global_release(ref->object);
-}
-
-/**
- * Adds the vbox memory manager object/structures to the global memory manager.
- */
-static int vbox_ttm_global_init(struct vbox_private *vbox)
-{
-       struct drm_global_reference *global_ref;
-       int ret;
-
-       global_ref = &vbox->ttm.mem_global_ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
-       global_ref->size = sizeof(struct ttm_mem_global);
-       global_ref->init = &vbox_ttm_mem_global_init;
-       global_ref->release = &vbox_ttm_mem_global_release;
-       ret = drm_global_item_ref(global_ref);
-       if (ret) {
-               DRM_ERROR("Failed setting up TTM memory subsystem.\n");
-               return ret;
-       }
-
-       vbox->ttm.bo_global_ref.mem_glob = vbox->ttm.mem_global_ref.object;
-       global_ref = &vbox->ttm.bo_global_ref.ref;
-       global_ref->global_type = DRM_GLOBAL_TTM_BO;
-       global_ref->size = sizeof(struct ttm_bo_global);
-       global_ref->init = &ttm_bo_global_init;
-       global_ref->release = &ttm_bo_global_release;
-
-       ret = drm_global_item_ref(global_ref);
-       if (ret) {
-               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(&vbox->ttm.mem_global_ref);
-               return ret;
-       }
-
-       return 0;
-}
-
-/**
- * Removes the vbox memory manager object from the global memory manager.
- */
-static void vbox_ttm_global_release(struct vbox_private *vbox)
-{
-       drm_global_item_unref(&vbox->ttm.bo_global_ref.ref);
-       drm_global_item_unref(&vbox->ttm.mem_global_ref);
-}
-
 static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo)
 {
        struct vbox_bo *bo;
@@ -227,18 +172,13 @@ int vbox_mm_init(struct vbox_private *vbox)
        struct drm_device *dev = &vbox->ddev;
        struct ttm_bo_device *bdev = &vbox->ttm.bdev;
 
-       ret = vbox_ttm_global_init(vbox);
-       if (ret)
-               return ret;
-
        ret = ttm_bo_device_init(&vbox->ttm.bdev,
-                                vbox->ttm.bo_global_ref.ref.object,
                                 &vbox_bo_driver,
                                 dev->anon_inode->i_mapping,
                                 DRM_FILE_PAGE_OFFSET, true);
        if (ret) {
                DRM_ERROR("Error initialising bo driver; %d\n", ret);
-               goto err_ttm_global_release;
+               return ret;
        }
 
        ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
@@ -260,8 +200,6 @@ int vbox_mm_init(struct vbox_private *vbox)
 
 err_device_release:
        ttm_bo_device_release(&vbox->ttm.bdev);
-err_ttm_global_release:
-       vbox_ttm_global_release(vbox);
        return ret;
 }
 
@@ -275,7 +213,6 @@ void vbox_mm_fini(struct vbox_private *vbox)
        arch_phys_wc_del(vbox->fb_mtrr);
 #endif
        ttm_bo_device_release(&vbox->ttm.bdev);
-       vbox_ttm_global_release(vbox);
 }
 
 void vbox_ttm_placement(struct vbox_bo *bo, int domain)
index 71888b979ab5defd3de444cfa1b6e34321b8813c..b19c960d549079b287ebe965acfb08b2eeef11fd 100644 (file)
@@ -641,8 +641,11 @@ static void cxgbit_send_halfclose(struct cxgbit_sock *csk)
 
 static void cxgbit_arp_failure_discard(void *handle, struct sk_buff *skb)
 {
+       struct cxgbit_sock *csk = handle;
+
        pr_debug("%s cxgbit_device %p\n", __func__, handle);
        kfree_skb(skb);
+       cxgbit_put_csk(csk);
 }
 
 static void cxgbit_abort_arp_failure(void *handle, struct sk_buff *skb)
@@ -1206,7 +1209,7 @@ cxgbit_pass_accept_rpl(struct cxgbit_sock *csk, struct cpl_pass_accept_req *req)
        rpl5->opt0 = cpu_to_be64(opt0);
        rpl5->opt2 = cpu_to_be32(opt2);
        set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->ctrlq_idx);
-       t4_set_arp_err_handler(skb, NULL, cxgbit_arp_failure_discard);
+       t4_set_arp_err_handler(skb, csk, cxgbit_arp_failure_discard);
        cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
 }
 
index f3f8856bfb68e8446ad19a0bf8156217f42cacab..c011c826fc26d70c523c82e3f6c0cbc152e15c6e 100644 (file)
@@ -58,6 +58,7 @@ static void *cxgbit_uld_add(const struct cxgb4_lld_info *lldi)
                return ERR_PTR(-ENOMEM);
 
        kref_init(&cdev->kref);
+       spin_lock_init(&cdev->np_lock);
 
        cdev->lldi = *lldi;
 
index f776b3eafb9619578986f2c0a3b0234fc2842067..3f779d25ec0cdfa10575b153b62dc34c0c5b218b 100644 (file)
@@ -552,30 +552,11 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
  */
 static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
-       unsigned char fcr;
-       unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
-
        if (p->capabilities & UART_CAP_FIFO) {
-               /*
-                * Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
-                * In case ENABLE_FIFO is not set, there is nothing to flush
-                * so just return. Furthermore, on certain implementations of
-                * the 8250 core, the FCR[7:3] bits may only be changed under
-                * specific conditions and changing them if those conditions
-                * are not met can have nasty side effects. One such core is
-                * the 8250-omap present in TI AM335x.
-                */
-               fcr = serial_in(p, UART_FCR);
-
-               /* FIFO is not enabled, there's nothing to clear. */
-               if (!(fcr & UART_FCR_ENABLE_FIFO))
-                       return;
-
-               fcr |= clr_mask;
-               serial_out(p, UART_FCR, fcr);
-
-               fcr &= ~clr_mask;
-               serial_out(p, UART_FCR, fcr);
+               serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
+               serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
+                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+               serial_out(p, UART_FCR, 0);
        }
 }
 
@@ -1467,7 +1448,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
         * Enable previously disabled RX interrupts.
         */
        if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
-               serial8250_clear_fifos(p);
+               serial8250_clear_and_reinit_fifos(p);
 
                p->ier |= UART_IER_RLSI | UART_IER_RDI;
                serial_port_out(&p->port, UART_IER, p->ier);
index 6cf3e9b0728f83d0c7b7adae94bcf45fea694066..3e77475668c02d25f88feaa9e95eb7e789ef8a46 100644 (file)
@@ -1394,22 +1394,43 @@ static inline struct console *SUNSU_CONSOLE(void)
 static enum su_type su_get_type(struct device_node *dp)
 {
        struct device_node *ap = of_find_node_by_path("/aliases");
+       enum su_type rc = SU_PORT_PORT;
 
        if (ap) {
                const char *keyb = of_get_property(ap, "keyboard", NULL);
                const char *ms = of_get_property(ap, "mouse", NULL);
+               struct device_node *match;
 
                if (keyb) {
-                       if (dp == of_find_node_by_path(keyb))
-                               return SU_PORT_KBD;
+                       match = of_find_node_by_path(keyb);
+
+                       /*
+                        * The pointer is used as an identifier not
+                        * as a pointer, we can drop the refcount on
+                        * the of__node immediately after getting it.
+                        */
+                       of_node_put(match);
+
+                       if (dp == match) {
+                               rc = SU_PORT_KBD;
+                               goto out;
+                       }
                }
                if (ms) {
-                       if (dp == of_find_node_by_path(ms))
-                               return SU_PORT_MS;
+                       match = of_find_node_by_path(ms);
+
+                       of_node_put(match);
+
+                       if (dp == match) {
+                               rc = SU_PORT_MS;
+                               goto out;
+                       }
                }
        }
 
-       return SU_PORT_PORT;
+out:
+       of_node_put(ap);
+       return rc;
 }
 
 static int su_probe(struct platform_device *op)
index c2493d0112257798d3b50660e2ae4e1fbcef37f8..3c5169eb23f5c7069cf1fbd35dc0c929a1c51c58 100644 (file)
@@ -204,9 +204,11 @@ hv_uio_open(struct uio_info *info, struct inode *inode)
        if (atomic_inc_return(&pdata->refcnt) != 1)
                return 0;
 
+       vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind);
+       vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel);
+
        ret = vmbus_connect_ring(dev->channel,
                                 hv_uio_channel_cb, dev->channel);
-
        if (ret == 0)
                dev->channel->inbound.ring_buffer->interrupt_mask = 1;
        else
@@ -334,9 +336,6 @@ hv_uio_probe(struct hv_device *dev,
                goto fail_close;
        }
 
-       vmbus_set_chn_rescind_callback(channel, hv_uio_rescind);
-       vmbus_set_sc_create_callback(channel, hv_uio_new_channel);
-
        ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr);
        if (ret)
                dev_notice(&dev->device,
index 94aca1b5ac8a228b6ecb690f84441f37c976fbdb..01b5818a4be5dceba4ba7dea73c285867b6fb773 100644 (file)
@@ -1507,7 +1507,8 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                portsc_buf[port_index] = 0;
 
                /* Bail out if a USB3 port has a new device in link training */
-               if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) {
+               if ((hcd->speed >= HCD_USB3) &&
+                   (t1 & PORT_PLS_MASK) == XDEV_POLLING) {
                        bus_state->bus_suspended = 0;
                        spin_unlock_irqrestore(&xhci->lock, flags);
                        xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
index c3515bad5dbbad26efcc71f89fdd64cc28911329..011dd45f871815915a3b9a9c09cd80238c0e5430 100644 (file)
@@ -1863,6 +1863,8 @@ struct xhci_hcd {
        unsigned                sw_lpm_support:1;
        /* support xHCI 1.0 spec USB2 hardware LPM */
        unsigned                hw_lpm_support:1;
+       /* Broken Suspend flag for SNPS Suspend resume issue */
+       unsigned                broken_suspend:1;
        /* cached usb2 extened protocol capabilites */
        u32                     *ext_caps;
        unsigned int            num_ext_caps;
@@ -1880,8 +1882,6 @@ struct xhci_hcd {
        void                    *dbc;
        /* platform-specific data -- must come last */
        unsigned long           priv[0] __aligned(sizeof(s64));
-       /* Broken Suspend flag for SNPS Suspend resume issue */
-       u8                      broken_suspend;
 };
 
 /* Platform specific overrides to generic XHCI hc_driver ops */
index e24ff16d4147754b382595dc401fa79bf815ac6b..1ce27f3ff7a78771d1c8037de8de604020de0f1f 100644 (file)
@@ -1164,6 +1164,10 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
          .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+       { USB_DEVICE(TELIT_VENDOR_ID, 0x1900),                          /* Telit LN940 (QMI) */
+         .driver_info = NCTRL(0) | RSVD(1) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff),    /* Telit LN940 (MBIM) */
+         .driver_info = NCTRL(0) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) },
@@ -1328,6 +1332,7 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(4) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) },    /* GosunCn ZTE WeLink ME3630 (MBIM mode) */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
          .driver_info = RSVD(4) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
@@ -1531,6 +1536,7 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(2) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff),  /* Telewell TW-LTE 4G v2 */
          .driver_info = RSVD(2) },
+       { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) },    /* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
@@ -1758,6 +1764,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
        { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E),
          .driver_info = RSVD(5) | RSVD(6) },
+       { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) },   /* Simcom SIM7500/SIM7600 MBIM mode */
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
          .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
@@ -1940,7 +1947,14 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) }, /* HP lt2523 (Novatel E371) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) },    /* HP lt2523 (Novatel E371) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x10) },    /* HP lt4132 (Huawei ME906s-158) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x12) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) },
+       { USB_DEVICE(0x1508, 0x1001),                                           /* Fibocom NL668 */
+         .driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index c84c8c189e902857e3272769c940836ff9464b17..1c0033ad87382d6c28742719bc17f341dc56ea85 100644 (file)
@@ -501,19 +501,19 @@ static int tps6598x_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct acpi_device_id tps6598x_acpi_match[] = {
-       { "INT3515", 0 },
+static const struct i2c_device_id tps6598x_id[] = {
+       { "tps6598x" },
        { }
 };
-MODULE_DEVICE_TABLE(acpi, tps6598x_acpi_match);
+MODULE_DEVICE_TABLE(i2c, tps6598x_id);
 
 static struct i2c_driver tps6598x_i2c_driver = {
        .driver = {
                .name = "tps6598x",
-               .acpi_match_table = tps6598x_acpi_match,
        },
        .probe_new = tps6598x_probe,
        .remove = tps6598x_remove,
+       .id_table = tps6598x_id,
 };
 module_i2c_driver(tps6598x_i2c_driver);
 
index ab11b2bee2739f261790559237f8848cd3eb0174..ad7a6f475a442a9b08843f77708729b3e123317b 100644 (file)
@@ -513,7 +513,13 @@ static void vhost_net_busy_poll(struct vhost_net *net,
        struct socket *sock;
        struct vhost_virtqueue *vq = poll_rx ? tvq : rvq;
 
-       mutex_lock_nested(&vq->mutex, poll_rx ? VHOST_NET_VQ_TX: VHOST_NET_VQ_RX);
+       /* Try to hold the vq mutex of the paired virtqueue. We can't
+        * use mutex_lock() here since we could not guarantee a
+        * consistenet lock ordering.
+        */
+       if (!mutex_trylock(&vq->mutex))
+               return;
+
        vhost_disable_notify(&net->dev, vq);
        sock = rvq->private_data;
 
index 6b98d8e3a5bf8247784303ce890a990fb8ec1259..55e5aa662ad59d4b72c44db743198876654f2d2d 100644 (file)
@@ -295,11 +295,8 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
 {
        int i;
 
-       for (i = 0; i < d->nvqs; ++i) {
-               mutex_lock(&d->vqs[i]->mutex);
+       for (i = 0; i < d->nvqs; ++i)
                __vhost_vq_meta_reset(d->vqs[i]);
-               mutex_unlock(&d->vqs[i]->mutex);
-       }
 }
 
 static void vhost_vq_reset(struct vhost_dev *dev,
@@ -895,6 +892,20 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
 #define vhost_get_used(vq, x, ptr) \
        vhost_get_user(vq, x, ptr, VHOST_ADDR_USED)
 
+static void vhost_dev_lock_vqs(struct vhost_dev *d)
+{
+       int i = 0;
+       for (i = 0; i < d->nvqs; ++i)
+               mutex_lock_nested(&d->vqs[i]->mutex, i);
+}
+
+static void vhost_dev_unlock_vqs(struct vhost_dev *d)
+{
+       int i = 0;
+       for (i = 0; i < d->nvqs; ++i)
+               mutex_unlock(&d->vqs[i]->mutex);
+}
+
 static int vhost_new_umem_range(struct vhost_umem *umem,
                                u64 start, u64 size, u64 end,
                                u64 userspace_addr, int perm)
@@ -976,6 +987,7 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
        int ret = 0;
 
        mutex_lock(&dev->mutex);
+       vhost_dev_lock_vqs(dev);
        switch (msg->type) {
        case VHOST_IOTLB_UPDATE:
                if (!dev->iotlb) {
@@ -1009,6 +1021,7 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
                break;
        }
 
+       vhost_dev_unlock_vqs(dev);
        mutex_unlock(&dev->mutex);
 
        return ret;
@@ -2220,6 +2233,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
                return -EFAULT;
        }
        if (unlikely(vq->log_used)) {
+               /* Make sure used idx is seen before log. */
+               smp_wmb();
                /* Log used index update. */
                log_write(vq->log_base,
                          vq->log_addr + offsetof(struct vring_used, idx),
index 8a3e8f61b991bd7fb14a5552eed46a56c88a1d6a..799ae49774f58e1e00e70cd9fe188f39bf9b08a5 100644 (file)
@@ -31,7 +31,7 @@
 
 #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
 
-static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
 {
        u8 csum = 0;
        size_t i;
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+       if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+           frame->version != 2 ||
+           frame->length != HDMI_AVI_INFOFRAME_SIZE)
+               return -EINVAL;
+
+       if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+       return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-                               size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+                                    void *buffer, size_t size)
 {
        u8 *ptr = buffer;
        size_t length;
+       int ret;
+
+       ret = hdmi_avi_infoframe_check_only(frame);
+       if (ret)
+               return ret;
 
        length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
        if (size < length)
                return -ENOSPC;
 
-       if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-               return -EINVAL;
-
        memset(buffer, 0, size);
 
        ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
        return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+                               void *buffer, size_t size)
+{
+       int ret;
+
+       ret = hdmi_avi_infoframe_check(frame);
+       if (ret)
+               return ret;
+
+       return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+       if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+           frame->version != 1 ||
+           frame->length != HDMI_SPD_INFOFRAME_SIZE)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+       return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-                               size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+                                    void *buffer, size_t size)
 {
        u8 *ptr = buffer;
        size_t length;
+       int ret;
+
+       ret = hdmi_spd_infoframe_check_only(frame);
+       if (ret)
+               return ret;
 
        length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
        return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+                               void *buffer, size_t size)
+{
+       int ret;
+
+       ret = hdmi_spd_infoframe_check(frame);
+       if (ret)
+               return ret;
+
+       return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+       if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+           frame->version != 1 ||
+           frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+       return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
+/**
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-                                 void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+                                      void *buffer, size_t size)
 {
        unsigned char channels;
        u8 *ptr = buffer;
        size_t length;
+       int ret;
+
+       ret = hdmi_audio_infoframe_check_only(frame);
+       if (ret)
+               return ret;
 
        length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
        return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+                                 void *buffer, size_t size)
+{
+       int ret;
+
+       ret = hdmi_audio_infoframe_check(frame);
+       if (ret)
+               return ret;
+
+       return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
         * value
         */
        frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+       frame->length = 4;
 
        return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
                return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+       if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+           frame->version != 1 ||
+           frame->oui != HDMI_IEEE_OUI)
+               return -EINVAL;
+
+       /* only one of those can be supplied */
+       if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+               return -EINVAL;
+
+       if (frame->length != hdmi_vendor_infoframe_length(frame))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+       frame->length = hdmi_vendor_infoframe_length(frame);
+
+       return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-                                void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+                                       void *buffer, size_t size)
 {
        u8 *ptr = buffer;
        size_t length;
+       int ret;
 
-       /* only one of those can be supplied */
-       if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-               return -EINVAL;
-
-       frame->length = hdmi_vendor_infoframe_length(frame);
+       ret = hdmi_vendor_infoframe_check_only(frame);
+       if (ret)
+               return ret;
 
        length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
        return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+                                  void *buffer, size_t size)
+{
+       int ret;
+
+       ret = hdmi_vendor_infoframe_check(frame);
+       if (ret)
+               return ret;
+
+       return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+       if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+           frame->any.version != 1)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+       int ret;
+
+       ret = hdmi_vendor_any_infoframe_check_only(frame);
+       if (ret)
+               return ret;
+
+       /* we only know about HDMI vendor infoframes */
+       if (frame->any.oui != HDMI_IEEE_OUI)
+               return -EINVAL;
+
+       return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-                          void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+                                   void *buffer, size_t size)
 {
+       int ret;
+
+       ret = hdmi_vendor_any_infoframe_check_only(frame);
+       if (ret)
+               return ret;
+
        /* we only know about HDMI vendor infoframes */
        if (frame->any.oui != HDMI_IEEE_OUI)
                return -EINVAL;
 
-       return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+       return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ *                                    and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+                              void *buffer, size_t size)
+{
+       int ret;
+
+       ret = hdmi_vendor_any_infoframe_check(frame);
+       if (ret)
+               return ret;
+
+       return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+       switch (frame->any.type) {
+       case HDMI_INFOFRAME_TYPE_AVI:
+               return hdmi_avi_infoframe_check(&frame->avi);
+       case HDMI_INFOFRAME_TYPE_SPD:
+               return hdmi_spd_infoframe_check(&frame->spd);
+       case HDMI_INFOFRAME_TYPE_AUDIO:
+               return hdmi_audio_infoframe_check(&frame->audio);
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               return hdmi_vendor_any_infoframe_check(&frame->vendor);
+       default:
+               WARN(1, "Bad infoframe type %d\n", frame->any.type);
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(hdmi_infoframe_check);
+
+/**
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+       ssize_t length;
+
+       switch (frame->any.type) {
+       case HDMI_INFOFRAME_TYPE_AVI:
+               length = hdmi_avi_infoframe_pack_only(&frame->avi,
+                                                     buffer, size);
+               break;
+       case HDMI_INFOFRAME_TYPE_SPD:
+               length = hdmi_spd_infoframe_pack_only(&frame->spd,
+                                                     buffer, size);
+               break;
+       case HDMI_INFOFRAME_TYPE_AUDIO:
+               length = hdmi_audio_infoframe_pack_only(&frame->audio,
+                                                       buffer, size);
+               break;
+       case HDMI_INFOFRAME_TYPE_VENDOR:
+               length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+                                                            buffer, size);
+               break;
+       default:
+               WARN(1, "Bad infoframe type %d\n", frame->any.type);
+               length = -EINVAL;
+       }
+
+       return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+                   void *buffer, size_t size)
 {
        ssize_t length;
 
@@ -471,7 +844,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 
 static void hdmi_infoframe_log_header(const char *level,
                                      struct device *dev,
-                                     struct hdmi_any_infoframe *frame)
+                                     const struct hdmi_any_infoframe *frame)
 {
        hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
                hdmi_infoframe_type_get_name(frame->type),
@@ -673,10 +1046,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
  */
 static void hdmi_avi_infoframe_log(const char *level,
                                   struct device *dev,
-                                  struct hdmi_avi_infoframe *frame)
+                                  const struct hdmi_avi_infoframe *frame)
 {
        hdmi_infoframe_log_header(level, dev,
-                                 (struct hdmi_any_infoframe *)frame);
+                                 (const struct hdmi_any_infoframe *)frame);
 
        hdmi_log("    colorspace: %s\n",
                        hdmi_colorspace_get_name(frame->colorspace));
@@ -750,12 +1123,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
  */
 static void hdmi_spd_infoframe_log(const char *level,
                                   struct device *dev,
-                                  struct hdmi_spd_infoframe *frame)
+                                  const struct hdmi_spd_infoframe *frame)
 {
        u8 buf[17];
 
        hdmi_infoframe_log_header(level, dev,
-                                 (struct hdmi_any_infoframe *)frame);
+                                 (const struct hdmi_any_infoframe *)frame);
 
        memset(buf, 0, sizeof(buf));
 
@@ -886,10 +1259,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
  */
 static void hdmi_audio_infoframe_log(const char *level,
                                     struct device *dev,
-                                    struct hdmi_audio_infoframe *frame)
+                                    const struct hdmi_audio_infoframe *frame)
 {
        hdmi_infoframe_log_header(level, dev,
-                                 (struct hdmi_any_infoframe *)frame);
+                                 (const struct hdmi_any_infoframe *)frame);
 
        if (frame->channels)
                hdmi_log("    channels: %u\n", frame->channels - 1);
@@ -949,12 +1322,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
 static void
 hdmi_vendor_any_infoframe_log(const char *level,
                              struct device *dev,
-                             union hdmi_vendor_any_infoframe *frame)
+                             const union hdmi_vendor_any_infoframe *frame)
 {
-       struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+       const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
        hdmi_infoframe_log_header(level, dev,
-                                 (struct hdmi_any_infoframe *)frame);
+                                 (const struct hdmi_any_infoframe *)frame);
 
        if (frame->any.oui != HDMI_IEEE_OUI) {
                hdmi_log("    not a HDMI vendor infoframe\n");
@@ -984,7 +1357,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
  */
 void hdmi_infoframe_log(const char *level,
                        struct device *dev,
-                       union hdmi_infoframe *frame)
+                       const union hdmi_infoframe *frame)
 {
        switch (frame->any.type) {
        case HDMI_INFOFRAME_TYPE_AVI:
@@ -1005,8 +1378,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
 
 /**
  * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
- * @buffer: source buffer
  * @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Auxiliary Video (AVI) information frame.
@@ -1016,11 +1390,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-                                    void *buffer)
+                                    const void *buffer, size_t size)
 {
-       u8 *ptr = buffer;
+       const u8 *ptr = buffer;
        int ret;
 
+       if (size < HDMI_INFOFRAME_SIZE(AVI))
+               return -EINVAL;
+
        if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
            ptr[1] != 2 ||
            ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
@@ -1068,8 +1445,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
 
 /**
  * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
- * @buffer: source buffer
  * @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Source Product Description (SPD) information frame.
@@ -1079,11 +1457,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-                                    void *buffer)
+                                    const void *buffer, size_t size)
 {
-       u8 *ptr = buffer;
+       const u8 *ptr = buffer;
        int ret;
 
+       if (size < HDMI_INFOFRAME_SIZE(SPD))
+               return -EINVAL;
+
        if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
            ptr[1] != 1 ||
            ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
@@ -1106,8 +1487,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
 
 /**
  * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
- * @buffer: source buffer
  * @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Audio information frame.
@@ -1117,11 +1499,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-                                      void *buffer)
+                                      const void *buffer, size_t size)
 {
-       u8 *ptr = buffer;
+       const u8 *ptr = buffer;
        int ret;
 
+       if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+               return -EINVAL;
+
        if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
            ptr[1] != 1 ||
            ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
@@ -1151,8 +1536,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
 
 /**
  * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
- * @buffer: source buffer
  * @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Vendor information frame.
@@ -1163,14 +1549,17 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-                                void *buffer)
+                                const void *buffer, size_t size)
 {
-       u8 *ptr = buffer;
+       const u8 *ptr = buffer;
        size_t length;
        int ret;
        u8 hdmi_video_format;
        struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
+       if (size < HDMI_INFOFRAME_HEADER_SIZE)
+               return -EINVAL;
+
        if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
            ptr[1] != 1 ||
            (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
@@ -1178,6 +1567,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
        length = ptr[2];
 
+       if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+               return -EINVAL;
+
        if (hdmi_infoframe_checksum(buffer,
                                    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
                return -EINVAL;
@@ -1224,8 +1616,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
- * @buffer: source buffer
  * @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary buffer @buffer into a structured
  * @frame of a HDMI infoframe.
@@ -1234,23 +1627,27 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  *
  * Returns 0 on success or a negative error code on failure.
  */
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+                         const void *buffer, size_t size)
 {
        int ret;
-       u8 *ptr = buffer;
+       const u8 *ptr = buffer;
+
+       if (size < HDMI_INFOFRAME_HEADER_SIZE)
+               return -EINVAL;
 
        switch (ptr[0]) {
        case HDMI_INFOFRAME_TYPE_AVI:
-               ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+               ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
                break;
        case HDMI_INFOFRAME_TYPE_SPD:
-               ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+               ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
                break;
        case HDMI_INFOFRAME_TYPE_AUDIO:
-               ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+               ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
                break;
        case HDMI_INFOFRAME_TYPE_VENDOR:
-               ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+               ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
                break;
        default:
                ret = -EINVAL;
index 9e7ef7ec2d70f0d84002dbfed141fa325d20ad8d..a8999f930b224ec6d6af2d74479270a43a000f56 100644 (file)
@@ -97,7 +97,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                goto finished;
 
-       smb2_set_next_command(server, &rqst[num_rqst++]);
+       smb2_set_next_command(server, &rqst[num_rqst++], 0);
 
        /* Operation */
        switch (command) {
@@ -111,7 +111,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                SMB2_O_INFO_FILE, 0,
                                sizeof(struct smb2_file_all_info) +
                                          PATH_MAX * 2, 0, NULL);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 0);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_DELETE:
@@ -127,14 +127,14 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                rqst[num_rqst].rq_iov = si_iov;
                rqst[num_rqst].rq_nvec = 1;
 
-               size[0] = 8;
+               size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
                data[0] = &delete_pending[0];
 
                rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
                                        COMPOUND_FID, current->tgid,
                                        FILE_DISPOSITION_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 1);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_SET_EOF:
@@ -149,7 +149,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_END_OF_FILE_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 0);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_SET_INFO:
@@ -165,7 +165,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_BASIC_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 0);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_RENAME:
@@ -189,7 +189,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_RENAME_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 0);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_HARDLINK:
@@ -213,7 +213,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_LINK_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_next_command(server, &rqst[num_rqst], 0);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        default:
index 225fec1cfa673360d794058e5acb1d5737acdd32..e25c7aade98a41e2b6c6268239d31e33648cac05 100644 (file)
@@ -1194,7 +1194,7 @@ smb2_ioctl_query_info(const unsigned int xid,
        rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
        if (rc)
                goto iqinf_exit;
-       smb2_set_next_command(ses->server, &rqst[0]);
+       smb2_set_next_command(ses->server, &rqst[0], 0);
 
        /* Query */
        memset(&qi_iov, 0, sizeof(qi_iov));
@@ -1208,7 +1208,7 @@ smb2_ioctl_query_info(const unsigned int xid,
                                  qi.output_buffer_length, buffer);
        if (rc)
                goto iqinf_exit;
-       smb2_set_next_command(ses->server, &rqst[1]);
+       smb2_set_next_command(ses->server, &rqst[1], 0);
        smb2_set_related(&rqst[1]);
 
        /* Close */
@@ -1761,16 +1761,23 @@ smb2_set_related(struct smb_rqst *rqst)
 char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
 
 void
-smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+                     bool has_space_for_padding)
 {
        struct smb2_sync_hdr *shdr;
        unsigned long len = smb_rqst_len(server, rqst);
 
        /* SMB headers in a compound are 8 byte aligned. */
        if (len & 7) {
-               rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
-               rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
-               rqst->rq_nvec++;
+               if (has_space_for_padding) {
+                       len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len;
+                       rqst->rq_iov[rqst->rq_nvec - 1].iov_len =
+                               (len + 7) & ~7;
+               } else {
+                       rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
+                       rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
+                       rqst->rq_nvec++;
+               }
                len = smb_rqst_len(server, rqst);
        }
 
@@ -1820,7 +1827,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
        rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path);
        if (rc)
                goto qfs_exit;
-       smb2_set_next_command(server, &rqst[0]);
+       smb2_set_next_command(server, &rqst[0], 0);
 
        memset(&qi_iov, 0, sizeof(qi_iov));
        rqst[1].rq_iov = qi_iov;
@@ -1833,7 +1840,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
                                  NULL);
        if (rc)
                goto qfs_exit;
-       smb2_set_next_command(server, &rqst[1]);
+       smb2_set_next_command(server, &rqst[1], 0);
        smb2_set_related(&rqst[1]);
 
        memset(&close_iov, 0, sizeof(close_iov));
index 9f4e9ed9ce53c23899e345d634b58c6e771253e2..2fe78acd7d0c14444a3372e3dbed6800b8bbc33f 100644 (file)
@@ -117,7 +117,8 @@ extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
                                  struct smb_rqst *rqst);
 extern void smb2_set_next_command(struct TCP_Server_Info *server,
-                                 struct smb_rqst *rqst);
+                                 struct smb_rqst *rqst,
+                                 bool has_space_for_padding);
 extern void smb2_set_related(struct smb_rqst *rqst);
 
 /*
index 5bc172f3dfe8c8f8600622cc66754406cdb3b3bf..d6bc98ae8d3503870c1c23f8fe1277cdb4476d85 100644 (file)
@@ -116,12 +116,6 @@ iomap_page_create(struct inode *inode, struct page *page)
        atomic_set(&iop->read_count, 0);
        atomic_set(&iop->write_count, 0);
        bitmap_zero(iop->uptodate, PAGE_SIZE / SECTOR_SIZE);
-
-       /*
-        * migrate_page_move_mapping() assumes that pages with private data have
-        * their count elevated by 1.
-        */
-       get_page(page);
        set_page_private(page, (unsigned long)iop);
        SetPagePrivate(page);
        return iop;
@@ -138,7 +132,6 @@ iomap_page_release(struct page *page)
        WARN_ON_ONCE(atomic_read(&iop->write_count));
        ClearPagePrivate(page);
        set_page_private(page, 0);
-       put_page(page);
        kfree(iop);
 }
 
index 902a7dd10e5c45fbc496cfbb4a9c39f1ca4bb417..bb6ae387469f4d020424bfb13333e24d84e68123 100644 (file)
@@ -101,7 +101,8 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
        struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-       cancel_delayed_work_sync(&c->wbuf_dwork);
+       if (jffs2_is_writebuffered(c))
+               cancel_delayed_work_sync(&c->wbuf_dwork);
 #endif
 
        mutex_lock(&c->alloc_sem);
index 0cab6494978c1295b965f503422bdbeacff6ccc4..914178cdbe94b45c1c14040733eb67cdbcf4bc55 100644 (file)
@@ -3701,8 +3701,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
        if (error)
                return error;
 
-       if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
-           !ns_capable(dentry->d_sb->s_user_ns, CAP_MKNOD))
+       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
                return -EPERM;
 
        if (!dir->i_op->mknod)
index 89921a0d2ebbcb9b31c361a7b5972480771cf5ad..4d598a399bbff1b32becb1cf24406f9b9e80287c 100644 (file)
@@ -464,7 +464,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 
        inode = new_inode(sb);
        if (!inode)
-               goto out;
+               return ERR_PTR(-ENOMEM);
 
        inode->i_ino = get_next_ino();
 
@@ -474,8 +474,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
        if (unlikely(head->unregistering)) {
                spin_unlock(&sysctl_lock);
                iput(inode);
-               inode = NULL;
-               goto out;
+               return ERR_PTR(-ENOENT);
        }
        ei->sysctl = head;
        ei->sysctl_entry = table;
@@ -500,7 +499,6 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
        if (root->set_ownership)
                root->set_ownership(head, table, &inode->i_uid, &inode->i_gid);
 
-out:
        return inode;
 }
 
@@ -549,10 +547,11 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
                        goto out;
        }
 
-       err = ERR_PTR(-ENOMEM);
        inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
-       if (!inode)
+       if (IS_ERR(inode)) {
+               err = ERR_CAST(inode);
                goto out;
+       }
 
        d_set_d_op(dentry, &proc_sys_dentry_operations);
        err = d_splice_alias(inode, dentry);
@@ -685,7 +684,7 @@ static bool proc_sys_fill_cache(struct file *file,
                if (d_in_lookup(child)) {
                        struct dentry *res;
                        inode = proc_sys_make_inode(dir->d_sb, head, table);
-                       if (!inode) {
+                       if (IS_ERR(inode)) {
                                d_lookup_done(child);
                                dput(child);
                                return false;
index 0a7252aecfa534fea4bcb9a570dc4db2b134b44f..bb71db63c99cade1f6c7e29e19b9475b5422d801 100644 (file)
@@ -334,7 +334,7 @@ int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
 }
 EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
 
-int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
+int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
 {
        int err = 0;
        int i;
@@ -493,7 +493,7 @@ bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
        return ret;
 }
 
-void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr)
+void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
 {
        int i;
        for (i = 0; ptr[i]; i++)
index 529856fbccd0ee5f6559519a3d9db12cf932a775..bc1e082d921d152a6df154378320ff4e5f3bce94 100644 (file)
@@ -12,9 +12,10 @@ config UBIFS_FS
        help
          UBIFS is a file system for flash devices which works on top of UBI.
 
+if UBIFS_FS
+
 config UBIFS_FS_ADVANCED_COMPR
        bool "Advanced compression options"
-       depends on UBIFS_FS
        help
          This option allows to explicitly choose which compressions, if any,
          are enabled in UBIFS. Removing compressors means inability to read
@@ -24,7 +25,6 @@ config UBIFS_FS_ADVANCED_COMPR
 
 config UBIFS_FS_LZO
        bool "LZO compression support" if UBIFS_FS_ADVANCED_COMPR
-       depends on UBIFS_FS
        default y
        help
           LZO compressor is generally faster than zlib but compresses worse.
@@ -32,14 +32,12 @@ config UBIFS_FS_LZO
 
 config UBIFS_FS_ZLIB
        bool "ZLIB compression support" if UBIFS_FS_ADVANCED_COMPR
-       depends on UBIFS_FS
        default y
        help
          Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
 
 config UBIFS_ATIME_SUPPORT
-       bool "Access time support" if UBIFS_FS
-       depends on UBIFS_FS
+       bool "Access time support"
        default n
        help
          Originally UBIFS did not support atime, because it looked like a bad idea due
@@ -54,7 +52,6 @@ config UBIFS_ATIME_SUPPORT
 
 config UBIFS_FS_XATTR
        bool "UBIFS XATTR support"
-       depends on UBIFS_FS
        default y
        help
          Saying Y here includes support for extended attributes (xattrs).
@@ -65,7 +62,7 @@ config UBIFS_FS_XATTR
 
 config UBIFS_FS_ENCRYPTION
        bool "UBIFS Encryption"
-       depends on UBIFS_FS && UBIFS_FS_XATTR && BLOCK
+       depends on UBIFS_FS_XATTR && BLOCK
        select FS_ENCRYPTION
        default n
        help
@@ -76,7 +73,7 @@ config UBIFS_FS_ENCRYPTION
 
 config UBIFS_FS_SECURITY
        bool "UBIFS Security Labels"
-       depends on UBIFS_FS && UBIFS_FS_XATTR
+       depends on UBIFS_FS_XATTR
        default y
        help
          Security labels provide an access control facility to support Linux
@@ -89,6 +86,7 @@ config UBIFS_FS_SECURITY
 
 config UBIFS_FS_AUTHENTICATION
        bool "UBIFS authentication support"
+       depends on KEYS
        select CRYPTO_HMAC
        help
          Enable authentication support for UBIFS. This feature offers protection
@@ -96,3 +94,5 @@ config UBIFS_FS_AUTHENTICATION
          If you say yes here you should also select a hashing algorithm such as
          sha256, these are not selected automatically since there are many
          different options.
+
+endif # UBIFS_FS
index d1d5e96350ddbd0ff549941655b0e4d8e089beef..b0c5f06128b5385cff7f8ca514f2c2a3f3296cb0 100644 (file)
@@ -1675,6 +1675,12 @@ int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)
        if (!ubifs_authenticated(c))
                return 0;
 
+       if (!c->nroot) {
+               err = ubifs_read_nnode(c, NULL, 0);
+               if (err)
+                       return err;
+       }
+
        desc = ubifs_hash_get_desc(c);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
@@ -1685,12 +1691,6 @@ int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)
                goto out;
        }
 
-       if (!c->nroot) {
-               err = ubifs_read_nnode(c, NULL, 0);
-               if (err)
-                       return err;
-       }
-
        cnode = (struct ubifs_cnode *)c->nroot;
 
        while (cnode) {
index 75f961c4c0449505aaac3f085aa80b00acb0b8ab..0a0e65c07c6d644e34b6816895ffe72023763108 100644 (file)
@@ -212,6 +212,38 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
        return ubifs_tnc_remove_range(c, &min_key, &max_key);
 }
 
+/**
+ * inode_still_linked - check whether inode in question will be re-linked.
+ * @c: UBIFS file-system description object
+ * @rino: replay entry to test
+ *
+ * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1.
+ * This case needs special care, otherwise all references to the inode will
+ * be removed upon the first replay entry of an inode with link count 0
+ * is found.
+ */
+static bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino)
+{
+       struct replay_entry *r;
+
+       ubifs_assert(c, rino->deletion);
+       ubifs_assert(c, key_type(c, &rino->key) == UBIFS_INO_KEY);
+
+       /*
+        * Find the most recent entry for the inode behind @rino and check
+        * whether it is a deletion.
+        */
+       list_for_each_entry_reverse(r, &c->replay_list, list) {
+               ubifs_assert(c, r->sqnum >= rino->sqnum);
+               if (key_inum(c, &r->key) == key_inum(c, &rino->key))
+                       return r->deletion == 0;
+
+       }
+
+       ubifs_assert(c, 0);
+       return false;
+}
+
 /**
  * apply_replay_entry - apply a replay entry to the TNC.
  * @c: UBIFS file-system description object
@@ -239,6 +271,11 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
                        {
                                ino_t inum = key_inum(c, &r->key);
 
+                               if (inode_still_linked(c, r)) {
+                                       err = 0;
+                                       break;
+                               }
+
                                err = ubifs_tnc_remove_ino(c, inum);
                                break;
                        }
@@ -533,6 +570,28 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
        return data == 0xFFFFFFFF;
 }
 
+/* authenticate_sleb_hash and authenticate_sleb_hmac are split out for stack usage */
+static int authenticate_sleb_hash(struct ubifs_info *c, struct shash_desc *log_hash, u8 *hash)
+{
+       SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
+
+       hash_desc->tfm = c->hash_tfm;
+       hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       ubifs_shash_copy_state(c, log_hash, hash_desc);
+       return crypto_shash_final(hash_desc, hash);
+}
+
+static int authenticate_sleb_hmac(struct ubifs_info *c, u8 *hash, u8 *hmac)
+{
+       SHASH_DESC_ON_STACK(hmac_desc, c->hmac_tfm);
+
+       hmac_desc->tfm = c->hmac_tfm;
+       hmac_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_shash_digest(hmac_desc, hash, c->hash_len, hmac);
+}
+
 /**
  * authenticate_sleb - authenticate one scan LEB
  * @c: UBIFS file-system description object
@@ -574,21 +633,12 @@ static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 
                if (snod->type == UBIFS_AUTH_NODE) {
                        struct ubifs_auth_node *auth = snod->node;
-                       SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
-                       SHASH_DESC_ON_STACK(hmac_desc, c->hmac_tfm);
-
-                       hash_desc->tfm = c->hash_tfm;
-                       hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
-                       ubifs_shash_copy_state(c, log_hash, hash_desc);
-                       err = crypto_shash_final(hash_desc, hash);
+                       err = authenticate_sleb_hash(c, log_hash, hash);
                        if (err)
                                goto out;
 
-                       hmac_desc->tfm = c->hmac_tfm;
-                       hmac_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-                       err = crypto_shash_digest(hmac_desc, hash, c->hash_len,
-                                                 hmac);
+                       err = authenticate_sleb_hmac(c, hash, hmac);
                        if (err)
                                goto out;
 
index 75a69dd26d6eafa609a01a2f9969c22c37512346..3da90c951c2354eafc32dcaeae1134b17a0573c1 100644 (file)
 /* Default time granularity in nanoseconds */
 #define DEFAULT_TIME_GRAN 1000000000
 
+static int get_default_compressor(struct ubifs_info *c)
+{
+       if (ubifs_compr_present(c, UBIFS_COMPR_LZO))
+               return UBIFS_COMPR_LZO;
+
+       if (ubifs_compr_present(c, UBIFS_COMPR_ZLIB))
+               return UBIFS_COMPR_ZLIB;
+
+       return UBIFS_COMPR_NONE;
+}
+
 /**
  * create_default_filesystem - format empty UBI volume.
  * @c: UBIFS file-system description object
@@ -207,7 +218,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        if (c->mount_opts.override_compr)
                sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
        else
-               sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
+               sup->default_compr = cpu_to_le16(get_default_compressor(c));
 
        generate_random_uuid(sup->uuid);
 
index 3a26aa7ead23c998dd335d60c5c171bc70defd1d..6db9a6d40c858df263f436a5a2071569e89ceefb 100644 (file)
@@ -73,7 +73,8 @@
 #define ACPI_LV_RESOURCES           0x00010000
 #define ACPI_LV_USER_REQUESTS       0x00020000
 #define ACPI_LV_PACKAGE             0x00040000
-#define ACPI_LV_VERBOSITY1          0x0007FF40 | ACPI_LV_ALL_EXCEPTIONS
+#define ACPI_LV_EVALUATION          0x00080000
+#define ACPI_LV_VERBOSITY1          0x000FFF40 | ACPI_LV_ALL_EXCEPTIONS
 
 /* Trace verbosity level 2 [Function tracing and memory allocation] */
 
 #define ACPI_DB_INTERRUPTS          ACPI_DEBUG_LEVEL (ACPI_LV_INTERRUPTS)
 #define ACPI_DB_USER_REQUESTS       ACPI_DEBUG_LEVEL (ACPI_LV_USER_REQUESTS)
 #define ACPI_DB_PACKAGE             ACPI_DEBUG_LEVEL (ACPI_LV_PACKAGE)
+#define ACPI_DB_EVALUATION          ACPI_DEBUG_LEVEL (ACPI_LV_EVALUATION)
 #define ACPI_DB_MUTEX               ACPI_DEBUG_LEVEL (ACPI_LV_MUTEX)
 #define ACPI_DB_EVENTS              ACPI_DEBUG_LEVEL (ACPI_LV_EVENTS)
 
 
 /* Defaults for debug_level, debug and normal */
 
-#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INFO | ACPI_LV_REPAIR)
+#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_EVALUATION | ACPI_LV_REPAIR)
 #define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR)
 #define ACPI_DEBUG_ALL              (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
 
index 14499757338f65416835330254b8c90a06918d64..de1804aeaf691f5dfb4c1beb55f1a86923045eff 100644 (file)
@@ -88,7 +88,14 @@ int acpi_pci_link_free_irq(acpi_handle handle);
 
 struct pci_bus;
 
+#ifdef CONFIG_PCI
 struct pci_dev *acpi_get_pci_dev(acpi_handle);
+#else
+static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
+{
+       return NULL;
+}
+#endif
 
 /* Arch-defined function to add a bus to the system */
 
index 0c19b68bf060b7d5ba033b85074550c69ead1e01..7aa38b648564fccaa4eaab082cf8e80e91dac8f5 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20181003
+#define ACPI_CA_VERSION                 0x20181213
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 517addd6b11de73de517e294e89f1a00215af7e4..0a977eca0a74693251ed606e4f3e2b6b1c7bd73d 100644 (file)
@@ -38,6 +38,7 @@
 #define ACPI_SIG_XSDT           "XSDT" /* Extended  System Description Table */
 #define ACPI_SIG_SSDT           "SSDT" /* Secondary System Description Table */
 #define ACPI_RSDP_NAME          "RSDP" /* Short name for RSDP, not signature */
+#define ACPI_OEM_NAME           "OEM"  /* Short name for OEM, not signature */
 
 /*
  * All tables and structures must be byte-packed to match the ACPI
index 501f341d1d922e0b6242aff049c1f8f4b3fb5eca..ea1ca49c9c1b3fef2fab92d09cd6089f773bdca4 100644 (file)
@@ -365,6 +365,29 @@ struct acpi_table_tcpa_server {
  *
  ******************************************************************************/
 
+/* Revision 3 */
+
+struct acpi_table_tpm23 {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 reserved;
+       u64 control_address;
+       u32 start_method;
+};
+
+/* Value for start_method above */
+
+#define ACPI_TPM23_ACPI_START_METHOD                 2
+
+/*
+ * Optional trailer for revision 3. If start method is 2, there is a 4 byte
+ * reserved area of all zeros.
+ */
+struct acpi_tmp23_trailer {
+       u32 reserved;
+};
+
+/* Revision 4 */
+
 struct acpi_table_tpm2 {
        struct acpi_table_header header;        /* Common ACPI table header */
        u16 platform_class;
index 66ceb12ebc63032a9f4af8a9da7db9ac04c83178..2590627dbfccdb2de2590b26dba5bfff11dabd9e 100644 (file)
@@ -527,6 +527,10 @@ typedef u64 acpi_integer;
 #define ACPI_VALIDATE_RSDP_SIG(a)       (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8))
 #define ACPI_MAKE_RSDP_SIG(dest)        (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8))
 
+/* Support for OEMx signature (x can be any character) */
+#define ACPI_IS_OEM_SIG(a)        (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_OEM_NAME, 3) &&\
+        strnlen (a, ACPI_NAME_SIZE) == ACPI_NAME_SIZE)
+
 /*
  * Algorithm to obtain access bit width.
  * Can be used with access_width of struct acpi_generic_address and access_size of
@@ -1273,6 +1277,8 @@ typedef enum {
 #define ACPI_OSI_WIN_10_RS1             0x0E
 #define ACPI_OSI_WIN_10_RS2             0x0F
 #define ACPI_OSI_WIN_10_RS3             0x10
+#define ACPI_OSI_WIN_10_RS4             0x11
+#define ACPI_OSI_WIN_10_RS5             0x12
 
 /* Definitions of getopt */
 
index 7451b3bca83a842bf9d632f1f4cd0898882daafe..e3d21d014fcc62ce1afbc0d76cc7400c6445daab 100644 (file)
 
 /* Kernel specific ACPICA configuration */
 
+#ifdef CONFIG_PCI
+#define ACPI_PCI_CONFIGURED
+#endif
+
 #ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
 #define ACPI_REDUCED_HARDWARE 1
 #endif
index cdafa5edea491ef01aedbeea78ee65c51bdb3417..20561a60db9c4f077c68ee1a182eac38ff96d4dd 100644 (file)
 #ifndef __ASSEMBLY__
 #include <linux/kernel.h>
 
-struct bug_entry {
+#ifdef CONFIG_BUG
+
 #ifdef CONFIG_GENERIC_BUG
+struct bug_entry {
 #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
        unsigned long   bug_addr;
 #else
@@ -33,10 +35,8 @@ struct bug_entry {
        unsigned short  line;
 #endif
        unsigned short  flags;
-#endif /* CONFIG_GENERIC_BUG */
 };
-
-#ifdef CONFIG_BUG
+#endif /* CONFIG_GENERIC_BUG */
 
 /*
  * Don't use BUG() or BUG_ON() unless there's really no way out; one
index ccb5aa8468e0bfe72be7e1759ae80e239ea2cb61..9c56412bb2cf2e0e3e64bb06306f17bfb76a362f 100644 (file)
@@ -133,6 +133,7 @@ struct dw_hdmi_plat_data {
        const struct dw_hdmi_phy_ops *phy_ops;
        const char *phy_name;
        void *phy_data;
+       unsigned int phy_force_vendor;
 
        /* Synopsys PHY support */
        const struct dw_hdmi_mpll_config *mpll_cfg;
index d9c6d549f9711ad7c9a3d484ad606a70590ce135..48a671e782cafd6ec3ef405f615802c187733ff5 100644 (file)
@@ -19,6 +19,13 @@ struct dw_mipi_dsi_phy_ops {
                             unsigned int *lane_mbps);
 };
 
+struct dw_mipi_dsi_host_ops {
+       int (*attach)(void *priv_data,
+                     struct mipi_dsi_device *dsi);
+       int (*detach)(void *priv_data,
+                     struct mipi_dsi_device *dsi);
+};
+
 struct dw_mipi_dsi_plat_data {
        void __iomem *base;
        unsigned int max_data_lanes;
@@ -27,6 +34,7 @@ struct dw_mipi_dsi_plat_data {
                                           const struct drm_display_mode *mode);
 
        const struct dw_mipi_dsi_phy_ops *phy_ops;
+       const struct dw_mipi_dsi_host_ops *host_ops;
 
        void *priv_data;
 };
@@ -35,10 +43,8 @@ struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev,
                                      const struct dw_mipi_dsi_plat_data
                                      *plat_data);
 void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi);
-struct dw_mipi_dsi *dw_mipi_dsi_bind(struct platform_device *pdev,
-                                    struct drm_encoder *encoder,
-                                    const struct dw_mipi_dsi_plat_data
-                                    *plat_data);
+int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder);
 void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi);
+void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave);
 
 #endif /* __DW_MIPI_DSI__ */
index 05350424a4d3bbd17ae8a1aa5fcb5e68871862c2..bdb0d5548f39ede087a64e626f34b215834733d5 100644 (file)
@@ -68,7 +68,6 @@
 #include <drm/drm_agpsupport.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
-#include <drm/drm_global.h>
 #include <drm/drm_hashtab.h>
 #include <drm/drm_mm.h>
 #include <drm/drm_os_linux.h>
@@ -110,4 +109,10 @@ static inline bool drm_can_sleep(void)
        return true;
 }
 
+#if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE)
+#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x)
+#else
+#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x)
+#endif
+
 #endif
index 1e810e0b76647239dee3c89f589f684b07b6786a..f9b35834c45d0e544fe7c2944353577072818ac2 100644 (file)
@@ -265,7 +265,6 @@ struct __drm_private_objs_state {
  * struct drm_atomic_state - the global state object for atomic updates
  * @ref: count of all references to this state (will not be freed until zero)
  * @dev: parent DRM device
- * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
  * @async_update: hint for asynchronous plane update
  * @planes: pointer to array of structures with per-plane data
@@ -284,6 +283,15 @@ struct drm_atomic_state {
        struct kref ref;
 
        struct drm_device *dev;
+
+       /**
+        * @allow_modeset:
+        *
+        * Allow full modeset. This is used by the ATOMIC IOCTL handler to
+        * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should
+        * never consult this flag, instead looking at the output of
+        * drm_atomic_crtc_needs_modeset().
+        */
        bool allow_modeset : 1;
        bool legacy_cursor_update : 1;
        bool async_update : 1;
index 657af7b393790b68298cf10c73e513d1201a394d..58214be3bf3d8393418b7294a6b3d3b4414d18a2 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_modeset_helper.h>
+#include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_util.h>
 
 struct drm_atomic_state;
@@ -126,6 +127,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
 int drm_atomic_helper_disable_all(struct drm_device *dev,
                                  struct drm_modeset_acquire_ctx *ctx);
 void drm_atomic_helper_shutdown(struct drm_device *dev);
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_state(struct drm_device *dev,
+                                 struct drm_modeset_acquire_ctx *ctx);
 struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev);
 int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
                                              struct drm_modeset_acquire_ctx *ctx);
@@ -144,51 +148,10 @@ int drm_atomic_helper_page_flip_target(
                                uint32_t flags,
                                uint32_t target,
                                struct drm_modeset_acquire_ctx *ctx);
-struct drm_encoder *
-drm_atomic_helper_best_encoder(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_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,
-                                    struct drm_plane_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_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,
-                                        struct drm_connector_state *conn_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);
-struct drm_atomic_state *
-drm_atomic_helper_duplicate_state(struct drm_device *dev,
-                                 struct drm_modeset_acquire_ctx *ctx);
-void
-__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
-void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
-                                         struct drm_connector_state *state);
 int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
                                       u16 *red, u16 *green, u16 *blue,
                                       uint32_t size,
                                       struct drm_modeset_acquire_ctx *ctx);
-void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
-                                                    struct drm_private_state *state);
 
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
new file mode 100644 (file)
index 0000000..66c92cb
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * 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:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <linux/types.h>
+
+struct drm_crtc;
+struct drm_crtc_state;
+struct drm_plane;
+struct drm_plane_state;
+struct drm_connector;
+struct drm_connector_state;
+struct drm_private_obj;
+struct drm_private_state;
+struct drm_modeset_acquire_ctx;
+struct drm_device;
+
+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_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,
+                                    struct drm_plane_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_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,
+                                        struct drm_connector_state *conn_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_state *state);
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                         struct drm_connector_state *state);
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+                                                    struct drm_private_state *state);
index 9ccad6b062f2bb62c54434288e7fc9a25b194b53..9be2181b3ed7a065afb8770b7dfd39b0537c4e26 100644 (file)
@@ -508,6 +508,18 @@ struct drm_connector_state {
         * drm_writeback_signal_completion()
         */
        struct drm_writeback_job *writeback_job;
+
+       /**
+        * @max_requested_bpc: Connector property to limit the maximum bit
+        * depth of the pixels.
+        */
+       u8 max_requested_bpc;
+
+       /**
+        * @max_bpc: Connector max_bpc based on the requested max_bpc property
+        * and the connector bpc limitations obtained from edid.
+        */
+       u8 max_bpc;
 };
 
 /**
@@ -959,6 +971,17 @@ struct drm_connector {
         */
        struct drm_property *scaling_mode_property;
 
+       /**
+        * @vrr_capable_property: Optional property to help userspace
+        * query hardware support for variable refresh rate on a connector.
+        * connector. Drivers can add the property to a connector by
+        * calling drm_connector_attach_vrr_capable_property().
+        *
+        * This should be updated only by calling
+        * drm_connector_set_vrr_capable_property().
+        */
+       struct drm_property *vrr_capable_property;
+
        /**
         * @content_protection_property: DRM ENUM property for content
         * protection. See drm_connector_attach_content_protection_property().
@@ -973,6 +996,12 @@ struct drm_connector {
         */
        struct drm_property_blob *path_blob_ptr;
 
+       /**
+        * @max_bpc_property: Default connector property for the max bpc to be
+        * driven out of the connector.
+        */
+       struct drm_property *max_bpc_property;
+
 #define DRM_CONNECTOR_POLL_HPD (1 << 0)
 #define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
 #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
@@ -1133,6 +1162,7 @@ int drm_connector_init(struct drm_device *dev,
                       struct drm_connector *connector,
                       const struct drm_connector_funcs *funcs,
                       int connector_type);
+void drm_connector_attach_edid_property(struct drm_connector *connector);
 int drm_connector_register(struct drm_connector *connector);
 void drm_connector_unregister(struct drm_connector *connector);
 int drm_connector_attach_encoder(struct drm_connector *connector,
@@ -1191,30 +1221,6 @@ static inline void drm_connector_put(struct drm_connector *connector)
        drm_mode_object_put(&connector->base);
 }
 
-/**
- * drm_connector_reference - acquire a connector reference
- * @connector: DRM connector
- *
- * This is a compatibility alias for drm_connector_get() and should not be
- * used by new code.
- */
-static inline void drm_connector_reference(struct drm_connector *connector)
-{
-       drm_connector_get(connector);
-}
-
-/**
- * drm_connector_unreference - release a connector reference
- * @connector: DRM connector
- *
- * This is a compatibility alias for drm_connector_put() and should not be
- * used by new code.
- */
-static inline void drm_connector_unreference(struct drm_connector *connector)
-{
-       drm_connector_put(connector);
-}
-
 /**
  * drm_connector_is_unregistered - has the connector been unregistered from
  * userspace?
@@ -1250,6 +1256,8 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev);
 int drm_connector_attach_content_type_property(struct drm_connector *dev);
 int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
                                               u32 scaling_mode_mask);
+int drm_connector_attach_vrr_capable_property(
+               struct drm_connector *connector);
 int drm_connector_attach_content_protection_property(
                struct drm_connector *connector);
 int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
@@ -1266,8 +1274,12 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
                                       const struct edid *edid);
 void drm_connector_set_link_status_property(struct drm_connector *connector,
                                            uint64_t link_status);
+void drm_connector_set_vrr_capable_property(
+               struct drm_connector *connector, bool capable);
 int drm_connector_init_panel_orientation_property(
        struct drm_connector *connector, int width, int height);
+int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
+                                         int min, int max);
 
 /**
  * struct drm_tile_group - Tile group metadata
index b21437bc95bf3169319b5baee2b356d149ee6e49..39c3900aab3cea107a0771b6fe0d5dc510ac4c11 100644 (file)
@@ -290,6 +290,15 @@ struct drm_crtc_state {
         */
        u32 pageflip_flags;
 
+       /**
+        * @vrr_enabled:
+        *
+        * Indicates if variable refresh rate should be enabled for the CRTC.
+        * Support for the requested vrr state will depend on driver and
+        * hardware capabiltiy - lacking support is not treated as failure.
+        */
+       bool vrr_enabled;
+
        /**
         * @event:
         *
index 6914633037a5359f1355a15e94163dbde7d4ebe2..d65f034843cea620a3d99ff7b28261e8e33122a9 100644 (file)
@@ -57,12 +57,6 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode);
 
 void drm_helper_resume_force_mode(struct drm_device *dev);
 
-int drm_helper_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);
-int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                 struct drm_framebuffer *old_fb);
-
 /* drm_probe_helper.c */
 int drm_helper_probe_single_connector_modes(struct drm_connector
                                            *connector, uint32_t maxX,
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h
new file mode 100644 (file)
index 0000000..4487660
--- /dev/null
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/**************************************************************************
+ *
+ * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Deepak Rawat <drawat@vmware.com>
+ *
+ **************************************************************************/
+
+#ifndef DRM_DAMAGE_HELPER_H_
+#define DRM_DAMAGE_HELPER_H_
+
+#include <drm/drm_atomic_helper.h>
+
+/**
+ * drm_atomic_for_each_plane_damage - Iterator macro for plane damage.
+ * @iter: The iterator to advance.
+ * @rect: Return a rectangle in fb coordinate clipped to plane src.
+ *
+ * Note that if the first call to iterator macro return false then no need to do
+ * plane update. Iterator will return full plane src when damage is not passed
+ * by user-space.
+ */
+#define drm_atomic_for_each_plane_damage(iter, rect) \
+       while (drm_atomic_helper_damage_iter_next(iter, rect))
+
+/**
+ * struct drm_atomic_helper_damage_iter - Closure structure for damage iterator.
+ *
+ * This structure tracks state needed to walk the list of plane damage clips.
+ */
+struct drm_atomic_helper_damage_iter {
+       /* private: Plane src in whole number. */
+       struct drm_rect plane_src;
+       /* private: Rectangles in plane damage blob. */
+       const struct drm_rect *clips;
+       /* private: Number of rectangles in plane damage blob. */
+       uint32_t num_clips;
+       /* private: Current clip iterator is advancing on. */
+       uint32_t curr_clip;
+       /* private: Whether need full plane update. */
+       bool full_update;
+};
+
+void drm_plane_enable_fb_damage_clips(struct drm_plane *plane);
+void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
+                                         struct drm_plane_state *plane_state);
+int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
+                             struct drm_file *file_priv, unsigned int flags,
+                             unsigned int color, struct drm_clip_rect *clips,
+                             unsigned int num_clips);
+void
+drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
+                                  const struct drm_plane_state *old_state,
+                                  const struct drm_plane_state *new_state);
+bool
+drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
+                                  struct drm_rect *rect);
+
+/**
+ * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect.
+ * @state: Plane state.
+ *
+ * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect
+ * can be obtained by simply typecasting &drm_mode_rect. This is because both
+ * are signed 32 and during drm_atomic_check_only() it is verified that damage
+ * clips are inside fb.
+ *
+ * Return: Clips in plane fb_damage_clips blob property.
+ */
+static inline struct drm_rect *
+drm_helper_get_plane_damage_clips(const struct drm_plane_state *state)
+{
+       return (struct drm_rect *)drm_plane_get_damage_clips(state);
+}
+
+#endif
index 2a3843f248cfeadfe9b4222b14c3c09320c9c946..5736c942c85b7d9d96707e9160d98d5dbe116cb1 100644 (file)
 #define DP_DSC_MAX_BITS_PER_PIXEL_LOW       0x067   /* eDP 1.4 */
 
 #define DP_DSC_MAX_BITS_PER_PIXEL_HI        0x068   /* eDP 1.4 */
+# define DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK  (0x3 << 0)
+# define DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT 8
 
 #define DP_DSC_DEC_COLOR_FORMAT_CAP         0x069
 # define DP_DSC_RGB                         (1 << 0)
 # define DP_DSC_THROUGHPUT_MODE_1_1000      (14 << 4)
 
 #define DP_DSC_MAX_SLICE_WIDTH              0x06C
+#define DP_DSC_MIN_SLICE_WIDTH_VALUE        2560
+#define DP_DSC_SLICE_WIDTH_MULTIPLIER       320
 
 #define DP_DSC_SLICE_CAP_2                  0x06D
 # define DP_DSC_16_PER_DP_DSC_SINK          (1 << 0)
 # define DP_AUX_FRAME_SYNC_VALID           (1 << 0)
 
 #define DP_DSC_ENABLE                       0x160   /* DP 1.4 */
+# define DP_DECOMPRESSION_EN                (1 << 0)
 
 #define DP_PSR_EN_CFG                      0x170   /* XXX 1.2? */
 # define DP_PSR_ENABLE                     (1 << 0)
 # define DP_EDP_12                         0x01
 # define DP_EDP_13                         0x02
 # define DP_EDP_14                         0x03
+# define DP_EDP_14a                         0x04    /* eDP 1.4a */
+# define DP_EDP_14b                         0x05    /* eDP 1.4b */
 
 #define DP_EDP_GENERAL_CAP_1               0x701
 # define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP          (1 << 0)
 #define DP_AUX_HDCP_KSV_FIFO           0x6802C
 #define DP_AUX_HDCP_AINFO              0x6803B
 
+/* DP HDCP2.2 parameter offsets in DPCD address space */
+#define DP_HDCP_2_2_REG_RTX_OFFSET             0x69000
+#define DP_HDCP_2_2_REG_TXCAPS_OFFSET          0x69008
+#define DP_HDCP_2_2_REG_CERT_RX_OFFSET         0x6900B
+#define DP_HDCP_2_2_REG_RRX_OFFSET             0x69215
+#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET         0x6921D
+#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET                0x69220
+#define DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET       0x692A0
+#define DP_HDCP_2_2_REG_M_OFFSET               0x692B0
+#define DP_HDCP_2_2_REG_HPRIME_OFFSET          0x692C0
+#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET       0x692E0
+#define DP_HDCP_2_2_REG_RN_OFFSET              0x692F0
+#define DP_HDCP_2_2_REG_LPRIME_OFFSET          0x692F8
+#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET                0x69318
+#define        DP_HDCP_2_2_REG_RIV_OFFSET              0x69328
+#define DP_HDCP_2_2_REG_RXINFO_OFFSET          0x69330
+#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET       0x69332
+#define DP_HDCP_2_2_REG_VPRIME_OFFSET          0x69335
+#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET    0x69345
+#define DP_HDCP_2_2_REG_V_OFFSET               0x693E0
+#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET       0x693F0
+#define DP_HDCP_2_2_REG_K_OFFSET               0x693F3
+#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET  0x693F5
+#define DP_HDCP_2_2_REG_MPRIME_OFFSET          0x69473
+#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET                0x69493
+#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET     0x69494
+#define DP_HDCP_2_2_REG_DBG_OFFSET             0x69518
+
+/* DP HDCP message start offsets in DPCD address space */
+#define DP_HDCP_2_2_AKE_INIT_OFFSET            DP_HDCP_2_2_REG_RTX_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET       DP_HDCP_2_2_REG_CERT_RX_OFFSET
+#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET    DP_HDCP_2_2_REG_EKPUB_KM_OFFSET
+#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET       DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET     DP_HDCP_2_2_REG_HPRIME_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \
+                                               DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET
+#define DP_HDCP_2_2_LC_INIT_OFFSET             DP_HDCP_2_2_REG_RN_OFFSET
+#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET      DP_HDCP_2_2_REG_LPRIME_OFFSET
+#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET                DP_HDCP_2_2_REG_EDKEY_KS_OFFSET
+#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET        DP_HDCP_2_2_REG_RXINFO_OFFSET
+#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET                DP_HDCP_2_2_REG_V_OFFSET
+#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET   DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET
+#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET    DP_HDCP_2_2_REG_MPRIME_OFFSET
+
+#define HDCP_2_2_DP_RXSTATUS_LEN               1
+#define HDCP_2_2_DP_RXSTATUS_READY(x)          ((x) & BIT(0))
+#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x)                ((x) & BIT(1))
+#define HDCP_2_2_DP_RXSTATUS_PAIRING(x)                ((x) & BIT(2))
+#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x)     ((x) & BIT(3))
+#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x)    ((x) & BIT(4))
+
 /* DP 1.2 Sideband message defines */
 /* peer device type - DP 1.2a Table 2-92 */
 #define DP_PEER_DEVICE_NONE            0x0
@@ -963,6 +1021,7 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI
 
 #define DP_BRANCH_OUI_HEADER_SIZE      0xc
 #define DP_RECEIVER_CAP_SIZE           0xf
+#define DP_DSC_RECEIVER_CAP_SIZE        0xf
 #define EDP_PSR_RECEIVER_CAP_SIZE      2
 #define EDP_DISPLAY_CTL_CAP_SIZE       3
 
@@ -993,6 +1052,7 @@ struct dp_sdp_header {
 
 #define EDP_SDP_HEADER_REVISION_MASK           0x1F
 #define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES     0x1F
+#define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F
 
 struct edp_vsc_psr {
        struct dp_sdp_header sdp_header;
@@ -1059,6 +1119,44 @@ drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
        return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT;
 }
 
+/* DP/eDP DSC support */
+u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE],
+                                  bool is_edp);
+u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]);
+int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE],
+                                        u8 dsc_bpc[3]);
+
+static inline bool
+drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
+{
+       return dsc_dpcd[DP_DSC_SUPPORT - DP_DSC_SUPPORT] &
+               DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+}
+
+static inline u16
+drm_edp_dsc_sink_output_bpp(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
+{
+       return dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] |
+               (dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] &
+                DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK <<
+                DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT);
+}
+
+static inline u32
+drm_dp_dsc_sink_max_slice_width(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
+{
+       /* Max Slicewidth = Number of Pixels * 320 */
+       return dsc_dpcd[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] *
+               DP_DSC_SLICE_WIDTH_MULTIPLIER;
+}
+
+/* Forward Error Correction Support on DP 1.4 */
+static inline bool
+drm_dp_sink_supports_fec(const u8 fec_capable)
+{
+       return fec_capable & DP_FEC_CAPABLE;
+}
+
 /*
  * DisplayPort AUX channel
  */
index 7f78d26a076694ce5dcd42fe99da555fe092daa1..59f005b419cf7c18625ca40e42ec97e29dff47a8 100644 (file)
@@ -409,7 +409,6 @@ struct drm_dp_payload {
 struct drm_dp_mst_topology_state {
        struct drm_private_state base;
        int avail_slots;
-       struct drm_atomic_state *state;
        struct drm_dp_mst_topology_mgr *mgr;
 };
 
@@ -497,11 +496,6 @@ struct drm_dp_mst_topology_mgr {
         */
        int pbn_div;
 
-       /**
-        * @state: State information for topology manager
-        */
-       struct drm_dp_mst_topology_state *state;
-
        /**
         * @funcs: Atomic helper callbacks
         */
index 3199ef70c007998921d300fb32753bad93dbca9c..35af23f5fa0d081a97eef6fa8e2e805b1e768669 100644 (file)
@@ -471,6 +471,8 @@ struct drm_driver {
         * @gem_prime_export:
         *
         * export GEM -> dmabuf
+        *
+        * This defaults to drm_gem_prime_export() if not set.
         */
        struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
                                struct drm_gem_object *obj, int flags);
@@ -478,6 +480,8 @@ struct drm_driver {
         * @gem_prime_import:
         *
         * import dmabuf -> GEM
+        *
+        * This defaults to drm_gem_prime_import() if not set.
         */
        struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
                                struct dma_buf *dma_buf);
@@ -523,8 +527,10 @@ struct drm_driver {
         * @dumb_map_offset:
         *
         * Allocate an offset in the drm device node's address space to be able to
-        * memory map a dumb buffer. GEM-based drivers must use
-        * drm_gem_create_mmap_offset() to implement this.
+        * memory map a dumb buffer.
+        *
+        * The default implementation is drm_gem_create_mmap_offset(). GEM based
+        * drivers must not overwrite this.
         *
         * Called by the user via ioctl.
         *
@@ -544,6 +550,9 @@ struct drm_driver {
         *
         * Called by the user via ioctl.
         *
+        * The default implementation is drm_gem_dumb_destroy(). GEM based drivers
+        * must not overwrite this.
+        *
         * Returns:
         *
         * Zero on success, negative errno on failure.
@@ -621,7 +630,6 @@ void drm_dev_unregister(struct drm_device *dev);
 
 void drm_dev_get(struct drm_device *dev);
 void drm_dev_put(struct drm_device *dev);
-void drm_dev_unref(struct drm_device *dev);
 void drm_put_dev(struct drm_device *dev);
 bool drm_dev_enter(struct drm_device *dev, int *idx);
 void drm_dev_exit(int idx);
diff --git a/include/drm/drm_dsc.h b/include/drm/drm_dsc.h
new file mode 100644 (file)
index 0000000..d03f1b8
--- /dev/null
@@ -0,0 +1,485 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * Authors:
+ * Manasi Navare <manasi.d.navare@intel.com>
+ */
+
+#ifndef DRM_DSC_H_
+#define DRM_DSC_H_
+
+#include <drm/drm_dp_helper.h>
+
+/* VESA Display Stream Compression DSC 1.2 constants */
+#define DSC_NUM_BUF_RANGES                     15
+#define DSC_MUX_WORD_SIZE_8_10_BPC             48
+#define DSC_MUX_WORD_SIZE_12_BPC               64
+#define DSC_RC_PIXELS_PER_GROUP                        3
+#define DSC_SCALE_DECREMENT_INTERVAL_MAX       4095
+#define DSC_RANGE_BPG_OFFSET_MASK              0x3f
+
+/* DSC Rate Control Constants */
+#define DSC_RC_MODEL_SIZE_CONST                    8192
+#define DSC_RC_EDGE_FACTOR_CONST           6
+#define DSC_RC_TGT_OFFSET_HI_CONST         3
+#define DSC_RC_TGT_OFFSET_LO_CONST         3
+
+/* DSC PPS constants and macros */
+#define DSC_PPS_VERSION_MAJOR_SHIFT            4
+#define DSC_PPS_BPC_SHIFT                      4
+#define DSC_PPS_MSB_SHIFT                      8
+#define DSC_PPS_LSB_MASK                       (0xFF << 0)
+#define DSC_PPS_BPP_HIGH_MASK                  (0x3 << 8)
+#define DSC_PPS_VBR_EN_SHIFT                   2
+#define DSC_PPS_SIMPLE422_SHIFT                        3
+#define DSC_PPS_CONVERT_RGB_SHIFT              4
+#define DSC_PPS_BLOCK_PRED_EN_SHIFT            5
+#define DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK      (0x3 << 8)
+#define DSC_PPS_SCALE_DEC_INT_HIGH_MASK                (0xF << 8)
+#define DSC_PPS_RC_TGT_OFFSET_HI_SHIFT         4
+#define DSC_PPS_RC_RANGE_MINQP_SHIFT           11
+#define DSC_PPS_RC_RANGE_MAXQP_SHIFT           6
+#define DSC_PPS_NATIVE_420_SHIFT               1
+#define DSC_1_2_MAX_LINEBUF_DEPTH_BITS         16
+#define DSC_1_2_MAX_LINEBUF_DEPTH_VAL          0
+#define DSC_1_1_MAX_LINEBUF_DEPTH_BITS         13
+
+/* Configuration for a single Rate Control model range */
+struct drm_dsc_rc_range_parameters {
+       /* Min Quantization Parameters allowed for this range */
+       u8 range_min_qp;
+       /* Max Quantization Parameters allowed for this range */
+       u8 range_max_qp;
+       /* Bits/group offset to apply to target for this group */
+       u8 range_bpg_offset;
+};
+
+struct drm_dsc_config {
+       /* Bits / component for previous reconstructed line buffer */
+       u8 line_buf_depth;
+       /* Bits per component to code (must be 8, 10, or 12) */
+       u8 bits_per_component;
+       /*
+        * Flag indicating to do RGB - YCoCg conversion
+        * and back (should be 1 for RGB input)
+        */
+       bool convert_rgb;
+       u8 slice_count;
+       /* Slice Width */
+       u16 slice_width;
+       /* Slice Height */
+       u16 slice_height;
+       /*
+        * 4:2:2 enable mode (from PPS, 4:2:2 conversion happens
+        * outside of DSC encode/decode algorithm)
+        */
+       bool enable422;
+       /* Picture Width */
+       u16 pic_width;
+       /* Picture Height */
+       u16 pic_height;
+       /* Offset to bits/group used by RC to determine QP adjustment */
+       u8 rc_tgt_offset_high;
+       /* Offset to bits/group used by RC to determine QP adjustment */
+       u8 rc_tgt_offset_low;
+       /* Bits/pixel target << 4 (ie., 4 fractional bits) */
+       u16 bits_per_pixel;
+       /*
+        * Factor to determine if an edge is present based
+        * on the bits produced
+        */
+       u8 rc_edge_factor;
+       /* Slow down incrementing once the range reaches this value */
+       u8 rc_quant_incr_limit1;
+       /* Slow down incrementing once the range reaches this value */
+       u8 rc_quant_incr_limit0;
+       /* Number of pixels to delay the initial transmission */
+       u16 initial_xmit_delay;
+       /* Number of pixels to delay the VLD on the decoder,not including SSM */
+       u16  initial_dec_delay;
+       /* Block prediction enable */
+       bool block_pred_enable;
+       /* Bits/group offset to use for first line of the slice */
+       u8 first_line_bpg_offset;
+       /* Value to use for RC model offset at slice start */
+       u16 initial_offset;
+       /* Thresholds defining each of the buffer ranges */
+       u16 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1];
+       /* Parameters for each of the RC ranges */
+       struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES];
+       /* Total size of RC model */
+       u16 rc_model_size;
+       /* Minimum QP where flatness information is sent */
+       u8 flatness_min_qp;
+       /* Maximum QP where flatness information is sent */
+       u8 flatness_max_qp;
+       /* Initial value for scale factor */
+       u8 initial_scale_value;
+       /* Decrement scale factor every scale_decrement_interval groups */
+       u16 scale_decrement_interval;
+       /* Increment scale factor every scale_increment_interval groups */
+       u16 scale_increment_interval;
+       /* Non-first line BPG offset to use */
+       u16 nfl_bpg_offset;
+       /* BPG offset used to enforce slice bit */
+       u16 slice_bpg_offset;
+       /* Final RC linear transformation offset value */
+       u16 final_offset;
+       /* Enable on-off VBR (ie., disable stuffing bits) */
+       bool vbr_enable;
+       /* Mux word size (in bits) for SSM mode */
+       u8 mux_word_size;
+       /*
+        * The (max) size in bytes of the "chunks" that are
+        * used in slice multiplexing
+        */
+       u16 slice_chunk_size;
+       /* Rate Control buffer siz in bits */
+       u16 rc_bits;
+       /* DSC Minor Version */
+       u8 dsc_version_minor;
+       /* DSC Major version */
+       u8 dsc_version_major;
+       /* Native 4:2:2 support */
+       bool native_422;
+       /* Native 4:2:0 support */
+       bool native_420;
+       /* Additional bits/grp for seconnd line of slice for native 4:2:0 */
+       u8 second_line_bpg_offset;
+       /* Num of bits deallocated for each grp that is not in second line of slice */
+       u16 nsl_bpg_offset;
+       /* Offset adj fr second line in Native 4:2:0 mode */
+       u16 second_line_offset_adj;
+};
+
+/**
+ * struct picture_parameter_set - Represents 128 bytes of Picture Parameter Set
+ *
+ * The VESA DSC standard defines picture parameter set (PPS) which display
+ * stream compression encoders must communicate to decoders.
+ * The PPS is encapsulated in 128 bytes (PPS 0 through PPS 127). The fields in
+ * this structure are as per Table 4.1 in Vesa DSC specification v1.1/v1.2.
+ * The PPS fields that span over more than a byte should be stored in Big Endian
+ * format.
+ */
+struct drm_dsc_picture_parameter_set {
+       /**
+        * @dsc_version:
+        * PPS0[3:0] - dsc_version_minor: Contains Minor version of DSC
+        * PPS0[7:4] - dsc_version_major: Contains major version of DSC
+        */
+       u8 dsc_version;
+       /**
+        * @pps_identifier:
+        * PPS1[7:0] - Application specific identifier that can be
+        * used to differentiate between different PPS tables.
+        */
+       u8 pps_identifier;
+       /**
+        * @pps_reserved:
+        * PPS2[7:0]- RESERVED Byte
+        */
+       u8 pps_reserved;
+       /**
+        * @pps_3:
+        * PPS3[3:0] - linebuf_depth: Contains linebuffer bit depth used to
+        * generate the bitstream. (0x0 - 16 bits for DSC 1.2, 0x8 - 8 bits,
+        * 0xA - 10 bits, 0xB - 11 bits, 0xC - 12 bits, 0xD - 13 bits,
+        * 0xE - 14 bits for DSC1.2, 0xF - 14 bits for DSC 1.2.
+        * PPS3[7:4] - bits_per_component: Bits per component for the original
+        * pixels of the encoded picture.
+        * 0x0 = 16bpc (allowed only when dsc_version_minor = 0x2)
+        * 0x8 = 8bpc, 0xA = 10bpc, 0xC = 12bpc, 0xE = 14bpc (also
+        * allowed only when dsc_minor_version = 0x2)
+        */
+       u8 pps_3;
+       /**
+        * @pps_4:
+        * PPS4[1:0] -These are the most significant 2 bits of
+        * compressed BPP bits_per_pixel[9:0] syntax element.
+        * PPS4[2] - vbr_enable: 0 = VBR disabled, 1 = VBR enabled
+        * PPS4[3] - simple_422: Indicates if decoder drops samples to
+        * reconstruct the 4:2:2 picture.
+        * PPS4[4] - Convert_rgb: Indicates if DSC color space conversion is
+        * active.
+        * PPS4[5] - blobk_pred_enable: Indicates if BP is used to code any
+        * groups in picture
+        * PPS4[7:6] - Reseved bits
+        */
+       u8 pps_4;
+       /**
+        * @bits_per_pixel_low:
+        * PPS5[7:0] - This indicates the lower significant 8 bits of
+        * the compressed BPP bits_per_pixel[9:0] element.
+        */
+       u8 bits_per_pixel_low;
+       /**
+        * @pic_height:
+        * PPS6[7:0], PPS7[7:0] -pic_height: Specifies the number of pixel rows
+        * within the raster.
+        */
+       __be16 pic_height;
+       /**
+        * @pic_width:
+        * PPS8[7:0], PPS9[7:0] - pic_width: Number of pixel columns within
+        * the raster.
+        */
+       __be16 pic_width;
+       /**
+        * @slice_height:
+        * PPS10[7:0], PPS11[7:0] - Slice height in units of pixels.
+        */
+       __be16 slice_height;
+       /**
+        * @slice_width:
+        * PPS12[7:0], PPS13[7:0] - Slice width in terms of pixels.
+        */
+       __be16 slice_width;
+       /**
+        * @chunk_size:
+        * PPS14[7:0], PPS15[7:0] - Size in units of bytes of the chunks
+        * that are used for slice multiplexing.
+        */
+       __be16 chunk_size;
+       /**
+        * @initial_xmit_delay_high:
+        * PPS16[1:0] - Most Significant two bits of initial transmission delay.
+        * It specifies the number of pixel times that the encoder waits before
+        * transmitting data from its rate buffer.
+        * PPS16[7:2] - Reserved
+        */
+       u8 initial_xmit_delay_high;
+       /**
+        * @initial_xmit_delay_low:
+        * PPS17[7:0] - Least significant 8 bits of initial transmission delay.
+        */
+       u8 initial_xmit_delay_low;
+       /**
+        * @initial_dec_delay:
+        *
+        * PPS18[7:0], PPS19[7:0] - Initial decoding delay which is the number
+        * of pixel times that the decoder accumulates data in its rate buffer
+        * before starting to decode and output pixels.
+        */
+       __be16 initial_dec_delay;
+       /**
+        * @pps20_reserved:
+        *
+        * PPS20[7:0] - Reserved
+        */
+       u8 pps20_reserved;
+       /**
+        * @initial_scale_value:
+        * PPS21[5:0] - Initial rcXformScale factor used at beginning
+        * of a slice.
+        * PPS21[7:6] - Reserved
+        */
+       u8 initial_scale_value;
+       /**
+        * @scale_increment_interval:
+        * PPS22[7:0], PPS23[7:0] - Number of group times between incrementing
+        * the rcXformScale factor at end of a slice.
+        */
+       __be16 scale_increment_interval;
+       /**
+        * @scale_decrement_interval_high:
+        * PPS24[3:0] - Higher 4 bits indicating number of group times between
+        * decrementing the rcXformScale factor at beginning of a slice.
+        * PPS24[7:4] - Reserved
+        */
+       u8 scale_decrement_interval_high;
+       /**
+        * @scale_decrement_interval_low:
+        * PPS25[7:0] - Lower 8 bits of scale decrement interval
+        */
+       u8 scale_decrement_interval_low;
+       /**
+        * @pps26_reserved:
+        * PPS26[7:0]
+        */
+       u8 pps26_reserved;
+       /**
+        * @first_line_bpg_offset:
+        * PPS27[4:0] - Number of additional bits that are allocated
+        * for each group on first line of a slice.
+        * PPS27[7:5] - Reserved
+        */
+       u8 first_line_bpg_offset;
+       /**
+        * @nfl_bpg_offset:
+        * PPS28[7:0], PPS29[7:0] - Number of bits including frac bits
+        * deallocated for each group for groups after the first line of slice.
+        */
+       __be16 nfl_bpg_offset;
+       /**
+        * @slice_bpg_offset:
+        * PPS30, PPS31[7:0] - Number of bits that are deallocated for each
+        * group to enforce the slice constraint.
+        */
+       __be16 slice_bpg_offset;
+       /**
+        * @initial_offset:
+        * PPS32,33[7:0] - Initial value for rcXformOffset
+        */
+       __be16 initial_offset;
+       /**
+        * @final_offset:
+        * PPS34,35[7:0] - Maximum end-of-slice value for rcXformOffset
+        */
+       __be16 final_offset;
+       /**
+        * @flatness_min_qp:
+        * PPS36[4:0] - Minimum QP at which flatness is signaled and
+        * flatness QP adjustment is made.
+        * PPS36[7:5] - Reserved
+        */
+       u8 flatness_min_qp;
+       /**
+        * @flatness_max_qp:
+        * PPS37[4:0] - Max QP at which flatness is signalled and
+        * the flatness adjustment is made.
+        * PPS37[7:5] - Reserved
+        */
+       u8 flatness_max_qp;
+       /**
+        * @rc_model_size:
+        * PPS38,39[7:0] - Number of bits within RC Model.
+        */
+       __be16 rc_model_size;
+       /**
+        * @rc_edge_factor:
+        * PPS40[3:0] - Ratio of current activity vs, previous
+        * activity to determine presence of edge.
+        * PPS40[7:4] - Reserved
+        */
+       u8 rc_edge_factor;
+       /**
+        * @rc_quant_incr_limit0:
+        * PPS41[4:0] - QP threshold used in short term RC
+        * PPS41[7:5] - Reserved
+        */
+       u8 rc_quant_incr_limit0;
+       /**
+        * @rc_quant_incr_limit1:
+        * PPS42[4:0] - QP threshold used in short term RC
+        * PPS42[7:5] - Reserved
+        */
+       u8 rc_quant_incr_limit1;
+       /**
+        * @rc_tgt_offset:
+        * PPS43[3:0] - Lower end of the variability range around the target
+        * bits per group that is allowed by short term RC.
+        * PPS43[7:4]- Upper end of the variability range around the target
+        * bits per group that i allowed by short term rc.
+        */
+       u8 rc_tgt_offset;
+       /**
+        * @rc_buf_thresh:
+        * PPS44[7:0] - PPS57[7:0] - Specifies the thresholds in RC model for
+        * the 15 ranges defined by 14 thresholds.
+        */
+       u8 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1];
+       /**
+        * @rc_range_parameters:
+        * PPS58[7:0] - PPS87[7:0]
+        * Parameters that correspond to each of the 15 ranges.
+        */
+       __be16 rc_range_parameters[DSC_NUM_BUF_RANGES];
+       /**
+        * @native_422_420:
+        * PPS88[0] - 0 = Native 4:2:2 not used
+        * 1 = Native 4:2:2 used
+        * PPS88[1] - 0 = Native 4:2:0 not use
+        * 1 = Native 4:2:0 used
+        * PPS88[7:2] - Reserved 6 bits
+        */
+       u8 native_422_420;
+       /**
+        * @second_line_bpg_offset:
+        * PPS89[4:0] - Additional bits/group budget for the
+        * second line of a slice in Native 4:2:0 mode.
+        * Set to 0 if DSC minor version is 1 or native420 is 0.
+        * PPS89[7:5] - Reserved
+        */
+       u8 second_line_bpg_offset;
+       /**
+        * @nsl_bpg_offset:
+        * PPS90[7:0], PPS91[7:0] - Number of bits that are deallocated
+        * for each group that is not in the second line of a slice.
+        */
+       __be16 nsl_bpg_offset;
+       /**
+        * @second_line_offset_adj:
+        * PPS92[7:0], PPS93[7:0] - Used as offset adjustment for the second
+        * line in Native 4:2:0 mode.
+        */
+       __be16 second_line_offset_adj;
+       /**
+        * @pps_long_94_reserved:
+        * PPS 94, 95, 96, 97 - Reserved
+        */
+       u32 pps_long_94_reserved;
+       /**
+        * @pps_long_98_reserved:
+        * PPS 98, 99, 100, 101 - Reserved
+        */
+       u32 pps_long_98_reserved;
+       /**
+        * @pps_long_102_reserved:
+        * PPS 102, 103, 104, 105 - Reserved
+        */
+       u32 pps_long_102_reserved;
+       /**
+        * @pps_long_106_reserved:
+        * PPS 106, 107, 108, 109 - reserved
+        */
+       u32 pps_long_106_reserved;
+       /**
+        * @pps_long_110_reserved:
+        * PPS 110, 111, 112, 113 - reserved
+        */
+       u32 pps_long_110_reserved;
+       /**
+        * @pps_long_114_reserved:
+        * PPS 114 - 117 - reserved
+        */
+       u32 pps_long_114_reserved;
+       /**
+        * @pps_long_118_reserved:
+        * PPS 118 - 121 - reserved
+        */
+       u32 pps_long_118_reserved;
+       /**
+        * @pps_long_122_reserved:
+        * PPS 122- 125 - reserved
+        */
+       u32 pps_long_122_reserved;
+       /**
+        * @pps_short_126_reserved:
+        * PPS 126, 127 - reserved
+        */
+       __be16 pps_short_126_reserved;
+} __packed;
+
+/**
+ * struct drm_dsc_pps_infoframe - DSC infoframe carrying the Picture Parameter
+ * Set Metadata
+ *
+ * This structure represents the DSC PPS infoframe required to send the Picture
+ * Parameter Set metadata required before enabling VESA Display Stream
+ * Compression. This is based on the DP Secondary Data Packet structure and
+ * comprises of SDP Header as defined in drm_dp_helper.h and PPS payload.
+ *
+ * @pps_header: Header for PPS as per DP SDP header format
+ * @pps_payload: PPS payload fields as per DSC specification Table 4-1
+ */
+struct drm_dsc_pps_infoframe {
+       struct dp_sdp_header pps_header;
+       struct drm_dsc_picture_parameter_set pps_payload;
+} __packed;
+
+void drm_dsc_dp_pps_header_init(struct drm_dsc_pps_infoframe *pps_sdp);
+void drm_dsc_pps_infoframe_pack(struct drm_dsc_pps_infoframe *pps_sdp,
+                               const struct drm_dsc_config *dsc_cfg);
+
+#endif /* _DRM_DSC_H_ */
index 4a65f0d155b001cee9d7b90a6f8e86725803b4e5..8dbbe1eece1bd28eb18e4ee82788b8ad840b670f 100644 (file)
@@ -26,8 +26,6 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma);
 
 void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma);
 void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
-void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
-                                       bool state);
 
 struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
        unsigned int plane);
index 26485acc51d7944697ce96f0988c2803f4d8c581..84ac79219e4ce64ccf062931b5e323b5cbb789e7 100644 (file)
@@ -164,14 +164,14 @@ struct drm_file {
         * See also the :ref:`section on primary nodes and authentication
         * <drm_primary_node>`.
         */
-       unsigned authenticated :1;
+       bool authenticated;
 
        /**
         * @stereo_allowed:
         *
         * True when the client has asked us to expose stereo 3D mode flags.
         */
-       unsigned stereo_allowed :1;
+       bool stereo_allowed;
 
        /**
         * @universal_planes:
@@ -179,10 +179,10 @@ struct drm_file {
         * True if client understands CRTC primary planes and cursor planes
         * in the plane list. Automatically set when @atomic is set.
         */
-       unsigned universal_planes:1;
+       bool universal_planes;
 
        /** @atomic: True if client understands atomic properties. */
-       unsigned atomic:1;
+       bool atomic;
 
        /**
         * @aspect_ratio_allowed:
@@ -190,14 +190,14 @@ struct drm_file {
         * True, if client can handle picture aspect ratios, and has requested
         * to pass this information along with the mode.
         */
-       unsigned aspect_ratio_allowed:1;
+       bool aspect_ratio_allowed;
 
        /**
         * @writeback_connectors:
         *
         * True if client understands writeback connectors
         */
-       unsigned writeback_connectors:1;
+       bool writeback_connectors;
 
        /**
         * @is_master:
@@ -208,7 +208,7 @@ struct drm_file {
         * See also the :ref:`section on primary nodes and authentication
         * <drm_primary_node>`.
         */
-       unsigned is_master:1;
+       bool is_master;
 
        /**
         * @master:
index 865ef60c17af385d2eb55db2d8c53a2f08d7ca07..bcb389f04618a25a924637e0ccbb4d4f7af340c7 100644 (file)
@@ -52,25 +52,86 @@ struct drm_mode_fb_cmd2;
 
 /**
  * struct drm_format_info - information about a DRM format
- * @format: 4CC format identifier (DRM_FORMAT_*)
- * @depth: Color depth (number of bits per pixel excluding padding bits),
- *     valid for a subset of RGB formats only. This is a legacy field, do not
- *     use in new code and set to 0 for new formats.
- * @num_planes: Number of color planes (1 to 3)
- * @cpp: Number of bytes per pixel (per plane)
- * @hsub: Horizontal chroma subsampling factor
- * @vsub: Vertical chroma subsampling factor
- * @has_alpha: Does the format embeds an alpha component?
- * @is_yuv: Is it a YUV format?
  */
 struct drm_format_info {
+       /** @format: 4CC format identifier (DRM_FORMAT_*) */
        u32 format;
+
+       /**
+        * @depth:
+        *
+        * Color depth (number of bits per pixel excluding padding bits),
+        * valid for a subset of RGB formats only. This is a legacy field, do
+        * not use in new code and set to 0 for new formats.
+        */
        u8 depth;
+
+       /** @num_planes: Number of color planes (1 to 3) */
        u8 num_planes;
-       u8 cpp[3];
+
+       union {
+               /**
+                * @cpp:
+                *
+                * Number of bytes per pixel (per plane), this is aliased with
+                * @char_per_block. It is deprecated in favour of using the
+                * triplet @char_per_block, @block_w, @block_h for better
+                * describing the pixel format.
+                */
+               u8 cpp[3];
+
+               /**
+                * @char_per_block:
+                *
+                * Number of bytes per block (per plane), where blocks are
+                * defined as a rectangle of pixels which are stored next to
+                * each other in a byte aligned memory region. Together with
+                * @block_w and @block_h this is used to properly describe tiles
+                * in tiled formats or to describe groups of pixels in packed
+                * formats for which the memory needed for a single pixel is not
+                * byte aligned.
+                *
+                * @cpp has been kept for historical reasons because there are
+                * a lot of places in drivers where it's used. In drm core for
+                * generic code paths the preferred way is to use
+                * @char_per_block, drm_format_info_block_width() and
+                * drm_format_info_block_height() which allows handling both
+                * block and non-block formats in the same way.
+                *
+                * For formats that are intended to be used only with non-linear
+                * modifiers both @cpp and @char_per_block must be 0 in the
+                * generic format table. Drivers could supply accurate
+                * information from their drm_mode_config.get_format_info hook
+                * if they want the core to be validating the pitch.
+                */
+               u8 char_per_block[3];
+       };
+
+       /**
+        * @block_w:
+        *
+        * Block width in pixels, this is intended to be accessed through
+        * drm_format_info_block_width()
+        */
+       u8 block_w[3];
+
+       /**
+        * @block_h:
+        *
+        * Block height in pixels, this is intended to be accessed through
+        * drm_format_info_block_height()
+        */
+       u8 block_h[3];
+
+       /** @hsub: Horizontal chroma subsampling factor */
        u8 hsub;
+       /** @vsub: Vertical chroma subsampling factor */
        u8 vsub;
+
+       /** @has_alpha: Does the format embeds an alpha component? */
        bool has_alpha;
+
+       /** @is_yuv: Is it a YUV format? */
        bool is_yuv;
 };
 
@@ -96,6 +157,12 @@ int drm_format_horz_chroma_subsampling(uint32_t format);
 int drm_format_vert_chroma_subsampling(uint32_t format);
 int drm_format_plane_width(int width, uint32_t format, int plane);
 int drm_format_plane_height(int height, uint32_t format, int plane);
+unsigned int drm_format_info_block_width(const struct drm_format_info *info,
+                                        int plane);
+unsigned int drm_format_info_block_height(const struct drm_format_info *info,
+                                         int plane);
+uint64_t drm_format_info_min_pitch(const struct drm_format_info *info,
+                                  int plane, unsigned int buffer_width);
 const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf);
 
 #endif /* __DRM_FOURCC_H__ */
index c50502c656e5751374ed4e088540285fb1ee95f4..c94acedfb08ebf4efcd3adba8365d64860905012 100644 (file)
@@ -240,30 +240,6 @@ static inline void drm_framebuffer_put(struct drm_framebuffer *fb)
        drm_mode_object_put(&fb->base);
 }
 
-/**
- * drm_framebuffer_reference - acquire a framebuffer reference
- * @fb: DRM framebuffer
- *
- * This is a compatibility alias for drm_framebuffer_get() and should not be
- * used by new code.
- */
-static inline void drm_framebuffer_reference(struct drm_framebuffer *fb)
-{
-       drm_framebuffer_get(fb);
-}
-
-/**
- * drm_framebuffer_unreference - release a framebuffer reference
- * @fb: DRM framebuffer
- *
- * This is a compatibility alias for drm_framebuffer_put() and should not be
- * used by new code.
- */
-static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb)
-{
-       drm_framebuffer_put(fb);
-}
-
 /**
  * drm_framebuffer_read_refcount - read the framebuffer reference count.
  * @fb: framebuffer
index 3583b98a1718139eb07dbda254af71987a45602b..c957274252844fc1d332bc04908a803161ed4c4c 100644 (file)
 
 #include <drm/drm_vma_manager.h>
 
+struct drm_gem_object;
+
+/**
+ * struct drm_gem_object_funcs - GEM object functions
+ */
+struct drm_gem_object_funcs {
+       /**
+        * @free:
+        *
+        * Deconstructor for drm_gem_objects.
+        *
+        * This callback is mandatory.
+        */
+       void (*free)(struct drm_gem_object *obj);
+
+       /**
+        * @open:
+        *
+        * Called upon GEM handle creation.
+        *
+        * This callback is optional.
+        */
+       int (*open)(struct drm_gem_object *obj, struct drm_file *file);
+
+       /**
+        * @close:
+        *
+        * Called upon GEM handle release.
+        *
+        * This callback is optional.
+        */
+       void (*close)(struct drm_gem_object *obj, struct drm_file *file);
+
+       /**
+        * @print_info:
+        *
+        * If driver subclasses struct &drm_gem_object, it can implement this
+        * optional hook for printing additional driver specific info.
+        *
+        * drm_printf_indent() should be used in the callback passing it the
+        * indent argument.
+        *
+        * This callback is called from drm_gem_print_info().
+        *
+        * This callback is optional.
+        */
+       void (*print_info)(struct drm_printer *p, unsigned int indent,
+                          const struct drm_gem_object *obj);
+
+       /**
+        * @export:
+        *
+        * Export backing buffer as a &dma_buf.
+        * If this is not set drm_gem_prime_export() is used.
+        *
+        * This callback is optional.
+        */
+       struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
+
+       /**
+        * @pin:
+        *
+        * Pin backing buffer in memory.
+        *
+        * This callback is optional.
+        */
+       int (*pin)(struct drm_gem_object *obj);
+
+       /**
+        * @unpin:
+        *
+        * Unpin backing buffer.
+        *
+        * This callback is optional.
+        */
+       void (*unpin)(struct drm_gem_object *obj);
+
+       /**
+        * @get_sg_table:
+        *
+        * Returns a Scatter-Gather table representation of the buffer.
+        * Used when exporting a buffer.
+        *
+        * This callback is mandatory if buffer export is supported.
+        */
+       struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
+
+       /**
+        * @vmap:
+        *
+        * Returns a virtual address for the buffer.
+        *
+        * This callback is optional.
+        */
+       void *(*vmap)(struct drm_gem_object *obj);
+
+       /**
+        * @vunmap:
+        *
+        * Releases the the address previously returned by @vmap.
+        *
+        * This callback is optional.
+        */
+       void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
+
+       /**
+        * @vm_ops:
+        *
+        * Virtual memory operations used with mmap.
+        *
+        * This is optional but necessary for mmap support.
+        */
+       const struct vm_operations_struct *vm_ops;
+};
+
 /**
  * struct drm_gem_object - GEM buffer object
  *
@@ -146,6 +261,17 @@ struct drm_gem_object {
         * simply leave it as NULL.
         */
        struct dma_buf_attachment *import_attach;
+
+       /**
+        * @funcs:
+        *
+        * Optional GEM object functions. If this is set, it will be used instead of the
+        * corresponding &drm_driver GEM callbacks.
+        *
+        * New drivers should use this.
+        *
+        */
+       const struct drm_gem_object_funcs *funcs;
 };
 
 /**
@@ -222,56 +348,6 @@ __drm_gem_object_put(struct drm_gem_object *obj)
 void drm_gem_object_put_unlocked(struct drm_gem_object *obj);
 void drm_gem_object_put(struct drm_gem_object *obj);
 
-/**
- * drm_gem_object_reference - acquire a GEM buffer object reference
- * @obj: GEM buffer object
- *
- * This is a compatibility alias for drm_gem_object_get() and should not be
- * used by new code.
- */
-static inline void drm_gem_object_reference(struct drm_gem_object *obj)
-{
-       drm_gem_object_get(obj);
-}
-
-/**
- * __drm_gem_object_unreference - raw function to release a GEM buffer object
- *                                reference
- * @obj: GEM buffer object
- *
- * This is a compatibility alias for __drm_gem_object_put() and should not be
- * used by new code.
- */
-static inline void __drm_gem_object_unreference(struct drm_gem_object *obj)
-{
-       __drm_gem_object_put(obj);
-}
-
-/**
- * drm_gem_object_unreference_unlocked - release a GEM buffer object reference
- * @obj: GEM buffer object
- *
- * This is a compatibility alias for drm_gem_object_put_unlocked() and should
- * not be used by new code.
- */
-static inline void
-drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
-{
-       drm_gem_object_put_unlocked(obj);
-}
-
-/**
- * drm_gem_object_unreference - release a GEM buffer object reference
- * @obj: GEM buffer object
- *
- * This is a compatibility alias for drm_gem_object_put() and should not be
- * used by new code.
- */
-static inline void drm_gem_object_unreference(struct drm_gem_object *obj)
-{
-       drm_gem_object_put(obj);
-}
-
 int drm_gem_handle_create(struct drm_file *file_priv,
                          struct drm_gem_object *obj,
                          u32 *handlep);
@@ -293,4 +369,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
                         struct drm_device *dev,
                         uint32_t handle);
 
+int drm_gem_pin(struct drm_gem_object *obj);
+void drm_gem_unpin(struct drm_gem_object *obj);
+void *drm_gem_vmap(struct drm_gem_object *obj);
+void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
+
 #endif /* __DRM_GEM_H__ */
index 19777145cf8ede8ff9a0272513f82fc971149345..07c504940ba16c169f32c58a6d25b82ae900c758 100644 (file)
@@ -103,4 +103,28 @@ int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
 void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj);
 void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 
+struct drm_gem_object *
+drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size);
+
+/**
+ * DRM_GEM_CMA_VMAP_DRIVER_OPS - CMA GEM driver operations ensuring a virtual
+ *                               address on the buffer
+ *
+ * This macro provides a shortcut for setting the default GEM operations in the
+ * &drm_driver structure for drivers that need the virtual address also on
+ * imported buffers.
+ */
+#define DRM_GEM_CMA_VMAP_DRIVER_OPS \
+       .gem_create_object      = drm_cma_gem_create_object_default_funcs, \
+       .dumb_create            = drm_gem_cma_dumb_create, \
+       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd, \
+       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle, \
+       .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table_vmap, \
+       .gem_prime_mmap         = drm_gem_prime_mmap
+
+struct drm_gem_object *
+drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *drm,
+                                      struct dma_buf_attachment *attach,
+                                      struct sg_table *sgt);
+
 #endif /* __DRM_GEM_CMA_HELPER_H__ */
diff --git a/include/drm/drm_global.h b/include/drm/drm_global.h
deleted file mode 100644 (file)
index 3a83060..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-/*
- * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
- */
-
-#ifndef _DRM_GLOBAL_H_
-#define _DRM_GLOBAL_H_
-enum drm_global_types {
-       DRM_GLOBAL_TTM_MEM = 0,
-       DRM_GLOBAL_TTM_BO,
-       DRM_GLOBAL_TTM_OBJECT,
-       DRM_GLOBAL_NUM
-};
-
-struct drm_global_reference {
-       enum drm_global_types global_type;
-       size_t size;
-       void *object;
-       int (*init) (struct drm_global_reference *);
-       void (*release) (struct drm_global_reference *);
-};
-
-void drm_global_init(void);
-void drm_global_release(void);
-int drm_global_item_ref(struct drm_global_reference *ref);
-void drm_global_item_unref(struct drm_global_reference *ref);
-
-#endif
index 98e63d870139db0c9956f4446d3e298eb2964e7a..a6de09c5e47f500b1c93b5302fc3a00fef267988 100644 (file)
 #define DRM_HDCP_DDC_BSTATUS                   0x41
 #define DRM_HDCP_DDC_KSV_FIFO                  0x43
 
+#define DRM_HDCP_1_4_SRM_ID                    0x8
+#define DRM_HDCP_1_4_VRL_LENGTH_SIZE           3
+#define DRM_HDCP_1_4_DCP_SIG_SIZE              40
+
+/* Protocol message definition for HDCP2.2 specification */
+/*
+ * Protected content streams are classified into 2 types:
+ * - Type0: Can be transmitted with HDCP 1.4+
+ * - Type1: Can be transmitted with HDCP 2.2+
+ */
+#define HDCP_STREAM_TYPE0                      0x00
+#define HDCP_STREAM_TYPE1                      0x01
+
+/* HDCP2.2 Msg IDs */
+#define HDCP_2_2_NULL_MSG                      1
+#define HDCP_2_2_AKE_INIT                      2
+#define HDCP_2_2_AKE_SEND_CERT                 3
+#define HDCP_2_2_AKE_NO_STORED_KM              4
+#define HDCP_2_2_AKE_STORED_KM                 5
+#define HDCP_2_2_AKE_SEND_HPRIME               7
+#define HDCP_2_2_AKE_SEND_PAIRING_INFO         8
+#define HDCP_2_2_LC_INIT                       9
+#define HDCP_2_2_LC_SEND_LPRIME                        10
+#define HDCP_2_2_SKE_SEND_EKS                  11
+#define HDCP_2_2_REP_SEND_RECVID_LIST          12
+#define HDCP_2_2_REP_SEND_ACK                  15
+#define HDCP_2_2_REP_STREAM_MANAGE             16
+#define HDCP_2_2_REP_STREAM_READY              17
+#define HDCP_2_2_ERRATA_DP_STREAM_TYPE         50
+
+#define HDCP_2_2_RTX_LEN                       8
+#define HDCP_2_2_RRX_LEN                       8
+
+#define HDCP_2_2_K_PUB_RX_MOD_N_LEN            128
+#define HDCP_2_2_K_PUB_RX_EXP_E_LEN            3
+#define HDCP_2_2_K_PUB_RX_LEN                  (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \
+                                                HDCP_2_2_K_PUB_RX_EXP_E_LEN)
+
+#define HDCP_2_2_DCP_LLC_SIG_LEN               384
+
+#define HDCP_2_2_E_KPUB_KM_LEN                 128
+#define HDCP_2_2_E_KH_KM_M_LEN                 (16 + 16)
+#define HDCP_2_2_H_PRIME_LEN                   32
+#define HDCP_2_2_E_KH_KM_LEN                   16
+#define HDCP_2_2_RN_LEN                                8
+#define HDCP_2_2_L_PRIME_LEN                   32
+#define HDCP_2_2_E_DKEY_KS_LEN                 16
+#define HDCP_2_2_RIV_LEN                       8
+#define HDCP_2_2_SEQ_NUM_LEN                   3
+#define HDCP_2_2_V_PRIME_HALF_LEN              (HDCP_2_2_L_PRIME_LEN / 2)
+#define HDCP_2_2_RECEIVER_ID_LEN               DRM_HDCP_KSV_LEN
+#define HDCP_2_2_MAX_DEVICE_COUNT              31
+#define HDCP_2_2_RECEIVER_IDS_MAX_LEN          (HDCP_2_2_RECEIVER_ID_LEN * \
+                                                HDCP_2_2_MAX_DEVICE_COUNT)
+#define HDCP_2_2_MPRIME_LEN                    32
+
+/* Following Macros take a byte at a time for bit(s) masking */
+/*
+ * TODO: This has to be changed for DP MST, as multiple stream on
+ * same port is possible.
+ * For HDCP2.2 on HDMI and DP SST this value is always 1.
+ */
+#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT       1
+#define HDCP_2_2_TXCAP_MASK_LEN                        2
+#define HDCP_2_2_RXCAPS_LEN                    3
+#define HDCP_2_2_RX_REPEATER(x)                        ((x) & BIT(0))
+#define HDCP_2_2_DP_HDCP_CAPABLE(x)            ((x) & BIT(1))
+#define HDCP_2_2_RXINFO_LEN                    2
+
+/* HDCP1.x compliant device in downstream */
+#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x)     ((x) & BIT(0))
+
+/* HDCP2.0 Compliant repeater in downstream */
+#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x)     ((x) & BIT(1))
+#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x)       ((x) & BIT(2))
+#define HDCP_2_2_MAX_DEVS_EXCEEDED(x)          ((x) & BIT(3))
+#define HDCP_2_2_DEV_COUNT_LO(x)               (((x) & (0xF << 4)) >> 4)
+#define HDCP_2_2_DEV_COUNT_HI(x)               ((x) & BIT(0))
+#define HDCP_2_2_DEPTH(x)                      (((x) & (0x7 << 1)) >> 1)
+
+struct hdcp2_cert_rx {
+       u8      receiver_id[HDCP_2_2_RECEIVER_ID_LEN];
+       u8      kpub_rx[HDCP_2_2_K_PUB_RX_LEN];
+       u8      reserved[2];
+       u8      dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN];
+} __packed;
+
+struct hdcp2_streamid_type {
+       u8      stream_id;
+       u8      stream_type;
+} __packed;
+
+/*
+ * The TxCaps field specified in the HDCP HDMI, DP specs
+ * This field is big endian as specified in the errata.
+ */
+struct hdcp2_tx_caps {
+       /* Transmitter must set this to 0x2 */
+       u8      version;
+
+       /* Reserved for HDCP and DP Spec. Read as Zero */
+       u8      tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN];
+} __packed;
+
+/* Main structures for HDCP2.2 protocol communication */
+struct hdcp2_ake_init {
+       u8                      msg_id;
+       u8                      r_tx[HDCP_2_2_RTX_LEN];
+       struct hdcp2_tx_caps    tx_caps;
+} __packed;
+
+struct hdcp2_ake_send_cert {
+       u8                      msg_id;
+       struct hdcp2_cert_rx    cert_rx;
+       u8                      r_rx[HDCP_2_2_RRX_LEN];
+       u8                      rx_caps[HDCP_2_2_RXCAPS_LEN];
+} __packed;
+
+struct hdcp2_ake_no_stored_km {
+       u8      msg_id;
+       u8      e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN];
+} __packed;
+
+struct hdcp2_ake_stored_km {
+       u8      msg_id;
+       u8      e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN];
+} __packed;
+
+struct hdcp2_ake_send_hprime {
+       u8      msg_id;
+       u8      h_prime[HDCP_2_2_H_PRIME_LEN];
+} __packed;
+
+struct hdcp2_ake_send_pairing_info {
+       u8      msg_id;
+       u8      e_kh_km[HDCP_2_2_E_KH_KM_LEN];
+} __packed;
+
+struct hdcp2_lc_init {
+       u8      msg_id;
+       u8      r_n[HDCP_2_2_RN_LEN];
+} __packed;
+
+struct hdcp2_lc_send_lprime {
+       u8      msg_id;
+       u8      l_prime[HDCP_2_2_L_PRIME_LEN];
+} __packed;
+
+struct hdcp2_ske_send_eks {
+       u8      msg_id;
+       u8      e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN];
+       u8      riv[HDCP_2_2_RIV_LEN];
+} __packed;
+
+struct hdcp2_rep_send_receiverid_list {
+       u8      msg_id;
+       u8      rx_info[HDCP_2_2_RXINFO_LEN];
+       u8      seq_num_v[HDCP_2_2_SEQ_NUM_LEN];
+       u8      v_prime[HDCP_2_2_V_PRIME_HALF_LEN];
+       u8      receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN];
+} __packed;
+
+struct hdcp2_rep_send_ack {
+       u8      msg_id;
+       u8      v[HDCP_2_2_V_PRIME_HALF_LEN];
+} __packed;
+
+struct hdcp2_rep_stream_manage {
+       u8                      msg_id;
+       u8                      seq_num_m[HDCP_2_2_SEQ_NUM_LEN];
+       __be16                  k;
+       struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT];
+} __packed;
+
+struct hdcp2_rep_stream_ready {
+       u8      msg_id;
+       u8      m_prime[HDCP_2_2_MPRIME_LEN];
+} __packed;
+
+struct hdcp2_dp_errata_stream_type {
+       u8      msg_id;
+       u8      stream_type;
+} __packed;
+
+/* HDCP2.2 TIMEOUTs in mSec */
+#define HDCP_2_2_CERT_TIMEOUT_MS               100
+#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS   1000
+#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS      200
+#define HDCP_2_2_PAIRING_TIMEOUT_MS            200
+#define        HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS         20
+#define HDCP_2_2_DP_LPRIME_TIMEOUT_MS          7
+#define HDCP_2_2_RECVID_LIST_TIMEOUT_MS                3000
+#define HDCP_2_2_STREAM_READY_TIMEOUT_MS       100
+
+/* HDMI HDCP2.2 Register Offsets */
+#define HDCP_2_2_HDMI_REG_VER_OFFSET           0x50
+#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET                0x60
+#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET      0x70
+#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET                0x80
+#define HDCP_2_2_HDMI_REG_DBG_OFFSET           0xC0
+
+#define HDCP_2_2_HDMI_SUPPORT_MASK             BIT(2)
+#define HDCP_2_2_RX_CAPS_VERSION_VAL           0x02
+#define HDCP_2_2_SEQ_NUM_MAX                   0xFFFFFF
+#define        HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN     200
+
+/* Below macros take a byte at a time and mask the bit(s) */
+#define HDCP_2_2_HDMI_RXSTATUS_LEN             2
+#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x)    ((x) & 0x3)
+#define HDCP_2_2_HDMI_RXSTATUS_READY(x)                ((x) & BIT(2))
+#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x)   ((x) & BIT(3))
+
 #endif
index 4fef19064b0f12cad6b70614112493fd54e51729..491528f48cfb220e88b62aa7c00ae445894b723e 100644 (file)
@@ -168,6 +168,12 @@ struct mipi_dsi_device_info {
  * @format: pixel format for video mode
  * @lanes: number of active data lanes
  * @mode_flags: DSI operation mode related flags
+ * @hs_rate: maximum lane frequency for high speed mode in hertz, this should
+ * be set to the real limits of the hardware, zero is only accepted for
+ * legacy drivers
+ * @lp_rate: maximum lane frequency for low power mode in hertz, this should
+ * be set to the real limits of the hardware, zero is only accepted for
+ * legacy drivers
  */
 struct mipi_dsi_device {
        struct mipi_dsi_host *host;
@@ -178,6 +184,8 @@ struct mipi_dsi_device {
        unsigned int lanes;
        enum mipi_dsi_pixel_format format;
        unsigned long mode_flags;
+       unsigned long hs_rate;
+       unsigned long lp_rate;
 };
 
 #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
index 928e4172a0bbe277058f5c791cfa9070eca9a9ca..572274ccbec7426a26083fd5f8a951b7ff8a2dd2 100644 (file)
@@ -52,6 +52,12 @@ struct drm_mode_config_funcs {
         * requested metadata, but most of that is left to the driver. See
         * &struct drm_mode_fb_cmd2 for details.
         *
+        * To validate the pixel format and modifier drivers can use
+        * drm_any_plane_has_format() to make sure at least one plane supports
+        * the requested values. Note that the driver must first determine the
+        * actual modifier used if the request doesn't have it specified,
+        * ie. when (@mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0.
+        *
         * If the parameters are deemed valid and the backing storage objects in
         * the underlying memory manager all exist, then the driver allocates
         * a new &drm_framebuffer structure, subclassed to contain
@@ -627,6 +633,15 @@ struct drm_mode_config {
         * &drm_crtc.
         */
        struct drm_property *prop_crtc_id;
+       /**
+        * @prop_fb_damage_clips: Optional plane property to mark damaged
+        * regions on the plane in framebuffer coordinates of the framebuffer
+        * attached to the plane.
+        *
+        * The layout of blob data is simply an array of &drm_mode_rect. Unlike
+        * plane src coordinates, damage clips are not in 16.16 fixed point.
+        */
+       struct drm_property *prop_fb_damage_clips;
        /**
         * @prop_active: Default atomic CRTC property to control the active
         * state, which is the simplified implementation for DPMS in atomic
@@ -639,6 +654,11 @@ struct drm_mode_config {
         * connectors must be of and active must be set to disabled, too.
         */
        struct drm_property *prop_mode_id;
+       /**
+        * @prop_vrr_enabled: Default atomic CRTC property to indicate
+        * whether variable refresh rate should be enabled on the CRTC.
+        */
+       struct drm_property *prop_vrr_enabled;
 
        /**
         * @dvi_i_subconnector_property: Optional DVI-I property to
@@ -809,6 +829,13 @@ struct drm_mode_config {
 
        /* dumb ioctl parameters */
        uint32_t preferred_depth, prefer_shadow;
+
+       /**
+        * @quirk_addfb_prefer_xbgr_30bpp:
+        *
+        * Special hack for legacy ADDFB to keep nouveau userspace happy. Should
+        * only ever be set by the nouveau kernel driver.
+        */
        bool quirk_addfb_prefer_xbgr_30bpp;
 
        /**
index a685d1bb21f262a256e3b5f6115d915e9d1d04e2..a308f2d6496f024f250349af24cf0f357ce194ec 100644 (file)
@@ -130,4 +130,63 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 int drm_modeset_lock_all_ctx(struct drm_device *dev,
                             struct drm_modeset_acquire_ctx *ctx);
 
+/**
+ * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks
+ * @dev: drm device
+ * @ctx: local modeset acquire context, will be dereferenced
+ * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init()
+ * @ret: local ret/err/etc variable to track error status
+ *
+ * Use these macros to simplify grabbing all modeset locks using a local
+ * context. This has the advantage of reducing boilerplate, but also properly
+ * checking return values where appropriate.
+ *
+ * Any code run between BEGIN and END will be holding the modeset locks.
+ *
+ * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and
+ * forth between the labels on deadlock and error conditions.
+ *
+ * Drivers can acquire additional modeset locks. If any lock acquisition
+ * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with
+ * the @ret parameter containing the return value of drm_modeset_lock().
+ *
+ * Returns:
+ * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN()
+ * is 0, so no error checking is necessary
+ */
+#define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret)               \
+       drm_modeset_acquire_init(&ctx, flags);                          \
+modeset_lock_retry:                                                    \
+       ret = drm_modeset_lock_all_ctx(dev, &ctx);                      \
+       if (ret)                                                        \
+               goto modeset_lock_fail;
+
+/**
+ * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks
+ * @ctx: local modeset acquire context, will be dereferenced
+ * @ret: local ret/err/etc variable to track error status
+ *
+ * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN
+ * if ret is -EDEADLK.
+ *
+ * It's important that you use the same ret variable for begin and end so
+ * deadlock conditions are properly handled.
+ *
+ * Returns:
+ * ret will be untouched unless it is -EDEADLK on entry. That means that if you
+ * successfully acquire the locks, ret will be whatever your code sets it to. If
+ * there is a deadlock or other failure with acquire or backoff, ret will be set
+ * to that failure. In both of these cases the code between BEGIN/END will not
+ * be run, so the failure will reflect the inability to grab the locks.
+ */
+#define DRM_MODESET_LOCK_ALL_END(ctx, ret)                             \
+modeset_lock_fail:                                                     \
+       if (ret == -EDEADLK) {                                          \
+               ret = drm_modeset_backoff(&ctx);                        \
+               if (!ret)                                               \
+                       goto modeset_lock_retry;                        \
+       }                                                               \
+       drm_modeset_drop_locks(&ctx);                                   \
+       drm_modeset_acquire_fini(&ctx);
+
 #endif /* DRM_MODESET_LOCK_H_ */
index 0a0834bef8bd2c0f8f54fac4511cd2fc46451dd9..6078c700d9ba547c6aba90d83df7bec4fa8bbb7e 100644 (file)
@@ -173,6 +173,16 @@ struct drm_plane_state {
         */
        enum drm_color_range color_range;
 
+       /**
+        * @fb_damage_clips:
+        *
+        * Blob representing damage (area in plane framebuffer that changed
+        * since last plane update) as an array of &drm_mode_rect in framebuffer
+        * coodinates of the attached framebuffer. Note that unlike plane src,
+        * damage clips are not in 16.16 fixed point.
+        */
+       struct drm_property_blob *fb_damage_clips;
+
        /** @src: clipped source coordinates of the plane (in 16.16) */
        /** @dst: clipped destination coordinates of the plane */
        struct drm_rect src, dst;
@@ -798,5 +808,39 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
 #define drm_for_each_plane(plane, dev) \
        list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
 
+bool drm_any_plane_has_format(struct drm_device *dev,
+                             u32 format, u64 modifier);
+/**
+ * drm_plane_get_damage_clips_count - Returns damage clips count.
+ * @state: Plane state.
+ *
+ * Simple helper to get the number of &drm_mode_rect clips set by user-space
+ * during plane update.
+ *
+ * Return: Number of clips in plane fb_damage_clips blob property.
+ */
+static inline unsigned int
+drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
+{
+       return (state && state->fb_damage_clips) ?
+               state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
+}
+
+/**
+ * drm_plane_get_damage_clips - Returns damage clips.
+ * @state: Plane state.
+ *
+ * Note that this function returns uapi type &drm_mode_rect. Drivers might
+ * instead be interested in internal &drm_rect which can be obtained by calling
+ * drm_helper_get_plane_damage_clips().
+ *
+ * Return: Damage clips in plane fb_damage_clips blob property.
+ */
+static inline struct drm_mode_rect *
+drm_plane_get_damage_clips(const struct drm_plane_state *state)
+{
+       return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
+                                       state->fb_damage_clips->data : NULL);
+}
 
 #endif
index 26cee29347819fc41b0dcc1bd7697f8a20c92faa..331ebd60b3a39ab58ae84bfbadd50604d27da5ac 100644 (file)
  */
 #define DRM_PLANE_HELPER_NO_SCALING (1<<16)
 
-int drm_plane_helper_check_update(struct drm_plane *plane,
-                                 struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_rect *src,
-                                 struct drm_rect *dest,
-                                 unsigned int rotation,
-                                 int min_scale,
-                                 int max_scale,
-                                 bool can_position,
-                                 bool can_update_disabled,
-                                 bool *visible);
-int drm_primary_helper_update(struct drm_plane *plane,
-                             struct drm_crtc *crtc,
-                             struct drm_framebuffer *fb,
-                             int crtc_x, int crtc_y,
-                             unsigned int crtc_w, unsigned int crtc_h,
-                             uint32_t src_x, uint32_t src_y,
-                             uint32_t src_w, uint32_t src_h,
-                             struct drm_modeset_acquire_ctx *ctx);
-int drm_primary_helper_disable(struct drm_plane *plane,
-                              struct drm_modeset_acquire_ctx *ctx);
 void drm_primary_helper_destroy(struct drm_plane *plane);
 extern const struct drm_plane_funcs drm_primary_helper_funcs;
 
-int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
-                           struct drm_framebuffer *fb,
-                           int crtc_x, int crtc_y,
-                           unsigned int crtc_w, unsigned int crtc_h,
-                           uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h,
-                           struct drm_modeset_acquire_ctx *ctx);
-int drm_plane_helper_disable(struct drm_plane *plane,
-                            struct drm_modeset_acquire_ctx *ctx);
-
-/* For use by drm_crtc_helper.c */
-int drm_plane_helper_commit(struct drm_plane *plane,
-                           struct drm_plane_state *plane_state,
-                           struct drm_framebuffer *old_fb);
 #endif
index d716d653b096465805e0e5c2f26c3bd0e388a708..b03731a3f079637db295fd02e5735a82d7fa038b 100644 (file)
@@ -70,6 +70,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
 int drm_gem_prime_handle_to_fd(struct drm_device *dev,
                               struct drm_file *file_priv, uint32_t handle, uint32_t flags,
                               int *prime_fd);
+int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                                            struct dma_buf *dma_buf);
 
@@ -93,9 +94,6 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
                           enum dma_data_direction dir);
 void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf);
 void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr);
-void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num);
-void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
-                          void *addr);
 int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma);
 
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
index 5b9efff35d6d2cfedff6a157e896f2a548eb934f..4a0a80d658c723db7d8ff5d71627e2f5d32c2765 100644 (file)
@@ -153,7 +153,8 @@ struct drm_property {
         *     userspace. The kernel is allowed to update the value of these
         *     properties. This is generally used to expose probe state to
         *     userspace, e.g. the EDID, or the connector path property on DP
-        *     MST sinks.
+        *     MST sinks. Kernel can update the value of an immutable property
+        *     by calling drm_object_property_set_value().
         */
        uint32_t flags;
 
index 425432b85a87a0ceef900430e81b42c232cfbd96..b1fe921f8e8f23132f1411e84a44a13e97411f69 100644 (file)
@@ -131,10 +131,10 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj)
 
 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
                                     u32 handle);
-void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
+void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
                               struct dma_fence *fence);
 int drm_syncobj_find_fence(struct drm_file *file_private,
-                          u32 handle, u64 point,
+                          u32 handle, u64 point, u64 flags,
                           struct dma_fence **fence);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
index d25a9603ab570518eb38945a920f459dae343397..6ad9630d4f48e04c991a68753e580c7f173e51d9 100644 (file)
@@ -95,7 +95,7 @@ struct drm_vblank_crtc {
        /**
         * @queue: Wait queue for vblank waiters.
         */
-       wait_queue_head_t queue;        /**< VBLANK wait queue */
+       wait_queue_head_t queue;
        /**
         * @disable_timer: Disable timer for the delayed vblank disabling
         * hysteresis logic. Vblank disabling is controlled through the
@@ -107,7 +107,7 @@ struct drm_vblank_crtc {
        /**
         * @seqlock: Protect vblank count and time.
         */
-       seqlock_t seqlock;              /* protects vblank count and time */
+       seqlock_t seqlock;
 
        /**
         * @count: Current software vblank counter.
@@ -123,7 +123,7 @@ struct drm_vblank_crtc {
         * this refcount reaches 0 can the hardware interrupt be disabled using
         * @disable_timer.
         */
-       atomic_t refcount;              /* number of users of vblank interruptsper crtc */
+       atomic_t refcount;
        /**
         * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
         */
@@ -136,7 +136,7 @@ struct drm_vblank_crtc {
         * call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly
         * save and restore the vblank count.
         */
-       unsigned int inmodeset;         /* Display driver is setting mode */
+       unsigned int inmodeset;
        /**
         * @pipe: drm_crtc_index() of the &drm_crtc corresponding to this
         * structure.
index d87b268f1781cb50fd8674d6349a0626760e125f..47e19796c45087f76664b161d5e1a9b654ed9f2b 100644 (file)
@@ -264,6 +264,7 @@ struct drm_sched_backend_ops {
  * @hang_limit: once the hangs by a job crosses this limit then it is marked
  *              guilty and it will be considered for scheduling further.
  * @num_jobs: the number of jobs in queue in the scheduler
+ * @ready: marks if the underlying HW is ready to work
  *
  * One scheduler is implemented for each hardware ring.
  */
@@ -283,22 +284,26 @@ struct drm_gpu_scheduler {
        spinlock_t                      job_list_lock;
        int                             hang_limit;
        atomic_t                        num_jobs;
+       bool                    ready;
 };
 
 int drm_sched_init(struct drm_gpu_scheduler *sched,
                   const struct drm_sched_backend_ops *ops,
                   uint32_t hw_submission, unsigned hang_limit, long timeout,
                   const char *name);
+
 void drm_sched_fini(struct drm_gpu_scheduler *sched);
 int drm_sched_job_init(struct drm_sched_job *job,
                       struct drm_sched_entity *entity,
                       void *owner);
+void drm_sched_job_cleanup(struct drm_sched_job *job);
 void drm_sched_wakeup(struct drm_gpu_scheduler *sched);
 void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched,
                            struct drm_sched_job *job);
 void drm_sched_job_recovery(struct drm_gpu_scheduler *sched);
 bool drm_sched_dependency_optimized(struct dma_fence* fence,
                                    struct drm_sched_entity *entity);
+void drm_sched_fault(struct drm_gpu_scheduler *sched);
 void drm_sched_job_kickout(struct drm_sched_job *s_job);
 
 void drm_sched_rq_add_entity(struct drm_sched_rq *rq,
@@ -326,4 +331,8 @@ struct drm_sched_fence *drm_sched_fence_create(
 void drm_sched_fence_scheduled(struct drm_sched_fence *fence);
 void drm_sched_fence_finished(struct drm_sched_fence *fence);
 
+unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched);
+void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
+                               unsigned long remaining);
+
 #endif
index fd965ffbb92e33fcef415033b1a78a09849bda05..192667144693a0ab3adb7ae12d04a420b7567b37 100644 (file)
        INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */
 
 /* AML/KBL Y GT2 */
-#define INTEL_AML_GT2_IDS(info) \
+#define INTEL_AML_KBL_GT2_IDS(info) \
        INTEL_VGA_DEVICE(0x591C, info),  /* ULX GT2 */ \
        INTEL_VGA_DEVICE(0x87C0, info) /* ULX GT2 */
 
+/* AML/CFL Y GT2 */
+#define INTEL_AML_CFL_GT2_IDS(info) \
+       INTEL_VGA_DEVICE(0x87CA, info)
+
 #define INTEL_KBL_IDS(info) \
        INTEL_KBL_GT1_IDS(info), \
        INTEL_KBL_GT2_IDS(info), \
        INTEL_KBL_GT3_IDS(info), \
        INTEL_KBL_GT4_IDS(info), \
-       INTEL_AML_GT2_IDS(info)
+       INTEL_AML_KBL_GT2_IDS(info)
 
 /* CFL S */
 #define INTEL_CFL_S_GT1_IDS(info) \
 
 /* WHL/CFL U GT1 */
 #define INTEL_WHL_U_GT1_IDS(info) \
-       INTEL_VGA_DEVICE(0x3EA1, info)
+       INTEL_VGA_DEVICE(0x3EA1, info), \
+       INTEL_VGA_DEVICE(0x3EA4, info)
 
 /* WHL/CFL U GT2 */
 #define INTEL_WHL_U_GT2_IDS(info) \
-       INTEL_VGA_DEVICE(0x3EA0, info)
+       INTEL_VGA_DEVICE(0x3EA0, info), \
+       INTEL_VGA_DEVICE(0x3EA3, info)
 
 /* WHL/CFL U GT3 */
 #define INTEL_WHL_U_GT3_IDS(info) \
-       INTEL_VGA_DEVICE(0x3EA2, info), \
-       INTEL_VGA_DEVICE(0x3EA3, info), \
-       INTEL_VGA_DEVICE(0x3EA4, info)
+       INTEL_VGA_DEVICE(0x3EA2, info)
 
 #define INTEL_CFL_IDS(info)       \
        INTEL_CFL_S_GT1_IDS(info), \
        INTEL_CFL_U_GT3_IDS(info), \
        INTEL_WHL_U_GT1_IDS(info), \
        INTEL_WHL_U_GT2_IDS(info), \
-       INTEL_WHL_U_GT3_IDS(info)
+       INTEL_WHL_U_GT3_IDS(info), \
+       INTEL_AML_CFL_GT2_IDS(info)
 
 /* CNL */
 #define INTEL_CNL_IDS(info) \
index fe9827d0ca8a5c9c5d1c7245dc6d49c4c2b238e7..448aa5ea4722da2007fcfe8ee79855ccb22bb6ef 100644 (file)
 #ifndef __LINUX_TINYDRM_H
 #define __LINUX_TINYDRM_H
 
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
+#include <linux/mutex.h>
 #include <drm/drm_simple_kms_helper.h>
 
+struct drm_clip_rect;
+struct drm_driver;
+struct drm_file;
+struct drm_framebuffer;
+struct drm_framebuffer_funcs;
+
 /**
  * struct tinydrm_device - tinydrm device
  */
@@ -53,27 +58,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
        return container_of(pipe, struct tinydrm_device, pipe);
 }
 
-/**
- * TINYDRM_GEM_DRIVER_OPS - default tinydrm gem operations
- *
- * This macro provides a shortcut for setting the tinydrm GEM operations in
- * the &drm_driver structure.
- */
-#define TINYDRM_GEM_DRIVER_OPS \
-       .gem_free_object_unlocked = tinydrm_gem_cma_free_object, \
-       .gem_print_info         = drm_gem_cma_print_info, \
-       .gem_vm_ops             = &drm_gem_cma_vm_ops, \
-       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd, \
-       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle, \
-       .gem_prime_import       = drm_gem_prime_import, \
-       .gem_prime_export       = drm_gem_prime_export, \
-       .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, \
-       .gem_prime_import_sg_table = tinydrm_gem_cma_prime_import_sg_table, \
-       .gem_prime_vmap         = drm_gem_cma_prime_vmap, \
-       .gem_prime_vunmap       = drm_gem_cma_prime_vunmap, \
-       .gem_prime_mmap         = drm_gem_cma_prime_mmap, \
-       .dumb_create            = drm_gem_cma_dumb_create
-
 /**
  * TINYDRM_MODE - tinydrm display mode
  * @hd: Horizontal resolution, width
@@ -97,11 +81,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
        .type = DRM_MODE_TYPE_DRIVER, \
        .clock = 1 /* pass validation */
 
-void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj);
-struct drm_gem_object *
-tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
-                                     struct dma_buf_attachment *attach,
-                                     struct sg_table *sgt);
 int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
                      const struct drm_framebuffer_funcs *fb_funcs,
                      struct drm_driver *driver);
index e4fee8e02559be50a8646710a7370d3033135455..1021106438b2a581c9ba642caf68bac2411f7694 100644 (file)
@@ -31,7 +31,6 @@
 #define _TTM_BO_DRIVER_H_
 
 #include <drm/drm_mm.h>
-#include <drm/drm_global.h>
 #include <drm/drm_vma_manager.h>
 #include <linux/workqueue.h>
 #include <linux/fs.h>
@@ -384,15 +383,6 @@ struct ttm_bo_driver {
                             void *buf, int len, int write);
 };
 
-/**
- * struct ttm_bo_global_ref - Argument to initialize a struct ttm_bo_global.
- */
-
-struct ttm_bo_global_ref {
-       struct drm_global_reference ref;
-       struct ttm_mem_global *mem_glob;
-};
-
 /**
  * struct ttm_bo_global - Buffer object driver global data.
  *
@@ -407,7 +397,7 @@ struct ttm_bo_global_ref {
  * @swap_lru: Lru list of buffer objects used for swapping.
  */
 
-struct ttm_bo_global {
+extern struct ttm_bo_global {
 
        /**
         * Constant after init.
@@ -416,12 +406,12 @@ struct ttm_bo_global {
        struct kobject kobj;
        struct ttm_mem_global *mem_glob;
        struct page *dummy_read_page;
-       struct mutex device_list_mutex;
        spinlock_t lru_lock;
 
        /**
-        * Protected by device_list_mutex.
+        * Protected by ttm_global_mutex.
         */
+       unsigned int use_count;
        struct list_head device_list;
 
        /**
@@ -433,7 +423,7 @@ struct ttm_bo_global {
         * Internal protection.
         */
        atomic_t bo_count;
-};
+} ttm_bo_glob;
 
 
 #define TTM_NUM_MEM_TYPES 8
@@ -578,9 +568,6 @@ void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem);
 void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo,
                           struct ttm_mem_reg *mem);
 
-void ttm_bo_global_release(struct drm_global_reference *ref);
-int ttm_bo_global_init(struct drm_global_reference *ref);
-
 int ttm_bo_device_release(struct ttm_bo_device *bdev);
 
 /**
@@ -598,7 +585,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev);
  * Returns:
  * !0: Failure.
  */
-int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_global *glob,
+int ttm_bo_device_init(struct ttm_bo_device *bdev,
                       struct ttm_bo_driver *driver,
                       struct address_space *mapping,
                       uint64_t file_page_offset, bool need_dma32);
index b0fdd1980034c592c5fdcb64cd05d5ee29df91d8..621615fa7728f1553afd7167f5398ae41a892a37 100644 (file)
  *
  * @head:           list head for thread-private list.
  * @bo:             refcounted buffer object pointer.
- * @shared:         should the fence be added shared?
+ * @num_shared:     How many shared fences we want to add.
  */
 
 struct ttm_validate_buffer {
        struct list_head head;
        struct ttm_buffer_object *bo;
-       bool shared;
+       unsigned int num_shared;
 };
 
 /**
index 737b5fed80031bac39aa1a59b65a3f2a6da42d11..3ff48a0a2d7b7728469034430434a311e4bbcb40 100644 (file)
@@ -63,7 +63,7 @@
 
 #define TTM_MEM_MAX_ZONES 2
 struct ttm_mem_zone;
-struct ttm_mem_global {
+extern struct ttm_mem_global {
        struct kobject kobj;
        struct ttm_bo_global *bo_glob;
        struct workqueue_struct *swap_queue;
@@ -78,7 +78,7 @@ struct ttm_mem_global {
 #else
        struct ttm_mem_zone *zone_dma32;
 #endif
-};
+} ttm_mem_glob;
 
 extern int ttm_mem_global_init(struct ttm_mem_global *glob);
 extern void ttm_mem_global_release(struct ttm_mem_global *glob);
index 6298fec0068545d116e9e833eaabbf84ede218e9..94ed3edfcc70066ab532774509fba353e31a6c91 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Core
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __DT_BINDINGS_MEDIA_XILINX_VIP_H__
diff --git a/include/dt-bindings/regulator/active-semi,8945a-regulator.h b/include/dt-bindings/regulator/active-semi,8945a-regulator.h
new file mode 100644 (file)
index 0000000..9bdba5e
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 Microchip Technology, Inc. All rights reserved.
+ *
+ * Device Tree binding constants for the ACT8945A PMIC regulators
+ */
+
+#ifndef _DT_BINDINGS_REGULATOR_ACT8945A_H
+#define _DT_BINDINGS_REGULATOR_ACT8945A_H
+
+/*
+ * These constants should be used to specify regulator modes in device tree for
+ * ACT8945A regulators as follows:
+ * ACT8945A_REGULATOR_MODE_FIXED:      It is specific to DCDC regulators and it
+ *                                     specifies the usage of fixed-frequency
+ *                                     PWM.
+ *
+ * ACT8945A_REGULATOR_MODE_NORMAL:     It is specific to LDO regulators and it
+ *                                     specifies the usage of normal mode.
+ *
+ * ACT8945A_REGULATOR_MODE_LOWPOWER:   For DCDC and LDO regulators; it specify
+ *                                     the usage of proprietary power-saving
+ *                                     mode.
+ */
+
+#define ACT8945A_REGULATOR_MODE_FIXED          1
+#define ACT8945A_REGULATOR_MODE_NORMAL         2
+#define ACT8945A_REGULATOR_MODE_LOWPOWER       3
+
+#endif
index e2d3892240b868af2a210e66fd48c2024ebd5f0e..1df06f8ad5c39249688b2ac43a4b3d73f3d7f2b3 100644 (file)
 #define QUINARY_TDM_TX_6       101
 #define QUINARY_TDM_RX_7       102
 #define QUINARY_TDM_TX_7       103
+#define DISPLAY_PORT_RX                104
 
 #endif /* __DT_BINDINGS_Q6_AFE_H__ */
 
index ed80f147bd5089739a33651e8ac97b53fecc2a65..4b3283cb09ab48b19dd4ec0bdb77ea5b13500353 100644 (file)
@@ -101,7 +101,7 @@ static inline bool has_acpi_companion(struct device *dev)
 static inline void acpi_preset_companion(struct device *dev,
                                         struct acpi_device *parent, u64 addr)
 {
-       ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL));
+       ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, false));
 }
 
 static inline const char *acpi_dev_name(struct acpi_device *adev)
@@ -340,7 +340,14 @@ struct pci_dev;
 int acpi_pci_irq_enable (struct pci_dev *dev);
 void acpi_penalize_isa_irq(int irq, int active);
 bool acpi_isa_irq_available(int irq);
+#ifdef CONFIG_PCI
 void acpi_penalize_sci_irq(int irq, int trigger, int polarity);
+#else
+static inline void acpi_penalize_sci_irq(int irq, int trigger,
+                                       int polarity)
+{
+}
+#endif
 void acpi_pci_irq_disable (struct pci_dev *dev);
 
 extern int ec_read(u8 addr, u8 *val);
@@ -1054,6 +1061,17 @@ static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
 }
 #endif
 
+#if defined(CONFIG_ACPI) && IS_ENABLED(CONFIG_I2C)
+bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
+                              struct acpi_resource_i2c_serialbus **i2c);
+#else
+static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
+                                            struct acpi_resource_i2c_serialbus **i2c)
+{
+       return false;
+}
+#endif
+
 /* Device properties */
 
 #ifdef CONFIG_ACPI
index 2d29f55923e3ad2e79c70cd0832a8c8523f96ef8..2a629acb4c3f467221c8db81ded322780f31b99a 100644 (file)
@@ -7,12 +7,7 @@
 #ifndef _LINUX_ADXL_H
 #define _LINUX_ADXL_H
 
-#ifdef CONFIG_ACPI_ADXL
 const char * const *adxl_get_component_names(void);
 int adxl_decode(u64 addr, u64 component_values[]);
-#else
-static inline const char * const *adxl_get_component_names(void)  { return NULL; }
-static inline int adxl_decode(u64 addr, u64 component_values[])   { return  -EOPNOTSUPP; }
-#endif
 
 #endif /* _LINUX_ADXL_H */
index 06396c1cf127f75bb357326883f1dcb69161ccf1..fc5004a4b07d7b5b546e07f7d952fd1094892ead 100644 (file)
@@ -99,13 +99,22 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  * unique, to convince GCC not to merge duplicate inline asm statements.
  */
 #define annotate_reachable() ({                                                \
-       asm volatile("ANNOTATE_REACHABLE counter=%c0"                   \
-                    : : "i" (__COUNTER__));                            \
+       asm volatile("%c0:\n\t"                                         \
+                    ".pushsection .discard.reachable\n\t"              \
+                    ".long %c0b - .\n\t"                               \
+                    ".popsection\n\t" : : "i" (__COUNTER__));          \
 })
 #define annotate_unreachable() ({                                      \
-       asm volatile("ANNOTATE_UNREACHABLE counter=%c0"                 \
-                    : : "i" (__COUNTER__));                            \
+       asm volatile("%c0:\n\t"                                         \
+                    ".pushsection .discard.unreachable\n\t"            \
+                    ".long %c0b - .\n\t"                               \
+                    ".popsection\n\t" : : "i" (__COUNTER__));          \
 })
+#define ASM_UNREACHABLE                                                        \
+       "999:\n\t"                                                      \
+       ".pushsection .discard.unreachable\n\t"                         \
+       ".long 999b - .\n\t"                                            \
+       ".popsection\n\t"
 #else
 #define annotate_reachable()
 #define annotate_unreachable()
@@ -293,45 +302,6 @@ static inline void *offset_to_ptr(const int *off)
        return (void *)((unsigned long)off + *off);
 }
 
-#else /* __ASSEMBLY__ */
-
-#ifdef __KERNEL__
-#ifndef LINKER_SCRIPT
-
-#ifdef CONFIG_STACK_VALIDATION
-.macro ANNOTATE_UNREACHABLE counter:req
-\counter:
-       .pushsection .discard.unreachable
-       .long \counter\()b -.
-       .popsection
-.endm
-
-.macro ANNOTATE_REACHABLE counter:req
-\counter:
-       .pushsection .discard.reachable
-       .long \counter\()b -.
-       .popsection
-.endm
-
-.macro ASM_UNREACHABLE
-999:
-       .pushsection .discard.unreachable
-       .long 999b - .
-       .popsection
-.endm
-#else /* CONFIG_STACK_VALIDATION */
-.macro ANNOTATE_UNREACHABLE counter:req
-.endm
-
-.macro ANNOTATE_REACHABLE counter:req
-.endm
-
-.macro ASM_UNREACHABLE
-.endm
-#endif /* CONFIG_STACK_VALIDATION */
-
-#endif /* LINKER_SCRIPT */
-#endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 
 /* Compile time object size, -1 for unknown */
index 4a3f9c09c92d04583f9a0d4fa335a1fb9ce44ab8..ba814f18cb4ce240d53b9d42aaa4a5117591dab8 100644 (file)
@@ -104,6 +104,60 @@ struct ftrace_likely_data {
        unsigned long                   constant;
 };
 
+#ifdef CONFIG_ENABLE_MUST_CHECK
+#define __must_check           __attribute__((__warn_unused_result__))
+#else
+#define __must_check
+#endif
+
+#if defined(CC_USING_HOTPATCH)
+#define notrace                        __attribute__((hotpatch(0, 0)))
+#else
+#define notrace                        __attribute__((__no_instrument_function__))
+#endif
+
+/*
+ * it doesn't make sense on ARM (currently the only user of __naked)
+ * to trace naked functions because then mcount is called without
+ * stack and frame pointer being set up and there is no chance to
+ * restore the lr register to the value before mcount was called.
+ */
+#define __naked                        __attribute__((__naked__)) notrace
+
+#define __compiler_offsetof(a, b)      __builtin_offsetof(a, b)
+
+/*
+ * Force always-inline if the user requests it so via the .config.
+ * GCC does not warn about unused static inline functions for
+ * -Wunused-function.  This turns out to avoid the need for complex #ifdef
+ * directives.  Suppress the warning in clang as well by using "unused"
+ * function attribute, which is redundant but not harmful for gcc.
+ * Prefer gnu_inline, so that extern inline functions do not emit an
+ * externally visible function. This makes extern inline behave as per gnu89
+ * semantics rather than c99. This prevents multiple symbol definition errors
+ * of extern inline functions at link time.
+ * A lot of inline functions can cause havoc with function tracing.
+ * Do not use __always_inline here, since currently it expands to inline again
+ * (which would break users of __always_inline).
+ */
+#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
+       !defined(CONFIG_OPTIMIZE_INLINING)
+#define inline inline __attribute__((__always_inline__)) __gnu_inline \
+       __maybe_unused notrace
+#else
+#define inline inline                                    __gnu_inline \
+       __maybe_unused notrace
+#endif
+
+#define __inline__ inline
+#define __inline   inline
+
+/*
+ * Rather then using noinline to prevent stack consumption, use
+ * noinline_for_stack instead.  For documentation reasons.
+ */
+#define noinline_for_stack noinline
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
@@ -161,58 +215,4 @@ struct ftrace_likely_data {
 #define __diag_error(compiler, version, option, comment) \
        __diag_ ## compiler(version, error, option)
 
-#ifdef CONFIG_ENABLE_MUST_CHECK
-#define __must_check           __attribute__((__warn_unused_result__))
-#else
-#define __must_check
-#endif
-
-#if defined(CC_USING_HOTPATCH)
-#define notrace                        __attribute__((hotpatch(0, 0)))
-#else
-#define notrace                        __attribute__((__no_instrument_function__))
-#endif
-
-/*
- * it doesn't make sense on ARM (currently the only user of __naked)
- * to trace naked functions because then mcount is called without
- * stack and frame pointer being set up and there is no chance to
- * restore the lr register to the value before mcount was called.
- */
-#define __naked                        __attribute__((__naked__)) notrace
-
-#define __compiler_offsetof(a, b)      __builtin_offsetof(a, b)
-
-/*
- * Force always-inline if the user requests it so via the .config.
- * GCC does not warn about unused static inline functions for
- * -Wunused-function.  This turns out to avoid the need for complex #ifdef
- * directives.  Suppress the warning in clang as well by using "unused"
- * function attribute, which is redundant but not harmful for gcc.
- * Prefer gnu_inline, so that extern inline functions do not emit an
- * externally visible function. This makes extern inline behave as per gnu89
- * semantics rather than c99. This prevents multiple symbol definition errors
- * of extern inline functions at link time.
- * A lot of inline functions can cause havoc with function tracing.
- * Do not use __always_inline here, since currently it expands to inline again
- * (which would break users of __always_inline).
- */
-#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
-       !defined(CONFIG_OPTIMIZE_INLINING)
-#define inline inline __attribute__((__always_inline__)) __gnu_inline \
-       __maybe_unused notrace
-#else
-#define inline inline                                    __gnu_inline \
-       __maybe_unused notrace
-#endif
-
-#define __inline__ inline
-#define __inline   inline
-
-/*
- * Rather then using noinline to prevent stack consumption, use
- * noinline_for_stack instead.  For documentation reasons.
- */
-#define noinline_for_stack noinline
-
 #endif /* __LINUX_COMPILER_TYPES_H */
index faed7a8977e85bd6e34f9803c75d9dfcc05d4803..4dff74f48d4b11024766303a4e0bd17379b26bdb 100644 (file)
@@ -33,6 +33,8 @@ struct cpuidle_state_usage {
        unsigned long long      disable;
        unsigned long long      usage;
        unsigned long long      time; /* in US */
+       unsigned long long      above; /* Number of times it's been too deep */
+       unsigned long long      below; /* Number of times it's been too shallow */
 #ifdef CONFIG_SUSPEND
        unsigned long long      s2idle_usage;
        unsigned long long      s2idle_time; /* in US */
diff --git a/include/linux/dell-led.h b/include/linux/dell-led.h
deleted file mode 100644 (file)
index 9252147..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __DELL_LED_H__
-#define __DELL_LED_H__
-
-int dell_micmute_led_set(int on);
-
-#endif
index e4963b0f45da9bc860150659d859a48a217a674d..fbffa74bfc1bb94c5099a21f438da2c95f251a5e 100644 (file)
@@ -131,6 +131,9 @@ struct devfreq_dev_profile {
  * @scaling_min_freq:  Limit minimum frequency requested by OPP interface
  * @scaling_max_freq:  Limit maximum frequency requested by OPP interface
  * @stop_polling:       devfreq polling status of a device.
+ * @suspend_freq:       frequency of a device set during suspend phase.
+ * @resume_freq:        frequency of a device set in resume phase.
+ * @suspend_count:      suspend requests counter for a device.
  * @total_trans:       Number of devfreq transitions
  * @trans_table:       Statistics of devfreq transitions
  * @time_in_state:     Statistics of devfreq states
@@ -167,6 +170,10 @@ struct devfreq {
        unsigned long scaling_max_freq;
        bool stop_polling;
 
+       unsigned long suspend_freq;
+       unsigned long resume_freq;
+       atomic_t suspend_count;
+
        /* information for device frequency transition */
        unsigned int total_trans;
        unsigned int *trans_table;
@@ -198,6 +205,9 @@ extern void devm_devfreq_remove_device(struct device *dev,
 extern int devfreq_suspend_device(struct devfreq *devfreq);
 extern int devfreq_resume_device(struct devfreq *devfreq);
 
+extern void devfreq_suspend(void);
+extern void devfreq_resume(void);
+
 /**
  * update_devfreq() - Reevaluate the device and configure frequency
  * @devfreq:   the devfreq device
@@ -324,6 +334,9 @@ static inline int devfreq_resume_device(struct devfreq *devfreq)
        return 0;
 }
 
+static inline void devfreq_suspend(void) {}
+static inline void devfreq_resume(void) {}
+
 static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
                                           unsigned long *freq, u32 flags)
 {
index 02dba8cd033d8e8d9ce9d673a2bd14e91fd87ea2..999e4b1044103fb3e9c0e1e041fb394be58043ca 100644 (file)
@@ -541,6 +541,7 @@ static inline signed long dma_fence_wait(struct dma_fence *fence, bool intr)
        return ret < 0 ? ret : 0;
 }
 
+struct dma_fence *dma_fence_get_stub(void);
 u64 dma_fence_context_alloc(unsigned num);
 
 #define DMA_FENCE_TRACE(f, fmt, args...) \
index 15bd41447025a425a5695ac51ba8d72561726b00..d327bdd53716f2ff96b388c4f0848e611e921b90 100644 (file)
@@ -796,7 +796,7 @@ static inline void dmam_release_declared_memory(struct device *dev)
 static inline void *dma_alloc_wc(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t gfp)
 {
-       unsigned long attrs = DMA_ATTR_NO_WARN;
+       unsigned long attrs = DMA_ATTR_WRITE_COMBINE;
 
        if (gfp & __GFP_NOWARN)
                attrs |= DMA_ATTR_NO_WARN;
index 1d0c9ea8825d2f398b3b920b38c5ece69edb4e79..342dabda9c7ef23cdeb4f7da161bb648de423c84 100644 (file)
@@ -669,10 +669,4 @@ struct mem_ctl_info {
        bool fake_inject_ue;
        u16 fake_inject_count;
 };
-
-/*
- * Maximum number of memory controllers in the coherent fabric.
- */
-#define EDAC_MAX_MCS   2 * MAX_NUMNODES
-
 #endif
index 795ff0b869bbf6403c0e89b87fdc7855e3bbb5cd..a8b9d90a804223e7a82be545b90b285b6cacb9d8 100644 (file)
@@ -861,7 +861,7 @@ bpf_run_sk_reuseport(struct sock_reuseport *reuse, struct sock *sk,
 extern int bpf_jit_enable;
 extern int bpf_jit_harden;
 extern int bpf_jit_kallsyms;
-extern int bpf_jit_limit;
+extern long bpf_jit_limit;
 
 typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
 
index f2f887795d43e9ae2cbe8b15be896547dbebbb43..8aebcf822082ea84ecbd7dafeecde7be662d1f00 100644 (file)
@@ -104,6 +104,7 @@ struct gpio_descs *__must_check
 devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
                              enum gpiod_flags flags);
 void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
+void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc);
 void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
 
 int gpiod_get_direction(struct gpio_desc *desc);
@@ -172,6 +173,10 @@ int desc_to_gpio(const struct gpio_desc *desc);
 struct device_node;
 struct fwnode_handle;
 
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label);
 struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
                                              struct device_node *node,
                                              const char *propname, int index,
@@ -245,6 +250,15 @@ static inline void gpiod_put(struct gpio_desc *desc)
        WARN_ON(1);
 }
 
+static inline void devm_gpiod_unhinge(struct device *dev,
+                                     struct gpio_desc *desc)
+{
+       might_sleep();
+
+       /* GPIO can never have been requested */
+       WARN_ON(1);
+}
+
 static inline void gpiod_put_array(struct gpio_descs *descs)
 {
        might_sleep();
@@ -517,6 +531,15 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
 struct device_node;
 struct fwnode_handle;
 
+static inline
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
 static inline
 struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
                                              struct device_node *node,
index 4f3febc0f971cbf603bd5a905d4a2693fba8d3df..d2bacf5024295dcfb6092de230179e6f78117c3f 100644 (file)
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
 ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
                                size_t size);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+                                    void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
        HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
                            const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
                                size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+                                    void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
        HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
                                  void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+                                      void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
        HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
                                   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+                                       void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
        struct {
@@ -330,10 +342,14 @@ union hdmi_infoframe {
        struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+                           size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+                                void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+                         const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-                       union hdmi_infoframe *frame);
+                       const union hdmi_infoframe *frame);
 
 #endif /* _DRM_HDMI_H */
diff --git a/include/linux/i3c/ccc.h b/include/linux/i3c/ccc.h
new file mode 100644 (file)
index 0000000..73b0982
--- /dev/null
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef I3C_CCC_H
+#define I3C_CCC_H
+
+#include <linux/bitops.h>
+#include <linux/i3c/device.h>
+
+/* I3C CCC (Common Command Codes) related definitions */
+#define I3C_CCC_DIRECT                 BIT(7)
+
+#define I3C_CCC_ID(id, broadcast)      \
+       ((id) | ((broadcast) ? 0 : I3C_CCC_DIRECT))
+
+/* Commands valid in both broadcast and unicast modes */
+#define I3C_CCC_ENEC(broadcast)                I3C_CCC_ID(0x0, broadcast)
+#define I3C_CCC_DISEC(broadcast)       I3C_CCC_ID(0x1, broadcast)
+#define I3C_CCC_ENTAS(as, broadcast)   I3C_CCC_ID(0x2 + (as), broadcast)
+#define I3C_CCC_RSTDAA(broadcast)      I3C_CCC_ID(0x6, broadcast)
+#define I3C_CCC_SETMWL(broadcast)      I3C_CCC_ID(0x9, broadcast)
+#define I3C_CCC_SETMRL(broadcast)      I3C_CCC_ID(0xa, broadcast)
+#define I3C_CCC_SETXTIME(broadcast)    ((broadcast) ? 0x28 : 0x98)
+#define I3C_CCC_VENDOR(id, broadcast)  ((id) + ((broadcast) ? 0x61 : 0xe0))
+
+/* Broadcast-only commands */
+#define I3C_CCC_ENTDAA                 I3C_CCC_ID(0x7, true)
+#define I3C_CCC_DEFSLVS                        I3C_CCC_ID(0x8, true)
+#define I3C_CCC_ENTTM                  I3C_CCC_ID(0xb, true)
+#define I3C_CCC_ENTHDR(x)              I3C_CCC_ID(0x20 + (x), true)
+
+/* Unicast-only commands */
+#define I3C_CCC_SETDASA                        I3C_CCC_ID(0x7, false)
+#define I3C_CCC_SETNEWDA               I3C_CCC_ID(0x8, false)
+#define I3C_CCC_GETMWL                 I3C_CCC_ID(0xb, false)
+#define I3C_CCC_GETMRL                 I3C_CCC_ID(0xc, false)
+#define I3C_CCC_GETPID                 I3C_CCC_ID(0xd, false)
+#define I3C_CCC_GETBCR                 I3C_CCC_ID(0xe, false)
+#define I3C_CCC_GETDCR                 I3C_CCC_ID(0xf, false)
+#define I3C_CCC_GETSTATUS              I3C_CCC_ID(0x10, false)
+#define I3C_CCC_GETACCMST              I3C_CCC_ID(0x11, false)
+#define I3C_CCC_SETBRGTGT              I3C_CCC_ID(0x13, false)
+#define I3C_CCC_GETMXDS                        I3C_CCC_ID(0x14, false)
+#define I3C_CCC_GETHDRCAP              I3C_CCC_ID(0x15, false)
+#define I3C_CCC_GETXTIME               I3C_CCC_ID(0x19, false)
+
+#define I3C_CCC_EVENT_SIR              BIT(0)
+#define I3C_CCC_EVENT_MR               BIT(1)
+#define I3C_CCC_EVENT_HJ               BIT(3)
+
+/**
+ * struct i3c_ccc_events - payload passed to ENEC/DISEC CCC
+ *
+ * @events: bitmask of I3C_CCC_EVENT_xxx events.
+ *
+ * Depending on the CCC command, the specific events coming from all devices
+ * (broadcast version) or a specific device (unicast version) will be
+ * enabled (ENEC) or disabled (DISEC).
+ */
+struct i3c_ccc_events {
+       u8 events;
+};
+
+/**
+ * struct i3c_ccc_mwl - payload passed to SETMWL/GETMWL CCC
+ *
+ * @len: maximum write length in bytes
+ *
+ * The maximum write length is only applicable to SDR private messages or
+ * extended Write CCCs (like SETXTIME).
+ */
+struct i3c_ccc_mwl {
+       __be16 len;
+};
+
+/**
+ * struct i3c_ccc_mrl - payload passed to SETMRL/GETMRL CCC
+ *
+ * @len: maximum read length in bytes
+ * @ibi_len: maximum IBI payload length
+ *
+ * The maximum read length is only applicable to SDR private messages or
+ * extended Read CCCs (like GETXTIME).
+ * The IBI length is only valid if the I3C slave is IBI capable
+ * (%I3C_BCR_IBI_REQ_CAP is set).
+ */
+struct i3c_ccc_mrl {
+       __be16 read_len;
+       u8 ibi_len;
+} __packed;
+
+/**
+ * struct i3c_ccc_dev_desc - I3C/I2C device descriptor used for DEFSLVS
+ *
+ * @dyn_addr: dynamic address assigned to the I3C slave or 0 if the entry is
+ *           describing an I2C slave.
+ * @dcr: DCR value (not applicable to entries describing I2C devices)
+ * @lvr: LVR value (not applicable to entries describing I3C devices)
+ * @bcr: BCR value or 0 if this entry is describing an I2C slave
+ * @static_addr: static address or 0 if the device does not have a static
+ *              address
+ *
+ * The DEFSLVS command should be passed an array of i3c_ccc_dev_desc
+ * descriptors (one entry per I3C/I2C dev controlled by the master).
+ */
+struct i3c_ccc_dev_desc {
+       u8 dyn_addr;
+       union {
+               u8 dcr;
+               u8 lvr;
+       };
+       u8 bcr;
+       u8 static_addr;
+};
+
+/**
+ * struct i3c_ccc_defslvs - payload passed to DEFSLVS CCC
+ *
+ * @count: number of dev descriptors
+ * @master: descriptor describing the current master
+ * @slaves: array of descriptors describing slaves controlled by the
+ *         current master
+ *
+ * Information passed to the broadcast DEFSLVS to propagate device
+ * information to all masters currently acting as slaves on the bus.
+ * This is only meaningful if you have more than one master.
+ */
+struct i3c_ccc_defslvs {
+       u8 count;
+       struct i3c_ccc_dev_desc master;
+       struct i3c_ccc_dev_desc slaves[0];
+} __packed;
+
+/**
+ * enum i3c_ccc_test_mode - enum listing all available test modes
+ *
+ * @I3C_CCC_EXIT_TEST_MODE: exit test mode
+ * @I3C_CCC_VENDOR_TEST_MODE: enter vendor test mode
+ */
+enum i3c_ccc_test_mode {
+       I3C_CCC_EXIT_TEST_MODE,
+       I3C_CCC_VENDOR_TEST_MODE,
+};
+
+/**
+ * struct i3c_ccc_enttm - payload passed to ENTTM CCC
+ *
+ * @mode: one of the &enum i3c_ccc_test_mode modes
+ *
+ * Information passed to the ENTTM CCC to instruct an I3C device to enter a
+ * specific test mode.
+ */
+struct i3c_ccc_enttm {
+       u8 mode;
+};
+
+/**
+ * struct i3c_ccc_setda - payload passed to SETNEWDA and SETDASA CCCs
+ *
+ * @addr: dynamic address to assign to an I3C device
+ *
+ * Information passed to the SETNEWDA and SETDASA CCCs to assign/change the
+ * dynamic address of an I3C device.
+ */
+struct i3c_ccc_setda {
+       u8 addr;
+};
+
+/**
+ * struct i3c_ccc_getpid - payload passed to GETPID CCC
+ *
+ * @pid: 48 bits PID in big endian
+ */
+struct i3c_ccc_getpid {
+       u8 pid[6];
+};
+
+/**
+ * struct i3c_ccc_getbcr - payload passed to GETBCR CCC
+ *
+ * @bcr: BCR (Bus Characteristic Register) value
+ */
+struct i3c_ccc_getbcr {
+       u8 bcr;
+};
+
+/**
+ * struct i3c_ccc_getdcr - payload passed to GETDCR CCC
+ *
+ * @dcr: DCR (Device Characteristic Register) value
+ */
+struct i3c_ccc_getdcr {
+       u8 dcr;
+};
+
+#define I3C_CCC_STATUS_PENDING_INT(status)     ((status) & GENMASK(3, 0))
+#define I3C_CCC_STATUS_PROTOCOL_ERROR          BIT(5)
+#define I3C_CCC_STATUS_ACTIVITY_MODE(status)   \
+       (((status) & GENMASK(7, 6)) >> 6)
+
+/**
+ * struct i3c_ccc_getstatus - payload passed to GETSTATUS CCC
+ *
+ * @status: status of the I3C slave (see I3C_CCC_STATUS_xxx macros for more
+ *         information).
+ */
+struct i3c_ccc_getstatus {
+       __be16 status;
+};
+
+/**
+ * struct i3c_ccc_getaccmst - payload passed to GETACCMST CCC
+ *
+ * @newmaster: address of the master taking bus ownership
+ */
+struct i3c_ccc_getaccmst {
+       u8 newmaster;
+};
+
+/**
+ * struct i3c_ccc_bridged_slave_desc - bridged slave descriptor
+ *
+ * @addr: dynamic address of the bridged device
+ * @id: ID of the slave device behind the bridge
+ */
+struct i3c_ccc_bridged_slave_desc {
+       u8 addr;
+       __be16 id;
+} __packed;
+
+/**
+ * struct i3c_ccc_setbrgtgt - payload passed to SETBRGTGT CCC
+ *
+ * @count: number of bridged slaves
+ * @bslaves: bridged slave descriptors
+ */
+struct i3c_ccc_setbrgtgt {
+       u8 count;
+       struct i3c_ccc_bridged_slave_desc bslaves[0];
+} __packed;
+
+/**
+ * enum i3c_sdr_max_data_rate - max data rate values for private SDR transfers
+ */
+enum i3c_sdr_max_data_rate {
+       I3C_SDR0_FSCL_MAX,
+       I3C_SDR1_FSCL_8MHZ,
+       I3C_SDR2_FSCL_6MHZ,
+       I3C_SDR3_FSCL_4MHZ,
+       I3C_SDR4_FSCL_2MHZ,
+};
+
+/**
+ * enum i3c_tsco - clock to data turn-around
+ */
+enum i3c_tsco {
+       I3C_TSCO_8NS,
+       I3C_TSCO_9NS,
+       I3C_TSCO_10NS,
+       I3C_TSCO_11NS,
+       I3C_TSCO_12NS,
+};
+
+#define I3C_CCC_MAX_SDR_FSCL_MASK      GENMASK(2, 0)
+#define I3C_CCC_MAX_SDR_FSCL(x)                ((x) & I3C_CCC_MAX_SDR_FSCL_MASK)
+
+/**
+ * struct i3c_ccc_getmxds - payload passed to GETMXDS CCC
+ *
+ * @maxwr: write limitations
+ * @maxrd: read limitations
+ * @maxrdturn: maximum read turn-around expressed micro-seconds and
+ *            little-endian formatted
+ */
+struct i3c_ccc_getmxds {
+       u8 maxwr;
+       u8 maxrd;
+       u8 maxrdturn[3];
+} __packed;
+
+#define I3C_CCC_HDR_MODE(mode)         BIT(mode)
+
+/**
+ * struct i3c_ccc_gethdrcap - payload passed to GETHDRCAP CCC
+ *
+ * @modes: bitmap of supported HDR modes
+ */
+struct i3c_ccc_gethdrcap {
+       u8 modes;
+} __packed;
+
+/**
+ * enum i3c_ccc_setxtime_subcmd - SETXTIME sub-commands
+ */
+enum i3c_ccc_setxtime_subcmd {
+       I3C_CCC_SETXTIME_ST = 0x7f,
+       I3C_CCC_SETXTIME_DT = 0xbf,
+       I3C_CCC_SETXTIME_ENTER_ASYNC_MODE0 = 0xdf,
+       I3C_CCC_SETXTIME_ENTER_ASYNC_MODE1 = 0xef,
+       I3C_CCC_SETXTIME_ENTER_ASYNC_MODE2 = 0xf7,
+       I3C_CCC_SETXTIME_ENTER_ASYNC_MODE3 = 0xfb,
+       I3C_CCC_SETXTIME_ASYNC_TRIGGER = 0xfd,
+       I3C_CCC_SETXTIME_TPH = 0x3f,
+       I3C_CCC_SETXTIME_TU = 0x9f,
+       I3C_CCC_SETXTIME_ODR = 0x8f,
+};
+
+/**
+ * struct i3c_ccc_setxtime - payload passed to SETXTIME CCC
+ *
+ * @subcmd: one of the sub-commands ddefined in &enum i3c_ccc_setxtime_subcmd
+ * @data: sub-command payload. Amount of data is determined by
+ *       &i3c_ccc_setxtime->subcmd
+ */
+struct i3c_ccc_setxtime {
+       u8 subcmd;
+       u8 data[0];
+} __packed;
+
+#define I3C_CCC_GETXTIME_SYNC_MODE     BIT(0)
+#define I3C_CCC_GETXTIME_ASYNC_MODE(x) BIT((x) + 1)
+#define I3C_CCC_GETXTIME_OVERFLOW      BIT(7)
+
+/**
+ * struct i3c_ccc_getxtime - payload retrieved from GETXTIME CCC
+ *
+ * @supported_modes: bitmap describing supported XTIME modes
+ * @state: current status (enabled mode and overflow status)
+ * @frequency: slave's internal oscillator frequency in 500KHz steps
+ * @inaccuracy: slave's internal oscillator inaccuracy in 0.1% steps
+ */
+struct i3c_ccc_getxtime {
+       u8 supported_modes;
+       u8 state;
+       u8 frequency;
+       u8 inaccuracy;
+} __packed;
+
+/**
+ * struct i3c_ccc_cmd_payload - CCC payload
+ *
+ * @len: payload length
+ * @data: payload data. This buffer must be DMA-able
+ */
+struct i3c_ccc_cmd_payload {
+       u16 len;
+       void *data;
+};
+
+/**
+ * struct i3c_ccc_cmd_dest - CCC command destination
+ *
+ * @addr: can be an I3C device address or the broadcast address if this is a
+ *       broadcast CCC
+ * @payload: payload to be sent to this device or broadcasted
+ */
+struct i3c_ccc_cmd_dest {
+       u8 addr;
+       struct i3c_ccc_cmd_payload payload;
+};
+
+/**
+ * struct i3c_ccc_cmd - CCC command
+ *
+ * @rnw: true if the CCC should retrieve data from the device. Only valid for
+ *      unicast commands
+ * @id: CCC command id
+ * @ndests: number of destinations. Should always be one for broadcast commands
+ * @dests: array of destinations and associated payload for this CCC. Most of
+ *        the time, only one destination is provided
+ * @err: I3C error code
+ */
+struct i3c_ccc_cmd {
+       u8 rnw;
+       u8 id;
+       unsigned int ndests;
+       struct i3c_ccc_cmd_dest *dests;
+       enum i3c_error_code err;
+};
+
+#endif /* I3C_CCC_H */
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
new file mode 100644 (file)
index 0000000..5ecb055
--- /dev/null
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef I3C_DEV_H
+#define I3C_DEV_H
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/kconfig.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+
+/**
+ * enum i3c_error_code - I3C error codes
+ *
+ * These are the standard error codes as defined by the I3C specification.
+ * When -EIO is returned by the i3c_device_do_priv_xfers() or
+ * i3c_device_send_hdr_cmds() one can check the error code in
+ * &struct_i3c_priv_xfer.err or &struct i3c_hdr_cmd.err to get a better idea of
+ * what went wrong.
+ *
+ * @I3C_ERROR_UNKNOWN: unknown error, usually means the error is not I3C
+ *                    related
+ * @I3C_ERROR_M0: M0 error
+ * @I3C_ERROR_M1: M1 error
+ * @I3C_ERROR_M2: M2 error
+ */
+enum i3c_error_code {
+       I3C_ERROR_UNKNOWN = 0,
+       I3C_ERROR_M0 = 1,
+       I3C_ERROR_M1,
+       I3C_ERROR_M2,
+};
+
+/**
+ * enum i3c_hdr_mode - HDR mode ids
+ * @I3C_HDR_DDR: DDR mode
+ * @I3C_HDR_TSP: TSP mode
+ * @I3C_HDR_TSL: TSL mode
+ */
+enum i3c_hdr_mode {
+       I3C_HDR_DDR,
+       I3C_HDR_TSP,
+       I3C_HDR_TSL,
+};
+
+/**
+ * struct i3c_priv_xfer - I3C SDR private transfer
+ * @rnw: encodes the transfer direction. true for a read, false for a write
+ * @len: transfer length in bytes of the transfer
+ * @data: input/output buffer
+ * @data.in: input buffer. Must point to a DMA-able buffer
+ * @data.out: output buffer. Must point to a DMA-able buffer
+ * @err: I3C error code
+ */
+struct i3c_priv_xfer {
+       u8 rnw;
+       u16 len;
+       union {
+               void *in;
+               const void *out;
+       } data;
+       enum i3c_error_code err;
+};
+
+/**
+ * enum i3c_dcr - I3C DCR values
+ * @I3C_DCR_GENERIC_DEVICE: generic I3C device
+ */
+enum i3c_dcr {
+       I3C_DCR_GENERIC_DEVICE = 0,
+};
+
+#define I3C_PID_MANUF_ID(pid)          (((pid) & GENMASK_ULL(47, 33)) >> 33)
+#define I3C_PID_RND_LOWER_32BITS(pid)  (!!((pid) & BIT_ULL(32)))
+#define I3C_PID_RND_VAL(pid)           ((pid) & GENMASK_ULL(31, 0))
+#define I3C_PID_PART_ID(pid)           (((pid) & GENMASK_ULL(31, 16)) >> 16)
+#define I3C_PID_INSTANCE_ID(pid)       (((pid) & GENMASK_ULL(15, 12)) >> 12)
+#define I3C_PID_EXTRA_INFO(pid)                ((pid) & GENMASK_ULL(11, 0))
+
+#define I3C_BCR_DEVICE_ROLE(bcr)       ((bcr) & GENMASK(7, 6))
+#define I3C_BCR_I3C_SLAVE              (0 << 6)
+#define I3C_BCR_I3C_MASTER             (1 << 6)
+#define I3C_BCR_HDR_CAP                        BIT(5)
+#define I3C_BCR_BRIDGE                 BIT(4)
+#define I3C_BCR_OFFLINE_CAP            BIT(3)
+#define I3C_BCR_IBI_PAYLOAD            BIT(2)
+#define I3C_BCR_IBI_REQ_CAP            BIT(1)
+#define I3C_BCR_MAX_DATA_SPEED_LIM     BIT(0)
+
+/**
+ * struct i3c_device_info - I3C device information
+ * @pid: Provisional ID
+ * @bcr: Bus Characteristic Register
+ * @dcr: Device Characteristic Register
+ * @static_addr: static/I2C address
+ * @dyn_addr: dynamic address
+ * @hdr_cap: supported HDR modes
+ * @max_read_ds: max read speed information
+ * @max_write_ds: max write speed information
+ * @max_ibi_len: max IBI payload length
+ * @max_read_turnaround: max read turn-around time in micro-seconds
+ * @max_read_len: max private SDR read length in bytes
+ * @max_write_len: max private SDR write length in bytes
+ *
+ * These are all basic information that should be advertised by an I3C device.
+ * Some of them are optional depending on the device type and device
+ * capabilities.
+ * For each I3C slave attached to a master with
+ * i3c_master_add_i3c_dev_locked(), the core will send the relevant CCC command
+ * to retrieve these data.
+ */
+struct i3c_device_info {
+       u64 pid;
+       u8 bcr;
+       u8 dcr;
+       u8 static_addr;
+       u8 dyn_addr;
+       u8 hdr_cap;
+       u8 max_read_ds;
+       u8 max_write_ds;
+       u8 max_ibi_len;
+       u32 max_read_turnaround;
+       u16 max_read_len;
+       u16 max_write_len;
+};
+
+/*
+ * I3C device internals are kept hidden from I3C device users. It's just
+ * simpler to refactor things when everything goes through getter/setters, and
+ * I3C device drivers should not have to worry about internal representation
+ * anyway.
+ */
+struct i3c_device;
+
+/* These macros should be used to i3c_device_id entries. */
+#define I3C_MATCH_MANUF_AND_PART (I3C_MATCH_MANUF | I3C_MATCH_PART)
+
+#define I3C_DEVICE(_manufid, _partid, _drvdata)                                \
+       {                                                               \
+               .match_flags = I3C_MATCH_MANUF_AND_PART,                \
+               .manuf_id = _manufid,                                   \
+               .part_id = _partid,                                     \
+               .data = _drvdata,                                       \
+       }
+
+#define I3C_DEVICE_EXTRA_INFO(_manufid, _partid, _info, _drvdata)      \
+       {                                                               \
+               .match_flags = I3C_MATCH_MANUF_AND_PART |               \
+                              I3C_MATCH_EXTRA_INFO,                    \
+               .manuf_id = _manufid,                                   \
+               .part_id = _partid,                                     \
+               .extra_info = _info,                                    \
+               .data = _drvdata,                                       \
+       }
+
+#define I3C_CLASS(_dcr, _drvdata)                                      \
+       {                                                               \
+               .match_flags = I3C_MATCH_DCR,                           \
+               .dcr = _dcr,                                            \
+       }
+
+/**
+ * struct i3c_driver - I3C device driver
+ * @driver: inherit from device_driver
+ * @probe: I3C device probe method
+ * @remove: I3C device remove method
+ * @id_table: I3C device match table. Will be used by the framework to decide
+ *           which device to bind to this driver
+ */
+struct i3c_driver {
+       struct device_driver driver;
+       int (*probe)(struct i3c_device *dev);
+       int (*remove)(struct i3c_device *dev);
+       const struct i3c_device_id *id_table;
+};
+
+static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv)
+{
+       return container_of(drv, struct i3c_driver, driver);
+}
+
+struct device *i3cdev_to_dev(struct i3c_device *i3cdev);
+struct i3c_device *dev_to_i3cdev(struct device *dev);
+
+static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev,
+                                     void *data)
+{
+       struct device *dev = i3cdev_to_dev(i3cdev);
+
+       dev_set_drvdata(dev, data);
+}
+
+static inline void *i3cdev_get_drvdata(struct i3c_device *i3cdev)
+{
+       struct device *dev = i3cdev_to_dev(i3cdev);
+
+       return dev_get_drvdata(dev);
+}
+
+int i3c_driver_register_with_owner(struct i3c_driver *drv,
+                                  struct module *owner);
+void i3c_driver_unregister(struct i3c_driver *drv);
+
+#define i3c_driver_register(__drv)             \
+       i3c_driver_register_with_owner(__drv, THIS_MODULE)
+
+/**
+ * module_i3c_driver() - Register a module providing an I3C driver
+ * @__drv: the I3C driver to register
+ *
+ * Provide generic init/exit functions that simply register/unregister an I3C
+ * driver.
+ * Should be used by any driver that does not require extra init/cleanup steps.
+ */
+#define module_i3c_driver(__drv)               \
+       module_driver(__drv, i3c_driver_register, i3c_driver_unregister)
+
+/**
+ * i3c_i2c_driver_register() - Register an i2c and an i3c driver
+ * @i3cdrv: the I3C driver to register
+ * @i2cdrv: the I2C driver to register
+ *
+ * This function registers both @i2cdev and @i3cdev, and fails if one of these
+ * registrations fails. This is mainly useful for devices that support both I2C
+ * and I3C modes.
+ * Note that when CONFIG_I3C is not enabled, this function only registers the
+ * I2C driver.
+ *
+ * Return: 0 if both registrations succeeds, a negative error code otherwise.
+ */
+static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
+                                         struct i2c_driver *i2cdrv)
+{
+       int ret;
+
+       ret = i2c_add_driver(i2cdrv);
+       if (ret || !IS_ENABLED(CONFIG_I3C))
+               return ret;
+
+       ret = i3c_driver_register(i3cdrv);
+       if (ret)
+               i2c_del_driver(i2cdrv);
+
+       return ret;
+}
+
+/**
+ * i3c_i2c_driver_unregister() - Unregister an i2c and an i3c driver
+ * @i3cdrv: the I3C driver to register
+ * @i2cdrv: the I2C driver to register
+ *
+ * This function unregisters both @i3cdrv and @i2cdrv.
+ * Note that when CONFIG_I3C is not enabled, this function only unregisters the
+ * @i2cdrv.
+ */
+static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
+                                            struct i2c_driver *i2cdrv)
+{
+       if (IS_ENABLED(CONFIG_I3C))
+               i3c_driver_unregister(i3cdrv);
+
+       i2c_del_driver(i2cdrv);
+}
+
+/**
+ * module_i3c_i2c_driver() - Register a module providing an I3C and an I2C
+ *                          driver
+ * @__i3cdrv: the I3C driver to register
+ * @__i2cdrv: the I3C driver to register
+ *
+ * Provide generic init/exit functions that simply register/unregister an I3C
+ * and an I2C driver.
+ * This macro can be used even if CONFIG_I3C is disabled, in this case, only
+ * the I2C driver will be registered.
+ * Should be used by any driver that does not require extra init/cleanup steps.
+ */
+#define module_i3c_i2c_driver(__i3cdrv, __i2cdrv)      \
+       module_driver(__i3cdrv,                         \
+                     i3c_i2c_driver_register,          \
+                     i3c_i2c_driver_unregister)
+
+int i3c_device_do_priv_xfers(struct i3c_device *dev,
+                            struct i3c_priv_xfer *xfers,
+                            int nxfers);
+
+void i3c_device_get_info(struct i3c_device *dev, struct i3c_device_info *info);
+
+struct i3c_ibi_payload {
+       unsigned int len;
+       const void *data;
+};
+
+/**
+ * struct i3c_ibi_setup - IBI setup object
+ * @max_payload_len: maximum length of the payload associated to an IBI. If one
+ *                  IBI appears to have a payload that is bigger than this
+ *                  number, the IBI will be rejected.
+ * @num_slots: number of pre-allocated IBI slots. This should be chosen so that
+ *            the system never runs out of IBI slots, otherwise you'll lose
+ *            IBIs.
+ * @handler: IBI handler, every time an IBI is received. This handler is called
+ *          in a workqueue context. It is allowed to sleep and send new
+ *          messages on the bus, though it's recommended to keep the
+ *          processing done there as fast as possible to avoid delaying
+ *          processing of other queued on the same workqueue.
+ *
+ * Temporary structure used to pass information to i3c_device_request_ibi().
+ * This object can be allocated on the stack since i3c_device_request_ibi()
+ * copies every bit of information and do not use it after
+ * i3c_device_request_ibi() has returned.
+ */
+struct i3c_ibi_setup {
+       unsigned int max_payload_len;
+       unsigned int num_slots;
+       void (*handler)(struct i3c_device *dev,
+                       const struct i3c_ibi_payload *payload);
+};
+
+int i3c_device_request_ibi(struct i3c_device *dev,
+                          const struct i3c_ibi_setup *setup);
+void i3c_device_free_ibi(struct i3c_device *dev);
+int i3c_device_enable_ibi(struct i3c_device *dev);
+int i3c_device_disable_ibi(struct i3c_device *dev);
+
+#endif /* I3C_DEV_H */
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
new file mode 100644 (file)
index 0000000..f13fd8b
--- /dev/null
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Cadence Design Systems Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef I3C_MASTER_H
+#define I3C_MASTER_H
+
+#include <asm/bitsperlong.h>
+
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/i3c/ccc.h>
+#include <linux/i3c/device.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#define I3C_HOT_JOIN_ADDR              0x2
+#define I3C_BROADCAST_ADDR             0x7e
+#define I3C_MAX_ADDR                   GENMASK(6, 0)
+
+struct i3c_master_controller;
+struct i3c_bus;
+struct i2c_device;
+struct i3c_device;
+
+/**
+ * struct i3c_i2c_dev_desc - Common part of the I3C/I2C device descriptor
+ * @node: node element used to insert the slot into the I2C or I3C device
+ *       list
+ * @master: I3C master that instantiated this device. Will be used to do
+ *         I2C/I3C transfers
+ * @master_priv: master private data assigned to the device. Can be used to
+ *              add master specific information
+ *
+ * This structure is describing common I3C/I2C dev information.
+ */
+struct i3c_i2c_dev_desc {
+       struct list_head node;
+       struct i3c_master_controller *master;
+       void *master_priv;
+};
+
+#define I3C_LVR_I2C_INDEX_MASK         GENMASK(7, 5)
+#define I3C_LVR_I2C_INDEX(x)           ((x) << 5)
+#define I3C_LVR_I2C_FM_MODE            BIT(4)
+
+#define I2C_MAX_ADDR                   GENMASK(9, 0)
+
+/**
+ * struct i2c_dev_boardinfo - I2C device board information
+ * @node: used to insert the boardinfo object in the I2C boardinfo list
+ * @base: regular I2C board information
+ * @lvr: LVR (Legacy Virtual Register) needed by the I3C core to know about
+ *      the I2C device limitations
+ *
+ * This structure is used to attach board-level information to an I2C device.
+ * Each I2C device connected on the I3C bus should have one.
+ */
+struct i2c_dev_boardinfo {
+       struct list_head node;
+       struct i2c_board_info base;
+       u8 lvr;
+};
+
+/**
+ * struct i2c_dev_desc - I2C device descriptor
+ * @common: common part of the I2C device descriptor
+ * @boardinfo: pointer to the boardinfo attached to this I2C device
+ * @dev: I2C device object registered to the I2C framework
+ *
+ * Each I2C device connected on the bus will have an i2c_dev_desc.
+ * This object is created by the core and later attached to the controller
+ * using &struct_i3c_master_controller->ops->attach_i2c_dev().
+ *
+ * &struct_i2c_dev_desc is the internal representation of an I2C device
+ * connected on an I3C bus. This object is also passed to all
+ * &struct_i3c_master_controller_ops hooks.
+ */
+struct i2c_dev_desc {
+       struct i3c_i2c_dev_desc common;
+       const struct i2c_dev_boardinfo *boardinfo;
+       struct i2c_client *dev;
+};
+
+/**
+ * struct i3c_ibi_slot - I3C IBI (In-Band Interrupt) slot
+ * @work: work associated to this slot. The IBI handler will be called from
+ *       there
+ * @dev: the I3C device that has generated this IBI
+ * @len: length of the payload associated to this IBI
+ * @data: payload buffer
+ *
+ * An IBI slot is an object pre-allocated by the controller and used when an
+ * IBI comes in.
+ * Every time an IBI comes in, the I3C master driver should find a free IBI
+ * slot in its IBI slot pool, retrieve the IBI payload and queue the IBI using
+ * i3c_master_queue_ibi().
+ *
+ * How IBI slots are allocated is left to the I3C master driver, though, for
+ * simple kmalloc-based allocation, the generic IBI slot pool can be used.
+ */
+struct i3c_ibi_slot {
+       struct work_struct work;
+       struct i3c_dev_desc *dev;
+       unsigned int len;
+       void *data;
+};
+
+/**
+ * struct i3c_device_ibi_info - IBI information attached to a specific device
+ * @all_ibis_handled: used to be informed when no more IBIs are waiting to be
+ *                   processed. Used by i3c_device_disable_ibi() to wait for
+ *                   all IBIs to be dequeued
+ * @pending_ibis: count the number of pending IBIs. Each pending IBI has its
+ *               work element queued to the controller workqueue
+ * @max_payload_len: maximum payload length for an IBI coming from this device.
+ *                  this value is specified when calling
+ *                  i3c_device_request_ibi() and should not change at run
+ *                  time. All messages IBIs exceeding this limit should be
+ *                  rejected by the master
+ * @num_slots: number of IBI slots reserved for this device
+ * @enabled: reflect the IBI status
+ * @handler: IBI handler specified at i3c_device_request_ibi() call time. This
+ *          handler will be called from the controller workqueue, and as such
+ *          is allowed to sleep (though it is recommended to process the IBI
+ *          as fast as possible to not stall processing of other IBIs queued
+ *          on the same workqueue).
+ *          New I3C messages can be sent from the IBI handler
+ *
+ * The &struct_i3c_device_ibi_info object is allocated when
+ * i3c_device_request_ibi() is called and attached to a specific device. This
+ * object is here to manage IBIs coming from a specific I3C device.
+ *
+ * Note that this structure is the generic view of the IBI management
+ * infrastructure. I3C master drivers may have their own internal
+ * representation which they can associate to the device using
+ * controller-private data.
+ */
+struct i3c_device_ibi_info {
+       struct completion all_ibis_handled;
+       atomic_t pending_ibis;
+       unsigned int max_payload_len;
+       unsigned int num_slots;
+       unsigned int enabled;
+       void (*handler)(struct i3c_device *dev,
+                       const struct i3c_ibi_payload *payload);
+};
+
+/**
+ * struct i3c_dev_boardinfo - I3C device board information
+ * @node: used to insert the boardinfo object in the I3C boardinfo list
+ * @init_dyn_addr: initial dynamic address requested by the FW. We provide no
+ *                guarantee that the device will end up using this address,
+ *                but try our best to assign this specific address to the
+ *                device
+ * @static_addr: static address the I3C device listen on before it's been
+ *              assigned a dynamic address by the master. Will be used during
+ *              bus initialization to assign it a specific dynamic address
+ *              before starting DAA (Dynamic Address Assignment)
+ * @pid: I3C Provisional ID exposed by the device. This is a unique identifier
+ *      that may be used to attach boardinfo to i3c_dev_desc when the device
+ *      does not have a static address
+ * @of_node: optional DT node in case the device has been described in the DT
+ *
+ * This structure is used to attach board-level information to an I3C device.
+ * Not all I3C devices connected on the bus will have a boardinfo. It's only
+ * needed if you want to attach extra resources to a device or assign it a
+ * specific dynamic address.
+ */
+struct i3c_dev_boardinfo {
+       struct list_head node;
+       u8 init_dyn_addr;
+       u8 static_addr;
+       u64 pid;
+       struct device_node *of_node;
+};
+
+/**
+ * struct i3c_dev_desc - I3C device descriptor
+ * @common: common part of the I3C device descriptor
+ * @info: I3C device information. Will be automatically filled when you create
+ *       your device with i3c_master_add_i3c_dev_locked()
+ * @ibi_lock: lock used to protect the &struct_i3c_device->ibi
+ * @ibi: IBI info attached to a device. Should be NULL until
+ *      i3c_device_request_ibi() is called
+ * @dev: pointer to the I3C device object exposed to I3C device drivers. This
+ *      should never be accessed from I3C master controller drivers. Only core
+ *      code should manipulate it in when updating the dev <-> desc link or
+ *      when propagating IBI events to the driver
+ * @boardinfo: pointer to the boardinfo attached to this I3C device
+ *
+ * Internal representation of an I3C device. This object is only used by the
+ * core and passed to I3C master controller drivers when they're requested to
+ * do some operations on the device.
+ * The core maintains the link between the internal I3C dev descriptor and the
+ * object exposed to the I3C device drivers (&struct_i3c_device).
+ */
+struct i3c_dev_desc {
+       struct i3c_i2c_dev_desc common;
+       struct i3c_device_info info;
+       struct mutex ibi_lock;
+       struct i3c_device_ibi_info *ibi;
+       struct i3c_device *dev;
+       const struct i3c_dev_boardinfo *boardinfo;
+};
+
+/**
+ * struct i3c_device - I3C device object
+ * @dev: device object to register the I3C dev to the device model
+ * @desc: pointer to an i3c device descriptor object. This link is updated
+ *       every time the I3C device is rediscovered with a different dynamic
+ *       address assigned
+ * @bus: I3C bus this device is attached to
+ *
+ * I3C device object exposed to I3C device drivers. The takes care of linking
+ * this object to the relevant &struct_i3c_dev_desc one.
+ * All I3C devs on the I3C bus are represented, including I3C masters. For each
+ * of them, we have an instance of &struct i3c_device.
+ */
+struct i3c_device {
+       struct device dev;
+       struct i3c_dev_desc *desc;
+       struct i3c_bus *bus;
+};
+
+/*
+ * The I3C specification says the maximum number of devices connected on the
+ * bus is 11, but this number depends on external parameters like trace length,
+ * capacitive load per Device, and the types of Devices present on the Bus.
+ * I3C master can also have limitations, so this number is just here as a
+ * reference and should be adjusted on a per-controller/per-board basis.
+ */
+#define I3C_BUS_MAX_DEVS               11
+
+#define I3C_BUS_MAX_I3C_SCL_RATE       12900000
+#define I3C_BUS_TYP_I3C_SCL_RATE       12500000
+#define I3C_BUS_I2C_FM_PLUS_SCL_RATE   1000000
+#define I3C_BUS_I2C_FM_SCL_RATE                400000
+#define I3C_BUS_TLOW_OD_MIN_NS         200
+
+/**
+ * enum i3c_bus_mode - I3C bus mode
+ * @I3C_BUS_MODE_PURE: only I3C devices are connected to the bus. No limitation
+ *                    expected
+ * @I3C_BUS_MODE_MIXED_FAST: I2C devices with 50ns spike filter are present on
+ *                          the bus. The only impact in this mode is that the
+ *                          high SCL pulse has to stay below 50ns to trick I2C
+ *                          devices when transmitting I3C frames
+ * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are present
+ *                          on the bus
+ */
+enum i3c_bus_mode {
+       I3C_BUS_MODE_PURE,
+       I3C_BUS_MODE_MIXED_FAST,
+       I3C_BUS_MODE_MIXED_SLOW,
+};
+
+/**
+ * enum i3c_addr_slot_status - I3C address slot status
+ * @I3C_ADDR_SLOT_FREE: address is free
+ * @I3C_ADDR_SLOT_RSVD: address is reserved
+ * @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device
+ * @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device
+ * @I3C_ADDR_SLOT_STATUS_MASK: address slot mask
+ *
+ * On an I3C bus, addresses are assigned dynamically, and we need to know which
+ * addresses are free to use and which ones are already assigned.
+ *
+ * Addresses marked as reserved are those reserved by the I3C protocol
+ * (broadcast address, ...).
+ */
+enum i3c_addr_slot_status {
+       I3C_ADDR_SLOT_FREE,
+       I3C_ADDR_SLOT_RSVD,
+       I3C_ADDR_SLOT_I2C_DEV,
+       I3C_ADDR_SLOT_I3C_DEV,
+       I3C_ADDR_SLOT_STATUS_MASK = 3,
+};
+
+/**
+ * struct i3c_bus - I3C bus object
+ * @cur_master: I3C master currently driving the bus. Since I3C is multi-master
+ *             this can change over the time. Will be used to let a master
+ *             know whether it needs to request bus ownership before sending
+ *             a frame or not
+ * @id: bus ID. Assigned by the framework when register the bus
+ * @addrslots: a bitmap with 2-bits per-slot to encode the address status and
+ *            ease the DAA (Dynamic Address Assignment) procedure (see
+ *            &enum i3c_addr_slot_status)
+ * @mode: bus mode (see &enum i3c_bus_mode)
+ * @scl_rate.i3c: maximum rate for the clock signal when doing I3C SDR/priv
+ *               transfers
+ * @scl_rate.i2c: maximum rate for the clock signal when doing I2C transfers
+ * @scl_rate: SCL signal rate for I3C and I2C mode
+ * @devs.i3c: contains a list of I3C device descriptors representing I3C
+ *           devices connected on the bus and successfully attached to the
+ *           I3C master
+ * @devs.i2c: contains a list of I2C device descriptors representing I2C
+ *           devices connected on the bus and successfully attached to the
+ *           I3C master
+ * @devs: 2 lists containing all I3C/I2C devices connected to the bus
+ * @lock: read/write lock on the bus. This is needed to protect against
+ *       operations that have an impact on the whole bus and the devices
+ *       connected to it. For example, when asking slaves to drop their
+ *       dynamic address (RSTDAA CCC), we need to make sure no one is trying
+ *       to send I3C frames to these devices.
+ *       Note that this lock does not protect against concurrency between
+ *       devices: several drivers can send different I3C/I2C frames through
+ *       the same master in parallel. This is the responsibility of the
+ *       master to guarantee that frames are actually sent sequentially and
+ *       not interlaced
+ *
+ * The I3C bus is represented with its own object and not implicitly described
+ * by the I3C master to cope with the multi-master functionality, where one bus
+ * can be shared amongst several masters, each of them requesting bus ownership
+ * when they need to.
+ */
+struct i3c_bus {
+       struct i3c_dev_desc *cur_master;
+       int id;
+       unsigned long addrslots[((I2C_MAX_ADDR + 1) * 2) / BITS_PER_LONG];
+       enum i3c_bus_mode mode;
+       struct {
+               unsigned long i3c;
+               unsigned long i2c;
+       } scl_rate;
+       struct {
+               struct list_head i3c;
+               struct list_head i2c;
+       } devs;
+       struct rw_semaphore lock;
+};
+
+/**
+ * struct i3c_master_controller_ops - I3C master methods
+ * @bus_init: hook responsible for the I3C bus initialization. You should at
+ *           least call master_set_info() from there and set the bus mode.
+ *           You can also put controller specific initialization in there.
+ *           This method is mandatory.
+ * @bus_cleanup: cleanup everything done in
+ *              &i3c_master_controller_ops->bus_init().
+ *              This method is optional.
+ * @attach_i3c_dev: called every time an I3C device is attached to the bus. It
+ *                 can be after a DAA or when a device is statically declared
+ *                 by the FW, in which case it will only have a static address
+ *                 and the dynamic address will be 0.
+ *                 When this function is called, device information have not
+ *                 been retrieved yet.
+ *                 This is a good place to attach master controller specific
+ *                 data to I3C devices.
+ *                 This method is optional.
+ * @reattach_i3c_dev: called every time an I3C device has its addressed
+ *                   changed. It can be because the device has been powered
+ *                   down and has lost its address, or it can happen when a
+ *                   device had a static address and has been assigned a
+ *                   dynamic address with SETDASA.
+ *                   This method is optional.
+ * @detach_i3c_dev: called when an I3C device is detached from the bus. Usually
+ *                 happens when the master device is unregistered.
+ *                 This method is optional.
+ * @do_daa: do a DAA (Dynamic Address Assignment) procedure. This is procedure
+ *         should send an ENTDAA CCC command and then add all devices
+ *         discovered sure the DAA using i3c_master_add_i3c_dev_locked().
+ *         Add devices added with i3c_master_add_i3c_dev_locked() will then be
+ *         attached or re-attached to the controller.
+ *         This method is mandatory.
+ * @supports_ccc_cmd: should return true if the CCC command is supported, false
+ *                   otherwise.
+ *                   This method is optional, if not provided the core assumes
+ *                   all CCC commands are supported.
+ * @send_ccc_cmd: send a CCC command
+ *               This method is mandatory.
+ * @priv_xfers: do one or several private I3C SDR transfers
+ *             This method is mandatory.
+ * @attach_i2c_dev: called every time an I2C device is attached to the bus.
+ *                 This is a good place to attach master controller specific
+ *                 data to I2C devices.
+ *                 This method is optional.
+ * @detach_i2c_dev: called when an I2C device is detached from the bus. Usually
+ *                 happens when the master device is unregistered.
+ *                 This method is optional.
+ * @i2c_xfers: do one or several I2C transfers. Note that, unlike i3c
+ *            transfers, the core does not guarantee that buffers attached to
+ *            the transfers are DMA-safe. If drivers want to have DMA-safe
+ *            buffers, they should use the i2c_get_dma_safe_msg_buf()
+ *            and i2c_put_dma_safe_msg_buf() helpers provided by the I2C
+ *            framework.
+ *            This method is mandatory.
+ * @i2c_funcs: expose the supported I2C functionalities.
+ *            This method is mandatory.
+ * @request_ibi: attach an IBI handler to an I3C device. This implies defining
+ *              an IBI handler and the constraints of the IBI (maximum payload
+ *              length and number of pre-allocated slots).
+ *              Some controllers support less IBI-capable devices than regular
+ *              devices, so this method might return -%EBUSY if there's no
+ *              more space for an extra IBI registration
+ *              This method is optional.
+ * @free_ibi: free an IBI previously requested with ->request_ibi(). The IBI
+ *           should have been disabled with ->disable_irq() prior to that
+ *           This method is mandatory only if ->request_ibi is not NULL.
+ * @enable_ibi: enable the IBI. Only valid if ->request_ibi() has been called
+ *             prior to ->enable_ibi(). The controller should first enable
+ *             the IBI on the controller end (for example, unmask the hardware
+ *             IRQ) and then send the ENEC CCC command (with the IBI flag set)
+ *             to the I3C device.
+ *             This method is mandatory only if ->request_ibi is not NULL.
+ * @disable_ibi: disable an IBI. First send the DISEC CCC command with the IBI
+ *              flag set and then deactivate the hardware IRQ on the
+ *              controller end.
+ *              This method is mandatory only if ->request_ibi is not NULL.
+ * @recycle_ibi_slot: recycle an IBI slot. Called every time an IBI has been
+ *                   processed by its handler. The IBI slot should be put back
+ *                   in the IBI slot pool so that the controller can re-use it
+ *                   for a future IBI
+ *                   This method is mandatory only if ->request_ibi is not
+ *                   NULL.
+ */
+struct i3c_master_controller_ops {
+       int (*bus_init)(struct i3c_master_controller *master);
+       void (*bus_cleanup)(struct i3c_master_controller *master);
+       int (*attach_i3c_dev)(struct i3c_dev_desc *dev);
+       int (*reattach_i3c_dev)(struct i3c_dev_desc *dev, u8 old_dyn_addr);
+       void (*detach_i3c_dev)(struct i3c_dev_desc *dev);
+       int (*do_daa)(struct i3c_master_controller *master);
+       bool (*supports_ccc_cmd)(struct i3c_master_controller *master,
+                                const struct i3c_ccc_cmd *cmd);
+       int (*send_ccc_cmd)(struct i3c_master_controller *master,
+                           struct i3c_ccc_cmd *cmd);
+       int (*priv_xfers)(struct i3c_dev_desc *dev,
+                         struct i3c_priv_xfer *xfers,
+                         int nxfers);
+       int (*attach_i2c_dev)(struct i2c_dev_desc *dev);
+       void (*detach_i2c_dev)(struct i2c_dev_desc *dev);
+       int (*i2c_xfers)(struct i2c_dev_desc *dev,
+                        const struct i2c_msg *xfers, int nxfers);
+       u32 (*i2c_funcs)(struct i3c_master_controller *master);
+       int (*request_ibi)(struct i3c_dev_desc *dev,
+                          const struct i3c_ibi_setup *req);
+       void (*free_ibi)(struct i3c_dev_desc *dev);
+       int (*enable_ibi)(struct i3c_dev_desc *dev);
+       int (*disable_ibi)(struct i3c_dev_desc *dev);
+       void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
+                                struct i3c_ibi_slot *slot);
+};
+
+/**
+ * struct i3c_master_controller - I3C master controller object
+ * @dev: device to be registered to the device-model
+ * @this: an I3C device object representing this master. This device will be
+ *       added to the list of I3C devs available on the bus
+ * @i2c: I2C adapter used for backward compatibility. This adapter is
+ *      registered to the I2C subsystem to be as transparent as possible to
+ *      existing I2C drivers
+ * @ops: master operations. See &struct i3c_master_controller_ops
+ * @secondary: true if the master is a secondary master
+ * @init_done: true when the bus initialization is done
+ * @boardinfo.i3c: list of I3C  boardinfo objects
+ * @boardinfo.i2c: list of I2C boardinfo objects
+ * @boardinfo: board-level information attached to devices connected on the bus
+ * @bus: I3C bus exposed by this master
+ * @wq: workqueue used to execute IBI handlers. Can also be used by master
+ *     drivers if they need to postpone operations that need to take place
+ *     in a thread context. Typical examples are Hot Join processing which
+ *     requires taking the bus lock in maintenance, which in turn, can only
+ *     be done from a sleep-able context
+ *
+ * A &struct i3c_master_controller has to be registered to the I3C subsystem
+ * through i3c_master_register(). None of &struct i3c_master_controller fields
+ * should be set manually, just pass appropriate values to
+ * i3c_master_register().
+ */
+struct i3c_master_controller {
+       struct device dev;
+       struct i3c_dev_desc *this;
+       struct i2c_adapter i2c;
+       const struct i3c_master_controller_ops *ops;
+       unsigned int secondary : 1;
+       unsigned int init_done : 1;
+       struct {
+               struct list_head i3c;
+               struct list_head i2c;
+       } boardinfo;
+       struct i3c_bus bus;
+       struct workqueue_struct *wq;
+};
+
+/**
+ * i3c_bus_for_each_i2cdev() - iterate over all I2C devices present on the bus
+ * @bus: the I3C bus
+ * @dev: an I2C device descriptor pointer updated to point to the current slot
+ *      at each iteration of the loop
+ *
+ * Iterate over all I2C devs present on the bus.
+ */
+#define i3c_bus_for_each_i2cdev(bus, dev)                              \
+       list_for_each_entry(dev, &(bus)->devs.i2c, common.node)
+
+/**
+ * i3c_bus_for_each_i3cdev() - iterate over all I3C devices present on the bus
+ * @bus: the I3C bus
+ * @dev: and I3C device descriptor pointer updated to point to the current slot
+ *      at each iteration of the loop
+ *
+ * Iterate over all I3C devs present on the bus.
+ */
+#define i3c_bus_for_each_i3cdev(bus, dev)                              \
+       list_for_each_entry(dev, &(bus)->devs.i3c, common.node)
+
+int i3c_master_do_i2c_xfers(struct i3c_master_controller *master,
+                           const struct i2c_msg *xfers,
+                           int nxfers);
+
+int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr,
+                           u8 evts);
+int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr,
+                          u8 evts);
+int i3c_master_entdaa_locked(struct i3c_master_controller *master);
+int i3c_master_defslvs_locked(struct i3c_master_controller *master);
+
+int i3c_master_get_free_addr(struct i3c_master_controller *master,
+                            u8 start_addr);
+
+int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
+                                 u8 addr);
+int i3c_master_do_daa(struct i3c_master_controller *master);
+
+int i3c_master_set_info(struct i3c_master_controller *master,
+                       const struct i3c_device_info *info);
+
+int i3c_master_register(struct i3c_master_controller *master,
+                       struct device *parent,
+                       const struct i3c_master_controller_ops *ops,
+                       bool secondary);
+int i3c_master_unregister(struct i3c_master_controller *master);
+
+/**
+ * i3c_dev_get_master_data() - get master private data attached to an I3C
+ *                            device descriptor
+ * @dev: the I3C device descriptor to get private data from
+ *
+ * Return: the private data previously attached with i3c_dev_set_master_data()
+ *        or NULL if no data has been attached to the device.
+ */
+static inline void *i3c_dev_get_master_data(const struct i3c_dev_desc *dev)
+{
+       return dev->common.master_priv;
+}
+
+/**
+ * i3c_dev_set_master_data() - attach master private data to an I3C device
+ *                            descriptor
+ * @dev: the I3C device descriptor to attach private data to
+ * @data: private data
+ *
+ * This functions allows a master controller to attach per-device private data
+ * which can then be retrieved with i3c_dev_get_master_data().
+ */
+static inline void i3c_dev_set_master_data(struct i3c_dev_desc *dev,
+                                          void *data)
+{
+       dev->common.master_priv = data;
+}
+
+/**
+ * i2c_dev_get_master_data() - get master private data attached to an I2C
+ *                            device descriptor
+ * @dev: the I2C device descriptor to get private data from
+ *
+ * Return: the private data previously attached with i2c_dev_set_master_data()
+ *        or NULL if no data has been attached to the device.
+ */
+static inline void *i2c_dev_get_master_data(const struct i2c_dev_desc *dev)
+{
+       return dev->common.master_priv;
+}
+
+/**
+ * i2c_dev_set_master_data() - attach master private data to an I2C device
+ *                            descriptor
+ * @dev: the I2C device descriptor to attach private data to
+ * @data: private data
+ *
+ * This functions allows a master controller to attach per-device private data
+ * which can then be retrieved with i2c_device_get_master_data().
+ */
+static inline void i2c_dev_set_master_data(struct i2c_dev_desc *dev,
+                                          void *data)
+{
+       dev->common.master_priv = data;
+}
+
+/**
+ * i3c_dev_get_master() - get master used to communicate with a device
+ * @dev: I3C dev
+ *
+ * Return: the master controller driving @dev
+ */
+static inline struct i3c_master_controller *
+i3c_dev_get_master(struct i3c_dev_desc *dev)
+{
+       return dev->common.master;
+}
+
+/**
+ * i2c_dev_get_master() - get master used to communicate with a device
+ * @dev: I2C dev
+ *
+ * Return: the master controller driving @dev
+ */
+static inline struct i3c_master_controller *
+i2c_dev_get_master(struct i2c_dev_desc *dev)
+{
+       return dev->common.master;
+}
+
+/**
+ * i3c_master_get_bus() - get the bus attached to a master
+ * @master: master object
+ *
+ * Return: the I3C bus @master is connected to
+ */
+static inline struct i3c_bus *
+i3c_master_get_bus(struct i3c_master_controller *master)
+{
+       return &master->bus;
+}
+
+struct i3c_generic_ibi_pool;
+
+struct i3c_generic_ibi_pool *
+i3c_generic_ibi_alloc_pool(struct i3c_dev_desc *dev,
+                          const struct i3c_ibi_setup *req);
+void i3c_generic_ibi_free_pool(struct i3c_generic_ibi_pool *pool);
+
+struct i3c_ibi_slot *
+i3c_generic_ibi_get_free_slot(struct i3c_generic_ibi_pool *pool);
+void i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool,
+                                 struct i3c_ibi_slot *slot);
+
+void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot);
+
+struct i3c_ibi_slot *i3c_master_get_free_ibi_slot(struct i3c_dev_desc *dev);
+
+#endif /* I3C_MASTER_H */
index 7393a316d9fadf6e01497b1273222977e98c9132..580cbaef789a097ea16f6cb3e3db93835774b07c 100644 (file)
@@ -487,4 +487,24 @@ struct led_pattern {
        int brightness;
 };
 
+enum led_audio {
+       LED_AUDIO_MUTE,         /* master mute LED */
+       LED_AUDIO_MICMUTE,      /* mic mute LED */
+       NUM_AUDIO_LEDS
+};
+
+#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO)
+enum led_brightness ledtrig_audio_get(enum led_audio type);
+void ledtrig_audio_set(enum led_audio type, enum led_brightness state);
+#else
+static inline enum led_brightness ledtrig_audio_get(enum led_audio type)
+{
+       return LED_OFF;
+}
+static inline void ledtrig_audio_set(enum led_audio type,
+                                    enum led_brightness state)
+{
+}
+#endif
+
 #endif         /* __LINUX_LEDS_H_INCLUDED */
index 517e60eecbcbea92e6f81c9fb7615b2a9a387fcb..1293695245dfe7cce4aaafea84a46a14fe82450c 100644 (file)
@@ -35,7 +35,7 @@ enum axp20x_variants {
 #define AXP152_ALDO_OP_MODE            0x13
 #define AXP152_LDO0_CTRL               0x15
 #define AXP152_DCDC2_V_OUT             0x23
-#define AXP152_DCDC2_V_SCAL            0x25
+#define AXP152_DCDC2_V_RAMP            0x25
 #define AXP152_DCDC1_V_OUT             0x26
 #define AXP152_DCDC3_V_OUT             0x27
 #define AXP152_ALDO12_V_OUT            0x28
@@ -53,7 +53,7 @@ enum axp20x_variants {
 #define AXP20X_USB_OTG_STATUS          0x02
 #define AXP20X_PWR_OUT_CTRL            0x12
 #define AXP20X_DCDC2_V_OUT             0x23
-#define AXP20X_DCDC2_LDO3_V_SCAL       0x25
+#define AXP20X_DCDC2_LDO3_V_RAMP       0x25
 #define AXP20X_DCDC3_V_OUT             0x27
 #define AXP20X_LDO24_V_OUT             0x28
 #define AXP20X_LDO3_V_OUT              0x29
index b19c370fe81a07d302ccca41d2f038f6de472b98..f346167c0e00166dced89e1c89b064436f9cf0dc 100644 (file)
@@ -20,9 +20,6 @@
 #define WM8994_NUM_AIF   3
 
 struct wm8994_ldo_pdata {
-       /** GPIOs to enable regulator, 0 or less if not available */
-       int enable;
-
        const struct regulator_init_data *init_data;
 };
 
index 34e17e6f894290f161d5e734e6fb2f9dfb0c148e..4e77bfe0b5803330e14c6fe39f038089713d2fcb 100644 (file)
@@ -582,11 +582,13 @@ struct mlx5_ifc_flow_table_nic_cap_bits {
 };
 
 struct mlx5_ifc_flow_table_eswitch_cap_bits {
-       u8      reserved_at_0[0x1c];
-       u8      fdb_multi_path_to_table[0x1];
-       u8      reserved_at_1d[0x1];
+       u8      reserved_at_0[0x1a];
        u8      multi_fdb_encap[0x1];
-       u8      reserved_at_1e[0x1e1];
+       u8      reserved_at_1b[0x1];
+       u8      fdb_multi_path_to_table[0x1];
+       u8      reserved_at_1d[0x3];
+
+       u8      reserved_at_20[0x1e0];
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_esw_fdb;
 
index 01797cb4587ede275db60176820571a3dea92c18..f9bd2f34b99f442af76b98683706468d0dc5473f 100644 (file)
@@ -448,6 +448,23 @@ struct pci_epf_device_id {
        kernel_ulong_t driver_data;
 };
 
+/* i3c */
+
+#define I3C_MATCH_DCR                  0x1
+#define I3C_MATCH_MANUF                        0x2
+#define I3C_MATCH_PART                 0x4
+#define I3C_MATCH_EXTRA_INFO           0x8
+
+struct i3c_device_id {
+       __u8 match_flags;
+       __u8 dcr;
+       __u16 manuf_id;
+       __u16 part_id;
+       __u16 extra_info;
+
+       const void *data;
+};
+
 /* spi */
 
 #define SPI_NAME_SIZE  32
@@ -565,7 +582,7 @@ struct platform_device_id {
 /**
  * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus
  * @phy_id: The result of
- *     (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask
+ *     (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&MII_PHYSID2)) & @phy_id_mask
  *     for this PHY type
  * @phy_id_mask: Defines the significant bits of @phy_id.  A value of 0
  *     is used to terminate an array of struct mdio_device_id.
index 9b57a9b1b081d375b2a5bf0b8f28f4ee92305b18..cbf77168658c72aed74214d8b75d54617b457dd1 100644 (file)
@@ -377,6 +377,7 @@ struct cfi_fixup {
 #define CFI_MFR_SHARP          0x00B0
 #define CFI_MFR_SST            0x00BF
 #define CFI_MFR_ST             0x0020 /* STMicroelectronics */
+#define CFI_MFR_MICRON         0x002C /* Micron */
 #define CFI_MFR_TOSHIBA                0x0098
 #define CFI_MFR_WINBOND                0x00DA
 
index cd0be91bdefa55f568253904c7d374751fffac52..ba8fa9072aca404314bf59ffded5acf7bf6b745d 100644 (file)
@@ -207,6 +207,7 @@ struct mtd_debug_info {
 struct mtd_info {
        u_char type;
        uint32_t flags;
+       uint32_t orig_flags; /* Flags as before running mtd checks */
        uint64_t size;   // Total size of the MTD
 
        /* "Major" erase size for the device. Naïve users may take this
@@ -386,7 +387,7 @@ static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
        return dev_of_node(&mtd->dev);
 }
 
-static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
+static inline u32 mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
 {
        return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
 }
index e10b126e148f0a9f8e045ffbfa9b016f9adaed17..33e240acdc6dd4088750cefa3ff212d83109fc8f 100644 (file)
@@ -203,9 +203,12 @@ enum nand_ecc_algo {
  */
 #define NAND_IS_BOOT_MEDIUM    0x00400000
 
-/* Options set by nand scan */
-/* Nand scan has allocated controller struct */
-#define NAND_CONTROLLER_ALLOC  0x80000000
+/*
+ * Do not try to tweak the timings at runtime. This is needed when the
+ * controller initializes the timings on itself or when it relies on
+ * configuration done by the bootloader.
+ */
+#define NAND_KEEP_TIMINGS      0x00800000
 
 /* Cell info constants */
 #define NAND_CI_CHIPNR_MSK     0x03
@@ -244,49 +247,6 @@ struct nand_id {
        int len;
 };
 
-/**
- * struct nand_controller_ops - Controller operations
- *
- * @attach_chip: this method is called after the NAND detection phase after
- *              flash ID and MTD fields such as erase size, page size and OOB
- *              size have been set up. ECC requirements are available if
- *              provided by the NAND chip or device tree. Typically used to
- *              choose the appropriate ECC configuration and allocate
- *              associated resources.
- *              This hook is optional.
- * @detach_chip: free all resources allocated/claimed in
- *              nand_controller_ops->attach_chip().
- *              This hook is optional.
- */
-struct nand_controller_ops {
-       int (*attach_chip)(struct nand_chip *chip);
-       void (*detach_chip)(struct nand_chip *chip);
-};
-
-/**
- * struct nand_controller - Structure used to describe a NAND controller
- *
- * @lock:               protection lock
- * @active:            the mtd device which holds the controller currently
- * @wq:                        wait queue to sleep on if a NAND operation is in
- *                     progress used instead of the per chip wait queue
- *                     when a hw controller is available.
- * @ops:               NAND controller operations.
- */
-struct nand_controller {
-       spinlock_t lock;
-       struct nand_chip *active;
-       wait_queue_head_t wq;
-       const struct nand_controller_ops *ops;
-};
-
-static inline void nand_controller_init(struct nand_controller *nfc)
-{
-       nfc->active = NULL;
-       spin_lock_init(&nfc->lock);
-       init_waitqueue_head(&nfc->wq);
-}
-
 /**
  * struct nand_ecc_step_info - ECC step information of ECC engine
  * @stepsize: data bytes per ECC step
@@ -879,18 +839,21 @@ struct nand_op_parser {
 
 /**
  * struct nand_operation - NAND operation descriptor
+ * @cs: the CS line to select for this NAND operation
  * @instrs: array of instructions to execute
  * @ninstrs: length of the @instrs array
  *
  * The actual operation structure that will be passed to chip->exec_op().
  */
 struct nand_operation {
+       unsigned int cs;
        const struct nand_op_instr *instrs;
        unsigned int ninstrs;
 };
 
-#define NAND_OPERATION(_instrs)                                        \
+#define NAND_OPERATION(_cs, _instrs)                           \
        {                                                       \
+               .cs = _cs,                                      \
                .instrs = _instrs,                              \
                .ninstrs = ARRAY_SIZE(_instrs),                 \
        }
@@ -898,11 +861,68 @@ struct nand_operation {
 int nand_op_parser_exec_op(struct nand_chip *chip,
                           const struct nand_op_parser *parser,
                           const struct nand_operation *op, bool check_only);
+/**
+ * struct nand_controller_ops - Controller operations
+ *
+ * @attach_chip: this method is called after the NAND detection phase after
+ *              flash ID and MTD fields such as erase size, page size and OOB
+ *              size have been set up. ECC requirements are available if
+ *              provided by the NAND chip or device tree. Typically used to
+ *              choose the appropriate ECC configuration and allocate
+ *              associated resources.
+ *              This hook is optional.
+ * @detach_chip: free all resources allocated/claimed in
+ *              nand_controller_ops->attach_chip().
+ *              This hook is optional.
+ * @exec_op:    controller specific method to execute NAND operations.
+ *              This method replaces chip->legacy.cmdfunc(),
+ *              chip->legacy.{read,write}_{buf,byte,word}(),
+ *              chip->legacy.dev_ready() and chip->legacy.waifunc().
+ * @setup_data_interface: setup the data interface and timing. If
+ *                       chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
+ *                       means the configuration should not be applied but
+ *                       only checked.
+ *                       This hook is optional.
+ */
+struct nand_controller_ops {
+       int (*attach_chip)(struct nand_chip *chip);
+       void (*detach_chip)(struct nand_chip *chip);
+       int (*exec_op)(struct nand_chip *chip,
+                      const struct nand_operation *op,
+                      bool check_only);
+       int (*setup_data_interface)(struct nand_chip *chip, int chipnr,
+                                   const struct nand_data_interface *conf);
+};
+
+/**
+ * struct nand_controller - Structure used to describe a NAND controller
+ *
+ * @lock:               protection lock
+ * @active:            the mtd device which holds the controller currently
+ * @wq:                        wait queue to sleep on if a NAND operation is in
+ *                     progress used instead of the per chip wait queue
+ *                     when a hw controller is available.
+ * @ops:               NAND controller operations.
+ */
+struct nand_controller {
+       spinlock_t lock;
+       struct nand_chip *active;
+       wait_queue_head_t wq;
+       const struct nand_controller_ops *ops;
+};
+
+static inline void nand_controller_init(struct nand_controller *nfc)
+{
+       nfc->active = NULL;
+       spin_lock_init(&nfc->lock);
+       init_waitqueue_head(&nfc->wq);
+}
 
 /**
  * struct nand_legacy - NAND chip legacy fields/hooks
  * @IO_ADDR_R: address to read the 8 I/O lines of the flash device
  * @IO_ADDR_W: address to write the 8 I/O lines of the flash device
+ * @select_chip: select/deselect a specific target/die
  * @read_byte: read one byte from the chip
  * @write_byte: write a single byte to the chip on the low 8 I/O lines
  * @write_buf: write data from the buffer to the chip
@@ -921,6 +941,8 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
  * @get_features: get the NAND chip features
  * @chip_delay: chip dependent delay for transferring data from array to read
  *             regs (tR).
+ * @dummy_controller: dummy controller implementation for drivers that can
+ *                   only control a single chip
  *
  * If you look at this structure you're already wrong. These fields/hooks are
  * all deprecated.
@@ -928,6 +950,7 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
 struct nand_legacy {
        void __iomem *IO_ADDR_R;
        void __iomem *IO_ADDR_W;
+       void (*select_chip)(struct nand_chip *chip, int cs);
        u8 (*read_byte)(struct nand_chip *chip);
        void (*write_byte)(struct nand_chip *chip, u8 byte);
        void (*write_buf)(struct nand_chip *chip, const u8 *buf, int len);
@@ -945,6 +968,7 @@ struct nand_legacy {
        int (*get_features)(struct nand_chip *chip, int feature_addr,
                            u8 *subfeature_para);
        int chip_delay;
+       struct nand_controller dummy_controller;
 };
 
 /**
@@ -955,17 +979,10 @@ struct nand_legacy {
  *                     you're modifying an existing driver that is using those
  *                     fields/hooks, you should consider reworking the driver
  *                     avoid using them.
- * @select_chip:       [REPLACEABLE] select chip nr
- * @exec_op:           controller specific method to execute NAND operations.
- *                     This method replaces ->cmdfunc(),
- *                     ->legacy.{read,write}_{buf,byte,word}(),
- *                     ->legacy.dev_ready() and ->waifunc().
  * @setup_read_retry:  [FLASHSPECIFIC] flash (vendor) specific function for
  *                     setting the read-retry mode. Mostly needed for MLC NAND.
  * @ecc:               [BOARDSPECIFIC] ECC control structure
  * @buf_align:         minimum buffer alignment required by a platform
- * @dummy_controller:  dummy controller implementation for drivers that can
- *                     only control a single chip
  * @state:             [INTERN] the current state of the NAND device
  * @oob_poi:           "poison value buffer," used for laying out OOB data
  *                     before writing
@@ -1012,11 +1029,11 @@ struct nand_legacy {
  *                     this nand device will encounter their life times.
  * @blocks_per_die:    [INTERN] The number of PEBs in a die
  * @data_interface:    [INTERN] NAND interface timing information
+ * @cur_cs:            currently selected target. -1 means no target selected,
+ *                     otherwise we should always have cur_cs >= 0 &&
+ *                     cur_cs < numchips. NAND Controller drivers should not
+ *                     modify this value, but they're allowed to read it.
  * @read_retries:      [INTERN] the number of read retry modes supported
- * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If
- *                       chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
- *                       means the configuration should not be applied but
- *                       only checked.
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
  *                     lookup.
@@ -1037,13 +1054,7 @@ struct nand_chip {
 
        struct nand_legacy legacy;
 
-       void (*select_chip)(struct nand_chip *chip, int cs);
-       int (*exec_op)(struct nand_chip *chip,
-                      const struct nand_operation *op,
-                      bool check_only);
        int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
-       int (*setup_data_interface)(struct nand_chip *chip, int chipnr,
-                                   const struct nand_data_interface *conf);
 
        unsigned int options;
        unsigned int bbt_options;
@@ -1073,6 +1084,8 @@ struct nand_chip {
 
        struct nand_data_interface data_interface;
 
+       int cur_cs;
+
        int read_retries;
 
        flstate_t state;
@@ -1082,7 +1095,6 @@ struct nand_chip {
 
        struct nand_ecc_ctrl ecc;
        unsigned long buf_align;
-       struct nand_controller dummy_controller;
 
        uint8_t *bbt;
        struct nand_bbt_descr *bbt_td;
@@ -1098,15 +1110,6 @@ struct nand_chip {
        } manufacturer;
 };
 
-static inline int nand_exec_op(struct nand_chip *chip,
-                              const struct nand_operation *op)
-{
-       if (!chip->exec_op)
-               return -ENOTSUPP;
-
-       return chip->exec_op(chip, op, false);
-}
-
 extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
 extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
 
@@ -1345,5 +1348,12 @@ void nand_release(struct nand_chip *chip);
  * instruction and have no physical pin to check it.
  */
 int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms);
+struct gpio_desc;
+int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
+                     unsigned long timeout_ms);
+
+/* Select/deselect a NAND target. */
+void nand_select_target(struct nand_chip *chip, unsigned int cs);
+void nand_deselect_target(struct nand_chip *chip);
 
 #endif /* __LINUX_MTD_RAWNAND_H */
index c759d403cbc06fba6626de302ca583800176de94..78fc2d4218c8082fe3855accf0a4f295a574c604 100644 (file)
@@ -1,20 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
  * SuperH FLCTL nand controller
  *
  * Copyright © 2008 Renesas Solutions Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #ifndef __SH_FLCTL_H__
index 7f0c7303575e92a0f9029e6973c624c775776136..fa2d89e38e403dda8107c84d24fb9c8a5d9094bc 100644 (file)
@@ -1,10 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  */
 
 #ifndef __LINUX_MTD_SPI_NOR_H
@@ -23,7 +19,8 @@
 #define SNOR_MFR_ATMEL         CFI_MFR_ATMEL
 #define SNOR_MFR_GIGADEVICE    0xc8
 #define SNOR_MFR_INTEL         CFI_MFR_INTEL
-#define SNOR_MFR_MICRON                CFI_MFR_ST /* ST Micro <--> Micron */
+#define SNOR_MFR_ST            CFI_MFR_ST      /* ST Micro */
+#define SNOR_MFR_MICRON                CFI_MFR_MICRON  /* Micron */
 #define SNOR_MFR_MACRONIX      CFI_MFR_MACRONIX
 #define SNOR_MFR_SPANSION      CFI_MFR_AMD
 #define SNOR_MFR_SST           CFI_MFR_SST
@@ -236,6 +233,8 @@ enum spi_nor_option_flags {
        SNOR_F_READY_XSR_RDY    = BIT(4),
        SNOR_F_USE_CLSR         = BIT(5),
        SNOR_F_BROKEN_RESET     = BIT(6),
+       SNOR_F_4B_OPCODES       = BIT(7),
+       SNOR_F_HAS_4BAIT        = BIT(8),
 };
 
 /**
index 088ff96c3eb6d4964df57fad76cc4f7a76089267..b92e2aa955b6f8f59fec6dfc802e15658b126b5c 100644 (file)
@@ -194,8 +194,10 @@ struct spinand_manufacturer {
 };
 
 /* SPI NAND manufacturers */
+extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
 /**
index 4a520d3304a2fad7a47ddd366672c2fbb054ec1e..cf09ab37b45b7d5990c388799b7f502d500cd182 100644 (file)
@@ -62,18 +62,6 @@ static inline bool lockdep_nfnl_is_held(__u8 subsys_id)
 }
 #endif /* CONFIG_PROVE_LOCKING */
 
-/*
- * nfnl_dereference - fetch RCU pointer when updates are prevented by subsys mutex
- *
- * @p: The pointer to read, prior to dereferencing
- * @ss: The nfnetlink subsystem ID
- *
- * Return the value of the specified RCU-protected pointer, but omit
- * the READ_ONCE(), because caller holds the NFNL subsystem mutex.
- */
-#define nfnl_dereference(p, ss)                                        \
-       rcu_dereference_protected(p, lockdep_nfnl_is_held(ss))
-
 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
        MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
 
index 11c71c4ecf75a584ca28723083ec8b640e293b2f..51a5a5217667f9b6eab49167d1872a9d41968e68 100644 (file)
@@ -1960,7 +1960,11 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev,
                                 enum pcie_reset_state state);
 int pcibios_add_device(struct pci_dev *dev);
 void pcibios_release_device(struct pci_dev *dev);
+#ifdef CONFIG_PCI
 void pcibios_penalize_isa_irq(int irq, int active);
+#else
+static inline void pcibios_penalize_isa_irq(int irq, int active) {}
+#endif
 int pcibios_alloc_irq(struct pci_dev *dev);
 void pcibios_free_irq(struct pci_dev *dev);
 resource_size_t pcibios_default_alignment(void);
index 85ad68f9206ae929b4cc3ec571735c651134be09..7fe80f1c7e081c0cad5b0ba4ce2db562f249edc8 100644 (file)
@@ -79,6 +79,7 @@ struct davinci_mcasp_pdata {
        /* McASP specific fields */
        int tdm_slots;
        u8 op_mode;
+       u8 dismod;
        u8 num_serializer;
        u8 *serial_dir;
        u8 version;
index e723b78d835706f2af7e06dc2e0379e9406a981c..0bd9de116826a02a942e3162b8f4126fe3526242 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/timer.h>
+#include <linux/hrtimer.h>
 #include <linux/completion.h>
 
 /*
@@ -608,7 +609,7 @@ struct dev_pm_info {
        unsigned int            should_wakeup:1;
 #endif
 #ifdef CONFIG_PM
-       struct timer_list       suspend_timer;
+       struct hrtimer          suspend_timer;
        unsigned long           timer_expires;
        struct work_struct      work;
        wait_queue_head_t       wait_queue;
@@ -631,7 +632,7 @@ struct dev_pm_info {
        enum rpm_status         runtime_status;
        int                     runtime_error;
        int                     autosuspend_delay;
-       unsigned long           last_busy;
+       u64                     last_busy;
        unsigned long           active_jiffies;
        unsigned long           suspended_jiffies;
        unsigned long           accounting_timestamp;
index 3b5d7280e52e19971fdd0b21e311c54d39b60f15..dd364abb649a40cdd9ca02a29b86d94588fbeaa2 100644 (file)
@@ -73,6 +73,7 @@ struct genpd_power_state {
 
 struct genpd_lock_ops;
 struct dev_pm_opp;
+struct opp_table;
 
 struct generic_pm_domain {
        struct device dev;
@@ -94,6 +95,7 @@ struct generic_pm_domain {
        unsigned int performance_state; /* Aggregated max performance state */
        int (*power_off)(struct generic_pm_domain *domain);
        int (*power_on)(struct generic_pm_domain *domain);
+       struct opp_table *opp_table;    /* OPP table of the genpd */
        unsigned int (*opp_to_performance_state)(struct generic_pm_domain *genpd,
                                                 struct dev_pm_opp *opp);
        int (*set_performance_state)(struct generic_pm_domain *genpd,
@@ -134,6 +136,10 @@ struct gpd_link {
        struct list_head master_node;
        struct generic_pm_domain *slave;
        struct list_head slave_node;
+
+       /* Sub-domain's per-master domain performance state */
+       unsigned int performance_state;
+       unsigned int prev_performance_state;
 };
 
 struct gpd_timing_data {
@@ -258,8 +264,8 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent,
 struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
 int of_genpd_parse_idle_states(struct device_node *dn,
                               struct genpd_power_state **states, int *n);
-unsigned int of_genpd_opp_to_performance_state(struct device *dev,
-                               struct device_node *np);
+unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev,
+                                              struct dev_pm_opp *opp);
 
 int genpd_dev_pm_attach(struct device *dev);
 struct device *genpd_dev_pm_attach_by_id(struct device *dev,
@@ -300,8 +306,8 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,
 }
 
 static inline unsigned int
-of_genpd_opp_to_performance_state(struct device *dev,
-                                 struct device_node *np)
+pm_genpd_opp_to_performance_state(struct device *genpd_dev,
+                                 struct dev_pm_opp *opp)
 {
        return 0;
 }
index 5d399eeef172770124cd5a59679c0d2a2e3c2f10..0a2a88e5a383f18934830f0548892cad10737bad 100644 (file)
@@ -126,6 +126,9 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name);
 void dev_pm_opp_put_clkname(struct opp_table *opp_table);
 struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
 void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
+struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, struct device *virt_dev, int index);
+void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, struct device *virt_dev);
+int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
 int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -272,6 +275,18 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const
 
 static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
 
+static inline struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, struct device *virt_dev, int index)
+{
+       return ERR_PTR(-ENOTSUPP);
+}
+
+static inline void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, struct device *virt_dev) {}
+
+static inline int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate)
+{
+       return -ENOTSUPP;
+}
+
 static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 {
        return -ENOTSUPP;
@@ -305,8 +320,8 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
 void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
 int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
 struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
-struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, struct device_node *np);
 struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp);
+int of_get_required_opp_performance_state(struct device_node *np, int index);
 #else
 static inline int dev_pm_opp_of_add_table(struct device *dev)
 {
@@ -341,13 +356,13 @@ static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device
        return NULL;
 }
 
-static inline struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, struct device_node *np)
+static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
 {
        return NULL;
 }
-static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
+static inline int of_get_required_opp_performance_state(struct device_node *np, int index)
 {
-       return NULL;
+       return -ENOTSUPP;
 }
 #endif
 
index f0fc4700b6ff53adfb8584162ae0bb3c522237a2..54af4eef169f3e6b8e775a2352a83f99cfa36b37 100644 (file)
@@ -51,7 +51,7 @@ extern void pm_runtime_no_callbacks(struct device *dev);
 extern void pm_runtime_irq_safe(struct device *dev);
 extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
 extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
-extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
+extern u64 pm_runtime_autosuspend_expiration(struct device *dev);
 extern void pm_runtime_update_max_time_suspended(struct device *dev,
                                                 s64 delta_ns);
 extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable);
@@ -105,7 +105,7 @@ static inline bool pm_runtime_callbacks_present(struct device *dev)
 
 static inline void pm_runtime_mark_last_busy(struct device *dev)
 {
-       WRITE_ONCE(dev->power.last_busy, jiffies);
+       WRITE_ONCE(dev->power.last_busy, ktime_to_ns(ktime_get()));
 }
 
 static inline bool pm_runtime_is_irq_safe(struct device *dev)
@@ -168,7 +168,7 @@ static inline void __pm_runtime_use_autosuspend(struct device *dev,
                                                bool use) {}
 static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
                                                int delay) {}
-static inline unsigned long pm_runtime_autosuspend_expiration(
+static inline u64 pm_runtime_autosuspend_expiration(
                                struct device *dev) { return 0; }
 static inline void pm_runtime_set_memalloc_noio(struct device *dev,
                                                bool enable){}
index 7b81dad712de86512b0ab95f7a69b90ffaa12390..d0b37e937037269cc3493dce71fc629d229b802e 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * OMAP Smartreflex Defines and Routines
  *
  *
  * Copyright (C) 2007 Texas Instruments, Inc.
  * Lesly A M <x0080970@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __POWER_SMARTREFLEX_H
@@ -303,9 +300,6 @@ void omap_sr_enable(struct voltagedomain *voltdm);
 void omap_sr_disable(struct voltagedomain *voltdm);
 void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
 
-/* API to register the pmic specific data with the smartreflex driver. */
-void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
-
 /* Smartreflex driver hooks to be called from Smartreflex class driver */
 int sr_enable(struct omap_sr *sr, unsigned long volt);
 void sr_disable(struct omap_sr *sr);
@@ -320,7 +314,5 @@ static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
 static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
 static inline void omap_sr_disable_reset_volt(
                struct voltagedomain *voltdm) {}
-static inline void omap_sr_register_pmic(
-               struct omap_sr_pmic_data *pmic_data) {}
 #endif
 #endif
index 56518adc31dd702bc849078005a564b8ae6fa0df..d5199b507d79527a6f5278194596b0c42f452e9c 100644 (file)
@@ -348,42 +348,6 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
        return pwm_apply_state(pwm, &state);
 }
 
-/**
- * pwm_set_polarity() - configure the polarity of a PWM signal
- * @pwm: PWM device
- * @polarity: new polarity of the PWM signal
- *
- * Note that the polarity cannot be configured while the PWM device is
- * enabled.
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-static inline int pwm_set_polarity(struct pwm_device *pwm,
-                                  enum pwm_polarity polarity)
-{
-       struct pwm_state state;
-
-       if (!pwm)
-               return -EINVAL;
-
-       pwm_get_state(pwm, &state);
-       if (state.polarity == polarity)
-               return 0;
-
-       /*
-        * Changing the polarity of a running PWM without adjusting the
-        * dutycycle/period value is a bit risky (can introduce glitches).
-        * Return -EBUSY in this case.
-        * Note that this is allowed when using pwm_apply_state() because
-        * the user specifies all the parameters.
-        */
-       if (state.enabled)
-               return -EBUSY;
-
-       state.polarity = polarity;
-       return pwm_apply_state(pwm, &state);
-}
-
 /**
  * pwm_enable() - start a PWM output toggling
  * @pwm: PWM device
@@ -483,12 +447,6 @@ static inline int pwm_capture(struct pwm_device *pwm,
        return -EINVAL;
 }
 
-static inline int pwm_set_polarity(struct pwm_device *pwm,
-                                  enum pwm_polarity polarity)
-{
-       return -ENOTSUPP;
-}
-
 static inline int pwm_enable(struct pwm_device *pwm)
 {
        return -EINVAL;
index 25602afd48447f3c410f79082e966b1d4589d911..f3f76051e8b008346a0e7acd4b6512d7ecef85f3 100644 (file)
@@ -508,7 +508,7 @@ static inline int regulator_get_error_flags(struct regulator *regulator,
 
 static inline int regulator_set_load(struct regulator *regulator, int load_uA)
 {
-       return REGULATOR_MODE_NORMAL;
+       return 0;
 }
 
 static inline int regulator_allow_bypass(struct regulator *regulator,
index a9c030192147dffd23610082ae8a22426dc000c7..389bcaf7900f6ab733618801b69450441c6cc356 100644 (file)
 #ifndef __LINUX_REGULATOR_DRIVER_H_
 #define __LINUX_REGULATOR_DRIVER_H_
 
-#define MAX_COUPLED            4
+#define MAX_COUPLED            2
 
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/regulator/consumer.h>
+#include <linux/ww_mutex.h>
 
 struct gpio_desc;
 struct regmap;
@@ -462,7 +463,7 @@ struct regulator_dev {
        struct coupling_desc coupling_desc;
 
        struct blocking_notifier_head notifier;
-       struct mutex mutex; /* consumer lock */
+       struct ww_mutex mutex; /* consumer lock */
        struct task_struct *mutex_owner;
        int ref_cnt;
        struct module *owner;
@@ -473,7 +474,6 @@ struct regulator_dev {
        struct regmap *regmap;
 
        struct delayed_work disable_work;
-       int deferred_disables;
 
        void *reg_data;         /* regulator_dev data */
 
@@ -545,4 +545,7 @@ int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
                                          bool enable);
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 
+void regulator_lock(struct regulator_dev *rdev);
+void regulator_unlock(struct regulator_dev *rdev);
+
 #endif
index a459a5e973a7294f171e192dd4dacf98d5b27c16..1d34a70ffda27e58e109835933b57344687b8aaa 100644 (file)
@@ -158,6 +158,9 @@ struct regulation_constraints {
        /* used for coupled regulators */
        int max_spread;
 
+       /* used for changing voltage in steps */
+       int max_uV_step;
+
        /* valid regulator operating modes for this machine */
        unsigned int valid_modes_mask;
 
index cb5aecd40f07d95478141af180d071e43f53af6e..331d7d940c7aadb02a5ae93e4906c55e1ad83294 100644 (file)
@@ -33,7 +33,8 @@
 #define PFUZE100_VGEN4         12
 #define PFUZE100_VGEN5         13
 #define PFUZE100_VGEN6         14
-#define PFUZE100_MAX_REGULATOR 15
+#define PFUZE100_COIN          15
+#define PFUZE100_MAX_REGULATOR 16
 
 #define PFUZE200_SW1AB         0
 #define PFUZE200_SW2           1
index 02166e815afb904c0396159c8c9d556c370f1e9d..2f0ffca357807858c8446ad2d4051dec853481e8 100644 (file)
@@ -68,7 +68,6 @@ struct reservation_object_list {
  * @seq: sequence count for managing RCU read-side synchronization
  * @fence_excl: the exclusive fence, if there is one currently
  * @fence: list of current shared fences
- * @staged: staged copy of shared fences for RCU updates
  */
 struct reservation_object {
        struct ww_mutex lock;
@@ -76,7 +75,6 @@ struct reservation_object {
 
        struct dma_fence __rcu *fence_excl;
        struct reservation_object_list __rcu *fence;
-       struct reservation_object_list *staged;
 };
 
 #define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base)
@@ -95,7 +93,6 @@ reservation_object_init(struct reservation_object *obj)
        __seqcount_init(&obj->seq, reservation_seqcount_string, &reservation_seqcount_class);
        RCU_INIT_POINTER(obj->fence, NULL);
        RCU_INIT_POINTER(obj->fence_excl, NULL);
-       obj->staged = NULL;
 }
 
 /**
@@ -124,7 +121,6 @@ reservation_object_fini(struct reservation_object *obj)
 
                kfree(fobj);
        }
-       kfree(obj->staged);
 
        ww_mutex_destroy(&obj->lock);
 }
@@ -218,6 +214,11 @@ reservation_object_trylock(struct reservation_object *obj)
 static inline void
 reservation_object_unlock(struct reservation_object *obj)
 {
+#ifdef CONFIG_DEBUG_MUTEXES
+       /* Test shared fence slot reservation */
+       if (obj->fence)
+               obj->fence->shared_max = obj->fence->shared_count;
+#endif
        ww_mutex_unlock(&obj->lock);
 }
 
@@ -265,7 +266,8 @@ reservation_object_get_excl_rcu(struct reservation_object *obj)
        return fence;
 }
 
-int reservation_object_reserve_shared(struct reservation_object *obj);
+int reservation_object_reserve_shared(struct reservation_object *obj,
+                                     unsigned int num_fences);
 void reservation_object_add_shared_fence(struct reservation_object *obj,
                                         struct dma_fence *fence);
 
index 9ec4c147abbc7750710da12924c96a7343127364..b0674e330ef66177feaf935f50a56b0e587b52e5 100644 (file)
@@ -25,6 +25,7 @@ struct dma_chan;
 struct pxa2xx_spi_master {
        u16 num_chipselect;
        u8 enable_dma;
+       bool is_slave;
 
        /* DMA engine specific config */
        bool (*dma_filter)(struct dma_chan *chan, void *param);
index 69ee30456864a05ceb76bac1d0dbe8df3a0e3448..3fe24500c5ee957d104f319cd3246e0abccf3a34 100644 (file)
 /**
  * enum spi_mem_data_dir - describes the direction of a SPI memory data
  *                        transfer from the controller perspective
+ * @SPI_MEM_NO_DATA: no data transferred
  * @SPI_MEM_DATA_IN: data coming from the SPI memory
- * @SPI_MEM_DATA_OUT: data sent the SPI memory
+ * @SPI_MEM_DATA_OUT: data sent to the SPI memory
  */
 enum spi_mem_data_dir {
+       SPI_MEM_NO_DATA,
        SPI_MEM_DATA_IN,
        SPI_MEM_DATA_OUT,
 };
@@ -122,6 +124,49 @@ struct spi_mem_op {
                .data = __data,                                 \
        }
 
+/**
+ * struct spi_mem_dirmap_info - Direct mapping information
+ * @op_tmpl: operation template that should be used by the direct mapping when
+ *          the memory device is accessed
+ * @offset: absolute offset this direct mapping is pointing to
+ * @length: length in byte of this direct mapping
+ *
+ * These information are used by the controller specific implementation to know
+ * the portion of memory that is directly mapped and the spi_mem_op that should
+ * be used to access the device.
+ * A direct mapping is only valid for one direction (read or write) and this
+ * direction is directly encoded in the ->op_tmpl.data.dir field.
+ */
+struct spi_mem_dirmap_info {
+       struct spi_mem_op op_tmpl;
+       u64 offset;
+       u64 length;
+};
+
+/**
+ * struct spi_mem_dirmap_desc - Direct mapping descriptor
+ * @mem: the SPI memory device this direct mapping is attached to
+ * @info: information passed at direct mapping creation time
+ * @nodirmap: set to 1 if the SPI controller does not implement
+ *           ->mem_ops->dirmap_create() or when this function returned an
+ *           error. If @nodirmap is true, all spi_mem_dirmap_{read,write}()
+ *           calls will use spi_mem_exec_op() to access the memory. This is a
+ *           degraded mode that allows spi_mem drivers to use the same code
+ *           no matter whether the controller supports direct mapping or not
+ * @priv: field pointing to controller specific data
+ *
+ * Common part of a direct mapping descriptor. This object is created by
+ * spi_mem_dirmap_create() and controller implementation of ->create_dirmap()
+ * can create/attach direct mapping resources to the descriptor in the ->priv
+ * field.
+ */
+struct spi_mem_dirmap_desc {
+       struct spi_mem *mem;
+       struct spi_mem_dirmap_info info;
+       unsigned int nodirmap;
+       void *priv;
+};
+
 /**
  * struct spi_mem - describes a SPI memory device
  * @spi: the underlying SPI device
@@ -177,10 +222,32 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
  *           Note that if the implementation of this function allocates memory
  *           dynamically, then it should do so with devm_xxx(), as we don't
  *           have a ->free_name() function.
+ * @dirmap_create: create a direct mapping descriptor that can later be used to
+ *                access the memory device. This method is optional
+ * @dirmap_destroy: destroy a memory descriptor previous created by
+ *                 ->dirmap_create()
+ * @dirmap_read: read data from the memory device using the direct mapping
+ *              created by ->dirmap_create(). The function can return less
+ *              data than requested (for example when the request is crossing
+ *              the currently mapped area), and the caller of
+ *              spi_mem_dirmap_read() is responsible for calling it again in
+ *              this case.
+ * @dirmap_write: write data to the memory device using the direct mapping
+ *               created by ->dirmap_create(). The function can return less
+ *               data than requested (for example when the request is crossing
+ *               the currently mapped area), and the caller of
+ *               spi_mem_dirmap_write() is responsible for calling it again in
+ *               this case.
  *
  * This interface should be implemented by SPI controllers providing an
  * high-level interface to execute SPI memory operation, which is usually the
  * case for QSPI controllers.
+ *
+ * Note on ->dirmap_{read,write}(): drivers should avoid accessing the direct
+ * mapping from the CPU because doing that can stall the CPU waiting for the
+ * SPI mem transaction to finish, and this will make real-time maintainers
+ * unhappy and might make your system less reactive. Instead, drivers should
+ * use DMA to access this direct mapping.
  */
 struct spi_controller_mem_ops {
        int (*adjust_op_size)(struct spi_mem *mem, struct spi_mem_op *op);
@@ -189,6 +256,12 @@ struct spi_controller_mem_ops {
        int (*exec_op)(struct spi_mem *mem,
                       const struct spi_mem_op *op);
        const char *(*get_name)(struct spi_mem *mem);
+       int (*dirmap_create)(struct spi_mem_dirmap_desc *desc);
+       void (*dirmap_destroy)(struct spi_mem_dirmap_desc *desc);
+       ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *desc,
+                              u64 offs, size_t len, void *buf);
+       ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc,
+                               u64 offs, size_t len, const void *buf);
 };
 
 /**
@@ -249,6 +322,15 @@ int spi_mem_exec_op(struct spi_mem *mem,
 
 const char *spi_mem_get_name(struct spi_mem *mem);
 
+struct spi_mem_dirmap_desc *
+spi_mem_dirmap_create(struct spi_mem *mem,
+                     const struct spi_mem_dirmap_info *info);
+void spi_mem_dirmap_destroy(struct spi_mem_dirmap_desc *desc);
+ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+                           u64 offs, size_t len, void *buf);
+ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+                            u64 offs, size_t len, const void *buf);
+
 int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
                                       struct module *owner);
 
index 6be77fa5ab90cd38c5a86fe1f1c3e3546e3a016b..314d922ca607c15c752b20caed7f25e6e8b1b5be 100644 (file)
@@ -154,7 +154,10 @@ struct spi_device {
 #define        SPI_TX_QUAD     0x200                   /* transmit with 4 wires */
 #define        SPI_RX_DUAL     0x400                   /* receive with 2 wires */
 #define        SPI_RX_QUAD     0x800                   /* receive with 4 wires */
-#define SPI_CS_WORD    0x1000                  /* toggle cs after each word */
+#define        SPI_CS_WORD     0x1000                  /* toggle cs after each word */
+#define        SPI_TX_OCTAL    0x2000                  /* transmit with 8 wires */
+#define        SPI_RX_OCTAL    0x4000                  /* receive with 8 wires */
+#define        SPI_3WIRE_HIZ   0x8000                  /* high impedance turnaround */
        int                     irq;
        void                    *controller_state;
        void                    *controller_data;
index d8a07a4f171dbfe21ee0e288d98658f304308735..a8f6d5d89524d3163a0c8f1dc835259f8d1dea51 100644 (file)
@@ -18,6 +18,8 @@ struct notifier_block;
 
 struct bio;
 
+struct pagevec;
+
 #define SWAP_FLAG_PREFER       0x8000  /* set if swap priority specified */
 #define SWAP_FLAG_PRIO_MASK    0x7fff
 #define SWAP_FLAG_PRIO_SHIFT   0
@@ -369,7 +371,7 @@ static inline int node_reclaim(struct pglist_data *pgdat, gfp_t mask,
 #endif
 
 extern int page_evictable(struct page *page);
-extern void check_move_unevictable_pages(struct page **, int nr_pages);
+extern void check_move_unevictable_pages(struct pagevec *pvec);
 
 extern int kswapd_run(int nid);
 extern void kswapd_stop(int nid);
index 987cefa337de672c44cecedc281eed3b32aff11d..786816cf4aa54e1ffcdeaae970cf8dc97b6edb6e 100644 (file)
@@ -234,7 +234,7 @@ int __must_check sysfs_create_file_ns(struct kobject *kobj,
                                      const struct attribute *attr,
                                      const void *ns);
 int __must_check sysfs_create_files(struct kobject *kobj,
-                                  const struct attribute **attr);
+                                  const struct attribute * const *attr);
 int __must_check sysfs_chmod_file(struct kobject *kobj,
                                  const struct attribute *attr, umode_t mode);
 struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
@@ -243,7 +243,7 @@ void sysfs_unbreak_active_protection(struct kernfs_node *kn);
 void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
                          const void *ns);
 bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr);
-void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
+void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *attr);
 
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
                                       const struct bin_attribute *attr);
@@ -342,7 +342,7 @@ static inline int sysfs_create_file_ns(struct kobject *kobj,
 }
 
 static inline int sysfs_create_files(struct kobject *kobj,
-                                   const struct attribute **attr)
+                                   const struct attribute * const *attr)
 {
        return 0;
 }
@@ -377,7 +377,7 @@ static inline bool sysfs_remove_file_self(struct kobject *kobj,
 }
 
 static inline void sysfs_remove_files(struct kobject *kobj,
-                                    const struct attribute **attr)
+                                    const struct attribute * const *attr)
 {
 }
 
index b9626aa7e90c67e1ecfa38d07d9a4754213313d0..3e2a80cc7b56dd3da0a13918de609cd11a1801c9 100644 (file)
@@ -39,12 +39,13 @@ struct t10_pi_tuple {
 
 static inline u32 t10_pi_ref_tag(struct request *rq)
 {
+       unsigned int shift = ilog2(queue_logical_block_size(rq->q));
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
-       return blk_rq_pos(rq) >>
-               (rq->q->integrity.interval_exp - 9) & 0xffffffff;
-#else
-       return -1U;
+       if (rq->q->integrity.interval_exp)
+               shift = rq->q->integrity.interval_exp;
 #endif
+       return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff;
 }
 
 extern const struct blk_integrity_profile t10_pi_type1_crc;
diff --git a/include/linux/thinkpad_acpi.h b/include/linux/thinkpad_acpi.h
deleted file mode 100644 (file)
index 9fb3179..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __THINKPAD_ACPI_H__
-#define __THINKPAD_ACPI_H__
-
-/* These two functions return 0 if success, or negative error code
-   (e g -ENODEV if no led present) */
-
-enum {
-       TPACPI_LED_MUTE,
-       TPACPI_LED_MICMUTE,
-       TPACPI_LED_MAX,
-};
-
-int tpacpi_led_set(int whichled, bool on);
-
-#endif
index 3fe5e5d2bb7e50b67b98dbbceae5ab2521591b90..707411ef8ba28124814da48bc3042045de028f76 100644 (file)
@@ -155,6 +155,7 @@ struct cec_adapter {
        unsigned int transmit_queue_sz;
        struct list_head wait_queue;
        struct cec_data *transmitting;
+       bool transmit_in_progress;
 
        struct task_struct *kthread_config;
        struct completion config_completion;
index 79a566d7defd00353651c8a06fc0d3a3d62a8615..5c31a768249201d48459e6f603d9a00df5e8cf14 100644 (file)
@@ -100,10 +100,6 @@ struct vpbe_config {
 struct vpbe_device;
 
 struct vpbe_device_ops {
-       /* crop cap for the display */
-       int (*g_cropcap)(struct vpbe_device *vpbe_dev,
-                        struct v4l2_cropcap *cropcap);
-
        /* Enumerate the outputs */
        int (*enum_outputs)(struct vpbe_device *vpbe_dev,
                            struct v4l2_output *output);
index bfa3017cecbaa4da39b4b4b13e615baf32a33f03..d621acadfbf361c2ae86cc6872e18fe8d1fbb5a7 100644 (file)
@@ -277,6 +277,7 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_WINFAST                   "rc-winfast"
 #define RC_MAP_WINFAST_USBII_DELUXE      "rc-winfast-usbii-deluxe"
 #define RC_MAP_SU3000                    "rc-su3000"
+#define RC_MAP_XBOX_DVD                  "rc-xbox-dvd"
 #define RC_MAP_ZX_IRDEC                  "rc-zx-irdec"
 
 /*
index 82715645617b8e563dc7a22cb0a9349f5909c011..0c511ed8ffb09fae4e965df6d9130ce0760407c7 100644 (file)
@@ -396,4 +396,9 @@ int v4l2_g_parm_cap(struct video_device *vdev,
 int v4l2_s_parm_cap(struct video_device *vdev,
                    struct v4l2_subdev *sd, struct v4l2_streamparm *a);
 
+/* Compare two v4l2_fract structs */
+#define V4L2_FRACT_COMPARE(a, OP, b)                   \
+       ((u64)(a).numerator * (b).denominator OP        \
+       (u64)(b).numerator * (a).denominator)
+
 #endif /* V4L2_COMMON_H_ */
index 456ac13eca1d62cf0f221b247345278c8386dd76..48531e57cc5a86d2c95bda85108d1b44c93f6c29 100644 (file)
@@ -74,10 +74,19 @@ struct v4l2_ctrl_handler;
  *     indicates that file->private_data points to &struct v4l2_fh.
  *     This flag is set by the core when v4l2_fh_init() is called.
  *     All new drivers should use it.
+ * @V4L2_FL_QUIRK_INVERTED_CROP:
+ *     some old M2M drivers use g/s_crop/cropcap incorrectly: crop and
+ *     compose are swapped. If this flag is set, then the selection
+ *     targets are swapped in the g/s_crop/cropcap functions in v4l2-ioctl.c.
+ *     This allows those drivers to correctly implement the selection API,
+ *     but the old crop API will still work as expected in order to preserve
+ *     backwards compatibility.
+ *     Never set this flag for new drivers.
  */
 enum v4l2_video_device_flags {
-       V4L2_FL_REGISTERED      = 0,
-       V4L2_FL_USES_V4L2_FH    = 1,
+       V4L2_FL_REGISTERED              = 0,
+       V4L2_FL_USES_V4L2_FH            = 1,
+       V4L2_FL_QUIRK_INVERTED_CROP     = 2,
 };
 
 /* Priority helper functions */
index 5848d92c30da3ddd4ee24f806eaa10315603b2e5..8533ece5026e459181a9c485d6aa986a3ddcba4a 100644 (file)
@@ -48,6 +48,9 @@ struct v4l2_fh;
  * @vidioc_enum_fmt_meta_cap: pointer to the function that implements
  *     :ref:`VIDIOC_ENUM_FMT <vidioc_enum_fmt>` ioctl logic
  *     for metadata capture
+ * @vidioc_enum_fmt_meta_out: pointer to the function that implements
+ *     :ref:`VIDIOC_ENUM_FMT <vidioc_enum_fmt>` ioctl logic
+ *     for metadata output
  * @vidioc_g_fmt_vid_cap: pointer to the function that implements
  *     :ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for video capture
  *     in single plane mode
@@ -80,6 +83,8 @@ struct v4l2_fh;
  *     Radio output
  * @vidioc_g_fmt_meta_cap: pointer to the function that implements
  *     :ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
+ * @vidioc_g_fmt_meta_out: pointer to the function that implements
+ *     :ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for metadata output
  * @vidioc_s_fmt_vid_cap: pointer to the function that implements
  *     :ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for video capture
  *     in single plane mode
@@ -112,6 +117,8 @@ struct v4l2_fh;
  *     Radio output
  * @vidioc_s_fmt_meta_cap: pointer to the function that implements
  *     :ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
+ * @vidioc_s_fmt_meta_out: pointer to the function that implements
+ *     :ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for metadata output
  * @vidioc_try_fmt_vid_cap: pointer to the function that implements
  *     :ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for video capture
  *     in single plane mode
@@ -146,6 +153,8 @@ struct v4l2_fh;
  *     Radio output
  * @vidioc_try_fmt_meta_cap: pointer to the function that implements
  *     :ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
+ * @vidioc_try_fmt_meta_out: pointer to the function that implements
+ *     :ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for metadata output
  * @vidioc_reqbufs: pointer to the function that implements
  *     :ref:`VIDIOC_REQBUFS <vidioc_reqbufs>` ioctl
  * @vidioc_querybuf: pointer to the function that implements
@@ -220,12 +229,8 @@ struct v4l2_fh;
  *     :ref:`VIDIOC_G_MODULATOR <vidioc_g_modulator>` ioctl
  * @vidioc_s_modulator: pointer to the function that implements
  *     :ref:`VIDIOC_S_MODULATOR <vidioc_g_modulator>` ioctl
- * @vidioc_cropcap: pointer to the function that implements
- *     :ref:`VIDIOC_CROPCAP <vidioc_cropcap>` ioctl
- * @vidioc_g_crop: pointer to the function that implements
- *     :ref:`VIDIOC_G_CROP <vidioc_g_crop>` ioctl
- * @vidioc_s_crop: pointer to the function that implements
- *     :ref:`VIDIOC_S_CROP <vidioc_g_crop>` ioctl
+ * @vidioc_g_pixelaspect: pointer to the function that implements
+ *     the pixelaspect part of the :ref:`VIDIOC_CROPCAP <vidioc_cropcap>` ioctl
  * @vidioc_g_selection: pointer to the function that implements
  *     :ref:`VIDIOC_G_SELECTION <vidioc_g_selection>` ioctl
  * @vidioc_s_selection: pointer to the function that implements
@@ -318,6 +323,8 @@ struct v4l2_ioctl_ops {
                                       struct v4l2_fmtdesc *f);
        int (*vidioc_enum_fmt_meta_cap)(struct file *file, void *fh,
                                        struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_meta_out)(struct file *file, void *fh,
+                                       struct v4l2_fmtdesc *f);
 
        /* VIDIOC_G_FMT handlers */
        int (*vidioc_g_fmt_vid_cap)(struct file *file, void *fh,
@@ -346,6 +353,8 @@ struct v4l2_ioctl_ops {
                                    struct v4l2_format *f);
        int (*vidioc_g_fmt_meta_cap)(struct file *file, void *fh,
                                     struct v4l2_format *f);
+       int (*vidioc_g_fmt_meta_out)(struct file *file, void *fh,
+                                    struct v4l2_format *f);
 
        /* VIDIOC_S_FMT handlers */
        int (*vidioc_s_fmt_vid_cap)(struct file *file, void *fh,
@@ -374,6 +383,8 @@ struct v4l2_ioctl_ops {
                                    struct v4l2_format *f);
        int (*vidioc_s_fmt_meta_cap)(struct file *file, void *fh,
                                     struct v4l2_format *f);
+       int (*vidioc_s_fmt_meta_out)(struct file *file, void *fh,
+                                    struct v4l2_format *f);
 
        /* VIDIOC_TRY_FMT handlers */
        int (*vidioc_try_fmt_vid_cap)(struct file *file, void *fh,
@@ -402,6 +413,8 @@ struct v4l2_ioctl_ops {
                                      struct v4l2_format *f);
        int (*vidioc_try_fmt_meta_cap)(struct file *file, void *fh,
                                       struct v4l2_format *f);
+       int (*vidioc_try_fmt_meta_out)(struct file *file, void *fh,
+                                      struct v4l2_format *f);
 
        /* Buffer handlers */
        int (*vidioc_reqbufs)(struct file *file, void *fh,
@@ -491,12 +504,8 @@ struct v4l2_ioctl_ops {
        int (*vidioc_s_modulator)(struct file *file, void *fh,
                                  const struct v4l2_modulator *a);
        /* Crop ioctls */
-       int (*vidioc_cropcap)(struct file *file, void *fh,
-                             struct v4l2_cropcap *a);
-       int (*vidioc_g_crop)(struct file *file, void *fh,
-                            struct v4l2_crop *a);
-       int (*vidioc_s_crop)(struct file *file, void *fh,
-                            const struct v4l2_crop *a);
+       int (*vidioc_g_pixelaspect)(struct file *file, void *fh,
+                                   int buf_type, struct v4l2_fract *aspect);
        int (*vidioc_g_selection)(struct file *file, void *fh,
                                  struct v4l2_selection *s);
        int (*vidioc_s_selection)(struct file *file, void *fh,
index 9102d6ca566e01f271935131bc95409126ca1aa9..47af609dc8f10764a9ced6bc608b587e473a5a9b 100644 (file)
@@ -776,7 +776,11 @@ struct v4l2_subdev_internal_ops {
 #define V4L2_SUBDEV_FL_IS_SPI                  (1U << 1)
 /* Set this flag if this subdev needs a device node. */
 #define V4L2_SUBDEV_FL_HAS_DEVNODE             (1U << 2)
-/* Set this flag if this subdev generates events. */
+/*
+ * Set this flag if this subdev generates events.
+ * Note controls can send events, thus drivers exposing controls
+ * should set this flag.
+ */
 #define V4L2_SUBDEV_FL_HAS_EVENTS              (1U << 3)
 
 struct regulator_bulk_data;
index b0d022ff6ea1702037b84a038f3c81ce56540aa4..5ce926701bd02f102b5b1dca28e17d50616a5fd1 100644 (file)
@@ -144,25 +144,6 @@ struct ip_tunnel {
        bool                    ignore_df;
 };
 
-#define TUNNEL_CSUM            __cpu_to_be16(0x01)
-#define TUNNEL_ROUTING         __cpu_to_be16(0x02)
-#define TUNNEL_KEY             __cpu_to_be16(0x04)
-#define TUNNEL_SEQ             __cpu_to_be16(0x08)
-#define TUNNEL_STRICT          __cpu_to_be16(0x10)
-#define TUNNEL_REC             __cpu_to_be16(0x20)
-#define TUNNEL_VERSION         __cpu_to_be16(0x40)
-#define TUNNEL_NO_KEY          __cpu_to_be16(0x80)
-#define TUNNEL_DONT_FRAGMENT    __cpu_to_be16(0x0100)
-#define TUNNEL_OAM             __cpu_to_be16(0x0200)
-#define TUNNEL_CRIT_OPT                __cpu_to_be16(0x0400)
-#define TUNNEL_GENEVE_OPT      __cpu_to_be16(0x0800)
-#define TUNNEL_VXLAN_OPT       __cpu_to_be16(0x1000)
-#define TUNNEL_NOCACHE         __cpu_to_be16(0x2000)
-#define TUNNEL_ERSPAN_OPT      __cpu_to_be16(0x4000)
-
-#define TUNNEL_OPTIONS_PRESENT \
-               (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
-
 struct tnl_ptk_info {
        __be16 flags;
        __be16 proto;
index f665d74ae509b41d3ffe10faad4065b61f369341..0e3a09380655e00584d6199f357f2427d2f7e704 100644 (file)
@@ -2340,22 +2340,39 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags);
 
 /**
- * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
+ * _sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
  * @sk:                socket sending this packet
  * @tsflags:   timestamping flags to use
  * @tx_flags:  completed with instructions for time stamping
+ * @tskey:      filled in with next sk_tskey (not for TCP, which uses seqno)
  *
  * Note: callers should take care of initial ``*tx_flags`` value (usually 0)
  */
-static inline void sock_tx_timestamp(const struct sock *sk, __u16 tsflags,
-                                    __u8 *tx_flags)
+static inline void _sock_tx_timestamp(struct sock *sk, __u16 tsflags,
+                                     __u8 *tx_flags, __u32 *tskey)
 {
-       if (unlikely(tsflags))
+       if (unlikely(tsflags)) {
                __sock_tx_timestamp(tsflags, tx_flags);
+               if (tsflags & SOF_TIMESTAMPING_OPT_ID && tskey &&
+                   tsflags & SOF_TIMESTAMPING_TX_RECORD_MASK)
+                       *tskey = sk->sk_tskey++;
+       }
        if (unlikely(sock_flag(sk, SOCK_WIFI_STATUS)))
                *tx_flags |= SKBTX_WIFI_STATUS;
 }
 
+static inline void sock_tx_timestamp(struct sock *sk, __u16 tsflags,
+                                    __u8 *tx_flags)
+{
+       _sock_tx_timestamp(sk, tsflags, tx_flags, NULL);
+}
+
+static inline void skb_setup_tx_timestamp(struct sk_buff *skb, __u16 tsflags)
+{
+       _sock_tx_timestamp(skb->sk, tsflags, &skb_shinfo(skb)->tx_flags,
+                          &skb_shinfo(skb)->tskey);
+}
+
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
  * @sk: socket to eat this skb from
index bab5627ff5e393502fc5ed4eb7bd33cae5d02d14..3cbcd12303fd68fc604d61d4334cde643e10395a 100644 (file)
  *
  * void (*unhash)(struct tls_device *device, struct sock *sk);
  *     This function cleans listen state set by Inline TLS driver
+ *
+ * void (*release)(struct kref *kref);
+ *     Release the registered device and allocated resources
+ * @kref: Number of reference to tls_device
  */
 struct tls_device {
        char name[TLS_DEVICE_NAME_MAX];
@@ -83,6 +87,8 @@ struct tls_device {
        int  (*feature)(struct tls_device *device);
        int  (*hash)(struct tls_device *device, struct sock *sk);
        void (*unhash)(struct tls_device *device, struct sock *sk);
+       void (*release)(struct kref *kref);
+       struct kref kref;
 };
 
 enum {
index 0eb390c205af023eca277c8ca5db85faaea8fa4a..da588def3c61d45767ebc7a68994fe3958469b50 100644 (file)
@@ -1552,6 +1552,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
                    int (*func)(struct xfrm_state *, int, void*), void *);
 void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net);
 struct xfrm_state *xfrm_state_alloc(struct net *net);
+void xfrm_state_free(struct xfrm_state *x);
 struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
                                   const xfrm_address_t *saddr,
                                   const struct flowi *fl,
index ea8c93bbb0e05490b023fdf402e8aa1d2f76ceeb..0cdc3999ecfa84ebb289eca932b33d1806c2fa13 100644 (file)
@@ -23,6 +23,7 @@ struct snd_compr_ops;
  * struct snd_compr_runtime: runtime stream description
  * @state: stream state
  * @ops: pointer to DSP callbacks
+ * @dma_buffer_p: runtime dma buffer pointer
  * @buffer: pointer to kernel buffer, valid only when not in mmap mode or
  *     DSP doesn't implement copy
  * @buffer_size: size of the above buffer
@@ -37,6 +38,7 @@ struct snd_compr_ops;
 struct snd_compr_runtime {
        snd_pcm_state_t state;
        struct snd_compr_ops *ops;
+       struct snd_dma_buffer *dma_buffer_p;
        void *buffer;
        u64 buffer_size;
        u32 fragment_size;
@@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
        wake_up(&stream->runtime->sleep);
 }
 
+/**
+ * snd_compr_set_runtime_buffer - Set the Compress runtime buffer
+ * @substream: compress substream to set
+ * @bufp: the buffer information, NULL to clear
+ *
+ * Copy the buffer information to runtime buffer when @bufp is non-NULL.
+ * Otherwise it clears the current buffer information.
+ */
+static inline void snd_compr_set_runtime_buffer(
+                                       struct snd_compr_stream *substream,
+                                       struct snd_dma_buffer *bufp)
+{
+       struct snd_compr_runtime *runtime = substream->runtime;
+
+       runtime->dma_buffer_p = bufp;
+}
+
 int snd_compr_stop_error(struct snd_compr_stream *stream,
                         snd_pcm_state_t state);
 
index 0d98bb9068b178cb2b7cb77f43c41220496c4757..7fa48b100936183464d17c9eb3c42711d28336be 100644 (file)
@@ -236,6 +236,7 @@ struct hda_codec {
        /* misc flags */
        unsigned int in_freeing:1; /* being released */
        unsigned int registered:1; /* codec was registered */
+       unsigned int display_power_control:1; /* needs display power */
        unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
                                             * status change
                                             * (e.g. Realtek codecs)
index 78626cde70811ab23353cca17eaff1cade3281f5..2ec31b35895045e1eb8eb33fc8d5622fb87aa2dd 100644 (file)
@@ -5,10 +5,15 @@
 #define __SOUND_HDA_COMPONENT_H
 
 #include <drm/drm_audio_component.h>
+#include <sound/hdaudio.h>
+
+/* virtual idx for controller */
+#define HDA_CODEC_IDX_CONTROLLER       HDA_MAX_CODECS
 
 #ifdef CONFIG_SND_HDA_COMPONENT
 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
-int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
+void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx,
+                           bool enable);
 int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
                             int dev_id, int rate);
 int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
@@ -25,9 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
 {
        return 0;
 }
-static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
+static inline void snd_hdac_display_power(struct hdac_bus *bus,
+                                         unsigned int idx, bool enable)
 {
-       return 0;
 }
 static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
                                           hda_nid_t nid, int dev_id, int rate)
index cd1773d0e08f07247a42788a035a0355da113493..b4fa1c7752510b5216a92f6d663d4fc0d1da3b39 100644 (file)
@@ -79,7 +79,6 @@ struct hdac_device {
 
        /* misc flags */
        atomic_t in_pm;         /* suspend/resume being performed */
-       bool  link_power_control:1;
 
        /* sysfs */
        struct hdac_widget_tree *widgets;
@@ -99,6 +98,12 @@ enum {
        HDA_DEV_ASOC,
 };
 
+enum {
+       SND_SKL_PCI_BIND_AUTO,  /* automatic selection based on pci class */
+       SND_SKL_PCI_BIND_LEGACY,/* bind only with legacy driver */
+       SND_SKL_PCI_BIND_ASOC   /* bind only with ASoC driver */
+};
+
 /* direction */
 enum {
        HDA_INPUT, HDA_OUTPUT
@@ -237,8 +242,6 @@ struct hdac_bus_ops {
        /* get a response from the last command */
        int (*get_response)(struct hdac_bus *bus, unsigned int addr,
                            unsigned int *res);
-       /* control the link power  */
-       int (*link_power)(struct hdac_bus *bus, bool enable);
 };
 
 /*
@@ -363,7 +366,8 @@ struct hdac_bus {
 
        /* DRM component interface */
        struct drm_audio_component *audio_component;
-       int drm_power_refcount;
+       long display_power_status;
+       bool display_power_active;
 
        /* parameters required for enhanced capabilities */
        int num_streams;
@@ -389,6 +393,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
 int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
 void snd_hdac_bus_remove_device(struct hdac_bus *bus,
                                struct hdac_device *codec);
+void snd_hdac_bus_process_unsol_events(struct work_struct *work);
 
 static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
 {
@@ -404,7 +409,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
 int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
                              unsigned int *res);
 int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus);
-int snd_hdac_link_power(struct hdac_device *codec, bool enable);
 
 bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
 void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
index fb0318f9b10f3847c8ae7949f259d80c71fdbe94..6d69ed2bd7b1115a2f83fdb511466a6ebe8068b8 100644 (file)
@@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card);
 
 void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
                                      struct snd_pcm_hw_params *params);
-void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+void asoc_simple_card_parse_convert(struct device *dev,
+                                   struct device_node *np, char *prefix,
                                    struct asoc_simple_card_data *data);
 
 int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
-                                     char *prefix,
-                                     int optional);
+                                     char *prefix);
 int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
                                      char *prefix);
 
index f48f59e5b7b02bc394f184e9e39ab0f66503c8a8..bb5e1e4ce8bf915eb8d449a97ecd4075a0f5fa25 100644 (file)
@@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
 
 /*
  * generic table used for HDA codec-based platforms, possibly with
index e45b2330d16a458b638f08dcdcdd87a4f87f76b0..266e64e3c24c4fad654af09c6c70383d844166e7 100644 (file)
@@ -37,6 +37,20 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
 struct snd_soc_acpi_mach *
 snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
 
+/**
+ * snd_soc_acpi_mach_params: interface for machine driver configuration
+ *
+ * @acpi_ipc_irq_index: used for BYT-CR detection
+ * @platform: string used for HDaudio codec support
+ * @codec_mask: used for HDAudio support
+ */
+struct snd_soc_acpi_mach_params {
+       u32 acpi_ipc_irq_index;
+       const char *platform;
+       u32 codec_mask;
+       u32 dmic_num;
+};
+
 /**
  * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
  * related to the hardware, except for the firmware and topology file names.
@@ -68,6 +82,7 @@ struct snd_soc_acpi_mach {
        struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
        const void *quirk_data;
        void *pdata;
+       struct snd_soc_acpi_mach_params mach_params;
        const char *sof_fw_filename;
        const char *sof_tplg_filename;
        const char *asoc_plat_name;
index 70c10a8f3e90a7a828d9df930e16fed5915f1686..8ec1de856ee7e17f0d080623544a17e09d8746bd 100644 (file)
@@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 }
 #endif
 
-#ifdef CONFIG_SND_SOC_AC97_BUS
 struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
 struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
        unsigned int id, unsigned int id_mask);
 void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
 
+#ifdef CONFIG_SND_SOC_AC97_BUS
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
                struct platform_device *pdev);
@@ -1477,10 +1477,20 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
                              unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width);
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+void snd_soc_of_parse_node_prefix(struct device_node *np,
                                   struct snd_soc_codec_conf *codec_conf,
                                   struct device_node *of_node,
                                   const char *propname);
+static inline
+void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+                                  struct snd_soc_codec_conf *codec_conf,
+                                  struct device_node *of_node,
+                                  const char *propname)
+{
+       snd_soc_of_parse_node_prefix(card->dev->of_node,
+                                    codec_conf, of_node, propname);
+}
+
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname);
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
index 21381449d98a88f0b5f68942b307128a4269926a..355c4ac2c0b0d04ae334f99ae2d9dea86a9cad9c 100644 (file)
@@ -3,6 +3,7 @@
 #
 mandatory-y += auxvec.h
 mandatory-y += bitsperlong.h
+mandatory-y += bpf_perf_event.h
 mandatory-y += byteorder.h
 mandatory-y += errno.h
 mandatory-y += fcntl.h
index 370e9a5536ef5255bf91f497c08e86298f57655c..be84e43c1e19e916e8d7de8dc14b498a4dbc6a28 100644 (file)
@@ -326,6 +326,12 @@ struct drm_amdgpu_gem_userptr {
 /* GFX9 and later: */
 #define AMDGPU_TILING_SWIZZLE_MODE_SHIFT               0
 #define AMDGPU_TILING_SWIZZLE_MODE_MASK                        0x1f
+#define AMDGPU_TILING_DCC_OFFSET_256B_SHIFT            5
+#define AMDGPU_TILING_DCC_OFFSET_256B_MASK             0xFFFFFF
+#define AMDGPU_TILING_DCC_PITCH_MAX_SHIFT              29
+#define AMDGPU_TILING_DCC_PITCH_MAX_MASK               0x3FFF
+#define AMDGPU_TILING_DCC_INDEPENDENT_64B_SHIFT                43
+#define AMDGPU_TILING_DCC_INDEPENDENT_64B_MASK         0x1
 
 /* Set/Get helpers for tiling flags. */
 #define AMDGPU_TILING_SET(field, value) \
index 0cd40ebfa1b1669e2c29aa757b294cc479e51991..0b44260a5ee969a4abbb1c94358bd8ae08e28193 100644 (file)
@@ -151,6 +151,21 @@ extern "C" {
 #define DRM_FORMAT_VYUY                fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */
 
 #define DRM_FORMAT_AYUV                fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
+#define DRM_FORMAT_XYUV8888            fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+
+/*
+ * packed YCbCr420 2x2 tiled formats
+ * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile
+ */
+/* [63:0]   A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0  1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */
+#define DRM_FORMAT_Y0L0                fourcc_code('Y', '0', 'L', '0')
+/* [63:0]   X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0  1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */
+#define DRM_FORMAT_X0L0                fourcc_code('X', '0', 'L', '0')
+
+/* [63:0]   A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0  1:1:10:10:10:1:1:10:10:10 little endian */
+#define DRM_FORMAT_Y0L2                fourcc_code('Y', '0', 'L', '2')
+/* [63:0]   X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0  1:1:10:10:10:1:1:10:10:10 little endian */
+#define DRM_FORMAT_X0L2                fourcc_code('X', '0', 'L', '2')
 
 /*
  * 2 plane RGB + A
index d3e0fe31efc55351573be5432ca92d3c372b1c08..a439c2e67896b030222da5a32fbafbccfa5d4d66 100644 (file)
@@ -888,6 +888,25 @@ struct drm_mode_revoke_lease {
        __u32 lessee_id;
 };
 
+/**
+ * struct drm_mode_rect - Two dimensional rectangle.
+ * @x1: Horizontal starting coordinate (inclusive).
+ * @y1: Vertical starting coordinate (inclusive).
+ * @x2: Horizontal ending coordinate (exclusive).
+ * @y2: Vertical ending coordinate (exclusive).
+ *
+ * With drm subsystem using struct drm_rect to manage rectangular area this
+ * export it to user-space.
+ *
+ * Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS.
+ */
+struct drm_mode_rect {
+       __s32 x1;
+       __s32 y1;
+       __s32 x2;
+       __s32 y2;
+};
+
 #if defined(__cplusplus)
 }
 #endif
index a4446f452040aa2bdb15dfd8c28c320b073f9bf0..298b2e197744bbc28782d1a853e1ee3577f02bee 100644 (file)
@@ -412,6 +412,14 @@ typedef struct drm_i915_irq_wait {
        int irq_seq;
 } drm_i915_irq_wait_t;
 
+/*
+ * Different modes of per-process Graphics Translation Table,
+ * see I915_PARAM_HAS_ALIASING_PPGTT
+ */
+#define I915_GEM_PPGTT_NONE    0
+#define I915_GEM_PPGTT_ALIASING        1
+#define I915_GEM_PPGTT_FULL    2
+
 /* Ioctl to query kernel params:
  */
 #define I915_PARAM_IRQ_ACTIVE            1
index c06d0a5bdd808235850c2d3ac54c2eb07ef561b1..91a16b333c69005417b9314d192b0db0eac43b19 100644 (file)
@@ -105,14 +105,24 @@ struct drm_msm_gem_new {
        __u32 handle;         /* out */
 };
 
-#define MSM_INFO_IOVA  0x01
-
-#define MSM_INFO_FLAGS (MSM_INFO_IOVA)
+/* Get or set GEM buffer info.  The requested value can be passed
+ * directly in 'value', or for data larger than 64b 'value' is a
+ * pointer to userspace buffer, with 'len' specifying the number of
+ * bytes copied into that buffer.  For info returned by pointer,
+ * calling the GEM_INFO ioctl with null 'value' will return the
+ * required buffer size in 'len'
+ */
+#define MSM_INFO_GET_OFFSET    0x00   /* get mmap() offset, returned by value */
+#define MSM_INFO_GET_IOVA      0x01   /* get iova, returned by value */
+#define MSM_INFO_SET_NAME      0x02   /* set the debug name (by pointer) */
+#define MSM_INFO_GET_NAME      0x03   /* get debug name, returned by pointer */
 
 struct drm_msm_gem_info {
        __u32 handle;         /* in */
-       __u32 flags;          /* in - combination of MSM_INFO_* flags */
-       __u64 offset;         /* out, mmap() offset or iova */
+       __u32 info;           /* in - one of MSM_INFO_* */
+       __u64 value;          /* in or out */
+       __u32 len;            /* in or out */
+       __u32 pad;
 };
 
 #define MSM_PREP_READ        0x01
@@ -188,8 +198,11 @@ struct drm_msm_gem_submit_cmd {
  */
 #define MSM_SUBMIT_BO_READ             0x0001
 #define MSM_SUBMIT_BO_WRITE            0x0002
+#define MSM_SUBMIT_BO_DUMP             0x0004
 
-#define MSM_SUBMIT_BO_FLAGS            (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
+#define MSM_SUBMIT_BO_FLAGS            (MSM_SUBMIT_BO_READ | \
+                                       MSM_SUBMIT_BO_WRITE | \
+                                       MSM_SUBMIT_BO_DUMP)
 
 struct drm_msm_gem_submit_bo {
        __u32 flags;          /* in, mask of MSM_SUBMIT_BO_x */
index 7b6627783608edb92cc6fbfe7c9932a5766e6e8b..35c7d813c66e297d3814710d7bfddbf05b2c346c 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 #define DRM_V3D_MMAP_BO                           0x03
 #define DRM_V3D_GET_PARAM                         0x04
 #define DRM_V3D_GET_BO_OFFSET                     0x05
+#define DRM_V3D_SUBMIT_TFU                        0x06
 
 #define DRM_IOCTL_V3D_SUBMIT_CL           DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
 #define DRM_IOCTL_V3D_WAIT_BO             DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
@@ -43,6 +44,7 @@ extern "C" {
 #define DRM_IOCTL_V3D_MMAP_BO             DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo)
 #define DRM_IOCTL_V3D_GET_PARAM           DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
 #define DRM_IOCTL_V3D_GET_BO_OFFSET       DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
+#define DRM_IOCTL_V3D_SUBMIT_TFU          DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
 
 /**
  * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
@@ -58,10 +60,15 @@ struct drm_v3d_submit_cl {
         * coordinate shader to determine where primitives land on the screen,
         * then writes out the state updates and draw calls necessary per tile
         * to the tile allocation BO.
+        *
+        * This BCL will block on any previous BCL submitted on the
+        * same FD, but not on any RCL or BCLs submitted by other
+        * clients -- that is left up to the submitter to control
+        * using in_sync_bcl if necessary.
         */
        __u32 bcl_start;
 
-        /** End address of the BCL (first byte after the BCL) */
+       /** End address of the BCL (first byte after the BCL) */
        __u32 bcl_end;
 
        /* Offset of the render command list.
@@ -69,10 +76,15 @@ struct drm_v3d_submit_cl {
         * This is the second set of commands executed, which will either
         * execute the tiles that have been set up by the BCL, or a fixed set
         * of tiles (in the case of RCL-only blits).
+        *
+        * This RCL will block on this submit's BCL, and any previous
+        * RCL submitted on the same FD, but not on any RCL or BCLs
+        * submitted by other clients -- that is left up to the
+        * submitter to control using in_sync_rcl if necessary.
         */
        __u32 rcl_start;
 
-        /** End address of the RCL (first byte after the RCL) */
+       /** End address of the RCL (first byte after the RCL) */
        __u32 rcl_end;
 
        /** An optional sync object to wait on before starting the BCL. */
@@ -169,6 +181,7 @@ enum drm_v3d_param {
        DRM_V3D_PARAM_V3D_CORE0_IDENT0,
        DRM_V3D_PARAM_V3D_CORE0_IDENT1,
        DRM_V3D_PARAM_V3D_CORE0_IDENT2,
+       DRM_V3D_PARAM_SUPPORTS_TFU,
 };
 
 struct drm_v3d_get_param {
@@ -187,6 +200,28 @@ struct drm_v3d_get_bo_offset {
        __u32 offset;
 };
 
+struct drm_v3d_submit_tfu {
+       __u32 icfg;
+       __u32 iia;
+       __u32 iis;
+       __u32 ica;
+       __u32 iua;
+       __u32 ioa;
+       __u32 ios;
+       __u32 coef[4];
+       /* First handle is the output BO, following are other inputs.
+        * 0 for unused.
+        */
+       __u32 bo_handles[4];
+       /* sync object to block on before running the TFU job.  Each TFU
+        * job will execute in the order submitted to its FD.  Synchronization
+        * against rendering jobs requires using sync objects.
+        */
+       __u32 in_sync;
+       /* Sync object to signal when the TFU job is done. */
+       __u32 out_sync;
+};
+
 #if defined(__cplusplus)
 }
 #endif
index 9a781f0611df0280be7d952258f486f805f27528..f06a789f34cd9993f3952da30723adf995790605 100644 (file)
@@ -47,6 +47,13 @@ extern "C" {
 #define DRM_VIRTGPU_WAIT     0x08
 #define DRM_VIRTGPU_GET_CAPS  0x09
 
+#define VIRTGPU_EXECBUF_FENCE_FD_IN    0x01
+#define VIRTGPU_EXECBUF_FENCE_FD_OUT   0x02
+#define VIRTGPU_EXECBUF_FLAGS  (\
+               VIRTGPU_EXECBUF_FENCE_FD_IN |\
+               VIRTGPU_EXECBUF_FENCE_FD_OUT |\
+               0)
+
 struct drm_virtgpu_map {
        __u64 offset; /* use for mmap system call */
        __u32 handle;
@@ -54,12 +61,12 @@ struct drm_virtgpu_map {
 };
 
 struct drm_virtgpu_execbuffer {
-       __u32           flags;          /* for future use */
+       __u32 flags;
        __u32 size;
        __u64 command; /* void* */
        __u64 bo_handles;
        __u32 num_bo_handles;
-       __u32 pad;
+       __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */
 };
 
 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
@@ -137,7 +144,7 @@ struct drm_virtgpu_get_caps {
        DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map)
 
 #define DRM_IOCTL_VIRTGPU_EXECBUFFER \
-       DRM_IOW(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
                struct drm_virtgpu_execbuffer)
 
 #define DRM_IOCTL_VIRTGPU_GETPARAM \
index 8f08ff9bdea091a001094119f753046c79f7dd9f..6fa38d001d84ff5af90fe6014e7874d18f8e2bc1 100644 (file)
@@ -141,7 +141,7 @@ struct blk_zone_range {
  */
 #define BLKREPORTZONE  _IOWR(0x12, 130, struct blk_zone_report)
 #define BLKRESETZONE   _IOW(0x12, 131, struct blk_zone_range)
-#define BLKGETZONESZ   _IOW(0x12, 132, __u32)
-#define BLKGETNRZONES  _IOW(0x12, 133, __u32)
+#define BLKGETZONESZ   _IOR(0x12, 132, __u32)
+#define BLKGETNRZONES  _IOR(0x12, 133, __u32)
 
 #endif /* _UAPI_BLKZONED_H */
index 1b3d148c4560813089b13215e1ab9b961c8c54e0..7d9105533c7b93b0e92d7679292a8c6447a8d08c 100644 (file)
@@ -160,4 +160,24 @@ enum {
 };
 
 #define IFLA_VTI_MAX   (__IFLA_VTI_MAX - 1)
+
+#define TUNNEL_CSUM            __cpu_to_be16(0x01)
+#define TUNNEL_ROUTING         __cpu_to_be16(0x02)
+#define TUNNEL_KEY             __cpu_to_be16(0x04)
+#define TUNNEL_SEQ             __cpu_to_be16(0x08)
+#define TUNNEL_STRICT          __cpu_to_be16(0x10)
+#define TUNNEL_REC             __cpu_to_be16(0x20)
+#define TUNNEL_VERSION         __cpu_to_be16(0x40)
+#define TUNNEL_NO_KEY          __cpu_to_be16(0x80)
+#define TUNNEL_DONT_FRAGMENT    __cpu_to_be16(0x0100)
+#define TUNNEL_OAM             __cpu_to_be16(0x0200)
+#define TUNNEL_CRIT_OPT                __cpu_to_be16(0x0400)
+#define TUNNEL_GENEVE_OPT      __cpu_to_be16(0x0800)
+#define TUNNEL_VXLAN_OPT       __cpu_to_be16(0x1000)
+#define TUNNEL_NOCACHE         __cpu_to_be16(0x2000)
+#define TUNNEL_ERSPAN_OPT      __cpu_to_be16(0x4000)
+
+#define TUNNEL_OPTIONS_PRESENT \
+               (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
+
 #endif /* _UAPI_IF_TUNNEL_H_ */
index 48e8a225b985ae646b4bba2cdcdf62ca9c42a7a6..f6052e70bf403950eb658cd350337162a100df5f 100644 (file)
@@ -266,10 +266,14 @@ struct sockaddr_in {
 
 #define        IN_CLASSD(a)            ((((long int) (a)) & 0xf0000000) == 0xe0000000)
 #define        IN_MULTICAST(a)         IN_CLASSD(a)
-#define IN_MULTICAST_NET       0xF0000000
+#define        IN_MULTICAST_NET        0xe0000000
 
-#define        IN_EXPERIMENTAL(a)      ((((long int) (a)) & 0xf0000000) == 0xf0000000)
-#define        IN_BADCLASS(a)          IN_EXPERIMENTAL((a))
+#define        IN_BADCLASS(a)          ((((long int) (a) ) == 0xffffffff)
+#define        IN_EXPERIMENTAL(a)      IN_BADCLASS((a))
+
+#define        IN_CLASSE(a)            ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#define        IN_CLASSE_NET           0xffffffff
+#define        IN_CLASSE_NSHIFT        0
 
 /* Address to accept any incoming messages. */
 #define        INADDR_ANY              ((unsigned long int) 0x00000000)
index b01eb502d49c55d04f33cace28a410171239eaf5..e622fd1fbd46399c967e448c762b69b8dd3220b2 100644 (file)
@@ -398,6 +398,24 @@ struct kfd_ioctl_unmap_memory_from_gpu_args {
        __u32 n_success;                /* to/from KFD */
 };
 
+struct kfd_ioctl_get_dmabuf_info_args {
+       __u64 size;             /* from KFD */
+       __u64 metadata_ptr;     /* to KFD */
+       __u32 metadata_size;    /* to KFD (space allocated by user)
+                                * from KFD (actual metadata size)
+                                */
+       __u32 gpu_id;   /* from KFD */
+       __u32 flags;            /* from KFD (KFD_IOC_ALLOC_MEM_FLAGS) */
+       __u32 dmabuf_fd;        /* to KFD */
+};
+
+struct kfd_ioctl_import_dmabuf_args {
+       __u64 va_addr;  /* to KFD */
+       __u64 handle;   /* from KFD */
+       __u32 gpu_id;   /* to KFD */
+       __u32 dmabuf_fd;        /* to KFD */
+};
+
 #define AMDKFD_IOCTL_BASE 'K'
 #define AMDKFD_IO(nr)                  _IO(AMDKFD_IOCTL_BASE, nr)
 #define AMDKFD_IOR(nr, type)           _IOR(AMDKFD_IOCTL_BASE, nr, type)
@@ -486,7 +504,13 @@ struct kfd_ioctl_unmap_memory_from_gpu_args {
 #define AMDKFD_IOC_GET_QUEUE_WAVE_STATE                \
                AMDKFD_IOWR(0x1B, struct kfd_ioctl_get_queue_wave_state_args)
 
+#define AMDKFD_IOC_GET_DMABUF_INFO             \
+               AMDKFD_IOWR(0x1C, struct kfd_ioctl_get_dmabuf_info_args)
+
+#define AMDKFD_IOC_IMPORT_DMABUF               \
+               AMDKFD_IOWR(0x1D, struct kfd_ioctl_import_dmabuf_args)
+
 #define AMDKFD_COMMAND_START           0x01
-#define AMDKFD_COMMAND_END             0x1C
+#define AMDKFD_COMMAND_END             0x1E
 
 #endif
index 97ff3c17ec4d2021a728c71141f1baa39f707eee..e5b39721c6e4877c1235b2708956474c80f4761f 100644 (file)
@@ -155,8 +155,8 @@ enum txtime_flags {
 };
 
 struct sock_txtime {
-       clockid_t       clockid;        /* reference clockid */
-       __u32           flags;          /* as defined by enum txtime_flags */
+       __kernel_clockid_t      clockid;/* reference clockid */
+       __u32                   flags;  /* as defined by enum txtime_flags */
 };
 
 #endif /* _NET_TIMESTAMPING_H */
index 486ed1f0c0bc17f48dca895ebf9581aa7d69278d..0a4d73317759c9ee523d7d5482548b3171c821e6 100644 (file)
@@ -155,7 +155,7 @@ enum nlmsgerr_attrs {
 #define NETLINK_LIST_MEMBERSHIPS       9
 #define NETLINK_CAP_ACK                        10
 #define NETLINK_EXT_ACK                        11
-#define NETLINK_DUMP_STRICT_CHK                12
+#define NETLINK_GET_STRICT_CHK         12
 
 struct nl_pktinfo {
        __u32   group;
index 4f7b892377cd6880f0df9ec17edee016888b9851..7d21c1634b4d12cce2492639c58dc58409a437c7 100644 (file)
 /* Current composing area plus all padding pixels */
 #define V4L2_SEL_TGT_COMPOSE_PADDED    0x0103
 
-/* Backward compatibility target definitions --- to be removed. */
-#define V4L2_SEL_TGT_CROP_ACTIVE       V4L2_SEL_TGT_CROP
-#define V4L2_SEL_TGT_COMPOSE_ACTIVE    V4L2_SEL_TGT_COMPOSE
-#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL        V4L2_SEL_TGT_CROP
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
-#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS        V4L2_SEL_TGT_CROP_BOUNDS
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
-
 /* Selection flags */
 #define V4L2_SEL_FLAG_GE               (1 << 0)
 #define V4L2_SEL_FLAG_LE               (1 << 1)
 #define V4L2_SEL_FLAG_KEEP_CONFIG      (1 << 2)
 
-/* Backward compatibility flag definitions --- to be removed. */
-#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE   V4L2_SEL_FLAG_GE
-#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE   V4L2_SEL_FLAG_LE
-#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
-
 struct v4l2_edid {
        __u32 pad;
        __u32 start_block;
@@ -105,4 +92,19 @@ struct v4l2_edid {
        __u8  *edid;
 };
 
+#ifndef __KERNEL__
+/* Backward compatibility target definitions --- to be removed. */
+#define V4L2_SEL_TGT_CROP_ACTIVE       V4L2_SEL_TGT_CROP
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE    V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL        V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS        V4L2_SEL_TGT_CROP_BOUNDS
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
+
+/* Backward compatibility flag definitions --- to be removed. */
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE   V4L2_SEL_FLAG_GE
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE   V4L2_SEL_FLAG_LE
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
+#endif
+
 #endif /* __V4L2_COMMON__ */
index 2ba2ad0e23fbb67d54f886ed6f292308b2815bb6..b5671ce2724fa1c50f2fff8ec25fcef36bb7cb7b 100644 (file)
@@ -145,6 +145,7 @@ enum v4l2_buf_type {
        V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
        V4L2_BUF_TYPE_SDR_OUTPUT           = 12,
        V4L2_BUF_TYPE_META_CAPTURE         = 13,
+       V4L2_BUF_TYPE_META_OUTPUT          = 14,
        /* Deprecated, do not use */
        V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
@@ -469,6 +470,7 @@ struct v4l2_capability {
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
 #define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
+#define V4L2_CAP_META_OUTPUT           0x08000000  /* Is a metadata output device */
 
 #define V4L2_CAP_TOUCH                  0x10000000  /* Is a touch device */
 
@@ -689,6 +691,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MT21C    v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */
 #define V4L2_PIX_FMT_INZI     v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
 #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */
+#define V4L2_PIX_FMT_CNF4     v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */
 
 /* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */
 #define V4L2_PIX_FMT_IPU3_SBGGR10      v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */
@@ -879,6 +882,7 @@ struct v4l2_requestbuffers {
 #define V4L2_BUF_CAP_SUPPORTS_USERPTR  (1 << 1)
 #define V4L2_BUF_CAP_SUPPORTS_DMABUF   (1 << 2)
 #define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
+#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
 
 /**
  * struct v4l2_plane - plane info for multi-planar buffers
index f43c3c6171ffeb3725ef4d55e4f22b99a8f86a51..8e88eba1fa7a1c457d519a62f1dd51747cfad504 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 
 #define VIRTIO_GPU_F_VIRGL 0
+#define VIRTIO_GPU_F_EDID  1
 
 enum virtio_gpu_ctrl_type {
        VIRTIO_GPU_UNDEFINED = 0,
@@ -56,6 +57,7 @@ enum virtio_gpu_ctrl_type {
        VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
        VIRTIO_GPU_CMD_GET_CAPSET_INFO,
        VIRTIO_GPU_CMD_GET_CAPSET,
+       VIRTIO_GPU_CMD_GET_EDID,
 
        /* 3d commands */
        VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
@@ -76,6 +78,7 @@ enum virtio_gpu_ctrl_type {
        VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
        VIRTIO_GPU_RESP_OK_CAPSET_INFO,
        VIRTIO_GPU_RESP_OK_CAPSET,
+       VIRTIO_GPU_RESP_OK_EDID,
 
        /* error responses */
        VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
@@ -291,6 +294,21 @@ struct virtio_gpu_resp_capset {
        __u8 capset_data[];
 };
 
+/* VIRTIO_GPU_CMD_GET_EDID */
+struct virtio_gpu_cmd_get_edid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 scanout;
+       __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_EDID */
+struct virtio_gpu_resp_edid {
+       struct virtio_gpu_ctrl_hdr hdr;
+       __le32 size;
+       __le32 padding;
+       __u8 edid[1024];
+};
+
 #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
 
 struct virtio_gpu_config {
index f0a547d86679792d8a21a3c9a95e320cee71f3d6..ae12826ed641be27a613ca78c0ca0276fb101766 100644 (file)
@@ -12,6 +12,7 @@
 #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE      0x4e617475
 #define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE   0x746e736c
 #define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
+#define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL    0x7473636d
 
 struct snd_firewire_event_common {
        unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -53,12 +54,24 @@ struct snd_firewire_event_motu_notification {
        __u32 message;  /* MOTU-specific bits. */
 };
 
+struct snd_firewire_tascam_change {
+       unsigned int index;
+       __be32 before;
+       __be32 after;
+};
+
+struct snd_firewire_event_tascam_control {
+       unsigned int type;
+       struct snd_firewire_tascam_change changes[0];
+};
+
 union snd_firewire_event {
        struct snd_firewire_event_common            common;
        struct snd_firewire_event_lock_status       lock_status;
        struct snd_firewire_event_dice_notification dice_notification;
        struct snd_firewire_event_efw_response      efw_response;
        struct snd_firewire_event_digi00x_message   digi00x_message;
+       struct snd_firewire_event_tascam_control    tascam_control;
        struct snd_firewire_event_motu_notification motu_notification;
 };
 
@@ -66,6 +79,7 @@ union snd_firewire_event {
 #define SNDRV_FIREWIRE_IOCTL_GET_INFO _IOR('H', 0xf8, struct snd_firewire_get_info)
 #define SNDRV_FIREWIRE_IOCTL_LOCK      _IO('H', 0xf9)
 #define SNDRV_FIREWIRE_IOCTL_UNLOCK    _IO('H', 0xfa)
+#define SNDRV_FIREWIRE_IOCTL_TASCAM_STATE _IOR('H', 0xfb, struct snd_firewire_tascam_state)
 
 #define SNDRV_FIREWIRE_TYPE_DICE       1
 #define SNDRV_FIREWIRE_TYPE_FIREWORKS  2
@@ -88,4 +102,10 @@ struct snd_firewire_get_info {
  * Returns -EBUSY if the driver is already streaming.
  */
 
+#define SNDRV_FIREWIRE_TASCAM_STATE_COUNT      64
+
+struct snd_firewire_tascam_state {
+       __be32 data[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
+};
+
 #endif /* _UAPI_SOUND_FIREWIRE_H_INCLUDED */
index abbad94e14a1021ed622ef428cbd5a6fee9ed86c..e582e8e7527afc9c7c37eb9bfaf6d070b807045b 100644 (file)
@@ -246,6 +246,9 @@ struct ipu_image {
        struct v4l2_rect rect;
        dma_addr_t phys0;
        dma_addr_t phys1;
+       /* chroma plane offset overrides */
+       u32 u_offset;
+       u32 v_offset;
 };
 
 void ipu_cpmem_zero(struct ipuv3_channel *ch);
@@ -387,6 +390,12 @@ int ipu_ic_task_init(struct ipu_ic *ic,
                     int out_width, int out_height,
                     enum ipu_color_space in_cs,
                     enum ipu_color_space out_cs);
+int ipu_ic_task_init_rsc(struct ipu_ic *ic,
+                        int in_width, int in_height,
+                        int out_width, int out_height,
+                        enum ipu_color_space in_cs,
+                        enum ipu_color_space out_cs,
+                        u32 rsc);
 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
                              enum ipu_color_space in_g_cs,
                              bool galpha_en, u32 galpha,
index b1a3545d0ec89f747d1cd51b7140fd64ad2fe6fd..b2890c268cb340cab7424ef750ec47bcc5488ad4 100644 (file)
@@ -365,13 +365,11 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp)
 }
 
 #ifdef CONFIG_BPF_JIT
-# define BPF_JIT_LIMIT_DEFAULT (PAGE_SIZE * 40000)
-
 /* All BPF JIT sysctl knobs here. */
 int bpf_jit_enable   __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_ALWAYS_ON);
 int bpf_jit_harden   __read_mostly;
 int bpf_jit_kallsyms __read_mostly;
-int bpf_jit_limit    __read_mostly = BPF_JIT_LIMIT_DEFAULT;
+long bpf_jit_limit   __read_mostly;
 
 static __always_inline void
 bpf_get_prog_addr_region(const struct bpf_prog *prog,
@@ -580,16 +578,27 @@ int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 
 static atomic_long_t bpf_jit_current;
 
+/* Can be overridden by an arch's JIT compiler if it has a custom,
+ * dedicated BPF backend memory area, or if neither of the two
+ * below apply.
+ */
+u64 __weak bpf_jit_alloc_exec_limit(void)
+{
 #if defined(MODULES_VADDR)
+       return MODULES_END - MODULES_VADDR;
+#else
+       return VMALLOC_END - VMALLOC_START;
+#endif
+}
+
 static int __init bpf_jit_charge_init(void)
 {
        /* Only used as heuristic here to derive limit. */
-       bpf_jit_limit = min_t(u64, round_up((MODULES_END - MODULES_VADDR) >> 2,
-                                           PAGE_SIZE), INT_MAX);
+       bpf_jit_limit = min_t(u64, round_up(bpf_jit_alloc_exec_limit() >> 2,
+                                           PAGE_SIZE), LONG_MAX);
        return 0;
 }
 pure_initcall(bpf_jit_charge_init);
-#endif
 
 static int bpf_jit_charge_modmem(u32 pages)
 {
index fc760d00a38c497502c28b56aad1a8d426565560..51ba84d4d34a06b6557245a05211a919d23259fb 100644 (file)
@@ -5102,9 +5102,16 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
        }
        new_sl->next = env->explored_states[insn_idx];
        env->explored_states[insn_idx] = new_sl;
-       /* connect new state to parentage chain */
-       for (i = 0; i < BPF_REG_FP; i++)
-               cur_regs(env)[i].parent = &new->frame[new->curframe]->regs[i];
+       /* connect new state to parentage chain. Current frame needs all
+        * registers connected. Only r6 - r9 of the callers are alive (pushed
+        * to the stack implicitly by JITs) so in callers' frames connect just
+        * r6 - r9 as an optimization. Callers will have r1 - r5 connected to
+        * the state of the call instruction (with WRITTEN set), and r0 comes
+        * from callee with its full parentage chain, anyway.
+        */
+       for (j = 0; j <= cur->curframe; j++)
+               for (i = j < cur->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++)
+                       cur->frame[j]->regs[i].parent = &new->frame[j]->regs[i];
        /* clear write marks in current state: the writes we did are not writes
         * our child did, so they don't screen off its reads from us.
         * (There are no read marks in current state, because reads always mark
index 22a12ab5a5e9aaac7ac5207d70b059bd75e48965..375c77e8d52fa0aa17d4dee12651836fc7981556 100644 (file)
@@ -309,7 +309,12 @@ int dma_direct_supported(struct device *dev, u64 mask)
 
        min_mask = min_t(u64, min_mask, (max_pfn - 1) << PAGE_SHIFT);
 
-       return mask >= phys_to_dma(dev, min_mask);
+       /*
+        * This check needs to be against the actual bit mask value, so
+        * use __phys_to_dma() here so that the SME encryption mask isn't
+        * part of the check.
+        */
+       return mask >= __phys_to_dma(dev, min_mask);
 }
 
 int dma_direct_mapping_error(struct device *dev, dma_addr_t dma_addr)
index 07cddff89c7b6bac3658c8cb41dd32dc64a3cfa4..e2a5156bc9c3301eeb83b21d0fc4f1f9541b3d7b 100644 (file)
@@ -240,8 +240,10 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
         * free_thread_stack() can be called in interrupt context,
         * so cache the vm_struct.
         */
-       if (stack)
+       if (stack) {
                tsk->stack_vm_area = find_vm_area(stack);
+               tsk->stack = stack;
+       }
        return stack;
 #else
        struct page *page = alloc_pages_node(node, THREADINFO_GFP,
@@ -288,7 +290,10 @@ static struct kmem_cache *thread_stack_cache;
 static unsigned long *alloc_thread_stack_node(struct task_struct *tsk,
                                                  int node)
 {
-       return kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node);
+       unsigned long *stack;
+       stack = kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node);
+       tsk->stack = stack;
+       return stack;
 }
 
 static void free_thread_stack(struct task_struct *tsk)
index f423f9b6577eb23849ebbbf87ee9549d74e62da2..5cc8083a4c890976c93d5ff5bc45357349f13f25 100644 (file)
@@ -1148,11 +1148,65 @@ out_error:
        return ret;
 }
 
+static int handle_exit_race(u32 __user *uaddr, u32 uval,
+                           struct task_struct *tsk)
+{
+       u32 uval2;
+
+       /*
+        * If PF_EXITPIDONE is not yet set, then try again.
+        */
+       if (tsk && !(tsk->flags & PF_EXITPIDONE))
+               return -EAGAIN;
+
+       /*
+        * Reread the user space value to handle the following situation:
+        *
+        * CPU0                         CPU1
+        *
+        * sys_exit()                   sys_futex()
+        *  do_exit()                    futex_lock_pi()
+        *                                futex_lock_pi_atomic()
+        *   exit_signals(tsk)              No waiters:
+        *    tsk->flags |= PF_EXITING;     *uaddr == 0x00000PID
+        *  mm_release(tsk)                 Set waiter bit
+        *   exit_robust_list(tsk) {        *uaddr = 0x80000PID;
+        *      Set owner died              attach_to_pi_owner() {
+        *    *uaddr = 0xC0000000;           tsk = get_task(PID);
+        *   }                               if (!tsk->flags & PF_EXITING) {
+        *  ...                                attach();
+        *  tsk->flags |= PF_EXITPIDONE;     } else {
+        *                                     if (!(tsk->flags & PF_EXITPIDONE))
+        *                                       return -EAGAIN;
+        *                                     return -ESRCH; <--- FAIL
+        *                                   }
+        *
+        * Returning ESRCH unconditionally is wrong here because the
+        * user space value has been changed by the exiting task.
+        *
+        * The same logic applies to the case where the exiting task is
+        * already gone.
+        */
+       if (get_futex_value_locked(&uval2, uaddr))
+               return -EFAULT;
+
+       /* If the user space value has changed, try again. */
+       if (uval2 != uval)
+               return -EAGAIN;
+
+       /*
+        * The exiting task did not have a robust list, the robust list was
+        * corrupted or the user space value in *uaddr is simply bogus.
+        * Give up and tell user space.
+        */
+       return -ESRCH;
+}
+
 /*
  * Lookup the task for the TID provided from user space and attach to
  * it after doing proper sanity checks.
  */
-static int attach_to_pi_owner(u32 uval, union futex_key *key,
+static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
                              struct futex_pi_state **ps)
 {
        pid_t pid = uval & FUTEX_TID_MASK;
@@ -1162,12 +1216,15 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key,
        /*
         * We are the first waiter - try to look up the real owner and attach
         * the new pi_state to it, but bail out when TID = 0 [1]
+        *
+        * The !pid check is paranoid. None of the call sites should end up
+        * with pid == 0, but better safe than sorry. Let the caller retry
         */
        if (!pid)
-               return -ESRCH;
+               return -EAGAIN;
        p = find_get_task_by_vpid(pid);
        if (!p)
-               return -ESRCH;
+               return handle_exit_race(uaddr, uval, NULL);
 
        if (unlikely(p->flags & PF_KTHREAD)) {
                put_task_struct(p);
@@ -1187,7 +1244,7 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key,
                 * set, we know that the task has finished the
                 * cleanup:
                 */
-               int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN;
+               int ret = handle_exit_race(uaddr, uval, p);
 
                raw_spin_unlock_irq(&p->pi_lock);
                put_task_struct(p);
@@ -1244,7 +1301,7 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval,
         * We are the first waiter - try to look up the owner based on
         * @uval and attach to it.
         */
-       return attach_to_pi_owner(uval, key, ps);
+       return attach_to_pi_owner(uaddr, uval, key, ps);
 }
 
 static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
@@ -1352,7 +1409,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
         * attach to the owner. If that fails, no harm done, we only
         * set the FUTEX_WAITERS bit in the user space variable.
         */
-       return attach_to_pi_owner(uval, key, ps);
+       return attach_to_pi_owner(uaddr, newval, key, ps);
 }
 
 /**
index 35b50823d83be811552c8e800844bb86fac29a66..98e76cad128b81c37a8a8f9592884fd9daf95c56 100644 (file)
@@ -318,23 +318,12 @@ static int suspend_stats_show(struct seq_file *s, void *unused)
 
        return 0;
 }
-
-static int suspend_stats_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, suspend_stats_show, NULL);
-}
-
-static const struct file_operations suspend_stats_operations = {
-       .open           = suspend_stats_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(suspend_stats);
 
 static int __init pm_debugfs_init(void)
 {
        debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
-                       NULL, NULL, &suspend_stats_operations);
+                       NULL, NULL, &suspend_stats_fops);
        return 0;
 }
 
index 86d72ffb811b6483374833eb1c81dd751b34eeec..b7a82502857a3f912588828d324da8c6489279b8 100644 (file)
@@ -184,7 +184,7 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
        c->target_value = value;
 }
 
-static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused)
+static int pm_qos_debug_show(struct seq_file *s, void *unused)
 {
        struct pm_qos_object *qos = (struct pm_qos_object *)s->private;
        struct pm_qos_constraints *c;
@@ -245,18 +245,7 @@ out:
        return 0;
 }
 
-static int pm_qos_dbg_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pm_qos_dbg_show_requests,
-                          inode->i_private);
-}
-
-static const struct file_operations pm_qos_debug_fops = {
-       .open           = pm_qos_dbg_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pm_qos_debug);
 
 /**
  * pm_qos_update_target - manages the constraints list and calls the notifiers
index 5e54cbcae6735b3b5cd969bdda2ff1432b8bf53a..22bd8980f32f8b84401d013539d3e5a441a68615 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Scheduler code and data structures related to cpufreq.
  *
  * Copyright (C) 2016, Intel Corporation
  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 #include "sched.h"
 
index 3fffad3bc8a86a366b93d5480c8840f34a84121e..626ddd4ffa4333723a405e639258c44d9dd55dd0 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * CPUFreq governor based on scheduler-provided CPU utilization data.
  *
  * Copyright (C) 2016, Intel Corporation
  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index bd62b5eeb5a057b000d6b8019072853b5daa37d6..31f49ae80f43dd76e5eea85416dc362b45e60780 100644 (file)
@@ -289,9 +289,6 @@ static void common_hrtimer_rearm(struct k_itimer *timr)
 {
        struct hrtimer *timer = &timr->it.real.timer;
 
-       if (!timr->it_interval)
-               return;
-
        timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
                                            timr->it_interval);
        hrtimer_restart(timer);
@@ -317,7 +314,7 @@ void posixtimer_rearm(struct kernel_siginfo *info)
        if (!timr)
                return;
 
-       if (timr->it_requeue_pending == info->si_sys_private) {
+       if (timr->it_interval && timr->it_requeue_pending == info->si_sys_private) {
                timr->kclock->timer_rearm(timr);
 
                timr->it_active = 1;
index 5da55b38b1b7fd2878a20b41c180b839096fd872..e84a10b0d310d0be5acebedcd2d422fe5e928f86 100644 (file)
@@ -2144,23 +2144,25 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
         */
        old_pmd = pmdp_invalidate(vma, haddr, pmd);
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
        pmd_migration = is_pmd_migration_entry(old_pmd);
-       if (pmd_migration) {
+       if (unlikely(pmd_migration)) {
                swp_entry_t entry;
 
                entry = pmd_to_swp_entry(old_pmd);
                page = pfn_to_page(swp_offset(entry));
-       } else
-#endif
+               write = is_write_migration_entry(entry);
+               young = false;
+               soft_dirty = pmd_swp_soft_dirty(old_pmd);
+       } else {
                page = pmd_page(old_pmd);
+               if (pmd_dirty(old_pmd))
+                       SetPageDirty(page);
+               write = pmd_write(old_pmd);
+               young = pmd_young(old_pmd);
+               soft_dirty = pmd_soft_dirty(old_pmd);
+       }
        VM_BUG_ON_PAGE(!page_count(page), page);
        page_ref_add(page, HPAGE_PMD_NR - 1);
-       if (pmd_dirty(old_pmd))
-               SetPageDirty(page);
-       write = pmd_write(old_pmd);
-       young = pmd_young(old_pmd);
-       soft_dirty = pmd_soft_dirty(old_pmd);
 
        /*
         * Withdraw the table only after we mark the pmd entry invalid.
index 2ec9cc407216565f849b752484e731433fba146c..e95b5b7c9c3d637efe29d07d86c75975acbfc500 100644 (file)
@@ -5542,6 +5542,18 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                        cond_resched();
                }
        }
+#ifdef CONFIG_SPARSEMEM
+       /*
+        * If the zone does not span the rest of the section then
+        * we should at least initialize those pages. Otherwise we
+        * could blow up on a poisoned page in some paths which depend
+        * on full sections being initialized (e.g. memory hotplug).
+        */
+       while (end_pfn % PAGES_PER_SECTION) {
+               __init_single_page(pfn_to_page(end_pfn), end_pfn, zone, nid);
+               end_pfn++;
+       }
+#endif
 }
 
 #ifdef CONFIG_ZONE_DEVICE
@@ -7802,11 +7814,14 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                 * handle each tail page individually in migration.
                 */
                if (PageHuge(page)) {
+                       struct page *head = compound_head(page);
+                       unsigned int skip_pages;
 
-                       if (!hugepage_migration_supported(page_hstate(page)))
+                       if (!hugepage_migration_supported(page_hstate(head)))
                                goto unmovable;
 
-                       iter = round_up(iter + 1, 1<<compound_order(page)) - 1;
+                       skip_pages = (1 << compound_order(head)) - (page - head);
+                       iter += skip_pages - 1;
                        continue;
                }
 
index 5d07e0b1352f3f2c81081a0eae4fb772566d057c..375f3ac19bb88c9cd3b132cf0ffc14e84ff771dd 100644 (file)
@@ -758,7 +758,7 @@ void shmem_unlock_mapping(struct address_space *mapping)
                        break;
                index = indices[pvec.nr - 1] + 1;
                pagevec_remove_exceptionals(&pvec);
-               check_move_unevictable_pages(pvec.pages, pvec.nr);
+               check_move_unevictable_pages(&pvec);
                pagevec_release(&pvec);
                cond_resched();
        }
index 62ac0c488624fd8fd3d2306b04951466cca1a0df..24ab1f7394abaafa9e0dccac37597ae65ef77e0f 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/delayacct.h>
 #include <linux/sysctl.h>
 #include <linux/oom.h>
+#include <linux/pagevec.h>
 #include <linux/prefetch.h>
 #include <linux/printk.h>
 #include <linux/dax.h>
@@ -4182,17 +4183,16 @@ int page_evictable(struct page *page)
        return ret;
 }
 
-#ifdef CONFIG_SHMEM
 /**
- * check_move_unevictable_pages - check pages for evictability and move to appropriate zone lru list
- * @pages:     array of pages to check
- * @nr_pages:  number of pages to check
+ * check_move_unevictable_pages - check pages for evictability and move to
+ * appropriate zone lru list
+ * @pvec: pagevec with lru pages to check
  *
- * Checks pages for evictability and moves them to the appropriate lru list.
- *
- * This function is only used for SysV IPC SHM_UNLOCK.
+ * Checks pages for evictability, if an evictable page is in the unevictable
+ * lru list, moves it to the appropriate evictable lru list. This function
+ * should be only used for lru pages.
  */
-void check_move_unevictable_pages(struct page **pages, int nr_pages)
+void check_move_unevictable_pages(struct pagevec *pvec)
 {
        struct lruvec *lruvec;
        struct pglist_data *pgdat = NULL;
@@ -4200,8 +4200,8 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages)
        int pgrescued = 0;
        int i;
 
-       for (i = 0; i < nr_pages; i++) {
-               struct page *page = pages[i];
+       for (i = 0; i < pvec->nr; i++) {
+               struct page *page = pvec->pages[i];
                struct pglist_data *pagepgdat = page_pgdat(page);
 
                pgscanned++;
@@ -4233,4 +4233,4 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages)
                spin_unlock_irq(&pgdat->lru_lock);
        }
 }
-#endif /* CONFIG_SHMEM */
+EXPORT_SYMBOL_GPL(check_move_unevictable_pages);
index 3aab7664933fdc67770cdbc8b80a231b41dc2555..c70207537488ff3c4f6183a725cf6334d2d042eb 100644 (file)
@@ -771,7 +771,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if (err < 0)
                goto free_skb;
 
-       sock_tx_timestamp(sk, sk->sk_tsflags, &skb_shinfo(skb)->tx_flags);
+       skb_setup_tx_timestamp(skb, sk->sk_tsflags);
 
        skb->dev = dev;
        skb->sk  = sk;
index 588f475019d47c9d6bae8883acebab48aaf63b48..af68207ee56c34324939e2a0ca0b0e6a87dee2fc 100644 (file)
@@ -783,6 +783,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
                /* Pass parameters to the BPF program */
                cb->qdisc_cb.flow_keys = &flow_keys;
                flow_keys.nhoff = nhoff;
+               flow_keys.thoff = nhoff;
 
                bpf_compute_data_pointers((struct sk_buff *)skb);
                result = BPF_PROG_RUN(attached, skb);
@@ -790,9 +791,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
                /* Restore state */
                memcpy(cb, &cb_saved, sizeof(cb_saved));
 
+               flow_keys.nhoff = clamp_t(u16, flow_keys.nhoff, 0, skb->len);
+               flow_keys.thoff = clamp_t(u16, flow_keys.thoff,
+                                         flow_keys.nhoff, skb->len);
+
                __skb_flow_bpf_to_target(&flow_keys, flow_dissector,
                                         target_container);
-               key_control->thoff = min_t(u16, key_control->thoff, skb->len);
                rcu_read_unlock();
                return result == BPF_OK;
        }
index 4b54e5f107c6a3a50031a6e19fb249a15086b892..acf45ddbe924e62c5a8382ac3f9b176dfe56ca7e 100644 (file)
@@ -84,6 +84,7 @@ void gro_cells_destroy(struct gro_cells *gcells)
        for_each_possible_cpu(i) {
                struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
 
+               napi_disable(&cell->napi);
                netif_napi_del(&cell->napi);
                __skb_queue_purge(&cell->napi_skbs);
        }
index 41954e42a2ded2ac1770c4b107505a5eee57a2be..5fa32c064bafdff8e83dff2bfe081e1fa0090229 100644 (file)
@@ -2494,11 +2494,16 @@ static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
 
                ndm = nlmsg_data(nlh);
                if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
-                   ndm->ndm_state || ndm->ndm_flags || ndm->ndm_type) {
+                   ndm->ndm_state || ndm->ndm_type) {
                        NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
                        return -EINVAL;
                }
 
+               if (ndm->ndm_flags & ~NTF_PROXY) {
+                       NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
+                       return -EINVAL;
+               }
+
                err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
                                         NULL, extack);
        } else {
index 56a99d0c9aa08db3bc294e129aa571325bd335cb..b7dbb3c976cd2932b52ddf9fbc8a2f724ca423f0 100644 (file)
@@ -94,6 +94,9 @@ int sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src,
        }
 
        while (len) {
+               if (sk_msg_full(dst))
+                       return -ENOSPC;
+
                sge_len = sge->length - off;
                sge_off = sge->offset + off;
                if (sge_len > len)
index 37b4667128a3808395e23b0c53325a5d937c6b54..d67ec17f2cc862852e892dd279522433dcbd73cd 100644 (file)
@@ -28,6 +28,8 @@ static int two __maybe_unused = 2;
 static int min_sndbuf = SOCK_MIN_SNDBUF;
 static int min_rcvbuf = SOCK_MIN_RCVBUF;
 static int max_skb_frags = MAX_SKB_FRAGS;
+static long long_one __maybe_unused = 1;
+static long long_max __maybe_unused = LONG_MAX;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -289,6 +291,17 @@ proc_dointvec_minmax_bpf_restricted(struct ctl_table *table, int write,
 
        return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 }
+
+static int
+proc_dolongvec_minmax_bpf_restricted(struct ctl_table *table, int write,
+                                    void __user *buffer, size_t *lenp,
+                                    loff_t *ppos)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
+}
 #endif
 
 static struct ctl_table net_core_table[] = {
@@ -398,10 +411,11 @@ static struct ctl_table net_core_table[] = {
        {
                .procname       = "bpf_jit_limit",
                .data           = &bpf_jit_limit,
-               .maxlen         = sizeof(int),
+               .maxlen         = sizeof(long),
                .mode           = 0600,
-               .proc_handler   = proc_dointvec_minmax_bpf_restricted,
-               .extra1         = &one,
+               .proc_handler   = proc_dolongvec_minmax_bpf_restricted,
+               .extra1         = &long_one,
+               .extra2         = &long_max,
        },
 #endif
        {
index a34602ae27dee2d3ff5d579172910c5f9f004292..608a6f4223fb964c487f3bd9c4e074f3f34167d7 100644 (file)
@@ -952,17 +952,18 @@ static int inet_abc_len(__be32 addr)
 {
        int rc = -1;    /* Something else, probably a multicast. */
 
-       if (ipv4_is_zeronet(addr))
+       if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
                rc = 0;
        else {
                __u32 haddr = ntohl(addr);
-
                if (IN_CLASSA(haddr))
                        rc = 8;
                else if (IN_CLASSB(haddr))
                        rc = 16;
                else if (IN_CLASSC(haddr))
                        rc = 24;
+               else if (IN_CLASSE(haddr))
+                       rc = 32;
        }
 
        return rc;
index 4e5bc4b2f14e6786ceb7d63e5902f8fc17819dfa..1a4e9ff02762ed757545da13de1ee352f38c867b 100644 (file)
@@ -998,7 +998,9 @@ next_chunk:
                        if (!inet_diag_bc_sk(bc, sk))
                                goto next_normal;
 
-                       sock_hold(sk);
+                       if (!refcount_inc_not_zero(&sk->sk_refcnt))
+                               goto next_normal;
+
                        num_arr[accum] = num;
                        sk_arr[accum] = sk;
                        if (++accum == SKARR_SZ)
index 32662e9e5d218868341169bba1dc3ab430952c58..d5984d31ab931487fdea844aa4a240df00d2b64e 100644 (file)
@@ -72,6 +72,7 @@ static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *s
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       skb->tstamp = 0;
        return dst_output(net, sk, skb);
 }
 
index aa0b22697998ab60f0013bf65cea9cef2913f61f..867be8f7f1fa03063c35310b1fd37a65e5c726fb 100644 (file)
@@ -346,10 +346,10 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        struct net *net = container_of(qp->q.net, struct net, ipv4.frags);
        struct rb_node **rbn, *parent;
        struct sk_buff *skb1, *prev_tail;
+       int ihl, end, skb1_run_end;
        struct net_device *dev;
        unsigned int fragsize;
        int flags, offset;
-       int ihl, end;
        int err = -ENOENT;
        u8 ecn;
 
@@ -419,7 +419,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
         *   overlapping fragment, the entire datagram (and any constituent
         *   fragments) MUST be silently discarded.
         *
-        * We do the same here for IPv4 (and increment an snmp counter).
+        * We do the same here for IPv4 (and increment an snmp counter) but
+        * we do not want to drop the whole queue in response to a duplicate
+        * fragment.
         */
 
        err = -EINVAL;
@@ -444,13 +446,17 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
                do {
                        parent = *rbn;
                        skb1 = rb_to_skb(parent);
+                       skb1_run_end = skb1->ip_defrag_offset +
+                                      FRAG_CB(skb1)->frag_run_len;
                        if (end <= skb1->ip_defrag_offset)
                                rbn = &parent->rb_left;
-                       else if (offset >= skb1->ip_defrag_offset +
-                                               FRAG_CB(skb1)->frag_run_len)
+                       else if (offset >= skb1_run_end)
                                rbn = &parent->rb_right;
-                       else /* Found an overlap with skb1. */
-                               goto overlap;
+                       else if (offset >= skb1->ip_defrag_offset &&
+                                end <= skb1_run_end)
+                               goto err; /* No new data, potential duplicate */
+                       else
+                               goto overlap; /* Found an overlap */
                } while (*rbn);
                /* Here we have parent properly set, and rbn pointing to
                 * one of its NULL left/right children. Insert skb.
index 88212615bf4ce75f5e840297b1be70f4e4e0b83b..2393e5c106bfa490dc2f45c6fbb843532bffc404 100644 (file)
@@ -429,6 +429,8 @@ static int __init ic_defaults(void)
                        ic_netmask = htonl(IN_CLASSB_NET);
                else if (IN_CLASSC(ntohl(ic_myaddr)))
                        ic_netmask = htonl(IN_CLASSC_NET);
+               else if (IN_CLASSE(ntohl(ic_myaddr)))
+                       ic_netmask = htonl(IN_CLASSE_NET);
                else {
                        pr_err("IP-Config: Unable to guess netmask for address %pI4\n",
                               &ic_myaddr);
index a6defbec4f1b4338993756ea7b8681012450aa1a..e7a3879cedd0a13610027fa88dfa2a8f715ba9f0 100644 (file)
@@ -69,6 +69,8 @@
 #include <net/nexthop.h>
 #include <net/switchdev.h>
 
+#include <linux/nospec.h>
+
 struct ipmr_rule {
        struct fib_rule         common;
 };
@@ -1612,6 +1614,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
                        return -EFAULT;
                if (vr.vifi >= mrt->maxvif)
                        return -EINVAL;
+               vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif);
                read_lock(&mrt_lock);
                vif = &mrt->vif_table[vr.vifi];
                if (VIF_EXISTS(mrt, vr.vifi)) {
@@ -1686,6 +1689,7 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
                        return -EFAULT;
                if (vr.vifi >= mrt->maxvif)
                        return -EINVAL;
+               vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif);
                read_lock(&mrt_lock);
                vif = &mrt->vif_table[vr.vifi];
                if (VIF_EXISTS(mrt, vr.vifi)) {
index 8ca3eb06ba04246ce9f53045488f1da57dc8e689..169a652b3dd1a7c2d9d6401236f76f76e427562c 100644 (file)
@@ -391,7 +391,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
 
        skb->ip_summed = CHECKSUM_NONE;
 
-       sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags);
+       skb_setup_tx_timestamp(skb, sockc->tsflags);
 
        if (flags & MSG_CONFIRM)
                skb_set_dst_pending_confirm(skb, 1);
index fcd3c66ded1620d0d320fd7b1753f2734d1dfa46..4591ca4bdbe8831f8183c4df0d4237d023b5bb68 100644 (file)
@@ -378,6 +378,7 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
        __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
        __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
 
+       skb->tstamp = 0;
        return dst_output(net, sk, skb);
 }
 
index a9d06d4dd05784b9f3d6e492ac3f395ed6a234d6..99179b9c83840bb730a27e7391c9e7f67d043cf1 100644 (file)
@@ -901,6 +901,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
                        goto drop;
                if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
                        goto drop;
+               ipv6h = ipv6_hdr(skb);
                if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr))
                        goto drop;
                if (iptunnel_pull_header(skb, 0, tpi->proto, false))
index b283f293ee4ae7537da0bde51b5a4695a2e6f249..caad40d6e74d5c12b5215b0acda1f78e53da7955 100644 (file)
@@ -15,7 +15,7 @@
 int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
                     struct socket **sockp)
 {
-       struct sockaddr_in6 udp6_addr;
+       struct sockaddr_in6 udp6_addr = {};
        int err;
        struct socket *sock = NULL;
 
@@ -42,6 +42,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
                goto error;
 
        if (cfg->peer_udp_port) {
+               memset(&udp6_addr, 0, sizeof(udp6_addr));
                udp6_addr.sin6_family = AF_INET6;
                memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
                       sizeof(udp6_addr.sin6_addr));
index eeaf7455d51e52f12b62ffd0c1c82e2ee09e4fc1..706fe42e4928990c84ba157496628d14803f7199 100644 (file)
@@ -318,6 +318,7 @@ static int vti6_rcv(struct sk_buff *skb)
                        return 0;
                }
 
+               ipv6h = ipv6_hdr(skb);
                if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
                        t->dev->stats.rx_dropped++;
                        rcu_read_unlock();
index e2ea691e42c6d6efe4ddf845e01422bf31e9fc4e..377a2ee5d9ad8a6aec96a5fea7f63e6890399771 100644 (file)
@@ -52,6 +52,8 @@
 #include <net/ip6_checksum.h>
 #include <linux/netconf.h>
 
+#include <linux/nospec.h>
+
 struct ip6mr_rule {
        struct fib_rule         common;
 };
@@ -1841,6 +1843,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
                        return -EFAULT;
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
+               vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
                read_lock(&mrt_lock);
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
@@ -1915,6 +1918,7 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
                        return -EFAULT;
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
+               vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
                read_lock(&mrt_lock);
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
index 5e0efd3954e90ade89eb4da17cd5ecef1894a1a3..fc2b5e845fdf3e2f8ccafbccbbfc7465af0fa13b 100644 (file)
@@ -658,6 +658,8 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
 
        skb->ip_summed = CHECKSUM_NONE;
 
+       skb_setup_tx_timestamp(skb, sockc->tsflags);
+
        if (flags & MSG_CONFIRM)
                skb_set_dst_pending_confirm(skb, 1);
 
index aa26c45486d94ab2f2f9f443b837642d8b582f83..a5bb59ee50acc4b813765a61dab5fd030ea089dd 100644 (file)
@@ -384,6 +384,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                if (skb_try_coalesce(head, fp, &headstolen, &delta)) {
                        kfree_skb_partial(fp, headstolen);
                } else {
+                       fp->sk = NULL;
                        if (!skb_shinfo(head)->frag_list)
                                skb_shinfo(head)->frag_list = fp;
                        head->data_len += fp->len;
index 5f3c81e705c7df9ea7ff7c69eb3b6aff00df17ee..3a0171a65db320d5a42eb84a2fbcaff2c85a00d3 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (c) 2016        Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1951,6 +1952,8 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
        WARN(local->open_count, "%s: open count remains %d\n",
             wiphy_name(local->hw.wiphy), local->open_count);
 
+       ieee80211_txq_teardown_flows(local);
+
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
                list_del(&sdata->list);
index 83e71e6b2ebe04f244b574fcdfe8b95f1a48ca00..7b8320d4a8e4bf42475277db8e8acf59ba7e3fa6 100644 (file)
@@ -1262,7 +1262,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        rtnl_unlock();
        ieee80211_led_exit(local);
        ieee80211_wep_free(local);
-       ieee80211_txq_teardown_flows(local);
  fail_flows:
        destroy_workqueue(local->workqueue);
  fail_workqueue:
@@ -1288,7 +1287,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 #if IS_ENABLED(CONFIG_IPV6)
        unregister_inet6addr_notifier(&local->ifa6_notifier);
 #endif
-       ieee80211_txq_teardown_flows(local);
 
        rtnl_lock();
 
index a794ca7290001a778d7ef5fde62a7c32b7c110b1..3f0b96e1e02fa572bde737a0cc3f98967fe8ac0f 100644 (file)
@@ -556,6 +556,11 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
        }
 
        ieee80211_led_tx(local);
+
+       if (skb_has_frag_list(skb)) {
+               kfree_skb_list(skb_shinfo(skb)->frag_list);
+               skb_shinfo(skb)->frag_list = NULL;
+       }
 }
 
 /*
index 4eef55da0878e299d0bb912fa7ea69d3d4e91441..8da228da53ae98e0befbcede2d3b3c8f394aefc2 100644 (file)
@@ -531,8 +531,8 @@ nla_put_failure:
                ret = -EMSGSIZE;
        } else {
                cb->args[IPSET_CB_ARG0] = i;
+               ipset_nest_end(skb, atd);
        }
-       ipset_nest_end(skb, atd);
 out:
        rcu_read_unlock();
        return ret;
index b6d0f6deea86c34437f997533df3f4f7f4f6bd50..9cd180bda0920304467165cef1365c7291575347 100644 (file)
@@ -427,7 +427,7 @@ insert_tree(struct net *net,
        count = 1;
        rbconn->list.count = count;
 
-       rb_link_node(&rbconn->node, parent, rbnode);
+       rb_link_node_rcu(&rbconn->node, parent, rbnode);
        rb_insert_color(&rbconn->node, root);
 out_unlock:
        spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]);
index a975efd6b8c3e3baac2a80334237be9201ace130..9da303461069cd9ea353ab9fa173b5b4322a665f 100644 (file)
@@ -115,12 +115,12 @@ static void nf_ct_sack_block_adjust(struct sk_buff *skb,
 /* TCP SACK sequence number adjustment */
 static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
                                      unsigned int protoff,
-                                     struct tcphdr *tcph,
                                      struct nf_conn *ct,
                                      enum ip_conntrack_info ctinfo)
 {
-       unsigned int dir, optoff, optend;
+       struct tcphdr *tcph = (void *)skb->data + protoff;
        struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
+       unsigned int dir, optoff, optend;
 
        optoff = protoff + sizeof(struct tcphdr);
        optend = protoff + tcph->doff * 4;
@@ -128,6 +128,7 @@ static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
        if (!skb_make_writable(skb, optend))
                return 0;
 
+       tcph = (void *)skb->data + protoff;
        dir = CTINFO2DIR(ctinfo);
 
        while (optoff < optend) {
@@ -207,7 +208,7 @@ int nf_ct_seq_adjust(struct sk_buff *skb,
                 ntohl(newack));
        tcph->ack_seq = newack;
 
-       res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo);
+       res = nf_ct_sack_adjust(skb, protoff, ct, ctinfo);
 out:
        spin_unlock_bh(&ct->lock);
 
index e2b196054dfc6dbe2eeedbee76a8ab342187e297..2268b10a9dcf844b8ce9d8d43c6b32e943553496 100644 (file)
@@ -117,7 +117,8 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
        dst = skb_dst(skb);
        if (dst->xfrm)
                dst = ((struct xfrm_dst *)dst)->route;
-       dst_hold(dst);
+       if (!dst_hold_safe(dst))
+               return -EHOSTUNREACH;
 
        if (sk && !net_eq(net, sock_net(sk)))
                sk = NULL;
index 2e61aab6ed731356e34df28a6c1c8d41659ad749..6e548d7c9f67bee955f887319bc3c26fdd0c5bf7 100644 (file)
@@ -1216,7 +1216,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
                if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
                        goto nla_put_failure;
 
-               if (basechain->stats && nft_dump_stats(skb, basechain->stats))
+               if (rcu_access_pointer(basechain->stats) &&
+                   nft_dump_stats(skb, rcu_dereference(basechain->stats)))
                        goto nla_put_failure;
        }
 
@@ -1392,7 +1393,8 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
        return newstats;
 }
 
-static void nft_chain_stats_replace(struct nft_base_chain *chain,
+static void nft_chain_stats_replace(struct net *net,
+                                   struct nft_base_chain *chain,
                                    struct nft_stats __percpu *newstats)
 {
        struct nft_stats __percpu *oldstats;
@@ -1400,8 +1402,9 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain,
        if (newstats == NULL)
                return;
 
-       if (chain->stats) {
-               oldstats = nfnl_dereference(chain->stats, NFNL_SUBSYS_NFTABLES);
+       if (rcu_access_pointer(chain->stats)) {
+               oldstats = rcu_dereference_protected(chain->stats,
+                                       lockdep_commit_lock_is_held(net));
                rcu_assign_pointer(chain->stats, newstats);
                synchronize_rcu();
                free_percpu(oldstats);
@@ -1439,9 +1442,10 @@ static void nf_tables_chain_destroy(struct nft_ctx *ctx)
                struct nft_base_chain *basechain = nft_base_chain(chain);
 
                module_put(basechain->type->owner);
-               free_percpu(basechain->stats);
-               if (basechain->stats)
+               if (rcu_access_pointer(basechain->stats)) {
                        static_branch_dec(&nft_counters_enabled);
+                       free_percpu(rcu_dereference_raw(basechain->stats));
+               }
                kfree(chain->name);
                kfree(basechain);
        } else {
@@ -1590,7 +1594,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                                kfree(basechain);
                                return PTR_ERR(stats);
                        }
-                       basechain->stats = stats;
+                       rcu_assign_pointer(basechain->stats, stats);
                        static_branch_inc(&nft_counters_enabled);
                }
 
@@ -6180,7 +6184,8 @@ static void nft_chain_commit_update(struct nft_trans *trans)
                return;
 
        basechain = nft_base_chain(trans->ctx.chain);
-       nft_chain_stats_replace(basechain, nft_trans_chain_stats(trans));
+       nft_chain_stats_replace(trans->ctx.net, basechain,
+                               nft_trans_chain_stats(trans));
 
        switch (nft_trans_chain_policy(trans)) {
        case NF_DROP:
index 3fbce3b9c5ec0f51c9841aca36c0e5fc48b233c6..a50500232b0a9fb197b2a366a0c466d363867134 100644 (file)
@@ -101,7 +101,7 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain,
        struct nft_stats *stats;
 
        base_chain = nft_base_chain(chain);
-       if (!base_chain->stats)
+       if (!rcu_access_pointer(base_chain->stats))
                return;
 
        local_bh_disable();
index 6bb9f3cde0b0d82af00a6b4f212be8c0d385dd47..3c023d6120f657b098639d7fbdef56776225b676 100644 (file)
@@ -1706,7 +1706,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                        nlk->flags &= ~NETLINK_F_EXT_ACK;
                err = 0;
                break;
-       case NETLINK_DUMP_STRICT_CHK:
+       case NETLINK_GET_STRICT_CHK:
                if (val)
                        nlk->flags |= NETLINK_F_STRICT_CHK;
                else
@@ -1806,7 +1806,7 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
                        return -EFAULT;
                err = 0;
                break;
-       case NETLINK_DUMP_STRICT_CHK:
+       case NETLINK_GET_STRICT_CHK:
                if (len < sizeof(int))
                        return -EINVAL;
                len = sizeof(int);
index a74650e98f423d752e3c49df1388e9c86cb5ee44..5dda263b4a0a12e05c90329bfda18fc24a0c1de7 100644 (file)
@@ -1965,7 +1965,7 @@ retry:
        skb->mark = sk->sk_mark;
        skb->tstamp = sockc.transmit_time;
 
-       sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags);
+       skb_setup_tx_timestamp(skb, sockc.tsflags);
 
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;
@@ -2460,7 +2460,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
        skb->priority = po->sk.sk_priority;
        skb->mark = po->sk.sk_mark;
        skb->tstamp = sockc->transmit_time;
-       sock_tx_timestamp(&po->sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags);
+       skb_setup_tx_timestamp(skb, sockc->tsflags);
        skb_zcopy_set_nouarg(skb, ph.raw);
 
        skb_reserve(skb, hlen);
@@ -2627,6 +2627,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                proto   = saddr->sll_protocol;
                addr    = saddr->sll_addr;
                dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
+               if (addr && dev && saddr->sll_halen < dev->addr_len)
+                       goto out;
        }
 
        err = -ENXIO;
@@ -2825,6 +2827,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                proto   = saddr->sll_protocol;
                addr    = saddr->sll_addr;
                dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex);
+               if (addr && dev && saddr->sll_halen < dev->addr_len)
+                       goto out;
        }
 
        err = -ENXIO;
@@ -2898,7 +2902,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                goto out_free;
        }
 
-       sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags);
+       skb_setup_tx_timestamp(skb, sockc.tsflags);
 
        if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) &&
            !packet_extra_vlan_len_allowed(dev, skb)) {
index 4b00b1152a5f0a885100098e565b881ab68b7e57..f139420ba1f6837998567f9a7d1ac786147080cf 100644 (file)
@@ -308,16 +308,27 @@ out:
 /*
  * RDS ops use this to grab SG entries from the rm's sg pool.
  */
-struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents)
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents,
+                                         int *ret)
 {
        struct scatterlist *sg_first = (struct scatterlist *) &rm[1];
        struct scatterlist *sg_ret;
 
-       WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs);
-       WARN_ON(!nents);
+       if (WARN_ON(!ret))
+               return NULL;
 
-       if (rm->m_used_sgs + nents > rm->m_total_sgs)
+       if (nents <= 0) {
+               pr_warn("rds: alloc sgs failed! nents <= 0\n");
+               *ret = -EINVAL;
                return NULL;
+       }
+
+       if (rm->m_used_sgs + nents > rm->m_total_sgs) {
+               pr_warn("rds: alloc sgs failed! total %d used %d nents %d\n",
+                       rm->m_total_sgs, rm->m_used_sgs, nents);
+               *ret = -ENOMEM;
+               return NULL;
+       }
 
        sg_ret = &sg_first[rm->m_used_sgs];
        sg_init_table(sg_ret, nents);
@@ -332,6 +343,7 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
        unsigned int i;
        int num_sgs = ceil(total_len, PAGE_SIZE);
        int extra_bytes = num_sgs * sizeof(struct scatterlist);
+       int ret;
 
        rm = rds_message_alloc(extra_bytes, GFP_NOWAIT);
        if (!rm)
@@ -340,10 +352,10 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
        set_bit(RDS_MSG_PAGEVEC, &rm->m_flags);
        rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
        rm->data.op_nents = ceil(total_len, PAGE_SIZE);
-       rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
+       rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret);
        if (!rm->data.op_sg) {
                rds_message_put(rm);
-               return ERR_PTR(-ENOMEM);
+               return ERR_PTR(ret);
        }
 
        for (i = 0; i < rm->data.op_nents; ++i) {
index 98237feb607ac6f3d24ecd18ecb3320c47065d30..182ab8430594a967533fe64b44ebe41a97fab83c 100644 (file)
@@ -517,9 +517,10 @@ static int rds_rdma_pages(struct rds_iovec iov[], int nr_iovecs)
        return tot_pages;
 }
 
-int rds_rdma_extra_size(struct rds_rdma_args *args)
+int rds_rdma_extra_size(struct rds_rdma_args *args,
+                       struct rds_iov_vector *iov)
 {
-       struct rds_iovec vec;
+       struct rds_iovec *vec;
        struct rds_iovec __user *local_vec;
        int tot_pages = 0;
        unsigned int nr_pages;
@@ -530,13 +531,23 @@ int rds_rdma_extra_size(struct rds_rdma_args *args)
        if (args->nr_local == 0)
                return -EINVAL;
 
+       iov->iov = kcalloc(args->nr_local,
+                          sizeof(struct rds_iovec),
+                          GFP_KERNEL);
+       if (!iov->iov)
+               return -ENOMEM;
+
+       vec = &iov->iov[0];
+
+       if (copy_from_user(vec, local_vec, args->nr_local *
+                          sizeof(struct rds_iovec)))
+               return -EFAULT;
+       iov->len = args->nr_local;
+
        /* figure out the number of pages in the vector */
-       for (i = 0; i < args->nr_local; i++) {
-               if (copy_from_user(&vec, &local_vec[i],
-                                  sizeof(struct rds_iovec)))
-                       return -EFAULT;
+       for (i = 0; i < args->nr_local; i++, vec++) {
 
-               nr_pages = rds_pages_in_vec(&vec);
+               nr_pages = rds_pages_in_vec(vec);
                if (nr_pages == 0)
                        return -EINVAL;
 
@@ -558,15 +569,15 @@ int rds_rdma_extra_size(struct rds_rdma_args *args)
  * Extract all arguments and set up the rdma_op
  */
 int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg)
+                      struct cmsghdr *cmsg,
+                      struct rds_iov_vector *vec)
 {
        struct rds_rdma_args *args;
        struct rm_rdma_op *op = &rm->rdma;
        int nr_pages;
        unsigned int nr_bytes;
        struct page **pages = NULL;
-       struct rds_iovec iovstack[UIO_FASTIOV], *iovs = iovstack;
-       int iov_size;
+       struct rds_iovec *iovs;
        unsigned int i, j;
        int ret = 0;
 
@@ -586,31 +597,23 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
                goto out_ret;
        }
 
-       /* Check whether to allocate the iovec area */
-       iov_size = args->nr_local * sizeof(struct rds_iovec);
-       if (args->nr_local > UIO_FASTIOV) {
-               iovs = sock_kmalloc(rds_rs_to_sk(rs), iov_size, GFP_KERNEL);
-               if (!iovs) {
-                       ret = -ENOMEM;
-                       goto out_ret;
-               }
+       if (vec->len != args->nr_local) {
+               ret = -EINVAL;
+               goto out_ret;
        }
 
-       if (copy_from_user(iovs, (struct rds_iovec __user *)(unsigned long) args->local_vec_addr, iov_size)) {
-               ret = -EFAULT;
-               goto out;
-       }
+       iovs = vec->iov;
 
        nr_pages = rds_rdma_pages(iovs, args->nr_local);
        if (nr_pages < 0) {
                ret = -EINVAL;
-               goto out;
+               goto out_ret;
        }
 
        pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
        if (!pages) {
                ret = -ENOMEM;
-               goto out;
+               goto out_ret;
        }
 
        op->op_write = !!(args->flags & RDS_RDMA_READWRITE);
@@ -620,11 +623,9 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
        op->op_active = 1;
        op->op_recverr = rs->rs_recverr;
        WARN_ON(!nr_pages);
-       op->op_sg = rds_message_alloc_sgs(rm, nr_pages);
-       if (!op->op_sg) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       op->op_sg = rds_message_alloc_sgs(rm, nr_pages, &ret);
+       if (!op->op_sg)
+               goto out_pages;
 
        if (op->op_notify || op->op_recverr) {
                /* We allocate an uninitialized notifier here, because
@@ -635,7 +636,7 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
                op->op_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
                if (!op->op_notifier) {
                        ret = -ENOMEM;
-                       goto out;
+                       goto out_pages;
                }
                op->op_notifier->n_user_token = args->user_token;
                op->op_notifier->n_status = RDS_RDMA_SUCCESS;
@@ -681,7 +682,7 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
                 */
                ret = rds_pin_pages(iov->addr, nr, pages, !op->op_write);
                if (ret < 0)
-                       goto out;
+                       goto out_pages;
                else
                        ret = 0;
 
@@ -714,13 +715,11 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
                                nr_bytes,
                                (unsigned int) args->remote_vec.bytes);
                ret = -EINVAL;
-               goto out;
+               goto out_pages;
        }
        op->op_bytes = nr_bytes;
 
-out:
-       if (iovs != iovstack)
-               sock_kfree_s(rds_rs_to_sk(rs), iovs, iov_size);
+out_pages:
        kfree(pages);
 out_ret:
        if (ret)
@@ -838,11 +837,9 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
        rm->atomic.op_silent = !!(args->flags & RDS_RDMA_SILENT);
        rm->atomic.op_active = 1;
        rm->atomic.op_recverr = rs->rs_recverr;
-       rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1);
-       if (!rm->atomic.op_sg) {
-               ret = -ENOMEM;
+       rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1, &ret);
+       if (!rm->atomic.op_sg)
                goto err;
-       }
 
        /* verify 8 byte-aligned */
        if (args->local_addr & 0x7) {
index 6bfaf05b63b21efddec1b9fd03e80bc196276c3d..02ec4a3b2799018f7c99a09a24821fc8a72abb13 100644 (file)
@@ -386,6 +386,18 @@ static inline void rds_message_zcopy_queue_init(struct rds_msg_zcopy_queue *q)
        INIT_LIST_HEAD(&q->zcookie_head);
 }
 
+struct rds_iov_vector {
+       struct rds_iovec *iov;
+       int               len;
+};
+
+struct rds_iov_vector_arr {
+       struct rds_iov_vector *vec;
+       int                    len;
+       int                    indx;
+       int                    incr;
+};
+
 struct rds_message {
        refcount_t              m_refcount;
        struct list_head        m_sock_item;
@@ -827,7 +839,8 @@ rds_conn_connecting(struct rds_connection *conn)
 
 /* message.c */
 struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
-struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents);
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents,
+                                         int *ret);
 int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
                               bool zcopy);
 struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
@@ -904,13 +917,13 @@ int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
 int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
 int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
 void rds_rdma_drop_keys(struct rds_sock *rs);
-int rds_rdma_extra_size(struct rds_rdma_args *args);
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
+int rds_rdma_extra_size(struct rds_rdma_args *args,
+                       struct rds_iov_vector *iov);
 int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
                          struct cmsghdr *cmsg);
 int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
+                         struct cmsghdr *cmsg,
+                         struct rds_iov_vector *vec);
 int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
                          struct cmsghdr *cmsg);
 void rds_rdma_free_op(struct rm_rdma_op *ro);
index fe785ee819ddb195db524124c854decf6937d23b..3d822bad7de9093c4673349b0c465406b89d4722 100644 (file)
@@ -876,13 +876,18 @@ out:
  * rds_message is getting to be quite complicated, and we'd like to allocate
  * it all in one go. This figures out how big it needs to be up front.
  */
-static int rds_rm_size(struct msghdr *msg, int num_sgs)
+static int rds_rm_size(struct msghdr *msg, int num_sgs,
+                      struct rds_iov_vector_arr *vct)
 {
        struct cmsghdr *cmsg;
        int size = 0;
        int cmsg_groups = 0;
        int retval;
        bool zcopy_cookie = false;
+       struct rds_iov_vector *iov, *tmp_iov;
+
+       if (num_sgs < 0)
+               return -EINVAL;
 
        for_each_cmsghdr(cmsg, msg) {
                if (!CMSG_OK(msg, cmsg))
@@ -893,8 +898,24 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs)
 
                switch (cmsg->cmsg_type) {
                case RDS_CMSG_RDMA_ARGS:
+                       if (vct->indx >= vct->len) {
+                               vct->len += vct->incr;
+                               tmp_iov =
+                                       krealloc(vct->vec,
+                                                vct->len *
+                                                sizeof(struct rds_iov_vector),
+                                                GFP_KERNEL);
+                               if (!tmp_iov) {
+                                       vct->len -= vct->incr;
+                                       return -ENOMEM;
+                               }
+                               vct->vec = tmp_iov;
+                       }
+                       iov = &vct->vec[vct->indx];
+                       memset(iov, 0, sizeof(struct rds_iov_vector));
+                       vct->indx++;
                        cmsg_groups |= 1;
-                       retval = rds_rdma_extra_size(CMSG_DATA(cmsg));
+                       retval = rds_rdma_extra_size(CMSG_DATA(cmsg), iov);
                        if (retval < 0)
                                return retval;
                        size += retval;
@@ -951,10 +972,11 @@ static int rds_cmsg_zcopy(struct rds_sock *rs, struct rds_message *rm,
 }
 
 static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
-                        struct msghdr *msg, int *allocated_mr)
+                        struct msghdr *msg, int *allocated_mr,
+                        struct rds_iov_vector_arr *vct)
 {
        struct cmsghdr *cmsg;
-       int ret = 0;
+       int ret = 0, ind = 0;
 
        for_each_cmsghdr(cmsg, msg) {
                if (!CMSG_OK(msg, cmsg))
@@ -968,7 +990,10 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
                 */
                switch (cmsg->cmsg_type) {
                case RDS_CMSG_RDMA_ARGS:
-                       ret = rds_cmsg_rdma_args(rs, rm, cmsg);
+                       if (ind >= vct->indx)
+                               return -ENOMEM;
+                       ret = rds_cmsg_rdma_args(rs, rm, cmsg, &vct->vec[ind]);
+                       ind++;
                        break;
 
                case RDS_CMSG_RDMA_DEST:
@@ -1084,6 +1109,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
                      sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY));
        int num_sgs = ceil(payload_len, PAGE_SIZE);
        int namelen;
+       struct rds_iov_vector_arr vct;
+       int ind;
+
+       memset(&vct, 0, sizeof(vct));
+
+       /* expect 1 RDMA CMSG per rds_sendmsg. can still grow if more needed. */
+       vct.incr = 1;
 
        /* Mirror Linux UDP mirror of BSD error message compatibility */
        /* XXX: Perhaps MSG_MORE someday */
@@ -1220,7 +1252,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
                num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX);
        }
        /* size of rm including all sgs */
-       ret = rds_rm_size(msg, num_sgs);
+       ret = rds_rm_size(msg, num_sgs, &vct);
        if (ret < 0)
                goto out;
 
@@ -1232,11 +1264,9 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 
        /* Attach data to the rm */
        if (payload_len) {
-               rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
-               if (!rm->data.op_sg) {
-                       ret = -ENOMEM;
+               rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret);
+               if (!rm->data.op_sg)
                        goto out;
-               }
                ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy);
                if (ret)
                        goto out;
@@ -1270,7 +1300,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
        rm->m_conn_path = cpath;
 
        /* Parse any control messages the user may have included. */
-       ret = rds_cmsg_send(rs, rm, msg, &allocated_mr);
+       ret = rds_cmsg_send(rs, rm, msg, &allocated_mr, &vct);
        if (ret) {
                /* Trigger connection so that its ready for the next retry */
                if (ret ==  -EAGAIN)
@@ -1348,9 +1378,18 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
        if (ret)
                goto out;
        rds_message_put(rm);
+
+       for (ind = 0; ind < vct.indx; ind++)
+               kfree(vct.vec[ind].iov);
+       kfree(vct.vec);
+
        return payload_len;
 
 out:
+       for (ind = 0; ind < vct.indx; ind++)
+               kfree(vct.vec[ind].iov);
+       kfree(vct.vec);
+
        /* If the user included a RDMA_MAP cmsg, we allocated a MR on the fly.
         * If the sendmsg goes through, we keep the MR. If it fails with EAGAIN
         * or in any other way, we need to destroy the MR again */
index 71312d7bd8f490c9b8200ccaac59ea0cd0031da6..208d940464d7b45665d7e6224775ff2f44544c27 100644 (file)
@@ -1258,10 +1258,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
                fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
 
        if (fold) {
-               if (!tc_skip_sw(fold->flags))
-                       rhashtable_remove_fast(&fold->mask->ht,
-                                              &fold->ht_node,
-                                              fold->mask->filter_ht_params);
+               rhashtable_remove_fast(&fold->mask->ht,
+                                      &fold->ht_node,
+                                      fold->mask->filter_ht_params);
                if (!tc_skip_hw(fold->flags))
                        fl_hw_destroy_filter(tp, fold, NULL);
        }
index fc6c5e4bffa540069f70cf33bda2942d7143fcd4..7f0539db56047919dbb79d32bafdfb513305b4a3 100644 (file)
@@ -101,6 +101,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
+                       addr->a.v6.sin6_flowinfo = 0;
                        addr->a.v6.sin6_addr = ifa->addr;
                        addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
                        addr->valid = 1;
index 5fbaf1901571cd2e41a65773ac2f3dc7fa80525d..82cb0e5634bc76ca4f3be1019e3f517591d74be3 100644 (file)
@@ -147,8 +147,14 @@ static int smc_release(struct socket *sock)
                sk->sk_shutdown |= SHUTDOWN_MASK;
        }
        if (smc->clcsock) {
+               if (smc->use_fallback && sk->sk_state == SMC_LISTEN) {
+                       /* wake up clcsock accept */
+                       rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
+               }
+               mutex_lock(&smc->clcsock_release_lock);
                sock_release(smc->clcsock);
                smc->clcsock = NULL;
+               mutex_unlock(&smc->clcsock_release_lock);
        }
        if (smc->use_fallback) {
                if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)
@@ -205,6 +211,7 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
        spin_lock_init(&smc->conn.send_lock);
        sk->sk_prot->hash(sk);
        sk_refcnt_debug_inc(sk);
+       mutex_init(&smc->clcsock_release_lock);
 
        return sk;
 }
@@ -821,7 +828,7 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
        struct socket *new_clcsock = NULL;
        struct sock *lsk = &lsmc->sk;
        struct sock *new_sk;
-       int rc;
+       int rc = -EINVAL;
 
        release_sock(lsk);
        new_sk = smc_sock_alloc(sock_net(lsk), NULL, lsk->sk_protocol);
@@ -834,7 +841,10 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
        }
        *new_smc = smc_sk(new_sk);
 
-       rc = kernel_accept(lsmc->clcsock, &new_clcsock, 0);
+       mutex_lock(&lsmc->clcsock_release_lock);
+       if (lsmc->clcsock)
+               rc = kernel_accept(lsmc->clcsock, &new_clcsock, 0);
+       mutex_unlock(&lsmc->clcsock_release_lock);
        lock_sock(lsk);
        if  (rc < 0)
                lsk->sk_err = -rc;
index 08786ace6010028aae9f946e4b72378c3ad9181c..5721416d060534ff294be6db270e699fd942ba7f 100644 (file)
@@ -219,6 +219,10 @@ struct smc_sock {                          /* smc sock container */
                                                 * started, waiting for unsent
                                                 * data to be sent
                                                 */
+       struct mutex            clcsock_release_lock;
+                                               /* protects clcsock of a listen
+                                                * socket
+                                                * */
 };
 
 static inline struct smc_sock *smc_sk(const struct sock *sk)
index c6782aa475257bb510402a2172c8d4f55706a79a..24cbddc44c884ce6fa9a4ba51a7e85c30953edd2 100644 (file)
@@ -1952,6 +1952,7 @@ call_connect_status(struct rpc_task *task)
                /* retry with existing socket, after a delay */
                rpc_delay(task, 3*HZ);
                /* fall through */
+       case -ENOTCONN:
        case -EAGAIN:
                /* Check for timeouts before looping back to call_bind */
        case -ETIMEDOUT:
index ce927002862a675a9f1169d12fbeb6999984a1c6..73547d17d3c61a844c860c33acaff5259c81d54e 100644 (file)
@@ -67,7 +67,6 @@
  */
 static void     xprt_init(struct rpc_xprt *xprt, struct net *net);
 static __be32  xprt_alloc_xid(struct rpc_xprt *xprt);
-static void    xprt_connect_status(struct rpc_task *task);
 static void     xprt_destroy(struct rpc_xprt *xprt);
 
 static DEFINE_SPINLOCK(xprt_list_lock);
@@ -680,7 +679,9 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
        /* Try to schedule an autoclose RPC call */
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
                queue_work(xprtiod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -EAGAIN);
+       else if (xprt->snd_task)
+               rpc_wake_up_queued_task_set_status(&xprt->pending,
+                               xprt->snd_task, -ENOTCONN);
        spin_unlock_bh(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_force_disconnect);
@@ -820,7 +821,7 @@ void xprt_connect(struct rpc_task *task)
        if (!xprt_connected(xprt)) {
                task->tk_timeout = task->tk_rqstp->rq_timeout;
                task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie;
-               rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
+               rpc_sleep_on(&xprt->pending, task, NULL);
 
                if (test_bit(XPRT_CLOSING, &xprt->state))
                        return;
@@ -839,34 +840,6 @@ void xprt_connect(struct rpc_task *task)
        xprt_release_write(xprt, task);
 }
 
-static void xprt_connect_status(struct rpc_task *task)
-{
-       switch (task->tk_status) {
-       case 0:
-               dprintk("RPC: %5u xprt_connect_status: connection established\n",
-                               task->tk_pid);
-               break;
-       case -ECONNREFUSED:
-       case -ECONNRESET:
-       case -ECONNABORTED:
-       case -ENETUNREACH:
-       case -EHOSTUNREACH:
-       case -EPIPE:
-       case -EAGAIN:
-               dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
-               break;
-       case -ETIMEDOUT:
-               dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
-                               "out\n", task->tk_pid);
-               break;
-       default:
-               dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
-                               "server %s\n", task->tk_pid, -task->tk_status,
-                               task->tk_rqstp->rq_xprt->servername);
-               task->tk_status = -EIO;
-       }
-}
-
 enum xprt_xid_rb_cmp {
        XID_RB_EQUAL,
        XID_RB_LEFT,
index 8a5e823e0b339b1998ff21b9cac814de213a2b23..f0b3700cec95e8f0ccf9eac212b47158877066ab 100644 (file)
@@ -1217,6 +1217,8 @@ static void xs_reset_transport(struct sock_xprt *transport)
 
        trace_rpc_socket_close(xprt, sock);
        sock_release(sock);
+
+       xprt_disconnect_done(xprt);
 }
 
 /**
@@ -1237,8 +1239,6 @@ static void xs_close(struct rpc_xprt *xprt)
 
        xs_reset_transport(transport);
        xprt->reestablish_timeout = 0;
-
-       xprt_disconnect_done(xprt);
 }
 
 static void xs_inject_disconnect(struct rpc_xprt *xprt)
@@ -1489,8 +1489,6 @@ static void xs_tcp_state_change(struct sock *sk)
                                        &transport->sock_state))
                        xprt_clear_connecting(xprt);
                clear_bit(XPRT_CLOSING, &xprt->state);
-               if (sk->sk_err)
-                       xprt_wake_pending_tasks(xprt, -sk->sk_err);
                /* Trigger the socket release */
                xs_tcp_force_close(xprt);
        }
@@ -2092,8 +2090,8 @@ static void xs_udp_setup_socket(struct work_struct *work)
        trace_rpc_socket_connect(xprt, sock, 0);
        status = 0;
 out:
-       xprt_unlock_connect(xprt, transport);
        xprt_clear_connecting(xprt);
+       xprt_unlock_connect(xprt, transport);
        xprt_wake_pending_tasks(xprt, status);
 }
 
@@ -2329,8 +2327,8 @@ static void xs_tcp_setup_socket(struct work_struct *work)
        }
        status = -EAGAIN;
 out:
-       xprt_unlock_connect(xprt, transport);
        xprt_clear_connecting(xprt);
+       xprt_unlock_connect(xprt, transport);
        xprt_wake_pending_tasks(xprt, status);
 }
 
index b57b1be7252baef2f6410710e225864877c08ac1..8f34db2a97857bbdf0b3fc9bf33353a6e1740912 100644 (file)
@@ -880,7 +880,6 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        int blks = tsk_blocks(GROUP_H_SIZE + dlen);
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_group *grp = tsk->group;
        struct net *net = sock_net(sk);
        struct tipc_member *mb = NULL;
        u32 node, port;
@@ -894,7 +893,9 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,
        /* Block or return if destination link or member is congested */
        rc = tipc_wait_for_cond(sock, &timeout,
                                !tipc_dest_find(&tsk->cong_links, node, 0) &&
-                               !tipc_group_cong(grp, node, port, blks, &mb));
+                               tsk->group &&
+                               !tipc_group_cong(tsk->group, node, port, blks,
+                                                &mb));
        if (unlikely(rc))
                return rc;
 
@@ -924,7 +925,6 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
        struct tipc_sock *tsk = tipc_sk(sk);
        struct list_head *cong_links = &tsk->cong_links;
        int blks = tsk_blocks(GROUP_H_SIZE + dlen);
-       struct tipc_group *grp = tsk->group;
        struct tipc_msg *hdr = &tsk->phdr;
        struct tipc_member *first = NULL;
        struct tipc_member *mbr = NULL;
@@ -941,9 +941,10 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
        type = msg_nametype(hdr);
        inst = dest->addr.name.name.instance;
        scope = msg_lookup_scope(hdr);
-       exclude = tipc_group_exclude(grp);
 
        while (++lookups < 4) {
+               exclude = tipc_group_exclude(tsk->group);
+
                first = NULL;
 
                /* Look for a non-congested destination member, if any */
@@ -952,7 +953,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
                                                 &dstcnt, exclude, false))
                                return -EHOSTUNREACH;
                        tipc_dest_pop(&dsts, &node, &port);
-                       cong = tipc_group_cong(grp, node, port, blks, &mbr);
+                       cong = tipc_group_cong(tsk->group, node, port, blks,
+                                              &mbr);
                        if (!cong)
                                break;
                        if (mbr == first)
@@ -971,7 +973,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
                /* Block or return if destination link or member is congested */
                rc = tipc_wait_for_cond(sock, &timeout,
                                        !tipc_dest_find(cong_links, node, 0) &&
-                                       !tipc_group_cong(grp, node, port,
+                                       tsk->group &&
+                                       !tipc_group_cong(tsk->group, node, port,
                                                         blks, &mbr));
                if (unlikely(rc))
                        return rc;
@@ -1006,8 +1009,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,
        struct sock *sk = sock->sk;
        struct net *net = sock_net(sk);
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_group *grp = tsk->group;
-       struct tipc_nlist *dsts = tipc_group_dests(grp);
+       struct tipc_nlist *dsts;
        struct tipc_mc_method *method = &tsk->mc_method;
        bool ack = method->mandatory && method->rcast;
        int blks = tsk_blocks(MCAST_H_SIZE + dlen);
@@ -1016,15 +1018,17 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,
        struct sk_buff_head pkts;
        int rc = -EHOSTUNREACH;
 
-       if (!dsts->local && !dsts->remote)
-               return -EHOSTUNREACH;
-
        /* Block or return if any destination link or member is congested */
-       rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt &&
-                               !tipc_group_bc_cong(grp, blks));
+       rc = tipc_wait_for_cond(sock, &timeout,
+                               !tsk->cong_link_cnt && tsk->group &&
+                               !tipc_group_bc_cong(tsk->group, blks));
        if (unlikely(rc))
                return rc;
 
+       dsts = tipc_group_dests(tsk->group);
+       if (!dsts->local && !dsts->remote)
+               return -EHOSTUNREACH;
+
        /* Complete message header */
        if (dest) {
                msg_set_type(hdr, TIPC_GRP_MCAST_MSG);
@@ -1036,7 +1040,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,
        msg_set_hdr_sz(hdr, GROUP_H_SIZE);
        msg_set_destport(hdr, 0);
        msg_set_destnode(hdr, 0);
-       msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(grp));
+       msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(tsk->group));
 
        /* Avoid getting stuck with repeated forced replicasts */
        msg_set_grp_bc_ack_req(hdr, ack);
@@ -2724,11 +2728,15 @@ void tipc_sk_reinit(struct net *net)
                rhashtable_walk_start(&iter);
 
                while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) {
-                       spin_lock_bh(&tsk->sk.sk_lock.slock);
+                       sock_hold(&tsk->sk);
+                       rhashtable_walk_stop(&iter);
+                       lock_sock(&tsk->sk);
                        msg = &tsk->phdr;
                        msg_set_prevnode(msg, tipc_own_addr(net));
                        msg_set_orignode(msg, tipc_own_addr(net));
-                       spin_unlock_bh(&tsk->sk.sk_lock.slock);
+                       release_sock(&tsk->sk);
+                       rhashtable_walk_start(&iter);
+                       sock_put(&tsk->sk);
                }
 
                rhashtable_walk_stop(&iter);
index 10dc59ce9c8221abbe0edce624d59bd0cf758d69..4d85d71f16e2abcee0f2abd84020f9b471f3e8fa 100644 (file)
@@ -245,10 +245,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
                }
 
                err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr);
-               if (err) {
-                       kfree_skb(_skb);
+               if (err)
                        goto out;
-               }
        }
        err = 0;
 out:
@@ -681,6 +679,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
        if (err)
                goto err;
 
+       if (remote.proto != local.proto) {
+               err = -EINVAL;
+               goto err;
+       }
+
        /* Checking remote ip address */
        rmcast = tipc_udp_is_mcast_addr(&remote);
 
index 311cec8e533dee755fc452977b4955e59893c13a..28887cf628b82321d2eab5bea38f9994d82d3fef 100644 (file)
@@ -56,7 +56,7 @@ enum {
 static struct proto *saved_tcpv6_prot;
 static DEFINE_MUTEX(tcpv6_prot_mutex);
 static LIST_HEAD(device_list);
-static DEFINE_MUTEX(device_mutex);
+static DEFINE_SPINLOCK(device_spinlock);
 static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
 static struct proto_ops tls_sw_proto_ops;
 
@@ -538,11 +538,14 @@ static struct tls_context *create_ctx(struct sock *sk)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tls_context *ctx;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
        if (!ctx)
                return NULL;
 
        icsk->icsk_ulp_data = ctx;
+       ctx->setsockopt = sk->sk_prot->setsockopt;
+       ctx->getsockopt = sk->sk_prot->getsockopt;
+       ctx->sk_proto_close = sk->sk_prot->close;
        return ctx;
 }
 
@@ -552,7 +555,7 @@ static int tls_hw_prot(struct sock *sk)
        struct tls_device *dev;
        int rc = 0;
 
-       mutex_lock(&device_mutex);
+       spin_lock_bh(&device_spinlock);
        list_for_each_entry(dev, &device_list, dev_list) {
                if (dev->feature && dev->feature(dev)) {
                        ctx = create_ctx(sk);
@@ -570,7 +573,7 @@ static int tls_hw_prot(struct sock *sk)
                }
        }
 out:
-       mutex_unlock(&device_mutex);
+       spin_unlock_bh(&device_spinlock);
        return rc;
 }
 
@@ -579,12 +582,17 @@ static void tls_hw_unhash(struct sock *sk)
        struct tls_context *ctx = tls_get_ctx(sk);
        struct tls_device *dev;
 
-       mutex_lock(&device_mutex);
+       spin_lock_bh(&device_spinlock);
        list_for_each_entry(dev, &device_list, dev_list) {
-               if (dev->unhash)
+               if (dev->unhash) {
+                       kref_get(&dev->kref);
+                       spin_unlock_bh(&device_spinlock);
                        dev->unhash(dev, sk);
+                       kref_put(&dev->kref, dev->release);
+                       spin_lock_bh(&device_spinlock);
+               }
        }
-       mutex_unlock(&device_mutex);
+       spin_unlock_bh(&device_spinlock);
        ctx->unhash(sk);
 }
 
@@ -595,12 +603,17 @@ static int tls_hw_hash(struct sock *sk)
        int err;
 
        err = ctx->hash(sk);
-       mutex_lock(&device_mutex);
+       spin_lock_bh(&device_spinlock);
        list_for_each_entry(dev, &device_list, dev_list) {
-               if (dev->hash)
+               if (dev->hash) {
+                       kref_get(&dev->kref);
+                       spin_unlock_bh(&device_spinlock);
                        err |= dev->hash(dev, sk);
+                       kref_put(&dev->kref, dev->release);
+                       spin_lock_bh(&device_spinlock);
+               }
        }
-       mutex_unlock(&device_mutex);
+       spin_unlock_bh(&device_spinlock);
 
        if (err)
                tls_hw_unhash(sk);
@@ -675,9 +688,6 @@ static int tls_init(struct sock *sk)
                rc = -ENOMEM;
                goto out;
        }
-       ctx->setsockopt = sk->sk_prot->setsockopt;
-       ctx->getsockopt = sk->sk_prot->getsockopt;
-       ctx->sk_proto_close = sk->sk_prot->close;
 
        /* Build IPv6 TLS whenever the address of tcpv6 _prot changes */
        if (ip_ver == TLSV6 &&
@@ -699,17 +709,17 @@ out:
 
 void tls_register_device(struct tls_device *device)
 {
-       mutex_lock(&device_mutex);
+       spin_lock_bh(&device_spinlock);
        list_add_tail(&device->dev_list, &device_list);
-       mutex_unlock(&device_mutex);
+       spin_unlock_bh(&device_spinlock);
 }
 EXPORT_SYMBOL(tls_register_device);
 
 void tls_unregister_device(struct tls_device *device)
 {
-       mutex_lock(&device_mutex);
+       spin_lock_bh(&device_spinlock);
        list_del(&device->dev_list);
-       mutex_unlock(&device_mutex);
+       spin_unlock_bh(&device_spinlock);
 }
 EXPORT_SYMBOL(tls_unregister_device);
 
index 7b1af8b59cd20e56841c437aa97d981fa89be864..29b27858fff10e2ec7a45b5a5f40841223e93ded 100644 (file)
@@ -935,10 +935,12 @@ fallback_to_reg_send:
                                    tls_ctx->tx.overhead_size);
                }
 
-               ret = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, msg_pl,
-                                              try_to_copy);
-               if (ret < 0)
-                       goto trim_sgl;
+               if (try_to_copy) {
+                       ret = sk_msg_memcopy_from_iter(sk, &msg->msg_iter,
+                                                      msg_pl, try_to_copy);
+                       if (ret < 0)
+                               goto trim_sgl;
+               }
 
                /* Open records defined only if successfully copied, otherwise
                 * we would trim the sg but not reset the open record frags.
index ab27a2872935774d41fb1f2c2f9341eb67c8cc0a..43a1dec08825fe824395851a2e81b8cf18f0f518 100644 (file)
 #include <linux/mutex.h>
 #include <linux/net.h>
 #include <linux/poll.h>
+#include <linux/random.h>
 #include <linux/skbuff.h>
 #include <linux/smp.h>
 #include <linux/socket.h>
@@ -504,9 +505,13 @@ out:
 static int __vsock_bind_stream(struct vsock_sock *vsk,
                               struct sockaddr_vm *addr)
 {
-       static u32 port = LAST_RESERVED_PORT + 1;
+       static u32 port = 0;
        struct sockaddr_vm new_addr;
 
+       if (!port)
+               port = LAST_RESERVED_PORT + 1 +
+                       prandom_u32_max(U32_MAX - LAST_RESERVED_PORT);
+
        vsock_addr_init(&new_addr, addr->svm_cid, addr->svm_port);
 
        if (addr->svm_port == VMADDR_PORT_ANY) {
index cb332adb84cdcadc006de6d7a8668111babd2f53..c361ce7824123da38ec613361a2ae5fa21197b7b 100644 (file)
@@ -263,6 +263,31 @@ vmci_transport_send_control_pkt_bh(struct sockaddr_vm *src,
                                                 false);
 }
 
+static int
+vmci_transport_alloc_send_control_pkt(struct sockaddr_vm *src,
+                                     struct sockaddr_vm *dst,
+                                     enum vmci_transport_packet_type type,
+                                     u64 size,
+                                     u64 mode,
+                                     struct vmci_transport_waiting_info *wait,
+                                     u16 proto,
+                                     struct vmci_handle handle)
+{
+       struct vmci_transport_packet *pkt;
+       int err;
+
+       pkt = kmalloc(sizeof(*pkt), GFP_KERNEL);
+       if (!pkt)
+               return -ENOMEM;
+
+       err = __vmci_transport_send_control_pkt(pkt, src, dst, type, size,
+                                               mode, wait, proto, handle,
+                                               true);
+       kfree(pkt);
+
+       return err;
+}
+
 static int
 vmci_transport_send_control_pkt(struct sock *sk,
                                enum vmci_transport_packet_type type,
@@ -272,9 +297,7 @@ vmci_transport_send_control_pkt(struct sock *sk,
                                u16 proto,
                                struct vmci_handle handle)
 {
-       struct vmci_transport_packet *pkt;
        struct vsock_sock *vsk;
-       int err;
 
        vsk = vsock_sk(sk);
 
@@ -284,17 +307,10 @@ vmci_transport_send_control_pkt(struct sock *sk,
        if (!vsock_addr_bound(&vsk->remote_addr))
                return -EINVAL;
 
-       pkt = kmalloc(sizeof(*pkt), GFP_KERNEL);
-       if (!pkt)
-               return -ENOMEM;
-
-       err = __vmci_transport_send_control_pkt(pkt, &vsk->local_addr,
-                                               &vsk->remote_addr, type, size,
-                                               mode, wait, proto, handle,
-                                               true);
-       kfree(pkt);
-
-       return err;
+       return vmci_transport_alloc_send_control_pkt(&vsk->local_addr,
+                                                    &vsk->remote_addr,
+                                                    type, size, mode,
+                                                    wait, proto, handle);
 }
 
 static int vmci_transport_send_reset_bh(struct sockaddr_vm *dst,
@@ -312,12 +328,29 @@ static int vmci_transport_send_reset_bh(struct sockaddr_vm *dst,
 static int vmci_transport_send_reset(struct sock *sk,
                                     struct vmci_transport_packet *pkt)
 {
+       struct sockaddr_vm *dst_ptr;
+       struct sockaddr_vm dst;
+       struct vsock_sock *vsk;
+
        if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_RST)
                return 0;
-       return vmci_transport_send_control_pkt(sk,
-                                       VMCI_TRANSPORT_PACKET_TYPE_RST,
-                                       0, 0, NULL, VSOCK_PROTO_INVALID,
-                                       VMCI_INVALID_HANDLE);
+
+       vsk = vsock_sk(sk);
+
+       if (!vsock_addr_bound(&vsk->local_addr))
+               return -EINVAL;
+
+       if (vsock_addr_bound(&vsk->remote_addr)) {
+               dst_ptr = &vsk->remote_addr;
+       } else {
+               vsock_addr_init(&dst, pkt->dg.src.context,
+                               pkt->src_port);
+               dst_ptr = &dst;
+       }
+       return vmci_transport_alloc_send_control_pkt(&vsk->local_addr, dst_ptr,
+                                            VMCI_TRANSPORT_PACKET_TYPE_RST,
+                                            0, 0, NULL, VSOCK_PROTO_INVALID,
+                                            VMCI_INVALID_HANDLE);
 }
 
 static int vmci_transport_send_negotiate(struct sock *sk, size_t size)
index 8d763725498c15fc7474f5ca78802233800ee4c5..2317727d64134ffe98f8930eb02359d69834d4ac 100644 (file)
@@ -8930,8 +8930,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
                int r = validate_pae_over_nl80211(rdev, info);
 
-               if (r < 0)
+               if (r < 0) {
+                       kzfree(connkeys);
                        return r;
+               }
 
                ibss.control_port_over_nl80211 = true;
        }
index 684c0bc01e2c12ce5ef61195030fbad2cd26fc02..d5635908587f4de80396831f24cdf7591522f511 100644 (file)
@@ -346,6 +346,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
                skb->sp->xvec[skb->sp->len++] = x;
 
+               skb_dst_force(skb);
+               if (!skb_dst(skb)) {
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
+                       goto drop;
+               }
+
 lock:
                spin_lock(&x->lock);
 
@@ -385,7 +391,6 @@ lock:
                XFRM_SKB_CB(skb)->seq.input.low = seq;
                XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
 
-               skb_dst_force(skb);
                dev_hold(skb->dev);
 
                if (crypto_done)
index 4ae87c5ce2e357b420aaa102bdbb416e7039f90a..fef6b2da3c5d7fadd06f466f9ee1cdf3909a5809 100644 (file)
@@ -102,6 +102,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
                skb_dst_force(skb);
                if (!skb_dst(skb)) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+                       err = -EHOSTUNREACH;
                        goto error_nolock;
                }
 
index dc4a9f1fb941a8eef7f1a3b68563c17abcf4d919..23c92891758a829e06dd776baf7ca340dec67b9f 100644 (file)
@@ -426,6 +426,12 @@ static void xfrm_put_mode(struct xfrm_mode *mode)
        module_put(mode->owner);
 }
 
+void xfrm_state_free(struct xfrm_state *x)
+{
+       kmem_cache_free(xfrm_state_cache, x);
+}
+EXPORT_SYMBOL(xfrm_state_free);
+
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
        tasklet_hrtimer_cancel(&x->mtimer);
@@ -452,7 +458,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
        }
        xfrm_dev_state_free(x);
        security_xfrm_state_free(x);
-       kmem_cache_free(xfrm_state_cache, x);
+       xfrm_state_free(x);
 }
 
 static void xfrm_state_gc_task(struct work_struct *work)
@@ -788,7 +794,7 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
 {
        spin_lock_bh(&net->xfrm.xfrm_state_lock);
        si->sadcnt = net->xfrm.state_num;
-       si->sadhcnt = net->xfrm.state_hmask;
+       si->sadhcnt = net->xfrm.state_hmask + 1;
        si->sadhmcnt = xfrm_state_hashmax;
        spin_unlock_bh(&net->xfrm.xfrm_state_lock);
 }
index c9a84e22f5d578216cd59687e293ed3a078cd565..277c1c46fe94e17db85f20a4abe3bacae9a1f1b0 100644 (file)
@@ -2288,13 +2288,13 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        }
 
-       kfree(x);
+       xfrm_state_free(x);
        kfree(xp);
 
        return 0;
 
 free_state:
-       kfree(x);
+       xfrm_state_free(x);
 nomem:
        return err;
 }
index f520e3aef9c64802114d92020a4afcd03c43f380..27ec30952cfab96368e61fad8b9ab20d5cd12fae 100644 (file)
@@ -80,13 +80,13 @@ struct skeleton {
 };
 
 struct skel_buffer {
-       struct vb2_buffer vb;
+       struct vb2_v4l2_buffer vb;
        struct list_head list;
 };
 
-static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2)
+static inline struct skel_buffer *to_skel_buffer(struct vb2_v4l2_buffer *vbuf)
 {
-       return container_of(vb2, struct skel_buffer, vb);
+       return container_of(vbuf, struct skel_buffer, vb);
 }
 
 static const struct pci_device_id skeleton_pci_tbl[] = {
@@ -212,8 +212,9 @@ static int buffer_prepare(struct vb2_buffer *vb)
  */
 static void buffer_queue(struct vb2_buffer *vb)
 {
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);
-       struct skel_buffer *buf = to_skel_buffer(vb);
+       struct skel_buffer *buf = to_skel_buffer(vbuf);
        unsigned long flags;
 
        spin_lock_irqsave(&skel->qlock, flags);
@@ -232,7 +233,7 @@ static void return_all_buffers(struct skeleton *skel,
 
        spin_lock_irqsave(&skel->qlock, flags);
        list_for_each_entry_safe(buf, node, &skel->buf_list, list) {
-               vb2_buffer_done(&buf->vb, state);
+               vb2_buffer_done(&buf->vb.vb2_buf, state);
                list_del(&buf->list);
        }
        spin_unlock_irqrestore(&skel->qlock, flags);
index bb015551c2d9ae11c67f276cc64d7f84ef5521fc..3d09844405c923c2d1a7fa04d6e1c15b6567180d 100644 (file)
@@ -115,9 +115,7 @@ __cc-option = $(call try-run,\
 
 # Do not attempt to build with gcc plugins during cc-option tests.
 # (And this uses delayed resolution so the flags will be up to date.)
-# In addition, do not include the asm macros which are built later.
-CC_OPTION_FILTERED = $(GCC_PLUGINS_CFLAGS) $(ASM_MACRO_FLAGS)
-CC_OPTION_CFLAGS = $(filter-out $(CC_OPTION_FILTERED),$(KBUILD_CFLAGS))
+CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))
 
 # cc-option
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
diff --git a/scripts/coccinelle/api/drm-get-put.cocci b/scripts/coccinelle/api/drm-get-put.cocci
deleted file mode 100644 (file)
index 3a09c97..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-///
-/// Use drm_*_get() and drm_*_put() helpers instead of drm_*_reference() and
-/// drm_*_unreference() helpers.
-///
-// Confidence: High
-// Copyright: (C) 2017 NVIDIA Corporation
-// Options: --no-includes --include-headers
-//
-
-virtual patch
-virtual report
-
-@depends on patch@
-expression object;
-@@
-
-(
-- drm_connector_reference(object)
-+ drm_connector_get(object)
-|
-- drm_connector_unreference(object)
-+ drm_connector_put(object)
-|
-- drm_framebuffer_reference(object)
-+ drm_framebuffer_get(object)
-|
-- drm_framebuffer_unreference(object)
-+ drm_framebuffer_put(object)
-|
-- drm_gem_object_reference(object)
-+ drm_gem_object_get(object)
-|
-- drm_gem_object_unreference(object)
-+ drm_gem_object_put(object)
-|
-- __drm_gem_object_unreference(object)
-+ __drm_gem_object_put(object)
-|
-- drm_gem_object_unreference_unlocked(object)
-+ drm_gem_object_put_unlocked(object)
-|
-- drm_dev_unref(object)
-+ drm_dev_put(object)
-)
-
-@r depends on report@
-expression object;
-position p;
-@@
-
-(
-drm_connector_unreference@p(object)
-|
-drm_connector_reference@p(object)
-|
-drm_framebuffer_unreference@p(object)
-|
-drm_framebuffer_reference@p(object)
-|
-drm_gem_object_unreference@p(object)
-|
-drm_gem_object_reference@p(object)
-|
-__drm_gem_object_unreference(object)
-|
-drm_gem_object_unreference_unlocked(object)
-|
-drm_dev_unref@p(object)
-)
-
-@script:python depends on report@
-object << r.object;
-p << r.p;
-@@
-
-msg="WARNING: use get/put helpers to reference and dereference %s" % (object)
-coccilib.report.print_report(p[0], msg)
index a5b4af47987a7ab84af40d84d5b8b84f48973068..42c5d50f2bccf1d3ed8de3366526ae8279c31eb9 100644 (file)
@@ -4,8 +4,6 @@ OBJECT_FILES_NON_STANDARD := y
 hostprogs-y    := modpost mk_elfconfig
 always         := $(hostprogs-y) empty.o
 
-CFLAGS_REMOVE_empty.o := $(ASM_MACRO_FLAGS)
-
 modpost-objs   := modpost.o file2alias.o sumversion.o
 
 devicetable-offsets-file := devicetable-offsets.h
index 8c9499867c918bb163946679f0e0d7f57fad5dfa..7489cb7de6dc9ff5c1caaa83c1574a8a713ecfd5 100644 (file)
@@ -580,9 +580,9 @@ void ima_update_policy(void)
        ima_update_policy_flag();
 }
 
+/* Keep the enumeration in sync with the policy_tokens! */
 enum {
-       Opt_err = -1,
-       Opt_measure = 1, Opt_dont_measure,
+       Opt_measure, Opt_dont_measure,
        Opt_appraise, Opt_dont_appraise,
        Opt_audit, Opt_hash, Opt_dont_hash,
        Opt_obj_user, Opt_obj_role, Opt_obj_type,
@@ -592,10 +592,10 @@ enum {
        Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
        Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
        Opt_appraise_type, Opt_permit_directio,
-       Opt_pcr
+       Opt_pcr, Opt_err
 };
 
-static match_table_t policy_tokens = {
+static const match_table_t policy_tokens = {
        {Opt_measure, "measure"},
        {Opt_dont_measure, "dont_measure"},
        {Opt_appraise, "appraise"},
@@ -1103,7 +1103,7 @@ void ima_policy_stop(struct seq_file *m, void *v)
 {
 }
 
-#define pt(token)      policy_tokens[token + Opt_err].pattern
+#define pt(token)      policy_tokens[token].pattern
 #define mt(token)      mask_tokens[token]
 
 /*
index 783978842f13a78805718015f1442bc61ca1b9ca..70e65a2ff2073a5d65cd20fb07b5accce4684955 100644 (file)
@@ -25,7 +25,7 @@ static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
 }
 
 enum {
-       Opt_err = -1,
+       Opt_err,
        Opt_enc,                /* "enc=<encoding>" eg. "enc=oaep" */
        Opt_hash,               /* "hash=<digest-name>" eg. "hash=sha1" */
 };
index ff6789365a12fb15ed91e160ba2936262ec5c29c..697bfc6c819236c39b828fc786cd6d08ff7bd592 100644 (file)
@@ -711,7 +711,7 @@ static int key_unseal(struct trusted_key_payload *p,
 }
 
 enum {
-       Opt_err = -1,
+       Opt_err,
        Opt_new, Opt_load, Opt_update,
        Opt_keyhandle, Opt_keyauth, Opt_blobauth,
        Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
index 1eddf8fa188f1c619fbeaf271f100240ac687a76..8797d42e2b76285f7da87a8000517fb943cd5e61 100644 (file)
@@ -776,7 +776,7 @@ static int check_codec(struct aoa_codec *codec,
        struct codec_connection *cc;
 
        /* if the codec has a 'codec' node, we require a reference */
-       if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
+       if (of_node_name_eq(codec->node, "codec")) {
                snprintf(propname, sizeof(propname),
                         "platform-%s-codec-ref", codec->name);
                ref = of_get_property(ldev->sound, propname, NULL);
@@ -1008,8 +1008,8 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
                return -ENODEV;
 
        /* by breaking out we keep a reference */
-       while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) {
-               if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
+       for_each_child_of_node(sdev->ofdev.dev.of_node, sound) {
+               if (of_node_is_type(sound, "soundchip"))
                        break;
        }
        if (!sound)
index 70bcaa7f93ddc1ee5bfe719446449d29510abee4..065d3a55725edf3aa42fdfaed1667ba712c149c0 100644 (file)
@@ -74,11 +74,11 @@ static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
        of = &soundbus_dev->ofdev;
 
        /* stuff we want to pass to /sbin/hotplug */
-       retval = add_uevent_var(env, "OF_NAME=%s", of->dev.of_node->name);
+       retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
        if (retval)
                return retval;
 
-       retval = add_uevent_var(env, "OF_TYPE=%s", of->dev.of_node->type);
+       retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
        if (retval)
                return retval;
 
index bd7c5029fc59300ec3432d94543aa2b027f28fa8..c3f57a3fb1a533218144cd76930e1161e1f529bf 100644 (file)
@@ -154,7 +154,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
                          struct device_node *np)
 {
        struct i2sbus_dev *dev;
-       struct device_node *child = NULL, *sound = NULL;
+       struct device_node *child, *sound = NULL;
        struct resource *r;
        int i, layout = 0, rlen, ok = force;
        char node_name[6];
@@ -177,8 +177,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
                return 0;
 
        i = 0;
-       while ((child = of_get_next_child(np, child))) {
-               if (strcmp(child->name, "sound") == 0) {
+       for_each_child_of_node(np, child) {
+               if (of_node_name_eq(child, "sound")) {
                        i++;
                        sound = child;
                }
index 81da020bddef6ddbfc2d056361302bb36233f0fd..a2d55e15afbb8a6754fab387bae16cc7be064beb 100644 (file)
@@ -1,18 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/stat.h>
 /* FIX UP */
 #include "soundbus.h"
 
-#define soundbus_config_of_attr(field, format_string)                  \
-static ssize_t                                                         \
-field##_show (struct device *dev, struct device_attribute *attr,       \
-              char *buf)                                               \
-{                                                                      \
-       struct soundbus_dev *mdev = to_soundbus_device (dev);           \
-       return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
-}
-
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -25,17 +17,33 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                strcat(buf, "\n");
                length = strlen(buf);
        } else {
-               length = sprintf(buf, "of:N%sT%s\n",
-                                of->dev.of_node->name, of->dev.of_node->type);
+               length = sprintf(buf, "of:N%pOFn%c%s\n",
+                                of->dev.of_node, 'T',
+                                 of_node_get_device_type(of->dev.of_node));
        }
 
        return length;
 }
 static DEVICE_ATTR_RO(modalias);
 
-soundbus_config_of_attr (name, "%s\n");
+static ssize_t name_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct soundbus_dev *sdev = to_soundbus_device(dev);
+       struct platform_device *of = &sdev->ofdev;
+
+       return sprintf(buf, "%pOFn\n", of->dev.of_node);
+}
 static DEVICE_ATTR_RO(name);
-soundbus_config_of_attr (type, "%s\n");
+
+static ssize_t type_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct soundbus_dev *sdev = to_soundbus_device(dev);
+       struct platform_device *of = &sdev->ofdev;
+
+       return sprintf(buf, "%s\n", of_node_get_device_type(of->dev.of_node));
+}
 static DEVICE_ATTR_RO(type);
 
 struct attribute *soundbus_dev_attrs[] = {
index 26b5e245b0747dce67fb3c8aad3ca0d5f513a194..a5b09e75e7874bb6a1facc9a9fd70e6fdac10791 100644 (file)
@@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
        }
 
        data->stream.ops->free(&data->stream);
-       kfree(data->stream.runtime->buffer);
+       if (!data->stream.runtime->dma_buffer_p)
+               kfree(data->stream.runtime->buffer);
        kfree(data->stream.runtime);
        kfree(data);
        return 0;
@@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
                struct snd_compr_params *params)
 {
        unsigned int buffer_size;
-       void *buffer;
+       void *buffer = NULL;
 
        buffer_size = params->buffer.fragment_size * params->buffer.fragments;
        if (stream->ops->copy) {
@@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
                 * the data from core
                 */
        } else {
-               buffer = kmalloc(buffer_size, GFP_KERNEL);
+               if (stream->runtime->dma_buffer_p) {
+
+                       if (buffer_size > stream->runtime->dma_buffer_p->bytes)
+                               dev_err(&stream->device->dev,
+                                               "Not enough DMA buffer");
+                       else
+                               buffer = stream->runtime->dma_buffer_p->area;
+
+               } else {
+                       buffer = kmalloc(buffer_size, GFP_KERNEL);
+               }
+
                if (!buffer)
                        return -ENOMEM;
        }
index 649d3217590ed465c6e13e39bdeb2f9e53a4a2e5..fad7db40244341e4d93528953c541de74c62c5c8 100644 (file)
@@ -348,22 +348,41 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
        return 0;
 }
 
-/* add a new kcontrol object; call with card->controls_rwsem locked */
-static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+enum snd_ctl_add_mode {
+       CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
+};
+
+/* add/replace a new kcontrol object; call with card->controls_rwsem locked */
+static int __snd_ctl_add_replace(struct snd_card *card,
+                                struct snd_kcontrol *kcontrol,
+                                enum snd_ctl_add_mode mode)
 {
        struct snd_ctl_elem_id id;
        unsigned int idx;
        unsigned int count;
+       struct snd_kcontrol *old;
+       int err;
 
        id = kcontrol->id;
        if (id.index > UINT_MAX - kcontrol->count)
                return -EINVAL;
 
-       if (snd_ctl_find_id(card, &id)) {
-               dev_err(card->dev,
-                       "control %i:%i:%i:%s:%i is already present\n",
-                       id.iface, id.device, id.subdevice, id.name, id.index);
-               return -EBUSY;
+       old = snd_ctl_find_id(card, &id);
+       if (!old) {
+               if (mode == CTL_REPLACE)
+                       return -EINVAL;
+       } else {
+               if (mode == CTL_ADD_EXCLUSIVE) {
+                       dev_err(card->dev,
+                               "control %i:%i:%i:%s:%i is already present\n",
+                               id.iface, id.device, id.subdevice, id.name,
+                               id.index);
+                       return -EBUSY;
+               }
+
+               err = snd_ctl_remove(card, old);
+               if (err < 0)
+                       return err;
        }
 
        if (snd_ctl_find_hole(card, kcontrol->count) < 0)
@@ -382,21 +401,9 @@ static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
        return 0;
 }
 
-/**
- * snd_ctl_add - add the control instance to the card
- * @card: the card instance
- * @kcontrol: the control instance to add
- *
- * Adds the control instance created via snd_ctl_new() or
- * snd_ctl_new1() to the given card. Assigns also an unique
- * numid used for fast search.
- *
- * It frees automatically the control which cannot be added.
- *
- * Return: Zero if successful, or a negative error code on failure.
- *
- */
-int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+static int snd_ctl_add_replace(struct snd_card *card,
+                              struct snd_kcontrol *kcontrol,
+                              enum snd_ctl_add_mode mode)
 {
        int err = -EINVAL;
 
@@ -406,7 +413,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
                goto error;
 
        down_write(&card->controls_rwsem);
-       err = __snd_ctl_add(card, kcontrol);
+       err = __snd_ctl_add_replace(card, kcontrol, mode);
        up_write(&card->controls_rwsem);
        if (err < 0)
                goto error;
@@ -416,6 +423,25 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
        snd_ctl_free_one(kcontrol);
        return err;
 }
+
+/**
+ * snd_ctl_add - add the control instance to the card
+ * @card: the card instance
+ * @kcontrol: the control instance to add
+ *
+ * Adds the control instance created via snd_ctl_new() or
+ * snd_ctl_new1() to the given card. Assigns also an unique
+ * numid used for fast search.
+ *
+ * It frees automatically the control which cannot be added.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ *
+ */
+int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+{
+       return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE);
+}
 EXPORT_SYMBOL(snd_ctl_add);
 
 /**
@@ -435,53 +461,8 @@ EXPORT_SYMBOL(snd_ctl_add);
 int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
                    bool add_on_replace)
 {
-       struct snd_ctl_elem_id id;
-       unsigned int count;
-       unsigned int idx;
-       struct snd_kcontrol *old;
-       int ret;
-
-       if (!kcontrol)
-               return -EINVAL;
-       if (snd_BUG_ON(!card || !kcontrol->info)) {
-               ret = -EINVAL;
-               goto error;
-       }
-       id = kcontrol->id;
-       down_write(&card->controls_rwsem);
-       old = snd_ctl_find_id(card, &id);
-       if (!old) {
-               if (add_on_replace)
-                       goto add;
-               up_write(&card->controls_rwsem);
-               ret = -EINVAL;
-               goto error;
-       }
-       ret = snd_ctl_remove(card, old);
-       if (ret < 0) {
-               up_write(&card->controls_rwsem);
-               goto error;
-       }
-add:
-       if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
-               up_write(&card->controls_rwsem);
-               ret = -ENOMEM;
-               goto error;
-       }
-       list_add_tail(&kcontrol->list, &card->controls);
-       card->controls_count += kcontrol->count;
-       kcontrol->id.numid = card->last_numid + 1;
-       card->last_numid += kcontrol->count;
-       id = kcontrol->id;
-       count = kcontrol->count;
-       up_write(&card->controls_rwsem);
-       for (idx = 0; idx < count; idx++, id.index++, id.numid++)
-               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
-       return 0;
-
-error:
-       snd_ctl_free_one(kcontrol);
-       return ret;
+       return snd_ctl_add_replace(card, kcontrol,
+                                  add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE);
 }
 EXPORT_SYMBOL(snd_ctl_replace);
 
@@ -1369,7 +1350,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
 
        /* This function manage to free the instance on failure. */
        down_write(&card->controls_rwsem);
-       err = __snd_ctl_add(card, kctl);
+       err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
        if (err < 0) {
                snd_ctl_free_one(kctl);
                goto unlock;
index fdb9b92fc8d6b307d4f887266317bbc6ed77adf0..01b9d62eef14db9f22bd1fb67bcaf5456f791d38 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/mutex.h>
 #include <linux/device.h>
+#include <linux/nospec.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -129,6 +130,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                                return -EFAULT;
                        if (stream < 0 || stream > 1)
                                return -EINVAL;
+                       stream = array_index_nospec(stream, 2);
                        if (get_user(subdevice, &info->subdevice))
                                return -EFAULT;
                        mutex_lock(&register_mutex);
index 8a146b0392761402ffeb79e869fe985abb172cff..052e005902590c41247bff33f415b430e0c8744d 100644 (file)
@@ -41,6 +41,7 @@ config SND_OXFW
           * Mackie(Loud) U.420/U.420d
           * TASCAM FireOne
           * Stanton Controllers & Systems 1 Deck/Mixer
+          * APOGEE duet FireWire
 
          To compile this driver as a module, choose M here: the module
          will be called snd-oxfw.
@@ -161,5 +162,6 @@ config SND_FIREFACE
        help
         Say Y here to include support for RME fireface series.
          * Fireface 400
+         * Fireface 800
 
 endif # SND_FIREWIRE
index 54cdd4ffa9ceb1a0fb3a1967dc0fd8bd1c7f3412..ac20acf48fc6912190df52dcecaa3fca801f5fc5 100644 (file)
@@ -131,7 +131,7 @@ TRACE_EVENT(in_packet_without_header,
                __entry->index = index;
        ),
        TP_printk(
-               "%02u %04u %04x %04x %02d %03u %3u %3u %02u %01u %02u",
+               "%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
                __entry->second,
                __entry->cycle,
                __entry->src,
@@ -169,7 +169,7 @@ TRACE_EVENT(out_packet_without_header,
                __entry->dest = fw_parent_device(s->unit)->node_id;
                __entry->payload_quadlets = payload_length / 4;
                __entry->data_blocks = data_blocks,
-               __entry->data_blocks = s->data_block_counter,
+               __entry->data_block_counter = s->data_block_counter,
                __entry->packet_index = s->packet_index;
                __entry->irq = !!in_interrupt();
                __entry->index = index;
index 9be76c808fccf09ef8a8785152657510bcef1f1e..3ada55ed5381d34d1fb88378049f2ebf59686587 100644 (file)
@@ -654,15 +654,17 @@ end:
 }
 
 static int handle_in_packet_without_header(struct amdtp_stream *s,
-                       unsigned int payload_quadlets, unsigned int cycle,
+                       unsigned int payload_length, unsigned int cycle,
                        unsigned int index)
 {
        __be32 *buffer;
+       unsigned int payload_quadlets;
        unsigned int data_blocks;
        struct snd_pcm_substream *pcm;
        unsigned int pcm_frames;
 
        buffer = s->buffer.packets[s->packet_index].buffer;
+       payload_quadlets = payload_length / 4;
        data_blocks = payload_quadlets / s->data_block_quadlets;
 
        trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
index 672d1348845473b67b9017d4d3270786b9986068..d91874275d2c371f078f1601c2c2627e875627f3 100644 (file)
@@ -408,7 +408,7 @@ static const struct ieee1394_device_id bebob_id_table[] = {
        /* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */
        SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal),
        /* Apogee Electronics, Ensemble */
-       SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00001eee, &spec_normal),
+       SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
        /* ESI, Quatafire610 */
        SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
        /* AcousticReality, eARMasterOne */
index 8f807284ba54344fd11d5d576e4627d5993e3a2c..79a7d6d99d7287b0735a0aaf1d690429ae7c2cad 100644 (file)
@@ -1,3 +1,4 @@
 snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
-                    ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o
+                    ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \
+                    ff-protocol-ff800.o
 obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
index bf47f9ec87039543ebc9c6aab50513ccbb6f1924..d0bc96b20a65d45e10b12010d220745b80c3bc7b 100644 (file)
@@ -8,11 +8,6 @@
 
 #include "ff.h"
 
-static inline unsigned int get_multiplier_mode_with_index(unsigned int index)
-{
-       return ((int)index - 1) / 2;
-}
-
 static int hw_rule_rate(struct snd_pcm_hw_params *params,
                        struct snd_pcm_hw_rule *rule)
 {
@@ -24,10 +19,16 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
        struct snd_interval t = {
                .min = UINT_MAX, .max = 0, .integer = 1
        };
-       unsigned int i, mode;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
-               mode = get_multiplier_mode_with_index(i);
+               enum snd_ff_stream_mode mode;
+               int err;
+
+               err = snd_ff_stream_get_multiplier_mode(i, &mode);
+               if (err < 0)
+                       continue;
+
                if (!snd_interval_test(c, pcm_channels[mode]))
                        continue;
 
@@ -49,10 +50,16 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
        struct snd_interval t = {
                .min = UINT_MAX, .max = 0, .integer = 1
        };
-       unsigned int i, mode;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
-               mode = get_multiplier_mode_with_index(i);
+               enum snd_ff_stream_mode mode;
+               int err;
+
+               err = snd_ff_stream_get_multiplier_mode(i, &mode);
+               if (err < 0)
+                       continue;
+
                if (!snd_interval_test(r, amdtp_rate_table[i]))
                        continue;
 
@@ -66,7 +73,6 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
 static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
                                     const unsigned int *pcm_channels)
 {
-       unsigned int mode;
        unsigned int rate, channels;
        int i;
 
@@ -76,7 +82,12 @@ static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
        hw->rate_max = 0;
 
        for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
-               mode = get_multiplier_mode_with_index(i);
+               enum snd_ff_stream_mode mode;
+               int err;
+
+               err = snd_ff_stream_get_multiplier_mode(i, &mode);
+               if (err < 0)
+                       continue;
 
                channels = pcm_channels[mode];
                if (pcm_channels[mode] == 0)
@@ -141,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
        if (err < 0)
                goto release_lock;
 
-       err = ff->spec->protocol->get_clock(ff, &rate, &src);
+       err = snd_ff_transaction_get_clock(ff, &rate, &src);
        if (err < 0)
                goto release_lock;
 
index 40ccbfd8ef89af6b5753602471c16948fa83b0a5..a0c550dabe9ace95a4186f71cbad32eaf5e84c57 100644 (file)
@@ -12,16 +12,205 @@ static void proc_dump_clock_config(struct snd_info_entry *entry,
                                   struct snd_info_buffer *buffer)
 {
        struct snd_ff *ff = entry->private_data;
+       __le32 reg;
+       u32 data;
+       unsigned int rate;
+       const char *src;
+       int err;
 
-       ff->spec->protocol->dump_clock_config(ff, buffer);
+       err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
+                                SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return;
+
+       data = le32_to_cpu(reg);
+
+       snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
+                   (data & 0x20) ? "Professional" : "Consumer",
+                   (data & 0x40) ? "on" : "off");
+
+       snd_iprintf(buffer, "Optical output interface format: %s\n",
+                   ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
+
+       snd_iprintf(buffer, "Word output single speed: %s\n",
+                   ((data >> 8) & 0x20) ? "on" : "off");
+
+       snd_iprintf(buffer, "S/PDIF input interface: %s\n",
+                   ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
+
+       switch ((data >> 1) & 0x03) {
+       case 0x01:
+               rate = 32000;
+               break;
+       case 0x00:
+               rate = 44100;
+               break;
+       case 0x03:
+               rate = 48000;
+               break;
+       case 0x02:
+       default:
+               return;
+       }
+
+       if (data & 0x08)
+               rate *= 2;
+       else if (data & 0x10)
+               rate *= 4;
+
+       snd_iprintf(buffer, "Sampling rate: %d\n", rate);
+
+       if (data & 0x01) {
+               src = "Internal";
+       } else {
+               switch ((data >> 10) & 0x07) {
+               case 0x00:
+                       src = "ADAT1";
+                       break;
+               case 0x01:
+                       src = "ADAT2";
+                       break;
+               case 0x03:
+                       src = "S/PDIF";
+                       break;
+               case 0x04:
+                       src = "Word";
+                       break;
+               case 0x05:
+                       src = "LTC";
+                       break;
+               default:
+                       return;
+               }
+       }
+
+       snd_iprintf(buffer, "Sync to clock source: %s\n", src);
 }
 
 static void proc_dump_sync_status(struct snd_info_entry *entry,
                                  struct snd_info_buffer *buffer)
 {
        struct snd_ff *ff = entry->private_data;
+       __le32 reg;
+       u32 data;
+       int err;
+
+       err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+                                SND_FF_REG_SYNC_STATUS, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return;
+
+       data = le32_to_cpu(reg);
+
+       snd_iprintf(buffer, "External source detection:\n");
+
+       snd_iprintf(buffer, "Word Clock:");
+       if ((data >> 24) & 0x20) {
+               if ((data >> 24) & 0x40)
+                       snd_iprintf(buffer, "sync\n");
+               else
+                       snd_iprintf(buffer, "lock\n");
+       } else {
+               snd_iprintf(buffer, "none\n");
+       }
+
+       snd_iprintf(buffer, "S/PDIF:");
+       if ((data >> 16) & 0x10) {
+               if ((data >> 16) & 0x04)
+                       snd_iprintf(buffer, "sync\n");
+               else
+                       snd_iprintf(buffer, "lock\n");
+       } else {
+               snd_iprintf(buffer, "none\n");
+       }
+
+       snd_iprintf(buffer, "ADAT1:");
+       if ((data >> 8) & 0x04) {
+               if ((data >> 8) & 0x10)
+                       snd_iprintf(buffer, "sync\n");
+               else
+                       snd_iprintf(buffer, "lock\n");
+       } else {
+               snd_iprintf(buffer, "none\n");
+       }
+
+       snd_iprintf(buffer, "ADAT2:");
+       if ((data >> 8) & 0x08) {
+               if ((data >> 8) & 0x20)
+                       snd_iprintf(buffer, "sync\n");
+               else
+                       snd_iprintf(buffer, "lock\n");
+       } else {
+               snd_iprintf(buffer, "none\n");
+       }
+
+       snd_iprintf(buffer, "\nUsed external source:\n");
+
+       if (((data >> 22) & 0x07) == 0x07) {
+               snd_iprintf(buffer, "None\n");
+       } else {
+               switch ((data >> 22) & 0x07) {
+               case 0x00:
+                       snd_iprintf(buffer, "ADAT1:");
+                       break;
+               case 0x01:
+                       snd_iprintf(buffer, "ADAT2:");
+                       break;
+               case 0x03:
+                       snd_iprintf(buffer, "S/PDIF:");
+                       break;
+               case 0x04:
+                       snd_iprintf(buffer, "Word:");
+                       break;
+               case 0x07:
+                       snd_iprintf(buffer, "Nothing:");
+                       break;
+               case 0x02:
+               case 0x05:
+               case 0x06:
+               default:
+                       snd_iprintf(buffer, "unknown:");
+                       break;
+               }
+
+               if ((data >> 25) & 0x07) {
+                       switch ((data >> 25) & 0x07) {
+                       case 0x01:
+                               snd_iprintf(buffer, "32000\n");
+                               break;
+                       case 0x02:
+                               snd_iprintf(buffer, "44100\n");
+                               break;
+                       case 0x03:
+                               snd_iprintf(buffer, "48000\n");
+                               break;
+                       case 0x04:
+                               snd_iprintf(buffer, "64000\n");
+                               break;
+                       case 0x05:
+                               snd_iprintf(buffer, "88200\n");
+                               break;
+                       case 0x06:
+                               snd_iprintf(buffer, "96000\n");
+                               break;
+                       case 0x07:
+                               snd_iprintf(buffer, "128000\n");
+                               break;
+                       case 0x08:
+                               snd_iprintf(buffer, "176400\n");
+                               break;
+                       case 0x09:
+                               snd_iprintf(buffer, "192000\n");
+                               break;
+                       case 0x00:
+                               snd_iprintf(buffer, "unknown\n");
+                               break;
+                       }
+               }
+       }
 
-       ff->spec->protocol->dump_sync_status(ff, buffer);
+       snd_iprintf(buffer, "Multiplied:");
+       snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
 }
 
 static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
index 654a50319198e4ec59c5acf85e36816783f3f8df..2280fab9b3c7fe36f1c58f2d9af9e1cd8dda4504 100644 (file)
 #define FF400_ISOC_COMM_START  0x000080100508ull
 #define FF400_TX_PACKET_FORMAT 0x00008010050cull
 #define FF400_ISOC_COMM_STOP   0x000080100510ull
-#define FF400_SYNC_STATUS      0x0000801c0000ull
-#define FF400_FETCH_PCM_FRAMES 0x0000801c0000ull       /* For block request. */
-#define FF400_CLOCK_CONFIG     0x0000801c0004ull
 
-#define FF400_MIDI_HIGH_ADDR   0x0000801003f4ull
-#define FF400_MIDI_RX_PORT_0   0x000080180000ull
-#define FF400_MIDI_RX_PORT_1   0x000080190000ull
-
-static int ff400_get_clock(struct snd_ff *ff, unsigned int *rate,
-                          enum snd_ff_clock_src *src)
+/*
+ * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
+ * we can allocate between 0 and 7 channel.
+ */
+static int keep_resources(struct snd_ff *ff, unsigned int rate)
 {
-       __le32 reg;
-       u32 data;
+       enum snd_ff_stream_mode mode;
+       int i;
        int err;
 
-       err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
-                                FF400_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+       // Check whether the given value is supported or not.
+       for (i = 0; i < CIP_SFC_COUNT; i++) {
+               if (amdtp_rate_table[i] == rate)
+                       break;
+       }
+       if (i >= CIP_SFC_COUNT)
+               return -EINVAL;
+
+       err = snd_ff_stream_get_multiplier_mode(i, &mode);
        if (err < 0)
                return err;
-       data = le32_to_cpu(reg);
 
-       /* Calculate sampling rate. */
-       switch ((data >> 1) & 0x03) {
-       case 0x01:
-               *rate = 32000;
-               break;
-       case 0x00:
-               *rate = 44100;
-               break;
-       case 0x03:
-               *rate = 48000;
-               break;
-       case 0x02:
-       default:
-               return -EIO;
-       }
-
-       if (data & 0x08)
-               *rate *= 2;
-       else if (data & 0x10)
-               *rate *= 4;
+       /* Keep resources for in-stream. */
+       ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
+       err = fw_iso_resources_allocate(&ff->tx_resources,
+                       amdtp_stream_get_max_payload(&ff->tx_stream),
+                       fw_parent_device(ff->unit)->max_speed);
+       if (err < 0)
+               return err;
 
-       /* Calculate source of clock. */
-       if (data & 0x01) {
-               *src = SND_FF_CLOCK_SRC_INTERNAL;
-       } else {
-               /* TODO: 0x00, 0x01, 0x02, 0x06, 0x07? */
-               switch ((data >> 10) & 0x07) {
-               case 0x03:
-                       *src = SND_FF_CLOCK_SRC_SPDIF;
-                       break;
-               case 0x04:
-                       *src = SND_FF_CLOCK_SRC_WORD;
-                       break;
-               case 0x05:
-                       *src = SND_FF_CLOCK_SRC_LTC;
-                       break;
-               case 0x00:
-               default:
-                       *src = SND_FF_CLOCK_SRC_ADAT;
-                       break;
-               }
-       }
+       /* Keep resources for out-stream. */
+       err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
+                                     ff->spec->pcm_playback_channels[mode]);
+       if (err < 0)
+               return err;
+       ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
+       err = fw_iso_resources_allocate(&ff->rx_resources,
+                       amdtp_stream_get_max_payload(&ff->rx_stream),
+                       fw_parent_device(ff->unit)->max_speed);
+       if (err < 0)
+               fw_iso_resources_free(&ff->tx_resources);
 
-       return 0;
+       return err;
 }
 
 static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
 {
        __le32 reg;
-       int i, err;
+       int err;
 
-       /* Check whether the given value is supported or not. */
-       for (i = 0; i < CIP_SFC_COUNT; i++) {
-               if (amdtp_rate_table[i] == rate)
-                       break;
-       }
-       if (i == CIP_SFC_COUNT)
-               return -EINVAL;
+       err = keep_resources(ff, rate);
+       if (err < 0)
+               return err;
 
        /* Set the number of data blocks transferred in a second. */
        reg = cpu_to_le32(rate);
@@ -142,233 +117,45 @@ static void ff400_finish_session(struct snd_ff *ff)
                           FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
 }
 
-static int ff400_switch_fetching_mode(struct snd_ff *ff, bool enable)
+static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
 {
-       __le32 *reg;
        int i;
-       int err;
 
-       reg = kcalloc(18, sizeof(__le32), GFP_KERNEL);
-       if (reg == NULL)
-               return -ENOMEM;
+       for (i = 0; i < length / 4; i++) {
+               u32 quad = le32_to_cpu(buf[i]);
+               u8 byte;
+               unsigned int index;
+               struct snd_rawmidi_substream *substream;
 
-       if (enable) {
+               /* Message in first port. */
                /*
-                * Each quadlet is corresponding to data channels in a data
-                * blocks in reverse order. Precisely, quadlets for available
-                * data channels should be enabled. Here, I take second best
-                * to fetch PCM frames from all of data channels regardless of
-                * stf.
+                * This value may represent the index of this unit when the same
+                * units are on the same IEEE 1394 bus. This driver doesn't use
+                * it.
                 */
-               for (i = 0; i < 18; ++i)
-                       reg[i] = cpu_to_le32(0x00000001);
-       }
-
-       err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
-                                FF400_FETCH_PCM_FRAMES, reg,
-                                sizeof(__le32) * 18, 0);
-       kfree(reg);
-       return err;
-}
-
-static void ff400_dump_sync_status(struct snd_ff *ff,
-                                  struct snd_info_buffer *buffer)
-{
-       __le32 reg;
-       u32 data;
-       int err;
-
-       err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
-                                FF400_SYNC_STATUS, &reg, sizeof(reg), 0);
-       if (err < 0)
-               return;
-
-       data = le32_to_cpu(reg);
-
-       snd_iprintf(buffer, "External source detection:\n");
-
-       snd_iprintf(buffer, "Word Clock:");
-       if ((data >> 24) & 0x20) {
-               if ((data >> 24) & 0x40)
-                       snd_iprintf(buffer, "sync\n");
-               else
-                       snd_iprintf(buffer, "lock\n");
-       } else {
-               snd_iprintf(buffer, "none\n");
-       }
-
-       snd_iprintf(buffer, "S/PDIF:");
-       if ((data >> 16) & 0x10) {
-               if ((data >> 16) & 0x04)
-                       snd_iprintf(buffer, "sync\n");
-               else
-                       snd_iprintf(buffer, "lock\n");
-       } else {
-               snd_iprintf(buffer, "none\n");
-       }
-
-       snd_iprintf(buffer, "ADAT:");
-       if ((data >> 8) & 0x04) {
-               if ((data >> 8) & 0x10)
-                       snd_iprintf(buffer, "sync\n");
-               else
-                       snd_iprintf(buffer, "lock\n");
-       } else {
-               snd_iprintf(buffer, "none\n");
-       }
-
-       snd_iprintf(buffer, "\nUsed external source:\n");
-
-       if (((data >> 22) & 0x07) == 0x07) {
-               snd_iprintf(buffer, "None\n");
-       } else {
-               switch ((data >> 22) & 0x07) {
-               case 0x00:
-                       snd_iprintf(buffer, "ADAT:");
-                       break;
-               case 0x03:
-                       snd_iprintf(buffer, "S/PDIF:");
-                       break;
-               case 0x04:
-                       snd_iprintf(buffer, "Word:");
-                       break;
-               case 0x07:
-                       snd_iprintf(buffer, "Nothing:");
-                       break;
-               case 0x01:
-               case 0x02:
-               case 0x05:
-               case 0x06:
-               default:
-                       snd_iprintf(buffer, "unknown:");
-                       break;
-               }
-
-               if ((data >> 25) & 0x07) {
-                       switch ((data >> 25) & 0x07) {
-                       case 0x01:
-                               snd_iprintf(buffer, "32000\n");
-                               break;
-                       case 0x02:
-                               snd_iprintf(buffer, "44100\n");
-                               break;
-                       case 0x03:
-                               snd_iprintf(buffer, "48000\n");
-                               break;
-                       case 0x04:
-                               snd_iprintf(buffer, "64000\n");
-                               break;
-                       case 0x05:
-                               snd_iprintf(buffer, "88200\n");
-                               break;
-                       case 0x06:
-                               snd_iprintf(buffer, "96000\n");
-                               break;
-                       case 0x07:
-                               snd_iprintf(buffer, "128000\n");
-                               break;
-                       case 0x08:
-                               snd_iprintf(buffer, "176400\n");
-                               break;
-                       case 0x09:
-                               snd_iprintf(buffer, "192000\n");
-                               break;
-                       case 0x00:
-                               snd_iprintf(buffer, "unknown\n");
-                               break;
+               index = (quad >> 8) & 0xff;
+               if (index > 0) {
+                       substream = READ_ONCE(ff->tx_midi_substreams[0]);
+                       if (substream != NULL) {
+                               byte = quad & 0xff;
+                               snd_rawmidi_receive(substream, &byte, 1);
                        }
                }
-       }
-
-       snd_iprintf(buffer, "Multiplied:");
-       snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
-}
 
-static void ff400_dump_clock_config(struct snd_ff *ff,
-                                   struct snd_info_buffer *buffer)
-{
-       __le32 reg;
-       u32 data;
-       unsigned int rate;
-       const char *src;
-       int err;
-
-       err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
-                                FF400_CLOCK_CONFIG, &reg, sizeof(reg), 0);
-       if (err < 0)
-               return;
-
-       data = le32_to_cpu(reg);
-
-       snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
-                   (data & 0x20) ? "Professional" : "Consumer",
-                   (data & 0x40) ? "on" : "off");
-
-       snd_iprintf(buffer, "Optical output interface format: %s\n",
-                   ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
-
-       snd_iprintf(buffer, "Word output single speed: %s\n",
-                   ((data >> 8) & 0x20) ? "on" : "off");
-
-       snd_iprintf(buffer, "S/PDIF input interface: %s\n",
-                   ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
-
-       switch ((data >> 1) & 0x03) {
-       case 0x01:
-               rate = 32000;
-               break;
-       case 0x00:
-               rate = 44100;
-               break;
-       case 0x03:
-               rate = 48000;
-               break;
-       case 0x02:
-       default:
-               return;
-       }
-
-       if (data & 0x08)
-               rate *= 2;
-       else if (data & 0x10)
-               rate *= 4;
-
-       snd_iprintf(buffer, "Sampling rate: %d\n", rate);
-
-       if (data & 0x01) {
-               src = "Internal";
-       } else {
-               switch ((data >> 10) & 0x07) {
-               case 0x00:
-                       src = "ADAT";
-                       break;
-               case 0x03:
-                       src = "S/PDIF";
-                       break;
-               case 0x04:
-                       src = "Word";
-                       break;
-               case 0x05:
-                       src = "LTC";
-                       break;
-               default:
-                       return;
+               /* Message in second port. */
+               index = (quad >> 24) & 0xff;
+               if (index > 0) {
+                       substream = READ_ONCE(ff->tx_midi_substreams[1]);
+                       if (substream != NULL) {
+                               byte = (quad >> 16) & 0xff;
+                               snd_rawmidi_receive(substream, &byte, 1);
+                       }
                }
        }
-
-       snd_iprintf(buffer, "Sync to clock source: %s\n", src);
 }
 
 const struct snd_ff_protocol snd_ff_protocol_ff400 = {
-       .get_clock              = ff400_get_clock,
+       .handle_midi_msg        = ff400_handle_midi_msg,
        .begin_session          = ff400_begin_session,
        .finish_session         = ff400_finish_session,
-       .switch_fetching_mode   = ff400_switch_fetching_mode,
-
-       .dump_sync_status       = ff400_dump_sync_status,
-       .dump_clock_config      = ff400_dump_clock_config,
-
-       .midi_high_addr_reg     = FF400_MIDI_HIGH_ADDR,
-       .midi_rx_port_0_reg     = FF400_MIDI_RX_PORT_0,
-       .midi_rx_port_1_reg     = FF400_MIDI_RX_PORT_1,
 };
diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-ff800.c
new file mode 100644 (file)
index 0000000..2acbf60
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * ff-protocol-ff800.c - a part of driver for RME Fireface series
+ *
+ * Copyright (c) 2018 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/delay.h>
+
+#include "ff.h"
+
+#define FF800_STF              0x0000fc88f000
+#define FF800_RX_PACKET_FORMAT 0x0000fc88f004
+#define FF800_ALLOC_TX_STREAM  0x0000fc88f008
+#define FF800_ISOC_COMM_START  0x0000fc88f00c
+#define   FF800_TX_S800_FLAG   0x00000800
+#define FF800_ISOC_COMM_STOP   0x0000fc88f010
+
+#define FF800_TX_PACKET_ISOC_CH        0x0000801c0008
+
+static int allocate_rx_resources(struct snd_ff *ff)
+{
+       u32 data;
+       __le32 reg;
+       int err;
+
+       // Controllers should allocate isochronous resources for rx stream.
+       err = fw_iso_resources_allocate(&ff->rx_resources,
+                               amdtp_stream_get_max_payload(&ff->rx_stream),
+                               fw_parent_device(ff->unit)->max_speed);
+       if (err < 0)
+               return err;
+
+       // Set isochronous channel and the number of quadlets of rx packets.
+       data = ff->rx_stream.data_block_quadlets << 3;
+       data = (data << 8) | ff->rx_resources.channel;
+       reg = cpu_to_le32(data);
+       return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                               FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
+}
+
+static int allocate_tx_resources(struct snd_ff *ff)
+{
+       __le32 reg;
+       unsigned int count;
+       unsigned int tx_isoc_channel;
+       int err;
+
+       reg = cpu_to_le32(ff->tx_stream.data_block_quadlets);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                FF800_ALLOC_TX_STREAM, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // Wait till the format of tx packet is available.
+       count = 0;
+       while (count++ < 10) {
+               u32 data;
+               err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+                               FF800_TX_PACKET_ISOC_CH, &reg, sizeof(reg), 0);
+               if (err < 0)
+                       return err;
+
+               data = le32_to_cpu(reg);
+               if (data != 0xffffffff) {
+                       tx_isoc_channel = data;
+                       break;
+               }
+
+               msleep(50);
+       }
+       if (count >= 10)
+               return -ETIMEDOUT;
+
+       // NOTE: this is a makeshift to start OHCI 1394 IR context in the
+       // channel. On the other hand, 'struct fw_iso_resources.allocated' is
+       // not true and it's not deallocated at stop.
+       ff->tx_resources.channel = tx_isoc_channel;
+
+       return 0;
+}
+
+static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+       __le32 reg;
+       int err;
+
+       reg = cpu_to_le32(rate);
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                FF800_STF, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       // If starting isochronous communication immediately, change of STF has
+       // no effect. In this case, the communication runs based on former STF.
+       // Let's sleep for a bit.
+       msleep(100);
+
+       err = allocate_rx_resources(ff);
+       if (err < 0)
+               return err;
+
+       err = allocate_tx_resources(ff);
+       if (err < 0)
+               return err;
+
+       reg = cpu_to_le32(0x80000000);
+       reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
+       if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
+               reg |= cpu_to_le32(FF800_TX_S800_FLAG);
+       return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                FF800_ISOC_COMM_START, &reg, sizeof(reg), 0);
+}
+
+static void ff800_finish_session(struct snd_ff *ff)
+{
+       __le32 reg;
+
+       reg = cpu_to_le32(0x80000000);
+       snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          FF800_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
+}
+
+static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
+{
+       int i;
+
+       for (i = 0; i < length / 4; i++) {
+               u8 byte = le32_to_cpu(buf[i]) & 0xff;
+               struct snd_rawmidi_substream *substream;
+
+               substream = READ_ONCE(ff->tx_midi_substreams[0]);
+               if (substream)
+                       snd_rawmidi_receive(substream, &byte, 1);
+       }
+}
+
+const struct snd_ff_protocol snd_ff_protocol_ff800 = {
+       .handle_midi_msg        = ff800_handle_midi_msg,
+       .begin_session          = ff800_begin_session,
+       .finish_session         = ff800_finish_session,
+};
index 78880922120e77b7493b47f0c691f79d8d3cb176..a490e45537212d75a48c82b24bd6dbd9815511b9 100644 (file)
 
 #define CALLBACK_TIMEOUT_MS    200
 
-static int get_rate_mode(unsigned int rate, unsigned int *mode)
+int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
+                                     enum snd_ff_stream_mode *mode)
 {
-       int i;
-
-       for (i = 0; i < CIP_SFC_COUNT; i++) {
-               if (amdtp_rate_table[i] == rate)
-                       break;
-       }
-
-       if (i == CIP_SFC_COUNT)
+       static const enum snd_ff_stream_mode modes[] = {
+               [CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
+               [CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
+               [CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
+               [CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
+               [CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
+               [CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
+               [CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
+       };
+
+       if (sfc >= CIP_SFC_COUNT)
                return -EINVAL;
 
-       *mode = ((int)i - 1) / 2;
+       *mode = modes[sfc];
 
        return 0;
 }
 
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
+static void release_resources(struct snd_ff *ff)
 {
-       int mode;
-       int err;
-
-       err = get_rate_mode(rate, &mode);
-       if (err < 0)
-               return err;
+       fw_iso_resources_free(&ff->tx_resources);
+       fw_iso_resources_free(&ff->rx_resources);
+}
 
-       /* Keep resources for in-stream. */
-       err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
-                                     ff->spec->pcm_capture_channels[mode]);
-       if (err < 0)
-               return err;
-       ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
-       err = fw_iso_resources_allocate(&ff->tx_resources,
-                       amdtp_stream_get_max_payload(&ff->tx_stream),
-                       fw_parent_device(ff->unit)->max_speed);
-       if (err < 0)
-               return err;
+static int switch_fetching_mode(struct snd_ff *ff, bool enable)
+{
+       unsigned int count;
+       __le32 *reg;
+       int i;
+       int err;
 
-       /* Keep resources for out-stream. */
-       err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
-                                     ff->spec->pcm_playback_channels[mode]);
-       if (err < 0)
-               return err;
-       ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
-       err = fw_iso_resources_allocate(&ff->rx_resources,
-                       amdtp_stream_get_max_payload(&ff->rx_stream),
-                       fw_parent_device(ff->unit)->max_speed);
-       if (err < 0)
-               fw_iso_resources_free(&ff->tx_resources);
+       count = 0;
+       for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
+               count = max(count, ff->spec->pcm_playback_channels[i]);
+
+       reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
+       if (!reg)
+               return -ENOMEM;
+
+       if (!enable) {
+               /*
+                * Each quadlet is corresponding to data channels in a data
+                * blocks in reverse order. Precisely, quadlets for available
+                * data channels should be enabled. Here, I take second best
+                * to fetch PCM frames from all of data channels regardless of
+                * stf.
+                */
+               for (i = 0; i < count; ++i)
+                       reg[i] = cpu_to_le32(0x00000001);
+       }
 
+       err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
+                                SND_FF_REG_FETCH_PCM_FRAMES, reg,
+                                sizeof(__le32) * count, 0);
+       kfree(reg);
        return err;
 }
 
-static void release_resources(struct snd_ff *ff)
-{
-       fw_iso_resources_free(&ff->tx_resources);
-       fw_iso_resources_free(&ff->rx_resources);
-}
-
 static inline void finish_session(struct snd_ff *ff)
 {
        ff->spec->protocol->finish_session(ff);
-       ff->spec->protocol->switch_fetching_mode(ff, false);
+       switch_fetching_mode(ff, false);
 }
 
 static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
@@ -149,7 +147,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
        if (ff->substreams_counter == 0)
                return 0;
 
-       err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
+       err = snd_ff_transaction_get_clock(ff, &curr_rate, &src);
        if (err < 0)
                return err;
        if (curr_rate != rate ||
@@ -168,9 +166,29 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
         * packets. Then, the device transfers packets.
         */
        if (!amdtp_stream_running(&ff->rx_stream)) {
-               err = keep_resources(ff, rate);
+               enum snd_ff_stream_mode mode;
+               int i;
+
+               for (i = 0; i < CIP_SFC_COUNT; ++i) {
+                       if (amdtp_rate_table[i] == rate)
+                               break;
+               }
+               if (i >= CIP_SFC_COUNT)
+                       return -EINVAL;
+
+               err = snd_ff_stream_get_multiplier_mode(i, &mode);
                if (err < 0)
-                       goto error;
+                       return err;
+
+               err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
+                                       ff->spec->pcm_capture_channels[mode]);
+               if (err < 0)
+                       return err;
+
+               err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
+                                       ff->spec->pcm_playback_channels[mode]);
+               if (err < 0)
+                       return err;
 
                err = ff->spec->protocol->begin_session(ff, rate);
                if (err < 0)
@@ -188,7 +206,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
                        goto error;
                }
 
-               err = ff->spec->protocol->switch_fetching_mode(ff, true);
+               err = switch_fetching_mode(ff, true);
                if (err < 0)
                        goto error;
        }
index 332b29f8ed754da9c3a9d4c38807fe30935b2a18..5f4ddfd55403a35ae4cb2f29f82ff23ee585292f 100644 (file)
@@ -8,6 +8,72 @@
 
 #include "ff.h"
 
+#define SND_FF_REG_MIDI_RX_PORT_0      0x000080180000ull
+#define SND_FF_REG_MIDI_RX_PORT_1      0x000080190000ull
+
+int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
+                                enum snd_ff_clock_src *src)
+{
+       __le32 reg;
+       u32 data;
+       int err;
+
+       err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+                                SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+       data = le32_to_cpu(reg);
+
+       /* Calculate sampling rate. */
+       switch ((data >> 1) & 0x03) {
+       case 0x01:
+               *rate = 32000;
+               break;
+       case 0x00:
+               *rate = 44100;
+               break;
+       case 0x03:
+               *rate = 48000;
+               break;
+       case 0x02:
+       default:
+               return -EIO;
+       }
+
+       if (data & 0x08)
+               *rate *= 2;
+       else if (data & 0x10)
+               *rate *= 4;
+
+       /* Calculate source of clock. */
+       if (data & 0x01) {
+               *src = SND_FF_CLOCK_SRC_INTERNAL;
+       } else {
+               /* TODO: 0x02, 0x06, 0x07? */
+               switch ((data >> 10) & 0x07) {
+               case 0x00:
+                       *src = SND_FF_CLOCK_SRC_ADAT1;
+                       break;
+               case 0x01:
+                       *src = SND_FF_CLOCK_SRC_ADAT2;
+                       break;
+               case 0x03:
+                       *src = SND_FF_CLOCK_SRC_SPDIF;
+                       break;
+               case 0x04:
+                       *src = SND_FF_CLOCK_SRC_WORD;
+                       break;
+               case 0x05:
+                       *src = SND_FF_CLOCK_SRC_LTC;
+                       break;
+               default:
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
 static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
                                     int rcode)
 {
@@ -90,10 +156,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
                fill_midi_buf(ff, port, i, buf[i]);
 
        if (port == 0) {
-               addr = ff->spec->protocol->midi_rx_port_0_reg;
+               addr = SND_FF_REG_MIDI_RX_PORT_0;
                callback = finish_transmit_midi0_msg;
        } else {
-               addr = ff->spec->protocol->midi_rx_port_1_reg;
+               addr = SND_FF_REG_MIDI_RX_PORT_1;
                callback = finish_transmit_midi1_msg;
        }
 
@@ -140,42 +206,10 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
 {
        struct snd_ff *ff = callback_data;
        __le32 *buf = data;
-       u32 quad;
-       u8 byte;
-       unsigned int index;
-       struct snd_rawmidi_substream *substream;
-       int i;
 
        fw_send_response(card, request, RCODE_COMPLETE);
 
-       for (i = 0; i < length / 4; i++) {
-               quad = le32_to_cpu(buf[i]);
-
-               /* Message in first port. */
-               /*
-                * This value may represent the index of this unit when the same
-                * units are on the same IEEE 1394 bus. This driver doesn't use
-                * it.
-                */
-               index = (quad >> 8) & 0xff;
-               if (index > 0) {
-                       substream = READ_ONCE(ff->tx_midi_substreams[0]);
-                       if (substream != NULL) {
-                               byte = quad & 0xff;
-                               snd_rawmidi_receive(substream, &byte, 1);
-                       }
-               }
-
-               /* Message in second port. */
-               index = (quad >> 24) & 0xff;
-               if (index > 0) {
-                       substream = READ_ONCE(ff->tx_midi_substreams[1]);
-                       if (substream != NULL) {
-                               byte = (quad >> 16) & 0xff;
-                               snd_rawmidi_receive(substream, &byte, 1);
-                       }
-               }
-       }
+       ff->spec->protocol->handle_midi_msg(ff, buf, length);
 }
 
 static int allocate_own_address(struct snd_ff *ff, int i)
@@ -203,36 +237,33 @@ static int allocate_own_address(struct snd_ff *ff, int i)
 }
 
 /*
- * The configuration to start asynchronous transactions for MIDI messages is in
- * 0x'0000'8010'051c. This register includes the other options, thus this driver
- * doesn't touch it and leaves the decision to userspace. The userspace MUST add
- * 0x04000000 to write transactions to the register to receive any MIDI
- * messages.
- *
- * Here, I just describe MIDI-related offsets of the register, in little-endian
- * order.
- *
  * Controllers are allowed to register higher 4 bytes of address to receive
- * the transactions. The register is 0x'0000'8010'03f4. On the other hand, the
- * controllers are not allowed to register lower 4 bytes of the address. They
- * are forced to select from 4 options by writing corresponding bits to
- * 0x'0000'8010'051c.
+ * the transactions. Different models have different registers for this purpose;
+ * e.g. 0x'0000'8010'03f4 for Fireface 400.
+ * The controllers are not allowed to register lower 4 bytes of the address.
+ * They are forced to select one of 4 options for the part of address by writing
+ * corresponding bits to 0x'0000'8010'051f.
+ *
+ * The 3rd-6th bits of this register are flags to indicate lower 4 bytes of
+ * address to which the device transferrs the transactions. In short:
+ *  - 0x20: 0x'....'....'0000'0180
+ *  - 0x10: 0x'....'....'0000'0100
+ *  - 0x08: 0x'....'....'0000'0080
+ *  - 0x04: 0x'....'....'0000'0000
  *
- * The 3rd-6th bits in MSB of this register are used to indicate lower 4 bytes
- * of address to which the device transferrs the transactions.
- *  - 6th: 0x'....'....'0000'0180
- *  - 5th: 0x'....'....'0000'0100
- *  - 4th: 0x'....'....'0000'0080
- *  - 3rd: 0x'....'....'0000'0000
+ * This driver configure 0x'....'....'0000'0000 to receive MIDI messages from
+ * units. The 3rd bit of the register should be configured, however this driver
+ * deligates this task to userspace applications due to a restriction that this
+ * register is write-only and the other bits have own effects.
  *
- * This driver configure 0x'....'....'0000'0000 for units to receive MIDI
- * messages. 3rd bit of the register should be configured, however this driver
- * deligates this task to user space applications due to a restriction that
- * this register is write-only and the other bits have own effects.
+ * Unlike Fireface 800, Fireface 400 cancels transferring asynchronous
+ * transactions when the 1st and 2nd of the register stand. These two bits have
+ * the same effect.
+ *  - 0x02, 0x01: cancel transferring
  *
- * The 1st and 2nd bits in LSB of this register are used to cancel transferring
- * asynchronous transactions. These two bits have the same effect.
- *  - 1st/2nd: cancel transferring
+ * On the other hand, the bits have no effect on Fireface 800. This model
+ * cancels asynchronous transactions when the higher 4 bytes of address is
+ * overwritten with zero.
  */
 int snd_ff_transaction_reregister(struct snd_ff *ff)
 {
@@ -247,7 +278,7 @@ int snd_ff_transaction_reregister(struct snd_ff *ff)
        addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32);
        reg = cpu_to_le32(addr);
        return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                                 ff->spec->protocol->midi_high_addr_reg,
+                                 ff->spec->midi_high_addr,
                                  &reg, sizeof(reg), 0);
 }
 
@@ -288,7 +319,7 @@ void snd_ff_transaction_unregister(struct snd_ff *ff)
        /* Release higher 4 bytes of address. */
        reg = cpu_to_le32(0x00000000);
        snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-                          ff->spec->protocol->midi_high_addr_reg,
+                          ff->spec->midi_high_addr,
                           &reg, sizeof(reg), 0);
 
        fw_core_remove_address_handler(&ff->async_handler);
index 3f61cfeace69e7249658d96f5ec4c108553a5c1d..36575f4159d13cc0be238ba25704521fb718e711 100644 (file)
@@ -145,6 +145,16 @@ static void snd_ff_remove(struct fw_unit *unit)
        fw_unit_put(ff->unit);
 }
 
+static const struct snd_ff_spec spec_ff800 = {
+       .name = "Fireface800",
+       .pcm_capture_channels = {28, 20, 12},
+       .pcm_playback_channels = {28, 20, 12},
+       .midi_in_ports = 1,
+       .midi_out_ports = 1,
+       .protocol = &snd_ff_protocol_ff800,
+       .midi_high_addr = 0x000200000320ull,
+};
+
 static const struct snd_ff_spec spec_ff400 = {
        .name = "Fireface400",
        .pcm_capture_channels = {18, 14, 10},
@@ -152,9 +162,22 @@ static const struct snd_ff_spec spec_ff400 = {
        .midi_in_ports = 2,
        .midi_out_ports = 2,
        .protocol = &snd_ff_protocol_ff400,
+       .midi_high_addr = 0x0000801003f4ull,
 };
 
 static const struct ieee1394_device_id snd_ff_id_table[] = {
+       /* Fireface 800 */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_SPECIFIER_ID |
+                                 IEEE1394_MATCH_VERSION |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_RME,
+               .specifier_id   = OUI_RME,
+               .version        = 0x000001,
+               .model_id       = 0x101800,
+               .driver_data    = (kernel_ulong_t)&spec_ff800,
+       },
        /* Fireface 400 */
        {
                .match_flags    = IEEE1394_MATCH_VENDOR_ID |
@@ -162,7 +185,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
                                  IEEE1394_MATCH_VERSION |
                                  IEEE1394_MATCH_MODEL_ID,
                .vendor_id      = OUI_RME,
-               .specifier_id   = 0x000a35,
+               .specifier_id   = OUI_RME,
                .version        = 0x000002,
                .model_id       = 0x101800,
                .driver_data    = (kernel_ulong_t)&spec_ff400,
index 64df44beb95058ab42f51d195edc4f6497edea88..7dfc7745a9141f2780db3d3ba432ad2c3d2b5b11 100644 (file)
 #include "../amdtp-stream.h"
 #include "../iso-resources.h"
 
-#define SND_FF_STREAM_MODES            3
-
 #define SND_FF_MAXIMIM_MIDI_QUADS      9
 #define SND_FF_IN_MIDI_PORTS           2
 #define SND_FF_OUT_MIDI_PORTS          2
 
+#define SND_FF_REG_SYNC_STATUS         0x0000801c0000ull
+/* For block write request. */
+#define SND_FF_REG_FETCH_PCM_FRAMES    0x0000801c0000ull
+#define SND_FF_REG_CLOCK_CONFIG                0x0000801c0004ull
+
+enum snd_ff_stream_mode {
+       SND_FF_STREAM_MODE_LOW = 0,
+       SND_FF_STREAM_MODE_MID,
+       SND_FF_STREAM_MODE_HIGH,
+       SND_FF_STREAM_MODE_COUNT,
+};
+
 struct snd_ff_protocol;
 struct snd_ff_spec {
        const char *const name;
 
-       const unsigned int pcm_capture_channels[SND_FF_STREAM_MODES];
-       const unsigned int pcm_playback_channels[SND_FF_STREAM_MODES];
+       const unsigned int pcm_capture_channels[SND_FF_STREAM_MODE_COUNT];
+       const unsigned int pcm_playback_channels[SND_FF_STREAM_MODE_COUNT];
 
        unsigned int midi_in_ports;
        unsigned int midi_out_ports;
 
        const struct snd_ff_protocol *protocol;
+       u64 midi_high_addr;
 };
 
 struct snd_ff {
@@ -89,31 +100,24 @@ struct snd_ff {
 enum snd_ff_clock_src {
        SND_FF_CLOCK_SRC_INTERNAL,
        SND_FF_CLOCK_SRC_SPDIF,
-       SND_FF_CLOCK_SRC_ADAT,
+       SND_FF_CLOCK_SRC_ADAT1,
+       SND_FF_CLOCK_SRC_ADAT2,
        SND_FF_CLOCK_SRC_WORD,
        SND_FF_CLOCK_SRC_LTC,
-       /* TODO: perhaps ADAT2 and TCO exists. */
+       /* TODO: perhaps TCO exists. */
 };
 
 struct snd_ff_protocol {
-       int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
-                        enum snd_ff_clock_src *src);
+       void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
        int (*begin_session)(struct snd_ff *ff, unsigned int rate);
        void (*finish_session)(struct snd_ff *ff);
-       int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
-
-       void (*dump_sync_status)(struct snd_ff *ff,
-                                struct snd_info_buffer *buffer);
-       void (*dump_clock_config)(struct snd_ff *ff,
-                                 struct snd_info_buffer *buffer);
-
-       u64 midi_high_addr_reg;
-       u64 midi_rx_port_0_reg;
-       u64 midi_rx_port_1_reg;
 };
 
+extern const struct snd_ff_protocol snd_ff_protocol_ff800;
 extern const struct snd_ff_protocol snd_ff_protocol_ff400;
 
+int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
+                                enum snd_ff_clock_src *src);
 int snd_ff_transaction_register(struct snd_ff *ff);
 int snd_ff_transaction_reregister(struct snd_ff *ff);
 void snd_ff_transaction_unregister(struct snd_ff *ff);
@@ -125,6 +129,8 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
 int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
                  enum amdtp_stream_direction dir);
 
+int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
+                                     enum snd_ff_stream_mode *mode);
 int snd_ff_stream_init_duplex(struct snd_ff *ff);
 void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
index afb78d90384b80b3368a0e8a4621174469435e6f..3d27f3378d5ddf1b54cd9ec164ee3125002df091 100644 (file)
@@ -20,6 +20,7 @@
 #define VENDOR_LACIE           0x00d04b
 #define VENDOR_TASCAM          0x00022e
 #define OUI_STANTON            0x001260
+#define OUI_APOGEE             0x0003db
 
 #define MODEL_SATELLITE                0x00200f
 
@@ -397,6 +398,13 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
                .vendor_id      = OUI_STANTON,
                .model_id       = 0x002000,
        },
+       // APOGEE, duet FireWire
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_APOGEE,
+               .model_id       = 0x01dddd,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
index ab482423c16545d3161e04d7d8e78f614b3b70ea..a52d1f76c610fbed8003e8195d60a61251e8dc45 100644 (file)
@@ -117,6 +117,55 @@ int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
        return amdtp_stream_add_pcm_hw_constraints(s, runtime);
 }
 
+static void read_status_messages(struct amdtp_stream *s,
+                                __be32 *buffer, unsigned int data_blocks)
+{
+       struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream);
+       bool used = READ_ONCE(tscm->hwdep->used);
+       int i;
+
+       for (i = 0; i < data_blocks; i++) {
+               unsigned int index;
+               __be32 before;
+               __be32 after;
+
+               index = be32_to_cpu(buffer[0]) % SNDRV_FIREWIRE_TASCAM_STATE_COUNT;
+               before = tscm->state[index];
+               after = buffer[s->data_block_quadlets - 1];
+
+               if (used && index > 4 && index < 16) {
+                       __be32 mask;
+
+                       if (index == 5)
+                               mask = cpu_to_be32(~0x0000ffff);
+                       else if (index == 6)
+                               mask = cpu_to_be32(~0x0000ffff);
+                       else if (index == 8)
+                               mask = cpu_to_be32(~0x000f0f00);
+                       else
+                               mask = cpu_to_be32(~0x00000000);
+
+                       if ((before ^ after) & mask) {
+                               struct snd_firewire_tascam_change *entry =
+                                               &tscm->queue[tscm->push_pos];
+
+                               spin_lock_irq(&tscm->lock);
+                               entry->index = index;
+                               entry->before = before;
+                               entry->after = after;
+                               if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
+                                       tscm->push_pos = 0;
+                               spin_unlock_irq(&tscm->lock);
+
+                               wake_up(&tscm->hwdep_wait);
+                       }
+               }
+
+               tscm->state[index] = after;
+               buffer += s->data_block_quadlets;
+       }
+}
+
 static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
                                           __be32 *buffer,
                                           unsigned int data_blocks,
@@ -128,7 +177,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
        if (data_blocks > 0 && pcm)
                read_pcm_s32(s, pcm, buffer, data_blocks);
 
-       /* A place holder for control messages. */
+       read_status_messages(s, buffer, data_blocks);
 
        return data_blocks;
 }
index 4e4c1e9020e8cb3e930828513949a07c087cf717..0414abf5daa835e3a393e06bedf84ff5e4d09e62 100644 (file)
 
 #include "tascam.h"
 
+static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
+                                  long count, loff_t *offset)
+{
+       struct snd_firewire_event_lock_status event = {
+               .type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+       };
+
+       event.status = (tscm->dev_lock_count > 0);
+       tscm->dev_lock_changed = false;
+       count = min_t(long, count, sizeof(event));
+
+       spin_unlock_irq(&tscm->lock);
+
+       if (copy_to_user(buf, &event, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
+                                 long remained, loff_t *offset)
+{
+       char __user *pos = buf;
+       unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
+       struct snd_firewire_tascam_change *entries = tscm->queue;
+       long count;
+
+       // At least, one control event can be copied.
+       if (remained < sizeof(type) + sizeof(*entries)) {
+               spin_unlock_irq(&tscm->lock);
+               return -EINVAL;
+       }
+
+       // Copy the type field later.
+       count = sizeof(type);
+       remained -= sizeof(type);
+       pos += sizeof(type);
+
+       while (true) {
+               unsigned int head_pos;
+               unsigned int tail_pos;
+               unsigned int length;
+
+               if (tscm->pull_pos == tscm->push_pos)
+                       break;
+               else if (tscm->pull_pos < tscm->push_pos)
+                       tail_pos = tscm->push_pos;
+               else
+                       tail_pos = SND_TSCM_QUEUE_COUNT;
+               head_pos = tscm->pull_pos;
+
+               length = (tail_pos - head_pos) * sizeof(*entries);
+               if (remained < length)
+                       length = rounddown(remained, sizeof(*entries));
+               if (length == 0)
+                       break;
+
+               spin_unlock_irq(&tscm->lock);
+               if (copy_to_user(pos, &entries[head_pos], length))
+                       return -EFAULT;
+
+               spin_lock_irq(&tscm->lock);
+
+               tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
+
+               count += length;
+               remained -= length;
+               pos += length;
+       }
+
+       spin_unlock_irq(&tscm->lock);
+
+       if (copy_to_user(buf, &type, sizeof(type)))
+               return -EFAULT;
+
+       return count;
+}
+
 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                       loff_t *offset)
 {
        struct snd_tscm *tscm = hwdep->private_data;
        DEFINE_WAIT(wait);
-       union snd_firewire_event event = {
-               .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
-       };
 
        spin_lock_irq(&tscm->lock);
 
-       while (!tscm->dev_lock_changed) {
+       while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
                prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
                spin_unlock_irq(&tscm->lock);
                schedule();
@@ -37,15 +112,15 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                spin_lock_irq(&tscm->lock);
        }
 
-       event.lock_status.status = (tscm->dev_lock_count > 0);
-       tscm->dev_lock_changed = false;
-
-       spin_unlock_irq(&tscm->lock);
-
-       count = min_t(long, count, sizeof(event.lock_status));
-
-       if (copy_to_user(buf, &event, count))
-               return -EFAULT;
+       // NOTE: The acquired lock should be released in callee side.
+       if (tscm->dev_lock_changed) {
+               count = tscm_hwdep_read_locked(tscm, buf, count, offset);
+       } else if (tscm->push_pos != tscm->pull_pos) {
+               count = tscm_hwdep_read_queue(tscm, buf, count, offset);
+       } else {
+               spin_unlock_irq(&tscm->lock);
+               count = 0;
+       }
 
        return count;
 }
@@ -59,7 +134,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
        poll_wait(file, &tscm->hwdep_wait, wait);
 
        spin_lock_irq(&tscm->lock);
-       if (tscm->dev_lock_changed)
+       if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
                events = EPOLLIN | EPOLLRDNORM;
        else
                events = 0;
@@ -123,6 +198,14 @@ static int hwdep_unlock(struct snd_tscm *tscm)
        return err;
 }
 
+static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
+{
+       if (copy_to_user(arg, tscm->state, sizeof(tscm->state)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
 {
        struct snd_tscm *tscm = hwdep->private_data;
@@ -147,6 +230,8 @@ static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
                return hwdep_lock(tscm);
        case SNDRV_FIREWIRE_IOCTL_UNLOCK:
                return hwdep_unlock(tscm);
+       case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE:
+               return tscm_hwdep_state(tscm, (void __user *)arg);
        default:
                return -ENOIOCTLCMD;
        }
@@ -185,5 +270,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
        hwdep->private_data = tscm;
        hwdep->exclusive = true;
 
+       tscm->hwdep = hwdep;
+
        return err;
 }
index a5bd167eb5d99232d2e47449ca1030877c23a738..6a411ee0dcf1ab60f6e701e025ed0b7bfda19ded 100644 (file)
@@ -62,6 +62,8 @@ struct snd_fw_async_midi_port {
        int consume_bytes;
 };
 
+#define SND_TSCM_QUEUE_COUNT   16
+
 struct snd_tscm {
        struct snd_card *card;
        struct fw_unit *unit;
@@ -89,6 +91,13 @@ struct snd_tscm {
 
        /* For MIDI message outgoing transactions. */
        struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
+
+       // A cache of status information in tx isoc packets.
+       __be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
+       struct snd_hwdep *hwdep;
+       struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT];
+       unsigned int pull_pos;
+       unsigned int push_pos;
 };
 
 #define TSCM_ADDR_BASE                 0xffff00000000ull
index 714a51721a313cef9e47309662b778e5c5b3c55b..012305177f68227af7bb25890a92c1ef93690221 100644 (file)
@@ -9,8 +9,6 @@
 #include <sound/hdaudio.h>
 #include "trace.h"
 
-static void process_unsol_events(struct work_struct *work);
-
 static const struct hdac_bus_ops default_ops = {
        .command = snd_hdac_bus_send_cmd,
        .get_response = snd_hdac_bus_get_response,
@@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
        bus->io_ops = io_ops;
        INIT_LIST_HEAD(&bus->stream_list);
        INIT_LIST_HEAD(&bus->codec_list);
-       INIT_WORK(&bus->unsol_work, process_unsol_events);
+       INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
        spin_lock_init(&bus->reg_lock);
        mutex_init(&bus->cmd_mutex);
        bus->irq = -1;
@@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event);
 /*
  * process queued unsolicited events
  */
-static void process_unsol_events(struct work_struct *work)
+void snd_hdac_bus_process_unsol_events(struct work_struct *work)
 {
        struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work);
        struct hdac_device *codec;
@@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work)
                        drv->unsol_event(codec, res);
        }
 }
+EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events);
 
 /**
  * snd_hdac_bus_add_device - Add a codec to bus
index 6e46a9c73aed463bbc1755edd2fc85f1aa20fa09..a6d37b9d6413f51b49fd4486a251bf7e84261532 100644 (file)
@@ -54,41 +54,44 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
 /**
  * snd_hdac_display_power - Power up / down the power refcount
  * @bus: HDA core bus
+ * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
  * @enable: power up or down
  *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with graphics driver.
+ * This function is used by either HD-audio controller or codec driver that
+ * needs the interaction with graphics driver.
  *
- * This function manages a refcount and calls the get_power() and
+ * This function updates the power status, and calls the get_power() and
  * put_power() ops accordingly, toggling the codec wakeup, too.
- *
- * Returns zero for success or a negative error code.
  */
-int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
+void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
 {
        struct drm_audio_component *acomp = bus->audio_component;
 
-       if (!acomp || !acomp->ops)
-               return -ENODEV;
-
        dev_dbg(bus->dev, "display power %s\n",
                enable ? "enable" : "disable");
+       if (enable)
+               set_bit(idx, &bus->display_power_status);
+       else
+               clear_bit(idx, &bus->display_power_status);
 
-       if (enable) {
-               if (!bus->drm_power_refcount++) {
+       if (!acomp || !acomp->ops)
+               return;
+
+       if (bus->display_power_status) {
+               if (!bus->display_power_active) {
                        if (acomp->ops->get_power)
                                acomp->ops->get_power(acomp->dev);
                        snd_hdac_set_codec_wakeup(bus, true);
                        snd_hdac_set_codec_wakeup(bus, false);
+                       bus->display_power_active = true;
                }
        } else {
-               WARN_ON(!bus->drm_power_refcount);
-               if (!--bus->drm_power_refcount)
+               if (bus->display_power_active) {
                        if (acomp->ops->put_power)
                                acomp->ops->put_power(acomp->dev);
+                       bus->display_power_active = false;
+               }
        }
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_display_power);
 
@@ -321,10 +324,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
        if (!acomp)
                return 0;
 
-       WARN_ON(bus->drm_power_refcount);
-       if (bus->drm_power_refcount > 0 && acomp->ops)
+       if (WARN_ON(bus->display_power_active) && acomp->ops)
                acomp->ops->put_power(acomp->dev);
 
+       bus->display_power_active = false;
+       bus->display_power_status = 0;
+
        component_master_del(dev, &hdac_component_master_ops);
 
        bus->audio_component = NULL;
index dbf02a3a8d2f28d4dab93c06eddd8148f9dacc7c..95b073ee4b32bbefa29cf3aeaac68fc4ca9d6447 100644 (file)
@@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec)
 EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
 #endif
 
-/**
- * snd_hdac_link_power - Enable/disable the link power for a codec
- * @codec: the codec object
- * @bool: enable or disable the link power
- */
-int snd_hdac_link_power(struct hdac_device *codec, bool enable)
-{
-       if  (!codec->link_power_control)
-               return 0;
-
-       if  (codec->bus->ops->link_power)
-               return codec->bus->ops->link_power(codec->bus, enable);
-       else
-               return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_link_power);
-
 /* codec vendor labels */
 struct hda_vendor_id {
        unsigned int id;
index a31fe15509038dcd8eb12701f25c1c8111baee56..aad74e80979728db913a25628d7663d1966981c3 100644 (file)
@@ -1183,7 +1183,7 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
 static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
                                        u32 h_stream)
 {
-  struct hpi_format hpi_format;
+       struct hpi_format hpi_format;
        u16 format;
        u16 err;
        u32 h_control;
index 6ebe817801ea9a2f5e0ef3c318ce1b2fad383446..1f25e6d029d82db67c195acf228c33e9ab5208fb 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/moduleparam.h>
+#include <linux/nospec.h>
 
 #include <sound/core.h>
 #include <sound/tlv.h>
@@ -1026,6 +1027,8 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
 
        if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
                return -EINVAL;
+       ipcm->substream = array_index_nospec(ipcm->substream,
+                                            EMU10K1_FX8010_PCM_COUNT);
        if (ipcm->channels > 32)
                return -EINVAL;
        pcm = &emu->fx8010.pcm[ipcm->substream];
@@ -1072,6 +1075,8 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
 
        if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
                return -EINVAL;
+       ipcm->substream = array_index_nospec(ipcm->substream,
+                                            EMU10K1_FX8010_PCM_COUNT);
        pcm = &emu->fx8010.pcm[ipcm->substream];
        mutex_lock(&emu->fx8010.lock);
        spin_lock_irq(&emu->reg_lock);
index 4235907b785891326a479023f3433d2afd9b231e..0d38c006e1824795eba8f8427f27e0fec9db5a00 100644 (file)
@@ -226,6 +226,68 @@ config SND_HDA_POWER_SAVE_DEFAULT
          The default time-out value in seconds for HD-audio automatic
          power-save mode.  0 means to disable the power-save mode.
 
+if SND_HDA_INTEL
+
+# The options below should not be enabled by distributions or
+# users. They are selected by Intel/Skylake or SOF drivers when they
+# register for a PCI ID which is also handled by the HDAudio legacy
+# driver. When this option is selected and the DSP is detected based on
+# the PCI class/subclass/prog-if, the probe of the HDAudio legacy
+# aborts. This mechanism removes the need for distributions to use
+# blacklists. It can be bypassed with module parameters should the
+# Intel/Skylake or SOF drivers fail to handle a specific platform.
+
+config SND_HDA_INTEL_DSP_DETECTION_SKL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         Skylake machines.
+
+config SND_HDA_INTEL_DSP_DETECTION_APL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         Broxton/ApolloLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_KBL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         KabyLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_GLK
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         GeminiLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_CNL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         CannonLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_CFL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         CoffeeLake machines
+
+config SND_HDA_INTEL_DSP_DETECTION_ICL
+       bool
+       help
+         This option is selected by SOF or SST drivers, not users or distros.
+         It enables DSP detection based on PCI class information for
+         IceLake machines
+
+endif ## SND_HDA_INTEL
+
 endif
 
 endmenu
diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c
deleted file mode 100644 (file)
index bbd6c87..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Helper functions for Dell Mic Mute LED control;
- * to be included from codec driver
- */
-
-#if IS_ENABLED(CONFIG_DELL_LAPTOP)
-#include <linux/dell-led.h>
-
-static int (*dell_micmute_led_set_func)(int);
-
-static void dell_micmute_update(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       dell_micmute_led_set_func(spec->micmute_led.led_value);
-}
-
-static void alc_fixup_dell_wmi(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       bool removefunc = false;
-
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               if (!dell_micmute_led_set_func)
-                       dell_micmute_led_set_func = symbol_request(dell_micmute_led_set);
-               if (!dell_micmute_led_set_func) {
-                       codec_warn(codec, "Failed to find dell wmi symbol dell_micmute_led_set\n");
-                       return;
-               }
-
-               removefunc = (dell_micmute_led_set_func(false) < 0) ||
-                       (snd_hda_gen_add_micmute_led(codec,
-                                                    dell_micmute_update) < 0);
-       }
-
-       if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
-               symbol_put(dell_micmute_led_set);
-               dell_micmute_led_set_func = NULL;
-       }
-}
-
-#else /* CONFIG_DELL_LAPTOP */
-static void alc_fixup_dell_wmi(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-}
-
-#endif /* CONFIG_DELL_LAPTOP */
index 0957813939e5cfbcc0d4632059a36c7e8f164616..9f8d59e7e89f4625afab833adf3e0f31fe6d1420 100644 (file)
@@ -36,6 +36,7 @@
 #include "hda_beep.h"
 #include "hda_jack.h"
 #include <sound/hda_hwdep.h>
+#include <sound/hda_component.h>
 
 #define codec_in_pm(codec)             snd_hdac_is_in_pm(&codec->core)
 #define hda_codec_is_power_on(codec)   snd_hdac_is_power_on(&codec->core)
@@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
 static unsigned int hda_set_power_state(struct hda_codec *codec,
                                unsigned int power_state);
 
+/* enable/disable display power per codec */
+static void codec_display_power(struct hda_codec *codec, bool enable)
+{
+       if (codec->display_power_control)
+               snd_hdac_display_power(&codec->bus->core, codec->addr, enable);
+}
+
 /* also called from hda_bind.c */
 void snd_hda_codec_register(struct hda_codec *codec)
 {
@@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
                return;
        if (device_is_registered(hda_codec_dev(codec))) {
                snd_hda_register_beep_device(codec);
-               snd_hdac_link_power(&codec->core, true);
+               codec_display_power(codec, true);
                pm_runtime_enable(hda_codec_dev(codec));
                /* it was powered up in snd_hda_codec_new(), now all done */
                snd_hda_power_down(codec);
@@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
 
        codec->in_freeing = 1;
        snd_hdac_device_unregister(&codec->core);
-       snd_hdac_link_power(&codec->core, false);
+       codec_display_power(codec, false);
        put_device(hda_codec_dev(codec));
        return 0;
 }
@@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
            (codec_has_clkstop(codec) && codec_has_epss(codec) &&
             (state & AC_PWRST_CLK_STOP_OK)))
                snd_hdac_codec_link_down(&codec->core);
-       snd_hdac_link_power(&codec->core, false);
+       codec_display_power(codec, false);
        return 0;
 }
 
@@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev)
 {
        struct hda_codec *codec = dev_to_hda_codec(dev);
 
-       snd_hdac_link_power(&codec->core, true);
+       codec_display_power(codec, true);
        snd_hdac_codec_link_up(&codec->core);
        hda_call_codec_resume(codec);
        pm_runtime_mark_last_busy(dev);
index fe2506672a72049b2dd7fb1c4f69d1f288ce4634..532e081f8b8a243d3fcb1199227ef1883ab76bf6 100644 (file)
@@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
                return azx_rirb_get_response(bus, addr, res);
 }
 
-static int azx_link_power(struct hdac_bus *bus, bool enable)
-{
-       struct azx *chip = bus_to_azx(bus);
-
-       if (chip->ops->link_power)
-               return chip->ops->link_power(chip, enable);
-       else
-               return -EINVAL;
-}
-
 static const struct hdac_bus_ops bus_core_ops = {
        .command = azx_send_cmd,
        .get_response = azx_get_response,
-       .link_power = azx_link_power,
 };
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
index c95097bb5a0c0312a03cce011a0ca16c34462d83..e0c3fcbaa02843586feed1db7dd10bc32d48b55f 100644 (file)
@@ -37,7 +37,7 @@
 #else
 #define AZX_DCAPS_I915_COMPONENT 0             /* NOP */
 #endif
-/* 14 unused */
+#define AZX_DCAPS_INTEL_SHARED (1 << 14)       /* shared with ASoC */
 #define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
 #define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
 /* 17 unused */
 /* 24 unused */
 #define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
 #define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
-#ifdef CONFIG_SND_HDA_I915
-#define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
-#else
-#define AZX_DCAPS_I915_POWERWELL 0             /* NOP */
-#endif
+/* 27 unused */
 #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
 #define AZX_DCAPS_NO_MSI64      (1 << 29)      /* Stick to 32-bit MSIs */
 #define AZX_DCAPS_SEPARATE_STREAM_TAG  (1 << 30) /* capture and playback use separate stream tag */
index 276150f29cda9090178b485b67ac1834824883aa..4095cd7c56c639357324d3bd25587e477b3bdb2e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/leds.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/tlv.h>
@@ -4035,6 +4036,36 @@ int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
 
+#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
+static void call_ledtrig_micmute(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       ledtrig_audio_set(LED_AUDIO_MICMUTE,
+                         spec->micmute_led.led_value ? LED_ON : LED_OFF);
+}
+#endif
+
+/**
+ * snd_hda_gen_fixup_micmute_led - A fixup for mic-mute LED trigger
+ *
+ * Pass this function to the quirk entry if another driver supports the
+ * audio mic-mute LED trigger.  Then this will bind the mixer capture switch
+ * change with the LED.
+ *
+ * Note that this fixup has to be called after other fixup that sets
+ * cap_sync_hook.  Otherwise the chaining wouldn't work.
+ */
+void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
+       if (action == HDA_FIXUP_ACT_PROBE)
+               snd_hda_gen_add_micmute_led(codec, call_ledtrig_micmute);
+#endif
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_fixup_micmute_led);
+
 /*
  * parse digital I/Os and set up NIDs in BIOS auto-parse mode
  */
index 10123664fa619af70a3b9060685060d541106d2e..78d77042b05aa2c3447e6e2d0d7c5d9273c88813 100644 (file)
@@ -357,5 +357,7 @@ int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
 
 int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
                                void (*hook)(struct hda_codec *));
+void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action);
 
 #endif /* __SOUND_HDA_GENERIC_H */
index 76f03abd15ab766190c4d5739f707d81aa0e2d70..e42cc22309771c5ccca02437cc2f6d911abbacd9 100644 (file)
@@ -172,6 +172,9 @@ module_param_array(beep_mode, bool, NULL, 0444);
 MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
                            "(0=off, 1=on) (default=1).");
 #endif
+static int skl_pci_binding;
+module_param_named(pci_binding, skl_pci_binding, int, 0444);
+MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
 
 #ifdef CONFIG_PM
 static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -310,31 +313,28 @@ enum {
 #define AZX_DCAPS_INTEL_HASWELL \
        (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
         AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
-        AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
+        AZX_DCAPS_SNOOP_TYPE(SCH))
 
 /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
 #define AZX_DCAPS_INTEL_BROADWELL \
        (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
         AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
-        AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
+        AZX_DCAPS_SNOOP_TYPE(SCH))
 
 #define AZX_DCAPS_INTEL_BAYTRAIL \
-       (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\
-        AZX_DCAPS_I915_POWERWELL)
+       (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
 
 #define AZX_DCAPS_INTEL_BRASWELL \
        (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
-        AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL)
+        AZX_DCAPS_I915_COMPONENT)
 
 #define AZX_DCAPS_INTEL_SKYLAKE \
        (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
-        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
-        AZX_DCAPS_I915_POWERWELL)
+        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
 
 #define AZX_DCAPS_INTEL_BROXTON \
        (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
-        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
-        AZX_DCAPS_I915_POWERWELL)
+        AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -360,6 +360,7 @@ enum {
         AZX_DCAPS_NO_64BIT |\
         AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
 
+#define AZX_DCAPS_INTEL_DSP_DETECTION(conf) (IS_ENABLED(CONFIG_SND_HDA_INTEL_DSP_DETECTION_##conf) ? AZX_DCAPS_INTEL_SHARED : 0)
 /*
  * vga_switcheroo support
  */
@@ -591,8 +592,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
        struct pci_dev *pci = chip->pci;
        u32 val;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               snd_hdac_set_codec_wakeup(bus, true);
+       snd_hdac_set_codec_wakeup(bus, true);
        if (chip->driver_type == AZX_DRIVER_SKL) {
                pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
                val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
@@ -604,8 +604,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
                val = val | INTEL_HDA_CGCTL_MISCBDCGE;
                pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
        }
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               snd_hdac_set_codec_wakeup(bus, false);
+
+       snd_hdac_set_codec_wakeup(bus, false);
 
        /* reduce dma latency to avoid noise */
        if (IS_BXT(pci))
@@ -667,13 +667,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
        return 0;
 }
 
-/* Enable/disable i915 display power for the link */
-static int azx_intel_link_power(struct azx *chip, bool enable)
-{
-       struct hdac_bus *bus = azx_bus(chip);
-
-       return snd_hdac_display_power(bus, enable);
-}
+#define display_power(chip, enable) \
+       snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
 
 /*
  * Check whether the current DMA position is acceptable for updating
@@ -930,35 +925,75 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
        mutex_unlock(&card_list_lock);
        return 0;
 }
-#else
-#define azx_add_card_list(chip) /* NOP */
-#define azx_del_card_list(chip) /* NOP */
-#endif /* CONFIG_PM */
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
-static int azx_suspend(struct device *dev)
+static bool azx_is_pm_ready(struct snd_card *card)
 {
-       struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
        struct hda_intel *hda;
-       struct hdac_bus *bus;
 
        if (!card)
-               return 0;
-
+               return false;
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
        if (chip->disabled || hda->init_failed || !chip->running)
+               return false;
+       return true;
+}
+
+static void __azx_runtime_suspend(struct azx *chip)
+{
+       azx_stop_chip(chip);
+       azx_enter_link_reset(chip);
+       azx_clear_irq_pending(chip);
+       display_power(chip, false);
+}
+
+static void __azx_runtime_resume(struct azx *chip)
+{
+       struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+       struct hdac_bus *bus = azx_bus(chip);
+       struct hda_codec *codec;
+       int status;
+
+       display_power(chip, true);
+       if (hda->need_i915_power)
+               snd_hdac_i915_set_bclk(bus);
+
+       /* Read STATESTS before controller reset */
+       status = azx_readw(chip, STATESTS);
+
+       azx_init_pci(chip);
+       hda_intel_init_chip(chip, true);
+
+       if (status) {
+               list_for_each_codec(codec, &chip->bus)
+                       if (status & (1 << codec->addr))
+                               schedule_delayed_work(&codec->jackpoll_work,
+                                                     codec->jackpoll_interval);
+       }
+
+       /* power down again for link-controlled chips */
+       if (!hda->need_i915_power)
+               display_power(chip, false);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int azx_suspend(struct device *dev)
+{
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct azx *chip;
+       struct hdac_bus *bus;
+
+       if (!azx_is_pm_ready(card))
                return 0;
 
+       chip = card->private_data;
        bus = azx_bus(chip);
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       azx_clear_irq_pending(chip);
-       azx_stop_chip(chip);
-       azx_enter_link_reset(chip);
+       __azx_runtime_suspend(chip);
        if (bus->irq >= 0) {
                free_irq(bus->irq, chip);
                bus->irq = -1;
@@ -966,9 +1001,6 @@ static int azx_suspend(struct device *dev)
 
        if (chip->msi)
                pci_disable_msi(chip->pci);
-       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               && hda->need_i915_power)
-               snd_hdac_display_power(bus, false);
 
        trace_azx_suspend(chip);
        return 0;
@@ -976,41 +1008,19 @@ static int azx_suspend(struct device *dev)
 
 static int azx_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
-       struct hda_intel *hda;
-       struct hdac_bus *bus;
 
-       if (!card)
+       if (!azx_is_pm_ready(card))
                return 0;
 
        chip = card->private_data;
-       hda = container_of(chip, struct hda_intel, chip);
-       bus = azx_bus(chip);
-       if (chip->disabled || hda->init_failed || !chip->running)
-               return 0;
-
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               snd_hdac_display_power(bus, true);
-               if (hda->need_i915_power)
-                       snd_hdac_i915_set_bclk(bus);
-       }
-
        if (chip->msi)
-               if (pci_enable_msi(pci) < 0)
+               if (pci_enable_msi(chip->pci) < 0)
                        chip->msi = 0;
        if (azx_acquire_irq(chip, 1) < 0)
                return -EIO;
-       azx_init_pci(chip);
-
-       hda_intel_init_chip(chip, true);
-
-       /* power down again for link-controlled chips */
-       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
-           !hda->need_i915_power)
-               snd_hdac_display_power(bus, false);
-
+       __azx_runtime_resume(chip);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
        trace_azx_resume(chip);
@@ -1045,21 +1055,14 @@ static int azx_thaw_noirq(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-#ifdef CONFIG_PM
 static int azx_runtime_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
-       struct hda_intel *hda;
 
-       if (!card)
+       if (!azx_is_pm_ready(card))
                return 0;
-
        chip = card->private_data;
-       hda = container_of(chip, struct hda_intel, chip);
-       if (chip->disabled || hda->init_failed)
-               return 0;
-
        if (!azx_has_pm_runtime(chip))
                return 0;
 
@@ -1067,13 +1070,7 @@ static int azx_runtime_suspend(struct device *dev)
        azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
                  STATESTS_INT_MASK);
 
-       azx_stop_chip(chip);
-       azx_enter_link_reset(chip);
-       azx_clear_irq_pending(chip);
-       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               && hda->need_i915_power)
-               snd_hdac_display_power(azx_bus(chip), false);
-
+       __azx_runtime_suspend(chip);
        trace_azx_runtime_suspend(chip);
        return 0;
 }
@@ -1082,51 +1079,18 @@ static int azx_runtime_resume(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
-       struct hda_intel *hda;
-       struct hdac_bus *bus;
-       struct hda_codec *codec;
-       int status;
 
-       if (!card)
+       if (!azx_is_pm_ready(card))
                return 0;
-
        chip = card->private_data;
-       hda = container_of(chip, struct hda_intel, chip);
-       bus = azx_bus(chip);
-       if (chip->disabled || hda->init_failed)
-               return 0;
-
        if (!azx_has_pm_runtime(chip))
                return 0;
-
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               snd_hdac_display_power(bus, true);
-               if (hda->need_i915_power)
-                       snd_hdac_i915_set_bclk(bus);
-       }
-
-       /* Read STATESTS before controller reset */
-       status = azx_readw(chip, STATESTS);
-
-       azx_init_pci(chip);
-       hda_intel_init_chip(chip, true);
-
-       if (status) {
-               list_for_each_codec(codec, &chip->bus)
-                       if (status & (1 << codec->addr))
-                               schedule_delayed_work(&codec->jackpoll_work,
-                                                     codec->jackpoll_interval);
-       }
+       __azx_runtime_resume(chip);
 
        /* disable controller Wake Up event*/
        azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
                        ~STATESTS_INT_MASK);
 
-       /* power down again for link-controlled chips */
-       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
-           !hda->need_i915_power)
-               snd_hdac_display_power(bus, false);
-
        trace_azx_runtime_resume(chip);
        return 0;
 }
@@ -1167,6 +1131,8 @@ static const struct dev_pm_ops azx_pm = {
 
 #define AZX_PM_OPS     &azx_pm
 #else
+#define azx_add_card_list(chip) /* NOP */
+#define azx_del_card_list(chip) /* NOP */
 #define AZX_PM_OPS     NULL
 #endif /* CONFIG_PM */
 
@@ -1374,11 +1340,8 @@ static int azx_free(struct azx *chip)
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
        release_firmware(chip->fw);
 #endif
+       display_power(chip, false);
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               if (hda->need_i915_power)
-                       snd_hdac_display_power(bus, false);
-       }
        if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
                snd_hdac_i915_exit(bus);
        kfree(hda);
@@ -1935,8 +1898,7 @@ static int azx_first_init(struct azx *chip)
        /* initialize chip */
        azx_init_pci(chip);
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               snd_hdac_i915_set_bclk(bus);
+       snd_hdac_i915_set_bclk(bus);
 
        hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
 
@@ -2078,7 +2040,6 @@ static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
        .pcm_mmap_prepare = pcm_mmap_prepare,
        .position_check = azx_position_check,
-       .link_power = azx_intel_link_power,
 };
 
 static int azx_probe(struct pci_dev *pci,
@@ -2091,6 +2052,28 @@ static int azx_probe(struct pci_dev *pci,
        bool schedule_probe;
        int err;
 
+       /* check if this driver can be used on SKL+ Intel platforms */
+       if (pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) {
+               switch (skl_pci_binding) {
+               case SND_SKL_PCI_BIND_AUTO:
+                       if (pci->class != 0x040300) {
+                               dev_info(&pci->dev, "The DSP is enabled on this platform, aborting probe\n");
+                               return -ENODEV;
+                       }
+                       dev_info(&pci->dev, "No DSP detected, continuing HDaudio legacy probe\n");
+                       break;
+               case SND_SKL_PCI_BIND_LEGACY:
+                       dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, bypassed detection logic\n");
+                       break;
+               case SND_SKL_PCI_BIND_ASOC:
+                       dev_info(&pci->dev, "Module parameter forced binding with SKL+ ASoC driver, aborting probe\n");
+                       return -ENODEV;
+               default:
+                       dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
+                       break;
+               }
+       }
+
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
@@ -2245,10 +2228,13 @@ static int azx_probe_continue(struct azx *chip)
                                goto out_free;
                        } else {
                                /* don't bother any longer */
-                               chip->driver_caps &=
-                                       ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL);
+                               chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
                        }
                }
+
+               /* HSW/BDW controllers need this power */
+               if (CONTROLLER_IN_GPU(pci))
+                       hda->need_i915_power = 1;
        }
 
        /* Request display power well for the HDA controller or codec. For
@@ -2256,18 +2242,7 @@ static int azx_probe_continue(struct azx *chip)
         * this power. For other platforms, like Baytrail/Braswell, only the
         * display codec needs the power and it can be released after probe.
         */
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               /* HSW/BDW controllers need this power */
-               if (CONTROLLER_IN_GPU(pci))
-                       hda->need_i915_power = 1;
-
-               err = snd_hdac_display_power(bus, true);
-               if (err < 0) {
-                       dev_err(chip->card->dev,
-                               "Cannot turn on display power on i915\n");
-                       goto i915_power_fail;
-               }
-       }
+       display_power(chip, true);
 
        err = azx_first_init(chip);
        if (err < 0)
@@ -2315,11 +2290,8 @@ static int azx_probe_continue(struct azx *chip)
                pm_runtime_put_autosuspend(&pci->dev);
 
 out_free:
-       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               && !hda->need_i915_power)
-               snd_hdac_display_power(bus, false);
-
-i915_power_fail:
+       if (err < 0 || !hda->need_i915_power)
+               display_power(chip, false);
        if (err < 0)
                hda->init_failed = 1;
        complete_all(&hda->probe_wait);
@@ -2408,34 +2380,48 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+         AZX_DCAPS_INTEL_DSP_DETECTION(SKL)
+       },
        /* Kabylake */
        { PCI_DEVICE(0x8086, 0xa171),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
        /* Kabylake-LP */
        { PCI_DEVICE(0x8086, 0x9d71),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+         AZX_DCAPS_INTEL_DSP_DETECTION(KBL)
+       },
        /* Kabylake-H */
        { PCI_DEVICE(0x8086, 0xa2f0),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
        /* Coffelake */
        { PCI_DEVICE(0x8086, 0xa348),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+         AZX_DCAPS_INTEL_DSP_DETECTION(CFL)
+       },
        /* Cannonlake */
        { PCI_DEVICE(0x8086, 0x9dc8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+         AZX_DCAPS_INTEL_DSP_DETECTION(CNL)
+       },
        /* Icelake */
        { PCI_DEVICE(0x8086, 0x34c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
+         AZX_DCAPS_INTEL_DSP_DETECTION(ICL)
+       },
        /* Broxton-P(Apollolake) */
        { PCI_DEVICE(0x8086, 0x5a98),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
+         AZX_DCAPS_INTEL_DSP_DETECTION(APL)
+       },
        /* Broxton-T */
        { PCI_DEVICE(0x8086, 0x1a98),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
        /* Gemini-Lake */
        { PCI_DEVICE(0x8086, 0x3198),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
+         AZX_DCAPS_INTEL_DSP_DETECTION(GLK)
+       },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0a0c),
          .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
index c499727920e61c1ac28fb8981000c4963e151745..74b46952fc987441b59f86ba06efce8d1b507ead 100644 (file)
@@ -339,9 +339,15 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
                if (jack->nid) {
                        if (!jack->jack || jack->block_report)
                                continue;
-                       state = get_jack_plug_state(jack->pin_sense);
-                       snd_jack_report(jack->jack,
-                                       state ? jack->type : 0);
+                       state = jack->button_state;
+                       if (get_jack_plug_state(jack->pin_sense))
+                               state |= jack->type;
+                       snd_jack_report(jack->jack, state);
+                       if (jack->button_state) {
+                               snd_jack_report(jack->jack,
+                                               state & ~jack->button_state);
+                               jack->button_state = 0; /* button released */
+                       }
                }
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync);
@@ -379,15 +385,19 @@ static void hda_free_jack_priv(struct snd_jack *jack)
  * @nid: pin NID to assign
  * @name: string name for the jack
  * @phantom_jack: flag to deal as a phantom jack
+ * @type: jack type bits to be reported, 0 for guessing from pincfg
+ * @keymap: optional jack / key mapping
  *
  * This assigns a jack-detection kctl to the given pin.  The kcontrol
  * will have the given name and index.
  */
 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
-                         const char *name, bool phantom_jack)
+                         const char *name, bool phantom_jack,
+                         int type, const struct hda_jack_keymap *keymap)
 {
        struct hda_jack_tbl *jack;
-       int err, state, type;
+       const struct hda_jack_keymap *map;
+       int err, state, buttons;
 
        jack = snd_hda_jack_tbl_new(codec, nid);
        if (!jack)
@@ -395,16 +405,30 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
        if (jack->jack)
                return 0; /* already created */
 
-       type = get_input_jack_type(codec, nid);
-       err = snd_jack_new(codec->card, name, type,
+       if (!type)
+               type = get_input_jack_type(codec, nid);
+
+       buttons = 0;
+       if (keymap) {
+               for (map = keymap; map->type; map++)
+                       buttons |= map->type;
+       }
+
+       err = snd_jack_new(codec->card, name, type | buttons,
                           &jack->jack, true, phantom_jack);
        if (err < 0)
                return err;
 
        jack->phantom_jack = !!phantom_jack;
        jack->type = type;
+       jack->button_state = 0;
        jack->jack->private_data = jack;
        jack->jack->private_free = hda_free_jack_priv;
+       if (keymap) {
+               for (map = keymap; map->type; map++)
+                       snd_jack_set_key(jack->jack, map->type, map->key);
+       }
+
        state = snd_hda_jack_detect(codec, nid);
        snd_jack_report(jack->jack, state ? jack->type : 0);
 
@@ -437,7 +461,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
        if (phantom_jack)
                /* Example final name: "Internal Mic Phantom Jack" */
                strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
-       err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
+       err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL);
        if (err < 0)
                return err;
 
@@ -508,19 +532,25 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
 
-static void call_jack_callback(struct hda_codec *codec,
+static void call_jack_callback(struct hda_codec *codec, unsigned int res,
                               struct hda_jack_tbl *jack)
 {
        struct hda_jack_callback *cb;
 
-       for (cb = jack->callback; cb; cb = cb->next)
+       for (cb = jack->callback; cb; cb = cb->next) {
+               cb->jack = jack;
+               cb->unsol_res = res;
                cb->func(codec, cb);
+       }
        if (jack->gated_jack) {
                struct hda_jack_tbl *gated =
                        snd_hda_jack_tbl_get(codec, jack->gated_jack);
                if (gated) {
-                       for (cb = gated->callback; cb; cb = cb->next)
+                       for (cb = gated->callback; cb; cb = cb->next) {
+                               cb->jack = gated;
+                               cb->unsol_res = res;
                                cb->func(codec, cb);
+                       }
                }
        }
 }
@@ -540,7 +570,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
                return;
        event->jack_dirty = 1;
 
-       call_jack_callback(codec, event);
+       call_jack_callback(codec, res, event);
        snd_hda_jack_report_sync(codec);
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
@@ -566,7 +596,7 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
                if (old_sense == get_jack_plug_state(jack->pin_sense))
                        continue;
                changes = 1;
-               call_jack_callback(codec, jack);
+               call_jack_callback(codec, 0, jack);
        }
        if (changes)
                snd_hda_jack_report_sync(codec);
index e9814c0168ea5d77da2922454ed4256d7ad2a30a..1d713201c160bb501d19183c009051b62277215f 100644 (file)
@@ -13,6 +13,7 @@
 #define __SOUND_HDA_JACK_H
 
 #include <linux/err.h>
+#include <sound/jack.h>
 
 struct auto_pin_cfg;
 struct hda_jack_tbl;
@@ -24,6 +25,8 @@ struct hda_jack_callback {
        hda_nid_t nid;
        hda_jack_callback_fn func;
        unsigned int private_data;      /* arbitrary data */
+       unsigned int unsol_res;         /* unsolicited event bits */
+       struct hda_jack_tbl *jack;      /* associated jack entry */
        struct hda_jack_callback *next;
 };
 
@@ -40,9 +43,15 @@ struct hda_jack_tbl {
        hda_nid_t gating_jack;          /* valid when gating jack plugged */
        hda_nid_t gated_jack;           /* gated is dependent on this jack */
        int type;
+       int button_state;
        struct snd_jack *jack;
 };
 
+struct hda_jack_keymap {
+       enum snd_jack_types type;
+       int key;
+};
+
 struct hda_jack_tbl *
 snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
 struct hda_jack_tbl *
@@ -82,7 +91,8 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
 
 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
-                         const char *name, bool phantom_jack);
+                         const char *name, bool phantom_jack,
+                         int type, const struct hda_jack_keymap *keymap);
 int snd_hda_jack_add_kctls(struct hda_codec *codec,
                           const struct auto_pin_cfg *cfg);
 
index dd7d4242d6d2afeec5cfb5a813ef43d813c0b6be..83befd8d43e83fb399836b9ef094a2306740ac32 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/string.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -344,6 +345,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
        int err;
        unsigned short gcap;
        int irq_id = platform_get_irq(pdev, 0);
+       const char *sname;
+       struct device_node *root;
 
        err = hda_tegra_init_chip(chip, pdev);
        if (err)
@@ -401,8 +404,23 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
                return -ENODEV;
        }
 
+       /* driver name */
        strcpy(card->driver, "tegra-hda");
-       strcpy(card->shortname, "tegra-hda");
+
+       root = of_find_node_by_path("/");
+       sname = of_get_property(root, "compatible", NULL);
+       of_node_put(root);
+       if (!sname) {
+               dev_err(card->dev,
+                       "failed to get compatible property from root node\n");
+               return -ENODEV;
+       }
+       /* shortname for card */
+       if (strlen(sname) > sizeof(card->shortname))
+               dev_info(card->dev, "truncating shortname for card\n");
+       strncpy(card->shortname, sname, sizeof(card->shortname));
+
+       /* longname for card */
        snprintf(card->longname, sizeof(card->longname),
                 "%s at 0x%lx irq %i",
                 card->shortname, bus->addr, bus->irq);
@@ -513,7 +531,7 @@ static void hda_tegra_probe_work(struct work_struct *work)
                goto out_free;
 
        /* create codec instances */
-       err = azx_probe_codecs(chip, 0);
+       err = azx_probe_codecs(chip, 8);
        if (err < 0)
                goto out_free;
 
index 0a567634e5faddafd470220c7a9ebaff88ce8cef..e5bdbc2456822cb835c9644c7bc69468c91a92c7 100644 (file)
@@ -1081,6 +1081,18 @@ enum {
        QUIRK_AE5,
 };
 
+#ifdef CONFIG_PCI
+#define ca0132_quirk(spec)             ((spec)->quirk)
+#define ca0132_use_pci_mmio(spec)      ((spec)->use_pci_mmio)
+#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
+#define ca0132_use_alt_controls(spec)  ((spec)->use_alt_controls)
+#else
+#define ca0132_quirk(spec)             ({ (void)(spec); QUIRK_NONE; })
+#define ca0132_use_alt_functions(spec) ({ (void)(spec); false; })
+#define ca0132_use_pci_mmio(spec)      ({ (void)(spec); false; })
+#define ca0132_use_alt_controls(spec)  ({ (void)(spec); false; })
+#endif
+
 static const struct hda_pintbl alienware_pincfgs[] = {
        { 0x0b, 0x90170110 }, /* Builtin Speaker */
        { 0x0c, 0x411111f0 }, /* N/A */
@@ -3101,7 +3113,7 @@ static void dspload_post_setup(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
        codec_dbg(codec, "---- dspload_post_setup ------\n");
-       if (!spec->use_alt_functions) {
+       if (!ca0132_use_alt_functions(spec)) {
                /*set DSP speaker to 2.0 configuration*/
                chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
                chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000);
@@ -3333,7 +3345,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
        case QUIRK_AE5:
                snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
@@ -3344,6 +3356,8 @@ static void ca0132_gpio_init(struct hda_codec *codec)
                snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
                snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B);
                break;
+       default:
+               break;
        }
 
 }
@@ -3353,7 +3367,7 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
                snd_hda_codec_write(codec, 0x01, 0,
                                AC_VERB_SET_GPIO_DIRECTION, 0x07);
@@ -3372,6 +3386,8 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
                snd_hda_codec_write(codec, 0x01, 0,
                                AC_VERB_SET_GPIO_DATA, 0x0C);
                break;
+       default:
+               break;
        }
 }
 
@@ -4172,7 +4188,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
 
        switch (spec->cur_out_type) {
        case SPEAKER_OUT:
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                        ca0113_mmio_gpio_set(codec, 7, false);
                        ca0113_mmio_gpio_set(codec, 4, true);
@@ -4203,10 +4219,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
                        chipio_set_control_param(codec, 0x0d, 0xa4);
                        chipio_write(codec, 0x18b03c, 0x00000012);
                        break;
+               default:
+                       break;
                }
                break;
        case HEADPHONE_OUT:
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                        ca0113_mmio_gpio_set(codec, 7, true);
                        ca0113_mmio_gpio_set(codec, 4, true);
@@ -4238,10 +4256,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
                        chipio_set_control_param(codec, 0x0d, 0xa1);
                        chipio_write(codec, 0x18b03c, 0x00000012);
                        break;
+               default:
+                       break;
                }
                break;
        case SURROUND_OUT:
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                        ca0113_mmio_gpio_set(codec, 7, false);
                        ca0113_mmio_gpio_set(codec, 4, true);
@@ -4272,6 +4292,8 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
                        chipio_set_control_param(codec, 0x0d, 0xa4);
                        chipio_write(codec, 0x18b03c, 0x00000012);
                        break;
+               default:
+                       break;
                }
                break;
        }
@@ -4446,7 +4468,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
                to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
        struct hda_jack_tbl *jack;
 
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ca0132_alt_select_out(spec->codec);
        else
                ca0132_select_out(spec->codec);
@@ -4530,14 +4552,14 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
 
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
                chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (spec->quirk == QUIRK_R3DI)
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
                        chipio_set_conn_rate(codec, 0x0F, SR_96_000);
 
 
                if (spec->in_enum_val == REAR_LINE_IN)
                        tmp = FLOAT_ZERO;
                else {
-                       if (spec->quirk == QUIRK_SBZ)
+                       if (ca0132_quirk(spec) == QUIRK_SBZ)
                                tmp = FLOAT_THREE;
                        else
                                tmp = FLOAT_ONE;
@@ -4549,7 +4571,7 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
                codec_dbg(codec, "%s: on.", __func__);
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
                chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
-               if (spec->quirk == QUIRK_R3DI)
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
                        chipio_set_conn_rate(codec, 0x0F, SR_16_000);
 
                if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID])
@@ -4645,7 +4667,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
        switch (spec->cur_mic_type) {
        case REAR_MIC:
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
                        ca0113_mmio_gpio_set(codec, 0, false);
@@ -4669,14 +4691,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
                chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (spec->quirk == QUIRK_R3DI)
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
                        chipio_set_conn_rate(codec, 0x0F, SR_96_000);
 
                dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x0000000C);
@@ -4689,12 +4711,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x0000004C);
                        break;
+               default:
+                       break;
                }
                ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
        case REAR_LINE_IN:
                ca0132_mic_boost_set(codec, 0);
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
                        ca0113_mmio_gpio_set(codec, 0, false);
@@ -4705,28 +4729,32 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                case QUIRK_AE5:
                        ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
                        break;
+               default:
+                       break;
                }
 
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
                chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (spec->quirk == QUIRK_R3DI)
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
                        chipio_set_conn_rate(codec, 0x0F, SR_96_000);
 
                tmp = FLOAT_ZERO;
                dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                case QUIRK_AE5:
                        chipio_write(codec, 0x18B098, 0x00000000);
                        chipio_write(codec, 0x18B09C, 0x00000000);
                        break;
+               default:
+                       break;
                }
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
                break;
        case FRONT_MIC:
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                case QUIRK_R3D:
                        ca0113_mmio_gpio_set(codec, 0, true);
@@ -4748,7 +4776,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
                chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
                chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (spec->quirk == QUIRK_R3DI)
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
                        chipio_set_conn_rate(codec, 0x0F, SR_96_000);
 
                dspio_set_uint_param(codec, 0x80, 0x00, tmp);
@@ -4756,7 +4784,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                chipio_set_stream_control(codec, 0x03, 1);
                chipio_set_stream_control(codec, 0x04, 1);
 
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x000000CC);
@@ -4765,6 +4793,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x0000004C);
                        break;
+               default:
+                       break;
                }
                ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
@@ -4859,7 +4889,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                        val = 0;
 
                /* If Voice Focus on SBZ, set to two channel. */
-               if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
+               if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
                                && (spec->cur_mic_type != REAR_LINE_IN)) {
                        if (spec->effects_switch[CRYSTAL_VOICE -
                                                 EFFECT_START_NID]) {
@@ -4878,7 +4908,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                 * For SBZ noise reduction, there's an extra command
                 * to module ID 0x47. No clue why.
                 */
-               if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
+               if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
                                && (spec->cur_mic_type != REAR_LINE_IN)) {
                        if (spec->effects_switch[CRYSTAL_VOICE -
                                                 EFFECT_START_NID]) {
@@ -4894,7 +4924,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                }
 
                /* If rear line in disable effects. */
-               if (spec->use_alt_functions &&
+               if (ca0132_use_alt_functions(spec) &&
                                spec->in_enum_val == REAR_LINE_IN)
                        val = 0;
        }
@@ -4924,7 +4954,7 @@ static int ca0132_pe_switch_set(struct hda_codec *codec)
        codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
                    spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
 
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ca0132_alt_select_out(codec);
 
        i = OUT_EFFECT_START_NID - EFFECT_START_NID;
@@ -4984,7 +5014,7 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec)
 
        /* set correct vipsource */
        oldval = stop_mic1(codec);
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ret |= ca0132_alt_set_vipsource(codec, 1);
        else
                ret |= ca0132_set_vipsource(codec, 1);
@@ -5053,7 +5083,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
                auto_jack =
                        spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
                if (!auto_jack) {
-                       if (spec->use_alt_functions)
+                       if (ca0132_use_alt_functions(spec))
                                ca0132_alt_select_out(codec);
                        else
                                ca0132_select_out(codec);
@@ -5070,7 +5100,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
        }
 
        if (nid == VNID_HP_ASEL) {
-               if (spec->use_alt_functions)
+               if (ca0132_use_alt_functions(spec))
                        ca0132_alt_select_out(codec);
                else
                        ca0132_select_out(codec);
@@ -5784,7 +5814,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
        /* mic boost */
        if (nid == spec->input_pins[0]) {
                spec->cur_mic_boost = *valp;
-               if (spec->use_alt_functions) {
+               if (ca0132_use_alt_functions(spec)) {
                        if (spec->in_enum_val != REAR_LINE_IN)
                                changed = ca0132_mic_boost_set(codec, *valp);
                } else {
@@ -6080,7 +6110,7 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
        /* If using alt_controls, add FX: prefix. But, don't add FX:
         * prefix to OutFX or InFX enable controls.
         */
-       if ((spec->use_alt_controls) && (nid <= IN_EFFECT_END_NID))
+       if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
                sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
        else
                sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
@@ -6357,7 +6387,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
                        return err;
        }
        /* Setup vmaster with surround slaves for desktop ca0132 devices */
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
                                        spec->tlv);
                snd_hda_add_vmaster(codec, "Master Playback Volume",
@@ -6377,7 +6407,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
        num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
        for (i = 0; i < num_fx; i++) {
                /* Desktop cards break if Echo Cancellation is used. */
-               if (spec->use_pci_mmio) {
+               if (ca0132_use_pci_mmio(spec)) {
                        if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
                                                OUT_EFFECTS_COUNT))
                                continue;
@@ -6394,7 +6424,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
         * EQ presets, and Smart Volume presets. Also, change names to add FX
         * prefix, and change PlayEnhancement and CrystalVoice to match.
         */
-       if (spec->use_alt_controls) {
+       if (ca0132_use_alt_controls(spec)) {
                err = ca0132_alt_add_svm_enum(codec);
                if (err < 0)
                        return err;
@@ -6448,7 +6478,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
         * to select the new outputs and inputs, plus add the new mic boost
         * setting control.
         */
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                err = ca0132_alt_add_output_enum(codec);
                if (err < 0)
                        return err;
@@ -6459,14 +6489,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
                 * ZxR only has microphone input, there is no front panel
                 * header on the card, and aux-in is handled by the DBPro board.
                 */
-               if (spec->quirk != QUIRK_ZXR) {
+               if (ca0132_quirk(spec) != QUIRK_ZXR) {
                        err = ca0132_alt_add_input_enum(codec);
                        if (err < 0)
                                return err;
                }
        }
 
-       if (spec->quirk == QUIRK_AE5) {
+       if (ca0132_quirk(spec) == QUIRK_AE5) {
                err = ae5_add_headphone_gain_enum(codec);
                if (err < 0)
                        return err;
@@ -6475,7 +6505,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
                        return err;
        }
 
-       if (spec->quirk == QUIRK_ZXR) {
+       if (ca0132_quirk(spec) == QUIRK_ZXR) {
                err = zxr_add_headphone_gain_switch(codec);
                if (err < 0)
                        return err;
@@ -6505,7 +6535,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
                        return err;
        }
 
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ca0132_alt_add_chmap_ctls(codec);
 
        return 0;
@@ -6583,7 +6613,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
        info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
        if (!info)
                return -ENOMEM;
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                info->own_chmap = true;
                info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
                        = ca0132_alt_chmaps;
@@ -6597,7 +6627,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
 
        /* With the DSP enabled, desktops don't use this ADC. */
-       if (!spec->use_alt_functions) {
+       if (!ca0132_use_alt_functions(spec)) {
                info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
                if (!info)
                        return -ENOMEM;
@@ -6795,7 +6825,7 @@ static void ca0132_init_dmic(struct hda_codec *codec)
         * Bit   6: set to select Data2, clear for Data1
         * Bit   7: set to enable DMic, clear for AMic
         */
-       if (spec->quirk == QUIRK_ALIENWARE_M17XR4)
+       if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
                val = 0x33;
        else
                val = 0x23;
@@ -6877,7 +6907,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
        /* Mic 1 Setup */
        chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
        chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-       if (spec->quirk == QUIRK_R3DI) {
+       if (ca0132_quirk(spec) == QUIRK_R3DI) {
                chipio_set_conn_rate(codec, 0x0F, SR_96_000);
                tmp = FLOAT_ONE;
        } else
@@ -6887,7 +6917,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
        /* Mic 2 setup (not present on desktop cards) */
        chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
        chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
-       if (spec->quirk == QUIRK_R3DI)
+       if (ca0132_quirk(spec) == QUIRK_R3DI)
                chipio_set_conn_rate(codec, 0x0F, SR_96_000);
        tmp = FLOAT_ZERO;
        dspio_set_uint_param(codec, 0x80, 0x01, tmp);
@@ -6949,7 +6979,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
        chipio_set_stream_channels(codec, 0x0C, 6);
        chipio_set_stream_control(codec, 0x0C, 1);
        /* No clue what these control */
-       if (spec->quirk == QUIRK_SBZ) {
+       if (ca0132_quirk(spec) == QUIRK_SBZ) {
                chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
                chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
                chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
@@ -6962,7 +6992,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
                chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
                chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
                chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
-       } else if (spec->quirk == QUIRK_ZXR) {
+       } else if (ca0132_quirk(spec) == QUIRK_ZXR) {
                chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
                chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
                chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
@@ -6992,7 +7022,7 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
         * why this is, but multiple tests have confirmed it.
         */
        for (i = 0; i < 2; i++) {
-               switch (spec->quirk) {
+               switch (ca0132_quirk(spec)) {
                case QUIRK_SBZ:
                case QUIRK_AE5:
                        tmp = 0x00000003;
@@ -7021,6 +7051,8 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
                        tmp = 0x00000000;
                        dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
                        break;
+               default:
+                       break;
                }
                msleep(100);
        }
@@ -7043,7 +7075,7 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
        chipio_set_stream_control(codec, 0x03, 1);
        chipio_set_stream_control(codec, 0x04, 1);
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
                chipio_write(codec, 0x18b098, 0x0000000c);
                chipio_write(codec, 0x18b09C, 0x0000000c);
@@ -7052,6 +7084,8 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
                chipio_write(codec, 0x18b098, 0x0000000c);
                chipio_write(codec, 0x18b09c, 0x0000004c);
                break;
+       default:
+               break;
        }
 }
 
@@ -7273,7 +7307,7 @@ static void r3d_setup_defaults(struct hda_codec *codec)
        /* Set speaker source? */
        dspio_set_uint_param(codec, 0x32, 0x00, tmp);
 
-       if (spec->quirk == QUIRK_R3DI)
+       if (ca0132_quirk(spec) == QUIRK_R3DI)
                r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
 
        /* Setup effect defaults */
@@ -7420,7 +7454,7 @@ static void ca0132_init_flags(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1);
                chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1);
                chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1);
@@ -7453,7 +7487,7 @@ static void ca0132_init_params(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
                chipio_set_conn_rate(codec, 0x0B, SR_48_000);
                chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0);
@@ -7490,7 +7524,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
         * can use the default firmware, but I'll leave the option in case
         * it needs it again.
         */
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
        case QUIRK_R3D:
        case QUIRK_AE5:
@@ -7564,7 +7598,7 @@ static void ca0132_download_dsp(struct hda_codec *codec)
        }
 
        /* For codecs using alt functions, this is already done earlier */
-       if (spec->dsp_state == DSP_DOWNLOADED && (!spec->use_alt_functions))
+       if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
                ca0132_set_dsp_msr(codec, true);
 }
 
@@ -7601,7 +7635,7 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ca0132_alt_select_in(codec);
        else
                ca0132_select_mic(codec);
@@ -7616,7 +7650,7 @@ static void ca0132_init_unsol(struct hda_codec *codec)
        snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
                                            ca0132_process_dsp_response);
        /* Front headphone jack detection */
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                snd_hda_jack_detect_enable_callback(codec,
                        spec->unsol_tag_front_hp, hp_callback);
 }
@@ -7706,7 +7740,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
        mutex_init(&spec->chipio_mutex);
 
        spec->cur_out_type = SPEAKER_OUT;
-       if (!spec->use_alt_functions)
+       if (!ca0132_use_alt_functions(spec))
                spec->cur_mic_type = DIGITAL_MIC;
        else
                spec->cur_mic_type = REAR_MIC;
@@ -7732,7 +7766,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
         * Sets defaults for the effect slider controls, only for alternative
         * ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
         */
-       if (spec->use_alt_controls) {
+       if (ca0132_use_alt_controls(spec)) {
                spec->xbass_xover_freq = 8;
                for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
                        spec->fx_ctl_val[i] = effect_slider_defaults[i];
@@ -7747,7 +7781,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
         * the daughter board. So, there is no input enum control, and we need
         * to make sure that spec->in_enum_val is set properly.
         */
-       if (spec->quirk == QUIRK_ZXR)
+       if (ca0132_quirk(spec) == QUIRK_ZXR)
                spec->in_enum_val = REAR_MIC;
 
 #ifdef ENABLE_TUNING_CONTROLS
@@ -8088,27 +8122,27 @@ static void ca0132_mmio_init(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000001, spec->mem_base + 0x400);
        else
                writel(0x00000000, spec->mem_base + 0x400);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000001, spec->mem_base + 0x408);
        else
                writel(0x00000000, spec->mem_base + 0x408);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000001, spec->mem_base + 0x40c);
        else
                writel(0x00000000, spec->mem_base + 0x40C);
 
-       if (spec->quirk == QUIRK_ZXR)
+       if (ca0132_quirk(spec) == QUIRK_ZXR)
                writel(0x00880640, spec->mem_base + 0x01C);
        else
                writel(0x00880680, spec->mem_base + 0x01C);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000080, spec->mem_base + 0xC0C);
        else
                writel(0x00000083, spec->mem_base + 0xC0C);
@@ -8116,7 +8150,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
        writel(0x00000030, spec->mem_base + 0xC00);
        writel(0x00000000, spec->mem_base + 0xC04);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000000, spec->mem_base + 0xC0C);
        else
                writel(0x00000003, spec->mem_base + 0xC0C);
@@ -8125,7 +8159,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
        writel(0x00000003, spec->mem_base + 0xC0C);
        writel(0x00000003, spec->mem_base + 0xC0C);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                writel(0x00000001, spec->mem_base + 0xC08);
        else
                writel(0x000000C1, spec->mem_base + 0xC08);
@@ -8136,7 +8170,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
        writel(0x000000C1, spec->mem_base + 0xC08);
        writel(0x00000080, spec->mem_base + 0xC04);
 
-       if (spec->quirk == QUIRK_AE5) {
+       if (ca0132_quirk(spec) == QUIRK_AE5) {
                writel(0x00000000, spec->mem_base + 0x42c);
                writel(0x00000000, spec->mem_base + 0x46c);
                writel(0x00000000, spec->mem_base + 0x4ac);
@@ -8211,7 +8245,7 @@ static void ca0132_alt_init(struct hda_codec *codec)
 
        ca0132_alt_vol_setup(codec);
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
                codec_dbg(codec, "SBZ alt_init");
                ca0132_gpio_init(codec);
@@ -8248,6 +8282,8 @@ static void ca0132_alt_init(struct hda_codec *codec)
                snd_hda_sequence_write(codec, spec->chip_init_verbs);
                snd_hda_sequence_write(codec, spec->desktop_init_verbs);
                break;
+       default:
+               break;
        }
 }
 
@@ -8274,7 +8310,7 @@ static int ca0132_init(struct hda_codec *codec)
                        spec->dsp_reload = true;
                        spec->dsp_state = DSP_DOWNLOAD_INIT;
                } else {
-                       if (spec->quirk == QUIRK_SBZ)
+                       if (ca0132_quirk(spec) == QUIRK_SBZ)
                                sbz_dsp_startup_check(codec);
                        return 0;
                }
@@ -8284,12 +8320,12 @@ static int ca0132_init(struct hda_codec *codec)
                spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
 
-       if (spec->use_pci_mmio)
+       if (ca0132_use_pci_mmio(spec))
                ca0132_mmio_init(codec);
 
        snd_hda_power_up_pm(codec);
 
-       if (spec->quirk == QUIRK_AE5)
+       if (ca0132_quirk(spec) == QUIRK_AE5)
                ae5_register_set(codec);
 
        ca0132_init_unsol(codec);
@@ -8298,14 +8334,14 @@ static int ca0132_init(struct hda_codec *codec)
 
        snd_hda_sequence_write(codec, spec->base_init_verbs);
 
-       if (spec->use_alt_functions)
+       if (ca0132_use_alt_functions(spec))
                ca0132_alt_init(codec);
 
        ca0132_download_dsp(codec);
 
        ca0132_refresh_widget_caps(codec);
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_R3DI:
        case QUIRK_R3D:
                r3d_setup_defaults(codec);
@@ -8334,7 +8370,7 @@ static int ca0132_init(struct hda_codec *codec)
 
        init_input(codec, cfg->dig_in_pin, spec->dig_in);
 
-       if (!spec->use_alt_functions) {
+       if (!ca0132_use_alt_functions(spec)) {
                snd_hda_sequence_write(codec, spec->chip_init_verbs);
                snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
                            VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D);
@@ -8342,11 +8378,11 @@ static int ca0132_init(struct hda_codec *codec)
                            VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20);
        }
 
-       if (spec->quirk == QUIRK_SBZ)
+       if (ca0132_quirk(spec) == QUIRK_SBZ)
                ca0132_gpio_setup(codec);
 
        snd_hda_sequence_write(codec, spec->spec_init_verbs);
-       if (spec->use_alt_functions) {
+       if (ca0132_use_alt_functions(spec)) {
                ca0132_alt_select_out(codec);
                ca0132_alt_select_in(codec);
        } else {
@@ -8391,7 +8427,7 @@ static void ca0132_free(struct hda_codec *codec)
 
        cancel_delayed_work_sync(&spec->unsol_hp_work);
        snd_hda_power_up(codec);
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
                sbz_exit_chip(codec);
                break;
@@ -8407,13 +8443,15 @@ static void ca0132_free(struct hda_codec *codec)
        case QUIRK_R3DI:
                r3di_gpio_shutdown(codec);
                break;
+       default:
+               break;
        }
 
        snd_hda_sequence_write(codec, spec->base_exit_verbs);
        ca0132_exit_chip(codec);
 
        snd_hda_power_down(codec);
-       if (spec->mem_base)
+       if (IS_ENABLED(CONFIG_PCI) && spec->mem_base)
                pci_iounmap(codec->bus->pci, spec->mem_base);
        kfree(spec->spec_init_verbs);
        kfree(codec->spec);
@@ -8461,12 +8499,12 @@ static void ca0132_config(struct hda_codec *codec)
        spec->multiout.dac_nids = spec->dacs;
        spec->multiout.num_dacs = 3;
 
-       if (!spec->use_alt_functions)
+       if (!ca0132_use_alt_functions(spec))
                spec->multiout.max_channels = 2;
        else
                spec->multiout.max_channels = 6;
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_ALIENWARE:
                codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
                snd_hda_apply_pincfgs(codec, alienware_pincfgs);
@@ -8491,9 +8529,11 @@ static void ca0132_config(struct hda_codec *codec)
                codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
                snd_hda_apply_pincfgs(codec, ae5_pincfgs);
                break;
+       default:
+               break;
        }
 
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_ALIENWARE:
                spec->num_outputs = 2;
                spec->out_pins[0] = 0x0b; /* speaker out */
@@ -8654,7 +8694,7 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
         * Since desktop cards use pci_mmio, this can be used to determine
         * whether or not to use these verbs instead of a separate bool.
         */
-       if (spec->use_pci_mmio)
+       if (ca0132_use_pci_mmio(spec))
                spec->desktop_init_verbs = ca0132_init_verbs1;
        spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
                                        sizeof(struct hda_verb),
@@ -8729,11 +8769,10 @@ static int patch_ca0132(struct hda_codec *codec)
                spec->quirk = quirk->value;
        else
                spec->quirk = QUIRK_NONE;
-
-       if (spec->quirk == QUIRK_SBZ)
+       if (ca0132_quirk(spec) == QUIRK_SBZ)
                sbz_detect_quirk(codec);
 
-       if (spec->quirk == QUIRK_ZXR_DBPRO)
+       if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
                codec->patch_ops = dbpro_patch_ops;
        else
                codec->patch_ops = ca0132_patch_ops;
@@ -8746,7 +8785,7 @@ static int patch_ca0132(struct hda_codec *codec)
        spec->num_mixers = 1;
 
        /* Set which mixers each quirk uses. */
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
                spec->mixers[0] = desktop_mixer;
                snd_hda_codec_set_name(codec, "Sound Blaster Z");
@@ -8775,7 +8814,7 @@ static int patch_ca0132(struct hda_codec *codec)
        }
 
        /* Setup whether or not to use alt functions/controls/pci_mmio */
-       switch (spec->quirk) {
+       switch (ca0132_quirk(spec)) {
        case QUIRK_SBZ:
        case QUIRK_R3D:
        case QUIRK_AE5:
@@ -8796,6 +8835,7 @@ static int patch_ca0132(struct hda_codec *codec)
                break;
        }
 
+#ifdef CONFIG_PCI
        if (spec->use_pci_mmio) {
                spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
                if (spec->mem_base == NULL) {
@@ -8803,6 +8843,7 @@ static int patch_ca0132(struct hda_codec *codec)
                        spec->quirk = QUIRK_NONE;
                }
        }
+#endif
 
        spec->base_init_verbs = ca0132_base_init_verbs;
        spec->base_exit_verbs = ca0132_base_exit_verbs;
index 950e02e717669a7b80ba774ff9d250b9bbb9940e..51cc6589443f5f12e21c5ea6e66a6e30a6a445cc 100644 (file)
@@ -923,6 +923,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
index 67099cbb6be2f24906f6f365274e70b4e6c00256..46f88dc7b7e8fb1e0b215eae8fe1c2e7e4a5cd31 100644 (file)
@@ -2142,7 +2142,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
                strncat(hdmi_str, " Phantom",
                        sizeof(hdmi_str) - strlen(hdmi_str) - 1);
        ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str,
-                                   phantom_jack);
+                                   phantom_jack, 0, NULL);
        if (ret < 0)
                return ret;
        jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
@@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid)
        intel_haswell_enable_all_pins(codec, true);
        intel_haswell_fixup_enable_dp12(codec);
 
-       /* For Haswell/Broadwell, the controller is also in the power well and
-        * can cover the codec power request, and so need not set this flag.
-        */
-       if (!is_haswell(codec) && !is_broadwell(codec))
-               codec->core.link_power_control = 1;
+       codec->display_power_control = 1;
 
        codec->patch_ops.set_power_state = haswell_set_power_state;
        codec->depop_delay = 0;
@@ -2656,7 +2652,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
        /* For Valleyview/Cherryview, only the display codec is in the display
         * power well and can use link_power ops to request/release the power.
         */
-       codec->core.link_power_control = 1;
+       codec->display_power_control = 1;
 
        codec->depop_delay = 0;
        codec->auto_runtime_pm = 1;
@@ -3834,6 +3830,10 @@ HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",      patch_tegra_hdmi),
 HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",   patch_tegra_hdmi),
 HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",   patch_tegra_hdmi),
 HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",        patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
 HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",  patch_nvhdmi),
index 15021c83937284ff1eab5dd2f7b59f736a35626c..a4f4a9dd488df28a6f1aee4548d1ae68aa61c7cd 100644 (file)
@@ -5380,6 +5380,66 @@ static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
        snd_hda_override_wcaps(codec, 0x03, 0);
 }
 
+static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
+       { SND_JACK_BTN_0, KEY_PLAYPAUSE },
+       { SND_JACK_BTN_1, KEY_VOICECOMMAND },
+       { SND_JACK_BTN_2, KEY_VOLUMEUP },
+       { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
+       {}
+};
+
+static void alc_headset_btn_callback(struct hda_codec *codec,
+                                    struct hda_jack_callback *jack)
+{
+       int report = 0;
+
+       if (jack->unsol_res & (7 << 13))
+               report |= SND_JACK_BTN_0;
+
+       if (jack->unsol_res  & (1 << 16 | 3 << 8))
+               report |= SND_JACK_BTN_1;
+
+       /* Volume up key */
+       if (jack->unsol_res & (7 << 23))
+               report |= SND_JACK_BTN_2;
+
+       /* Volume down key */
+       if (jack->unsol_res & (7 << 10))
+               report |= SND_JACK_BTN_3;
+
+       jack->jack->button_state = report;
+}
+
+static void alc_fixup_headset_jack(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_jack_detect_enable_callback(codec, 0x55,
+                                                   alc_headset_btn_callback);
+               snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
+                                     SND_JACK_HEADSET, alc_headset_btn_keymap);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               switch (codec->core.vendor_id) {
+               case 0x10ec0225:
+               case 0x10ec0295:
+               case 0x10ec0299:
+                       alc_write_coef_idx(codec, 0x48, 0xd011);
+                       alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+                       alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
+                       break;
+               case 0x10ec0236:
+               case 0x10ec0256:
+                       alc_write_coef_idx(codec, 0x48, 0xd011);
+                       alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+                       break;
+               }
+               break;
+       }
+}
+
 /* for hda_fixup_thinkpad_acpi() */
 #include "thinkpad_helper.c"
 
@@ -5390,9 +5450,6 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
        hda_fixup_thinkpad_acpi(codec, fix, action);
 }
 
-/* for dell wmi mic mute led */
-#include "dell_wmi_helper.c"
-
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -5470,7 +5527,7 @@ enum {
        ALC292_FIXUP_TPT440_DOCK,
        ALC292_FIXUP_TPT440,
        ALC283_FIXUP_HEADSET_MIC,
-       ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
+       ALC255_FIXUP_MIC_MUTE_LED,
        ALC282_FIXUP_ASPIRE_V5_PINS,
        ALC280_FIXUP_HP_GPIO4,
        ALC286_FIXUP_HP_GPIO_LED,
@@ -5515,6 +5572,7 @@ enum {
        ALC298_FIXUP_TPT470_DOCK,
        ALC255_FIXUP_DUMMY_LINEOUT_VERB,
        ALC255_FIXUP_DELL_HEADSET_MIC,
+       ALC256_FIXUP_HUAWEI_MBXP_PINS,
        ALC295_FIXUP_HP_X360,
        ALC221_FIXUP_HP_HEADSET_MIC,
        ALC285_FIXUP_LENOVO_HEADPHONE_NOISE,
@@ -5523,6 +5581,7 @@ enum {
        ALC294_FIXUP_ASUS_MIC,
        ALC294_FIXUP_ASUS_HEADSET_MIC,
        ALC294_FIXUP_ASUS_SPK,
+       ALC225_FIXUP_HEADSET_JACK,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5770,7 +5829,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
                .chained = true,
-               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
        },
        [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -5794,6 +5853,24 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MIC
        },
+       [ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x12, 0x90a60130},
+                       {0x13, 0x40000000},
+                       {0x14, 0x90170110},
+                       {0x18, 0x411111f0},
+                       {0x19, 0x04a11040},
+                       {0x1a, 0x411111f0},
+                       {0x1b, 0x90170112},
+                       {0x1d, 0x40759a05},
+                       {0x1e, 0x411111f0},
+                       {0x21, 0x04211020},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
        [ALC269_FIXUP_ASUS_X101_FUNC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_x101_headset_mic,
@@ -5996,7 +6073,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc255,
                .chained = true,
-               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
        },
        [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -6031,9 +6108,9 @@ static const struct hda_fixup alc269_fixups[] = {
                        { },
                },
        },
-       [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
+       [ALC255_FIXUP_MIC_MUTE_LED] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_dell_wmi,
+               .v.func = snd_hda_gen_fixup_micmute_led,
        },
        [ALC282_FIXUP_ASPIRE_V5_PINS] = {
                .type = HDA_FIXUP_PINS,
@@ -6092,7 +6169,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_dell_alc288,
                .chained = true,
-               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
        },
        [ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
                .type = HDA_FIXUP_PINS,
@@ -6441,6 +6518,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
        },
+       [ALC225_FIXUP_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6573,6 +6654,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
        SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -6680,6 +6762,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       SND_PCI_QUIRK(0x19e5, 0x3200, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
+       SND_PCI_QUIRK(0x19e5, 0x3201, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
+       SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
 
 #if 0
@@ -6805,7 +6890,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
        {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
        {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
-       {.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"},
+       {.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"},
        {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
        {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
        {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
@@ -6844,6 +6929,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
        {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
        {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
+       {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-sense-combo"},
        {}
 };
 #define ALC225_STANDARD_PINS \
index 568575b72f2f7269c727a202f6544b6f51a57d03..4089feb8c68e339fc33bbbb26591a13b909daf0f 100644 (file)
@@ -3,12 +3,11 @@
  * to be included from codec driver
  */
 
-#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
+#if IS_ENABLED(CONFIG_THINKPAD_ACPI) && IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
 
 #include <linux/acpi.h>
-#include <linux/thinkpad_acpi.h>
+#include <linux/leds.h>
 
-static int (*led_set_func)(int, bool);
 static void (*old_vmaster_hook)(void *, int);
 
 static bool is_thinkpad(struct hda_codec *codec)
@@ -23,50 +22,20 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
        if (old_vmaster_hook)
                old_vmaster_hook(private_data, enabled);
 
-       if (led_set_func)
-               led_set_func(TPACPI_LED_MUTE, !enabled);
-}
-
-static void update_tpacpi_micmute(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
+       ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
 }
 
 static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
 {
        struct hda_gen_spec *spec = codec->spec;
-       bool removefunc = false;
 
        if (action == HDA_FIXUP_ACT_PROBE) {
                if (!is_thinkpad(codec))
                        return;
-               if (!led_set_func)
-                       led_set_func = symbol_request(tpacpi_led_set);
-               if (!led_set_func) {
-                       codec_warn(codec,
-                                  "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
-                       return;
-               }
-
-               removefunc = true;
-               if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
-                       old_vmaster_hook = spec->vmaster_mute.hook;
-                       spec->vmaster_mute.hook = update_tpacpi_mute_led;
-                       removefunc = false;
-               }
-               if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
-                   !snd_hda_gen_add_micmute_led(codec,
-                                                update_tpacpi_micmute))
-                       removefunc = false;
-       }
-
-       if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
-               symbol_put(tpacpi_led_set);
-               led_set_func = NULL;
-               old_vmaster_hook = NULL;
+               old_vmaster_hook = spec->vmaster_mute.hook;
+               spec->vmaster_mute.hook = update_tpacpi_mute_led;
+               snd_hda_gen_fixup_micmute_led(codec, fix, action);
        }
 }
 
index 1bff4b1b39cd04651f16efa1e151ca87c2804d9c..ba99ff0e93e0307aebc79d7dd2e59fb2d7a3b5fb 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/math64.h>
 #include <linux/vmalloc.h>
 #include <linux/io.h>
+#include <linux/nospec.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -4092,15 +4093,16 @@ static int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
                                    struct snd_pcm_channel_info *info)
 {
        struct hdsp *hdsp = snd_pcm_substream_chip(substream);
-       int mapped_channel;
+       unsigned int channel = info->channel;
 
-       if (snd_BUG_ON(info->channel >= hdsp->max_channels))
+       if (snd_BUG_ON(channel >= hdsp->max_channels))
                return -EINVAL;
+       channel = array_index_nospec(channel, hdsp->max_channels);
 
-       if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
+       if (hdsp->channel_map[channel] < 0)
                return -EINVAL;
 
-       info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
+       info->offset = hdsp->channel_map[channel] * HDSP_CHANNEL_BUFFER_BYTES;
        info->first = 0;
        info->step = 32;
        return 0;
index 48dd44f8e914c3270b80da68de91d71db13086d1..d692e4070167bff00d714cd93c8a8a9d366cd692 100644 (file)
@@ -908,7 +908,7 @@ static void detect_byte_swap(struct snd_pmac *chip)
 
        /* if seems that Keylargo can't byte-swap  */
        for (mio = chip->node->parent; mio; mio = mio->parent) {
-               if (strcmp(mio->name, "mac-io") == 0) {
+               if (of_node_name_eq(mio, "mac-io")) {
                        if (of_device_is_compatible(mio, "Keylargo"))
                                chip->can_byte_swap = 0;
                        break;
@@ -1313,7 +1313,7 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
        } else if (chip->is_pbook_G3) {
                struct device_node* mio;
                for (mio = chip->node->parent; mio; mio = mio->parent) {
-                       if (strcmp(mio->name, "mac-io") == 0) {
+                       if (of_node_name_eq(mio, "mac-io")) {
                                struct resource r;
                                if (of_address_to_resource(mio, 0, &r) == 0)
                                        chip->macio_base =
index 0779a29122379b6368a8e62a7602b857fb32f8ff..6d7ffffcce95b6a7b97e1ca046eefb2f30309841 100644 (file)
@@ -1365,8 +1365,8 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip)
        mix->anded_reset = 0;
        mix->reset_on_sleep = 1;
 
-       for (np = chip->node->child; np; np = np->sibling) {
-               if (!strcmp(np->name, "sound")) {
+       for_each_child_of_node(chip->node, np) {
+               if (of_node_name_eq(np, "sound")) {
                        if (of_get_property(np, "has-anded-reset", NULL))
                                mix->anded_reset = 1;
                        if (of_get_property(np, "layout-id", NULL))
index 1cf11cf51e1dd6912c3bdce14c9e651b4fd955c2..6592a422a047252e74754feec147c4cf6244f55a 100644 (file)
@@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/bcm/Kconfig"
 source "sound/soc/cirrus/Kconfig"
-source "sound/soc/davinci/Kconfig"
 source "sound/soc/dwc/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/hisilicon/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
-source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/img/Kconfig"
 source "sound/soc/intel/Kconfig"
@@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
 source "sound/soc/stm/Kconfig"
 source "sound/soc/sunxi/Kconfig"
 source "sound/soc/tegra/Kconfig"
+source "sound/soc/ti/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/uniphier/Kconfig"
 source "sound/soc/ux500/Kconfig"
+source "sound/soc/xilinx/Kconfig"
 source "sound/soc/xtensa/Kconfig"
 source "sound/soc/zte/Kconfig"
 
index 62a5f87c3cfc435b4ff8b1984f77ec65b3e53578..48c48c1c893ce32cf4384da1e7785eb3f4cdd974 100644 (file)
@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
 obj-$(CONFIG_SND_SOC)  += au1x/
 obj-$(CONFIG_SND_SOC)  += bcm/
 obj-$(CONFIG_SND_SOC)  += cirrus/
-obj-$(CONFIG_SND_SOC)  += davinci/
 obj-$(CONFIG_SND_SOC)  += dwc/
 obj-$(CONFIG_SND_SOC)  += fsl/
 obj-$(CONFIG_SND_SOC)  += hisilicon/
@@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
 obj-$(CONFIG_SND_SOC)  += meson/
 obj-$(CONFIG_SND_SOC)  += mxs/
 obj-$(CONFIG_SND_SOC)  += nuc900/
-obj-$(CONFIG_SND_SOC)  += omap/
 obj-$(CONFIG_SND_SOC)  += kirkwood/
 obj-$(CONFIG_SND_SOC)  += pxa/
 obj-$(CONFIG_SND_SOC)  += qcom/
@@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC)        += sti/
 obj-$(CONFIG_SND_SOC)  += stm/
 obj-$(CONFIG_SND_SOC)  += sunxi/
 obj-$(CONFIG_SND_SOC)  += tegra/
+obj-$(CONFIG_SND_SOC)  += ti/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += uniphier/
 obj-$(CONFIG_SND_SOC)  += ux500/
+obj-$(CONFIG_SND_SOC)  += xilinx/
 obj-$(CONFIG_SND_SOC)  += xtensa/
 obj-$(CONFIG_SND_SOC)  += zte/
index 58c1dcb4d2550f0931b182129747b471e84a7562..33ebec990c2fbae72670588075140040d6f5aa33 100644 (file)
@@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH
        depends on SND_SOC_AMD_ACP && I2C
        help
         This option enables machine driver for rt5645.
+
+config SND_SOC_AMD_ACP3x
+       tristate "AMD Audio Coprocessor-v3.x support"
+       depends on X86 && PCI
+       help
+        This option enables ACP v3.x I2S support on AMD platform
index 79b0622fa5d3aa0dcf6fd2a08fa390b3dbf80aea..8e1c571c3161b369dfcdafb138a7f5421dd7408b 100644 (file)
@@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
 obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
index 3f813ea5210a9dabf39404c6bd84d97390ea9ab2..a5daad973ce565b8c09fb0db9d97c0a285d9600a 100644 (file)
@@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = {
 static struct regulator_ops acp_da7219_ops = {
 };
 
-static struct regulator_desc acp_da7219_desc = {
+static const struct regulator_desc acp_da7219_desc = {
        .name = "reg-fixed-1.8V",
        .type = REGULATOR_VOLTAGE,
        .owner = THIS_MODULE,
index cdebab2f8ce53eb5347525cd1292d9533d1e899d..f4011bebc7ec0fec945464ad62f9986b76256e87 100644 (file)
@@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
 }
 
 /* Create page table entries in ACP SRAM for the allocated memory */
-static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr,
                           u16 num_of_pages, u32 pte_offset)
 {
        u16 page_idx;
-       u64 addr;
        u32 low;
        u32 high;
        u32 offset;
@@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
                /* Load the low address of page int ACP SRAM through SRBM */
                acp_reg_write((offset + (page_idx * 8)),
                              acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
-               addr = page_to_phys(pg);
 
                low = lower_32_bits(addr);
                high = upper_32_bits(addr);
@@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
                acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
 
                /* Move to next physically contiguos page */
-               pg++;
+               addr += PAGE_SIZE;
        }
 }
 
@@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio,
 {
        u16 ch_acp_sysmem, ch_acp_i2s;
 
-       acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
+       acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages,
                       rtd->pte_offset);
 
        if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
        int status;
        uint64_t size;
        u32 val = 0;
-       struct page *pg;
        struct snd_pcm_runtime *runtime;
        struct audio_substream_data *rtd;
        struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
                return status;
 
        memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
-       pg = virt_to_page(substream->dma_buffer.area);
 
-       if (pg) {
+       if (substream->dma_buffer.area) {
                acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
                /* Save for runtime private data */
-               rtd->pg = pg;
+               rtd->dma_addr = substream->dma_buffer.addr;
                rtd->order = get_order(size);
 
                /* Fill the page table entries in ACP SRAM */
-               rtd->pg = pg;
                rtd->size = size;
                rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
                rtd->direction = substream->stream;
@@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
                                                                    DRV_NAME);
        struct audio_drv_data *adata = dev_get_drvdata(component->dev);
+       struct device *parent = component->dev->parent;
 
        switch (adata->asic_type) {
        case CHIP_STONEY:
                ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
                                                            SNDRV_DMA_TYPE_DEV,
-                                                           NULL, ST_MIN_BUFFER,
+                                                           parent,
+                                                           ST_MIN_BUFFER,
                                                            ST_MAX_BUFFER);
                break;
        default:
                ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
                                                            SNDRV_DMA_TYPE_DEV,
-                                                           NULL, MIN_BUFFER,
+                                                           parent,
+                                                           MIN_BUFFER,
                                                            MAX_BUFFER);
                break;
        }
index dbbb1a85638db68c61f758c63fe5aa2cbbfcc2ca..e5ab6c6040a6a87c63f7151390adf21690dba9a8 100644 (file)
@@ -123,7 +123,7 @@ enum acp_dma_priority_level {
 };
 
 struct audio_substream_data {
-       struct page *pg;
+       dma_addr_t dma_addr;
        unsigned int order;
        u16 num_of_pages;
        u16 i2s_instance;
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile
new file mode 100644 (file)
index 0000000..108d1ac
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Raven Ridge platform Support
+snd-pci-acp3x-objs     := pci-acp3x.o
+snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x)         += snd-pci-acp3x.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x)         += snd-acp3x-pcm-dma.o
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
new file mode 100644 (file)
index 0000000..022a891
--- /dev/null
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// AMD ALSA SoC PCM Driver
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "acp3x.h"
+
+#define DRV_NAME "acp3x-i2s-audio"
+
+struct i2s_dev_data {
+       bool tdm_mode;
+       unsigned int i2s_irq;
+       u32 tdm_fmt;
+       void __iomem *acp3x_base;
+       struct snd_pcm_substream *play_stream;
+       struct snd_pcm_substream *capture_stream;
+};
+
+struct i2s_stream_instance {
+       u16 num_pages;
+       u16 channels;
+       u32 xfer_resolution;
+       struct page *pg;
+       void __iomem *acp3x_base;
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |  SNDRV_PCM_FMTBIT_S8 |
+                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 2,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_8000_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+       .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+       .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+       .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+       .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_BATCH |
+           SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_8000_48000,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+       .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+       .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+       .periods_min = CAPTURE_MIN_NUM_PERIODS,
+       .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
+
+static int acp3x_power_on(void __iomem *acp3x_base, bool on)
+{
+       u16 val, mask;
+       u32 timeout;
+
+       if (on == true) {
+               val = 1;
+               mask = ACP3x_POWER_ON;
+       } else {
+               val = 0;
+               mask = ACP3x_POWER_OFF;
+       }
+
+       rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
+       timeout = 0;
+       while (true) {
+               val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+               if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
+                       break;
+               if (timeout > 100) {
+                       pr_err("ACP3x power state change failure\n");
+                       return -ENODEV;
+               }
+               timeout++;
+               cpu_relax();
+       }
+       return 0;
+}
+
+static int acp3x_reset(void __iomem *acp3x_base)
+{
+       u32 val, timeout;
+
+       rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
+       timeout = 0;
+       while (true) {
+               val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+               if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
+                    timeout > 100) {
+                       if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
+                               break;
+                       return -ENODEV;
+               }
+               timeout++;
+               cpu_relax();
+       }
+
+       rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
+       timeout = 0;
+       while (true) {
+               val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+               if (!val || timeout > 100) {
+                       if (!val)
+                               break;
+                       return -ENODEV;
+               }
+               timeout++;
+               cpu_relax();
+       }
+       return 0;
+}
+
+static int acp3x_init(void __iomem *acp3x_base)
+{
+       int ret;
+
+       /* power on */
+       ret = acp3x_power_on(acp3x_base, true);
+       if (ret) {
+               pr_err("ACP3x power on failed\n");
+               return ret;
+       }
+       /* Reset */
+       ret = acp3x_reset(acp3x_base);
+       if (ret) {
+               pr_err("ACP3x reset failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+static int acp3x_deinit(void __iomem *acp3x_base)
+{
+       int ret;
+
+       /* Reset */
+       ret = acp3x_reset(acp3x_base);
+       if (ret) {
+               pr_err("ACP3x reset failed\n");
+               return ret;
+       }
+       /* power off */
+       ret = acp3x_power_on(acp3x_base, false);
+       if (ret) {
+               pr_err("ACP3x power off failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
+{
+       u16 play_flag, cap_flag;
+       u32 val;
+       struct i2s_dev_data *rv_i2s_data = dev_id;
+
+       if (!rv_i2s_data)
+               return IRQ_NONE;
+
+       play_flag = 0;
+       cap_flag = 0;
+       val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
+       if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
+               rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
+                         mmACP_EXTERNAL_INTR_STAT);
+               snd_pcm_period_elapsed(rv_i2s_data->play_stream);
+               play_flag = 1;
+       }
+
+       if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
+               rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
+                         mmACP_EXTERNAL_INTR_STAT);
+               snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
+               cap_flag = 1;
+       }
+
+       if (play_flag | cap_flag)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
+{
+       u16 page_idx;
+       u64 addr;
+       u32 low, high, val, acp_fifo_addr;
+       struct page *pg = rtd->pg;
+
+       /* 8 scratch registers used to map one 64 bit address */
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               val = 0;
+       else
+               val = rtd->num_pages * 8;
+
+       /* Group Enable */
+       rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
+                 mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
+       rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
+                 mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
+
+       for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
+               /* Load the low address of page int ACP SRAM through SRBM */
+               addr = page_to_phys(pg);
+               low = lower_32_bits(addr);
+               high = upper_32_bits(addr);
+
+               rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
+               high |= BIT(31);
+               rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
+                               + 4);
+               /* Move to next physically contiguos page */
+               val += 8;
+               pg++;
+       }
+
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* Config ringbuffer */
+               rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
+                         mmACP_BT_TX_RINGBUFADDR);
+               rv_writel(MAX_BUFFER, rtd->acp3x_base +
+                         mmACP_BT_TX_RINGBUFSIZE);
+               rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
+
+               /* Config audio fifo */
+               acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+                               + PLAYBACK_FIFO_ADDR_OFFSET;
+               rv_writel(acp_fifo_addr, rtd->acp3x_base +
+                         mmACP_BT_TX_FIFOADDR);
+               rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
+       } else {
+               /* Config ringbuffer */
+               rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
+                         mmACP_BT_RX_RINGBUFADDR);
+               rv_writel(MAX_BUFFER, rtd->acp3x_base +
+                         mmACP_BT_RX_RINGBUFSIZE);
+               rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
+
+               /* Config audio fifo */
+               acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+                               (rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
+               rv_writel(acp_fifo_addr, rtd->acp3x_base +
+                         mmACP_BT_RX_FIFOADDR);
+               rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
+       }
+
+       /* Enable  watermark/period interrupt to host */
+       rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
+                 rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
+}
+
+static int acp3x_dma_open(struct snd_pcm_substream *substream)
+{
+       int ret = 0;
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+                                                                   DRV_NAME);
+       struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
+
+       struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
+                                                      GFP_KERNEL);
+       if (!i2s_data)
+               return -EINVAL;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               runtime->hw = acp3x_pcm_hardware_playback;
+       else
+               runtime->hw = acp3x_pcm_hardware_capture;
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(component->dev, "set integer constraint failed\n");
+               kfree(i2s_data);
+               return ret;
+       }
+
+       if (!adata->play_stream && !adata->capture_stream)
+               rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               adata->play_stream = substream;
+       else
+               adata->capture_stream = substream;
+
+       i2s_data->acp3x_base = adata->acp3x_base;
+       runtime->private_data = i2s_data;
+       return 0;
+}
+
+static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *params)
+{
+       int status;
+       u64 size;
+       struct page *pg;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct i2s_stream_instance *rtd = runtime->private_data;
+
+       if (!rtd)
+               return -EINVAL;
+
+       size = params_buffer_bytes(params);
+       status = snd_pcm_lib_malloc_pages(substream, size);
+       if (status < 0)
+               return status;
+
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+       pg = virt_to_page(substream->dma_buffer.area);
+       if (pg) {
+               rtd->pg = pg;
+               rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
+               config_acp3x_dma(rtd, substream->stream);
+               status = 0;
+       } else {
+               status = -ENOMEM;
+       }
+       return status;
+}
+
+static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
+{
+       u32 pos = 0;
+       struct i2s_stream_instance *rtd = substream->runtime->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               pos = rv_readl(rtd->acp3x_base +
+                              mmACP_BT_TX_LINKPOSITIONCNTR);
+       else
+               pos = rv_readl(rtd->acp3x_base +
+                              mmACP_BT_RX_LINKPOSITIONCNTR);
+
+       if (pos >= MAX_BUFFER)
+               pos = 0;
+
+       return bytes_to_frames(substream->runtime, pos);
+}
+
+static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                                                    SNDRV_DMA_TYPE_DEV,
+                                                    NULL, MIN_BUFFER,
+                                                    MAX_BUFFER);
+}
+
+static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
+                         struct vm_area_struct *vma)
+{
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp3x_dma_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct i2s_stream_instance *rtd = substream->runtime->private_data;
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
+                                                                   DRV_NAME);
+       struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               adata->play_stream = NULL;
+       else
+               adata->capture_stream = NULL;
+
+       /* Disable ACP irq, when the current stream is being closed and
+        * another stream is also not active.
+        */
+       if (!adata->play_stream && !adata->capture_stream)
+               rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+       kfree(rtd);
+       return 0;
+}
+
+static struct snd_pcm_ops acp3x_dma_ops = {
+       .open = acp3x_dma_open,
+       .close = acp3x_dma_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = acp3x_dma_hw_params,
+       .hw_free = acp3x_dma_hw_free,
+       .pointer = acp3x_dma_pointer,
+       .mmap = acp3x_dma_mmap,
+};
+
+
+static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+
+       struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               adata->tdm_mode = false;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               adata->tdm_mode = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+                                 u32 rx_mask, int slots, int slot_width)
+{
+       u32 val = 0;
+       u16 slot_len;
+
+       struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (slot_width) {
+       case SLOT_WIDTH_8:
+               slot_len = 8;
+               break;
+       case SLOT_WIDTH_16:
+               slot_len = 16;
+               break;
+       case SLOT_WIDTH_24:
+               slot_len = 24;
+               break;
+       case SLOT_WIDTH_32:
+               slot_len = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
+       rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER);
+       val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
+       rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER);
+
+       val = (FRM_LEN | (slots << 15) | (slot_len << 18));
+       rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT);
+       rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT);
+
+       adata->tdm_fmt = val;
+       return 0;
+}
+
+static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       u32 val = 0;
+       struct i2s_stream_instance *rtd = substream->runtime->private_data;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_U8:
+       case SNDRV_PCM_FORMAT_S8:
+               rtd->xfer_resolution = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               rtd->xfer_resolution = 0x02;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               rtd->xfer_resolution = 0x04;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               rtd->xfer_resolution = 0x05;
+               break;
+       default:
+               return -EINVAL;
+       }
+       val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+       val = val | (rtd->xfer_resolution  << 3);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+       else
+               rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+
+       return 0;
+}
+
+static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
+                                int cmd, struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct i2s_stream_instance *rtd = substream->runtime->private_data;
+       u32 val, period_bytes;
+
+       period_bytes = frames_to_bytes(substream->runtime,
+                                      substream->runtime->period_size);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       rv_writel(period_bytes, rtd->acp3x_base +
+                                 mmACP_BT_TX_INTR_WATERMARK_SIZE);
+                       val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+                       val = val | BIT(0);
+                       rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+               } else {
+                       rv_writel(period_bytes, rtd->acp3x_base +
+                                 mmACP_BT_RX_INTR_WATERMARK_SIZE);
+                       val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
+                       val = val | BIT(0);
+                       rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+               }
+               rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
+                       val = val & ~BIT(0);
+                       rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
+               } else {
+                       val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
+                       val = val & ~BIT(0);
+                       rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
+               }
+               rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
+       .hw_params = acp3x_dai_i2s_hwparams,
+       .trigger   = acp3x_dai_i2s_trigger,
+       .set_fmt = acp3x_dai_i2s_set_fmt,
+       .set_tdm_slot = acp3x_dai_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
+       .playback = {
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                       SNDRV_PCM_FMTBIT_U8 |
+                                       SNDRV_PCM_FMTBIT_S24_LE |
+                                       SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                       SNDRV_PCM_FMTBIT_U8 |
+                                       SNDRV_PCM_FMTBIT_S24_LE |
+                                       SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &acp3x_dai_i2s_ops,
+};
+
+static const struct snd_soc_component_driver acp3x_i2s_component = {
+       .name           = DRV_NAME,
+       .ops            = &acp3x_dma_ops,
+       .pcm_new        = acp3x_dma_new,
+};
+
+static int acp3x_audio_probe(struct platform_device *pdev)
+{
+       int status;
+       struct resource *res;
+       struct i2s_dev_data *adata;
+       unsigned int irqflags;
+
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "platform_data not retrieved\n");
+               return -ENODEV;
+       }
+       irqflags = *((unsigned int *)(pdev->dev.platform_data));
+
+       adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
+                            GFP_KERNEL);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+                       return -ENODEV;
+       }
+
+       adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
+                                        resource_size(res));
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+               return -ENODEV;
+       }
+
+       adata->i2s_irq = res->start;
+       adata->play_stream = NULL;
+       adata->capture_stream = NULL;
+
+       dev_set_drvdata(&pdev->dev, adata);
+       /* Initialize ACP */
+       status = acp3x_init(adata->acp3x_base);
+       if (status)
+               return -ENODEV;
+       status = devm_snd_soc_register_component(&pdev->dev,
+                                                &acp3x_i2s_component,
+                                                &acp3x_i2s_dai_driver, 1);
+       if (status) {
+               dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
+               goto dev_err;
+       }
+       status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
+                                 irqflags, "ACP3x_I2S_IRQ", adata);
+       if (status) {
+               dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");
+               goto dev_err;
+       }
+
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       return 0;
+dev_err:
+       status = acp3x_deinit(adata->acp3x_base);
+       if (status)
+               dev_err(&pdev->dev, "ACP de-init failed\n");
+       else
+               dev_info(&pdev->dev, "ACP de-initialized\n");
+       /*ignore device status and return driver probe error*/
+       return -ENODEV;
+}
+
+static int acp3x_audio_remove(struct platform_device *pdev)
+{
+       int ret;
+       struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
+
+       ret = acp3x_deinit(adata->acp3x_base);
+       if (ret)
+               dev_err(&pdev->dev, "ACP de-init failed\n");
+       else
+               dev_info(&pdev->dev, "ACP de-initialized\n");
+
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
+static int acp3x_resume(struct device *dev)
+{
+       int status;
+       u32 val;
+       struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+       status = acp3x_init(adata->acp3x_base);
+       if (status)
+               return -ENODEV;
+
+       if (adata->play_stream && adata->play_stream->runtime) {
+               struct i2s_stream_instance *rtd =
+                       adata->play_stream->runtime->private_data;
+               config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+               rv_writel((rtd->xfer_resolution  << 3),
+                         rtd->acp3x_base + mmACP_BTTDM_ITER);
+               if (adata->tdm_mode == true) {
+                       rv_writel(adata->tdm_fmt, adata->acp3x_base +
+                                 mmACP_BTTDM_TXFRMT);
+                       val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
+                       rv_writel((val | 0x2), adata->acp3x_base +
+                                 mmACP_BTTDM_ITER);
+               }
+       }
+
+       if (adata->capture_stream && adata->capture_stream->runtime) {
+               struct i2s_stream_instance *rtd =
+                       adata->capture_stream->runtime->private_data;
+               config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+               rv_writel((rtd->xfer_resolution  << 3),
+                         rtd->acp3x_base + mmACP_BTTDM_IRER);
+               if (adata->tdm_mode == true) {
+                       rv_writel(adata->tdm_fmt, adata->acp3x_base +
+                                 mmACP_BTTDM_RXFRMT);
+                       val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
+                       rv_writel((val | 0x2), adata->acp3x_base +
+                                 mmACP_BTTDM_IRER);
+               }
+       }
+
+       rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+       return 0;
+}
+
+
+static int acp3x_pcm_runtime_suspend(struct device *dev)
+{
+       int status;
+       struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+       status = acp3x_deinit(adata->acp3x_base);
+       if (status)
+               dev_err(dev, "ACP de-init failed\n");
+       else
+               dev_info(dev, "ACP de-initialized\n");
+
+       rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+       return 0;
+}
+
+static int acp3x_pcm_runtime_resume(struct device *dev)
+{
+       int status;
+       struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+       status = acp3x_init(adata->acp3x_base);
+       if (status)
+               return -ENODEV;
+       rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+       return 0;
+}
+
+static const struct dev_pm_ops acp3x_pm_ops = {
+       .runtime_suspend = acp3x_pcm_runtime_suspend,
+       .runtime_resume = acp3x_pcm_runtime_resume,
+       .resume = acp3x_resume,
+};
+
+static struct platform_driver acp3x_dma_driver = {
+       .probe = acp3x_audio_probe,
+       .remove = acp3x_audio_remove,
+       .driver = {
+               .name = "acp3x_rv_i2s",
+               .pm = &acp3x_pm_ops,
+       },
+};
+
+module_platform_driver(acp3x_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h
new file mode 100644 (file)
index 0000000..4f2cadd
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ALSA SoC PCM Driver
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#include "chip_offset_byte.h"
+
+#define ACP3x_PHY_BASE_ADDRESS 0x1240000
+#define        ACP3x_I2S_MODE  0
+#define        ACP3x_REG_START 0x1240000
+#define        ACP3x_REG_END   0x1250200
+#define I2S_MODE       0x04
+#define        BT_TX_THRESHOLD 26
+#define        BT_RX_THRESHOLD 25
+#define ACP3x_POWER_ON 0x00
+#define ACP3x_POWER_ON_IN_PROGRESS 0x01
+#define ACP3x_POWER_OFF 0x02
+#define ACP3x_POWER_OFF_IN_PROGRESS 0x03
+#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK        0x00010001
+
+#define ACP_SRAM_PTE_OFFSET    0x02050000
+#define PAGE_SIZE_4K_ENABLE 0x2
+#define MEM_WINDOW_START       0x4000000
+#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
+#define CAPTURE_FIFO_ADDR_OFFSET  0x500
+
+#define PLAYBACK_MIN_NUM_PERIODS    2
+#define PLAYBACK_MAX_NUM_PERIODS    8
+#define PLAYBACK_MAX_PERIOD_SIZE    16384
+#define PLAYBACK_MIN_PERIOD_SIZE    4096
+#define CAPTURE_MIN_NUM_PERIODS     2
+#define CAPTURE_MAX_NUM_PERIODS     8
+#define CAPTURE_MAX_PERIOD_SIZE     16384
+#define CAPTURE_MIN_PERIOD_SIZE     4096
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+#define FIFO_SIZE 0x100
+#define DMA_SIZE 0x40
+#define FRM_LEN 0x100
+
+#define SLOT_WIDTH_8 0x08
+#define SLOT_WIDTH_16 0x10
+#define SLOT_WIDTH_24 0x18
+#define SLOT_WIDTH_32 0x20
+
+
+static inline u32 rv_readl(void __iomem *base_addr)
+{
+       return readl(base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
+
+static inline void rv_writel(u32 val, void __iomem *base_addr)
+{
+       writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
diff --git a/sound/soc/amd/raven/chip_offset_byte.h b/sound/soc/amd/raven/chip_offset_byte.h
new file mode 100644 (file)
index 0000000..9c1fac5
--- /dev/null
@@ -0,0 +1,639 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ACP 3.0 Register Documentation
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _acp_ip_OFFSET_HEADER
+#define _acp_ip_OFFSET_HEADER
+// Registers from ACP_DMA block
+
+#define mmACP_DMA_CNTL_0                                0x1240000
+#define mmACP_DMA_CNTL_1                                0x1240004
+#define mmACP_DMA_CNTL_2                                0x1240008
+#define mmACP_DMA_CNTL_3                                0x124000C
+#define mmACP_DMA_CNTL_4                                0x1240010
+#define mmACP_DMA_CNTL_5                                0x1240014
+#define mmACP_DMA_CNTL_6                                0x1240018
+#define mmACP_DMA_CNTL_7                                0x124001C
+#define mmACP_DMA_DSCR_STRT_IDX_0                       0x1240020
+#define mmACP_DMA_DSCR_STRT_IDX_1                       0x1240024
+#define mmACP_DMA_DSCR_STRT_IDX_2                       0x1240028
+#define mmACP_DMA_DSCR_STRT_IDX_3                       0x124002C
+#define mmACP_DMA_DSCR_STRT_IDX_4                       0x1240030
+#define mmACP_DMA_DSCR_STRT_IDX_5                       0x1240034
+#define mmACP_DMA_DSCR_STRT_IDX_6                       0x1240038
+#define mmACP_DMA_DSCR_STRT_IDX_7                       0x124003C
+#define mmACP_DMA_DSCR_CNT_0                            0x1240040
+#define mmACP_DMA_DSCR_CNT_1                            0x1240044
+#define mmACP_DMA_DSCR_CNT_2                            0x1240048
+#define mmACP_DMA_DSCR_CNT_3                            0x124004C
+#define mmACP_DMA_DSCR_CNT_4                            0x1240050
+#define mmACP_DMA_DSCR_CNT_5                            0x1240054
+#define mmACP_DMA_DSCR_CNT_6                            0x1240058
+#define mmACP_DMA_DSCR_CNT_7                            0x124005C
+#define mmACP_DMA_PRIO_0                                0x1240060
+#define mmACP_DMA_PRIO_1                                0x1240064
+#define mmACP_DMA_PRIO_2                                0x1240068
+#define mmACP_DMA_PRIO_3                                0x124006C
+#define mmACP_DMA_PRIO_4                                0x1240070
+#define mmACP_DMA_PRIO_5                                0x1240074
+#define mmACP_DMA_PRIO_6                                0x1240078
+#define mmACP_DMA_PRIO_7                                0x124007C
+#define mmACP_DMA_CUR_DSCR_0                            0x1240080
+#define mmACP_DMA_CUR_DSCR_1                            0x1240084
+#define mmACP_DMA_CUR_DSCR_2                            0x1240088
+#define mmACP_DMA_CUR_DSCR_3                            0x124008C
+#define mmACP_DMA_CUR_DSCR_4                            0x1240090
+#define mmACP_DMA_CUR_DSCR_5                            0x1240094
+#define mmACP_DMA_CUR_DSCR_6                            0x1240098
+#define mmACP_DMA_CUR_DSCR_7                            0x124009C
+#define mmACP_DMA_CUR_TRANS_CNT_0                       0x12400A0
+#define mmACP_DMA_CUR_TRANS_CNT_1                       0x12400A4
+#define mmACP_DMA_CUR_TRANS_CNT_2                       0x12400A8
+#define mmACP_DMA_CUR_TRANS_CNT_3                       0x12400AC
+#define mmACP_DMA_CUR_TRANS_CNT_4                       0x12400B0
+#define mmACP_DMA_CUR_TRANS_CNT_5                       0x12400B4
+#define mmACP_DMA_CUR_TRANS_CNT_6                       0x12400B8
+#define mmACP_DMA_CUR_TRANS_CNT_7                       0x12400BC
+#define mmACP_DMA_ERR_STS_0                             0x12400C0
+#define mmACP_DMA_ERR_STS_1                             0x12400C4
+#define mmACP_DMA_ERR_STS_2                             0x12400C8
+#define mmACP_DMA_ERR_STS_3                             0x12400CC
+#define mmACP_DMA_ERR_STS_4                             0x12400D0
+#define mmACP_DMA_ERR_STS_5                             0x12400D4
+#define mmACP_DMA_ERR_STS_6                             0x12400D8
+#define mmACP_DMA_ERR_STS_7                             0x12400DC
+#define mmACP_DMA_DESC_BASE_ADDR                        0x12400E0
+#define mmACP_DMA_DESC_MAX_NUM_DSCR                     0x12400E4
+#define mmACP_DMA_CH_STS                                0x12400E8
+#define mmACP_DMA_CH_GROUP                              0x12400EC
+#define mmACP_DMA_CH_RST_STS                            0x12400F0
+
+
+// Registers from ACP_AXI2AXIATU block
+
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1                0x1240C00
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1                0x1240C04
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2                0x1240C08
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2                0x1240C0C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3                0x1240C10
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3                0x1240C14
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4                0x1240C18
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4                0x1240C1C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5                0x1240C20
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5                0x1240C24
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6                0x1240C28
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6                0x1240C2C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7                0x1240C30
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7                0x1240C34
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8                0x1240C38
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8                0x1240C3C
+#define mmACPAXI2AXI_ATU_CTRL                           0x1240C40
+
+
+// Registers from ACP_CLKRST block
+
+#define mmACP_SOFT_RESET                                0x1241000
+#define mmACP_CONTROL                                   0x1241004
+#define mmACP_STATUS                                    0x1241008
+#define mmACP_DSP0_OCD_HALT_ON_RST                      0x124100C
+#define mmACP_DYNAMIC_CG_MASTER_CONTROL                 0x1241010
+
+
+// Registers from ACP_MISC block
+
+#define mmACP_EXTERNAL_INTR_ENB                         0x1241800
+#define mmACP_EXTERNAL_INTR_CNTL                        0x1241804
+#define mmACP_EXTERNAL_INTR_STAT                        0x1241808
+#define mmACP_DSP0_INTR_CNTL                            0x124180C
+#define mmACP_DSP0_INTR_STAT                            0x1241810
+#define mmACP_DSP_SW_INTR_CNTL                          0x1241814
+#define mmACP_DSP_SW_INTR_STAT                          0x1241818
+#define mmACP_SW_INTR_TRIG                              0x124181C
+#define mmACP_SMU_MAILBOX                               0x1241820
+#define mmDSP_INTERRUPT_ROUTING_CTRL                    0x1241824
+#define mmACP_DSP0_WATCHDOG_TIMER_CNTL                  0x1241828
+#define mmACP_DSP0_EXT_TIMER1_CNTL                      0x124182C
+#define mmACP_DSP0_EXT_TIMER2_CNTL                      0x1241830
+#define mmACP_DSP0_EXT_TIMER3_CNTL                      0x1241834
+#define mmACP_DSP0_EXT_TIMER4_CNTL                      0x1241838
+#define mmACP_DSP0_EXT_TIMER5_CNTL                      0x124183C
+#define mmACP_DSP0_EXT_TIMER6_CNTL                      0x1241840
+#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE                0x1241844
+#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE                0x1241848
+#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE                0x124184C
+#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE                0x1241850
+#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE                0x1241854
+#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE                0x1241858
+#define mmACP_FW_STATUS                                 0x124185C
+#define mmACP_TIMER                                     0x1241874
+#define mmACP_TIMER_CNTL                                0x1241878
+#define mmACP_PGMEM_CTRL                                0x12418C0
+#define mmACP_ERROR_STATUS                              0x12418C4
+#define mmACP_SW_I2S_ERROR_REASON                       0x12418C8
+#define mmACP_MEM_PG_STS                                0x12418CC
+
+
+// Registers from ACP_PGFSM block
+
+#define mmACP_I2S_PIN_CONFIG                            0x1241400
+#define mmACP_PAD_PULLUP_PULLDOWN_CTRL                  0x1241404
+#define mmACP_PAD_DRIVE_STRENGTH_CTRL                   0x1241408
+#define mmACP_SW_PAD_KEEPER_EN                          0x124140C
+#define mmACP_SW_WAKE_EN                                0x1241410
+#define mmACP_I2S_WAKE_EN                               0x1241414
+#define mmACP_PME_EN                                    0x1241418
+#define mmACP_PGFSM_CONTROL                             0x124141C
+#define mmACP_PGFSM_STATUS                              0x1241420
+
+
+// Registers from ACP_SCRATCH block
+
+#define mmACP_SCRATCH_REG_0                             0x1250000
+#define mmACP_SCRATCH_REG_1                             0x1250004
+#define mmACP_SCRATCH_REG_2                             0x1250008
+#define mmACP_SCRATCH_REG_3                             0x125000C
+#define mmACP_SCRATCH_REG_4                             0x1250010
+#define mmACP_SCRATCH_REG_5                             0x1250014
+#define mmACP_SCRATCH_REG_6                             0x1250018
+#define mmACP_SCRATCH_REG_7                             0x125001C
+#define mmACP_SCRATCH_REG_8                             0x1250020
+#define mmACP_SCRATCH_REG_9                             0x1250024
+#define mmACP_SCRATCH_REG_10                            0x1250028
+#define mmACP_SCRATCH_REG_11                            0x125002C
+#define mmACP_SCRATCH_REG_12                            0x1250030
+#define mmACP_SCRATCH_REG_13                            0x1250034
+#define mmACP_SCRATCH_REG_14                            0x1250038
+#define mmACP_SCRATCH_REG_15                            0x125003C
+#define mmACP_SCRATCH_REG_16                            0x1250040
+#define mmACP_SCRATCH_REG_17                            0x1250044
+#define mmACP_SCRATCH_REG_18                            0x1250048
+#define mmACP_SCRATCH_REG_19                            0x125004C
+#define mmACP_SCRATCH_REG_20                            0x1250050
+#define mmACP_SCRATCH_REG_21                            0x1250054
+#define mmACP_SCRATCH_REG_22                            0x1250058
+#define mmACP_SCRATCH_REG_23                            0x125005C
+#define mmACP_SCRATCH_REG_24                            0x1250060
+#define mmACP_SCRATCH_REG_25                            0x1250064
+#define mmACP_SCRATCH_REG_26                            0x1250068
+#define mmACP_SCRATCH_REG_27                            0x125006C
+#define mmACP_SCRATCH_REG_28                            0x1250070
+#define mmACP_SCRATCH_REG_29                            0x1250074
+#define mmACP_SCRATCH_REG_30                            0x1250078
+#define mmACP_SCRATCH_REG_31                            0x125007C
+#define mmACP_SCRATCH_REG_32                            0x1250080
+#define mmACP_SCRATCH_REG_33                            0x1250084
+#define mmACP_SCRATCH_REG_34                            0x1250088
+#define mmACP_SCRATCH_REG_35                            0x125008C
+#define mmACP_SCRATCH_REG_36                            0x1250090
+#define mmACP_SCRATCH_REG_37                            0x1250094
+#define mmACP_SCRATCH_REG_38                            0x1250098
+#define mmACP_SCRATCH_REG_39                            0x125009C
+#define mmACP_SCRATCH_REG_40                            0x12500A0
+#define mmACP_SCRATCH_REG_41                            0x12500A4
+#define mmACP_SCRATCH_REG_42                            0x12500A8
+#define mmACP_SCRATCH_REG_43                            0x12500AC
+#define mmACP_SCRATCH_REG_44                            0x12500B0
+#define mmACP_SCRATCH_REG_45                            0x12500B4
+#define mmACP_SCRATCH_REG_46                            0x12500B8
+#define mmACP_SCRATCH_REG_47                            0x12500BC
+#define mmACP_SCRATCH_REG_48                            0x12500C0
+#define mmACP_SCRATCH_REG_49                            0x12500C4
+#define mmACP_SCRATCH_REG_50                            0x12500C8
+#define mmACP_SCRATCH_REG_51                            0x12500CC
+#define mmACP_SCRATCH_REG_52                            0x12500D0
+#define mmACP_SCRATCH_REG_53                            0x12500D4
+#define mmACP_SCRATCH_REG_54                            0x12500D8
+#define mmACP_SCRATCH_REG_55                            0x12500DC
+#define mmACP_SCRATCH_REG_56                            0x12500E0
+#define mmACP_SCRATCH_REG_57                            0x12500E4
+#define mmACP_SCRATCH_REG_58                            0x12500E8
+#define mmACP_SCRATCH_REG_59                            0x12500EC
+#define mmACP_SCRATCH_REG_60                            0x12500F0
+#define mmACP_SCRATCH_REG_61                            0x12500F4
+#define mmACP_SCRATCH_REG_62                            0x12500F8
+#define mmACP_SCRATCH_REG_63                            0x12500FC
+#define mmACP_SCRATCH_REG_64                            0x1250100
+#define mmACP_SCRATCH_REG_65                            0x1250104
+#define mmACP_SCRATCH_REG_66                            0x1250108
+#define mmACP_SCRATCH_REG_67                            0x125010C
+#define mmACP_SCRATCH_REG_68                            0x1250110
+#define mmACP_SCRATCH_REG_69                            0x1250114
+#define mmACP_SCRATCH_REG_70                            0x1250118
+#define mmACP_SCRATCH_REG_71                            0x125011C
+#define mmACP_SCRATCH_REG_72                            0x1250120
+#define mmACP_SCRATCH_REG_73                            0x1250124
+#define mmACP_SCRATCH_REG_74                            0x1250128
+#define mmACP_SCRATCH_REG_75                            0x125012C
+#define mmACP_SCRATCH_REG_76                            0x1250130
+#define mmACP_SCRATCH_REG_77                            0x1250134
+#define mmACP_SCRATCH_REG_78                            0x1250138
+#define mmACP_SCRATCH_REG_79                            0x125013C
+#define mmACP_SCRATCH_REG_80                            0x1250140
+#define mmACP_SCRATCH_REG_81                            0x1250144
+#define mmACP_SCRATCH_REG_82                            0x1250148
+#define mmACP_SCRATCH_REG_83                            0x125014C
+#define mmACP_SCRATCH_REG_84                            0x1250150
+#define mmACP_SCRATCH_REG_85                            0x1250154
+#define mmACP_SCRATCH_REG_86                            0x1250158
+#define mmACP_SCRATCH_REG_87                            0x125015C
+#define mmACP_SCRATCH_REG_88                            0x1250160
+#define mmACP_SCRATCH_REG_89                            0x1250164
+#define mmACP_SCRATCH_REG_90                            0x1250168
+#define mmACP_SCRATCH_REG_91                            0x125016C
+#define mmACP_SCRATCH_REG_92                            0x1250170
+#define mmACP_SCRATCH_REG_93                            0x1250174
+#define mmACP_SCRATCH_REG_94                            0x1250178
+#define mmACP_SCRATCH_REG_95                            0x125017C
+#define mmACP_SCRATCH_REG_96                            0x1250180
+#define mmACP_SCRATCH_REG_97                            0x1250184
+#define mmACP_SCRATCH_REG_98                            0x1250188
+#define mmACP_SCRATCH_REG_99                            0x125018C
+#define mmACP_SCRATCH_REG_100                           0x1250190
+#define mmACP_SCRATCH_REG_101                           0x1250194
+#define mmACP_SCRATCH_REG_102                           0x1250198
+#define mmACP_SCRATCH_REG_103                           0x125019C
+#define mmACP_SCRATCH_REG_104                           0x12501A0
+#define mmACP_SCRATCH_REG_105                           0x12501A4
+#define mmACP_SCRATCH_REG_106                           0x12501A8
+#define mmACP_SCRATCH_REG_107                           0x12501AC
+#define mmACP_SCRATCH_REG_108                           0x12501B0
+#define mmACP_SCRATCH_REG_109                           0x12501B4
+#define mmACP_SCRATCH_REG_110                           0x12501B8
+#define mmACP_SCRATCH_REG_111                           0x12501BC
+#define mmACP_SCRATCH_REG_112                           0x12501C0
+#define mmACP_SCRATCH_REG_113                           0x12501C4
+#define mmACP_SCRATCH_REG_114                           0x12501C8
+#define mmACP_SCRATCH_REG_115                           0x12501CC
+#define mmACP_SCRATCH_REG_116                           0x12501D0
+#define mmACP_SCRATCH_REG_117                           0x12501D4
+#define mmACP_SCRATCH_REG_118                           0x12501D8
+#define mmACP_SCRATCH_REG_119                           0x12501DC
+#define mmACP_SCRATCH_REG_120                           0x12501E0
+#define mmACP_SCRATCH_REG_121                           0x12501E4
+#define mmACP_SCRATCH_REG_122                           0x12501E8
+#define mmACP_SCRATCH_REG_123                           0x12501EC
+#define mmACP_SCRATCH_REG_124                           0x12501F0
+#define mmACP_SCRATCH_REG_125                           0x12501F4
+#define mmACP_SCRATCH_REG_126                           0x12501F8
+#define mmACP_SCRATCH_REG_127                           0x12501FC
+#define mmACP_SCRATCH_REG_128                           0x1250200
+
+
+// Registers from ACP_SW_ACLK block
+
+#define mmSW_CORB_Base_Address                          0x1243200
+#define mmSW_CORB_Write_Pointer                         0x1243204
+#define mmSW_CORB_Read_Pointer                          0x1243208
+#define mmSW_CORB_Control                               0x124320C
+#define mmSW_CORB_Size                                  0x1243214
+#define mmSW_RIRB_Base_Address                          0x1243218
+#define mmSW_RIRB_Write_Pointer                         0x124321C
+#define mmSW_RIRB_Response_Interrupt_Count              0x1243220
+#define mmSW_RIRB_Control                               0x1243224
+#define mmSW_RIRB_Size                                  0x1243228
+#define mmSW_RIRB_FIFO_MIN_THDL                         0x124322C
+#define mmSW_imm_cmd_UPPER_WORD                         0x1243230
+#define mmSW_imm_cmd_LOWER_QWORD                        0x1243234
+#define mmSW_imm_resp_UPPER_WORD                        0x1243238
+#define mmSW_imm_resp_LOWER_QWORD                       0x124323C
+#define mmSW_imm_cmd_sts                                0x1243240
+#define mmSW_BRA_BASE_ADDRESS                           0x1243244
+#define mmSW_BRA_TRANSFER_SIZE                          0x1243248
+#define mmSW_BRA_DMA_BUSY                               0x124324C
+#define mmSW_BRA_RESP                                   0x1243250
+#define mmSW_BRA_RESP_FRAME_ADDR                        0x1243254
+#define mmSW_BRA_CURRENT_TRANSFER_SIZE                  0x1243258
+#define mmSW_STATE_CHANGE_STATUS_0TO7                   0x124325C
+#define mmSW_STATE_CHANGE_STATUS_8TO11                  0x1243260
+#define mmSW_STATE_CHANGE_STATUS_MASK_0to7              0x1243264
+#define mmSW_STATE_CHANGE_STATUS_MASK_8to11             0x1243268
+#define mmSW_CLK_FREQUENCY_CTRL                         0x124326C
+#define mmSW_ERROR_INTR_MASK                            0x1243270
+#define mmSW_PHY_TEST_MODE_DATA_OFF                     0x1243274
+
+
+// Registers from ACP_SW_SWCLK block
+
+#define mmACP_SW_EN                                     0x1243000
+#define mmACP_SW_EN_STATUS                              0x1243004
+#define mmACP_SW_FRAMESIZE                              0x1243008
+#define mmACP_SW_SSP_Counter                            0x124300C
+#define mmACP_SW_Audio_TX_EN                            0x1243010
+#define mmACP_SW_Audio_TX_EN_STATUS                     0x1243014
+#define mmACP_SW_Audio_TX_Frame_Format                  0x1243018
+#define mmACP_SW_Audio_TX_SampleInterval                0x124301C
+#define mmACP_SW_Audio_TX_Hctrl_DP0                     0x1243020
+#define mmACP_SW_Audio_TX_Hctrl_DP1                     0x1243024
+#define mmACP_SW_Audio_TX_Hctrl_DP2                     0x1243028
+#define mmACP_SW_Audio_TX_Hctrl_DP3                     0x124302C
+#define mmACP_SW_Audio_TX_offset_DP0                    0x1243030
+#define mmACP_SW_Audio_TX_offset_DP1                    0x1243034
+#define mmACP_SW_Audio_TX_offset_DP2                    0x1243038
+#define mmACP_SW_Audio_TX_offset_DP3                    0x124303C
+#define mmACP_SW_Audio_TX_Channel_Enable_DP0            0x1243040
+#define mmACP_SW_Audio_TX_Channel_Enable_DP1            0x1243044
+#define mmACP_SW_Audio_TX_Channel_Enable_DP2            0x1243048
+#define mmACP_SW_Audio_TX_Channel_Enable_DP3            0x124304C
+#define mmACP_SW_BT_TX_EN                               0x1243050
+#define mmACP_SW_BT_TX_EN_STATUS                        0x1243054
+#define mmACP_SW_BT_TX_Frame_Format                     0x1243058
+#define mmACP_SW_BT_TX_SampleInterval                   0x124305C
+#define mmACP_SW_BT_TX_Hctrl                            0x1243060
+#define mmACP_SW_BT_TX_offset                           0x1243064
+#define mmACP_SW_BT_TX_Channel_Enable_DP0               0x1243068
+#define mmACP_SW_Headset_TX_EN                          0x124306C
+#define mmACP_SW_Headset_TX_EN_STATUS                   0x1243070
+#define mmACP_SW_Headset_TX_Frame_Format                0x1243074
+#define mmACP_SW_Headset_TX_SampleInterval              0x1243078
+#define mmACP_SW_Headset_TX_Hctrl                       0x124307C
+#define mmACP_SW_Headset_TX_offset                      0x1243080
+#define mmACP_SW_Headset_TX_Channel_Enable_DP0          0x1243084
+#define mmACP_SW_Audio_RX_EN                            0x1243088
+#define mmACP_SW_Audio_RX_EN_STATUS                     0x124308C
+#define mmACP_SW_Audio_RX_Frame_Format                  0x1243090
+#define mmACP_SW_Audio_RX_SampleInterval                0x1243094
+#define mmACP_SW_Audio_RX_Hctrl_DP0                     0x1243098
+#define mmACP_SW_Audio_RX_Hctrl_DP1                     0x124309C
+#define mmACP_SW_Audio_RX_Hctrl_DP2                     0x1243100
+#define mmACP_SW_Audio_RX_Hctrl_DP3                     0x1243104
+#define mmACP_SW_Audio_RX_offset_DP0                    0x1243108
+#define mmACP_SW_Audio_RX_offset_DP1                    0x124310C
+#define mmACP_SW_Audio_RX_offset_DP2                    0x1243110
+#define mmACP_SW_Audio_RX_offset_DP3                    0x1243114
+#define mmACP_SW_Audio_RX_Channel_Enable_DP0            0x1243118
+#define mmACP_SW_Audio_RX_Channel_Enable_DP1            0x124311C
+#define mmACP_SW_Audio_RX_Channel_Enable_DP2            0x1243120
+#define mmACP_SW_Audio_RX_Channel_Enable_DP3            0x1243124
+#define mmACP_SW_BT_RX_EN                               0x1243128
+#define mmACP_SW_BT_RX_EN_STATUS                        0x124312C
+#define mmACP_SW_BT_RX_Frame_Format                     0x1243130
+#define mmACP_SW_BT_RX_SampleInterval                   0x1243134
+#define mmACP_SW_BT_RX_Hctrl                            0x1243138
+#define mmACP_SW_BT_RX_offset                           0x124313C
+#define mmACP_SW_BT_RX_Channel_Enable_DP0               0x1243140
+#define mmACP_SW_Headset_RX_EN                          0x1243144
+#define mmACP_SW_Headset_RX_EN_STATUS                   0x1243148
+#define mmACP_SW_Headset_RX_Frame_Format                0x124314C
+#define mmACP_SW_Headset_RX_SampleInterval              0x1243150
+#define mmACP_SW_Headset_RX_Hctrl                       0x1243154
+#define mmACP_SW_Headset_RX_offset                      0x1243158
+#define mmACP_SW_Headset_RX_Channel_Enable_DP0          0x124315C
+#define mmACP_SW_BPT_PORT_EN                            0x1243160
+#define mmACP_SW_BPT_PORT_EN_STATUS                     0x1243164
+#define mmACP_SW_BPT_PORT_Frame_Format                  0x1243168
+#define mmACP_SW_BPT_PORT_SampleInterval                0x124316C
+#define mmACP_SW_BPT_PORT_Hctrl                         0x1243170
+#define mmACP_SW_BPT_PORT_offset                        0x1243174
+#define mmACP_SW_BPT_PORT_Channel_Enable                0x1243178
+#define mmACP_SW_BPT_PORT_First_byte_addr               0x124317C
+#define mmACP_SW_CLK_RESUME_CTRL                        0x1243180
+#define mmACP_SW_CLK_RESUME_Delay_Cntr                  0x1243184
+#define mmACP_SW_BUS_RESET_CTRL                         0x1243188
+#define mmACP_SW_PRBS_ERR_STATUS                        0x124318C
+
+
+// Registers from ACP_AUDIO_BUFFERS block
+
+#define mmACP_I2S_RX_RINGBUFADDR                        0x1242000
+#define mmACP_I2S_RX_RINGBUFSIZE                        0x1242004
+#define mmACP_I2S_RX_LINKPOSITIONCNTR                   0x1242008
+#define mmACP_I2S_RX_FIFOADDR                           0x124200C
+#define mmACP_I2S_RX_FIFOSIZE                           0x1242010
+#define mmACP_I2S_RX_DMA_SIZE                           0x1242014
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH            0x1242018
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW             0x124201C
+#define mmACP_I2S_RX_INTR_WATERMARK_SIZE                0x1242020
+#define mmACP_I2S_TX_RINGBUFADDR                        0x1242024
+#define mmACP_I2S_TX_RINGBUFSIZE                        0x1242028
+#define mmACP_I2S_TX_LINKPOSITIONCNTR                   0x124202C
+#define mmACP_I2S_TX_FIFOADDR                           0x1242030
+#define mmACP_I2S_TX_FIFOSIZE                           0x1242034
+#define mmACP_I2S_TX_DMA_SIZE                           0x1242038
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH            0x124203C
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW             0x1242040
+#define mmACP_I2S_TX_INTR_WATERMARK_SIZE                0x1242044
+#define mmACP_BT_RX_RINGBUFADDR                         0x1242048
+#define mmACP_BT_RX_RINGBUFSIZE                         0x124204C
+#define mmACP_BT_RX_LINKPOSITIONCNTR                    0x1242050
+#define mmACP_BT_RX_FIFOADDR                            0x1242054
+#define mmACP_BT_RX_FIFOSIZE                            0x1242058
+#define mmACP_BT_RX_DMA_SIZE                            0x124205C
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH             0x1242060
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW              0x1242064
+#define mmACP_BT_RX_INTR_WATERMARK_SIZE                 0x1242068
+#define mmACP_BT_TX_RINGBUFADDR                         0x124206C
+#define mmACP_BT_TX_RINGBUFSIZE                         0x1242070
+#define mmACP_BT_TX_LINKPOSITIONCNTR                    0x1242074
+#define mmACP_BT_TX_FIFOADDR                            0x1242078
+#define mmACP_BT_TX_FIFOSIZE                            0x124207C
+#define mmACP_BT_TX_DMA_SIZE                            0x1242080
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH             0x1242084
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW              0x1242088
+#define mmACP_BT_TX_INTR_WATERMARK_SIZE                 0x124208C
+#define mmACP_HS_RX_RINGBUFADDR                         0x1242090
+#define mmACP_HS_RX_RINGBUFSIZE                         0x1242094
+#define mmACP_HS_RX_LINKPOSITIONCNTR                    0x1242098
+#define mmACP_HS_RX_FIFOADDR                            0x124209C
+#define mmACP_HS_RX_FIFOSIZE                            0x12420A0
+#define mmACP_HS_RX_DMA_SIZE                            0x12420A4
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH             0x12420A8
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW              0x12420AC
+#define mmACP_HS_RX_INTR_WATERMARK_SIZE                 0x12420B0
+#define mmACP_HS_TX_RINGBUFADDR                         0x12420B4
+#define mmACP_HS_TX_RINGBUFSIZE                         0x12420B8
+#define mmACP_HS_TX_LINKPOSITIONCNTR                    0x12420BC
+#define mmACP_HS_TX_FIFOADDR                            0x12420C0
+#define mmACP_HS_TX_FIFOSIZE                            0x12420C4
+#define mmACP_HS_TX_DMA_SIZE                            0x12420C8
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH             0x12420CC
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW              0x12420D0
+#define mmACP_HS_TX_INTR_WATERMARK_SIZE                 0x12420D4
+
+
+// Registers from ACP_I2S_TDM block
+
+#define mmACP_I2STDM_IER                                0x1242400
+#define mmACP_I2STDM_IRER                               0x1242404
+#define mmACP_I2STDM_RXFRMT                             0x1242408
+#define mmACP_I2STDM_ITER                               0x124240C
+#define mmACP_I2STDM_TXFRMT                             0x1242410
+
+
+// Registers from ACP_BT_TDM block
+
+#define mmACP_BTTDM_IER                                 0x1242800
+#define mmACP_BTTDM_IRER                                0x1242804
+#define mmACP_BTTDM_RXFRMT                              0x1242808
+#define mmACP_BTTDM_ITER                                0x124280C
+#define mmACP_BTTDM_TXFRMT                              0x1242810
+
+
+// Registers from AZALIA_IP block
+
+#define mmAudio_Az_Global_Capabilities                  0x1200000
+#define mmAudio_Az_Minor_Version                        0x1200002
+#define mmAudio_Az_Major_Version                        0x1200003
+#define mmAudio_Az_Output_Payload_Capability            0x1200004
+#define mmAudio_Az_Input_Payload_Capability             0x1200006
+#define mmAudio_Az_Global_Control                       0x1200008
+#define mmAudio_Az_Wake_Enable                          0x120000C
+#define mmAudio_Az_State_Change_Status                  0x120000E
+#define mmAudio_Az_Global_Status                        0x1200010
+#define mmAudio_Az_Linked_List_Capability_Header        0x1200014
+#define mmAudio_Az_Output_Stream_Payload_Capability     0x1200018
+#define mmAudio_Az_Input_Stream_Payload_Capability      0x120001A
+#define mmAudio_Az_Interrupt_Control                    0x1200020
+#define mmAudio_Az_Interrupt_Status                     0x1200024
+#define mmAudio_Az_Wall_Clock_Counter                   0x1200030
+#define mmAudio_Az_Stream_Synchronization               0x1200038
+#define mmAudio_Az_CORB_Lower_Base_Address              0x1200040
+#define mmAudio_Az_CORB_Upper_Base_Address              0x1200044
+#define mmAudio_Az_CORB_Write_Pointer                   0x1200048
+#define mmAudio_Az_CORB_Read_Pointer                    0x120004A
+#define mmAudio_Az_CORB_Control                         0x120004C
+#define mmAudio_Az_CORB_Status                          0x120004D
+#define mmAudio_Az_CORB_Size                            0x120004E
+#define mmAudio_Az_RIRB_Lower_Base_Address              0x1200050
+#define mmAudio_Az_RIRB_Upper_Base_Address              0x1200054
+#define mmAudio_Az_RIRB_Write_Pointer                   0x1200058
+#define mmAudio_Az_RIRB_Response_Interrupt_Count        0x120005A
+#define mmAudio_Az_RIRB_Control                         0x120005C
+#define mmAudio_Az_RIRB_Status                          0x120005D
+#define mmAudio_Az_RIRB_Size                            0x120005E
+#define mmAudio_Az_Immediate_Command_Output_Interface   0x1200060
+#define mmAudio_Az_Immediate_Response_Input_Interface   0x1200064
+#define mmAudio_Az_Immediate_Command_Status             0x1200068
+#define mmAudio_Az_DPLBASE                              0x1200070
+#define mmAudio_Az_DPUBASE                              0x1200074
+#define mmAudio_Az_Input_SD0CTL_and_STS                 0x1200080
+#define mmAudio_Az_Input_SD0LPIB                        0x1200084
+#define mmAudio_Az_Input_SD0CBL                         0x1200088
+#define mmAudio_Az_Input_SD0LVI                         0x120008C
+#define mmAudio_Az_Input_SD0FIFOS                       0x1200090
+#define mmAudio_Az_Input_SD0FMT                         0x1200092
+#define mmAudio_Az_Input_SD0BDPL                        0x1200098
+#define mmAudio_Az_Input_SD0BDPU                        0x120009C
+#define mmAudio_Az_Input_SD1CTL_and_STS                 0x12000A0
+#define mmAudio_Az_Input_SD1LPIB                        0x12000A4
+#define mmAudio_Az_Input_SD1CBL                         0x12000A8
+#define mmAudio_Az_Input_SD1LVI                         0x12000AC
+#define mmAudio_Az_Input_SD1FIFOS                       0x12000B0
+#define mmAudio_Az_Input_SD1FMT                         0x12000B2
+#define mmAudio_Az_Input_SD1BDPL                        0x12000B8
+#define mmAudio_Az_Input_SD1BDPU                        0x12000BC
+#define mmAudio_Az_Input_SD2CTL_and_STS                 0x12000C0
+#define mmAudio_Az_Input_SD2LPIB                        0x12000C4
+#define mmAudio_Az_Input_SD2CBL                         0x12000C8
+#define mmAudio_Az_Input_SD2LVI                         0x12000CC
+#define mmAudio_Az_Input_SD2FIFOS                       0x12000D0
+#define mmAudio_Az_Input_SD2FMT                         0x12000D2
+#define mmAudio_Az_Input_SD2BDPL                        0x12000D8
+#define mmAudio_Az_Input_SD2BDPU                        0x12000DC
+#define mmAudio_Az_Input_SD3CTL_and_STS                 0x12000E0
+#define mmAudio_Az_Input_SD3LPIB                        0x12000E4
+#define mmAudio_Az_Input_SD3CBL                         0x12000E8
+#define mmAudio_Az_Input_SD3LVI                         0x12000EC
+#define mmAudio_Az_Input_SD3FIFOS                       0x12000F0
+#define mmAudio_Az_Input_SD3FMT                         0x12000F2
+#define mmAudio_Az_Input_SD3BDPL                        0x12000F8
+#define mmAudio_Az_Input_SD3BDPU                        0x12000FC
+#define mmAudio_Az_Output_SD0CTL_and_STS                0x1200100
+#define mmAudio_Az_Output_SD0LPIB                       0x1200104
+#define mmAudio_Az_Output_SD0CBL                        0x1200108
+#define mmAudio_Az_Output_SD0LVI                        0x120010C
+#define mmAudio_Az_Output_SD0FIFOS                      0x1200110
+#define mmAudio_Az_Output_SD0FMT                        0x1200112
+#define mmAudio_Az_Output_SD0BDPL                       0x1200118
+#define mmAudio_Az_Output_SD0BDPU                       0x120011C
+#define mmAudio_Az_Output_SD1CTL_and_STS                0x1200120
+#define mmAudio_Az_Output_SD1LPIB                       0x1200124
+#define mmAudio_Az_Output_SD1CBL                        0x1200128
+#define mmAudio_Az_Output_SD1LVI                        0x120012C
+#define mmAudio_Az_Output_SD1FIFOS                      0x1200130
+#define mmAudio_Az_Output_SD1FMT                        0x1200132
+#define mmAudio_Az_Output_SD1BDPL                       0x1200138
+#define mmAudio_Az_Output_SD1BDPU                       0x120013C
+#define mmAudio_Az_Output_SD2CTL_and_STS                0x1200140
+#define mmAudio_Az_Output_SD2LPIB                       0x1200144
+#define mmAudio_Az_Output_SD2CBL                        0x1200148
+#define mmAudio_Az_Output_SD2LVI                        0x120014C
+#define mmAudio_Az_Output_SD2FIFOS                      0x1200150
+#define mmAudio_Az_Output_SD2FMT                        0x1200152
+#define mmAudio_Az_Output_SD2BDPL                       0x1200158
+#define mmAudio_Az_Output_SD2BDPU                       0x120015C
+#define mmAudio_Az_Output_SD3CTL_and_STS                0x1200160
+#define mmAudio_Az_Output_SD3LPIB                       0x1200164
+#define mmAudio_Az_Output_SD3CBL                        0x1200168
+#define mmAudio_Az_Output_SD3LVI                        0x120016C
+#define mmAudio_Az_Output_SD3FIFOS                      0x1200170
+#define mmAudio_Az_Output_SD3FMT                        0x1200172
+#define mmAudio_Az_Output_SD3BDPL                       0x1200178
+#define mmAudio_Az_Output_SD3BDPU                       0x120017C
+#define mmAudioAZ_Misc_Control_Register_1               0x1200180
+#define mmAudioAZ_Misc_Control_Register_2               0x1200182
+#define mmAudioAZ_Misc_Control_Register_3               0x1200183
+#define mmAudio_AZ_Multiple_Links_Capability_Header     0x1200200
+#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204
+#define mmAudio_AZ_Link0_Capabilities                   0x1200240
+#define mmAudio_AZ_Link0_Control                        0x1200244
+#define mmAudio_AZ_Link0_Output_Stream_ID               0x1200248
+#define mmAudio_AZ_Link0_SDI_Identifier                 0x120024C
+#define mmAudio_AZ_Link0_Per_Stream_Overhead            0x1200250
+#define mmAudio_AZ_Link0_Wall_Frame_Counter             0x1200258
+#define mmAudio_AZ_Link0_Output_Payload_Capability_L    0x1200260
+#define mmAudio_AZ_Link0_Output_Payload_Capability_U    0x1200264
+#define mmAudio_AZ_Link0_Input_Payload_Capability_L     0x1200270
+#define mmAudio_AZ_Link0_Input_Payload_Capability_U     0x1200274
+#define mmAudio_Az_Input_SD0LICBA                       0x1202084
+#define mmAudio_Az_Input_SD1LICBA                       0x12020A4
+#define mmAudio_Az_Input_SD2LICBA                       0x12020C4
+#define mmAudio_Az_Input_SD3LICBA                       0x12020E4
+#define mmAudio_Az_Output_SD0LICBA                      0x1202104
+#define mmAudio_Az_Output_SD1LICBA                      0x1202124
+#define mmAudio_Az_Output_SD2LICBA                      0x1202144
+#define mmAudio_Az_Output_SD3LICBA                      0x1202164
+#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL             0x1204000
+#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL                  0x1204004
+#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL                  0x1204008
+
+
+// Registers from ACP_AZALIA block
+
+#define mmACP_AZ_PAGE0_LBASE_ADDR                       0x1243800
+#define mmACP_AZ_PAGE0_UBASE_ADDR                       0x1243804
+#define mmACP_AZ_PAGE0_PGEN_SIZE                        0x1243808
+#define mmACP_AZ_PAGE0_OFFSET                           0x124380C
+#define mmACP_AZ_PAGE1_LBASE_ADDR                       0x1243810
+#define mmACP_AZ_PAGE1_UBASE_ADDR                       0x1243814
+#define mmACP_AZ_PAGE1_PGEN_SIZE                        0x1243818
+#define mmACP_AZ_PAGE1_OFFSET                           0x124381C
+#define mmACP_AZ_PAGE2_LBASE_ADDR                       0x1243820
+#define mmACP_AZ_PAGE2_UBASE_ADDR                       0x1243824
+#define mmACP_AZ_PAGE2_PGEN_SIZE                        0x1243828
+#define mmACP_AZ_PAGE2_OFFSET                           0x124382C
+#define mmACP_AZ_PAGE3_LBASE_ADDR                       0x1243830
+#define mmACP_AZ_PAGE3_UBASE_ADDR                       0x1243834
+#define mmACP_AZ_PAGE3_PGEN_SIZE                        0x1243838
+#define mmACP_AZ_PAGE3_OFFSET                           0x124383C
+#define mmACP_AZ_PAGE4_LBASE_ADDR                       0x1243840
+#define mmACP_AZ_PAGE4_UBASE_ADDR                       0x1243844
+#define mmACP_AZ_PAGE4_PGEN_SIZE                        0x1243848
+#define mmACP_AZ_PAGE4_OFFSET                           0x124384C
+#define mmACP_AZ_PAGE5_LBASE_ADDR                       0x1243850
+#define mmACP_AZ_PAGE5_UBASE_ADDR                       0x1243854
+#define mmACP_AZ_PAGE5_PGEN_SIZE                        0x1243858
+#define mmACP_AZ_PAGE5_OFFSET                           0x124385C
+#define mmACP_AZ_PAGE6_LBASE_ADDR                       0x1243860
+#define mmACP_AZ_PAGE6_UBASE_ADDR                       0x1243864
+#define mmACP_AZ_PAGE6_PGEN_SIZE                        0x1243868
+#define mmACP_AZ_PAGE6_OFFSET                           0x124386C
+#define mmACP_AZ_PAGE7_LBASE_ADDR                       0x1243870
+#define mmACP_AZ_PAGE7_UBASE_ADDR                       0x1243874
+#define mmACP_AZ_PAGE7_PGEN_SIZE                        0x1243878
+#define mmACP_AZ_PAGE7_OFFSET                           0x124387C
+
+
+#endif
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
new file mode 100644 (file)
index 0000000..facec24
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// AMD ACP PCI Driver
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include "acp3x.h"
+
+struct acp3x_dev_data {
+       void __iomem *acp3x_base;
+       bool acp3x_audio_mode;
+       struct resource *res;
+       struct platform_device *pdev;
+};
+
+static int snd_acp3x_probe(struct pci_dev *pci,
+                          const struct pci_device_id *pci_id)
+{
+       int ret;
+       u32 addr, val;
+       struct acp3x_dev_data *adata;
+       struct platform_device_info pdevinfo;
+       unsigned int irqflags;
+
+       if (pci_enable_device(pci)) {
+               dev_err(&pci->dev, "pci_enable_device failed\n");
+               return -ENODEV;
+       }
+
+       ret = pci_request_regions(pci, "AMD ACP3x audio");
+       if (ret < 0) {
+               dev_err(&pci->dev, "pci_request_regions failed\n");
+               goto disable_pci;
+       }
+
+       adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
+                            GFP_KERNEL);
+       if (!adata) {
+               ret = -ENOMEM;
+               goto release_regions;
+       }
+
+       /* check for msi interrupt support */
+       ret = pci_enable_msi(pci);
+       if (ret)
+               /* msi is not enabled */
+               irqflags = IRQF_SHARED;
+       else
+               /* msi is enabled */
+               irqflags = 0;
+
+       addr = pci_resource_start(pci, 0);
+       adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
+       if (!adata->acp3x_base) {
+               ret = -ENOMEM;
+               goto release_regions;
+       }
+       pci_set_master(pci);
+       pci_set_drvdata(pci, adata);
+
+       val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
+       switch (val) {
+       case I2S_MODE:
+               adata->res = devm_kzalloc(&pci->dev,
+                                         sizeof(struct resource) * 2,
+                                         GFP_KERNEL);
+               if (!adata->res) {
+                       ret = -ENOMEM;
+                       goto unmap_mmio;
+               }
+
+               adata->res[0].name = "acp3x_i2s_iomem";
+               adata->res[0].flags = IORESOURCE_MEM;
+               adata->res[0].start = addr;
+               adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+
+               adata->res[1].name = "acp3x_i2s_irq";
+               adata->res[1].flags = IORESOURCE_IRQ;
+               adata->res[1].start = pci->irq;
+               adata->res[1].end = pci->irq;
+
+               adata->acp3x_audio_mode = ACP3x_I2S_MODE;
+
+               memset(&pdevinfo, 0, sizeof(pdevinfo));
+               pdevinfo.name = "acp3x_rv_i2s";
+               pdevinfo.id = 0;
+               pdevinfo.parent = &pci->dev;
+               pdevinfo.num_res = 2;
+               pdevinfo.res = adata->res;
+               pdevinfo.data = &irqflags;
+               pdevinfo.size_data = sizeof(irqflags);
+
+               adata->pdev = platform_device_register_full(&pdevinfo);
+               if (IS_ERR(adata->pdev)) {
+                       dev_err(&pci->dev, "cannot register %s device\n",
+                               pdevinfo.name);
+                       ret = PTR_ERR(adata->pdev);
+                       goto unmap_mmio;
+               }
+               break;
+       default:
+               dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
+               ret = -ENODEV;
+               goto unmap_mmio;
+       }
+       return 0;
+
+unmap_mmio:
+       pci_disable_msi(pci);
+       iounmap(adata->acp3x_base);
+release_regions:
+       pci_release_regions(pci);
+disable_pci:
+       pci_disable_device(pci);
+
+       return ret;
+}
+
+static void snd_acp3x_remove(struct pci_dev *pci)
+{
+       struct acp3x_dev_data *adata = pci_get_drvdata(pci);
+
+       platform_device_unregister(adata->pdev);
+       iounmap(adata->acp3x_base);
+
+       pci_disable_msi(pci);
+       pci_release_regions(pci);
+       pci_disable_device(pci);
+}
+
+static const struct pci_device_id snd_acp3x_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
+       .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
+       .class_mask = 0xffffff },
+       { 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
+
+static struct pci_driver acp3x_driver  = {
+       .name = KBUILD_MODNAME,
+       .id_table = snd_acp3x_ids,
+       .probe = snd_acp3x_probe,
+       .remove = snd_acp3x_remove,
+};
+
+module_pci_driver(acp3x_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP3x PCI driver");
+MODULE_LICENSE("GPL v2");
index 9cc4f1848c9ba09e5c649b2ccc3ade6254fb9fd4..62bdb7e333b84fabd8d42890d2e07d9d261914fa 100644 (file)
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ADAU7002
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
+       select SND_SOC_AK4118 if I2C
        select SND_SOC_AK4458 if I2C
        select SND_SOC_AK4535 if I2C
        select SND_SOC_AK4554
@@ -392,6 +393,11 @@ config SND_SOC_AK4104
        tristate "AKM AK4104 CODEC"
        depends on SPI_MASTER
 
+config SND_SOC_AK4118
+       tristate "AKM AK4118 CODEC"
+       depends on I2C
+       select REGMAP_I2C
+
 config SND_SOC_AK4458
        tristate "AKM AK4458 CODEC"
        depends on I2C
index 8ffab8c8dbfa5aadeaa554ff26c3ffb5fd7d8b8a..66f55d18562074ff77f21e4ccb6f2eab02906e63 100644 (file)
@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
 snd-soc-adav803-objs := adav803.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
+snd-soc-ak4118-objs := ak4118.o
 snd-soc-ak4458-objs := ak4458.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4554-objs := ak4554.o
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801)  += snd-soc-adav801.o
 obj-$(CONFIG_SND_SOC_ADAV803)  += snd-soc-adav803.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
+obj-$(CONFIG_SND_SOC_AK4118)   += snd-soc-ak4118.o
 obj-$(CONFIG_SND_SOC_AK4458)   += snd-soc-ak4458.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4554)   += snd-soc-ak4554.o
index 32bc545c19cf73002e08e38606ec69b411b52537..6dec8a65eafcc2ce1eaa0513bd3bcbcf69042511 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <sound/asoundef.h>
 #include <sound/core.h>
@@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = {
 
 static int ak4104_spi_probe(struct spi_device *spi)
 {
-       struct device_node *np = spi->dev.of_node;
        struct ak4104_private *ak4104;
+       struct gpio_desc *reset_gpiod;
        unsigned int val;
        int ret;
 
@@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
                return ret;
        }
 
-       if (np) {
-               enum of_gpio_flags flags;
-               int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
-               if (gpio_is_valid(gpio)) {
-                       ret = devm_gpio_request_one(&spi->dev, gpio,
-                                    flags & OF_GPIO_ACTIVE_LOW ?
-                                       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
-                                    "ak4104 reset");
-                       if (ret < 0)
-                               return ret;
-               }
-       }
+       reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
+                                             GPIOD_OUT_HIGH);
+       if (IS_ERR(reset_gpiod) &&
+           PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        /* read the 'reserved' register - according to the datasheet, it
         * should contain 0x5b. Not a good way to verify the presence of
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
new file mode 100644 (file)
index 0000000..238ab29
--- /dev/null
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4118.c  --  Asahi Kasei ALSA Soc Audio driver
+ *
+ * Copyright 2018 DEVIALET
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define AK4118_REG_CLK_PWR_CTL         0x00
+#define AK4118_REG_FORMAT_CTL          0x01
+#define AK4118_REG_IO_CTL0             0x02
+#define AK4118_REG_IO_CTL1             0x03
+#define AK4118_REG_INT0_MASK           0x04
+#define AK4118_REG_INT1_MASK           0x05
+#define AK4118_REG_RCV_STATUS0         0x06
+#define AK4118_REG_RCV_STATUS1         0x07
+#define AK4118_REG_RXCHAN_STATUS0      0x08
+#define AK4118_REG_RXCHAN_STATUS1      0x09
+#define AK4118_REG_RXCHAN_STATUS2      0x0a
+#define AK4118_REG_RXCHAN_STATUS3      0x0b
+#define AK4118_REG_RXCHAN_STATUS4      0x0c
+#define AK4118_REG_TXCHAN_STATUS0      0x0d
+#define AK4118_REG_TXCHAN_STATUS1      0x0e
+#define AK4118_REG_TXCHAN_STATUS2      0x0f
+#define AK4118_REG_TXCHAN_STATUS3      0x10
+#define AK4118_REG_TXCHAN_STATUS4      0x11
+#define AK4118_REG_BURST_PREAMB_PC0    0x12
+#define AK4118_REG_BURST_PREAMB_PC1    0x13
+#define AK4118_REG_BURST_PREAMB_PD0    0x14
+#define AK4118_REG_BURST_PREAMB_PD1    0x15
+#define AK4118_REG_QSUB_CTL            0x16
+#define AK4118_REG_QSUB_TRACK          0x17
+#define AK4118_REG_QSUB_INDEX          0x18
+#define AK4118_REG_QSUB_MIN            0x19
+#define AK4118_REG_QSUB_SEC            0x1a
+#define AK4118_REG_QSUB_FRAME          0x1b
+#define AK4118_REG_QSUB_ZERO           0x1c
+#define AK4118_REG_QSUB_ABS_MIN                0x1d
+#define AK4118_REG_QSUB_ABS_SEC                0x1e
+#define AK4118_REG_QSUB_ABS_FRAME      0x1f
+#define AK4118_REG_GPE                 0x20
+#define AK4118_REG_GPDR                        0x21
+#define AK4118_REG_GPSCR               0x22
+#define AK4118_REG_GPLR                        0x23
+#define AK4118_REG_DAT_MASK_DTS                0x24
+#define AK4118_REG_RX_DETECT           0x25
+#define AK4118_REG_STC_DAT_DETECT      0x26
+#define AK4118_REG_RXCHAN_STATUS5      0x27
+#define AK4118_REG_TXCHAN_STATUS5      0x28
+#define AK4118_REG_MAX                 0x29
+
+#define AK4118_REG_FORMAT_CTL_DIF0     (1 << 4)
+#define AK4118_REG_FORMAT_CTL_DIF1     (1 << 5)
+#define AK4118_REG_FORMAT_CTL_DIF2     (1 << 6)
+
+struct ak4118_priv {
+       struct regmap *regmap;
+       struct gpio_desc *reset;
+       struct gpio_desc *irq;
+       struct snd_soc_component *component;
+};
+
+static const struct reg_default ak4118_reg_defaults[] = {
+       {AK4118_REG_CLK_PWR_CTL,        0x43},
+       {AK4118_REG_FORMAT_CTL,         0x6a},
+       {AK4118_REG_IO_CTL0,            0x88},
+       {AK4118_REG_IO_CTL1,            0x48},
+       {AK4118_REG_INT0_MASK,          0xee},
+       {AK4118_REG_INT1_MASK,          0xb5},
+       {AK4118_REG_RCV_STATUS0,        0x00},
+       {AK4118_REG_RCV_STATUS1,        0x10},
+       {AK4118_REG_TXCHAN_STATUS0,     0x00},
+       {AK4118_REG_TXCHAN_STATUS1,     0x00},
+       {AK4118_REG_TXCHAN_STATUS2,     0x00},
+       {AK4118_REG_TXCHAN_STATUS3,     0x00},
+       {AK4118_REG_TXCHAN_STATUS4,     0x00},
+       {AK4118_REG_GPE,                0x77},
+       {AK4118_REG_GPDR,               0x00},
+       {AK4118_REG_GPSCR,              0x00},
+       {AK4118_REG_GPLR,               0x00},
+       {AK4118_REG_DAT_MASK_DTS,       0x3f},
+       {AK4118_REG_RX_DETECT,          0x00},
+       {AK4118_REG_STC_DAT_DETECT,     0x00},
+       {AK4118_REG_TXCHAN_STATUS5,     0x00},
+};
+
+static const char * const ak4118_input_select_txt[] = {
+       "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
+};
+static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
+                           ak4118_input_select_txt);
+
+static const struct snd_kcontrol_new ak4118_input_mux_controls =
+       SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
+
+static const char * const ak4118_iec958_fs_txt[] = {
+       "44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
+       "8000", "96000", "64000", "176400", "192000",
+};
+
+static const int ak4118_iec958_fs_val[] = {
+       0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
+                                 0x4, 0x4, ak4118_iec958_fs_txt,
+                                 ak4118_iec958_fs_val);
+
+static struct snd_kcontrol_new ak4118_iec958_controls[] = {
+       SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
+       SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
+       SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
+       SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
+       SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
+};
+
+static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("INRX0"),
+       SND_SOC_DAPM_INPUT("INRX1"),
+       SND_SOC_DAPM_INPUT("INRX2"),
+       SND_SOC_DAPM_INPUT("INRX3"),
+       SND_SOC_DAPM_INPUT("INRX4"),
+       SND_SOC_DAPM_INPUT("INRX5"),
+       SND_SOC_DAPM_INPUT("INRX6"),
+       SND_SOC_DAPM_INPUT("INRX7"),
+       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+                        &ak4118_input_mux_controls),
+};
+
+static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
+       {"Input Mux", "RX0", "INRX0"},
+       {"Input Mux", "RX1", "INRX1"},
+       {"Input Mux", "RX2", "INRX2"},
+       {"Input Mux", "RX3", "INRX3"},
+       {"Input Mux", "RX4", "INRX4"},
+       {"Input Mux", "RX5", "INRX5"},
+       {"Input Mux", "RX6", "INRX6"},
+       {"Input Mux", "RX7", "INRX7"},
+};
+
+
+static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
+                                    unsigned int format)
+{
+       int dif;
+
+       switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               dif = AK4118_REG_FORMAT_CTL_DIF2;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return dif;
+}
+
+static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
+                                   unsigned int format)
+{
+       int dif;
+
+       switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
+                     AK4118_REG_FORMAT_CTL_DIF2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return dif;
+}
+
+static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
+                             unsigned int format)
+{
+       struct snd_soc_component *component = dai->component;
+       struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+       int dif;
+       int ret = 0;
+
+       switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* component is master */
+               dif = ak4118_set_dai_fmt_master(ak4118, format);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /*component is slave */
+               dif = ak4118_set_dai_fmt_slave(ak4118, format);
+               break;
+       default:
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       /* format not supported */
+       if (dif < 0) {
+               ret = dif;
+               goto exit;
+       }
+
+       ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
+                                AK4118_REG_FORMAT_CTL_DIF0 |
+                                AK4118_REG_FORMAT_CTL_DIF1 |
+                                AK4118_REG_FORMAT_CTL_DIF2, dif);
+       if (ret < 0)
+               goto exit;
+
+exit:
+       return ret;
+}
+
+static int ak4118_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ak4118_dai_ops = {
+       .hw_params = ak4118_hw_params,
+       .set_fmt   = ak4118_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ak4118_dai = {
+       .name = "ak4118-hifi",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                        SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE  |
+                          SNDRV_PCM_FMTBIT_S24_3LE |
+                          SNDRV_PCM_FMTBIT_S24_LE
+       },
+       .ops = &ak4118_dai_ops,
+};
+
+static irqreturn_t ak4118_irq_handler(int irq, void *data)
+{
+       struct ak4118_priv *ak4118 = data;
+       struct snd_soc_component *component = ak4118->component;
+       struct snd_kcontrol_new *kctl_new;
+       struct snd_kcontrol *kctl;
+       struct snd_ctl_elem_id *id;
+       unsigned int i;
+
+       if (!component)
+               return IRQ_NONE;
+
+       for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
+               kctl_new = &ak4118_iec958_controls[i];
+               kctl = snd_soc_card_get_kcontrol(component->card,
+                                                kctl_new->name);
+               if (!kctl)
+                       continue;
+               id = &kctl->id;
+               snd_ctl_notify(component->card->snd_card,
+                              SNDRV_CTL_EVENT_MASK_VALUE, id);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int ak4118_probe(struct snd_soc_component *component)
+{
+       struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       ak4118->component = component;
+
+       /* release reset */
+       gpiod_set_value(ak4118->reset, 0);
+
+       /* unmask all int1 sources */
+       ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
+       if (ret < 0) {
+               dev_err(component->dev,
+                       "failed to write regmap 0x%x 0x%x: %d\n",
+                       AK4118_REG_INT1_MASK, 0x00, ret);
+               return ret;
+       }
+
+       /* rx detect enable on all channels */
+       ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
+       if (ret < 0) {
+               dev_err(component->dev,
+                       "failed to write regmap 0x%x 0x%x: %d\n",
+                       AK4118_REG_RX_DETECT, 0xff, ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
+                                        ARRAY_SIZE(ak4118_iec958_controls));
+       if (ret) {
+               dev_err(component->dev,
+                       "failed to add component kcontrols: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ak4118_remove(struct snd_soc_component *component)
+{
+       struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+
+       /* hold reset */
+       gpiod_set_value(ak4118->reset, 1);
+}
+
+static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
+       .probe                  = ak4118_probe,
+       .remove                 = ak4118_remove,
+       .dapm_widgets           = ak4118_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(ak4118_dapm_widgets),
+       .dapm_routes            = ak4118_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(ak4118_dapm_routes),
+       .idle_bias_on           = 1,
+       .use_pmdown_time        = 1,
+       .endianness             = 1,
+       .non_legacy_dai_naming  = 1,
+};
+
+static const struct regmap_config ak4118_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .reg_defaults = ak4118_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
+
+       .cache_type = REGCACHE_NONE,
+       .max_register = AK4118_REG_MAX - 1,
+};
+
+static int ak4118_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct ak4118_priv *ak4118;
+       int ret;
+
+       ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
+                             GFP_KERNEL);
+       if (ak4118 == NULL)
+               return -ENOMEM;
+
+       ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
+       if (IS_ERR(ak4118->regmap))
+               return PTR_ERR(ak4118->regmap);
+
+       i2c_set_clientdata(i2c, ak4118);
+
+       ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(ak4118->reset)) {
+               ret = PTR_ERR(ak4118->reset);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
+               return ret;
+       }
+
+       ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
+       if (IS_ERR(ak4118->irq)) {
+               ret = PTR_ERR(ak4118->irq);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
+                                       NULL, ak4118_irq_handler,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       "ak4118-irq", ak4118);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118,
+                                         &ak4118_dai, 1);
+}
+
+static int ak4118_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_component(&i2c->dev);
+       return 0;
+}
+
+static const struct of_device_id ak4118_of_match[] = {
+       { .compatible = "asahi-kasei,ak4118", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ak4118_of_match);
+
+static const struct i2c_device_id ak4118_id_table[] = {
+       { "ak4118", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
+
+static struct i2c_driver ak4118_i2c_driver = {
+       .driver  = {
+               .name = "ak4118",
+               .of_match_table = of_match_ptr(ak4118_of_match),
+       },
+       .id_table = ak4118_id_table,
+       .probe  = ak4118_i2c_probe,
+       .remove = ak4118_i2c_remove,
+};
+
+module_i2c_driver(ak4118_i2c_driver);
+
+MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
+MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
+MODULE_LICENSE("GPL");
index 299ada4dfaa009f7cdc1d04f6b02ac13987597ae..70d4c89bd6fc38eb1794dfa9f80c4072f60f26d7 100644 (file)
@@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_dai_ops ak4458_dai_ops = {
+static const struct snd_soc_dai_ops ak4458_dai_ops = {
        .startup        = ak4458_startup,
        .hw_params      = ak4458_hw_params,
        .set_fmt        = ak4458_set_dai_fmt,
index 448bb90c9c8e0aa7cac5df5b596b526c286ace04..8179512129d3510cdc0070978da3f57cf624a140 100644 (file)
@@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream,
        u8 bits;
        int pcm_width = max(params_physical_width(params), ak5558->slot_width);
 
-       /* set master/slave audio interface */
-       bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
-       bits &= ~AK5558_BITS;
-
        switch (pcm_width) {
        case 16:
-               bits |= AK5558_DIF_24BIT_MODE;
+               bits = AK5558_DIF_24BIT_MODE;
                break;
        case 32:
-               bits |= AK5558_DIF_32BIT_MODE;
+               bits = AK5558_DIF_32BIT_MODE;
                break;
        default:
                return -EINVAL;
@@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        }
 
        /* set master/slave audio interface */
-       format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
-       format &= ~AK5558_DIF;
-
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               format |= AK5558_DIF_I2S_MODE;
+               format = AK5558_DIF_I2S_MODE;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               format |= AK5558_DIF_MSB_MODE;
+               format = AK5558_DIF_MSB_MODE;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               format |= AK5558_DIF_MSB_MODE;
+               format = AK5558_DIF_MSB_MODE;
                break;
        default:
                return -EINVAL;
@@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
                                          &ak5558_rate_constraints);
 }
 
-static struct snd_soc_dai_ops ak5558_dai_ops = {
+static const struct snd_soc_dai_ops ak5558_dai_ops = {
        .startup        = ak5558_startup,
        .hw_params      = ak5558_hw_params,
 
index 3c266eeb89bfb2eaec708783b4974a2d72e1b6a2..33d74f163bd753820bb77bd81d8f0a28461410e5 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
@@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = {
 static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
-       struct device_node *np = i2c_client->dev.of_node;
        struct cs4270_private *cs4270;
+       struct gpio_desc *reset_gpiod;
        unsigned int val;
        int ret, i;
 
@@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        if (ret < 0)
                return ret;
 
-       /* See if we have a way to bring the codec out of reset */
-       if (np) {
-               enum of_gpio_flags flags;
-               int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
-               if (gpio_is_valid(gpio)) {
-                       ret = devm_gpio_request_one(&i2c_client->dev, gpio,
-                                    flags & OF_GPIO_ACTIVE_LOW ?
-                                       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
-                                    "cs4270 reset");
-                       if (ret < 0)
-                               return ret;
-               }
-       }
+       reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
+                                             GPIOD_OUT_HIGH);
+       if (IS_ERR(reset_gpiod) &&
+           PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
        if (IS_ERR(cs4270->regmap))
index 71322e0410ee7623bc7551f8f868a03e5c7f1aaa..da921da50ef0fcc333e9747e3feb0bebbe053f2a 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
+#define MAX_MODESWITCH_DELAY 70
+static int modeswitch_delay;
+module_param(modeswitch_delay, uint, 0644);
+
+static int wakeup_delay;
+module_param(wakeup_delay, uint, 0644);
+
 struct dmic {
        struct gpio_desc *gpio_en;
        int wakeup_delay;
+       /* Delay after DMIC mode switch */
+       int modeswitch_delay;
+};
+
+int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct dmic *dmic = snd_soc_component_get_drvdata(component);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (dmic->modeswitch_delay)
+                       mdelay(dmic->modeswitch_delay);
+
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+       .trigger        = dmic_daiops_trigger,
 };
 
 static int dmic_aif_event(struct snd_soc_dapm_widget *w,
@@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = {
                        | SNDRV_PCM_FMTBIT_S24_LE
                        | SNDRV_PCM_FMTBIT_S16_LE,
        },
+       .ops    = &dmic_dai_ops,
 };
 
 static int dmic_component_probe(struct snd_soc_component *component)
@@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component)
 
        device_property_read_u32(component->dev, "wakeup-delay-ms",
                                 &dmic->wakeup_delay);
+       device_property_read_u32(component->dev, "modeswitch-delay-ms",
+                                &dmic->modeswitch_delay);
+       if (wakeup_delay)
+               dmic->wakeup_delay  = wakeup_delay;
+       if (modeswitch_delay)
+               dmic->modeswitch_delay  = modeswitch_delay;
+
+       if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
+               dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
 
        snd_soc_component_set_drvdata(component, dmic);
 
index 2aaa83028e55f28a45e55081f67bd6ba335da45c..ffecdaaa8cf2bb2e69bde2de7e2acb92cbdec0a1 100644 (file)
@@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
 static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
                                                 struct snd_soc_dai *dai);
 
-static struct snd_soc_dai_ops hdac_hda_dai_ops = {
+static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
        .startup = hdac_hda_dai_open,
        .shutdown = hdac_hda_dai_close,
        .prepare = hdac_hda_dai_prepare,
index e63d6e33df487dff441f1890e8235d491d7d5144..3ab2949c1dfa454f2df8ebf277dd60d82e56631e 100644 (file)
@@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map {
        struct hdac_hdmi_cvt *cvt;
 };
 
+/*
+ * pin to port mapping table where the value indicate the pin number and
+ * the index indicate the port number with 1 base.
+ */
+static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb};
+
 struct hdac_hdmi_drv_data {
        unsigned int vendor_nid;
+       const int *port_map; /* pin to port mapping table */
+       int port_num;
 };
 
 struct hdac_hdmi_priv {
@@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
        return 0;
 }
 
-#define INTEL_VENDOR_NID 0x08
-#define INTEL_GLK_VENDOR_NID 0x0b
+#define INTEL_VENDOR_NID_0x2 0x02
+#define INTEL_VENDOR_NID_0x8 0x08
+#define INTEL_VENDOR_NID_0xb 0x0b
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_SET_VENDOR_VERB 0x781
-#define INTEL_EN_DP12                  0x02 /* enable DP 1.2 features */
+#define INTEL_EN_DP12          0x02 /* enable DP 1.2 features */
 #define INTEL_EN_ALL_PIN_CVTS  0x01 /* enable 2nd & 3rd pins and convertors */
 
 static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
@@ -1538,7 +1547,26 @@ free_widgets:
 
 static int hdac_hdmi_pin2port(void *aptr, int pin)
 {
-       return pin - 4; /* map NID 0x05 -> port #1 */
+       struct hdac_device *hdev = aptr;
+       struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+       const int *map = hdmi->drv_data->port_map;
+       int i;
+
+       if (!hdmi->drv_data->port_num)
+               return pin - 4; /* map NID 0x05 -> port #1 */
+
+       /*
+        * looking for the pin number in the mapping table and return
+        * the index which indicate the port number
+        */
+       for (i = 0; i < hdmi->drv_data->port_num; i++) {
+               if (pin == map[i])
+                       return i + 1;
+       }
+
+       /* return -1 if pin number exceeds our expectation */
+       dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin);
+       return -1;
 }
 
 static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
        struct hdac_hdmi_port *hport = NULL;
        struct snd_soc_component *component = hdmi->component;
        int i;
-
-       /* Don't know how this mapping is derived */
-       hda_nid_t pin_nid = port + 0x04;
+       hda_nid_t pin_nid;
+
+       if (!hdmi->drv_data->port_num) {
+               /* for legacy platforms */
+               pin_nid = port + 0x04;
+       } else if (port < hdmi->drv_data->port_num) {
+               /* get pin number from the pin2port mapping table */
+               pin_nid = hdmi->drv_data->port_map[port - 1];
+       } else {
+               dev_err(&hdev->dev, "Can't find the pin for port %d\n", port);
+               return;
+       }
 
        dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
                                                        pin_nid, pipe);
@@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
        return port->eld.info.spk_alloc;
 }
 
+static struct hdac_hdmi_drv_data intel_icl_drv_data  = {
+       .vendor_nid = INTEL_VENDOR_NID_0x2,
+       .port_map = icl_pin2port_map,
+       .port_num = ARRAY_SIZE(icl_pin2port_map),
+};
+
 static struct hdac_hdmi_drv_data intel_glk_drv_data  = {
-       .vendor_nid = INTEL_GLK_VENDOR_NID,
+       .vendor_nid = INTEL_VENDOR_NID_0xb,
 };
 
 static struct hdac_hdmi_drv_data intel_drv_data  = {
-       .vendor_nid = INTEL_VENDOR_NID,
+       .vendor_nid = INTEL_VENDOR_NID_0x8,
 };
 
 static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@@ -2031,13 +2074,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
         * Turned off in the runtime_suspend during the first explicit
         * pm_runtime_suspend call.
         */
-       ret = snd_hdac_display_power(hdev->bus, true);
-       if (ret < 0) {
-               dev_err(&hdev->dev,
-                       "Cannot turn on display power on i915 err: %d\n",
-                       ret);
-               return ret;
-       }
+       snd_hdac_display_power(hdev->bus, hdev->addr, true);
 
        ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
        if (ret < 0) {
@@ -2065,6 +2102,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
        struct hdac_hdmi_port *port, *port_next;
        int i;
 
+       snd_hdac_display_power(hdev->bus, hdev->addr, false);
+
        list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
                pcm->cvt = NULL;
                if (list_empty(&pcm->port_list))
@@ -2170,7 +2209,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
        struct hdac_device *hdev = dev_to_hdac_dev(dev);
        struct hdac_bus *bus = hdev->bus;
        struct hdac_ext_link *hlink = NULL;
-       int err;
 
        dev_dbg(dev, "Enter: %s\n", __func__);
 
@@ -2196,11 +2234,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
 
        snd_hdac_ext_bus_link_put(bus, hlink);
 
-       err = snd_hdac_display_power(bus, false);
-       if (err < 0)
-               dev_err(dev, "Cannot turn off display power on i915\n");
+       snd_hdac_display_power(bus, hdev->addr, false);
 
-       return err;
+       return 0;
 }
 
 static int hdac_hdmi_runtime_resume(struct device *dev)
@@ -2208,7 +2244,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        struct hdac_device *hdev = dev_to_hdac_dev(dev);
        struct hdac_bus *bus = hdev->bus;
        struct hdac_ext_link *hlink = NULL;
-       int err;
 
        dev_dbg(dev, "Enter: %s\n", __func__);
 
@@ -2224,11 +2259,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
 
        snd_hdac_ext_bus_link_get(bus, hlink);
 
-       err = snd_hdac_display_power(bus, true);
-       if (err < 0) {
-               dev_err(dev, "Cannot turn on display power on i915\n");
-               return err;
-       }
+       snd_hdac_display_power(bus, hdev->addr, true);
 
        hdac_hdmi_skl_enable_all_pins(hdev);
        hdac_hdmi_skl_enable_dp12(hdev);
@@ -2258,6 +2289,8 @@ static const struct hda_device_id hdmi_list[] = {
                                                   &intel_glk_drv_data),
        HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
                                                   &intel_glk_drv_data),
+       HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI",
+                                                  &intel_icl_drv_data),
        {}
 };
 
index a09d01318f793de00237aad9123965ecdd096fc8..9c8616a7b61c9d0810f84173d448d804ab2e25bd 100644 (file)
@@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = {
        }
 };
 
+static void max98373_reset(struct max98373_priv *max98373, struct device *dev)
+{
+       int ret, reg, count;
+
+       /* Software Reset */
+       ret = regmap_update_bits(max98373->regmap,
+               MAX98373_R2000_SW_RESET,
+               MAX98373_SOFT_RESET,
+               MAX98373_SOFT_RESET);
+       if (ret)
+               dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
+
+       count = 0;
+       while (count < 3) {
+               usleep_range(10000, 11000);
+               /* Software Reset Verification */
+               ret = regmap_read(max98373->regmap,
+                       MAX98373_R21FF_REV_ID, &reg);
+               if (!ret) {
+                       dev_info(dev, "Reset completed (retry:%d)\n", count);
+                       return;
+               }
+               count++;
+       }
+       dev_err(dev, "Reset failed. (ret:%d)\n", ret);
+}
+
 static int max98373_probe(struct snd_soc_component *component)
 {
        struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 
        /* Software Reset */
-       regmap_write(max98373->regmap,
-               MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
-       usleep_range(10000, 11000);
+       max98373_reset(max98373, component->dev);
 
        /* IV default slot configuration */
        regmap_write(max98373->regmap,
@@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev)
 {
        struct max98373_priv *max98373 = dev_get_drvdata(dev);
 
-       regmap_write(max98373->regmap,
-               MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
-       usleep_range(10000, 11000);
+       max98373_reset(max98373, dev);
        regcache_cache_only(max98373->regmap, false);
        regcache_sync(max98373->regmap);
        return 0;
index 4ea3287162ad2356721116176cb33a81b258073f..8600c5439e1e36d25aeff37fd5d74e442a3d21ab 100644 (file)
@@ -1,12 +1,10 @@
-/*
- * max9867.c -- max9867 ALSA SoC Audio driver
- *
- * Copyright 2013-15 Maxim Integrated Products
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// MAX9867 ALSA SoC codec driver
+//
+// Copyright 2013-2015 Maxim Integrated Products
+// Copyright 2018 Ladislav Michl <ladis@linux-mips.org>
+//
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -23,254 +21,237 @@ static const char *const max9867_spmode[] = {
        "Stereo Single", "Mono Single",
        "Stereo Single Fast", "Mono Single Fast"
 };
-static const char *const max9867_sidetone_text[] = {
-       "None", "Left", "Right", "LeftRight", "LeftRightDiv2",
-};
 static const char *const max9867_filter_text[] = {"IIR", "FIR"};
 
 static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
        max9867_filter_text);
 static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
        max9867_spmode);
-static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
-       max9867_sidetone_text);
-static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
-static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
-static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
-       0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
-       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv,
+        0,  2, TLV_DB_SCALE_ITEM(-8600, 200, 1),
+        3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0),
+       18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0),
+       26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0),
+       35, 40, TLV_DB_SCALE_ITEM(  350,  50, 0),
+);
+static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0);
+static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv,
+       0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1),
+       3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
 );
 
 static const struct snd_kcontrol_new max9867_snd_controls[] = {
-       SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
-                               MAX9867_RIGHTVOL, 0, 63, 1),
-       SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
-                       MAX9867_RIGHTMICGAIN,
-                       0, 15, 1, max9860_capture_tlv),
-       SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
-                       MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
-       SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
-                       MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
-       SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
-       SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
-       SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
-       SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
-       SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
-                       4, 15, 1, max9860_adc_left_tlv),
-       SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
-                       0, 15, 1, max9860_adc_right_tlv),
+       SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL,
+                       MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv),
+       SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL,
+                       MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv),
+       SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN,
+                       MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv),
+       SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN,
+                       MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv),
+       SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1),
+       SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1,
+                       max9867_dac_tlv),
+       SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0,
+                       max9867_dacboost_tlv),
+       SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1,
+                       max9867_adc_tlv),
        SOC_ENUM("Speaker Mode", max9867_spkmode),
        SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
-       SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
+       SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0),
        SOC_ENUM("DSP Filter", max9867_filter),
 };
 
-static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
+/* Input mixer */
+static const struct snd_kcontrol_new max9867_input_mixer_controls[] = {
+       SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0),
+       SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0),
+};
+
+/* Output mixer */
+static const struct snd_kcontrol_new max9867_output_mixer_controls[] = {
+       SOC_DAPM_DOUBLE_R("Line Bypass Switch",
+                         MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1),
+};
 
-static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
-       MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
-       max9867_mux);
+/* Sidetone mixer */
+static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = {
+       SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0),
+};
 
-static const struct snd_kcontrol_new max9867_dapm_mux_controls =
-       SOC_DAPM_ENUM("Route", max9867_mux_enum);
+/* Line out switch */
+static const struct snd_kcontrol_new max9867_line_out_control =
+       SOC_DAPM_DOUBLE_R("Switch",
+                         MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1);
 
-static const struct snd_kcontrol_new max9867_left_dapm_control =
-       SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
-static const struct snd_kcontrol_new max9867_right_dapm_control =
-       SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
-static const struct snd_kcontrol_new max9867_line_dapm_control =
-       SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
 
 static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
-       SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
-       SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
-       SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_OUTPUT("HPOUT"),
-
-       SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
-       SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
-       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
-               &max9867_dapm_mux_controls),
-
-       SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
-               &max9867_left_dapm_control),
-       SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
-               &max9867_right_dapm_control),
-       SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
-               &max9867_line_dapm_control),
-       SND_SOC_DAPM_INPUT("LINE_IN"),
+       SND_SOC_DAPM_INPUT("MICL"),
+       SND_SOC_DAPM_INPUT("MICR"),
+       SND_SOC_DAPM_INPUT("LINL"),
+       SND_SOC_DAPM_INPUT("LINR"),
+
+       SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+                                    max9867_input_mixer_controls,
+                                    ARRAY_SIZE(max9867_input_mixer_controls)),
+       SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
+       SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
+
+       SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0,
+                          max9867_sidetone_mixer_controls,
+                          ARRAY_SIZE(max9867_sidetone_mixer_controls)),
+       SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0,
+                                    max9867_output_mixer_controls,
+                                    ARRAY_SIZE(max9867_output_mixer_controls)),
+       SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0),
+       SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0),
+       SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0,
+                           &max9867_line_out_control),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
 };
 
 static const struct snd_soc_dapm_route max9867_audio_map[] = {
-       {"Left DAC", NULL, "DAI_OUT"},
-       {"Right DAC", NULL, "DAI_OUT"},
-       {"Output Mixer", NULL, "Left DAC"},
-       {"Output Mixer", NULL, "Right DAC"},
-       {"HPOUT", NULL, "Output Mixer"},
-
-       {"Left ADC", NULL, "DAI_IN"},
-       {"Right ADC", NULL, "DAI_IN"},
-       {"Input Mixer", NULL, "Left ADC"},
-       {"Input Mixer", NULL, "Right ADC"},
-       {"Input Mux", "Line", "Input Mixer"},
-       {"Input Mux", "Mic", "Input Mixer"},
-       {"Input Mux", "Mic_Line", "Input Mixer"},
-       {"Right Line", "Switch", "Input Mux"},
-       {"Left Line", "Switch", "Input Mux"},
-       {"LINE_IN", NULL, "Left Line"},
-       {"LINE_IN", NULL, "Right Line"},
+       {"Left Line Input", NULL, "LINL"},
+       {"Right Line Input", NULL, "LINR"},
+       {"Input Mixer", "Mic Capture Switch", "MICL"},
+       {"Input Mixer", "Mic Capture Switch", "MICR"},
+       {"Input Mixer", "Line Capture Switch", "Left Line Input"},
+       {"Input Mixer", "Line Capture Switch", "Right Line Input"},
+       {"ADCL", NULL, "Input Mixer"},
+       {"ADCR", NULL, "Input Mixer"},
+
+       {"Digital", "Sidetone Switch", "ADCL"},
+       {"Digital", "Sidetone Switch", "ADCR"},
+       {"DACL", NULL, "Digital"},
+       {"DACR", NULL, "Digital"},
+
+       {"Output Mixer", "Line Bypass Switch", "Left Line Input"},
+       {"Output Mixer", "Line Bypass Switch", "Right Line Input"},
+       {"Output Mixer", NULL, "DACL"},
+       {"Output Mixer", NULL, "DACR"},
+       {"Master Playback", "Switch", "Output Mixer"},
+       {"LOUT", NULL, "Master Playback"},
+       {"ROUT", NULL, "Master Playback"},
+};
+
+static const unsigned int max9867_rates_44k1[] = {
+       11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = {
+       .list = max9867_rates_44k1,
+       .count = ARRAY_SIZE(max9867_rates_44k1),
 };
 
-enum rates {
-       pcm_rate_8, pcm_rate_16, pcm_rate_24,
-       pcm_rate_32, pcm_rate_44,
-       pcm_rate_48, max_pcm_rate,
+static const unsigned int max9867_rates_48k[] = {
+       8000, 16000, 32000, 48000,
 };
 
-static const struct ni_div_rates {
-       u32 mclk;
-       u16 ni[max_pcm_rate];
-} ni_div[] = {
-       {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
-       {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
-       {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
-       {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
-       {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
-       {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
-       {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
-       {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
+static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = {
+       .list = max9867_rates_48k,
+       .count = ARRAY_SIZE(max9867_rates_48k),
 };
 
-static inline int get_ni_value(int mclk, int rate)
+struct max9867_priv {
+       struct regmap *regmap;
+       const struct snd_pcm_hw_constraint_list *constraints;
+       unsigned int sysclk, pclk;
+       bool master, dsp_a;
+};
+
+static int max9867_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
 {
-       int i, ret = 0;
+        struct max9867_priv *max9867 =
+               snd_soc_component_get_drvdata(dai->component);
 
-       /* find the closest rate index*/
-       for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
-               if (ni_div[i].mclk >= mclk)
-                       break;
-       }
-       if (i == ARRAY_SIZE(ni_div))
-               return -EINVAL;
+       if (max9867->constraints)
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
 
-       switch (rate) {
-       case 8000:
-               return ni_div[i].ni[pcm_rate_8];
-       case 16000:
-               return ni_div[i].ni[pcm_rate_16];
-       case 32000:
-               return ni_div[i].ni[pcm_rate_32];
-       case 44100:
-               return ni_div[i].ni[pcm_rate_44];
-       case 48000:
-               return ni_div[i].ni[pcm_rate_48];
-       default:
-               pr_err("%s wrong rate %d\n", __func__, rate);
-               ret = -EINVAL;
-       }
-       return ret;
+       return 0;
 }
 
 static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
+       int value;
+       unsigned long int rate, ratio;
        struct snd_soc_component *component = dai->component;
        struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
-       unsigned int ni_h, ni_l;
-       int value;
+       unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params),
+                                               max9867->pclk);
 
-       value = get_ni_value(max9867->sysclk, params_rate(params));
-       if (value < 0)
-               return value;
-
-       ni_h = (0xFF00 & value) >> 8;
-       ni_l = 0x00FF & value;
        /* set up the ni value */
        regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
-               MAX9867_NI_HIGH_MASK, ni_h);
+               MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8);
        regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
-               MAX9867_NI_LOW_MASK, ni_l);
-       if (!max9867->master) {
-               /*
-                * digital pll locks on to any externally supplied LRCLK signal
-                * and also enable rapid lock mode.
-                */
-               regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
-                       MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
-               regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
-                       MAX9867_PLL, MAX9867_PLL);
-       } else {
-               unsigned long int bclk_rate, pclk_bclk_ratio;
-               int bclk_value;
-
-               bclk_rate = params_rate(params) * 2 * params_width(params);
-               pclk_bclk_ratio = max9867->pclk/bclk_rate;
-               switch (params_width(params)) {
-               case 8:
-               case 16:
-                       switch (pclk_bclk_ratio) {
-                       case 2:
-                               bclk_value = MAX9867_IFC1B_PCLK_2;
-                               break;
-                       case 4:
-                               bclk_value = MAX9867_IFC1B_PCLK_4;
-                               break;
+               MAX9867_NI_LOW_MASK, 0x00FF & ni);
+       if (max9867->master) {
+               if (max9867->dsp_a) {
+                       value = MAX9867_IFC1B_48X;
+               } else {
+                       rate = params_rate(params) * 2 * params_width(params);
+                       ratio = max9867->pclk / rate;
+                       switch (params_width(params)) {
                        case 8:
-                               bclk_value = MAX9867_IFC1B_PCLK_8;
-                               break;
                        case 16:
-                               bclk_value = MAX9867_IFC1B_PCLK_16;
+                               switch (ratio) {
+                               case 2:
+                                       value = MAX9867_IFC1B_PCLK_2;
+                                       break;
+                               case 4:
+                                       value = MAX9867_IFC1B_PCLK_4;
+                                       break;
+                               case 8:
+                                       value = MAX9867_IFC1B_PCLK_8;
+                                       break;
+                               case 16:
+                                       value = MAX9867_IFC1B_PCLK_16;
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               break;
+                       case 24:
+                               value = MAX9867_IFC1B_48X;
+                               break;
+                       case 32:
+                               value = MAX9867_IFC1B_64X;
                                break;
                        default:
-                               dev_err(component->dev,
-                                       "unsupported sampling rate\n");
                                return -EINVAL;
                        }
-                       break;
-               case 24:
-                       bclk_value = MAX9867_IFC1B_24BIT;
-                       break;
-               case 32:
-                       bclk_value = MAX9867_IFC1B_32BIT;
-                       break;
-               default:
-                       dev_err(component->dev, "unsupported sampling rate\n");
-                       return -EINVAL;
                }
                regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
-                       MAX9867_IFC1B_BCLK_MASK, bclk_value);
+                       MAX9867_IFC1B_BCLK_MASK, value);
+       } else {
+               /*
+                * digital pll locks on to any externally supplied LRCLK signal
+                * and also enable rapid lock mode.
+                */
+               regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
+                       MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
+               regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
+                       MAX9867_PLL, MAX9867_PLL);
        }
        return 0;
 }
 
-static int max9867_prepare(struct snd_pcm_substream *substream,
-                        struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-       struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
-
-       regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
-               MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
-       return 0;
-}
-
 static int max9867_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_component *component = dai->component;
        struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 
-       if (mute)
-               regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
-                       MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
-       else
-               regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
-                       MAX9867_DAC_MUTE_MASK, 0);
-       return 0;
+       return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
+                                 1 << 6, !!mute << 6);
 }
 
 static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        /* Set the prescaler based on the master clock frequency*/
        if (freq >= 10000000 && freq <= 20000000) {
                value |= MAX9867_PSCLK_10_20;
-               max9867->pclk =  freq;
+               max9867->pclk = freq;
        } else if (freq >= 20000000 && freq <= 40000000) {
                value |= MAX9867_PSCLK_20_40;
-               max9867->pclk =  freq/2;
+               max9867->pclk = freq / 2;
        } else if (freq >= 40000000 && freq <= 60000000) {
                value |= MAX9867_PSCLK_40_60;
-               max9867->pclk =  freq/4;
+               max9867->pclk = freq / 4;
        } else {
                dev_err(component->dev,
                        "Invalid clock frequency %uHz (required 10-60MHz)\n",
                        freq);
                return -EINVAL;
        }
-       value = value << MAX9867_PSCLK_SHIFT;
+       if (freq % 48000 == 0)
+               max9867->constraints = &max9867_constraints_48k;
+       else if (freq % 44100 == 0)
+               max9867->constraints = &max9867_constraints_44k1;
+       else
+               dev_warn(component->dev,
+                        "Unable to set exact rate with %uHz clock frequency\n",
+                        freq);
        max9867->sysclk = freq;
+       value = value << MAX9867_PSCLK_SHIFT;
        /* exact integer mode is not supported */
        value &= ~MAX9867_FREQ_MASK;
        regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
@@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_component *component = codec_dai->component;
        struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
-       u8 iface1A = 0, iface1B = 0;
+       u8 iface1A, iface1B;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               max9867->master = 1;
-               iface1A |= MAX9867_MASTER;
+               max9867->master = true;
+               iface1A = MAX9867_MASTER;
+               iface1B = MAX9867_IFC1B_48X;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
-               max9867->master = 0;
-               iface1A &= ~MAX9867_MASTER;
+               max9867->master = false;
+               iface1A = iface1B = 0;
                break;
        default:
                return -EINVAL;
@@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               max9867->dsp_a = false;
                iface1A |= MAX9867_I2S_DLY;
                break;
        case SND_SOC_DAIFMT_DSP_A:
+               max9867->dsp_a = true;
                iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
                break;
        default:
@@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 
        regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
        regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
+
        return 0;
 }
 
 static const struct snd_soc_dai_ops max9867_dai_ops = {
-       .set_fmt = max9867_dai_set_fmt,
        .set_sysclk     = max9867_set_dai_sysclk,
-       .prepare        = max9867_prepare,
+       .set_fmt        = max9867_dai_set_fmt,
        .digital_mute   = max9867_mute,
-       .hw_params = max9867_dai_hw_params,
+       .startup        = max9867_startup,
+       .hw_params      = max9867_dai_hw_params,
 };
 
-#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
-#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-
 static struct snd_soc_dai_driver max9867_dai[] = {
        {
        .name = "max9867-aif1",
@@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = {
                .stream_name = "HiFi Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = MAX9867_RATES,
-               .formats = MAX9867_FORMATS,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
                .stream_name = "HiFi Capture",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = MAX9867_RATES,
-               .formats = MAX9867_FORMATS,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .ops = &max9867_dai_ops,
        .symmetric_rates = 1,
        }
 };
 
-#ifdef CONFIG_PM_SLEEP
-static int max9867_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int max9867_suspend(struct snd_soc_component *component)
 {
-       struct max9867_priv *max9867 = dev_get_drvdata(dev);
+       snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
-       /* Drop down to power saving mode when system is suspended */
-       regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
-               MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
        return 0;
 }
 
-static int max9867_resume(struct device *dev)
+static int max9867_resume(struct snd_soc_component *component)
 {
-       struct max9867_priv *max9867 = dev_get_drvdata(dev);
+       snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
-       regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
-               MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
        return 0;
 }
+#else
+#define max9867_suspend        NULL
+#define max9867_resume NULL
 #endif
 
+static int max9867_set_bias_level(struct snd_soc_component *component,
+                                 enum snd_soc_bias_level level)
+{
+       int err;
+       struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+                       err = regcache_sync(max9867->regmap);
+                       if (err)
+                               return err;
+
+                       err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+                                                MAX9867_SHTDOWN, MAX9867_SHTDOWN);
+                       if (err)
+                               return err;
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+                                        MAX9867_SHTDOWN, 0);
+               if (err)
+                       return err;
+
+               regcache_mark_dirty(max9867->regmap);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver max9867_component = {
        .controls               = max9867_snd_controls,
        .num_controls           = ARRAY_SIZE(max9867_snd_controls),
@@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = {
        .num_dapm_routes        = ARRAY_SIZE(max9867_audio_map),
        .dapm_widgets           = max9867_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(max9867_dapm_widgets),
+       .suspend                = max9867_suspend,
+       .resume                 = max9867_resume,
+       .set_bias_level         = max9867_set_bias_level,
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
@@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = {
        { 0x0B, 0x00 },
        { 0x0C, 0x00 },
        { 0x0D, 0x00 },
-       { 0x0E, 0x00 },
-       { 0x0F, 0x00 },
+       { 0x0E, 0x40 },
+       { 0x0F, 0x40 },
        { 0x10, 0x00 },
        { 0x11, 0x00 },
        { 0x12, 0x00 },
@@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
                const struct i2c_device_id *id)
 {
        struct max9867_priv *max9867;
-       int ret = 0, reg;
+       int ret, reg;
 
-       max9867 = devm_kzalloc(&i2c->dev,
-                       sizeof(*max9867), GFP_KERNEL);
+       max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL);
        if (!max9867)
                return -ENOMEM;
 
@@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
                return ret;
        }
-       ret = regmap_read(max9867->regmap,
-                       MAX9867_REVISION, &reg);
+       ret = regmap_read(max9867->regmap, MAX9867_REVISION, &reg);
        if (ret < 0) {
                dev_err(&i2c->dev, "Failed to read: %d\n", ret);
                return ret;
@@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
        dev_info(&i2c->dev, "device revision: %x\n", reg);
        ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
                        max9867_dai, ARRAY_SIZE(max9867_dai));
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
-               return ret;
-       }
        return ret;
 }
 
@@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, max9867_of_match);
 
-static const struct dev_pm_ops max9867_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
-};
-
 static struct i2c_driver max9867_i2c_driver = {
        .driver = {
                .name = "max9867",
                .of_match_table = of_match_ptr(max9867_of_match),
-               .pm = &max9867_pm_ops,
        },
        .probe  = max9867_i2c_probe,
        .id_table = max9867_i2c_id,
@@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = {
 
 module_i2c_driver(max9867_i2c_driver);
 
-MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
+MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
+MODULE_DESCRIPTION("ASoC MAX9867 driver");
 MODULE_LICENSE("GPL");
index 55cd9976ff47d3ca10e1d12f8f6f6e6119e3f2d3..2277798291a1bdd4bf6e3f393f6dcb0aaccb5a93 100644 (file)
 #define MAX9867_PSCLK_10_20  0x1
 #define MAX9867_PSCLK_20_40  0x2
 #define MAX9867_PSCLK_40_60  0x3
-#define MAX9867_AUDIOCLKHIGH 0x06
-#define MAX9867_NI_HIGH_WIDTH 0x7
-#define MAX9867_NI_HIGH_MASK 0x7F
-#define MAX9867_NI_LOW_MASK 0x7F
-#define MAX9867_NI_LOW_SHIFT 0x1
-#define MAX9867_PLL     (1<<7)
-#define MAX9867_AUDIOCLKLOW  0x07
+#define MAX9867_AUDIOCLKHIGH   0x06
+#define MAX9867_NI_HIGH_MASK   0x7F
+#define MAX9867_NI_LOW_MASK    0xFE
+#define MAX9867_PLL            (1<<7)
+#define MAX9867_AUDIOCLKLOW    0x07
 #define MAX9867_RAPID_LOCK   0x01
 #define MAX9867_IFC1A        0x08
 #define MAX9867_MASTER       (1<<7)
 #define MAX9867_BCI_MODE     (1<<5)
 #define MAX9867_IFC1B        0x09
 #define MAX9867_IFC1B_BCLK_MASK 7
-#define MAX9867_IFC1B_32BIT  0x01
-#define MAX9867_IFC1B_24BIT  0x02
-#define MAX9867_IFC1B_PCLK_2 4
-#define MAX9867_IFC1B_PCLK_4 5
-#define MAX9867_IFC1B_PCLK_8 6
-#define MAX9867_IFC1B_PCLK_16 7
+#define MAX9867_IFC1B_64X      0x01
+#define MAX9867_IFC1B_48X      0x02
+#define MAX9867_IFC1B_PCLK_2   0x04
+#define MAX9867_IFC1B_PCLK_4   0x05
+#define MAX9867_IFC1B_PCLK_8   0x06
+#define MAX9867_IFC1B_PCLK_16  0x07
 #define MAX9867_CODECFLTR    0x0a
-#define MAX9867_DACGAIN      0x0b
+#define MAX9867_SIDETONE     0x0b
 #define MAX9867_DACLEVEL     0x0c
-#define MAX9867_DAC_MUTE_SHIFT 0x6
-#define MAX9867_DAC_MUTE_WIDTH 0x1
-#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
 #define MAX9867_ADCLEVEL     0x0d
 #define MAX9867_LEFTLINELVL  0x0e
-#define MAX9867_RIGTHLINELVL 0x0f
+#define MAX9867_RIGHTLINELVL 0x0f
 #define MAX9867_LEFTVOL      0x10
 #define MAX9867_RIGHTVOL     0x11
 #define MAX9867_LEFTMICGAIN  0x12
 #define MAX9867_RIGHTMICGAIN 0x13
 #define MAX9867_INPUTCONFIG  0x14
-#define MAX9867_INPUT_SHIFT  0x6
 #define MAX9867_MICCONFIG    0x15
 #define MAX9867_MODECONFIG   0x16
 #define MAX9867_PWRMAN       0x17
-#define MAX9867_SHTDOWN_MASK (1<<7)
+#define MAX9867_SHTDOWN      0x80
 #define MAX9867_REVISION     0xff
 
 #define MAX9867_CACHEREGNUM 10
 
-/* codec private data */
-struct max9867_priv {
-       struct regmap *regmap;
-       unsigned int sysclk;
-       unsigned int pclk;
-       unsigned int master;
-};
 #endif
index e3c8cd17daf2dab0afd66d8b18d2462818e164de..4dd1a609756be6be437beef69c6b5f1e99247f8e 100644 (file)
@@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in,
        fvco_max = 0;
        fvco_sel = ARRAY_SIZE(mclk_src_scaling);
        for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
-               fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+               fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
                if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
                        fvco_max < fvco) {
                        fvco_max = fvco;
index 622ce947f134625c8c4d59710426cae661fbe386..c6152a04441635bb7884feb48309eefe8e24593d 100644 (file)
@@ -1,18 +1,14 @@
-/*
- * nau8822.c  --  NAU8822 ALSA Soc Audio Codec driver
- *
- * Copyright 2017 Nuvoton Technology Corp.
- *
- * Author: David Lin <ctlin0@nuvoton.com>
- * Co-author: John Hsu <kchsu0@nuvoton.com>
- * Co-author: Seven Li <wtli@nuvoton.com>
- *
- * Based on WM8974.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// nau8822.c  --  NAU8822 ALSA Soc Audio driver
+//
+// Copyright 2017 Nuvoton Technology Crop.
+//
+// Author: David Lin <ctlin0@nuvoton.com>
+// Co-author: John Hsu <kchsu0@nuvoton.com>
+// Co-author: Seven Li <wtli@nuvoton.com>
+//
+// Based on WM8974.c
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index aa79c969cd44f58682216b07c719334f22a9868a..9c552983a293e8f3eea3175b96979e63687be07f 100644 (file)
@@ -1,13 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * nau8822.h  --  NAU8822 Soc Audio Codec driver
+ * nau8822.h  --  NAU8822 ALSA SoC Audio driver
+ *
+ * Copyright 2017 Nuvoton Technology Crop.
  *
  * Author: David Lin <ctlin0@nuvoton.com>
  * Co-author: John Hsu <kchsu0@nuvoton.com>
  * Co-author: Seven Li <wtli@nuvoton.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __NAU8822_H__
index b9fed99d8b5ed389d15d41af269f79d3f6ae0ce3..7bbcbf5f05c88760957e85b3bce64c04f60a01c0 100644 (file)
@@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
 {
        u32 gain, sidetone;
 
-       if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
-               WARN_ON(1);
+       if (WARN_ON(sig_org == 0 || sig_cros == 0))
                return 0;
-       }
 
        sig_org = nau8825_intlog10_dec3(sig_org);
        sig_cros = nau8825_intlog10_dec3(sig_cros);
index 771b46e1974b9d068cc7797b8c2d0353d4b2ddfd..6714aa8d90268241e5f9065d23d420bac06c6361 100644 (file)
@@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
 };
 
 static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
+                        PCM3060_REG_SHIFT_DAPSV, 1),
+
        SND_SOC_DAPM_OUTPUT("OUTL"),
        SND_SOC_DAPM_OUTPUT("OUTR"),
 
        SND_SOC_DAPM_INPUT("INL"),
        SND_SOC_DAPM_INPUT("INR"),
+
+       SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
+                        PCM3060_REG_SHIFT_ADPSV, 1),
 };
 
 static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
-       { "OUTL", NULL, "Playback" },
-       { "OUTR", NULL, "Playback" },
+       { "OUTL", NULL, "DAC" },
+       { "OUTR", NULL, "DAC" },
 
-       { "Capture", NULL, "INL" },
-       { "Capture", NULL, "INR" },
+       { "ADC", NULL, "INL" },
+       { "ADC", NULL, "INR" },
 };
 
 /* soc component */
@@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap);
 
 /* device */
 
+static void pcm3060_parse_dt(const struct device_node *np,
+                            struct pcm3060_priv *priv)
+{
+       priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
+}
+
 int pcm3060_probe(struct device *dev)
 {
        int rc;
+       struct pcm3060_priv *priv = dev_get_drvdata(dev);
+
+       if (dev->of_node)
+               pcm3060_parse_dt(dev->of_node, priv);
+
+       if (priv->out_se)
+               regmap_update_bits(priv->regmap, PCM3060_REG64,
+                                  PCM3060_REG_SE, PCM3060_REG_SE);
 
        rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
                                             pcm3060_dai,
index fd89a68aa8a77355641aa410bbf6c6507925f508..6a027b4a845d2a4adad1da09c1c29268772d070c 100644 (file)
@@ -25,6 +25,7 @@ struct pcm3060_priv_dai {
 struct pcm3060_priv {
        struct regmap *regmap;
        struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
+       u8 out_se: 1;
 };
 
 int pcm3060_probe(struct device *dev);
@@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev);
 #define PCM3060_REG_MRST               0x80
 #define PCM3060_REG_SRST               0x40
 #define PCM3060_REG_ADPSV              0x20
+#define PCM3060_REG_SHIFT_ADPSV        0x05
 #define PCM3060_REG_DAPSV              0x10
+#define PCM3060_REG_SHIFT_DAPSV        0x04
 #define PCM3060_REG_SE                 0x01
 
 #define PCM3060_REG65                  0x41
index 52cc950c9fd174912ea8e49797e6b8e8a0d28c78..08d3fe192e657218c6f78125b05405277cf53af3 100644 (file)
@@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
        SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
        SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
        SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
-       SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
-       SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
-       SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
-       SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
        SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
        SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
        SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
@@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
        SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
        SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
        SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
-       SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
-       SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
-       SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
        SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
        SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
        SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
@@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
        unsigned int fmt;
        unsigned int sample_min;
        unsigned int channel_max;
+       unsigned int channel_maxs[] = {
+               6, /* rx */
+               8  /* tx */
+       };
 
        if (tx)
                fmt = pcm3168a->dac_fmt;
@@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
                channel_max =  2;
                break;
        case PCM3168A_FMT_LEFT_J:
-               sample_min  = 24;
-               if (tx)
-                       channel_max = 8;
-               else
-                       channel_max = 6;
-               break;
        case PCM3168A_FMT_I2S:
                sample_min  = 24;
-               if (tx)
-                       channel_max = 8;
-               else
-                       channel_max = 6;
+               channel_max = channel_maxs[tx];
                break;
        default:
                sample_min  = 24;
@@ -770,15 +758,22 @@ err_clk:
 }
 EXPORT_SYMBOL_GPL(pcm3168a_probe);
 
-void pcm3168a_remove(struct device *dev)
+static void pcm3168a_disable(struct device *dev)
 {
        struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
 
-       pm_runtime_disable(dev);
        regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
-                               pcm3168a->supplies);
+                              pcm3168a->supplies);
        clk_disable_unprepare(pcm3168a->scki);
 }
+
+void pcm3168a_remove(struct device *dev)
+{
+       pm_runtime_disable(dev);
+#ifndef CONFIG_PM
+       pcm3168a_disable(dev);
+#endif
+}
 EXPORT_SYMBOL_GPL(pcm3168a_remove);
 
 #ifdef CONFIG_PM
@@ -833,10 +828,7 @@ static int pcm3168a_rt_suspend(struct device *dev)
 
        regcache_cache_only(pcm3168a->regmap, true);
 
-       regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
-                              pcm3168a->supplies);
-
-       clk_disable_unprepare(pcm3168a->scki);
+       pcm3168a_disable(dev);
 
        return 0;
 }
index f0f2d4fd3769f5785c55d42a613697a6682042b6..6cb1653be80417ae65ceddbc52791dcc92a4a367 100644 (file)
@@ -53,6 +53,8 @@ struct pcm512x_priv {
        unsigned long overclock_pll;
        unsigned long overclock_dac;
        unsigned long overclock_dsp;
+       int mute;
+       struct mutex mutex;
 };
 
 /*
@@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds =
        SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
                        pcm512x_ramp_step_text);
 
+static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
+{
+       return regmap_update_bits(
+               pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
+               (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
+               | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
+}
+
+static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+       mutex_lock(&pcm512x->mutex);
+       ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
+       ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
+       mutex_unlock(&pcm512x->mutex);
+
+       return 0;
+}
+
+static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+       int ret, changed = 0;
+
+       mutex_lock(&pcm512x->mutex);
+
+       if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
+               pcm512x->mute ^= 0x4;
+               changed = 1;
+       }
+       if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
+               pcm512x->mute ^= 0x2;
+               changed = 1;
+       }
+
+       if (changed) {
+               ret = pcm512x_update_mute(pcm512x);
+               if (ret != 0) {
+                       dev_err(component->dev,
+                               "Failed to update digital mute: %d\n", ret);
+                       mutex_unlock(&pcm512x->mutex);
+                       return ret;
+               }
+       }
+
+       mutex_unlock(&pcm512x->mutex);
+
+       return changed;
+}
+
 static const struct snd_kcontrol_new pcm512x_controls[] = {
 SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
                 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
@@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
               PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
 SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
               PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
-          PCM512x_RQMR_SHIFT, 1, 1),
+{
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Digital Playback Switch",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_ctl_boolean_stereo_info,
+       .get = pcm512x_digital_playback_switch_get,
+       .put = pcm512x_digital_playback_switch_put
+},
 
 SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
 SOC_ENUM("DSP Program", pcm512x_dsp_program),
@@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
+static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_component *component = dai->component;
+       struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+       int ret;
+       unsigned int mute_det;
+
+       mutex_lock(&pcm512x->mutex);
+
+       if (mute) {
+               pcm512x->mute |= 0x1;
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
+                                        PCM512x_RQML | PCM512x_RQMR,
+                                        PCM512x_RQML | PCM512x_RQMR);
+               if (ret != 0) {
+                       dev_err(component->dev,
+                               "Failed to set digital mute: %d\n", ret);
+                       mutex_unlock(&pcm512x->mutex);
+                       return ret;
+               }
+
+               regmap_read_poll_timeout(pcm512x->regmap,
+                                        PCM512x_ANALOG_MUTE_DET,
+                                        mute_det, (mute_det & 0x3) == 0,
+                                        200, 10000);
+
+               mutex_unlock(&pcm512x->mutex);
+       } else {
+               pcm512x->mute &= ~0x1;
+               ret = pcm512x_update_mute(pcm512x);
+               if (ret != 0) {
+                       dev_err(component->dev,
+                               "Failed to update digital mute: %d\n", ret);
+                       mutex_unlock(&pcm512x->mutex);
+                       return ret;
+               }
+
+               regmap_read_poll_timeout(pcm512x->regmap,
+                                        PCM512x_ANALOG_MUTE_DET,
+                                        mute_det,
+                                        (mute_det & 0x3)
+                                        == ((~pcm512x->mute >> 1) & 0x3),
+                                        200, 10000);
+       }
+
+       mutex_unlock(&pcm512x->mutex);
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops pcm512x_dai_ops = {
        .startup = pcm512x_dai_startup,
        .hw_params = pcm512x_hw_params,
        .set_fmt = pcm512x_set_fmt,
+       .digital_mute = pcm512x_digital_mute,
 };
 
 static struct snd_soc_dai_driver pcm512x_dai = {
@@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        if (!pcm512x)
                return -ENOMEM;
 
+       mutex_init(&pcm512x->mutex);
+
        dev_set_drvdata(dev, pcm512x);
        pcm512x->regmap = regmap;
 
index d70d9c0c2088c57da901161bc6e4301f6752fa52..9dda8693498ef655dd9f4558095aaa4b347fa138 100644 (file)
 #define PCM512x_RQST_SHIFT 4
 
 /* Page 0, Register 3 - mute */
+#define PCM512x_RQMR (1 << 0)
 #define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML (1 << 4)
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
index 27f7445b2432005e236f47f82de1c576316c598f..e74b2e8cd423e39a7d8d227066b07d25061b7a44 100644 (file)
@@ -1246,6 +1246,7 @@ MODULE_DEVICE_TABLE(of, rt5660_of_match);
 
 static const struct acpi_device_id rt5660_acpi_match[] = {
        { "10EC5660", 0 },
+       { "10EC3277", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
index 7eb2cbd39d6e092404c64317415d85151b94eaa1..da6647015708080ffaa6f897f4fbd8a728d9ce35 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -33,6 +34,9 @@
 #define RT5663_DEVICE_ID_2 0x6451
 #define RT5663_DEVICE_ID_1 0x6406
 
+#define RT5663_POWER_ON_DELAY_MS 300
+#define RT5663_SUPPLY_CURRENT_UA 500000
+
 enum {
        CODEC_VER_1,
        CODEC_VER_0,
@@ -48,6 +52,11 @@ struct impedance_mapping_table {
        unsigned int dc_offset_r_manual_mic;
 };
 
+static const char *const rt5663_supply_names[] = {
+       "avdd",
+       "cpvdd",
+};
+
 struct rt5663_priv {
        struct snd_soc_component *component;
        struct rt5663_platform_data pdata;
@@ -56,6 +65,7 @@ struct rt5663_priv {
        struct snd_soc_jack *hs_jack;
        struct timer_list btn_check_timer;
        struct impedance_mapping_table *imp_table;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)];
 
        int codec_ver;
        int sysclk;
@@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
 {
        struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct rt5663_priv *rt5663;
-       int ret;
+       int ret, i;
        unsigned int val;
        struct regmap *regmap;
 
@@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
        else
                rt5663_parse_dp(rt5663, &i2c->dev);
 
+       for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++)
+               rt5663->supplies[i].supply = rt5663_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev,
+                                     ARRAY_SIZE(rt5663->supplies),
+                                     rt5663->supplies);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       /* Set load for regulator. */
+       for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) {
+               ret = regulator_set_load(rt5663->supplies[i].consumer,
+                                        RT5663_SUPPLY_CURRENT_UA);
+               if (ret < 0) {
+                       dev_err(&i2c->dev,
+                               "Failed to set regulator load on %s, ret: %d\n",
+                               rt5663->supplies[i].supply, ret);
+                       return ret;
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies),
+                                   rt5663->supplies);
+
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+       msleep(RT5663_POWER_ON_DELAY_MS);
+
        regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
        if (IS_ERR(regmap)) {
                ret = PTR_ERR(regmap);
                dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
                        ret);
-               return ret;
+               goto err_enable;
        }
 
        ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
@@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev,
                        "Device with ID register %#x is not rt5663\n",
                        val);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_enable;
        }
 
        if (IS_ERR(rt5663->regmap)) {
                ret = PTR_ERR(rt5663->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
                        ret);
-               return ret;
+               goto err_enable;
        }
 
        /* reset and calibrate */
@@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
                ret = request_irq(i2c->irq, rt5663_irq,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
                        | IRQF_ONESHOT, "rt5663", rt5663);
-               if (ret)
+               if (ret) {
                        dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
                                __func__, ret);
+                       goto err_enable;
+               }
        }
 
        ret = devm_snd_soc_register_component(&i2c->dev,
                        &soc_component_dev_rt5663,
                        rt5663_dai, ARRAY_SIZE(rt5663_dai));
 
-       if (ret) {
-               if (i2c->irq)
-                       free_irq(i2c->irq, rt5663);
-       }
+       if (ret)
+               goto err_enable;
 
+       return 0;
+
+
+       /*
+        * Error after enabling regulators should goto err_enable
+        * to disable regulators.
+        */
+err_enable:
+       if (i2c->irq)
+               free_irq(i2c->irq, rt5663);
+
+       regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
        return ret;
 }
 
@@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
        if (i2c->irq)
                free_irq(i2c->irq, rt5663);
 
+       regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
+
        return 0;
 }
 
index 85524acf3e9cd2cdda5f56cec04a145c2bc99ade..c07e8a80b4b7dc99e5a31f352c9bebad023c2713 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 #include <sound/soc.h>
 
 #define DRV_NAME "simple-amplifier"
@@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
                               (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
        SND_SOC_DAPM_OUTPUT("OUTL"),
        SND_SOC_DAPM_OUTPUT("OUTR"),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0),
 };
 
 static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
        { "DRV", NULL, "INL" },
        { "DRV", NULL, "INR" },
+       { "OUTL", NULL, "VCC" },
+       { "OUTR", NULL, "VCC" },
        { "OUTL", NULL, "DRV" },
        { "OUTR", NULL, "DRV" },
 };
index 36aebdb8f55c5b9540f421235f0c37ef815fd213..aaba3929507993d9e84206cbcae28e176258b9bf 100644 (file)
@@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
        .non_legacy_dai_naming  = 1,
 };
 
-static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
        .hw_params      = tas6424_hw_params,
        .set_fmt        = tas6424_set_dai_fmt,
        .set_tdm_slot   = tas6424_set_dai_tdm_slot,
index 608ad49ad978760cbf9204d4018a2d6a89addcad..c6048d95c6d35187d0d974ae9325cf4c00bc5378 100644 (file)
@@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        if (freq/i > 20000000) {
                dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
                        __func__, freq);
-                       return -EINVAL;
+               return -EINVAL;
        }
        aic31xx->p_div = i;
 
index 6a271e6e6b8fc0149de7c00407decce4524308e0..6aa0edf8c5ef92115da50adc8b775235fa60d7ec 100644 (file)
@@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                aic3x->master = 0;
                iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aic3x->master = 1;
+               iface_areg |= BIT_CLK_MASTER;
+               iface_areg &= ~WORD_CLK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aic3x->master = 1;
+               iface_areg |= WORD_CLK_MASTER;
+               iface_areg &= ~BIT_CLK_MASTER;
+               break;
        default:
                return -EINVAL;
        }
index a957eaeb7bc137e97c6809810f40a1f557a64cd8..32907b1e20cf8fc333d9580819e3cb2f14484700 100644 (file)
@@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
                if (ret != 0) {
                        dev_err(component->dev,
                                "Failed to enable supplies: %d\n", ret);
-                               goto exit;
+                       goto exit;
                }
 
                if (dac33->power_gpio >= 0)
index 61294c787f27423a0aa083777f521971c27717b9..409bed30a4e48e580dadc80ca7af3a7df9ac8159 100644 (file)
@@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
                                dev_warn(component->dev,
                                         "Unsupported ASRC rate1 (%s)\n",
                                         arizona_sample_rate_val_to_name(val));
-                       return -EINVAL;
+                               return -EINVAL;
                        }
                        break;
                default:
index ccdf088461b7f078e1f10891e2ce0db3db4c7023..54c306707c02cc67c360445ad758c977bacb88e3 100644 (file)
@@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
        if (wm9705->mfd_pdata) {
                wm9705->ac97 = wm9705->mfd_pdata->ac97;
                regmap = wm9705->mfd_pdata->regmap;
-       } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+       } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
                wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
                                                      WM9705_VENDOR_ID_MASK);
                if (IS_ERR(wm9705->ac97)) {
@@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
                        snd_soc_free_ac97_component(wm9705->ac97);
                        return PTR_ERR(regmap);
                }
-#endif
+       } else {
+               return -ENXIO;
        }
 
        snd_soc_component_set_drvdata(component, wm9705->ac97);
@@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
 
 static void wm9705_soc_remove(struct snd_soc_component *component)
 {
-#ifdef CONFIG_SND_SOC_AC97_BUS
        struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
 
-       if (!wm9705->mfd_pdata) {
+       if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) {
                snd_soc_component_exit_regmap(component);
                snd_soc_free_ac97_component(wm9705->ac97);
        }
-#endif
 }
 
 static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
index e873baa9e7780fdc6286b40d703615319ce7284a..01949eaba4fd49f4f6980e3092e1abb233165734 100644 (file)
@@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
        if (wm9712->mfd_pdata) {
                wm9712->ac97 = wm9712->mfd_pdata->ac97;
                regmap = wm9712->mfd_pdata->regmap;
-       } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+       } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
                int ret;
 
                wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
@@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
                        snd_soc_free_ac97_component(wm9712->ac97);
                        return PTR_ERR(regmap);
                }
-#endif
+       } else {
+               return -ENXIO;
        }
 
        snd_soc_component_init_regmap(component, regmap);
@@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
 
 static void wm9712_soc_remove(struct snd_soc_component *component)
 {
-#ifdef CONFIG_SND_SOC_AC97_BUS
        struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 
-       if (!wm9712->mfd_pdata) {
+       if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
                snd_soc_component_exit_regmap(component);
                snd_soc_free_ac97_component(wm9712->ac97);
        }
-#endif
 }
 
 static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
index 643863bb32e0d34996c854890d7cbf60b24bd9ef..5a2fdf4f69bf3bc0f72dbd7b6ded0c3252314a7b 100644 (file)
@@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
        if (wm9713->mfd_pdata) {
                wm9713->ac97 = wm9713->mfd_pdata->ac97;
                regmap = wm9713->mfd_pdata->regmap;
-       } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+       } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
                wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
                                                      WM9713_VENDOR_ID_MASK);
                if (IS_ERR(wm9713->ac97))
@@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
                        snd_soc_free_ac97_component(wm9713->ac97);
                        return PTR_ERR(regmap);
                }
-#endif
+       } else {
+               return -ENXIO;
        }
 
        snd_soc_component_init_regmap(component, regmap);
@@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
 
 static void wm9713_soc_remove(struct snd_soc_component *component)
 {
-#ifdef CONFIG_SND_SOC_AC97_BUS
        struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 
-       if (!wm9713->mfd_pdata) {
+       if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) {
                snd_soc_component_exit_regmap(component);
                snd_soc_free_ac97_component(wm9713->ac97);
        }
-#endif
 }
 
 static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
index 66501b8dc46fb17e962f7bf1b69923da7bdae1a6..1dd291cebe67b78d53a48c549b2c7e5a399e75bc 100644 (file)
@@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp)
        return 0;
 }
 
-int wm_adsp1_init(struct wm_adsp *dsp)
+static int wm_adsp_common_init(struct wm_adsp *dsp)
 {
        int ret;
 
@@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp)
                return ret;
 
        INIT_LIST_HEAD(&dsp->alg_regions);
+       INIT_LIST_HEAD(&dsp->ctl_list);
 
        mutex_init(&dsp->pwr_lock);
 
        return 0;
 }
+
+int wm_adsp1_init(struct wm_adsp *dsp)
+{
+       return wm_adsp_common_init(dsp);
+}
 EXPORT_SYMBOL_GPL(wm_adsp1_init);
 
 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp)
 {
        int ret;
 
-       ret = wm_adsp_create_name(dsp);
+       ret = wm_adsp_common_init(dsp);
        if (ret)
                return ret;
 
@@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp)
                break;
        }
 
-       INIT_LIST_HEAD(&dsp->alg_regions);
-       INIT_LIST_HEAD(&dsp->ctl_list);
        INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
 
-       mutex_init(&dsp->pwr_lock);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
deleted file mode 100644 (file)
index 778faff..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-config SND_DAVINCI_SOC
-       tristate
-       depends on ARCH_DAVINCI
-       select SND_EDMA_SOC
-
-config SND_EDMA_SOC
-       tristate "SoC Audio for Texas Instruments chips using eDMA"
-       depends on TI_EDMA
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-       help
-         Say Y or M here if you want audio support for TI SoC which uses eDMA.
-         The following line of SoCs are supported by this platform driver:
-         - daVinci devices
-         - AM335x
-         - AM437x/AM438x
-         - DRA7xx family
-
-config SND_DAVINCI_SOC_I2S
-       tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support"
-       depends on SND_EDMA_SOC
-       help
-         Say Y or M here if you want to have support for McBSP IP found in
-         Texas Instruments DaVinci DA850 SoCs.
-
-config SND_DAVINCI_SOC_MCASP
-       tristate "Multichannel Audio Serial Port (McASP) support"
-       depends on SND_SDMA_SOC || SND_EDMA_SOC
-       help
-         Say Y or M here if you want to have support for McASP IP found in
-         various Texas Instruments SoCs like:
-         - daVinci devices
-         - Sitara line of SoCs (AM335x, AM438x, etc)
-         - DRA7x devices
-
-config SND_DAVINCI_SOC_VCIF
-       tristate
-
-config SND_DAVINCI_SOC_GENERIC_EVM
-       tristate
-       select SND_SOC_TLV320AIC3X
-       select SND_DAVINCI_SOC_MCASP
-
-config SND_AM33XX_SOC_EVM
-       tristate "SoC Audio for the AM33XX chip based boards"
-       depends on SND_EDMA_SOC && SOC_AM33XX && I2C
-       select SND_DAVINCI_SOC_GENERIC_EVM
-       help
-         Say Y or M if you want to add support for SoC audio on AM33XX
-         boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
-         AM335X-EVMSK, and BeagelBone with AudioCape boards have this
-         setup.
-
-config SND_DAVINCI_SOC_EVM
-       tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
-       depends on SND_EDMA_SOC && I2C
-       depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
-       select SND_DAVINCI_SOC_GENERIC_EVM
-       help
-         Say Y if you want to add support for SoC audio on TI
-         DaVinci DM6446, DM355 or DM365 EVM platforms.
-
-choice
-       prompt "DM365 codec select"
-       depends on SND_DAVINCI_SOC_EVM
-       depends on MACH_DAVINCI_DM365_EVM
-
-config SND_DM365_AIC3X_CODEC
-       tristate "Audio Codec - AIC3101"
-       help
-         Say Y if you want to add support for AIC3101 audio codec
-
-config SND_DM365_VOICE_CODEC
-       tristate "Voice Codec - CQ93VC"
-       select MFD_DAVINCI_VOICECODEC
-       select SND_DAVINCI_SOC_VCIF
-       select SND_SOC_CQ0093VC
-       help
-         Say Y if you want to add support for SoC On-chip voice codec
-endchoice
-
-config  SND_DM6467_SOC_EVM
-       tristate "SoC Audio support for DaVinci DM6467 EVM"
-       depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
-       select SND_DAVINCI_SOC_GENERIC_EVM
-       select SND_SOC_SPDIF
-
-       help
-         Say Y if you want to add support for SoC audio on TI
-
-config  SND_DA830_SOC_EVM
-       tristate "SoC Audio support for DA830/OMAP-L137 EVM"
-       depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
-       select SND_DAVINCI_SOC_GENERIC_EVM
-
-       help
-         Say Y if you want to add support for SoC audio on TI
-         DA830/OMAP-L137 EVM
-
-config  SND_DA850_SOC_EVM
-       tristate "SoC Audio support for DA850/OMAP-L138 EVM"
-       depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
-       select SND_DAVINCI_SOC_GENERIC_EVM
-       help
-         Say Y if you want to add support for SoC audio on TI
-         DA850/OMAP-L138 EVM
-
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
deleted file mode 100644 (file)
index 23c6592..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# DAVINCI Platform Support
-snd-soc-edma-objs := edma-pcm.o
-snd-soc-davinci-i2s-objs := davinci-i2s.o
-snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
-snd-soc-davinci-vcif-objs:= davinci-vcif.o
-
-obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
-obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
-obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
-obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
-
-# Generic DAVINCI/AM33xx Machine Support
-snd-soc-evm-objs := davinci-evm.o
-
-obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
deleted file mode 100644 (file)
index 7a369e0..0000000
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * ASoC driver for TI DAVINCI EVM platform
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <asm/mach-types.h>
-
-struct snd_soc_card_drvdata_davinci {
-       struct clk *mclk;
-       unsigned sysclk;
-};
-
-static int evm_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_card *soc_card = rtd->card;
-       struct snd_soc_card_drvdata_davinci *drvdata =
-               snd_soc_card_get_drvdata(soc_card);
-
-       if (drvdata->mclk)
-               return clk_prepare_enable(drvdata->mclk);
-
-       return 0;
-}
-
-static void evm_shutdown(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_card *soc_card = rtd->card;
-       struct snd_soc_card_drvdata_davinci *drvdata =
-               snd_soc_card_get_drvdata(soc_card);
-
-       if (drvdata->mclk)
-               clk_disable_unprepare(drvdata->mclk);
-}
-
-static int evm_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_card *soc_card = rtd->card;
-       int ret = 0;
-       unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
-                          snd_soc_card_get_drvdata(soc_card))->sysclk;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
-       if (ret < 0)
-               return ret;
-
-       /* set the CPU system clock */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops evm_ops = {
-       .startup = evm_startup,
-       .shutdown = evm_shutdown,
-       .hw_params = evm_hw_params,
-};
-
-/* davinci-evm machine dapm widgets */
-static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_LINE("Line Out", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-};
-
-/* davinci-evm machine audio_mapnections to the codec pins */
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* Headphone connected to HPLOUT, HPROUT */
-       {"Headphone Jack", NULL, "HPLOUT"},
-       {"Headphone Jack", NULL, "HPROUT"},
-
-       /* Line Out connected to LLOUT, RLOUT */
-       {"Line Out", NULL, "LLOUT"},
-       {"Line Out", NULL, "RLOUT"},
-
-       /* Mic connected to (MIC3L | MIC3R) */
-       {"MIC3L", NULL, "Mic Bias"},
-       {"MIC3R", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Mic Jack"},
-
-       /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
-       {"LINE1L", NULL, "Line In"},
-       {"LINE2L", NULL, "Line In"},
-       {"LINE1R", NULL, "Line In"},
-       {"LINE2R", NULL, "Line In"},
-};
-
-/* Logic for a aic3x as connected on a davinci-evm */
-static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_card *card = rtd->card;
-       struct device_node *np = card->dev->of_node;
-       int ret;
-
-       /* Add davinci-evm specific widgets */
-       snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
-                                 ARRAY_SIZE(aic3x_dapm_widgets));
-
-       if (np) {
-               ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
-               if (ret)
-                       return ret;
-       } else {
-               /* Set up davinci-evm specific audio path audio_map */
-               snd_soc_dapm_add_routes(&card->dapm, audio_map,
-                                       ARRAY_SIZE(audio_map));
-       }
-
-       /* not connected */
-       snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
-       snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
-       snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
-
-       return 0;
-}
-
-/* davinci-evm digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link dm6446_evm_dai = {
-       .name = "TLV320AIC3X",
-       .stream_name = "AIC3X",
-       .cpu_dai_name = "davinci-mcbsp",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.1-001b",
-       .platform_name = "davinci-mcbsp",
-       .init = evm_aic3x_init,
-       .ops = &evm_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-};
-
-static struct snd_soc_dai_link dm355_evm_dai = {
-       .name = "TLV320AIC3X",
-       .stream_name = "AIC3X",
-       .cpu_dai_name = "davinci-mcbsp.1",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.1-001b",
-       .platform_name = "davinci-mcbsp.1",
-       .init = evm_aic3x_init,
-       .ops = &evm_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-};
-
-static struct snd_soc_dai_link dm365_evm_dai = {
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
-       .name = "TLV320AIC3X",
-       .stream_name = "AIC3X",
-       .cpu_dai_name = "davinci-mcbsp",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.1-0018",
-       .platform_name = "davinci-mcbsp",
-       .init = evm_aic3x_init,
-       .ops = &evm_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
-       .name = "Voice Codec - CQ93VC",
-       .stream_name = "CQ93",
-       .cpu_dai_name = "davinci-vcif",
-       .codec_dai_name = "cq93vc-hifi",
-       .codec_name = "cq93vc-codec",
-       .platform_name = "davinci-vcif",
-#endif
-};
-
-static struct snd_soc_dai_link dm6467_evm_dai[] = {
-       {
-               .name = "TLV320AIC3X",
-               .stream_name = "AIC3X",
-               .cpu_dai_name= "davinci-mcasp.0",
-               .codec_dai_name = "tlv320aic3x-hifi",
-               .platform_name = "davinci-mcasp.0",
-               .codec_name = "tlv320aic3x-codec.0-001a",
-               .init = evm_aic3x_init,
-               .ops = &evm_ops,
-               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                          SND_SOC_DAIFMT_IB_NF,
-       },
-       {
-               .name = "McASP",
-               .stream_name = "spdif",
-               .cpu_dai_name= "davinci-mcasp.1",
-               .codec_dai_name = "dit-hifi",
-               .codec_name = "spdif_dit",
-               .platform_name = "davinci-mcasp.1",
-               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                          SND_SOC_DAIFMT_IB_NF,
-       },
-};
-
-static struct snd_soc_dai_link da830_evm_dai = {
-       .name = "TLV320AIC3X",
-       .stream_name = "AIC3X",
-       .cpu_dai_name = "davinci-mcasp.1",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.1-0018",
-       .platform_name = "davinci-mcasp.1",
-       .init = evm_aic3x_init,
-       .ops = &evm_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-};
-
-static struct snd_soc_dai_link da850_evm_dai = {
-       .name = "TLV320AIC3X",
-       .stream_name = "AIC3X",
-       .cpu_dai_name= "davinci-mcasp.0",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.1-0018",
-       .platform_name = "davinci-mcasp.0",
-       .init = evm_aic3x_init,
-       .ops = &evm_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-};
-
-/* davinci dm6446 evm audio machine driver */
-/*
- * ASP0 in DM6446 EVM is clocked by U55, as configured by
- * board-dm644x-evm.c using GPIOs from U18.  There are six
- * options; here we "know" we use a 48 KHz sample rate.
- */
-static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
-       .sysclk = 12288000,
-};
-
-static struct snd_soc_card dm6446_snd_soc_card_evm = {
-       .name = "DaVinci DM6446 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = &dm6446_evm_dai,
-       .num_links = 1,
-       .drvdata = &dm6446_snd_soc_card_drvdata,
-};
-
-/* davinci dm355 evm audio machine driver */
-/* ASP1 on DM355 EVM is clocked by an external oscillator */
-static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
-       .sysclk = 27000000,
-};
-
-static struct snd_soc_card dm355_snd_soc_card_evm = {
-       .name = "DaVinci DM355 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = &dm355_evm_dai,
-       .num_links = 1,
-       .drvdata = &dm355_snd_soc_card_drvdata,
-};
-
-/* davinci dm365 evm audio machine driver */
-static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
-       .sysclk = 27000000,
-};
-
-static struct snd_soc_card dm365_snd_soc_card_evm = {
-       .name = "DaVinci DM365 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = &dm365_evm_dai,
-       .num_links = 1,
-       .drvdata = &dm365_snd_soc_card_drvdata,
-};
-
-/* davinci dm6467 evm audio machine driver */
-static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
-       .sysclk = 27000000,
-};
-
-static struct snd_soc_card dm6467_snd_soc_card_evm = {
-       .name = "DaVinci DM6467 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = dm6467_evm_dai,
-       .num_links = ARRAY_SIZE(dm6467_evm_dai),
-       .drvdata = &dm6467_snd_soc_card_drvdata,
-};
-
-static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
-       .sysclk = 24576000,
-};
-
-static struct snd_soc_card da830_snd_soc_card = {
-       .name = "DA830/OMAP-L137 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = &da830_evm_dai,
-       .num_links = 1,
-       .drvdata = &da830_snd_soc_card_drvdata,
-};
-
-static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
-       .sysclk = 24576000,
-};
-
-static struct snd_soc_card da850_snd_soc_card = {
-       .name = "DA850/OMAP-L138 EVM",
-       .owner = THIS_MODULE,
-       .dai_link = &da850_evm_dai,
-       .num_links = 1,
-       .drvdata = &da850_snd_soc_card_drvdata,
-};
-
-#if defined(CONFIG_OF)
-
-/*
- * The struct is used as place holder. It will be completely
- * filled with data from dt node.
- */
-static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
-       .name           = "TLV320AIC3X",
-       .stream_name    = "AIC3X",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .ops            = &evm_ops,
-       .init           = evm_aic3x_init,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-                  SND_SOC_DAIFMT_IB_NF,
-};
-
-static const struct of_device_id davinci_evm_dt_ids[] = {
-       {
-               .compatible = "ti,da830-evm-audio",
-               .data = (void *) &evm_dai_tlv320aic3x,
-       },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
-
-/* davinci evm audio machine driver */
-static struct snd_soc_card evm_soc_card = {
-       .owner = THIS_MODULE,
-       .num_links = 1,
-};
-
-static int davinci_evm_probe(struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       const struct of_device_id *match;
-       struct snd_soc_dai_link *dai;
-       struct snd_soc_card_drvdata_davinci *drvdata = NULL;
-       struct clk *mclk;
-       int ret = 0;
-
-       match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
-       if (!match) {
-               dev_err(&pdev->dev, "Error: No device match found\n");
-               return -ENODEV;
-       }
-
-       dai = (struct snd_soc_dai_link *) match->data;
-
-       evm_soc_card.dai_link = dai;
-
-       dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
-       if (!dai->codec_of_node)
-               return -EINVAL;
-
-       dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
-       if (!dai->cpu_of_node)
-               return -EINVAL;
-
-       dai->platform_of_node = dai->cpu_of_node;
-
-       evm_soc_card.dev = &pdev->dev;
-       ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
-       if (ret)
-               return ret;
-
-       mclk = devm_clk_get(&pdev->dev, "mclk");
-       if (PTR_ERR(mclk) == -EPROBE_DEFER) {
-               return -EPROBE_DEFER;
-       } else if (IS_ERR(mclk)) {
-               dev_dbg(&pdev->dev, "mclk not found.\n");
-               mclk = NULL;
-       }
-
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
-       if (!drvdata)
-               return -ENOMEM;
-
-       drvdata->mclk = mclk;
-
-       ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
-
-       if (ret < 0) {
-               if (!drvdata->mclk) {
-                       dev_err(&pdev->dev,
-                               "No clock or clock rate defined.\n");
-                       return -EINVAL;
-               }
-               drvdata->sysclk = clk_get_rate(drvdata->mclk);
-       } else if (drvdata->mclk) {
-               unsigned int requestd_rate = drvdata->sysclk;
-               clk_set_rate(drvdata->mclk, drvdata->sysclk);
-               drvdata->sysclk = clk_get_rate(drvdata->mclk);
-               if (drvdata->sysclk != requestd_rate)
-                       dev_warn(&pdev->dev,
-                                "Could not get requested rate %u using %u.\n",
-                                requestd_rate, drvdata->sysclk);
-       }
-
-       snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
-       ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
-
-       if (ret)
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-
-       return ret;
-}
-
-static struct platform_driver davinci_evm_driver = {
-       .probe          = davinci_evm_probe,
-       .driver         = {
-               .name   = "davinci_evm",
-               .pm     = &snd_soc_pm_ops,
-               .of_match_table = of_match_ptr(davinci_evm_dt_ids),
-       },
-};
-#endif
-
-static struct platform_device *evm_snd_device;
-
-static int __init evm_init(void)
-{
-       struct snd_soc_card *evm_snd_dev_data;
-       int index;
-       int ret;
-
-       /*
-        * If dtb is there, the devices will be created dynamically.
-        * Only register platfrom driver structure.
-        */
-#if defined(CONFIG_OF)
-       if (of_have_populated_dt())
-               return platform_driver_register(&davinci_evm_driver);
-#endif
-
-       if (machine_is_davinci_evm()) {
-               evm_snd_dev_data = &dm6446_snd_soc_card_evm;
-               index = 0;
-       } else if (machine_is_davinci_dm355_evm()) {
-               evm_snd_dev_data = &dm355_snd_soc_card_evm;
-               index = 1;
-       } else if (machine_is_davinci_dm365_evm()) {
-               evm_snd_dev_data = &dm365_snd_soc_card_evm;
-               index = 0;
-       } else if (machine_is_davinci_dm6467_evm()) {
-               evm_snd_dev_data = &dm6467_snd_soc_card_evm;
-               index = 0;
-       } else if (machine_is_davinci_da830_evm()) {
-               evm_snd_dev_data = &da830_snd_soc_card;
-               index = 1;
-       } else if (machine_is_davinci_da850_evm()) {
-               evm_snd_dev_data = &da850_snd_soc_card;
-               index = 0;
-       } else
-               return -EINVAL;
-
-       evm_snd_device = platform_device_alloc("soc-audio", index);
-       if (!evm_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
-       ret = platform_device_add(evm_snd_device);
-       if (ret)
-               platform_device_put(evm_snd_device);
-
-       return ret;
-}
-
-static void __exit evm_exit(void)
-{
-#if defined(CONFIG_OF)
-       if (of_have_populated_dt()) {
-               platform_driver_unregister(&davinci_evm_driver);
-               return;
-       }
-#endif
-
-       platform_device_unregister(evm_snd_device);
-}
-
-module_init(evm_init);
-module_exit(evm_exit);
-
-MODULE_AUTHOR("Vladimir Barinov");
-MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
deleted file mode 100644 (file)
index a3206e6..0000000
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * DT support  (c) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
- *             based on davinci-mcasp.c DT support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * TODO:
- * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/platform_data/davinci_asp.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "edma-pcm.h"
-#include "davinci-i2s.h"
-
-#define DRV_NAME "davinci-i2s"
-
-/*
- * NOTE:  terminology here is confusing.
- *
- *  - This driver supports the "Audio Serial Port" (ASP),
- *    found on dm6446, dm355, and other DaVinci chips.
- *
- *  - But it labels it a "Multi-channel Buffered Serial Port"
- *    (McBSP) as on older chips like the dm642 ... which was
- *    backward-compatible, possibly explaining that confusion.
- *
- *  - OMAP chips have a controller called McBSP, which is
- *    incompatible with the DaVinci flavor of McBSP.
- *
- *  - Newer DaVinci chips have a controller called McASP,
- *    incompatible with ASP and with either McBSP.
- *
- * In short:  this uses ASP to implement I2S, not McBSP.
- * And it won't be the only DaVinci implemention of I2S.
- */
-#define DAVINCI_MCBSP_DRR_REG  0x00
-#define DAVINCI_MCBSP_DXR_REG  0x04
-#define DAVINCI_MCBSP_SPCR_REG 0x08
-#define DAVINCI_MCBSP_RCR_REG  0x0c
-#define DAVINCI_MCBSP_XCR_REG  0x10
-#define DAVINCI_MCBSP_SRGR_REG 0x14
-#define DAVINCI_MCBSP_PCR_REG  0x24
-
-#define DAVINCI_MCBSP_SPCR_RRST                (1 << 0)
-#define DAVINCI_MCBSP_SPCR_RINTM(v)    ((v) << 4)
-#define DAVINCI_MCBSP_SPCR_XRST                (1 << 16)
-#define DAVINCI_MCBSP_SPCR_XINTM(v)    ((v) << 20)
-#define DAVINCI_MCBSP_SPCR_GRST                (1 << 22)
-#define DAVINCI_MCBSP_SPCR_FRST                (1 << 23)
-#define DAVINCI_MCBSP_SPCR_FREE                (1 << 25)
-
-#define DAVINCI_MCBSP_RCR_RWDLEN1(v)   ((v) << 5)
-#define DAVINCI_MCBSP_RCR_RFRLEN1(v)   ((v) << 8)
-#define DAVINCI_MCBSP_RCR_RDATDLY(v)   ((v) << 16)
-#define DAVINCI_MCBSP_RCR_RFIG         (1 << 18)
-#define DAVINCI_MCBSP_RCR_RWDLEN2(v)   ((v) << 21)
-#define DAVINCI_MCBSP_RCR_RFRLEN2(v)   ((v) << 24)
-#define DAVINCI_MCBSP_RCR_RPHASE       BIT(31)
-
-#define DAVINCI_MCBSP_XCR_XWDLEN1(v)   ((v) << 5)
-#define DAVINCI_MCBSP_XCR_XFRLEN1(v)   ((v) << 8)
-#define DAVINCI_MCBSP_XCR_XDATDLY(v)   ((v) << 16)
-#define DAVINCI_MCBSP_XCR_XFIG         (1 << 18)
-#define DAVINCI_MCBSP_XCR_XWDLEN2(v)   ((v) << 21)
-#define DAVINCI_MCBSP_XCR_XFRLEN2(v)   ((v) << 24)
-#define DAVINCI_MCBSP_XCR_XPHASE       BIT(31)
-
-#define DAVINCI_MCBSP_SRGR_FWID(v)     ((v) << 8)
-#define DAVINCI_MCBSP_SRGR_FPER(v)     ((v) << 16)
-#define DAVINCI_MCBSP_SRGR_FSGM                (1 << 28)
-#define DAVINCI_MCBSP_SRGR_CLKSM       BIT(29)
-
-#define DAVINCI_MCBSP_PCR_CLKRP                (1 << 0)
-#define DAVINCI_MCBSP_PCR_CLKXP                (1 << 1)
-#define DAVINCI_MCBSP_PCR_FSRP         (1 << 2)
-#define DAVINCI_MCBSP_PCR_FSXP         (1 << 3)
-#define DAVINCI_MCBSP_PCR_SCLKME       (1 << 7)
-#define DAVINCI_MCBSP_PCR_CLKRM                (1 << 8)
-#define DAVINCI_MCBSP_PCR_CLKXM                (1 << 9)
-#define DAVINCI_MCBSP_PCR_FSRM         (1 << 10)
-#define DAVINCI_MCBSP_PCR_FSXM         (1 << 11)
-
-enum {
-       DAVINCI_MCBSP_WORD_8 = 0,
-       DAVINCI_MCBSP_WORD_12,
-       DAVINCI_MCBSP_WORD_16,
-       DAVINCI_MCBSP_WORD_20,
-       DAVINCI_MCBSP_WORD_24,
-       DAVINCI_MCBSP_WORD_32,
-};
-
-static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
-       [SNDRV_PCM_FORMAT_S8]           = 1,
-       [SNDRV_PCM_FORMAT_S16_LE]       = 2,
-       [SNDRV_PCM_FORMAT_S32_LE]       = 4,
-};
-
-static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
-       [SNDRV_PCM_FORMAT_S8]           = DAVINCI_MCBSP_WORD_8,
-       [SNDRV_PCM_FORMAT_S16_LE]       = DAVINCI_MCBSP_WORD_16,
-       [SNDRV_PCM_FORMAT_S32_LE]       = DAVINCI_MCBSP_WORD_32,
-};
-
-static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
-       [SNDRV_PCM_FORMAT_S8]           = SNDRV_PCM_FORMAT_S16_LE,
-       [SNDRV_PCM_FORMAT_S16_LE]       = SNDRV_PCM_FORMAT_S32_LE,
-};
-
-struct davinci_mcbsp_dev {
-       struct device *dev;
-       struct snd_dmaengine_dai_dma_data dma_data[2];
-       int dma_request[2];
-       void __iomem                    *base;
-#define MOD_DSP_A      0
-#define MOD_DSP_B      1
-       int                             mode;
-       u32                             pcr;
-       struct clk                      *clk;
-       /*
-        * Combining both channels into 1 element will at least double the
-        * amount of time between servicing the dma channel, increase
-        * effiency, and reduce the chance of overrun/underrun. But,
-        * it will result in the left & right channels being swapped.
-        *
-        * If relabeling the left and right channels is not possible,
-        * you may want to let the codec know to swap them back.
-        *
-        * It may allow x10 the amount of time to service dma requests,
-        * if the codec is master and is using an unnecessarily fast bit clock
-        * (ie. tlvaic23b), independent of the sample rate. So, having an
-        * entire frame at once means it can be serviced at the sample rate
-        * instead of the bit clock rate.
-        *
-        * In the now unlikely case that an underrun still
-        * occurs, both the left and right samples will be repeated
-        * so that no pops are heard, and the left and right channels
-        * won't end up being swapped because of the underrun.
-        */
-       unsigned enable_channel_combine:1;
-
-       unsigned int fmt;
-       int clk_div;
-       int clk_input_pin;
-       bool i2s_accurate_sck;
-};
-
-static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
-                                          int reg, u32 val)
-{
-       __raw_writel(val, dev->base + reg);
-}
-
-static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
-{
-       return __raw_readl(dev->base + reg);
-}
-
-static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
-{
-       u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
-       /* The clock needs to toggle to complete reset.
-        * So, fake it by toggling the clk polarity.
-        */
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
-}
-
-static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
-               struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
-       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       u32 spcr;
-       u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
-       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-       if (spcr & mask) {
-               /* start off disabled */
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
-                               spcr & ~mask);
-               toggle_clock(dev, playback);
-       }
-       if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM |
-                       DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) {
-               /* Start the sample generator */
-               spcr |= DAVINCI_MCBSP_SPCR_GRST;
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-       }
-
-       if (playback) {
-               /* Stop the DMA to avoid data loss */
-               /* while the transmitter is out of reset to handle XSYNCERR */
-               if (component->driver->ops->trigger) {
-                       int ret = component->driver->ops->trigger(substream,
-                               SNDRV_PCM_TRIGGER_STOP);
-                       if (ret < 0)
-                               printk(KERN_DEBUG "Playback DMA stop failed\n");
-               }
-
-               /* Enable the transmitter */
-               spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-               spcr |= DAVINCI_MCBSP_SPCR_XRST;
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-
-               /* wait for any unexpected frame sync error to occur */
-               udelay(100);
-
-               /* Disable the transmitter to clear any outstanding XSYNCERR */
-               spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-               spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-               toggle_clock(dev, playback);
-
-               /* Restart the DMA */
-               if (component->driver->ops->trigger) {
-                       int ret = component->driver->ops->trigger(substream,
-                               SNDRV_PCM_TRIGGER_START);
-                       if (ret < 0)
-                               printk(KERN_DEBUG "Playback DMA start failed\n");
-               }
-       }
-
-       /* Enable transmitter or receiver */
-       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-       spcr |= mask;
-
-       if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) {
-               /* Start frame sync */
-               spcr |= DAVINCI_MCBSP_SPCR_FRST;
-       }
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-}
-
-static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
-{
-       u32 spcr;
-
-       /* Reset transmitter/receiver and sample rate/frame sync generators */
-       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-       spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
-       spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-       toggle_clock(dev, playback);
-}
-
-#define DEFAULT_BITPERSAMPLE   16
-
-static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-                                  unsigned int fmt)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
-       unsigned int pcr;
-       unsigned int srgr;
-       bool inv_fs = false;
-       /* Attention srgr is updated by hw_params! */
-       srgr = DAVINCI_MCBSP_SRGR_FSGM |
-               DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
-               DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
-
-       dev->fmt = fmt;
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* cpu is master */
-               pcr = DAVINCI_MCBSP_PCR_FSXM |
-                       DAVINCI_MCBSP_PCR_FSRM |
-                       DAVINCI_MCBSP_PCR_CLKXM |
-                       DAVINCI_MCBSP_PCR_CLKRM;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
-               /*
-                * Selection of the clock input pin that is the
-                * input for the Sample Rate Generator.
-                * McBSP FSR and FSX are driven by the Sample Rate
-                * Generator.
-                */
-               switch (dev->clk_input_pin) {
-               case MCBSP_CLKS:
-                       pcr |= DAVINCI_MCBSP_PCR_CLKXM |
-                               DAVINCI_MCBSP_PCR_CLKRM;
-                       break;
-               case MCBSP_CLKR:
-                       pcr |= DAVINCI_MCBSP_PCR_SCLKME;
-                       break;
-               default:
-                       dev_err(dev->dev, "bad clk_input_pin\n");
-                       return -EINVAL;
-               }
-
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* codec is master */
-               pcr = 0;
-               break;
-       default:
-               printk(KERN_ERR "%s:bad master\n", __func__);
-               return -EINVAL;
-       }
-
-       /* interface format */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               /* Davinci doesn't support TRUE I2S, but some codecs will have
-                * the left and right channels contiguous. This allows
-                * dsp_a mode to be used with an inverted normal frame clk.
-                * If your codec is master and does not have contiguous
-                * channels, then you will have sound on only one channel.
-                * Try using a different mode, or codec as slave.
-                *
-                * The TLV320AIC33 is an example of a codec where this works.
-                * It has a variable bit clock frequency allowing it to have
-                * valid data on every bit clock.
-                *
-                * The TLV320AIC23 is an example of a codec where this does not
-                * work. It has a fixed bit clock frequency with progressively
-                * more empty bit clock slots between channels as the sample
-                * rate is lowered.
-                */
-               inv_fs = true;
-               /* fall through */
-       case SND_SOC_DAIFMT_DSP_A:
-               dev->mode = MOD_DSP_A;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               dev->mode = MOD_DSP_B;
-               break;
-       default:
-               printk(KERN_ERR "%s:bad format\n", __func__);
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               /* CLKRP Receive clock polarity,
-                *      1 - sampled on rising edge of CLKR
-                *      valid on rising edge
-                * CLKXP Transmit clock polarity,
-                *      1 - clocked on falling edge of CLKX
-                *      valid on rising edge
-                * FSRP  Receive frame sync pol, 0 - active high
-                * FSXP  Transmit frame sync pol, 0 - active high
-                */
-               pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP);
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               /* CLKRP Receive clock polarity,
-                *      0 - sampled on falling edge of CLKR
-                *      valid on falling edge
-                * CLKXP Transmit clock polarity,
-                *      0 - clocked on rising edge of CLKX
-                *      valid on falling edge
-                * FSRP  Receive frame sync pol, 1 - active low
-                * FSXP  Transmit frame sync pol, 1 - active low
-                */
-               pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               /* CLKRP Receive clock polarity,
-                *      1 - sampled on rising edge of CLKR
-                *      valid on rising edge
-                * CLKXP Transmit clock polarity,
-                *      1 - clocked on falling edge of CLKX
-                *      valid on rising edge
-                * FSRP  Receive frame sync pol, 1 - active low
-                * FSXP  Transmit frame sync pol, 1 - active low
-                */
-               pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP |
-                       DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               /* CLKRP Receive clock polarity,
-                *      0 - sampled on falling edge of CLKR
-                *      valid on falling edge
-                * CLKXP Transmit clock polarity,
-                *      0 - clocked on rising edge of CLKX
-                *      valid on falling edge
-                * FSRP  Receive frame sync pol, 0 - active high
-                * FSXP  Transmit frame sync pol, 0 - active high
-                */
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (inv_fs == true)
-               pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
-       dev->pcr = pcr;
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
-       return 0;
-}
-
-static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
-                               int div_id, int div)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
-
-       if (div_id != DAVINCI_MCBSP_CLKGDV)
-               return -ENODEV;
-
-       dev->clk_div = div;
-       return 0;
-}
-
-static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       struct snd_interval *i = NULL;
-       int mcbsp_word_length, master;
-       unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
-       u32 spcr;
-       snd_pcm_format_t fmt;
-       unsigned element_cnt = 1;
-
-       /* general line settings */
-       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-       } else {
-               spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
-       }
-
-       master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
-       fmt = params_format(params);
-       mcbsp_word_length = asp_word_length[fmt];
-
-       switch (master) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               freq = clk_get_rate(dev->clk);
-               srgr = DAVINCI_MCBSP_SRGR_FSGM |
-                      DAVINCI_MCBSP_SRGR_CLKSM;
-               srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
-                                               8 - 1);
-               if (dev->i2s_accurate_sck) {
-                       clk_div = 256;
-                       do {
-                               framesize = (freq / (--clk_div)) /
-                               params->rate_num *
-                                       params->rate_den;
-                       } while (((framesize < 33) || (framesize > 4095)) &&
-                                (clk_div));
-                       clk_div--;
-                       srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
-               } else {
-                       /* symmetric waveforms */
-                       clk_div = freq / (mcbsp_word_length * 16) /
-                                 params->rate_num * params->rate_den;
-                       srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
-                                                       16 - 1);
-               }
-               clk_div &= 0xFF;
-               srgr |= clk_div;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               srgr = DAVINCI_MCBSP_SRGR_FSGM;
-               clk_div = dev->clk_div - 1;
-               srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
-               srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
-               clk_div &= 0xFF;
-               srgr |= clk_div;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* Clock and frame sync given from external sources */
-               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
-               srgr = DAVINCI_MCBSP_SRGR_FSGM;
-               srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
-               pr_debug("%s - %d  FWID set: re-read srgr = %X\n",
-                       __func__, __LINE__, snd_interval_value(i) - 1);
-
-               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
-               srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
-               break;
-       default:
-               return -EINVAL;
-       }
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
-
-       rcr = DAVINCI_MCBSP_RCR_RFIG;
-       xcr = DAVINCI_MCBSP_XCR_XFIG;
-       if (dev->mode == MOD_DSP_B) {
-               rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
-               xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
-       } else {
-               rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
-               xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
-       }
-       /* Determine xfer data type */
-       fmt = params_format(params);
-       if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
-               printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
-               return -EINVAL;
-       }
-
-       if (params_channels(params) == 2) {
-               element_cnt = 2;
-               if (double_fmt[fmt] && dev->enable_channel_combine) {
-                       element_cnt = 1;
-                       fmt = double_fmt[fmt];
-               }
-               switch (master) {
-               case SND_SOC_DAIFMT_CBS_CFS:
-               case SND_SOC_DAIFMT_CBS_CFM:
-                       rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
-                       xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
-                       rcr |= DAVINCI_MCBSP_RCR_RPHASE;
-                       xcr |= DAVINCI_MCBSP_XCR_XPHASE;
-                       break;
-               case SND_SOC_DAIFMT_CBM_CFM:
-               case SND_SOC_DAIFMT_CBM_CFS:
-                       rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
-                       xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-       mcbsp_word_length = asp_word_length[fmt];
-
-       switch (master) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_CBS_CFM:
-               rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
-               xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
-               rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
-               xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
-               DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
-       xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
-               DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
-       else
-               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
-
-       pr_debug("%s - %d  srgr=%X\n", __func__, __LINE__, srgr);
-       pr_debug("%s - %d  xcr=%X\n", __func__, __LINE__, xcr);
-       pr_debug("%s - %d  rcr=%X\n", __func__, __LINE__, rcr);
-       return 0;
-}
-
-static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       davinci_mcbsp_stop(dev, playback);
-       return 0;
-}
-
-static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                              struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       int ret = 0;
-       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               davinci_mcbsp_start(dev, substream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               davinci_mcbsp_stop(dev, playback);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       davinci_mcbsp_stop(dev, playback);
-}
-
-#define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
-
-static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
-       .shutdown       = davinci_i2s_shutdown,
-       .prepare        = davinci_i2s_prepare,
-       .trigger        = davinci_i2s_trigger,
-       .hw_params      = davinci_i2s_hw_params,
-       .set_fmt        = davinci_i2s_set_dai_fmt,
-       .set_clkdiv     = davinci_i2s_dai_set_clkdiv,
-
-};
-
-static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver davinci_i2s_dai = {
-       .probe = davinci_i2s_dai_probe,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = DAVINCI_I2S_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = DAVINCI_I2S_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = &davinci_i2s_dai_ops,
-
-};
-
-static const struct snd_soc_component_driver davinci_i2s_component = {
-       .name           = DRV_NAME,
-};
-
-static int davinci_i2s_probe(struct platform_device *pdev)
-{
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       struct davinci_mcbsp_dev *dev;
-       struct resource *mem, *res;
-       void __iomem *io_base;
-       int *dma;
-       int ret;
-
-       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       if (!mem) {
-               dev_warn(&pdev->dev,
-                        "\"mpu\" mem resource not found, using index 0\n");
-               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!mem) {
-                       dev_err(&pdev->dev, "no mem resource?\n");
-                       return -ENODEV;
-               }
-       }
-
-       io_base = devm_ioremap_resource(&pdev->dev, mem);
-       if (IS_ERR(io_base))
-               return PTR_ERR(io_base);
-
-       dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
-                          GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       dev->base = io_base;
-
-       /* setup DMA, first TX, then RX */
-       dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (res) {
-               dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
-               *dma = res->start;
-               dma_data->filter_data = dma;
-       } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
-               dma_data->filter_data = "tx";
-       } else {
-               dev_err(&pdev->dev, "Missing DMA tx resource\n");
-               return -ENODEV;
-       }
-
-       dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-       dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (res) {
-               dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
-               *dma = res->start;
-               dma_data->filter_data = dma;
-       } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
-               dma_data->filter_data = "rx";
-       } else {
-               dev_err(&pdev->dev, "Missing DMA rx resource\n");
-               return -ENODEV;
-       }
-
-       dev->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dev->clk))
-               return -ENODEV;
-       clk_enable(dev->clk);
-
-       dev->dev = &pdev->dev;
-       dev_set_drvdata(&pdev->dev, dev);
-
-       ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
-                                        &davinci_i2s_dai, 1);
-       if (ret != 0)
-               goto err_release_clk;
-
-       ret = edma_pcm_platform_register(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_component;
-       }
-
-       return 0;
-
-err_unregister_component:
-       snd_soc_unregister_component(&pdev->dev);
-err_release_clk:
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
-       return ret;
-}
-
-static int davinci_i2s_remove(struct platform_device *pdev)
-{
-       struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
-
-       snd_soc_unregister_component(&pdev->dev);
-
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
-       dev->clk = NULL;
-
-       return 0;
-}
-
-static const struct of_device_id davinci_i2s_match[] = {
-       { .compatible = "ti,da850-mcbsp" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, davinci_i2s_match);
-
-static struct platform_driver davinci_mcbsp_driver = {
-       .probe          = davinci_i2s_probe,
-       .remove         = davinci_i2s_remove,
-       .driver         = {
-               .name   = "davinci-mcbsp",
-               .of_match_table = of_match_ptr(davinci_i2s_match),
-       },
-};
-
-module_platform_driver(davinci_mcbsp_driver);
-
-MODULE_AUTHOR("Vladimir Barinov");
-MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
deleted file mode 100644 (file)
index 48dac3e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _DAVINCI_I2S_H
-#define _DAVINCI_I2S_H
-
-/* McBSP dividers */
-enum davinci_mcbsp_div {
-       DAVINCI_MCBSP_CLKGDV,              /* Sample rate generator divider */
-};
-
-#endif
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
deleted file mode 100644 (file)
index 267aee7..0000000
+++ /dev/null
@@ -1,2131 +0,0 @@
-/*
- * ALSA SoC McASP Audio Layer for TI DAVINCI processor
- *
- * Multi-channel Audio Serial Port Driver
- *
- * Author: Nirmal Pandey <n-pandey@ti.com>,
- *         Suresh Rajashekara <suresh.r@ti.com>
- *         Steve Chen <schen@.mvista.com>
- *
- * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
- * Copyright:   (C) 2009  Texas Instruments, India
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/platform_data/davinci_asp.h>
-#include <linux/math64.h>
-
-#include <sound/asoundef.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "edma-pcm.h"
-#include "../omap/sdma-pcm.h"
-#include "davinci-mcasp.h"
-
-#define MCASP_MAX_AFIFO_DEPTH  64
-
-static u32 context_regs[] = {
-       DAVINCI_MCASP_TXFMCTL_REG,
-       DAVINCI_MCASP_RXFMCTL_REG,
-       DAVINCI_MCASP_TXFMT_REG,
-       DAVINCI_MCASP_RXFMT_REG,
-       DAVINCI_MCASP_ACLKXCTL_REG,
-       DAVINCI_MCASP_ACLKRCTL_REG,
-       DAVINCI_MCASP_AHCLKXCTL_REG,
-       DAVINCI_MCASP_AHCLKRCTL_REG,
-       DAVINCI_MCASP_PDIR_REG,
-       DAVINCI_MCASP_RXMASK_REG,
-       DAVINCI_MCASP_TXMASK_REG,
-       DAVINCI_MCASP_RXTDM_REG,
-       DAVINCI_MCASP_TXTDM_REG,
-};
-
-struct davinci_mcasp_context {
-       u32     config_regs[ARRAY_SIZE(context_regs)];
-       u32     afifo_regs[2]; /* for read/write fifo control registers */
-       u32     *xrsr_regs; /* for serializer configuration */
-       bool    pm_state;
-};
-
-struct davinci_mcasp_ruledata {
-       struct davinci_mcasp *mcasp;
-       int serializers;
-};
-
-struct davinci_mcasp {
-       struct snd_dmaengine_dai_dma_data dma_data[2];
-       void __iomem *base;
-       u32 fifo_base;
-       struct device *dev;
-       struct snd_pcm_substream *substreams[2];
-       unsigned int dai_fmt;
-
-       /* McASP specific data */
-       int     tdm_slots;
-       u32     tdm_mask[2];
-       int     slot_width;
-       u8      op_mode;
-       u8      num_serializer;
-       u8      *serial_dir;
-       u8      version;
-       u8      bclk_div;
-       int     streams;
-       u32     irq_request[2];
-       int     dma_request[2];
-
-       int     sysclk_freq;
-       bool    bclk_master;
-
-       /* McASP FIFO related */
-       u8      txnumevt;
-       u8      rxnumevt;
-
-       bool    dat_port;
-
-       /* Used for comstraint setting on the second stream */
-       u32     channels;
-
-#ifdef CONFIG_PM_SLEEP
-       struct davinci_mcasp_context context;
-#endif
-
-       struct davinci_mcasp_ruledata ruledata[2];
-       struct snd_pcm_hw_constraint_list chconstr[2];
-};
-
-static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
-                                 u32 val)
-{
-       void __iomem *reg = mcasp->base + offset;
-       __raw_writel(__raw_readl(reg) | val, reg);
-}
-
-static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
-                                 u32 val)
-{
-       void __iomem *reg = mcasp->base + offset;
-       __raw_writel((__raw_readl(reg) & ~(val)), reg);
-}
-
-static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
-                                 u32 val, u32 mask)
-{
-       void __iomem *reg = mcasp->base + offset;
-       __raw_writel((__raw_readl(reg) & ~mask) | val, reg);
-}
-
-static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
-                                u32 val)
-{
-       __raw_writel(val, mcasp->base + offset);
-}
-
-static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
-{
-       return (u32)__raw_readl(mcasp->base + offset);
-}
-
-static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
-{
-       int i = 0;
-
-       mcasp_set_bits(mcasp, ctl_reg, val);
-
-       /* programming GBLCTL needs to read back from GBLCTL and verfiy */
-       /* loop count is to avoid the lock-up */
-       for (i = 0; i < 1000; i++) {
-               if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
-                       break;
-       }
-
-       if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
-               printk(KERN_ERR "GBLCTL write error\n");
-}
-
-static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
-{
-       u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
-       u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
-
-       return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
-}
-
-static void mcasp_start_rx(struct davinci_mcasp *mcasp)
-{
-       if (mcasp->rxnumevt) {  /* enable FIFO */
-               u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-
-               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
-               mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
-       }
-
-       /* Start clocks */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
-       /*
-        * When ASYNC == 0 the transmit and receive sections operate
-        * synchronously from the transmit clock and frame sync. We need to make
-        * sure that the TX signlas are enabled when starting reception.
-        */
-       if (mcasp_is_synchronous(mcasp)) {
-               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
-               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
-       }
-
-       /* Activate serializer(s) */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
-       /* Release RX state machine */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
-       /* Release Frame Sync generator */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
-       if (mcasp_is_synchronous(mcasp))
-               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
-
-       /* enable receive IRQs */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
-                      mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-static void mcasp_start_tx(struct davinci_mcasp *mcasp)
-{
-       u32 cnt;
-
-       if (mcasp->txnumevt) {  /* enable FIFO */
-               u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-
-               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
-               mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
-       }
-
-       /* Start clocks */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
-       /* Activate serializer(s) */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
-
-       /* wait for XDATA to be cleared */
-       cnt = 0;
-       while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
-              (cnt < 100000))
-               cnt++;
-
-       /* Release TX state machine */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
-       /* Release Frame Sync generator */
-       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
-
-       /* enable transmit IRQs */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
-                      mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
-}
-
-static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
-{
-       mcasp->streams++;
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mcasp_start_tx(mcasp);
-       else
-               mcasp_start_rx(mcasp);
-}
-
-static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
-{
-       /* disable IRQ sources */
-       mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
-                      mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
-
-       /*
-        * In synchronous mode stop the TX clocks if no other stream is
-        * running
-        */
-       if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
-
-       if (mcasp->rxnumevt) {  /* disable FIFO */
-               u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-
-               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
-       }
-}
-
-static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
-{
-       u32 val = 0;
-
-       /* disable IRQ sources */
-       mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
-                      mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
-
-       /*
-        * In synchronous mode keep TX clocks running if the capture stream is
-        * still running.
-        */
-       if (mcasp_is_synchronous(mcasp) && mcasp->streams)
-               val =  TXHCLKRST | TXCLKRST | TXFSRST;
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
-
-       if (mcasp->txnumevt) {  /* disable FIFO */
-               u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-
-               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
-       }
-}
-
-static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
-{
-       mcasp->streams--;
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mcasp_stop_tx(mcasp);
-       else
-               mcasp_stop_rx(mcasp);
-}
-
-static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
-{
-       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
-       struct snd_pcm_substream *substream;
-       u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
-       u32 handled_mask = 0;
-       u32 stat;
-
-       stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
-       if (stat & XUNDRN & irq_mask) {
-               dev_warn(mcasp->dev, "Transmit buffer underflow\n");
-               handled_mask |= XUNDRN;
-
-               substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
-               if (substream)
-                       snd_pcm_stop_xrun(substream);
-       }
-
-       if (!handled_mask)
-               dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
-                        stat);
-
-       if (stat & XRERR)
-               handled_mask |= XRERR;
-
-       /* Ack the handled event only */
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
-
-       return IRQ_RETVAL(handled_mask);
-}
-
-static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
-{
-       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
-       struct snd_pcm_substream *substream;
-       u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
-       u32 handled_mask = 0;
-       u32 stat;
-
-       stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
-       if (stat & ROVRN & irq_mask) {
-               dev_warn(mcasp->dev, "Receive buffer overflow\n");
-               handled_mask |= ROVRN;
-
-               substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
-               if (substream)
-                       snd_pcm_stop_xrun(substream);
-       }
-
-       if (!handled_mask)
-               dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
-                        stat);
-
-       if (stat & XRERR)
-               handled_mask |= XRERR;
-
-       /* Ack the handled event only */
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
-
-       return IRQ_RETVAL(handled_mask);
-}
-
-static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
-{
-       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
-       irqreturn_t ret = IRQ_NONE;
-
-       if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
-               ret = davinci_mcasp_tx_irq_handler(irq, data);
-
-       if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
-               ret |= davinci_mcasp_rx_irq_handler(irq, data);
-
-       return ret;
-}
-
-static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-                                        unsigned int fmt)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       int ret = 0;
-       u32 data_delay;
-       bool fs_pol_rising;
-       bool inv_fs = false;
-
-       if (!fmt)
-               return 0;
-
-       pm_runtime_get_sync(mcasp->dev);
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-               /* 1st data bit occur one ACLK cycle after the frame sync */
-               data_delay = 1;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-       case SND_SOC_DAIFMT_AC97:
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-               /* No delay after FS */
-               data_delay = 0;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               /* configure a full-word SYNC pulse (LRCLK) */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-               /* 1st data bit occur one ACLK cycle after the frame sync */
-               data_delay = 1;
-               /* FS need to be inverted */
-               inv_fs = true;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               /* configure a full-word SYNC pulse (LRCLK) */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-               /* No delay after FS */
-               data_delay = 0;
-               break;
-       default:
-               ret = -EINVAL;
-               goto out;
-       }
-
-       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
-                      FSXDLY(3));
-       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
-                      FSRDLY(3));
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* codec is clock and frame slave */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
-
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
-
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
-               mcasp->bclk_master = 1;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-               /* codec is clock slave and frame master */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
-
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
-
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
-               mcasp->bclk_master = 1;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               /* codec is clock master and frame slave */
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
-
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
-
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
-               mcasp->bclk_master = 0;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* codec is clock and frame master */
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
-
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
-
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
-                              ACLKX | AFSX | ACLKR | AHCLKR | AFSR);
-               mcasp->bclk_master = 0;
-               break;
-       default:
-               ret = -EINVAL;
-               goto out;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_IB_NF:
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               fs_pol_rising = true;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               fs_pol_rising = false;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               fs_pol_rising = false;
-               break;
-       case SND_SOC_DAIFMT_NB_NF:
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
-               fs_pol_rising = true;
-               break;
-       default:
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (inv_fs)
-               fs_pol_rising = !fs_pol_rising;
-
-       if (fs_pol_rising) {
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
-       } else {
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
-       }
-
-       mcasp->dai_fmt = fmt;
-out:
-       pm_runtime_put(mcasp->dev);
-       return ret;
-}
-
-static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
-                                     int div, bool explicit)
-{
-       pm_runtime_get_sync(mcasp->dev);
-       switch (div_id) {
-       case MCASP_CLKDIV_AUXCLK:                       /* MCLK divider */
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
-                              AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
-                              AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
-               break;
-
-       case MCASP_CLKDIV_BCLK:                 /* BCLK divider */
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
-                              ACLKXDIV(div - 1), ACLKXDIV_MASK);
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
-                              ACLKRDIV(div - 1), ACLKRDIV_MASK);
-               if (explicit)
-                       mcasp->bclk_div = div;
-               break;
-
-       case MCASP_CLKDIV_BCLK_FS_RATIO:
-               /*
-                * BCLK/LRCLK ratio descries how many bit-clock cycles
-                * fit into one frame. The clock ratio is given for a
-                * full period of data (for I2S format both left and
-                * right channels), so it has to be divided by number
-                * of tdm-slots (for I2S - divided by 2).
-                * Instead of storing this ratio, we calculate a new
-                * tdm_slot width by dividing the the ratio by the
-                * number of configured tdm slots.
-                */
-               mcasp->slot_width = div / mcasp->tdm_slots;
-               if (div % mcasp->tdm_slots)
-                       dev_warn(mcasp->dev,
-                                "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
-                                __func__, div, mcasp->tdm_slots);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       pm_runtime_put(mcasp->dev);
-       return 0;
-}
-
-static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
-                                   int div)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
-       return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
-}
-
-static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-                                   unsigned int freq, int dir)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
-       pm_runtime_get_sync(mcasp->dev);
-       if (dir == SND_SOC_CLOCK_OUT) {
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
-       } else {
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
-       }
-
-       mcasp->sysclk_freq = freq;
-
-       pm_runtime_put(mcasp->dev);
-       return 0;
-}
-
-/* All serializers must have equal number of channels */
-static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
-                                      int serializers)
-{
-       struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
-       unsigned int *list = (unsigned int *) cl->list;
-       int slots = mcasp->tdm_slots;
-       int i, count = 0;
-
-       if (mcasp->tdm_mask[stream])
-               slots = hweight32(mcasp->tdm_mask[stream]);
-
-       for (i = 1; i <= slots; i++)
-               list[count++] = i;
-
-       for (i = 2; i <= serializers; i++)
-               list[count++] = i*slots;
-
-       cl->count = count;
-
-       return 0;
-}
-
-static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
-{
-       int rx_serializers = 0, tx_serializers = 0, ret, i;
-
-       for (i = 0; i < mcasp->num_serializer; i++)
-               if (mcasp->serial_dir[i] == TX_MODE)
-                       tx_serializers++;
-               else if (mcasp->serial_dir[i] == RX_MODE)
-                       rx_serializers++;
-
-       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
-                                         tx_serializers);
-       if (ret)
-               return ret;
-
-       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
-                                         rx_serializers);
-
-       return ret;
-}
-
-
-static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
-                                     unsigned int tx_mask,
-                                     unsigned int rx_mask,
-                                     int slots, int slot_width)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
-       dev_dbg(mcasp->dev,
-                "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
-                __func__, tx_mask, rx_mask, slots, slot_width);
-
-       if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
-               dev_err(mcasp->dev,
-                       "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
-                       tx_mask, rx_mask, slots);
-               return -EINVAL;
-       }
-
-       if (slot_width &&
-           (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
-               dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
-                       __func__, slot_width);
-               return -EINVAL;
-       }
-
-       mcasp->tdm_slots = slots;
-       mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
-       mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
-       mcasp->slot_width = slot_width;
-
-       return davinci_mcasp_set_ch_constraints(mcasp);
-}
-
-static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
-                                      int sample_width)
-{
-       u32 fmt;
-       u32 tx_rotate = (sample_width / 4) & 0x7;
-       u32 mask = (1ULL << sample_width) - 1;
-       u32 slot_width = sample_width;
-
-       /*
-        * For captured data we should not rotate, inversion and masking is
-        * enoguh to get the data to the right position:
-        * Format         data from bus         after reverse (XRBUF)
-        * S16_LE:      |LSB|MSB|xxx|xxx|       |xxx|xxx|MSB|LSB|
-        * S24_3LE:     |LSB|DAT|MSB|xxx|       |xxx|MSB|DAT|LSB|
-        * S24_LE:      |LSB|DAT|MSB|xxx|       |xxx|MSB|DAT|LSB|
-        * S32_LE:      |LSB|DAT|DAT|MSB|       |MSB|DAT|DAT|LSB|
-        */
-       u32 rx_rotate = 0;
-
-       /*
-        * Setting the tdm slot width either with set_clkdiv() or
-        * set_tdm_slot() allows us to for example send 32 bits per
-        * channel to the codec, while only 16 of them carry audio
-        * payload.
-        */
-       if (mcasp->slot_width) {
-               /*
-                * When we have more bclk then it is needed for the
-                * data, we need to use the rotation to move the
-                * received samples to have correct alignment.
-                */
-               slot_width = mcasp->slot_width;
-               rx_rotate = (slot_width - sample_width) / 4;
-       }
-
-       /* mapping of the XSSZ bit-field as described in the datasheet */
-       fmt = (slot_width >> 1) - 1;
-
-       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
-                              RXSSZ(0x0F));
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
-                              TXSSZ(0x0F));
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
-                              TXROT(7));
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
-                              RXROT(7));
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
-       }
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
-
-       return 0;
-}
-
-static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
-                                int period_words, int channels)
-{
-       struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
-       int i;
-       u8 tx_ser = 0;
-       u8 rx_ser = 0;
-       u8 slots = mcasp->tdm_slots;
-       u8 max_active_serializers = (channels + slots - 1) / slots;
-       int active_serializers, numevt;
-       u32 reg;
-       /* Default configuration */
-       if (mcasp->version < MCASP_VERSION_3)
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
-
-       /* All PINS as McASP */
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
-       } else {
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
-       }
-
-       for (i = 0; i < mcasp->num_serializer; i++) {
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
-                              mcasp->serial_dir[i]);
-               if (mcasp->serial_dir[i] == TX_MODE &&
-                                       tx_ser < max_active_serializers) {
-                       mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
-                                      DISMOD_LOW, DISMOD_MASK);
-                       tx_ser++;
-               } else if (mcasp->serial_dir[i] == RX_MODE &&
-                                       rx_ser < max_active_serializers) {
-                       mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
-                       rx_ser++;
-               } else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
-                                      SRMOD_INACTIVE, SRMOD_MASK);
-               }
-       }
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               active_serializers = tx_ser;
-               numevt = mcasp->txnumevt;
-               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-       } else {
-               active_serializers = rx_ser;
-               numevt = mcasp->rxnumevt;
-               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-       }
-
-       if (active_serializers < max_active_serializers) {
-               dev_warn(mcasp->dev, "stream has more channels (%d) than are "
-                        "enabled in mcasp (%d)\n", channels,
-                        active_serializers * slots);
-               return -EINVAL;
-       }
-
-       /* AFIFO is not in use */
-       if (!numevt) {
-               /* Configure the burst size for platform drivers */
-               if (active_serializers > 1) {
-                       /*
-                        * If more than one serializers are in use we have one
-                        * DMA request to provide data for all serializers.
-                        * For example if three serializers are enabled the DMA
-                        * need to transfer three words per DMA request.
-                        */
-                       dma_data->maxburst = active_serializers;
-               } else {
-                       dma_data->maxburst = 0;
-               }
-               return 0;
-       }
-
-       if (period_words % active_serializers) {
-               dev_err(mcasp->dev, "Invalid combination of period words and "
-                       "active serializers: %d, %d\n", period_words,
-                       active_serializers);
-               return -EINVAL;
-       }
-
-       /*
-        * Calculate the optimal AFIFO depth for platform side:
-        * The number of words for numevt need to be in steps of active
-        * serializers.
-        */
-       numevt = (numevt / active_serializers) * active_serializers;
-
-       while (period_words % numevt && numevt > 0)
-               numevt -= active_serializers;
-       if (numevt <= 0)
-               numevt = active_serializers;
-
-       mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
-       mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
-
-       /* Configure the burst size for platform drivers */
-       if (numevt == 1)
-               numevt = 0;
-       dma_data->maxburst = numevt;
-
-       return 0;
-}
-
-static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
-                             int channels)
-{
-       int i, active_slots;
-       int total_slots;
-       int active_serializers;
-       u32 mask = 0;
-       u32 busel = 0;
-
-       total_slots = mcasp->tdm_slots;
-
-       /*
-        * If more than one serializer is needed, then use them with
-        * all the specified tdm_slots. Otherwise, one serializer can
-        * cope with the transaction using just as many slots as there
-        * are channels in the stream.
-        */
-       if (mcasp->tdm_mask[stream]) {
-               active_slots = hweight32(mcasp->tdm_mask[stream]);
-               active_serializers = (channels + active_slots - 1) /
-                       active_slots;
-               if (active_serializers == 1) {
-                       active_slots = channels;
-                       for (i = 0; i < total_slots; i++) {
-                               if ((1 << i) & mcasp->tdm_mask[stream]) {
-                                       mask |= (1 << i);
-                                       if (--active_slots <= 0)
-                                               break;
-                               }
-                       }
-               }
-       } else {
-               active_serializers = (channels + total_slots - 1) / total_slots;
-               if (active_serializers == 1)
-                       active_slots = channels;
-               else
-                       active_slots = total_slots;
-
-               for (i = 0; i < active_slots; i++)
-                       mask |= (1 << i);
-       }
-       mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
-
-       if (!mcasp->dat_port)
-               busel = TXSEL;
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-                              FSXMOD(total_slots), FSXMOD(0x1FF));
-       } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-                              FSRMOD(total_slots), FSRMOD(0x1FF));
-               /*
-                * If McASP is set to be TX/RX synchronous and the playback is
-                * not running already we need to configure the TX slots in
-                * order to have correct FSX on the bus
-                */
-               if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-                                      FSXMOD(total_slots), FSXMOD(0x1FF));
-       }
-
-       return 0;
-}
-
-/* S/PDIF */
-static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
-                             unsigned int rate)
-{
-       u32 cs_value = 0;
-       u8 *cs_bytes = (u8*) &cs_value;
-
-       /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
-          and LSB first */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
-
-       /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
-
-       /* Set the TX tdm : for all the slots */
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
-
-       /* Set the TX clock controls : div = 1 and internal */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
-
-       mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
-
-       /* Only 44100 and 48000 are valid, both have the same setting */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
-
-       /* Enable the DIT */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
-
-       /* Set S/PDIF channel status bits */
-       cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
-       cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
-
-       switch (rate) {
-       case 22050:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
-               break;
-       case 24000:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
-               break;
-       case 32000:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
-               break;
-       case 44100:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
-               break;
-       case 48000:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
-               break;
-       case 88200:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
-               break;
-       case 96000:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
-               break;
-       case 176400:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
-               break;
-       case 192000:
-               cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
-               break;
-       default:
-               printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
-               return -EINVAL;
-       }
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
-
-       return 0;
-}
-
-static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
-                                     unsigned int bclk_freq, bool set)
-{
-       int error_ppm;
-       unsigned int sysclk_freq = mcasp->sysclk_freq;
-       u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
-       int div = sysclk_freq / bclk_freq;
-       int rem = sysclk_freq % bclk_freq;
-       int aux_div = 1;
-
-       if (div > (ACLKXDIV_MASK + 1)) {
-               if (reg & AHCLKXE) {
-                       aux_div = div / (ACLKXDIV_MASK + 1);
-                       if (div % (ACLKXDIV_MASK + 1))
-                               aux_div++;
-
-                       sysclk_freq /= aux_div;
-                       div = sysclk_freq / bclk_freq;
-                       rem = sysclk_freq % bclk_freq;
-               } else if (set) {
-                       dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
-                                sysclk_freq);
-               }
-       }
-
-       if (rem != 0) {
-               if (div == 0 ||
-                   ((sysclk_freq / div) - bclk_freq) >
-                   (bclk_freq - (sysclk_freq / (div+1)))) {
-                       div++;
-                       rem = rem - bclk_freq;
-               }
-       }
-       error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
-                    (int)bclk_freq)) / div - 1000000;
-
-       if (set) {
-               if (error_ppm)
-                       dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
-                                error_ppm);
-
-               __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
-               if (reg & AHCLKXE)
-                       __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
-                                                  aux_div, 0);
-       }
-
-       return error_ppm;
-}
-
-static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
-{
-       if (!mcasp->txnumevt)
-               return 0;
-
-       return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
-}
-
-static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
-{
-       if (!mcasp->rxnumevt)
-               return 0;
-
-       return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
-}
-
-static snd_pcm_sframes_t davinci_mcasp_delay(
-                       struct snd_pcm_substream *substream,
-                       struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 fifo_use;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_use = davinci_mcasp_tx_delay(mcasp);
-       else
-               fifo_use = davinci_mcasp_rx_delay(mcasp);
-
-       /*
-        * Divide the used locations with the channel count to get the
-        * FIFO usage in samples (don't care about partial samples in the
-        * buffer).
-        */
-       return fifo_use / substream->runtime->channels;
-}
-
-static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *params,
-                                       struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       int word_length;
-       int channels = params_channels(params);
-       int period_size = params_period_size(params);
-       int ret;
-
-       ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt);
-       if (ret)
-               return ret;
-
-       /*
-        * If mcasp is BCLK master, and a BCLK divider was not provided by
-        * the machine driver, we need to calculate the ratio.
-        */
-       if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               int slots = mcasp->tdm_slots;
-               int rate = params_rate(params);
-               int sbits = params_width(params);
-
-               if (mcasp->slot_width)
-                       sbits = mcasp->slot_width;
-
-               davinci_mcasp_calc_clk_div(mcasp, rate * sbits * slots, true);
-       }
-
-       ret = mcasp_common_hw_param(mcasp, substream->stream,
-                                   period_size * channels, channels);
-       if (ret)
-               return ret;
-
-       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
-               ret = mcasp_dit_hw_param(mcasp, params_rate(params));
-       else
-               ret = mcasp_i2s_hw_param(mcasp, substream->stream,
-                                        channels);
-
-       if (ret)
-               return ret;
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_U8:
-       case SNDRV_PCM_FORMAT_S8:
-               word_length = 8;
-               break;
-
-       case SNDRV_PCM_FORMAT_U16_LE:
-       case SNDRV_PCM_FORMAT_S16_LE:
-               word_length = 16;
-               break;
-
-       case SNDRV_PCM_FORMAT_U24_3LE:
-       case SNDRV_PCM_FORMAT_S24_3LE:
-               word_length = 24;
-               break;
-
-       case SNDRV_PCM_FORMAT_U24_LE:
-       case SNDRV_PCM_FORMAT_S24_LE:
-               word_length = 24;
-               break;
-
-       case SNDRV_PCM_FORMAT_U32_LE:
-       case SNDRV_PCM_FORMAT_S32_LE:
-               word_length = 32;
-               break;
-
-       default:
-               printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
-               return -EINVAL;
-       }
-
-       davinci_config_channel_size(mcasp, word_length);
-
-       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
-               mcasp->channels = channels;
-
-       return 0;
-}
-
-static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
-                                    int cmd, struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               davinci_mcasp_start(mcasp, substream->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               davinci_mcasp_stop(mcasp, substream->stream);
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const unsigned int davinci_mcasp_dai_rates[] = {
-       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
-       88200, 96000, 176400, 192000,
-};
-
-#define DAVINCI_MAX_RATE_ERROR_PPM 1000
-
-static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
-                                     struct snd_pcm_hw_rule *rule)
-{
-       struct davinci_mcasp_ruledata *rd = rule->private;
-       struct snd_interval *ri =
-               hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       int sbits = params_width(params);
-       int slots = rd->mcasp->tdm_slots;
-       struct snd_interval range;
-       int i;
-
-       if (rd->mcasp->slot_width)
-               sbits = rd->mcasp->slot_width;
-
-       snd_interval_any(&range);
-       range.empty = 1;
-
-       for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
-               if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
-                       uint bclk_freq = sbits*slots*
-                               davinci_mcasp_dai_rates[i];
-                       int ppm;
-
-                       ppm = davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq,
-                                                        false);
-                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
-                               if (range.empty) {
-                                       range.min = davinci_mcasp_dai_rates[i];
-                                       range.empty = 0;
-                               }
-                               range.max = davinci_mcasp_dai_rates[i];
-                       }
-               }
-       }
-
-       dev_dbg(rd->mcasp->dev,
-               "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
-               ri->min, ri->max, range.min, range.max, sbits, slots);
-
-       return snd_interval_refine(hw_param_interval(params, rule->var),
-                                  &range);
-}
-
-static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
-                                       struct snd_pcm_hw_rule *rule)
-{
-       struct davinci_mcasp_ruledata *rd = rule->private;
-       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-       struct snd_mask nfmt;
-       int rate = params_rate(params);
-       int slots = rd->mcasp->tdm_slots;
-       int i, count = 0;
-
-       snd_mask_none(&nfmt);
-
-       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
-               if (snd_mask_test(fmt, i)) {
-                       uint sbits = snd_pcm_format_width(i);
-                       int ppm;
-
-                       if (rd->mcasp->slot_width)
-                               sbits = rd->mcasp->slot_width;
-
-                       ppm = davinci_mcasp_calc_clk_div(rd->mcasp,
-                                                        sbits * slots * rate,
-                                                        false);
-                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
-                               snd_mask_set(&nfmt, i);
-                               count++;
-                       }
-               }
-       }
-       dev_dbg(rd->mcasp->dev,
-               "%d possible sample format for %d Hz and %d tdm slots\n",
-               count, rate, slots);
-
-       return snd_mask_refine(fmt, &nfmt);
-}
-
-static int davinci_mcasp_hw_rule_min_periodsize(
-               struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
-{
-       struct snd_interval *period_size = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
-       struct snd_interval frames;
-
-       snd_interval_any(&frames);
-       frames.min = 64;
-       frames.integer = 1;
-
-       return snd_interval_refine(period_size, &frames);
-}
-
-static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
-                                struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct davinci_mcasp_ruledata *ruledata =
-                                       &mcasp->ruledata[substream->stream];
-       u32 max_channels = 0;
-       int i, dir;
-       int tdm_slots = mcasp->tdm_slots;
-
-       /* Do not allow more then one stream per direction */
-       if (mcasp->substreams[substream->stream])
-               return -EBUSY;
-
-       mcasp->substreams[substream->stream] = substream;
-
-       if (mcasp->tdm_mask[substream->stream])
-               tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
-
-       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
-               return 0;
-
-       /*
-        * Limit the maximum allowed channels for the first stream:
-        * number of serializers for the direction * tdm slots per serializer
-        */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dir = TX_MODE;
-       else
-               dir = RX_MODE;
-
-       for (i = 0; i < mcasp->num_serializer; i++) {
-               if (mcasp->serial_dir[i] == dir)
-                       max_channels++;
-       }
-       ruledata->serializers = max_channels;
-       max_channels *= tdm_slots;
-       /*
-        * If the already active stream has less channels than the calculated
-        * limnit based on the seirializers * tdm_slots, we need to use that as
-        * a constraint for the second stream.
-        * Otherwise (first stream or less allowed channels) we use the
-        * calculated constraint.
-        */
-       if (mcasp->channels && mcasp->channels < max_channels)
-               max_channels = mcasp->channels;
-       /*
-        * But we can always allow channels upto the amount of
-        * the available tdm_slots.
-        */
-       if (max_channels < tdm_slots)
-               max_channels = tdm_slots;
-
-       snd_pcm_hw_constraint_minmax(substream->runtime,
-                                    SNDRV_PCM_HW_PARAM_CHANNELS,
-                                    0, max_channels);
-
-       snd_pcm_hw_constraint_list(substream->runtime,
-                                  0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                  &mcasp->chconstr[substream->stream]);
-
-       if (mcasp->slot_width)
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            8, mcasp->slot_width);
-
-       /*
-        * If we rely on implicit BCLK divider setting we should
-        * set constraints based on what we can provide.
-        */
-       if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               int ret;
-
-               ruledata->mcasp = mcasp;
-
-               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
-                                         SNDRV_PCM_HW_PARAM_RATE,
-                                         davinci_mcasp_hw_rule_rate,
-                                         ruledata,
-                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
-               if (ret)
-                       return ret;
-               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
-                                         SNDRV_PCM_HW_PARAM_FORMAT,
-                                         davinci_mcasp_hw_rule_format,
-                                         ruledata,
-                                         SNDRV_PCM_HW_PARAM_RATE, -1);
-               if (ret)
-                       return ret;
-       }
-
-       snd_pcm_hw_rule_add(substream->runtime, 0,
-                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-                           davinci_mcasp_hw_rule_min_periodsize, NULL,
-                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
-
-       return 0;
-}
-
-static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
-                                  struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-
-       mcasp->substreams[substream->stream] = NULL;
-
-       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
-               return;
-
-       if (!cpu_dai->active)
-               mcasp->channels = 0;
-}
-
-static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
-       .startup        = davinci_mcasp_startup,
-       .shutdown       = davinci_mcasp_shutdown,
-       .trigger        = davinci_mcasp_trigger,
-       .delay          = davinci_mcasp_delay,
-       .hw_params      = davinci_mcasp_hw_params,
-       .set_fmt        = davinci_mcasp_set_dai_fmt,
-       .set_clkdiv     = davinci_mcasp_set_clkdiv,
-       .set_sysclk     = davinci_mcasp_set_sysclk,
-       .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
-};
-
-static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
-       dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-       struct davinci_mcasp_context *context = &mcasp->context;
-       u32 reg;
-       int i;
-
-       context->pm_state = pm_runtime_active(mcasp->dev);
-       if (!context->pm_state)
-               pm_runtime_get_sync(mcasp->dev);
-
-       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
-               context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
-
-       if (mcasp->txnumevt) {
-               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-               context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
-       }
-       if (mcasp->rxnumevt) {
-               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-               context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
-       }
-
-       for (i = 0; i < mcasp->num_serializer; i++)
-               context->xrsr_regs[i] = mcasp_get_reg(mcasp,
-                                               DAVINCI_MCASP_XRSRCTL_REG(i));
-
-       pm_runtime_put_sync(mcasp->dev);
-
-       return 0;
-}
-
-static int davinci_mcasp_resume(struct snd_soc_dai *dai)
-{
-       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-       struct davinci_mcasp_context *context = &mcasp->context;
-       u32 reg;
-       int i;
-
-       pm_runtime_get_sync(mcasp->dev);
-
-       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
-               mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
-
-       if (mcasp->txnumevt) {
-               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
-               mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
-       }
-       if (mcasp->rxnumevt) {
-               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
-               mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
-       }
-
-       for (i = 0; i < mcasp->num_serializer; i++)
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
-                             context->xrsr_regs[i]);
-
-       if (!context->pm_state)
-               pm_runtime_put_sync(mcasp->dev);
-
-       return 0;
-}
-#else
-#define davinci_mcasp_suspend NULL
-#define davinci_mcasp_resume NULL
-#endif
-
-#define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
-
-#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
-                               SNDRV_PCM_FMTBIT_U8 | \
-                               SNDRV_PCM_FMTBIT_S16_LE | \
-                               SNDRV_PCM_FMTBIT_U16_LE | \
-                               SNDRV_PCM_FMTBIT_S24_LE | \
-                               SNDRV_PCM_FMTBIT_U24_LE | \
-                               SNDRV_PCM_FMTBIT_S24_3LE | \
-                               SNDRV_PCM_FMTBIT_U24_3LE | \
-                               SNDRV_PCM_FMTBIT_S32_LE | \
-                               SNDRV_PCM_FMTBIT_U32_LE)
-
-static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
-       {
-               .name           = "davinci-mcasp.0",
-               .probe          = davinci_mcasp_dai_probe,
-               .suspend        = davinci_mcasp_suspend,
-               .resume         = davinci_mcasp_resume,
-               .playback       = {
-                       .channels_min   = 1,
-                       .channels_max   = 32 * 16,
-                       .rates          = DAVINCI_MCASP_RATES,
-                       .formats        = DAVINCI_MCASP_PCM_FMTS,
-               },
-               .capture        = {
-                       .channels_min   = 1,
-                       .channels_max   = 32 * 16,
-                       .rates          = DAVINCI_MCASP_RATES,
-                       .formats        = DAVINCI_MCASP_PCM_FMTS,
-               },
-               .ops            = &davinci_mcasp_dai_ops,
-
-               .symmetric_samplebits   = 1,
-               .symmetric_rates        = 1,
-       },
-       {
-               .name           = "davinci-mcasp.1",
-               .probe          = davinci_mcasp_dai_probe,
-               .playback       = {
-                       .channels_min   = 1,
-                       .channels_max   = 384,
-                       .rates          = DAVINCI_MCASP_RATES,
-                       .formats        = DAVINCI_MCASP_PCM_FMTS,
-               },
-               .ops            = &davinci_mcasp_dai_ops,
-       },
-
-};
-
-static const struct snd_soc_component_driver davinci_mcasp_component = {
-       .name           = "davinci-mcasp",
-};
-
-/* Some HW specific values and defaults. The rest is filled in from DT. */
-static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
-       .tx_dma_offset = 0x400,
-       .rx_dma_offset = 0x400,
-       .version = MCASP_VERSION_1,
-};
-
-static struct davinci_mcasp_pdata da830_mcasp_pdata = {
-       .tx_dma_offset = 0x2000,
-       .rx_dma_offset = 0x2000,
-       .version = MCASP_VERSION_2,
-};
-
-static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
-       .tx_dma_offset = 0,
-       .rx_dma_offset = 0,
-       .version = MCASP_VERSION_3,
-};
-
-static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
-       /* The CFG port offset will be calculated if it is needed */
-       .tx_dma_offset = 0,
-       .rx_dma_offset = 0,
-       .version = MCASP_VERSION_4,
-};
-
-static const struct of_device_id mcasp_dt_ids[] = {
-       {
-               .compatible = "ti,dm646x-mcasp-audio",
-               .data = &dm646x_mcasp_pdata,
-       },
-       {
-               .compatible = "ti,da830-mcasp-audio",
-               .data = &da830_mcasp_pdata,
-       },
-       {
-               .compatible = "ti,am33xx-mcasp-audio",
-               .data = &am33xx_mcasp_pdata,
-       },
-       {
-               .compatible = "ti,dra7-mcasp-audio",
-               .data = &dra7_mcasp_pdata,
-       },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
-
-static int mcasp_reparent_fck(struct platform_device *pdev)
-{
-       struct device_node *node = pdev->dev.of_node;
-       struct clk *gfclk, *parent_clk;
-       const char *parent_name;
-       int ret;
-
-       if (!node)
-               return 0;
-
-       parent_name = of_get_property(node, "fck_parent", NULL);
-       if (!parent_name)
-               return 0;
-
-       dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
-
-       gfclk = clk_get(&pdev->dev, "fck");
-       if (IS_ERR(gfclk)) {
-               dev_err(&pdev->dev, "failed to get fck\n");
-               return PTR_ERR(gfclk);
-       }
-
-       parent_clk = clk_get(NULL, parent_name);
-       if (IS_ERR(parent_clk)) {
-               dev_err(&pdev->dev, "failed to get parent clock\n");
-               ret = PTR_ERR(parent_clk);
-               goto err1;
-       }
-
-       ret = clk_set_parent(gfclk, parent_clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to reparent fck\n");
-               goto err2;
-       }
-
-err2:
-       clk_put(parent_clk);
-err1:
-       clk_put(gfclk);
-       return ret;
-}
-
-static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
-                                               struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       struct davinci_mcasp_pdata *pdata = NULL;
-       const struct of_device_id *match =
-                       of_match_device(mcasp_dt_ids, &pdev->dev);
-       struct of_phandle_args dma_spec;
-
-       const u32 *of_serial_dir32;
-       u32 val;
-       int i, ret = 0;
-
-       if (pdev->dev.platform_data) {
-               pdata = pdev->dev.platform_data;
-               return pdata;
-       } else if (match) {
-               pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
-                                    GFP_KERNEL);
-               if (!pdata) {
-                       ret = -ENOMEM;
-                       return pdata;
-               }
-       } else {
-               /* control shouldn't reach here. something is wrong */
-               ret = -EINVAL;
-               goto nodata;
-       }
-
-       ret = of_property_read_u32(np, "op-mode", &val);
-       if (ret >= 0)
-               pdata->op_mode = val;
-
-       ret = of_property_read_u32(np, "tdm-slots", &val);
-       if (ret >= 0) {
-               if (val < 2 || val > 32) {
-                       dev_err(&pdev->dev,
-                               "tdm-slots must be in rage [2-32]\n");
-                       ret = -EINVAL;
-                       goto nodata;
-               }
-
-               pdata->tdm_slots = val;
-       }
-
-       of_serial_dir32 = of_get_property(np, "serial-dir", &val);
-       val /= sizeof(u32);
-       if (of_serial_dir32) {
-               u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
-                                                (sizeof(*of_serial_dir) * val),
-                                                GFP_KERNEL);
-               if (!of_serial_dir) {
-                       ret = -ENOMEM;
-                       goto nodata;
-               }
-
-               for (i = 0; i < val; i++)
-                       of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
-
-               pdata->num_serializer = val;
-               pdata->serial_dir = of_serial_dir;
-       }
-
-       ret = of_property_match_string(np, "dma-names", "tx");
-       if (ret < 0)
-               goto nodata;
-
-       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                        &dma_spec);
-       if (ret < 0)
-               goto nodata;
-
-       pdata->tx_dma_channel = dma_spec.args[0];
-
-       /* RX is not valid in DIT mode */
-       if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               ret = of_property_match_string(np, "dma-names", "rx");
-               if (ret < 0)
-                       goto nodata;
-
-               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                                &dma_spec);
-               if (ret < 0)
-                       goto nodata;
-
-               pdata->rx_dma_channel = dma_spec.args[0];
-       }
-
-       ret = of_property_read_u32(np, "tx-num-evt", &val);
-       if (ret >= 0)
-               pdata->txnumevt = val;
-
-       ret = of_property_read_u32(np, "rx-num-evt", &val);
-       if (ret >= 0)
-               pdata->rxnumevt = val;
-
-       ret = of_property_read_u32(np, "sram-size-playback", &val);
-       if (ret >= 0)
-               pdata->sram_size_playback = val;
-
-       ret = of_property_read_u32(np, "sram-size-capture", &val);
-       if (ret >= 0)
-               pdata->sram_size_capture = val;
-
-       return  pdata;
-
-nodata:
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Error populating platform data, err %d\n",
-                       ret);
-               pdata = NULL;
-       }
-       return  pdata;
-}
-
-enum {
-       PCM_EDMA,
-       PCM_SDMA,
-};
-static const char *sdma_prefix = "ti,omap";
-
-static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
-{
-       struct dma_chan *chan;
-       const char *tmp;
-       int ret = PCM_EDMA;
-
-       if (!mcasp->dev->of_node)
-               return PCM_EDMA;
-
-       tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
-       chan = dma_request_slave_channel_reason(mcasp->dev, tmp);
-       if (IS_ERR(chan)) {
-               if (PTR_ERR(chan) != -EPROBE_DEFER)
-                       dev_err(mcasp->dev,
-                               "Can't verify DMA configuration (%ld)\n",
-                               PTR_ERR(chan));
-               return PTR_ERR(chan);
-       }
-       if (WARN_ON(!chan->device || !chan->device->dev))
-               return -EINVAL;
-
-       if (chan->device->dev->of_node)
-               ret = of_property_read_string(chan->device->dev->of_node,
-                                             "compatible", &tmp);
-       else
-               dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
-
-       dma_release_channel(chan);
-       if (ret)
-               return ret;
-
-       dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
-       if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
-               return PCM_SDMA;
-
-       return PCM_EDMA;
-}
-
-static u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata)
-{
-       int i;
-       u32 offset = 0;
-
-       if (pdata->version != MCASP_VERSION_4)
-               return pdata->tx_dma_offset;
-
-       for (i = 0; i < pdata->num_serializer; i++) {
-               if (pdata->serial_dir[i] == TX_MODE) {
-                       if (!offset) {
-                               offset = DAVINCI_MCASP_TXBUF_REG(i);
-                       } else {
-                               pr_err("%s: Only one serializer allowed!\n",
-                                      __func__);
-                               break;
-                       }
-               }
-       }
-
-       return offset;
-}
-
-static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
-{
-       int i;
-       u32 offset = 0;
-
-       if (pdata->version != MCASP_VERSION_4)
-               return pdata->rx_dma_offset;
-
-       for (i = 0; i < pdata->num_serializer; i++) {
-               if (pdata->serial_dir[i] == RX_MODE) {
-                       if (!offset) {
-                               offset = DAVINCI_MCASP_RXBUF_REG(i);
-                       } else {
-                               pr_err("%s: Only one serializer allowed!\n",
-                                      __func__);
-                               break;
-                       }
-               }
-       }
-
-       return offset;
-}
-
-static int davinci_mcasp_probe(struct platform_device *pdev)
-{
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       struct resource *mem, *res, *dat;
-       struct davinci_mcasp_pdata *pdata;
-       struct davinci_mcasp *mcasp;
-       char *irq_name;
-       int *dma;
-       int irq;
-       int ret;
-
-       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
-       mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
-                          GFP_KERNEL);
-       if (!mcasp)
-               return  -ENOMEM;
-
-       pdata = davinci_mcasp_set_pdata_from_of(pdev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "no platform data\n");
-               return -EINVAL;
-       }
-
-       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       if (!mem) {
-               dev_warn(mcasp->dev,
-                        "\"mpu\" mem resource not found, using index 0\n");
-               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!mem) {
-                       dev_err(&pdev->dev, "no mem resource?\n");
-                       return -ENODEV;
-               }
-       }
-
-       mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
-       if (IS_ERR(mcasp->base))
-               return PTR_ERR(mcasp->base);
-
-       pm_runtime_enable(&pdev->dev);
-
-       mcasp->op_mode = pdata->op_mode;
-       /* sanity check for tdm slots parameter */
-       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
-               if (pdata->tdm_slots < 2) {
-                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-                               pdata->tdm_slots);
-                       mcasp->tdm_slots = 2;
-               } else if (pdata->tdm_slots > 32) {
-                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
-                               pdata->tdm_slots);
-                       mcasp->tdm_slots = 32;
-               } else {
-                       mcasp->tdm_slots = pdata->tdm_slots;
-               }
-       }
-
-       mcasp->num_serializer = pdata->num_serializer;
-#ifdef CONFIG_PM_SLEEP
-       mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
-                                       mcasp->num_serializer, sizeof(u32),
-                                       GFP_KERNEL);
-       if (!mcasp->context.xrsr_regs) {
-               ret = -ENOMEM;
-               goto err;
-       }
-#endif
-       mcasp->serial_dir = pdata->serial_dir;
-       mcasp->version = pdata->version;
-       mcasp->txnumevt = pdata->txnumevt;
-       mcasp->rxnumevt = pdata->rxnumevt;
-
-       mcasp->dev = &pdev->dev;
-
-       irq = platform_get_irq_byname(pdev, "common");
-       if (irq >= 0) {
-               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
-                                         dev_name(&pdev->dev));
-               if (!irq_name) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-                                               davinci_mcasp_common_irq_handler,
-                                               IRQF_ONESHOT | IRQF_SHARED,
-                                               irq_name, mcasp);
-               if (ret) {
-                       dev_err(&pdev->dev, "common IRQ request failed\n");
-                       goto err;
-               }
-
-               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
-               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
-       }
-
-       irq = platform_get_irq_byname(pdev, "rx");
-       if (irq >= 0) {
-               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
-                                         dev_name(&pdev->dev));
-               if (!irq_name) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-                                               davinci_mcasp_rx_irq_handler,
-                                               IRQF_ONESHOT, irq_name, mcasp);
-               if (ret) {
-                       dev_err(&pdev->dev, "RX IRQ request failed\n");
-                       goto err;
-               }
-
-               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
-       }
-
-       irq = platform_get_irq_byname(pdev, "tx");
-       if (irq >= 0) {
-               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
-                                         dev_name(&pdev->dev));
-               if (!irq_name) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-                                               davinci_mcasp_tx_irq_handler,
-                                               IRQF_ONESHOT, irq_name, mcasp);
-               if (ret) {
-                       dev_err(&pdev->dev, "TX IRQ request failed\n");
-                       goto err;
-               }
-
-               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
-       }
-
-       dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
-       if (dat)
-               mcasp->dat_port = true;
-
-       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       if (dat)
-               dma_data->addr = dat->start;
-       else
-               dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata);
-
-       dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (res)
-               *dma = res->start;
-       else
-               *dma = pdata->tx_dma_channel;
-
-       /* dmaengine filter data for DT and non-DT boot */
-       if (pdev->dev.of_node)
-               dma_data->filter_data = "tx";
-       else
-               dma_data->filter_data = dma;
-
-       /* RX is not valid in DIT mode */
-       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-               if (dat)
-                       dma_data->addr = dat->start;
-               else
-                       dma_data->addr =
-                               mem->start + davinci_mcasp_rxdma_offset(pdata);
-
-               dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (res)
-                       *dma = res->start;
-               else
-                       *dma = pdata->rx_dma_channel;
-
-               /* dmaengine filter data for DT and non-DT boot */
-               if (pdev->dev.of_node)
-                       dma_data->filter_data = "rx";
-               else
-                       dma_data->filter_data = dma;
-       }
-
-       if (mcasp->version < MCASP_VERSION_3) {
-               mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
-               /* dma_params->dma_addr is pointing to the data port address */
-               mcasp->dat_port = true;
-       } else {
-               mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
-       }
-
-       /* Allocate memory for long enough list for all possible
-        * scenarios. Maximum number tdm slots is 32 and there cannot
-        * be more serializers than given in the configuration.  The
-        * serializer directions could be taken into account, but it
-        * would make code much more complex and save only couple of
-        * bytes.
-        */
-       mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
-               devm_kcalloc(mcasp->dev,
-                            32 + mcasp->num_serializer - 1,
-                            sizeof(unsigned int),
-                            GFP_KERNEL);
-
-       mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
-               devm_kcalloc(mcasp->dev,
-                            32 + mcasp->num_serializer - 1,
-                            sizeof(unsigned int),
-                            GFP_KERNEL);
-
-       if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
-           !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       ret = davinci_mcasp_set_ch_constraints(mcasp);
-       if (ret)
-               goto err;
-
-       dev_set_drvdata(&pdev->dev, mcasp);
-
-       mcasp_reparent_fck(pdev);
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                       &davinci_mcasp_component,
-                                       &davinci_mcasp_dai[pdata->op_mode], 1);
-
-       if (ret != 0)
-               goto err;
-
-       ret = davinci_mcasp_get_dma_type(mcasp);
-       switch (ret) {
-       case PCM_EDMA:
-#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
-       (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
-        IS_MODULE(CONFIG_SND_EDMA_SOC))
-               ret = edma_pcm_platform_register(&pdev->dev);
-#else
-               dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
-               ret = -EINVAL;
-               goto err;
-#endif
-               break;
-       case PCM_SDMA:
-#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
-       (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
-        IS_MODULE(CONFIG_SND_SDMA_SOC))
-               ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
-#else
-               dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
-               ret = -EINVAL;
-               goto err;
-#endif
-               break;
-       default:
-               dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
-       case -EPROBE_DEFER:
-               goto err;
-               break;
-       }
-
-       if (ret) {
-               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err;
-       }
-
-       return 0;
-
-err:
-       pm_runtime_disable(&pdev->dev);
-       return ret;
-}
-
-static int davinci_mcasp_remove(struct platform_device *pdev)
-{
-       pm_runtime_disable(&pdev->dev);
-
-       return 0;
-}
-
-static struct platform_driver davinci_mcasp_driver = {
-       .probe          = davinci_mcasp_probe,
-       .remove         = davinci_mcasp_remove,
-       .driver         = {
-               .name   = "davinci-mcasp",
-               .of_match_table = mcasp_dt_ids,
-       },
-};
-
-module_platform_driver(davinci_mcasp_driver);
-
-MODULE_AUTHOR("Steve Chen");
-MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
deleted file mode 100644 (file)
index afddc80..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * ALSA SoC McASP Audio Layer for TI DAVINCI processor
- *
- * MCASP related definitions
- *
- * Author: Nirmal Pandey <n-pandey@ti.com>,
- *         Suresh Rajashekara <suresh.r@ti.com>
- *         Steve Chen <schen@.mvista.com>
- *
- * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
- * Copyright:   (C) 2009  Texas Instruments, India
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef DAVINCI_MCASP_H
-#define DAVINCI_MCASP_H
-
-/*
- * McASP register definitions
- */
-#define DAVINCI_MCASP_PID_REG          0x00
-#define DAVINCI_MCASP_PWREMUMGT_REG    0x04
-
-#define DAVINCI_MCASP_PFUNC_REG                0x10
-#define DAVINCI_MCASP_PDIR_REG         0x14
-#define DAVINCI_MCASP_PDOUT_REG                0x18
-#define DAVINCI_MCASP_PDSET_REG                0x1c
-
-#define DAVINCI_MCASP_PDCLR_REG                0x20
-
-#define DAVINCI_MCASP_TLGC_REG         0x30
-#define DAVINCI_MCASP_TLMR_REG         0x34
-
-#define DAVINCI_MCASP_GBLCTL_REG       0x44
-#define DAVINCI_MCASP_AMUTE_REG                0x48
-#define DAVINCI_MCASP_LBCTL_REG                0x4c
-
-#define DAVINCI_MCASP_TXDITCTL_REG     0x50
-
-#define DAVINCI_MCASP_GBLCTLR_REG      0x60
-#define DAVINCI_MCASP_RXMASK_REG       0x64
-#define DAVINCI_MCASP_RXFMT_REG                0x68
-#define DAVINCI_MCASP_RXFMCTL_REG      0x6c
-
-#define DAVINCI_MCASP_ACLKRCTL_REG     0x70
-#define DAVINCI_MCASP_AHCLKRCTL_REG    0x74
-#define DAVINCI_MCASP_RXTDM_REG                0x78
-#define DAVINCI_MCASP_EVTCTLR_REG      0x7c
-
-#define DAVINCI_MCASP_RXSTAT_REG       0x80
-#define DAVINCI_MCASP_RXTDMSLOT_REG    0x84
-#define DAVINCI_MCASP_RXCLKCHK_REG     0x88
-#define DAVINCI_MCASP_REVTCTL_REG      0x8c
-
-#define DAVINCI_MCASP_GBLCTLX_REG      0xa0
-#define DAVINCI_MCASP_TXMASK_REG       0xa4
-#define DAVINCI_MCASP_TXFMT_REG                0xa8
-#define DAVINCI_MCASP_TXFMCTL_REG      0xac
-
-#define DAVINCI_MCASP_ACLKXCTL_REG     0xb0
-#define DAVINCI_MCASP_AHCLKXCTL_REG    0xb4
-#define DAVINCI_MCASP_TXTDM_REG                0xb8
-#define DAVINCI_MCASP_EVTCTLX_REG      0xbc
-
-#define DAVINCI_MCASP_TXSTAT_REG       0xc0
-#define DAVINCI_MCASP_TXTDMSLOT_REG    0xc4
-#define DAVINCI_MCASP_TXCLKCHK_REG     0xc8
-#define DAVINCI_MCASP_XEVTCTL_REG      0xcc
-
-/* Left(even TDM Slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRA_REG      0x100
-/* Right(odd TDM slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRB_REG      0x118
-/* Left(even TDM slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRA_REG      0x130
-/* Right(odd TDM Slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRB_REG      0x148
-
-/* Serializer n Control Register */
-#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
-#define DAVINCI_MCASP_XRSRCTL_REG(n)   (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
-                                               (n << 2))
-
-/* Transmit Buffer for Serializer n */
-#define DAVINCI_MCASP_TXBUF_REG(n)     (0x200 + (n << 2))
-/* Receive Buffer for Serializer n */
-#define DAVINCI_MCASP_RXBUF_REG(n)     (0x280 + (n << 2))
-
-/* McASP FIFO Registers */
-#define DAVINCI_MCASP_V2_AFIFO_BASE    (0x1010)
-#define DAVINCI_MCASP_V3_AFIFO_BASE    (0x1000)
-
-/* FIFO register offsets from AFIFO base */
-#define MCASP_WFIFOCTL_OFFSET          (0x0)
-#define MCASP_WFIFOSTS_OFFSET          (0x4)
-#define MCASP_RFIFOCTL_OFFSET          (0x8)
-#define MCASP_RFIFOSTS_OFFSET          (0xc)
-
-/*
- * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
- *     Register Bits
- */
-#define MCASP_FREE     BIT(0)
-#define MCASP_SOFT     BIT(1)
-
-/*
- * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
- */
-#define AXR(n)         (1<<n)
-#define PFUNC_AMUTE    BIT(25)
-#define ACLKX          BIT(26)
-#define AHCLKX         BIT(27)
-#define AFSX           BIT(28)
-#define ACLKR          BIT(29)
-#define AHCLKR         BIT(30)
-#define AFSR           BIT(31)
-
-/*
- * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
- */
-#define AXR(n)         (1<<n)
-#define PDIR_AMUTE     BIT(25)
-#define ACLKX          BIT(26)
-#define AHCLKX         BIT(27)
-#define AFSX           BIT(28)
-#define ACLKR          BIT(29)
-#define AHCLKR         BIT(30)
-#define AFSR           BIT(31)
-
-/*
- * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
- */
-#define DITEN  BIT(0)  /* Transmit DIT mode enable/disable */
-#define VA     BIT(2)
-#define VB     BIT(3)
-
-/*
- * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
- */
-#define TXROT(val)     (val)
-#define TXSEL          BIT(3)
-#define TXSSZ(val)     (val<<4)
-#define TXPBIT(val)    (val<<8)
-#define TXPAD(val)     (val<<13)
-#define TXORD          BIT(15)
-#define FSXDLY(val)    (val<<16)
-
-/*
- * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
- */
-#define RXROT(val)     (val)
-#define RXSEL          BIT(3)
-#define RXSSZ(val)     (val<<4)
-#define RXPBIT(val)    (val<<8)
-#define RXPAD(val)     (val<<13)
-#define RXORD          BIT(15)
-#define FSRDLY(val)    (val<<16)
-
-/*
- * DAVINCI_MCASP_TXFMCTL_REG -  Transmit Frame Control Register Bits
- */
-#define FSXPOL         BIT(0)
-#define AFSXE          BIT(1)
-#define FSXDUR         BIT(4)
-#define FSXMOD(val)    (val<<7)
-
-/*
- * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
- */
-#define FSRPOL         BIT(0)
-#define AFSRE          BIT(1)
-#define FSRDUR         BIT(4)
-#define FSRMOD(val)    (val<<7)
-
-/*
- * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
- */
-#define ACLKXDIV(val)  (val)
-#define ACLKXE         BIT(5)
-#define TX_ASYNC       BIT(6)
-#define ACLKXPOL       BIT(7)
-#define ACLKXDIV_MASK  0x1f
-
-/*
- * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
- */
-#define ACLKRDIV(val)  (val)
-#define ACLKRE         BIT(5)
-#define RX_ASYNC       BIT(6)
-#define ACLKRPOL       BIT(7)
-#define ACLKRDIV_MASK  0x1f
-
-/*
- * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
- *     Register Bits
- */
-#define AHCLKXDIV(val) (val)
-#define AHCLKXPOL      BIT(14)
-#define AHCLKXE                BIT(15)
-#define AHCLKXDIV_MASK 0xfff
-
-/*
- * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
- *     Register Bits
- */
-#define AHCLKRDIV(val) (val)
-#define AHCLKRPOL      BIT(14)
-#define AHCLKRE                BIT(15)
-#define AHCLKRDIV_MASK 0xfff
-
-/*
- * DAVINCI_MCASP_XRSRCTL_BASE_REG -  Serializer Control Register Bits
- */
-#define MODE(val)      (val)
-#define DISMOD_3STATE  (0x0)
-#define DISMOD_LOW     (0x2 << 2)
-#define DISMOD_HIGH    (0x3 << 2)
-#define DISMOD_MASK    DISMOD_HIGH
-#define TXSTATE                BIT(4)
-#define RXSTATE                BIT(5)
-#define SRMOD_MASK     3
-#define SRMOD_INACTIVE 0
-
-/*
- * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
- */
-#define LBEN           BIT(0)
-#define LBORD          BIT(1)
-#define LBGENMODE(val) (val<<2)
-
-/*
- * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
- */
-#define TXTDMS(n)      (1<<n)
-
-/*
- * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
- */
-#define RXTDMS(n)      (1<<n)
-
-/*
- * DAVINCI_MCASP_GBLCTL_REG -  Global Control Register Bits
- */
-#define RXCLKRST       BIT(0)  /* Receiver Clock Divider Reset */
-#define RXHCLKRST      BIT(1)  /* Receiver High Frequency Clock Divider */
-#define RXSERCLR       BIT(2)  /* Receiver Serializer Clear */
-#define RXSMRST                BIT(3)  /* Receiver State Machine Reset */
-#define RXFSRST                BIT(4)  /* Frame Sync Generator Reset */
-#define TXCLKRST       BIT(8)  /* Transmitter Clock Divider Reset */
-#define TXHCLKRST      BIT(9)  /* Transmitter High Frequency Clock Divider*/
-#define TXSERCLR       BIT(10) /* Transmit Serializer Clear */
-#define TXSMRST                BIT(11) /* Transmitter State Machine Reset */
-#define TXFSRST                BIT(12) /* Frame Sync Generator Reset */
-
-/*
- * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits
- * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits
- */
-#define XRERR          BIT(8) /* Transmit/Receive error */
-#define XRDATA         BIT(5) /* Transmit/Receive data ready */
-
-/*
- * DAVINCI_MCASP_AMUTE_REG -  Mute Control Register Bits
- */
-#define MUTENA(val)    (val)
-#define MUTEINPOL      BIT(2)
-#define MUTEINENA      BIT(3)
-#define MUTEIN         BIT(4)
-#define MUTER          BIT(5)
-#define MUTEX          BIT(6)
-#define MUTEFSR                BIT(7)
-#define MUTEFSX                BIT(8)
-#define MUTEBADCLKR    BIT(9)
-#define MUTEBADCLKX    BIT(10)
-#define MUTERXDMAERR   BIT(11)
-#define MUTETXDMAERR   BIT(12)
-
-/*
- * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
- */
-#define RXDATADMADIS   BIT(0)
-
-/*
- * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
- */
-#define TXDATADMADIS   BIT(0)
-
-/*
- * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits
- */
-#define ROVRN          BIT(0)
-
-/*
- * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits
- */
-#define XUNDRN         BIT(0)
-
-/*
- * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
- */
-#define FIFO_ENABLE    BIT(16)
-#define NUMEVT_MASK    (0xFF << 8)
-#define NUMEVT(x)      (((x) & 0xFF) << 8)
-#define NUMDMA_MASK    (0xFF)
-
-/* clock divider IDs */
-#define MCASP_CLKDIV_AUXCLK            0 /* HCLK divider from AUXCLK */
-#define MCASP_CLKDIV_BCLK              1 /* BCLK divider from HCLK */
-#define MCASP_CLKDIV_BCLK_FS_RATIO     2 /* to set BCLK FS ration */
-
-#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
deleted file mode 100644 (file)
index 5415b72..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * ALSA SoC Voice Codec Interface for TI DAVINCI processor
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/mfd/davinci_voicecodec.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "edma-pcm.h"
-#include "davinci-i2s.h"
-
-#define MOD_REG_BIT(val, mask, set) do { \
-       if (set) { \
-               val |= mask; \
-       } else { \
-               val &= ~mask; \
-       } \
-} while (0)
-
-struct davinci_vcif_dev {
-       struct davinci_vc *davinci_vc;
-       struct snd_dmaengine_dai_dma_data dma_data[2];
-       int dma_request[2];
-};
-
-static void davinci_vcif_start(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_vcif_dev *davinci_vcif_dev =
-                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
-       u32 w;
-
-       /* Start the sample generator and enable transmitter/receiver */
-       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
-       else
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
-
-       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
-}
-
-static void davinci_vcif_stop(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_vcif_dev *davinci_vcif_dev =
-                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
-       u32 w;
-
-       /* Reset transmitter/receiver and sample rate/frame sync generators */
-       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
-       else
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
-
-       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
-}
-
-static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params,
-                                 struct snd_soc_dai *dai)
-{
-       struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
-       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
-       u32 w;
-
-       /* Restart the codec before setup */
-       davinci_vcif_stop(substream);
-       davinci_vcif_start(substream);
-
-       /* General line settings */
-       writel(DAVINCI_VC_CTRL_MASK, davinci_vc->base + DAVINCI_VC_CTRL);
-
-       writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTCLR);
-
-       writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTEN);
-
-       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
-
-       /* Determine xfer data type */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_U8:
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
-                           DAVINCI_VC_CTRL_RD_UNSIGNED |
-                           DAVINCI_VC_CTRL_WD_BITS_8 |
-                           DAVINCI_VC_CTRL_WD_UNSIGNED, 1);
-               break;
-       case SNDRV_PCM_FORMAT_S8:
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
-                           DAVINCI_VC_CTRL_WD_BITS_8, 1);
-
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_UNSIGNED |
-                           DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
-                           DAVINCI_VC_CTRL_RD_UNSIGNED |
-                           DAVINCI_VC_CTRL_WD_BITS_8 |
-                           DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
-               break;
-       default:
-               printk(KERN_WARNING "davinci-vcif: unsupported PCM format");
-               return -EINVAL;
-       }
-
-       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
-
-       return 0;
-}
-
-static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               davinci_vcif_start(substream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               davinci_vcif_stop(substream);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-#define DAVINCI_VCIF_RATES     SNDRV_PCM_RATE_8000_48000
-
-static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
-       .trigger        = davinci_vcif_trigger,
-       .hw_params      = davinci_vcif_hw_params,
-};
-
-static int davinci_vcif_dai_probe(struct snd_soc_dai *dai)
-{
-       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver davinci_vcif_dai = {
-       .probe = davinci_vcif_dai_probe,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = DAVINCI_VCIF_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = DAVINCI_VCIF_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = &davinci_vcif_dai_ops,
-
-};
-
-static const struct snd_soc_component_driver davinci_vcif_component = {
-       .name           = "davinci-vcif",
-};
-
-static int davinci_vcif_probe(struct platform_device *pdev)
-{
-       struct davinci_vc *davinci_vc = pdev->dev.platform_data;
-       struct davinci_vcif_dev *davinci_vcif_dev;
-       int ret;
-
-       davinci_vcif_dev = devm_kzalloc(&pdev->dev,
-                                       sizeof(struct davinci_vcif_dev),
-                                       GFP_KERNEL);
-       if (!davinci_vcif_dev)
-               return -ENOMEM;
-
-       /* DMA tx params */
-       davinci_vcif_dev->davinci_vc = davinci_vc;
-       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data =
-                               &davinci_vc->davinci_vcif.dma_tx_channel;
-       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
-                               davinci_vc->davinci_vcif.dma_tx_addr;
-
-       /* DMA rx params */
-       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data =
-                               &davinci_vc->davinci_vcif.dma_rx_channel;
-       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
-                               davinci_vc->davinci_vcif.dma_rx_addr;
-
-       dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                             &davinci_vcif_component,
-                                             &davinci_vcif_dai, 1);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "could not register dai\n");
-               return ret;
-       }
-
-       ret = edma_pcm_platform_register(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct platform_driver davinci_vcif_driver = {
-       .probe          = davinci_vcif_probe,
-       .driver         = {
-               .name   = "davinci-vcif",
-       },
-};
-
-module_platform_driver(davinci_vcif_driver);
-
-MODULE_AUTHOR("Miguel Aguilar");
-MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
deleted file mode 100644 (file)
index 59e588a..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
- *
- * Copyright (C) 2014 Texas Instruments, Inc.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * Based on: sound/soc/tegra/tegra_pcm.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-#include <linux/edma.h>
-
-#include "edma-pcm.h"
-
-static const struct snd_pcm_hardware edma_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
-                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
-                                 SNDRV_PCM_INFO_INTERLEAVED,
-       .buffer_bytes_max       = 128 * 1024,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 64 * 1024,
-       .periods_min            = 2,
-       .periods_max            = 19, /* Limit by edma dmaengine driver */
-};
-
-static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
-       .pcm_hardware = &edma_pcm_hardware,
-       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
-       .compat_filter_fn = edma_filter_fn,
-       .prealloc_buffer_size = 128 * 1024,
-};
-
-int edma_pcm_platform_register(struct device *dev)
-{
-       return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
-                                       SND_DMAENGINE_PCM_FLAG_COMPAT);
-}
-EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
-
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/davinci/edma-pcm.h
deleted file mode 100644 (file)
index b095774..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
- *
- * Copyright (C) 2014 Texas Instruments, Inc.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * Based on: sound/soc/tegra/tegra_pcm.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#ifndef __EDMA_PCM_H__
-#define __EDMA_PCM_H__
-
-#if IS_ENABLED(CONFIG_SND_EDMA_SOC)
-int edma_pcm_platform_register(struct device *dev);
-#else
-static inline int edma_pcm_platform_register(struct device *dev)
-{
-       return 0;
-}
-#endif /* CONFIG_SND_EDMA_SOC */
-
-#endif /* __EDMA_PCM_H__ */
index 6ec19fb4a934d08084b4e75016689a658bddce76..2e75b5bc5f1daafea2630fc6963b94f7e8a9c032 100644 (file)
@@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97
 
 config SND_SOC_EUKREA_TLV320
        tristate "Eukrea TLV320"
-       depends on ARCH_MXC && I2C
+       depends on ARCH_MXC && !ARM64 && I2C
        select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_IMX_SSI
index 44433b20435cce7778ea72ee54adf8445dbaca31..81f2fe2c6d230260f422640054b9a1827fb60376 100644 (file)
@@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        }
 
        /* Common settings for corresponding Freescale CPU DAI driver */
-       if (strstr(cpu_np->name, "ssi")) {
+       if (of_node_name_eq(cpu_np, "ssi")) {
                /* Only SSI needs to configure AUDMUX */
                ret = fsl_asoc_card_audmux_init(np, priv);
                if (ret) {
                        dev_err(&pdev->dev, "failed to init audmux\n");
                        goto asrc_fail;
                }
-       } else if (strstr(cpu_np->name, "esai")) {
+       } else if (of_node_name_eq(cpu_np, "esai")) {
                priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
                priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
-       } else if (strstr(cpu_np->name, "sai")) {
+       } else if (of_node_name_eq(cpu_np, "sai")) {
                priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
                priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
        }
index 1255dfe19eef8b6e82070c394042c59fa70472ce..6f6294149476adddc935ca325fd22c5b905c3824 100644 (file)
@@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, fsl_ssi_stats_show, inode->i_private);
-}
-
-static const struct file_operations fsl_ssi_stats_ops = {
-       .open = fsl_ssi_stats_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats);
 
 int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
 {
@@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
 
        ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
                                                 ssi_dbg->dbg_dir, ssi_dbg,
-                                                &fsl_ssi_stats_ops);
+                                                &fsl_ssi_stats_fops);
        if (!ssi_dbg->dbg_stats) {
                debugfs_remove(ssi_dbg->dbg_dir);
                return -ENOMEM;
index c954be0a0f96b052496dae219173cc46e9e14993..92c2cf06f40ac89bebdd7a9f193ae1ed51983907 100644 (file)
@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
        select SND_SIMPLE_CARD_UTILS
        help
          This option enables generic simple sound card support
+         It also support DPCM of multi CPU single Codec ststem.
 
 config SND_SIMPLE_SCU_CARD
        tristate "ASoC Simple SCU sound card support"
@@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD
        depends on OF
        select SND_SIMPLE_CARD_UTILS
        help
-         This option enables generic simple simple sound card support
+         This option enables generic simple sound card support
          with OF-graph DT bindings.
+         It also support DPCM of multi CPU single Codec ststem.
 
 config SND_AUDIO_GRAPH_SCU_CARD
        tristate "ASoC Audio Graph SCU sound card support"
index 25c819e402e1853c003efe4fde40cfa59ac34074..0d6144560a1e5d6ee31d0bfb8c0b186945c88d17 100644 (file)
 struct graph_card_data {
        struct snd_soc_card snd_card;
        struct graph_dai_props {
-               struct asoc_simple_dai cpu_dai;
-               struct asoc_simple_dai codec_dai;
+               struct asoc_simple_dai *cpu_dai;
+               struct asoc_simple_dai *codec_dai;
                struct snd_soc_dai_link_component codecs; /* single codec */
                struct snd_soc_dai_link_component platform;
+               struct asoc_simple_card_data adata;
+               struct snd_soc_codec_conf *codec_conf;
                unsigned int mclk_fs;
        } *dai_props;
-       unsigned int mclk_fs;
        struct asoc_simple_jack hp_jack;
        struct asoc_simple_jack mic_jack;
        struct snd_soc_dai_link *dai_link;
+       struct asoc_simple_dai *dais;
+       struct snd_soc_codec_conf *codec_conf;
        struct gpio_desc *pa_gpio;
 };
 
+#define graph_priv_to_card(priv) (&(priv)->snd_card)
+#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
+#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
+#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
+
+#define PREFIX "audio-graph-card,"
+
 static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
                                        struct snd_kcontrol *kcontrol,
                                        int event)
@@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
                               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 };
 
-#define graph_priv_to_card(priv) (&(priv)->snd_card)
-#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
-#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
-#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
-
 static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
        int ret;
 
-       ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+       ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
        if (ret)
                return ret;
 
-       ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+       ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
        if (ret)
-               asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+               asoc_simple_card_clk_disable(dai_props->cpu_dai);
 
        return ret;
 }
@@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
 
-       asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+       asoc_simple_card_clk_disable(dai_props->cpu_dai);
 
-       asoc_simple_card_clk_disable(&dai_props->codec_dai);
+       asoc_simple_card_clk_disable(dai_props->codec_dai);
 }
 
 static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
@@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
        unsigned int mclk, mclk_fs = 0;
        int ret = 0;
 
-       if (priv->mclk_fs)
-               mclk_fs = priv->mclk_fs;
-       else if (dai_props->mclk_fs)
+       if (dai_props->mclk_fs)
                mclk_fs = dai_props->mclk_fs;
 
        if (mclk_fs) {
@@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
 static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct graph_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *codec = rtd->codec_dai;
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       struct graph_dai_props *dai_props =
-               graph_priv_to_props(priv, rtd->num);
-       int ret;
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+       int ret = 0;
 
-       ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+       ret = asoc_simple_card_init_dai(rtd->codec_dai,
+                                       dai_props->codec_dai);
        if (ret < 0)
                return ret;
 
-       ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+       ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+                                       dai_props->cpu_dai);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
-                                       struct graph_card_data *priv,
-                                       int idx)
+static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                             struct snd_pcm_hw_params *params)
+{
+       struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+       asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+       return 0;
+}
+
+static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top,
+                                           struct device_node *cpu_ep,
+                                           struct device_node *codec_ep,
+                                           struct graph_card_data *priv,
+                                           int *dai_idx, int link_idx,
+                                           int *conf_idx, int is_cpu)
 {
        struct device *dev = graph_priv_to_dev(priv);
-       struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
-       struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
-       struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
-       struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
-       struct device_node *cpu_ep    = of_get_next_child(cpu_port, NULL);
-       struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
-       struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
+       struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+       struct device_node *ep = is_cpu ? cpu_ep : codec_ep;
+       struct device_node *port = of_get_parent(ep);
+       struct device_node *ports = of_get_parent(port);
+       struct device_node *node = of_graph_get_port_parent(ep);
+       struct asoc_simple_dai *dai;
+       struct snd_soc_dai_link_component *codecs = dai_link->codecs;
        int ret;
 
-       if (rcpu_ep != cpu_ep) {
-               dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
-                       cpu_ep->name, codec_ep->name, rcpu_ep->name);
-               ret = -EINVAL;
-               goto dai_link_of_err;
+       dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec");
+
+       of_property_read_u32(top,   "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(port,  "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(ep,    "mclk-fs", &dai_props->mclk_fs);
+
+       asoc_simple_card_parse_convert(dev, top,   NULL,   &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, node,  PREFIX, &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, ports, NULL,   &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, port,  NULL,   &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, ep,    NULL,   &dai_props->adata);
+
+       of_node_put(ports);
+       of_node_put(port);
+
+       if (is_cpu) {
+
+               /* BE is dummy */
+               codecs->of_node         = NULL;
+               codecs->dai_name        = "snd-soc-dummy-dai";
+               codecs->name            = "snd-soc-dummy";
+
+               /* FE settings */
+               dai_link->dynamic               = 1;
+               dai_link->dpcm_merged_format    = 1;
+
+               dai =
+               dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+
+               ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
+               if (ret)
+                       return ret;
+
+               ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+                                                       "fe.%s",
+                                                       dai_link->cpu_dai_name);
+               if (ret < 0)
+                       return ret;
+
+               /* card->num_links includes Codec */
+               asoc_simple_card_canonicalize_cpu(dai_link,
+                       of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
+       } else {
+               struct snd_soc_codec_conf *cconf;
+
+               /* FE is dummy */
+               dai_link->cpu_of_node           = NULL;
+               dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
+               dai_link->cpu_name              = "snd-soc-dummy";
+
+               /* BE settings */
+               dai_link->no_pcm                = 1;
+               dai_link->be_hw_params_fixup    = asoc_graph_card_be_hw_params_fixup;
+
+               dai =
+               dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
+
+               cconf =
+               dai_props->codec_conf   = &priv->codec_conf[(*conf_idx)++];
+
+               ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+                                                       "be.%s",
+                                                       codecs->dai_name);
+               if (ret < 0)
+                       return ret;
+
+               /* check "prefix" from top node */
+               snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+                                             "prefix");
+               snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+                                            PREFIX "prefix");
+               snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
+                                            "prefix");
+               snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
+                                            "prefix");
        }
 
+       ret = asoc_simple_card_of_parse_tdm(ep, dai);
+       if (ret)
+               return ret;
+
+       ret = asoc_simple_card_canonicalize_dailink(dai_link);
+       if (ret < 0)
+               return ret;
+
        ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
                                            NULL, &dai_link->dai_fmt);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
+
+       dai_link->dpcm_playback         = 1;
+       dai_link->dpcm_capture          = 1;
+       dai_link->ops                   = &asoc_graph_card_ops;
+       dai_link->init                  = asoc_graph_card_dai_init;
+
+       return 0;
+}
+
+static int asoc_graph_card_dai_link_of(struct device_node *top,
+                                       struct device_node *cpu_ep,
+                                       struct device_node *codec_ep,
+                                       struct graph_card_data *priv,
+                                       int *dai_idx, int link_idx)
+{
+       struct device *dev = graph_priv_to_dev(priv);
+       struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+       struct device_node *cpu_port = of_get_parent(cpu_ep);
+       struct device_node *codec_port = of_get_parent(codec_ep);
+       struct device_node *cpu_ports = of_get_parent(cpu_port);
+       struct device_node *codec_ports = of_get_parent(codec_port);
+       struct asoc_simple_dai *cpu_dai;
+       struct asoc_simple_dai *codec_dai;
+       int ret;
+
+       dev_dbg(dev, "link_of\n");
+
+       cpu_dai                 =
+       dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+       codec_dai               =
+       dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
 
-       of_property_read_u32(cpu_ep,   "mclk-fs", &dai_props->mclk_fs);
-       of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
+       /* Factor to mclk, used in hw_params() */
+       of_property_read_u32(top,         "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(cpu_ports,   "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(cpu_port,    "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(codec_port,  "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(cpu_ep,      "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(codec_ep,    "mclk-fs", &dai_props->mclk_fs);
+       of_node_put(cpu_port);
+       of_node_put(cpu_ports);
+       of_node_put(codec_port);
+       of_node_put(codec_ports);
+
+       ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+                                           NULL, &dai_link->dai_fmt);
+       if (ret < 0)
+               return ret;
 
        ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_canonicalize_dailink(dai_link);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        ret = asoc_simple_card_set_dailink_name(dev, dai_link,
                                                "%s-%s",
                                                dai_link->cpu_dai_name,
                                                dai_link->codecs->dai_name);
        if (ret < 0)
-               goto dai_link_of_err;
+               return ret;
 
        dai_link->ops = &asoc_graph_card_ops;
        dai_link->init = asoc_graph_card_dai_init;
@@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
        asoc_simple_card_canonicalize_cpu(dai_link,
                of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
 
-dai_link_of_err:
-       of_node_put(cpu_ep);
-       of_node_put(rcpu_ep);
-       of_node_put(codec_ep);
-
-       return ret;
+       return 0;
 }
 
 static int asoc_graph_card_parse_of(struct graph_card_data *priv)
@@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        struct of_phandle_iterator it;
        struct device *dev = graph_priv_to_dev(priv);
        struct snd_soc_card *card = graph_priv_to_card(priv);
-       struct device_node *node = dev->of_node;
-       int rc, idx = 0;
-       int ret;
+       struct device_node *top = dev->of_node;
+       struct device_node *node = top;
+       struct device_node *cpu_port;
+       struct device_node *cpu_ep              = NULL;
+       struct device_node *codec_ep            = NULL;
+       struct device_node *codec_port          = NULL;
+       struct device_node *codec_port_old      = NULL;
+       int rc, ret;
+       int link_idx, dai_idx, conf_idx;
+       int cpu;
 
        ret = asoc_simple_card_of_parse_widgets(card, NULL);
        if (ret < 0)
                return ret;
 
-       ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
+       ret = asoc_simple_card_of_parse_routing(card, NULL);
        if (ret < 0)
                return ret;
 
-       /* Factor to mclk, used in hw_params() */
-       of_property_read_u32(node, "mclk-fs", &priv->mclk_fs);
-
-       of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
-               ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
-               if (ret < 0) {
-                       of_node_put(it.node);
-
-                       return ret;
+       link_idx        = 0;
+       dai_idx         = 0;
+       conf_idx        = 0;
+       codec_port_old  = NULL;
+       for (cpu = 1; cpu >= 0; cpu--) {
+               /*
+                * Detect all CPU first, and Detect all Codec 2nd.
+                *
+                * In Normal sound case, all DAIs are detected
+                * as "CPU-Codec".
+                *
+                * In DPCM sound case,
+                * all CPUs   are detected as "CPU-dummy", and
+                * all Codecs are detected as "dummy-Codec".
+                * To avoid random sub-device numbering,
+                * detect "dummy-Codec" in last;
+                */
+               of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+                       cpu_port = it.node;
+                       cpu_ep   = NULL;
+                       while (1) {
+                               cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+                               if (!cpu_ep)
+                                       break;
+
+                               codec_ep   = of_graph_get_remote_endpoint(cpu_ep);
+                               codec_port = of_get_parent(codec_ep);
+
+                               of_node_put(codec_ep);
+                               of_node_put(codec_port);
+
+                               dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep);
+
+                               if (of_get_child_count(codec_port) > 1) {
+                                       /*
+                                        * for DPCM sound
+                                        */
+                                       if (!cpu) {
+                                               if (codec_port_old == codec_port)
+                                                       continue;
+                                               codec_port_old = codec_port;
+                                       }
+                                       ret = asoc_graph_card_dai_link_of_dpcm(
+                                               top, cpu_ep, codec_ep, priv,
+                                               &dai_idx, link_idx++,
+                                               &conf_idx, cpu);
+                               } else if (cpu) {
+                                       /*
+                                        * for Normal sound
+                                        */
+                                       ret = asoc_graph_card_dai_link_of(
+                                               top, cpu_ep, codec_ep, priv,
+                                               &dai_idx, link_idx++);
+                               }
+                               if (ret < 0)
+                                       return ret;
+                       }
                }
        }
 
        return asoc_simple_card_parse_card_name(card, NULL);
 }
 
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+                                     int *link_num,
+                                     int *dais_num,
+                                     int *ccnf_num)
 {
        struct of_phandle_iterator it;
        struct device_node *node = dev->of_node;
-       int count = 0;
+       struct device_node *cpu_port;
+       struct device_node *cpu_ep;
+       struct device_node *codec_ep;
+       struct device_node *codec_port;
+       struct device_node *codec_port_old;
+       struct device_node *codec_port_old2;
        int rc;
 
-       of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
-               count++;
-
-       return count;
+       /*
+        * link_num :   number of links.
+        *              CPU-Codec / CPU-dummy / dummy-Codec
+        * dais_num :   number of DAIs
+        * ccnf_num :   number of codec_conf
+        *              same number for "dummy-Codec"
+        *
+        * ex1)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 7
+        * CPU2 -/              ccnf : 1
+        * CPU3 --- Codec2
+        *
+        *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+        *      => 7 DAIs  = 4xCPU + 3xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex2)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 6
+        * CPU2 -/              ccnf : 1
+        * CPU3 -/
+        *
+        *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex3)
+        * CPU0 --- Codec0      link : 6
+        * CPU1 -/              dais : 6
+        * CPU2 --- Codec1      ccnf : 2
+        * CPU3 -/
+        *
+        *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 2 ccnf  = 2xdummy-Codec
+        */
+       codec_port_old = NULL;
+       codec_port_old2 = NULL;
+       of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+               cpu_port = it.node;
+               cpu_ep   = NULL;
+               while (1) {
+                       cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+                       if (!cpu_ep)
+                               break;
+
+                       codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+                       codec_port = of_get_parent(codec_ep);
+
+                       of_node_put(codec_ep);
+                       of_node_put(codec_port);
+
+                       (*link_num)++;
+                       (*dais_num)++;
+
+                       if (codec_port_old == codec_port) {
+                               if (codec_port_old2 != codec_port_old) {
+                                       (*link_num)++;
+                                       (*ccnf_num)++;
+                               }
+
+                               codec_port_old2 = codec_port_old;
+                               continue;
+                       }
+
+                       (*dais_num)++;
+                       codec_port_old = codec_port;
+               }
+       }
 }
 
 static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
@@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
        struct graph_card_data *priv;
        struct snd_soc_dai_link *dai_link;
        struct graph_dai_props *dai_props;
+       struct asoc_simple_dai *dais;
        struct device *dev = &pdev->dev;
        struct snd_soc_card *card;
-       int num, ret, i;
+       struct snd_soc_codec_conf *cconf;
+       int lnum = 0, dnum = 0, cnum = 0;
+       int ret, i;
 
        /* Allocate the private data and the DAI link array */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       num = asoc_graph_get_dais_count(dev);
-       if (num == 0)
+       asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+       if (!lnum || !dnum)
                return -EINVAL;
 
-       dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
-       dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
-       if (!dai_props || !dai_link)
+       dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+       dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link),  GFP_KERNEL);
+       dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
+       cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
+       if (!dai_props || !dai_link || !dais)
                return -ENOMEM;
 
        /*
@@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
         * see
         *      soc-core.c :: snd_soc_init_multicodec()
         */
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < lnum; i++) {
                dai_link[i].codecs      = &dai_props[i].codecs;
                dai_link[i].num_codecs  = 1;
                dai_link[i].platform    = &dai_props[i].platform;
@@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
 
        priv->dai_props                 = dai_props;
        priv->dai_link                  = dai_link;
+       priv->dais                      = dais;
+       priv->codec_conf                = cconf;
 
        /* Init snd_soc_card */
        card = graph_priv_to_card(priv);
-       card->owner     = THIS_MODULE;
-       card->dev       = dev;
-       card->dai_link  = dai_link;
-       card->num_links = num;
-       card->dapm_widgets = asoc_graph_card_dapm_widgets;
-       card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
-       card->probe     = asoc_graph_soc_card_probe;
+       card->owner             = THIS_MODULE;
+       card->dev               = dev;
+       card->dai_link          = dai_link;
+       card->num_links         = lnum;
+       card->dapm_widgets      = asoc_graph_card_dapm_widgets;
+       card->num_dapm_widgets  = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
+       card->probe             = asoc_graph_soc_card_probe;
+       card->codec_conf        = cconf;
+       card->num_configs       = cnum;
 
        ret = asoc_graph_card_parse_of(priv);
        if (ret < 0) {
@@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev)
 
 static const struct of_device_id asoc_graph_of_match[] = {
        { .compatible = "audio-graph-card", },
+       { .compatible = "audio-graph-scu-card", },
        {},
 };
 MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
index b83bb31021a9fb9d906c1fee32e3eed01b4b85cd..e1b192ea147b5370709c791b3d73a3c629331e1c 100644 (file)
 
 struct graph_card_data {
        struct snd_soc_card snd_card;
-       struct snd_soc_codec_conf codec_conf;
        struct graph_dai_props {
-               struct asoc_simple_dai dai;
+               struct asoc_simple_dai *cpu_dai;
+               struct asoc_simple_dai *codec_dai;
                struct snd_soc_dai_link_component codecs;
                struct snd_soc_dai_link_component platform;
+               struct asoc_simple_card_data adata;
+               struct snd_soc_codec_conf *codec_conf;
        } *dai_props;
        struct snd_soc_dai_link *dai_link;
+       struct asoc_simple_dai *dais;
        struct asoc_simple_card_data adata;
+       struct snd_soc_codec_conf *codec_conf;
 };
 
 #define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -39,13 +43,24 @@ struct graph_card_data {
 #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
 #define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
 
+#define PREFIX "audio-graph-card,"
+
 static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+       int ret = 0;
+
+       ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+       if (ret)
+               return ret;
 
-       return asoc_simple_card_clk_enable(&dai_props->dai);
+       ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+       if (ret)
+               asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+       return ret;
 }
 
 static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
 
-       asoc_simple_card_clk_disable(&dai_props->dai);
+       asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+       asoc_simple_card_clk_disable(dai_props->codec_dai);
 }
 
 static const struct snd_soc_ops asoc_graph_card_ops = {
@@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
 static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct graph_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *dai;
-       struct snd_soc_dai_link *dai_link;
-       struct graph_dai_props *dai_props;
-       int num = rtd->num;
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+       int ret = 0;
 
-       dai_link        = graph_priv_to_link(priv, num);
-       dai_props       = graph_priv_to_props(priv, num);
-       dai             = dai_link->dynamic ?
-                               rtd->cpu_dai :
-                               rtd->codec_dai;
+       ret = asoc_simple_card_init_dai(rtd->codec_dai,
+                                       dai_props->codec_dai);
+       if (ret < 0)
+               return ret;
 
-       return asoc_simple_card_init_dai(dai, &dai_props->dai);
+       ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+                                       dai_props->cpu_dai);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                               struct snd_pcm_hw_params *params)
 {
        struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+       asoc_simple_card_convert_fixup(&dai_props->adata, params);
 
+       /* overwrite by top level adata if exist */
        asoc_simple_card_convert_fixup(&priv->adata, params);
 
        return 0;
 }
 
-static int asoc_graph_card_dai_link_of(struct device_node *ep,
+static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep,
+                                      struct device_node *codec_ep,
                                       struct graph_card_data *priv,
-                                      unsigned int daifmt,
-                                      int idx, int is_fe)
+                                      int *dai_idx, int link_idx,
+                                      int *conf_idx, int is_fe)
 {
        struct device *dev = graph_priv_to_dev(priv);
-       struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
-       struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
+       struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+       struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
        struct snd_soc_card *card = graph_priv_to_card(priv);
+       struct device_node *ep = is_fe ? cpu_ep : codec_ep;
+       struct device_node *node = of_graph_get_port_parent(ep);
+       struct asoc_simple_dai *dai;
        int ret;
 
        if (is_fe) {
@@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
                dai_link->dynamic               = 1;
                dai_link->dpcm_merged_format    = 1;
 
+               dai =
+               dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+
                ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
                if (ret)
                        return ret;
 
-               ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
+               ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
                if (ret < 0)
                        return ret;
 
@@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
                asoc_simple_card_canonicalize_cpu(dai_link,
                        of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
        } else {
+               struct snd_soc_codec_conf *cconf;
+
                /* FE is dummy */
                dai_link->cpu_of_node           = NULL;
                dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
@@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
                dai_link->no_pcm                = 1;
                dai_link->be_hw_params_fixup    = asoc_graph_card_be_hw_params_fixup;
 
+               dai =
+               dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
+
+               cconf =
+               dai_props->codec_conf   = &priv->codec_conf[(*conf_idx)++];
+
                ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
                if (ret < 0)
                        return ret;
 
-               ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
+               ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
                if (ret < 0)
                        return ret;
 
@@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
                if (ret < 0)
                        return ret;
 
-               snd_soc_of_parse_audio_prefix(card,
-                                             &priv->codec_conf,
+               /* check "prefix" from top node */
+               snd_soc_of_parse_audio_prefix(card, cconf,
                                              dai_link->codecs->of_node,
                                              "prefix");
+               /* check "prefix" from each node if top doesn't have */
+               if (!cconf->of_node)
+                       snd_soc_of_parse_node_prefix(node, cconf,
+                                                    dai_link->codecs->of_node,
+                                                    PREFIX "prefix");
        }
 
-       ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
+       asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
+
+       ret = asoc_simple_card_of_parse_tdm(ep, dai);
        if (ret)
                return ret;
 
@@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
        if (ret < 0)
                return ret;
 
-       dai_link->dai_fmt               = daifmt;
+       ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+                                           NULL, &dai_link->dai_fmt);
+       if (ret < 0)
+               return ret;
+
        dai_link->dpcm_playback         = 1;
        dai_link->dpcm_capture          = 1;
        dai_link->ops                   = &asoc_graph_card_ops;
@@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        struct device_node *cpu_port;
        struct device_node *cpu_ep;
        struct device_node *codec_ep;
-       struct device_node *rcpu_ep;
        struct device_node *codec_port;
        struct device_node *codec_port_old;
-       unsigned int daifmt = 0;
-       int dai_idx, ret;
+       int dai_idx, link_idx, conf_idx, ret;
        int rc, codec;
 
        if (!node)
@@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
         * see simple-card
         */
 
-       ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
+       ret = asoc_simple_card_of_parse_routing(card, NULL);
        if (ret < 0)
                return ret;
 
-       asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
+       asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata);
 
        /*
         * it supports multi CPU, single CODEC only here
         * see asoc_graph_get_dais_count
         */
 
-       /* find 1st codec */
-       of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
-               cpu_port = it.node;
-               cpu_ep   = of_get_next_child(cpu_port, NULL);
-               codec_ep = of_graph_get_remote_endpoint(cpu_ep);
-               rcpu_ep  = of_graph_get_remote_endpoint(codec_ep);
-
-               of_node_put(cpu_ep);
-               of_node_put(codec_ep);
-               of_node_put(rcpu_ep);
-
-               if (!codec_ep)
-                       continue;
-
-               if (rcpu_ep != cpu_ep) {
-                       dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
-                               cpu_ep->name, codec_ep->name, rcpu_ep->name);
-                       ret = -EINVAL;
-                       goto parse_of_err;
-               }
-
-               ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
-                                                           NULL, &daifmt);
-               if (ret < 0) {
-                       of_node_put(cpu_port);
-                       goto parse_of_err;
-               }
-       }
-
+       link_idx = 0;
        dai_idx = 0;
+       conf_idx = 0;
        codec_port_old = NULL;
        for (codec = 0; codec < 2; codec++) {
                /*
@@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
 
                        of_node_put(cpu_ep);
                        of_node_put(codec_ep);
+                       of_node_put(cpu_port);
                        of_node_put(codec_port);
+                       it.node = NULL;
 
                        if (codec) {
-                               if (!codec_port)
-                                       continue;
-
                                if (codec_port_old == codec_port)
                                        continue;
 
                                codec_port_old = codec_port;
-
-                               /* Back-End (= Codec) */
-                               ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
-                               if (ret < 0) {
-                                       of_node_put(cpu_port);
-                                       goto parse_of_err;
-                               }
-                       } else {
-                               /* Front-End (= CPU) */
-                               ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
-                               if (ret < 0) {
-                                       of_node_put(cpu_port);
-                                       goto parse_of_err;
-                               }
                        }
+
+                       ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep,
+                                                         priv, &dai_idx,
+                                                         link_idx++, &conf_idx,
+                                                         !codec);
+                       if (ret < 0)
+                               goto parse_of_err;
                }
        }
 
@@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
        if (ret)
                goto parse_of_err;
 
+       if ((card->num_links   != link_idx) ||
+           (card->num_configs != conf_idx)) {
+               dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n",
+                       card->num_links, link_idx, card->num_configs, conf_idx);
+               ret = -EINVAL;
+               goto parse_of_err;
+       }
+
        ret = 0;
 
 parse_of_err:
        return ret;
 }
 
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+                                     int *link_num,
+                                     int *dais_num,
+                                     int *ccnf_num)
 {
        struct of_phandle_iterator it;
        struct device_node *node = dev->of_node;
@@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev)
        struct device_node *codec_ep;
        struct device_node *codec_port;
        struct device_node *codec_port_old;
-       int count = 0;
+       struct device_node *codec_port_old2;
        int rc;
 
+       /*
+        * link_num :   number of links.
+        *              CPU-Codec / CPU-dummy / dummy-Codec
+        * dais_num :   number of DAIs
+        * ccnf_num :   number of codec_conf
+        *              same number for dummy-Codec
+        *
+        * ex1)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 7
+        * CPU2 -/              ccnf : 1
+        * CPU3 --- Codec2
+        *
+        *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+        *      => 7 DAIs  = 4xCPU + 3xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex2)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 6
+        * CPU2 -/              ccnf : 1
+        * CPU3 -/
+        *
+        *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex3)
+        * CPU0 --- Codec0      link : 6
+        * CPU1 -/              dais : 6
+        * CPU2 --- Codec1      ccnf : 2
+        * CPU3 -/
+        *
+        *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 2 ccnf  = 2xdummy-Codec
+        */
        codec_port_old = NULL;
+       codec_port_old2 = NULL;
        of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
                cpu_port = it.node;
                cpu_ep   = of_get_next_child(cpu_port, NULL);
@@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
                of_node_put(codec_ep);
                of_node_put(codec_port);
 
-               if (cpu_ep)
-                       count++;
+               (*link_num)++;
+               (*dais_num)++;
 
-               if (!codec_port)
-                       continue;
+               if (codec_port_old == codec_port) {
+                       if (codec_port_old2 != codec_port_old) {
+                               (*link_num)++;
+                               (*ccnf_num)++;
+                       }
 
-               if (codec_port_old == codec_port)
+                       codec_port_old2 = codec_port_old;
                        continue;
+               }
 
-               count++;
+               (*dais_num)++;
                codec_port_old = codec_port;
        }
-
-       return count;
 }
 
 static int asoc_graph_card_probe(struct platform_device *pdev)
@@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
        struct graph_card_data *priv;
        struct snd_soc_dai_link *dai_link;
        struct graph_dai_props *dai_props;
+       struct asoc_simple_dai *dais;
        struct device *dev = &pdev->dev;
        struct snd_soc_card *card;
-       int num, ret, i;
+       struct snd_soc_codec_conf *cconf;
+       int lnum = 0, dnum = 0, cnum = 0;
+       int ret, i;
 
        /* Allocate the private data and the DAI link array */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       num = asoc_graph_get_dais_count(dev);
-       if (num == 0)
+       asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+       if (!lnum || !dnum)
                return -EINVAL;
 
-       dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
-       dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
-       if (!dai_props || !dai_link)
+       dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+       dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link),  GFP_KERNEL);
+       dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
+       cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
+       if (!dai_props || !dai_link || !dais)
                return -ENOMEM;
 
        /*
@@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
         * see
         *      soc-core.c :: snd_soc_init_multicodec()
         */
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < lnum; i++) {
                dai_link[i].codecs      = &dai_props[i].codecs;
                dai_link[i].num_codecs  = 1;
                dai_link[i].platform    = &dai_props[i].platform;
@@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
 
        priv->dai_props                 = dai_props;
        priv->dai_link                  = dai_link;
+       priv->dais                      = dais;
+       priv->codec_conf                = cconf;
 
        /* Init snd_soc_card */
        card = graph_priv_to_card(priv);
        card->owner             = THIS_MODULE;
        card->dev               = dev;
        card->dai_link          = priv->dai_link;
-       card->num_links         = num;
-       card->codec_conf        = &priv->codec_conf;
-       card->num_configs       = 1;
+       card->num_links         = lnum;
+       card->codec_conf        = cconf;
+       card->num_configs       = cnum;
 
        ret = asoc_graph_card_parse_of(priv);
        if (ret < 0) {
index f34cc6cddfa283d79051b832dad2ca8e4de39706..b807a47515ebc85b3b37dc14ccc11911d8b4bf3f 100644 (file)
@@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
 
-void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+void asoc_simple_card_parse_convert(struct device *dev,
+                                   struct device_node *np,
+                                   char *prefix,
                                    struct asoc_simple_card_data *data)
 {
-       struct device_node *np = dev->of_node;
        char prop[128];
 
        if (!prefix)
@@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
 
-static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
-                                         struct clk *clk)
-{
-       dai->clk = clk;
-}
-
 int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
 {
-       return clk_prepare_enable(dai->clk);
+       if (dai)
+               return clk_prepare_enable(dai->clk);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
 
 void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
 {
-       clk_disable_unprepare(dai->clk);
+       if (dai)
+               clk_disable_unprepare(dai->clk);
 }
 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
 
@@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
        if (!IS_ERR(clk)) {
                simple_dai->sysclk = clk_get_rate(clk);
 
-               asoc_simple_card_clk_register(simple_dai, clk);
+               simple_dai->clk = clk;
        } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
                simple_dai->sysclk = val;
        } else {
@@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
 {
        struct device_node *node;
        struct device_node *endpoint;
+       struct of_endpoint info;
        int i, id;
        int ret;
 
+       /* use driver specified DAI ID if exist */
        ret = snd_soc_get_dai_id(ep);
        if (ret != -ENOTSUPP)
                return ret;
 
+       /* use endpoint/port reg if exist */
+       ret = of_graph_parse_endpoint(ep, &info);
+       if (ret == 0) {
+               if (info.id)
+                       return info.id;
+               if (info.port)
+                       return info.port;
+       }
+
        node = of_graph_get_port_parent(ep);
 
        /*
@@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
 {
        int ret;
 
+       if (!simple_dai)
+               return 0;
+
        if (simple_dai->sysclk) {
                ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
                                             simple_dai->clk_direction);
@@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
 
 int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
-                                     char *prefix,
-                                     int optional)
+                                     char *prefix)
 {
        struct device_node *node = card->dev->of_node;
        char prop[128];
@@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
 
        snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
 
-       if (!of_property_read_bool(node, prop)) {
-               if (optional)
-                       return 0;
-               return -EINVAL;
-       }
+       if (!of_property_read_bool(node, prop))
+               return 0;
 
        return snd_soc_of_parse_audio_routing(card, prop);
 }
index 5a3f59aa4ba55c463e4ccd0de9424d265955aea6..37e001cf9cd1dc5f09c019b63e1719d061a36cd1 100644 (file)
 struct simple_card_data {
        struct snd_soc_card snd_card;
        struct simple_dai_props {
-               struct asoc_simple_dai cpu_dai;
-               struct asoc_simple_dai codec_dai;
+               struct asoc_simple_dai *cpu_dai;
+               struct asoc_simple_dai *codec_dai;
                struct snd_soc_dai_link_component codecs; /* single codec */
                struct snd_soc_dai_link_component platform;
+               struct asoc_simple_card_data adata;
+               struct snd_soc_codec_conf *codec_conf;
                unsigned int mclk_fs;
        } *dai_props;
-       unsigned int mclk_fs;
        struct asoc_simple_jack hp_jack;
        struct asoc_simple_jack mic_jack;
        struct snd_soc_dai_link *dai_link;
+       struct asoc_simple_dai *dais;
+       struct snd_soc_codec_conf *codec_conf;
 };
 
 #define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
                simple_priv_to_props(priv, rtd->num);
        int ret;
 
-       ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+       ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
        if (ret)
                return ret;
 
-       ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+       ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
        if (ret)
-               asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+               asoc_simple_card_clk_disable(dai_props->cpu_dai);
 
        return ret;
 }
@@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        struct simple_dai_props *dai_props =
                simple_priv_to_props(priv, rtd->num);
 
-       asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+       asoc_simple_card_clk_disable(dai_props->cpu_dai);
 
-       asoc_simple_card_clk_disable(&dai_props->codec_dai);
+       asoc_simple_card_clk_disable(dai_props->codec_dai);
 }
 
 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
                                    unsigned long rate)
 {
+       if (!simple_dai)
+               return 0;
+
        if (!simple_dai->clk)
                return 0;
 
@@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
        unsigned int mclk, mclk_fs = 0;
        int ret = 0;
 
-       if (priv->mclk_fs)
-               mclk_fs = priv->mclk_fs;
-       else if (dai_props->mclk_fs)
+       if (dai_props->mclk_fs)
                mclk_fs = dai_props->mclk_fs;
 
        if (mclk_fs) {
                mclk = params_rate(params) * mclk_fs;
 
-               ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
+               ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
                if (ret < 0)
                        return ret;
 
-               ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
+               ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
                if (ret < 0)
                        return ret;
 
@@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *codec = rtd->codec_dai;
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       struct simple_dai_props *dai_props =
-               simple_priv_to_props(priv, rtd->num);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
        int ret;
 
-       ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+       ret = asoc_simple_card_init_dai(rtd->codec_dai,
+                                       dai_props->codec_dai);
        if (ret < 0)
                return ret;
 
-       ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+       ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+                                       dai_props->cpu_dai);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int asoc_simple_card_dai_link_of(struct device_node *node,
+static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                              struct snd_pcm_hw_params *params)
+{
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+       asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+       return 0;
+}
+
+static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
+                                            struct device_node *node,
+                                            struct device_node *np,
+                                            struct device_node *codec,
+                                            struct simple_card_data *priv,
+                                            int *dai_idx, int link_idx,
+                                            int *conf_idx, int is_fe,
+                                            bool is_top_level_node)
+{
+       struct device *dev = simple_priv_to_dev(priv);
+       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+       struct asoc_simple_dai *dai;
+       struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+
+       char prop[128];
+       char *prefix = "";
+       int ret;
+
+       /* For single DAI link & old style of DT node */
+       if (is_top_level_node)
+               prefix = PREFIX;
+
+       if (is_fe) {
+               int is_single_links = 0;
+
+               /* BE is dummy */
+               codecs->of_node         = NULL;
+               codecs->dai_name        = "snd-soc-dummy-dai";
+               codecs->name            = "snd-soc-dummy";
+
+               /* FE settings */
+               dai_link->dynamic               = 1;
+               dai_link->dpcm_merged_format    = 1;
+
+               dai =
+               dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+
+               ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
+                                                &is_single_links);
+               if (ret)
+                       return ret;
+
+               ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+                                                       "fe.%s",
+                                                       dai_link->cpu_dai_name);
+               if (ret < 0)
+                       return ret;
+
+               asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
+       } else {
+               struct snd_soc_codec_conf *cconf;
+
+               /* FE is dummy */
+               dai_link->cpu_of_node           = NULL;
+               dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
+               dai_link->cpu_name              = "snd-soc-dummy";
+
+               /* BE settings */
+               dai_link->no_pcm                = 1;
+               dai_link->be_hw_params_fixup    = asoc_simple_card_be_hw_params_fixup;
+
+               dai =
+               dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
+
+               cconf =
+               dai_props->codec_conf   = &priv->codec_conf[(*conf_idx)++];
+
+               ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
+               if (ret < 0)
+                       return ret;
+
+               ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+                                                       "be.%s",
+                                                       codecs->dai_name);
+               if (ret < 0)
+                       return ret;
+
+               /* check "prefix" from top node */
+               snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+                                             PREFIX "prefix");
+               snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+                                            "prefix");
+               snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
+                                            "prefix");
+       }
+
+       asoc_simple_card_parse_convert(dev, top,  PREFIX, &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
+       asoc_simple_card_parse_convert(dev, np,   NULL,   &dai_props->adata);
+
+       ret = asoc_simple_card_of_parse_tdm(np, dai);
+       if (ret)
+               return ret;
+
+       ret = asoc_simple_card_canonicalize_dailink(dai_link);
+       if (ret < 0)
+               return ret;
+
+       snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+       of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(node, prop, &dai_props->mclk_fs);
+       of_property_read_u32(np,   prop, &dai_props->mclk_fs);
+
+       ret = asoc_simple_card_parse_daifmt(dev, node, codec,
+                                           prefix, &dai_link->dai_fmt);
+       if (ret < 0)
+               return ret;
+
+       dai_link->dpcm_playback         = 1;
+       dai_link->dpcm_capture          = 1;
+       dai_link->ops                   = &asoc_simple_card_ops;
+       dai_link->init                  = asoc_simple_card_dai_init;
+
+       return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *top,
+                                       struct device_node *node,
                                        struct simple_card_data *priv,
-                                       int idx,
+                                       int *dai_idx, int link_idx,
                                        bool is_top_level_node)
 {
        struct device *dev = simple_priv_to_dev(priv);
-       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
-       struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
-       struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
-       struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+       struct asoc_simple_dai *cpu_dai;
+       struct asoc_simple_dai *codec_dai;
        struct device_node *cpu = NULL;
        struct device_node *plat = NULL;
        struct device_node *codec = NULL;
@@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
                goto dai_link_of_err;
        }
 
+       cpu_dai                 =
+       dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+       codec_dai               =
+       dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
+
        ret = asoc_simple_card_parse_daifmt(dev, node, codec,
                                            prefix, &dai_link->dai_fmt);
        if (ret < 0)
                goto dai_link_of_err;
 
-       of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
+       snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+       of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
+       of_property_read_u32(node,  prop, &dai_props->mclk_fs);
+       of_property_read_u32(cpu,   prop, &dai_props->mclk_fs);
+       of_property_read_u32(codec, prop, &dai_props->mclk_fs);
 
        ret = asoc_simple_card_parse_cpu(cpu, dai_link,
                                         DAI, CELL, &single_cpu);
@@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
 static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 {
        struct device *dev = simple_priv_to_dev(priv);
+       struct device_node *top = dev->of_node;
        struct snd_soc_card *card = simple_priv_to_card(priv);
-       struct device_node *dai_link;
-       struct device_node *node = dev->of_node;
-       int ret;
-
-       if (!node)
+       struct device_node *node;
+       struct device_node *np;
+       struct device_node *codec;
+       bool is_fe;
+       int ret, loop;
+       int dai_idx, link_idx, conf_idx;
+
+       if (!top)
                return -EINVAL;
 
-       dai_link = of_get_child_by_name(node, PREFIX "dai-link");
-
        ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
        if (ret < 0)
-               goto card_parse_end;
+               return ret;
 
-       ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
+       ret = asoc_simple_card_of_parse_routing(card, PREFIX);
        if (ret < 0)
-               goto card_parse_end;
-
-       /* Factor to mclk, used in hw_params() */
-       of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
+               return ret;
 
        /* Single/Muti DAI link(s) & New style of DT node */
-       if (dai_link) {
-               struct device_node *np = NULL;
-               int i = 0;
-
-               for_each_child_of_node(node, np) {
-                       dev_dbg(dev, "\tlink %d:\n", i);
-                       ret = asoc_simple_card_dai_link_of(np, priv,
-                                                          i, false);
-                       if (ret < 0) {
-                               of_node_put(np);
-                               goto card_parse_end;
+       loop            = 1;
+       link_idx        = 0;
+       dai_idx         = 0;
+       conf_idx        = 0;
+       node = of_get_child_by_name(top, PREFIX "dai-link");
+       if (!node) {
+               node = dev->of_node;
+               loop = 0;
+       }
+
+       do  {
+               /* DPCM */
+               if (of_get_child_count(node) > 2) {
+                       for_each_child_of_node(node, np) {
+                               codec = of_get_child_by_name(node,
+                                                       loop ?  "codec" :
+                                                               PREFIX "codec");
+                               if (!codec)
+                                       return -ENODEV;
+
+                               is_fe = (np != codec);
+
+                               ret = asoc_simple_card_dai_link_of_dpcm(
+                                               top, node, np, codec, priv,
+                                               &dai_idx, link_idx++, &conf_idx,
+                                               is_fe, !loop);
                        }
-                       i++;
+               } else {
+                       ret = asoc_simple_card_dai_link_of(
+                                               top, node, priv,
+                                               &dai_idx, link_idx++, !loop);
                }
-       } else {
-               /* For single DAI link & old style of DT node */
-               ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
                if (ret < 0)
-                       goto card_parse_end;
-       }
+                       return ret;
+
+               node = of_get_next_child(top, node);
+       } while (loop && node);
 
        ret = asoc_simple_card_parse_card_name(card, PREFIX);
        if (ret < 0)
-               goto card_parse_end;
-
-       ret = asoc_simple_card_parse_aux_devs(node, priv);
+               return ret;
 
-card_parse_end:
-       of_node_put(dai_link);
+       ret = asoc_simple_card_parse_aux_devs(top, priv);
 
        return ret;
 }
 
+static void asoc_simple_card_get_dais_count(struct device *dev,
+                                           int *link_num,
+                                           int *dais_num,
+                                           int *ccnf_num)
+{
+       struct device_node *top = dev->of_node;
+       struct device_node *node;
+       int loop;
+       int num;
+
+       /*
+        * link_num :   number of links.
+        *              CPU-Codec / CPU-dummy / dummy-Codec
+        * dais_num :   number of DAIs
+        * ccnf_num :   number of codec_conf
+        *              same number for "dummy-Codec"
+        *
+        * ex1)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 7
+        * CPU2 -/              ccnf : 1
+        * CPU3 --- Codec2
+        *
+        *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+        *      => 7 DAIs  = 4xCPU + 3xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex2)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 6
+        * CPU2 -/              ccnf : 1
+        * CPU3 -/
+        *
+        *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex3)
+        * CPU0 --- Codec0      link : 6
+        * CPU1 -/              dais : 6
+        * CPU2 --- Codec1      ccnf : 2
+        * CPU3 -/
+        *
+        *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 2 ccnf  = 2xdummy-Codec
+        */
+       if (!top) {
+               (*link_num) = 1;
+               (*dais_num) = 2;
+               (*ccnf_num) = 0;
+               return;
+       }
+
+       loop = 1;
+       node = of_get_child_by_name(top, PREFIX "dai-link");
+       if (!node) {
+               node = top;
+               loop = 0;
+       }
+
+       do {
+               num = of_get_child_count(node);
+               (*dais_num) += num;
+               if (num > 2) {
+                       (*link_num) += num;
+                       (*ccnf_num)++;
+               } else {
+                       (*link_num)++;
+               }
+               node = of_get_next_child(top, node);
+       } while (loop && node);
+}
+
 static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
 {
        struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        struct simple_card_data *priv;
        struct snd_soc_dai_link *dai_link;
        struct simple_dai_props *dai_props;
+       struct asoc_simple_dai *dais;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct snd_soc_card *card;
-       int num, ret, i;
-
-       /* Get the number of DAI links */
-       if (np && of_get_child_by_name(np, PREFIX "dai-link"))
-               num = of_get_child_count(np);
-       else
-               num = 1;
+       struct snd_soc_codec_conf *cconf;
+       int lnum = 0, dnum = 0, cnum = 0;
+       int ret, i;
 
        /* Allocate the private data and the DAI link array */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
-       dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
-       if (!dai_props || !dai_link)
+       asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+       if (!lnum || !dnum)
+               return -EINVAL;
+
+       dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+       dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link),  GFP_KERNEL);
+       dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
+       cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
+       if (!dai_props || !dai_link || !dais)
                return -ENOMEM;
 
        /*
@@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
         * see
         *      soc-core.c :: snd_soc_init_multicodec()
         */
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < lnum; i++) {
                dai_link[i].codecs      = &dai_props[i].codecs;
                dai_link[i].num_codecs  = 1;
                dai_link[i].platform    = &dai_props[i].platform;
@@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 
        priv->dai_props                 = dai_props;
        priv->dai_link                  = dai_link;
+       priv->dais                      = dais;
+       priv->codec_conf                = cconf;
 
        /* Init snd_soc_card */
        card = simple_priv_to_card(priv);
        card->owner             = THIS_MODULE;
        card->dev               = dev;
        card->dai_link          = priv->dai_link;
-       card->num_links         = num;
+       card->num_links         = lnum;
+       card->codec_conf        = cconf;
+       card->num_configs       = cnum;
        card->probe             = asoc_simple_soc_card_probe;
 
        if (np && of_device_is_available(np)) {
@@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                struct asoc_simple_card_info *cinfo;
                struct snd_soc_dai_link_component *codecs;
                struct snd_soc_dai_link_component *platform;
+               int dai_idx = 0;
 
                cinfo = dev->platform_data;
                if (!cinfo) {
@@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                        return -EINVAL;
                }
 
+               dai_props->cpu_dai      = &priv->dais[dai_idx++];
+               dai_props->codec_dai    = &priv->dais[dai_idx++];
+
                codecs                  = dai_link->codecs;
                codecs->name            = cinfo->codec;
                codecs->dai_name        = cinfo->codec_dai.name;
@@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
                dai_link->dai_fmt       = cinfo->daifmt;
                dai_link->init          = asoc_simple_card_dai_init;
-               memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
-                                       sizeof(priv->dai_props->cpu_dai));
-               memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
-                                       sizeof(priv->dai_props->codec_dai));
+               memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+                                       sizeof(*priv->dai_props->cpu_dai));
+               memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
+                                       sizeof(*priv->dai_props->codec_dai));
        }
 
        snd_soc_card_set_drvdata(card, priv);
@@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
 
 static const struct of_device_id asoc_simple_of_match[] = {
        { .compatible = "simple-audio-card", },
+       { .compatible = "simple-scu-audio-card", },
        {},
 };
 MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
index 85b46f0eae0ff2f3172466add90314297b8624db..9d7299d536a88742e019a509fd024e63f30c48ff 100644 (file)
 
 struct simple_card_data {
        struct snd_soc_card snd_card;
-       struct snd_soc_codec_conf codec_conf;
        struct simple_dai_props {
-               struct asoc_simple_dai dai;
+               struct asoc_simple_dai *cpu_dai;
+               struct asoc_simple_dai *codec_dai;
                struct snd_soc_dai_link_component codecs;
                struct snd_soc_dai_link_component platform;
+               struct asoc_simple_card_data adata;
+               struct snd_soc_codec_conf *codec_conf;
        } *dai_props;
        struct snd_soc_dai_link *dai_link;
+       struct asoc_simple_dai *dais;
        struct asoc_simple_card_data adata;
+       struct snd_soc_codec_conf *codec_conf;
 };
 
 #define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
        struct simple_dai_props *dai_props =
                simple_priv_to_props(priv, rtd->num);
+       int ret;
+
+       ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+       if (ret)
+               return ret;
+
+       ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+       if (ret)
+               asoc_simple_card_clk_disable(dai_props->cpu_dai);
 
-       return asoc_simple_card_clk_enable(&dai_props->dai);
+       return ret;
 }
 
 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        struct simple_dai_props *dai_props =
                simple_priv_to_props(priv, rtd->num);
 
-       asoc_simple_card_clk_disable(&dai_props->dai);
+       asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+       asoc_simple_card_clk_disable(dai_props->codec_dai);
 }
 
 static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
 
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *dai;
-       struct snd_soc_dai_link *dai_link;
-       struct simple_dai_props *dai_props;
-       int num = rtd->num;
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+       int ret;
+
+       ret = asoc_simple_card_init_dai(rtd->codec_dai,
+                                       dai_props->codec_dai);
+       if (ret < 0)
+               return ret;
 
-       dai_link        = simple_priv_to_link(priv, num);
-       dai_props       = simple_priv_to_props(priv, num);
-       dai             = dai_link->dynamic ?
-                               rtd->cpu_dai :
-                               rtd->codec_dai;
+       ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+                                       dai_props->cpu_dai);
+       if (ret < 0)
+               return ret;
 
-       return asoc_simple_card_init_dai(dai, &dai_props->dai);
+       return 0;
 }
 
 static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                        struct snd_pcm_hw_params *params)
 {
        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+       asoc_simple_card_convert_fixup(&dai_props->adata, params);
 
+       /* overwrite by top level adata if exist */
        asoc_simple_card_convert_fixup(&priv->adata, params);
 
        return 0;
 }
 
-static int asoc_simple_card_dai_link_of(struct device_node *np,
+static int asoc_simple_card_dai_link_of(struct device_node *link,
+                                       struct device_node *np,
+                                       struct device_node *codec,
                                        struct simple_card_data *priv,
-                                       unsigned int daifmt,
-                                       int idx, bool is_fe)
+                                       int *dai_idx, int link_idx,
+                                       int *conf_idx, int is_fe,
+                                       bool is_top_level_node)
 {
        struct device *dev = simple_priv_to_dev(priv);
-       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
-       struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
        struct snd_soc_card *card = simple_priv_to_card(priv);
+       struct asoc_simple_dai *dai;
+       char *prefix = "";
        int ret;
 
+       /* For single DAI link & old style of DT node */
+       if (is_top_level_node)
+               prefix = PREFIX;
+
        if (is_fe) {
                int is_single_links = 0;
                struct snd_soc_dai_link_component *codecs;
@@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
                dai_link->dynamic               = 1;
                dai_link->dpcm_merged_format    = 1;
 
+               dai =
+               dai_props->cpu_dai      = &priv->dais[(*dai_idx)++];
+
                ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
                                                 &is_single_links);
                if (ret)
                        return ret;
 
-               ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
+               ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
                if (ret < 0)
                        return ret;
 
@@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
 
                asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
        } else {
+               struct snd_soc_codec_conf *cconf;
+
                /* FE is dummy */
                dai_link->cpu_of_node           = NULL;
                dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
@@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
                dai_link->no_pcm                = 1;
                dai_link->be_hw_params_fixup    = asoc_simple_card_be_hw_params_fixup;
 
+               dai =
+               dai_props->codec_dai    = &priv->dais[(*dai_idx)++];
+
+               cconf =
+               dai_props->codec_conf   = &priv->codec_conf[(*conf_idx)++];
+
                ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
                if (ret < 0)
                        return ret;
 
-               ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
+               ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
                if (ret < 0)
                        return ret;
 
@@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
                if (ret < 0)
                        return ret;
 
-               snd_soc_of_parse_audio_prefix(card,
-                                             &priv->codec_conf,
+               /* check "prefix" from top node */
+               snd_soc_of_parse_audio_prefix(card, cconf,
                                              dai_link->codecs->of_node,
                                              PREFIX "prefix");
+               /* check "prefix" from each node if top doesn't have */
+               if (!cconf->of_node)
+                       snd_soc_of_parse_node_prefix(np, cconf,
+                                                    dai_link->codecs->of_node,
+                                                    "prefix");
        }
 
-       ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
+       asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
+
+       ret = asoc_simple_card_of_parse_tdm(np, dai);
        if (ret)
                return ret;
 
@@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
        if (ret < 0)
                return ret;
 
-       dai_link->dai_fmt               = daifmt;
+       ret = asoc_simple_card_parse_daifmt(dev, link, codec,
+                                           prefix, &dai_link->dai_fmt);
+       if (ret < 0)
+               return ret;
+
        dai_link->dpcm_playback         = 1;
        dai_link->dpcm_capture          = 1;
        dai_link->ops                   = &asoc_simple_card_ops;
@@ -184,52 +236,136 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 
 {
        struct device *dev = simple_priv_to_dev(priv);
+       struct device_node *top = dev->of_node;
+       struct device_node *node;
        struct device_node *np;
+       struct device_node *codec;
        struct snd_soc_card *card = simple_priv_to_card(priv);
-       struct device_node *node = dev->of_node;
-       unsigned int daifmt = 0;
        bool is_fe;
-       int ret, i;
+       int ret, loop;
+       int dai_idx, link_idx, conf_idx;
 
-       if (!node)
+       if (!top)
                return -EINVAL;
 
        ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
        if (ret < 0)
                return ret;
 
-       ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
+       ret = asoc_simple_card_of_parse_routing(card, PREFIX);
        if (ret < 0)
                return ret;
 
-       asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
+       asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
 
-       /* find 1st codec */
-       np = of_get_child_by_name(node, PREFIX "codec");
-       if (!np)
-               return -ENODEV;
+       loop = 1;
+       link_idx = 0;
+       dai_idx = 0;
+       conf_idx = 0;
+       node = of_get_child_by_name(top, PREFIX "dai-link");
+       if (!node) {
+               node = dev->of_node;
+               loop = 0;
+       }
+
+       do  {
+               codec = of_get_child_by_name(node,
+                                            loop ? "codec" : PREFIX "codec");
+               if (!codec)
+                       return -ENODEV;
+
+               for_each_child_of_node(node, np) {
+                       is_fe = (np != codec);
+
+                       ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
+                                                          &dai_idx, link_idx++,
+                                                          &conf_idx,
+                                                          is_fe, !loop);
+                       if (ret < 0)
+                               return ret;
+               }
+               node = of_get_next_child(top, node);
+       } while (loop && node);
 
-       ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
+       ret = asoc_simple_card_parse_card_name(card, PREFIX);
        if (ret < 0)
                return ret;
 
-       i = 0;
-       for_each_child_of_node(node, np) {
-               is_fe = false;
-               if (strcmp(np->name, PREFIX "cpu") == 0)
-                       is_fe = true;
+       return 0;
+}
 
-               ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
-               if (ret < 0)
-                       return ret;
-               i++;
+static void asoc_simple_card_get_dais_count(struct device *dev,
+                                           int *link_num,
+                                           int *dais_num,
+                                           int *ccnf_num)
+{
+       struct device_node *top = dev->of_node;
+       struct device_node *node;
+       int loop;
+       int num;
+
+       /*
+        * link_num :   number of links.
+        *              CPU-Codec / CPU-dummy / dummy-Codec
+        * dais_num :   number of DAIs
+        * ccnf_num :   number of codec_conf
+        *              same number for "dummy-Codec"
+        *
+        * ex1)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 7
+        * CPU2 -/              ccnf : 1
+        * CPU3 --- Codec2
+        *
+        *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+        *      => 7 DAIs  = 4xCPU + 3xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex2)
+        * CPU0 --- Codec0      link : 5
+        * CPU1 --- Codec1      dais : 6
+        * CPU2 -/              ccnf : 1
+        * CPU3 -/
+        *
+        *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 1 ccnf  = 1xdummy-Codec
+        *
+        * ex3)
+        * CPU0 --- Codec0      link : 6
+        * CPU1 -/              dais : 6
+        * CPU2 --- Codec1      ccnf : 2
+        * CPU3 -/
+        *
+        *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+        *      => 6 DAIs  = 4xCPU + 2xCodec
+        *      => 2 ccnf  = 2xdummy-Codec
+        */
+       if (!top) {
+               (*link_num) = 1;
+               (*dais_num) = 2;
+               (*ccnf_num) = 0;
+               return;
        }
 
-       ret = asoc_simple_card_parse_card_name(card, PREFIX);
-       if (ret < 0)
-               return ret;
+       loop = 1;
+       node = of_get_child_by_name(top, PREFIX "dai-link");
+       if (!node) {
+               node = top;
+               loop = 0;
+       }
 
-       return 0;
+       do {
+               num = of_get_child_count(node);
+               (*dais_num) += num;
+               if (num > 2) {
+                       (*link_num) += num;
+                       (*ccnf_num)++;
+               } else {
+                       (*link_num)++;
+               }
+               node = of_get_next_child(top, node);
+       } while (loop && node);
 }
 
 static int asoc_simple_card_probe(struct platform_device *pdev)
@@ -237,21 +373,27 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        struct simple_card_data *priv;
        struct snd_soc_dai_link *dai_link;
        struct simple_dai_props *dai_props;
+       struct asoc_simple_dai *dais;
        struct snd_soc_card *card;
+       struct snd_soc_codec_conf *cconf;
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       int num, ret, i;
+       int ret, i;
+       int lnum = 0, dnum = 0, cnum = 0;
 
        /* Allocate the private data */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       num = of_get_child_count(np);
+       asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+       if (!lnum || !dnum)
+               return -EINVAL;
 
-       dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
-       dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
-       if (!dai_props || !dai_link)
+       dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+       dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+       dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
+       cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
+       if (!dai_props || !dai_link || !dais)
                return -ENOMEM;
 
        /*
@@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
         * see
         *      soc-core.c :: snd_soc_init_multicodec()
         */
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < lnum; i++) {
                dai_link[i].codecs      = &dai_props[i].codecs;
                dai_link[i].num_codecs  = 1;
                dai_link[i].platform    = &dai_props[i].platform;
@@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 
        priv->dai_props                         = dai_props;
        priv->dai_link                          = dai_link;
+       priv->dais                              = dais;
+       priv->codec_conf                        = cconf;
 
        /* Init snd_soc_card */
        card = simple_priv_to_card(priv);
        card->owner             = THIS_MODULE;
        card->dev               = dev;
        card->dai_link          = priv->dai_link;
-       card->num_links         = num;
-       card->codec_conf        = &priv->codec_conf;
-       card->num_configs       = 1;
+       card->num_links         = lnum;
+       card->codec_conf        = cconf;
+       card->num_configs       = cnum;
 
        ret = asoc_simple_card_parse_of(priv);
        if (ret < 0) {
index 18e71770368550f167ea32385160e853e9dd5264..2fd1b61e8331dd68d0c1ffa1d81420b6a9e71d37 100644 (file)
@@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
          recommended option
 
 config SND_SOC_INTEL_SKYLAKE
-       tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
+       tristate "All Skylake/SST Platforms"
        depends on PCI && ACPI
-       select SND_SOC_INTEL_SKYLAKE_COMMON
+       select SND_SOC_INTEL_SKL
+       select SND_SOC_INTEL_APL
+       select SND_SOC_INTEL_KBL
+       select SND_SOC_INTEL_GLK
+       select SND_SOC_INTEL_CNL
+       select SND_SOC_INTEL_CFL
        help
-         If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
-         GeminiLake or CannonLake platform with the DSP enabled in the BIOS
-         then enable this option by saying Y or m.
+          This is a backwards-compatible option to select all devices
+         supported by the Intel SST/Skylake driver. This option is no
+         longer recommended and will be deprecated when the SOF
+         driver is introduced.  Distributions should explicitly
+         select which platform uses this driver.
+
+config SND_SOC_INTEL_SKL
+       tristate "Skylake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel Skylake platform with the DSP enabled
+         in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_APL
+       tristate "Broxton/ApolloLake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel Broxton/ApolloLake platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_KBL
+       tristate "Kabylake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel Kabylake platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_GLK
+       tristate "GeminiLake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel GeminiLake platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CNL
+       tristate "CannonLake/WhiskyLake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel CNL/WHL platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CFL
+       tristate "CoffeeLake Platforms"
+       depends on PCI && ACPI
+       select SND_SOC_INTEL_SKYLAKE_FAMILY
+       help
+         If you have a Intel CoffeeLake platform with the DSP
+         enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_SKYLAKE_FAMILY
+       tristate
+       select SND_SOC_INTEL_SKYLAKE_COMMON
 
-if  SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKYLAKE_FAMILY
 
 config SND_SOC_INTEL_SKYLAKE_SSP_CLK
        tristate
@@ -129,13 +188,19 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
        select SND_SOC_TOPOLOGY
        select SND_SOC_INTEL_SST
        select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
+       select SND_HDA_INTEL_DSP_DETECTION_SKL if SND_SOC_INTEL_SKL
+       select SND_HDA_INTEL_DSP_DETECTION_APL if SND_SOC_INTEL_APL
+       select SND_HDA_INTEL_DSP_DETECTION_KBL if SND_SOC_INTEL_KBL
+       select SND_HDA_INTEL_DSP_DETECTION_GLK if SND_SOC_INTEL_GLK
+       select SND_HDA_INTEL_DSP_DETECTION_CNL if SND_SOC_INTEL_CNL
+       select SND_HDA_INTEL_DSP_DETECTION_CFL if SND_SOC_INTEL_CFL
        select SND_SOC_ACPI_INTEL_MATCH
        help
          If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
          GeminiLake or CannonLake platform with the DSP enabled in the BIOS
          then enable this option by saying Y or m.
 
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
 
 config SND_SOC_ACPI_INTEL_MATCH
        tristate
index c90b04cc071dc230391746628c40bc9541d07f95..ac542535b9d53fb036151e35da1e9aee063e7793 100644 (file)
@@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev)
                byt_rvp_platform_data.res_info = &bytcr_res_info;
        }
 
+       /* update machine parameters */
+       mach->mach_params.acpi_ipc_irq_index =
+               pdata->res_info->acpi_ipc_irq_index;
+
        plat_dev = platform_device_register_data(dev, pdata->platform, -1,
                                                NULL, 0);
        if (IS_ERR(plat_dev)) {
index 27413ebae9566eb356abbd44ec4bb62b9e5cdc90..b8c456753f015ff66557447a15ee196536641df2 100644 (file)
@@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst)
        const struct firmware *fw;
 
        retval = request_firmware(&fw, sst->firmware_name, sst->dev);
-       if (fw == NULL) {
-               dev_err(sst->dev, "fw is returning as null\n");
-               return -EINVAL;
-       }
        if (retval) {
                dev_err(sst->dev, "request fw failed %d\n", retval);
                return retval;
        }
+       if (fw == NULL) {
+               dev_err(sst->dev, "fw is returning as null\n");
+               return -EINVAL;
+       }
        mutex_lock(&sst->sst_lock);
        retval = sst_cache_and_parse_fw(sst, fw);
        mutex_unlock(&sst->sst_lock);
index af93244b48686f48ac08f8f8e55269911545b8ed..00a37a09dc9b0fa46166c309655eb004cf896fff 100644 (file)
@@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
 {
        struct ipc_post *msg;
 
-       msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
        if (large) {
-               msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+               msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
                if (!msg->mailbox_data) {
                        kfree(msg);
                        return -ENOMEM;
index b177db2a0dbb2ada825849e5e8d85d952a67d1b2..0a7e40d0639572b25c563dd65357e34538999d7e 100644 (file)
@@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
 
 endif ## SND_SST_ATOM_HIFI2_PLATFORM
 
-if SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKL
 
 config SND_SOC_INTEL_SKL_RT286_MACH
        tristate "SKL with RT286 I2S mode"
@@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
          Say Y or m if you have such a device. This is a recommended option.
          If unsure select "N".
 
+endif ## SND_SOC_INTEL_SKL
+
+if SND_SOC_INTEL_APL
+
 config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
        tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
        depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH
           Say Y or m if you have such a device. This is a recommended option.
           If unsure select "N".
 
+endif ## SND_SOC_INTEL_APL
+
+if SND_SOC_INTEL_KBL
+
 config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
        tristate "KBL with RT5663 and MAX98927 in I2S Mode"
        depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
          Say Y if you have such a device.
          If unsure select "N".
 
+config SND_SOC_INTEL_KBL_RT5660_MACH
+       tristate "KBL with RT5660 in I2S Mode"
+       depends on MFD_INTEL_LPSS && I2C && ACPI
+       select SND_SOC_RT5660
+       select SND_SOC_HDAC_HDMI
+       help
+         This adds support for ASoC Onboard Codec I2S machine driver. This will
+         create an alsa sound card for RT5660 I2S audio codec.
+         Say Y if you have such a device.
+
+endif ## SND_SOC_INTEL_KBL
+
+if SND_SOC_INTEL_GLK
+
 config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
        tristate "GLK with RT5682 and MAX98357A in I2S Mode"
        depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
           Say Y if you have such a device.
           If unsure select "N".
 
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_GLK
 
 if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
 
index 5381e27df9cc76ad5b0da3ac9f660d671dd9ecaa..bf072ea299b709ecf1d696b558e572341a0a45c3 100644 (file)
@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
 snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
 snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
 snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
+snd-soc-kbl_rt5660-objs := kbl_rt5660.o
 snd-soc-skl_rt286-objs := skl_rt286.o
 snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
 snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9
 obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
index 8587bd3d1cc17df7d65b7bd37388d1f5ae833c3a..a22366ce33c40389694b42b96f937f516c425a87 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/input.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF2 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Point of View Mobii TAB-P1005W-232 (V2.0) */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
+       {
+               /* Prowise PT301 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Prowise"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "PT301"),
+               },
+               .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+                                       BYT_RT5640_JD_SRC_JD2_IN4N |
+                                       BYT_RT5640_OVCD_TH_2000UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_DIFF_MIC |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
@@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
         * (will be overridden if DMI quirk is detected)
         */
        if (is_valleyview()) {
-               struct sst_platform_info *p_info = mach->pdata;
-               const struct sst_res_info *res_info = p_info->res_info;
-
-               if (res_info->acpi_ipc_irq_index == 0)
+               if (mach->mach_params.acpi_ipc_irq_index == 0)
                        is_bytcr = true;
        }
 
index c442981307208c3ea887c81adf1c9cd4bbbc8800..e528995668b78e6441b1494967dcb51542b112e3 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
-#include <asm/platform_sst_audio.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
         * (will be overridden if DMI quirk is detected)
         */
        if (x86_match_cpu(baytrail_cpu_ids)) {
-               struct sst_platform_info *p_info = mach->pdata;
-               const struct sst_res_info *res_info = p_info->res_info;
-
-               if (res_info->acpi_ipc_irq_index == 0)
+               if (mach->mach_params.acpi_ipc_irq_index == 0)
                        is_bytcr = true;
        }
 
index 9d9f6e41d81c079796cb7bec6d9422bd6cbb5c67..08a5152e635ac8b8c38ae9214173c66cd8bae445 100644 (file)
@@ -389,6 +389,20 @@ static struct snd_soc_card snd_soc_card_cht = {
 };
 
 static const struct dmi_system_id cht_max98090_quirk_table[] = {
+       {
+               /* Clapper model Chromebook */
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"),
+               },
+               .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
+       },
+       {
+               /* Gnawty model Chromebook (Acer Chromebook CB3-111) */
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"),
+               },
+               .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
+       },
        {
                /* Swanky model Chromebook (Toshiba Chromebook 2) */
                .matches = {
index f5a5ea6a093c7112cee4c9dc5ed160be518d6062..250a356a0cbf0867d05bf90ff4e822d746a1395c 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/dmi.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
         * (will be overridden if DMI quirk is detected)
         */
        if (is_valleyview()) {
-               struct sst_platform_info *p_info = mach->pdata;
-               const struct sst_res_info *res_info = p_info->res_info;
-
-               if (res_info->acpi_ipc_irq_index == 0)
+               if (mach->mach_params.acpi_ipc_irq_index == 0)
                        is_bytcr = true;
        }
 
index 51f0d45d6f8f9d7d4d0b5abdb9239fda3fb00071..9de64f447e7bed94cbbaf0d788f5bcbcc0c76743 100644 (file)
@@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        const char *i2c_name;
        int i;
 
-       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
        if (!drv)
                return -ENOMEM;
 
index c4b94e2617c59b00a606f69baf8c5a2471c93d90..c74c4f17316fe898ff29e16a2be4982499d7f612 100644 (file)
@@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev)
 {
        struct glk_card_private *ctx;
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
index 3fa1c3ca6d376f7ace55bca0c5b4331802c6642a..723a4935ed76ed287f93e4f21605fb8b325c6ab6 100644 (file)
@@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
 
        jack = &ctx->kabylake_headset;
        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
        da7219_aad_jack_det(component, &ctx->kabylake_headset);
 
@@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
 }
 
 
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
        .startup = kabylake_refcap_startup,
 };
 
@@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .dpcm_capture = 1,
                .nonatomic = 1,
                .dynamic = 1,
-               .ops = &skylaye_refcap_ops,
+               .ops = &skylake_refcap_ops,
        },
        [KBL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Kbl Audio DMIC cap",
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = {
                .dpcm_capture = 1,
                .nonatomic = 1,
                .dynamic = 1,
-               .ops = &skylaye_refcap_ops,
+               .ops = &skylake_refcap_ops,
        },
        [KBL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Kbl Audio DMIC cap",
@@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
 {
        struct kbl_codec_private *ctx;
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
new file mode 100644 (file)
index 0000000..3255e00
--- /dev/null
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018-19 Canonical Corporation.
+
+/*
+ * Intel Kabylake I2S Machine Driver with RT5660 Codec
+ *
+ * Modified from:
+ *   Intel Kabylake I2S Machine driver supporting MAXIM98357a and
+ *   DA7219 codecs
+ * Also referred to:
+ *   Intel Broadwell I2S Machine driver supporting RT5677 codec
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/hdac_hdmi.h"
+#include "../../codecs/rt5660.h"
+
+#define KBL_RT5660_CODEC_DAI "rt5660-aif1"
+#define DUAL_CHANNEL 2
+
+static struct snd_soc_card *kabylake_audio_card;
+static struct snd_soc_jack skylake_hdmi[3];
+static struct snd_soc_jack lineout_jack;
+static struct snd_soc_jack mic_jack;
+
+struct kbl_hdmi_pcm {
+       struct list_head head;
+       struct snd_soc_dai *codec_dai;
+       int device;
+};
+
+struct kbl_codec_private {
+       struct gpio_desc *gpio_lo_mute;
+       struct list_head hdmi_pcm_list;
+};
+
+enum {
+       KBL_DPCM_AUDIO_PB = 0,
+       KBL_DPCM_AUDIO_CP,
+       KBL_DPCM_AUDIO_HDMI1_PB,
+       KBL_DPCM_AUDIO_HDMI2_PB,
+       KBL_DPCM_AUDIO_HDMI3_PB,
+};
+
+#define GPIO_LINEOUT_MUTE_INDEX 0
+#define GPIO_LINEOUT_DET_INDEX 3
+#define GPIO_LINEIN_DET_INDEX 4
+
+static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true };
+static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false };
+static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false };
+
+
+static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = {
+       { "lineout-mute-gpios", &lineout_mute_gpio, 1 },
+       { "lineout-det-gpios", &lineout_det_gpio, 1 },
+       { "mic-det-gpios", &mic_det_gpio, 1 },
+       { NULL },
+};
+
+static struct snd_soc_jack_pin lineout_jack_pin = {
+       .pin    = "Line Out",
+       .mask   = SND_JACK_LINEOUT,
+};
+
+static struct snd_soc_jack_pin mic_jack_pin = {
+       .pin    = "Line In",
+       .mask   = SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio lineout_jack_gpio = {
+       .name                   = "lineout-det",
+       .report                 = SND_JACK_LINEOUT,
+       .debounce_time          = 200,
+};
+
+static struct snd_soc_jack_gpio mic_jack_gpio = {
+       .name                   = "mic-det",
+       .report                 = SND_JACK_MICROPHONE,
+       .debounce_time          = 200,
+};
+
+static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card);
+
+       gpiod_set_value_cansleep(priv->gpio_lo_mute,
+                       !(SND_SOC_DAPM_EVENT_ON(event)));
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new kabylake_rt5660_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Line In"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = {
+       SND_SOC_DAPM_MIC("Line In", NULL),
+       SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout),
+};
+
+static const struct snd_soc_dapm_route kabylake_rt5660_map[] = {
+       /* other jacks */
+       {"IN1P", NULL, "Line In"},
+       {"IN2P", NULL, "Line In"},
+       {"Line Out", NULL, "LOUTR"},
+       {"Line Out", NULL, "LOUTL"},
+
+       /* CODEC BE connections */
+       { "AIF1 Playback", NULL, "ssp0 Tx"},
+       { "ssp0 Tx", NULL, "codec0_out"},
+
+       { "codec0_in", NULL, "ssp0 Rx" },
+       { "ssp0 Rx", NULL, "AIF1 Capture" },
+
+       { "hifi1", NULL, "iDisp1 Tx"},
+       { "iDisp1 Tx", NULL, "iDisp1_out"},
+       { "hifi2", NULL, "iDisp2 Tx"},
+       { "iDisp2 Tx", NULL, "iDisp2_out"},
+       { "hifi3", NULL, "iDisp3 Tx"},
+       { "iDisp3 Tx", NULL, "iDisp3_out"},
+};
+
+static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = DUAL_CHANNEL;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_component *component = rtd->codec_dai->component;
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+       ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios);
+       if (ret)
+               dev_warn(component->dev, "Failed to add driver gpios\n");
+
+       /* Request rt5660 GPIO for lineout mute control, return if fails */
+       ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute",
+                                          GPIOD_OUT_HIGH);
+       if (IS_ERR(ctx->gpio_lo_mute)) {
+               dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n");
+               return PTR_ERR(ctx->gpio_lo_mute);
+       }
+
+       /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */
+       ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack",
+                                   SND_JACK_LINEOUT, &lineout_jack,
+                                   &lineout_jack_pin, 1);
+       if (ret)
+               dev_warn(component->dev, "Can't create Lineout jack\n");
+       else {
+               lineout_jack_gpio.gpiod_dev = component->dev;
+               ret = snd_soc_jack_add_gpios(&lineout_jack, 1,
+                                            &lineout_jack_gpio);
+               if (ret)
+                       dev_warn(component->dev, "Can't add Lineout jack gpio\n");
+       }
+
+       /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */
+       ret = snd_soc_card_jack_new(rtd->card, "Mic Jack",
+                                   SND_JACK_MICROPHONE, &mic_jack,
+                                   &mic_jack_pin, 1);
+       if (ret)
+               dev_warn(component->dev, "Can't create mic jack\n");
+       else {
+               mic_jack_gpio.gpiod_dev = component->dev;
+               ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio);
+               if (ret)
+                       dev_warn(component->dev, "Can't add mic jack gpio\n");
+       }
+
+       /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+       snd_soc_dapm_force_enable_pin(dapm, "BST1");
+       snd_soc_dapm_force_enable_pin(dapm, "BST2");
+
+       return 0;
+}
+
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
+{
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       struct kbl_hdmi_pcm *pcm;
+
+       pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       pcm->device = device;
+       pcm->codec_dai = dai;
+
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+       return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
+
+static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                    RT5660_SCLK_S_PLL1, params_rate(params) * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0,
+                                 RT5660_PLL1_S_BCLK,
+                                 params_rate(params) * 50,
+                                 params_rate(params) * 512);
+       if (ret < 0)
+               dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops kabylake_rt5660_ops = {
+       .hw_params = kabylake_rt5660_hw_params,
+};
+
+static const unsigned int rates[] = {
+       48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list  = rates,
+       .mask = 0,
+};
+
+static const unsigned int channels[] = {
+       DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+       .count = ARRAY_SIZE(channels),
+       .list = channels,
+       .mask = 0,
+};
+
+static int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       /*
+        * On this platform for PCM device we support,
+        * 48Khz
+        * stereo
+        * 16 bit audio
+        */
+
+       runtime->hw.channels_max = DUAL_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                          &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+       return 0;
+}
+
+static const struct snd_soc_ops kabylake_rt5660_fe_ops = {
+       .startup = kbl_fe_startup,
+};
+
+/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */
+static struct snd_soc_dai_link kabylake_rt5660_dais[] = {
+       /* Front End DAI links */
+       [KBL_DPCM_AUDIO_PB] = {
+               .name = "Kbl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .ops = &kabylake_rt5660_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_CP] = {
+               .name = "Kbl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .nonatomic = 1,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               .ops = &kabylake_rt5660_fe_ops,
+       },
+       [KBL_DPCM_AUDIO_HDMI1_PB] = {
+               .name = "Kbl HDMI Port1",
+               .stream_name = "Hdmi1",
+               .cpu_dai_name = "HDMI1 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_HDMI2_PB] = {
+               .name = "Kbl HDMI Port2",
+               .stream_name = "Hdmi2",
+               .cpu_dai_name = "HDMI2 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = NULL,
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+       [KBL_DPCM_AUDIO_HDMI3_PB] = {
+               .name = "Kbl HDMI Port3",
+               .stream_name = "Hdmi3",
+               .cpu_dai_name = "HDMI3 Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .init = NULL,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-10EC3277:00",
+               .codec_dai_name = KBL_RT5660_CODEC_DAI,
+               .init = kabylake_rt5660_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = kabylake_ssp0_fixup,
+               .ops = &kabylake_rt5660_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "iDisp1",
+               .id = 1,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .platform_name = "0000:00:1f.3",
+               .dpcm_playback = 1,
+               .init = kabylake_hdmi1_init,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 2,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_hdmi2_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp3",
+               .id = 3,
+               .cpu_dai_name = "iDisp3 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi3",
+               .platform_name = "0000:00:1f.3",
+               .init = kabylake_hdmi3_init,
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+
+#define NAME_SIZE      32
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+       struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
+       struct kbl_hdmi_pcm *pcm;
+       struct snd_soc_component *component = NULL;
+       int err, i = 0;
+       char jack_name[NAME_SIZE];
+
+       list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               component = pcm->codec_dai->component;
+               snprintf(jack_name, sizeof(jack_name),
+                       "HDMI/DP, pcm=%d Jack", pcm->device);
+               err = snd_soc_card_jack_new(card, jack_name,
+                                       SND_JACK_AVOUT, &skylake_hdmi[i],
+                                       NULL, 0);
+
+               if (err)
+                       return err;
+
+               err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+                               &skylake_hdmi[i]);
+               if (err < 0)
+                       return err;
+
+               i++;
+
+       }
+
+       if (!component)
+               return -EINVAL;
+
+       return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* kabylake audio machine driver for rt5660 */
+static struct snd_soc_card kabylake_audio_card_rt5660 = {
+       .name = "kblrt5660",
+       .owner = THIS_MODULE,
+       .dai_link = kabylake_rt5660_dais,
+       .num_links = ARRAY_SIZE(kabylake_rt5660_dais),
+       .controls = kabylake_rt5660_controls,
+       .num_controls = ARRAY_SIZE(kabylake_rt5660_controls),
+       .dapm_widgets = kabylake_rt5660_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets),
+       .dapm_routes = kabylake_rt5660_map,
+       .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
+       .fully_routed = true,
+       .late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+       struct kbl_codec_private *ctx;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       kabylake_audio_card =
+               (struct snd_soc_card *)pdev->id_entry->driver_data;
+
+       kabylake_audio_card->dev = &pdev->dev;
+       snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
+       return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+       {
+               .name = "kbl_rt5660",
+               .driver_data =
+                       (kernel_ulong_t)&kabylake_audio_card_rt5660,
+       },
+       { }
+};
+
+static struct platform_driver kabylake_audio = {
+       .probe = kabylake_audio_probe,
+       .driver = {
+               .name = "kbl_rt5660",
+               .pm = &snd_soc_pm_ops,
+       },
+       .id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode");
+MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5660");
index 99e1320c485ff2b6f14f7f9c4f25a089bc5f0b83..d71475200b08aad41ea82a466b8c35a95fc8aa6d 100644 (file)
@@ -25,9 +25,9 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-acpi.h>
 #include "../../codecs/rt5663.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
@@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
                                &constraints_16000);
 }
 
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
        .startup = kabylake_refcap_startup,
 };
 
@@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
                .dpcm_capture = 1,
                .nonatomic = 1,
                .dynamic = 1,
-               .ops = &skylaye_refcap_ops,
+               .ops = &skylake_refcap_ops,
        },
        [KBL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Kbl Audio DMIC cap",
@@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = {
 static int kabylake_audio_probe(struct platform_device *pdev)
 {
        struct kbl_rt5663_private *ctx;
-       struct skl_machine_pdata *pdata;
+       struct snd_soc_acpi_mach *mach;
        int ret;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
        kabylake_audio_card->dev = &pdev->dev;
        snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
 
-       pdata = dev_get_drvdata(&pdev->dev);
-       if (pdata)
-               dmic_constraints = pdata->dmic_num == 2 ?
+       mach = (&pdev->dev)->platform_data;
+       if (mach)
+               dmic_constraints = mach->mach_params.dmic_num == 2 ?
                        &constraints_dmic_2ch : &constraints_dmic_channels;
 
        ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
index a737c915d46a83128aef3af3575301eedd2ce6b7..7044d8c2b187375cd6fd44b3342eedf4b37fd8d1 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-acpi.h>
 #include "../../codecs/rt5514.h"
 #include "../../codecs/rt5663.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
 
 #define KBL_REALTEK_CODEC_DAI "rt5663-aif"
 #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
@@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = {
 static int kabylake_audio_probe(struct platform_device *pdev)
 {
        struct kbl_codec_private *ctx;
-       struct skl_machine_pdata *pdata;
+       struct snd_soc_acpi_mach *mach;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
        kabylake_audio_card.dev = &pdev->dev;
        snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
 
-       pdata = dev_get_drvdata(&pdev->dev);
-       if (pdata)
-               dmic_constraints = pdata->dmic_num == 2 ?
+       mach = (&pdev->dev)->platform_data;
+       if (mach)
+               dmic_constraints = mach->mach_params.dmic_num == 2 ?
                        &constraints_dmic_2ch : &constraints_dmic_channels;
 
        return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
index b415dd4c85f5ac9890f440fd40311ce5e8f4953b..b9a21e64ead2ecafdd9daaf78b96862b75ece2a7 100644 (file)
@@ -12,8 +12,8 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-acpi.h>
 #include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
 #include "skl_hda_dsp_common.h"
 
 static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
@@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = {
 #define IDISP_ROUTE_COUNT      (IDISP_DAI_COUNT * 2)
 #define IDISP_CODEC_MASK       0x4
 
-static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
+static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
 {
        struct snd_soc_card *card = &hda_soc_card;
        struct snd_soc_dai_link *dai_link;
        u32 codec_count, codec_mask;
        int i, num_links, num_route;
 
-       codec_mask = pdata->codec_mask;
+       codec_mask = mach_params->codec_mask;
        codec_count = hweight_long(codec_mask);
 
-       if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
+       if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) {
                num_links = IDISP_DAI_COUNT;
                num_route = IDISP_ROUTE_COUNT;
        } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
@@ -127,30 +127,30 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
        card->num_dapm_routes = num_route;
 
        for_each_card_prelinks(card, i, dai_link)
-               dai_link->platform_name = pdata->platform;
+               dai_link->platform_name = mach_params->platform;
 
        return 0;
 }
 
 static int skl_hda_audio_probe(struct platform_device *pdev)
 {
-       struct skl_machine_pdata *pdata;
+       struct snd_soc_acpi_mach *mach;
        struct skl_hda_private *ctx;
        int ret;
 
        dev_dbg(&pdev->dev, "%s: entry\n", __func__);
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 
-       pdata = dev_get_drvdata(&pdev->dev);
-       if (!pdata)
+       mach = (&pdev->dev)->platform_data;
+       if (!mach)
                return -EINVAL;
 
-       ret = skl_hda_fill_card_info(pdata);
+       ret = skl_hda_fill_card_info(&mach->mach_params);
        if (ret < 0) {
                dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
                return ret;
@@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
 
        ctx->pcm_count = hda_soc_card.num_links;
        ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
-       ctx->platform_name = pdata->platform;
+       ctx->platform_name = mach->mach_params.platform;
 
        hda_soc_card.dev = &pdev->dev;
        snd_soc_card_set_drvdata(&hda_soc_card, ctx);
index d31482b8c9bbb02a0dcbd6e1c74fe5e01db9f657..0922106bd323d7e89bd6e7e25b890dc14e6d22fb 100644 (file)
@@ -21,9 +21,9 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-acpi.h>
 #include "../../codecs/nau8825.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
 
 #define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
 #define SKL_MAXIM_CODEC_DAI "HiFi"
@@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
                                &constraints_16000);
 }
 
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
        .startup = skylake_refcap_startup,
 };
 
@@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
                .dpcm_capture = 1,
                .nonatomic = 1,
                .dynamic = 1,
-               .ops = &skylaye_refcap_ops,
+               .ops = &skylake_refcap_ops,
        },
        [SKL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Skl Audio DMIC cap",
@@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = {
 static int skylake_audio_probe(struct platform_device *pdev)
 {
        struct skl_nau8825_private *ctx;
-       struct skl_machine_pdata *pdata;
+       struct snd_soc_acpi_mach *mach;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
        skylake_audio_card.dev = &pdev->dev;
        snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
 
-       pdata = dev_get_drvdata(&pdev->dev);
-       if (pdata)
-               dmic_constraints = pdata->dmic_num == 2 ?
+       mach = (&pdev->dev)->platform_data;
+       if (mach)
+               dmic_constraints = mach->mach_params.dmic_num == 2 ?
                        &constraints_dmic_2ch : &constraints_dmic_channels;
 
        return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
index e877bb60beb10b3634efe82dcb5ae870e768b3a8..8433c521d39f21392524312ec18a499e205435c0 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
+#include <sound/soc-acpi.h>
 #include <sound/jack.h>
 #include <sound/pcm_params.h>
 #include "../../codecs/nau8825.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
 
 #define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
 #define SKL_SSM_CODEC_DAI      "ssm4567-hifi"
@@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
                        &constraints_16000);
 }
 
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
        .startup = skylake_refcap_startup,
 };
 
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
                .dpcm_capture = 1,
                .nonatomic = 1,
                .dynamic = 1,
-               .ops = &skylaye_refcap_ops,
+               .ops = &skylake_refcap_ops,
        },
        [SKL_DPCM_AUDIO_DMIC_CP] = {
                .name = "Skl Audio DMIC cap",
@@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = {
 static int skylake_audio_probe(struct platform_device *pdev)
 {
        struct skl_nau88125_private *ctx;
-       struct skl_machine_pdata *pdata;
+       struct snd_soc_acpi_mach *mach;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
        skylake_audio_card.dev = &pdev->dev;
        snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
 
-       pdata = dev_get_drvdata(&pdev->dev);
-       if (pdata)
-               dmic_constraints = pdata->dmic_num == 2 ?
+       mach = (&pdev->dev)->platform_data;
+       if (mach)
+               dmic_constraints = mach->mach_params.dmic_num == 2 ?
                        &constraints_dmic_2ch : &constraints_dmic_channels;
 
        return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
index c1f50a079d34aad252b84fe6830e01fb987bb5d4..56c81e20b5bf8d617a48cd59e02e2cbf58dfc169 100644 (file)
@@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
        soc-acpi-intel-hsw-bdw-match.o \
        soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
        soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
-       soc-acpi-intel-cnl-match.o \
+       soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \
        soc-acpi-intel-hda-match.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
index f39386e540d32273e0edba93f6ffa7c1f51cb6f3..61dedc103b19664cca08bab2b79669220242ff36 100644 (file)
@@ -6,9 +6,41 @@
  *
  */
 
+#include <linux/dmi.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 
+enum {
+       APL_RVP,
+};
+
+static const struct dmi_system_id apl_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"),
+               },
+               .driver_data = (void *)(APL_RVP),
+       },
+       {}
+};
+
+static struct snd_soc_acpi_mach *apl_quirk(void *arg)
+{
+       struct snd_soc_acpi_mach *mach = arg;
+       const struct dmi_system_id *dmi_id;
+       unsigned long apl_machine_id;
+
+       dmi_id = dmi_first_match(apl_table);
+       if (dmi_id) {
+               apl_machine_id = (unsigned long)dmi_id->driver_data;
+               if (apl_machine_id == APL_RVP)
+                       return NULL;
+       }
+
+       return mach;
+}
+
 static struct snd_soc_acpi_codecs bxt_codecs = {
        .num_codecs = 1,
        .codecs = {"MX98357A"}
@@ -19,6 +51,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
                .id = "INT343A",
                .drv_name = "bxt_alc298s_i2s",
                .fw_filename = "intel/dsp_fw_bxtn.bin",
+               .sof_fw_filename = "intel/sof-apl.ri",
+               .sof_tplg_filename = "intel/sof-apl-rt298.tplg",
+               .asoc_plat_name = "0000:00:0e.0",
        },
        {
                .id = "DLGS7219",
@@ -47,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
        {
                .id = "INT34C3",
                .drv_name = "bxt_tdf8532",
+               .machine_quirk = apl_quirk,
                .sof_fw_filename = "intel/sof-apl.ri",
                .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
                .asoc_plat_name = "0000:00:0e.0",
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
new file mode 100644 (file)
index 0000000..33b441d
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata icl_pdata = {
+       .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
+       {
+               .id = "INT34C2",
+               .drv_name = "icl_rt274",
+               .fw_filename = "intel/dsp_fw_icl.bin",
+               .pdata = &icl_pdata,
+               .sof_fw_filename = "intel/sof-icl.ri",
+               .sof_tplg_filename = "intel/sof-icl-rt274.tplg",
+               .asoc_plat_name = "0000:00:1f.3",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
index a317b7790fcecf1c233afbe5884c86187f39a322..e6fa6f470526dc5fd68d3807f6df8acb283a7378 100644 (file)
@@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
                .quirk_data = &kbl_7219_98927_codecs,
                .pdata = &skl_dmic_data
        },
+       {
+               .id = "10EC5660",
+               .drv_name = "kbl_rt5660",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
+       {
+               .id = "10EC3277",
+               .drv_name = "kbl_rt5660",
+               .fw_filename = "intel/dsp_fw_kbl.bin",
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
index 8bfb8b0fa3d5959b25ee42ef9bcb35255b2eb97f..b0e6fb93eaf83ce9e1bcaf01c2cb405784e72e73 100644 (file)
@@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .init_fw = cnl_sst_init_fw,
                .cleanup = cnl_sst_dsp_cleanup
        },
+       {
+               .id = 0xa348,
+               .num_cores = 4,
+               .loader_ops = bxt_get_loader_ops,
+               .init = cnl_sst_dsp_init,
+               .init_fw = cnl_sst_init_fw,
+               .cleanup = cnl_sst_dsp_cleanup
+       },
 };
 
 const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
index 01a050cf877537ddab712863e50fe1b523db98de..5d125a3df52792f838bb31e85c8e88719240520a 100644 (file)
@@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl)
        unsigned int dmic_geo = 0;
        u8 j;
 
+       if (!nhlt)
+               return 0;
+
        epnt = (struct nhlt_endpoint *)nhlt->desc;
 
        for (j = 0; j < nhlt->endpoint_count; j++) {
index 5234fafb758a0efdd65a60f30f290b24f8d5e780..9f3ce73593aec44be387a633c23077f6168f4950 100644 (file)
@@ -249,6 +249,8 @@ enum skl_ipc_glb_reply {
        IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
        IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
        IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
+       IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150,
+       IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151,
 
        IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
        IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
@@ -392,18 +394,47 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
        return 0;
 }
 
-static int skl_ipc_set_reply_error_code(u32 reply)
+struct skl_ipc_err_map {
+       const char *msg;
+       enum skl_ipc_glb_reply reply;
+       int err;
+};
+
+static struct skl_ipc_err_map skl_err_map[] = {
+       {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM},
+       {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY},
+       {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING,
+                       IPC_GLB_REPLY_SCLK_ALREADY_RUNNING},
+       {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING,
+                       IPC_GLB_REPLY_MCLK_ALREADY_RUNNING},
+};
+
+static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply)
 {
-       switch (reply) {
-       case IPC_GLB_REPLY_OUT_OF_MEMORY:
-               return -ENOMEM;
+       int i;
 
-       case IPC_GLB_REPLY_BUSY:
-               return -EBUSY;
+       for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) {
+               if (skl_err_map[i].reply == reply)
+                       break;
+       }
 
-       default:
+       if (i == ARRAY_SIZE(skl_err_map)) {
+               dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n",
+                               reply,
+                               ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
                return -EINVAL;
        }
+
+       if (skl_err_map[i].err < 0)
+               dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+                               skl_err_map[i].msg,
+                               ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+       else
+               dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+                               skl_err_map[i].msg,
+                               ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+
+       return skl_err_map[i].err;
 }
 
 void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
@@ -441,10 +472,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
 
                }
        } else {
-               msg->errno = skl_ipc_set_reply_error_code(reply);
-               dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
-               dev_err(ipc->dev, "FW Error Code: %u\n",
-                       ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+               msg->errno = skl_ipc_set_reply_error_code(ipc, reply);
                switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
                case IPC_GLB_LOAD_MULTIPLE_MODS:
                case IPC_GLB_LOAD_LIBRARY:
index 7487f388e65d729c8fc6032a3e84d0908ac454f4..60c94836bf5bc93bb3dde46a237c21abf77e5b6c 100644 (file)
@@ -40,6 +40,9 @@
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
 #include "../../../soc/codecs/hdac_hda.h"
 #endif
+static int skl_pci_binding;
+module_param_named(pci_binding, skl_pci_binding, int, 0444);
+MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
 
 /*
  * initialize the PCI registers
@@ -311,7 +314,7 @@ static int skl_suspend(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_bus *bus = pci_get_drvdata(pci);
        struct skl *skl  = bus_to_skl(bus);
-       int ret = 0;
+       int ret;
 
        /*
         * Do not suspend if streams which are marked ignore suspend are
@@ -333,14 +336,10 @@ static int skl_suspend(struct device *dev)
                skl->skl_sst->fw_loaded = false;
        }
 
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               ret = snd_hdac_display_power(bus, false);
-               if (ret < 0)
-                       dev_err(bus->dev,
-                               "Cannot turn OFF display power on i915\n");
-       }
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
 
-       return ret;
+       return 0;
 }
 
 static int skl_resume(struct device *dev)
@@ -352,14 +351,8 @@ static int skl_resume(struct device *dev)
        int ret;
 
        /* Turned OFF in HDMI codec driver after codec reconfiguration */
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               ret = snd_hdac_display_power(bus, true);
-               if (ret < 0) {
-                       dev_err(bus->dev,
-                               "Cannot turn on display power on i915\n");
-                       return ret;
-               }
-       }
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
 
        /*
         * resume only when we are not in suspend active, otherwise need to
@@ -517,7 +510,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
 
        if (pdata) {
                skl->use_tplg_pcm = pdata->use_tplg_pcm;
-               pdata->dmic_num = skl_get_dmic_geo(skl);
+               mach->mach_params.dmic_num = skl_get_dmic_geo(skl);
        }
 
        return 0;
@@ -527,7 +520,6 @@ static int skl_machine_device_register(struct skl *skl)
 {
        struct snd_soc_acpi_mach *mach = skl->mach;
        struct hdac_bus *bus = skl_to_bus(skl);
-       struct skl_machine_pdata *pdata;
        struct platform_device *pdev;
        int ret;
 
@@ -537,6 +529,16 @@ static int skl_machine_device_register(struct skl *skl)
                return -EIO;
        }
 
+       mach->mach_params.platform = dev_name(bus->dev);
+       mach->mach_params.codec_mask = bus->codec_mask;
+
+       ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
+       if (ret) {
+               dev_err(bus->dev, "failed to add machine device platform data\n");
+               platform_device_put(pdev);
+               return ret;
+       }
+
        ret = platform_device_add(pdev);
        if (ret) {
                dev_err(bus->dev, "failed to add machine device\n");
@@ -544,12 +546,6 @@ static int skl_machine_device_register(struct skl *skl)
                return -EIO;
        }
 
-       if (mach->pdata) {
-               pdata = (struct skl_machine_pdata *)mach->pdata;
-               pdata->platform = dev_name(bus->dev);
-               pdata->codec_mask = bus->codec_mask;
-               dev_set_drvdata(&pdev->dev, mach->pdata);
-       }
 
        skl->i2s_dev = pdev;
 
@@ -783,11 +779,9 @@ static int skl_i915_init(struct hdac_bus *bus)
        if (err < 0)
                return err;
 
-       err = snd_hdac_display_power(bus, true);
-       if (err < 0)
-               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+       snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
 
-       return err;
+       return 0;
 }
 
 static void skl_probe_work(struct work_struct *work)
@@ -823,12 +817,10 @@ static void skl_probe_work(struct work_struct *work)
                return;
        }
 
-       if (bus->ppcap) {
-               err = skl_machine_device_register(skl);
-               if (err < 0) {
-                       dev_err(bus->dev, "machine register failed: %d\n", err);
-                       goto out_err;
-               }
+       err = skl_machine_device_register(skl);
+       if (err < 0) {
+               dev_err(bus->dev, "machine register failed: %d\n", err);
+               goto out_err;
        }
 
        /*
@@ -837,14 +829,8 @@ static void skl_probe_work(struct work_struct *work)
        list_for_each_entry(hlink, &bus->hlink_list, list)
                snd_hdac_ext_bus_link_put(bus, hlink);
 
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               err = snd_hdac_display_power(bus, false);
-               if (err < 0) {
-                       dev_err(bus->dev, "Cannot turn off display power on i915\n");
-                       skl_machine_device_unregister(skl);
-                       return;
-               }
-       }
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
 
        /* configure PM */
        pm_runtime_put_noidle(bus->dev);
@@ -855,7 +841,7 @@ static void skl_probe_work(struct work_struct *work)
 
 out_err:
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
-               err = snd_hdac_display_power(bus, false);
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
 }
 
 /*
@@ -928,6 +914,12 @@ static int skl_first_init(struct hdac_bus *bus)
 
        snd_hdac_bus_parse_capabilities(bus);
 
+       /* check if PPCAP exists */
+       if (!bus->ppcap) {
+               dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n");
+               return -ENODEV;
+       }
+
        if (skl_acquire_irq(bus, 0) < 0)
                return -EBUSY;
 
@@ -937,23 +929,25 @@ static int skl_first_init(struct hdac_bus *bus)
        gcap = snd_hdac_chip_readw(bus, GCAP);
        dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
 
-       /* allow 64bit DMA address if supported by H/W */
-       if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
-       } else {
-               dma_set_mask(bus->dev, DMA_BIT_MASK(32));
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
-       }
-
        /* read number of streams from GCAP register */
        cp_streams = (gcap >> 8) & 0x0f;
        pb_streams = (gcap >> 12) & 0x0f;
 
-       if (!pb_streams && !cp_streams)
+       if (!pb_streams && !cp_streams) {
+               dev_err(bus->dev, "no streams found in GCAP definitions?\n");
                return -EIO;
+       }
 
        bus->num_streams = cp_streams + pb_streams;
 
+       /* allow 64bit DMA address if supported by H/W */
+       if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
+               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
+       } else {
+               dma_set_mask(bus->dev, DMA_BIT_MASK(32));
+               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
+       }
+
        /* initialize streams */
        snd_hdac_ext_stream_init_all
                (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
@@ -978,6 +972,36 @@ static int skl_probe(struct pci_dev *pci,
        struct hdac_bus *bus = NULL;
        int err;
 
+       switch (skl_pci_binding) {
+       case SND_SKL_PCI_BIND_AUTO:
+               /*
+                * detect DSP by checking class/subclass/prog-id information
+                * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
+                * class=04 subclass 01 prog-if 00: DSP is present
+                *   (and may be required e.g. for DMIC or SSP support)
+                * class=04 subclass 03 prog-if 80: use DSP or legacy mode
+                */
+               if (pci->class == 0x040300) {
+                       dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+                       return -ENODEV;
+               }
+               if (pci->class != 0x040100 && pci->class != 0x040380) {
+                       dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
+                       return -ENODEV;
+               }
+               dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+               break;
+       case SND_SKL_PCI_BIND_LEGACY:
+               dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
+               return -ENODEV;
+       case SND_SKL_PCI_BIND_ASOC:
+               dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n");
+               break;
+       default:
+               dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
+               break;
+       }
+
        /* we use ext core ops, so provide NULL for ops here */
        err = skl_create(pci, NULL, &skl);
        if (err < 0)
@@ -986,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci,
        bus = skl_to_bus(skl);
 
        err = skl_first_init(bus);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
                goto out_free;
+       }
 
        skl->pci_id = pci->device;
 
@@ -996,37 +1022,48 @@ static int skl_probe(struct pci_dev *pci,
        skl->nhlt = skl_nhlt_init(bus->dev);
 
        if (skl->nhlt == NULL) {
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
+               dev_err(bus->dev, "no nhlt info found\n");
                err = -ENODEV;
                goto out_free;
-       }
-
-       err = skl_nhlt_create_sysfs(skl);
-       if (err < 0)
-               goto out_nhlt_free;
+#else
+               dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n");
+#endif
+       } else {
 
-       skl_nhlt_update_topology_bin(skl);
+               err = skl_nhlt_create_sysfs(skl);
+               if (err < 0) {
+                       dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
+                       goto out_nhlt_free;
+               }
 
-       pci_set_drvdata(skl->pci, bus);
+               skl_nhlt_update_topology_bin(skl);
 
-       /* check if dsp is there */
-       if (bus->ppcap) {
                /* create device for dsp clk */
                err = skl_clock_device_register(skl);
-               if (err < 0)
+               if (err < 0) {
+                       dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
                        goto out_clk_free;
+               }
+       }
 
-               err = skl_find_machine(skl, (void *)pci_id->driver_data);
-               if (err < 0)
-                       goto out_nhlt_free;
+       pci_set_drvdata(skl->pci, bus);
 
-               err = skl_init_dsp(skl);
-               if (err < 0) {
-                       dev_dbg(bus->dev, "error failed to register dsp\n");
-                       goto out_nhlt_free;
-               }
-               skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
-               skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
+       err = skl_find_machine(skl, (void *)pci_id->driver_data);
+       if (err < 0) {
+               dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
+               goto out_nhlt_free;
        }
+
+       err = skl_init_dsp(skl);
+       if (err < 0) {
+               dev_dbg(bus->dev, "error failed to register dsp\n");
+               goto out_nhlt_free;
+       }
+       skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+       skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
        if (bus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(bus);
 
@@ -1034,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci,
 
        /* create device for soc dmic */
        err = skl_dmic_device_register(skl);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
                goto out_dsp_free;
+       }
 
        schedule_work(&skl->probe_work);
 
@@ -1103,21 +1142,36 @@ static void skl_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
        /* BXT-P */
        { PCI_DEVICE(0x8086, 0x5a98),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
        /* KBL */
        { PCI_DEVICE(0x8086, 0x9D71),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
        /* GLK */
        { PCI_DEVICE(0x8086, 0x3198),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
        /* CNL */
        { PCI_DEVICE(0x8086, 0x9dc8),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
+       /* CFL */
+       { PCI_DEVICE(0x8086, 0xa348),
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
index 8d48cd7c56c8358497cb1baef7275fe73e7196fc..85f8bb6687dcbd37ba949db15139aca877acf129 100644 (file)
@@ -119,10 +119,7 @@ struct skl_dma_params {
 };
 
 struct skl_machine_pdata {
-       u32 dmic_num;
        bool use_tplg_pcm; /* use dais and dai links from topology */
-       const char *platform;
-       u32 codec_mask;
 };
 
 struct skl_dsp_ops {
index 192f4d7b37b6ad003d558dcc9b6b74f125225792..bff7d71d07428407cff339daa58672c94c659a00 100644 (file)
@@ -828,7 +828,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
        /* request irq */
        irq_id = platform_get_irq(pdev, 0);
        if (!irq_id) {
-               dev_err(dev, "%s no irq found\n", dev->of_node->name);
+               dev_err(dev, "%pOFn no irq found\n", dev->of_node);
                return -ENXIO;
        }
        ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
index c0b6697503fd79831ddb2f6a711a54586a2a7a95..166aed28330da4a435744c9efe1f12ae4e71282f 100644 (file)
@@ -1092,7 +1092,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 
        irq_id = platform_get_irq(pdev, 0);
        if (irq_id <= 0) {
-               dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
+               dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
                return irq_id < 0 ? irq_id : -ENXIO;
        }
        ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
index 8b8426ed2363f50f9c4fdb466675e4da67277af9..8779fe23671d6cd4cff7c416a66f52b9f58ff4da 100644 (file)
@@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD
        imply SND_MESON_AXG_TDMIN
        imply SND_MESON_AXG_TDMOUT
        imply SND_MESON_AXG_SPDIFOUT
+       imply SND_MESON_AXG_SPDIFIN
        imply SND_MESON_AXG_PDM
        help
          Select Y or M to add support for the AXG SoC sound card
@@ -67,6 +68,13 @@ config SND_MESON_AXG_SPDIFOUT
          Select Y or M to add support for SPDIF output serializer embedded
          in the Amlogic AXG SoC family
 
+config SND_MESON_AXG_SPDIFIN
+       tristate "Amlogic AXG SPDIF Input Support"
+       imply SND_SOC_SPDIF
+       help
+         Select Y or M to add support for SPDIF input embedded
+         in the Amlogic AXG SoC family
+
 config SND_MESON_AXG_PDM
        tristate "Amlogic AXG PDM Input Support"
        imply SND_SOC_DMIC
@@ -74,5 +82,4 @@ config SND_MESON_AXG_PDM
        help
          Select Y or M to add support for PDM input embedded
          in the Amlogic AXG SoC family
-
 endmenu
index 4cd25104029d87d5fe6a17e766e73e02cc3c1fa3..b45dfb9e2f88803e5698581f40f00403a574c84a 100644 (file)
@@ -8,6 +8,7 @@ snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
 snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
 snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
 snd-soc-meson-axg-sound-card-objs := axg-card.o
+snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
 snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
 snd-soc-meson-axg-pdm-objs := axg-pdm.o
 
@@ -19,5 +20,6 @@ obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o
 obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
 obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
 obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
 obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
 obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
index cb6c4013ca33ff7458be4877d3478abd1b95aa82..d9f516cfbeda2d76939da1fa726811db54ee9249 100644 (file)
@@ -25,7 +25,8 @@ struct snd_soc_pcm_runtime;
                                         SNDRV_PCM_FMTBIT_S16_LE |      \
                                         SNDRV_PCM_FMTBIT_S20_LE |      \
                                         SNDRV_PCM_FMTBIT_S24_LE |      \
-                                        SNDRV_PCM_FMTBIT_S32_LE)
+                                        SNDRV_PCM_FMTBIT_S32_LE |      \
+                                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 #define AXG_FIFO_BURST                 8
 #define AXG_FIFO_MIN_CNT               64
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c
new file mode 100644 (file)
index 0000000..01b2035
--- /dev/null
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm_params.h>
+
+#define SPDIFIN_CTRL0                  0x00
+#define  SPDIFIN_CTRL0_EN              BIT(31)
+#define  SPDIFIN_CTRL0_RST_OUT         BIT(29)
+#define  SPDIFIN_CTRL0_RST_IN          BIT(28)
+#define  SPDIFIN_CTRL0_WIDTH_SEL       BIT(24)
+#define  SPDIFIN_CTRL0_STATUS_CH_SHIFT 11
+#define  SPDIFIN_CTRL0_STATUS_SEL      GENMASK(10, 8)
+#define  SPDIFIN_CTRL0_SRC_SEL         GENMASK(5, 4)
+#define  SPDIFIN_CTRL0_CHK_VALID       BIT(3)
+#define SPDIFIN_CTRL1                  0x04
+#define  SPDIFIN_CTRL1_BASE_TIMER      GENMASK(19, 0)
+#define  SPDIFIN_CTRL1_IRQ_MASK                GENMASK(27, 20)
+#define SPDIFIN_CTRL2                  0x08
+#define  SPDIFIN_THRES_PER_REG         3
+#define  SPDIFIN_THRES_WIDTH           10
+#define SPDIFIN_CTRL3                  0x0c
+#define SPDIFIN_CTRL4                  0x10
+#define  SPDIFIN_TIMER_PER_REG         4
+#define  SPDIFIN_TIMER_WIDTH           8
+#define SPDIFIN_CTRL5                  0x14
+#define SPDIFIN_CTRL6                  0x18
+#define SPDIFIN_STAT0                  0x1c
+#define  SPDIFIN_STAT0_MODE            GENMASK(30, 28)
+#define  SPDIFIN_STAT0_MAXW            GENMASK(17, 8)
+#define  SPDIFIN_STAT0_IRQ             GENMASK(7, 0)
+#define  SPDIFIN_IRQ_MODE_CHANGED      BIT(2)
+#define SPDIFIN_STAT1                  0x20
+#define SPDIFIN_STAT2                  0x24
+#define SPDIFIN_MUTE_VAL               0x28
+
+#define SPDIFIN_MODE_NUM               7
+
+struct axg_spdifin_cfg {
+       const unsigned int *mode_rates;
+       unsigned int ref_rate;
+};
+
+struct axg_spdifin {
+       const struct axg_spdifin_cfg *conf;
+       struct regmap *map;
+       struct clk *refclk;
+       struct clk *pclk;
+};
+
+/*
+ * TODO:
+ * It would have been nice to check the actual rate against the sample rate
+ * requested in hw_params(). Unfortunately, I was not able to make the mode
+ * detection and IRQ work reliably:
+ *
+ * 1. IRQs are generated on mode change only, so there is no notification
+ *    on transition between no signal and mode 0 (32kHz).
+ * 2. Mode detection very often has glitches, and may detects the
+ *    lowest or the highest mode before zeroing in on the actual mode.
+ *
+ * This makes calling snd_pcm_stop() difficult to get right. Even notifying
+ * the kcontrol would be very unreliable at this point.
+ * Let's keep things simple until the magic spell that makes this work is
+ * found.
+ */
+
+static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv)
+{
+       unsigned int stat, mode, rate = 0;
+
+       regmap_read(priv->map, SPDIFIN_STAT0, &stat);
+       mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat);
+
+       /*
+        * If max width is zero, we are not capturing anything.
+        * Also Sometimes, when the capture is on but there is no data,
+        * mode is SPDIFIN_MODE_NUM, but not always ...
+        */
+       if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&
+           mode < SPDIFIN_MODE_NUM)
+               rate = priv->conf->mode_rates[mode];
+
+       return rate;
+}
+
+static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+       /* Apply both reset */
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+                          SPDIFIN_CTRL0_RST_OUT |
+                          SPDIFIN_CTRL0_RST_IN,
+                          0);
+
+       /* Clear out reset before in reset */
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+                          SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT);
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+                          SPDIFIN_CTRL0_RST_IN,  SPDIFIN_CTRL0_RST_IN);
+
+       return 0;
+}
+
+static int axg_spdifin_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       ret = clk_prepare_enable(priv->refclk);
+       if (ret) {
+               dev_err(dai->dev,
+                       "failed to enable spdifin reference clock\n");
+               return ret;
+       }
+
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
+                          SPDIFIN_CTRL0_EN);
+
+       return 0;
+}
+
+static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
+       clk_disable_unprepare(priv->refclk);
+}
+
+static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
+                                        unsigned int val,
+                                        unsigned int num_per_reg,
+                                        unsigned int base_reg,
+                                        unsigned int width)
+{
+       uint64_t offset = mode;
+       unsigned int reg, shift, rem;
+
+       rem = do_div(offset, num_per_reg);
+
+       reg = offset * regmap_get_reg_stride(map) + base_reg;
+       shift = width * (num_per_reg - 1 - rem);
+
+       regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift,
+                          val << shift);
+}
+
+static void axg_spdifin_write_timer(struct regmap *map, int mode,
+                                   unsigned int val)
+{
+       axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG,
+                                    SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH);
+}
+
+static void axg_spdifin_write_threshold(struct regmap *map, int mode,
+                                       unsigned int val)
+{
+       axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG,
+                                    SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH);
+}
+
+static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv,
+                                          int mode,
+                                          unsigned int rate)
+{
+       /*
+        * Number of period of the reference clock during a period of the
+        * input signal reference clock
+        */
+       return rate / (128 * priv->conf->mode_rates[mode]);
+}
+
+static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
+                                         struct axg_spdifin *priv)
+{
+       unsigned int rate, t_next;
+       int ret, i = SPDIFIN_MODE_NUM - 1;
+
+       /* Set spdif input reference clock */
+       ret = clk_set_rate(priv->refclk, priv->conf->ref_rate);
+       if (ret) {
+               dev_err(dai->dev, "reference clock rate set failed\n");
+               return ret;
+       }
+
+       /*
+        * The rate actually set might be slightly different, get
+        * the actual rate for the following mode calculation
+        */
+       rate = clk_get_rate(priv->refclk);
+
+       /* HW will update mode every 1ms */
+       regmap_update_bits(priv->map, SPDIFIN_CTRL1,
+                          SPDIFIN_CTRL1_BASE_TIMER,
+                          FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
+
+       /* Threshold based on the minimum width between two edges */
+       regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+                          SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL);
+
+       /* Calculate the last timer which has no threshold */
+       t_next = axg_spdifin_mode_timer(priv, i, rate);
+       axg_spdifin_write_timer(priv->map, i, t_next);
+
+       do {
+               unsigned int t;
+
+               i -= 1;
+
+               /* Calculate the timer */
+               t = axg_spdifin_mode_timer(priv, i, rate);
+
+               /* Set the timer value */
+               axg_spdifin_write_timer(priv->map, i, t);
+
+               /* Set the threshold value */
+               axg_spdifin_write_threshold(priv->map, i, t + t_next);
+
+               /* Save the current timer for the next threshold calculation */
+               t_next = t;
+
+       } while (i > 0);
+
+       return 0;
+}
+
+static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
+{
+       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       ret = clk_prepare_enable(priv->pclk);
+       if (ret) {
+               dev_err(dai->dev, "failed to enable pclk\n");
+               return ret;
+       }
+
+       ret = axg_spdifin_sample_mode_config(dai, priv);
+       if (ret) {
+               dev_err(dai->dev, "mode configuration failed\n");
+               clk_disable_unprepare(priv->pclk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
+{
+       struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable_unprepare(priv->pclk);
+       return 0;
+}
+
+static const struct snd_soc_dai_ops axg_spdifin_ops = {
+       .prepare        = axg_spdifin_prepare,
+       .startup        = axg_spdifin_startup,
+       .shutdown       = axg_spdifin_shutdown,
+};
+
+static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       int i;
+
+       for (i = 0; i < 24; i++)
+               ucontrol->value.iec958.status[i] = 0xff;
+
+       return 0;
+}
+
+static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+       struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+       int i, j;
+
+       for (i = 0; i < 6; i++) {
+               unsigned int val;
+
+               regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+                                  SPDIFIN_CTRL0_STATUS_SEL,
+                                  FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i));
+
+               regmap_read(priv->map, SPDIFIN_STAT1, &val);
+
+               for (j = 0; j < 4; j++) {
+                       unsigned int offset = i * 4 + j;
+
+                       ucontrol->value.iec958.status[offset] =
+                               (val >> (j * 8)) & 0xff;
+               }
+       }
+
+       return 0;
+}
+
+#define AXG_SPDIFIN_IEC958_MASK                                                \
+       {                                                               \
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,                   \
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,                      \
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),       \
+               .info = axg_spdifin_iec958_info,                        \
+               .get = axg_spdifin_get_status_mask,                     \
+       }
+
+#define AXG_SPDIFIN_IEC958_STATUS                                      \
+       {                                                               \
+               .access = (SNDRV_CTL_ELEM_ACCESS_READ |                 \
+                          SNDRV_CTL_ELEM_ACCESS_VOLATILE),             \
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,                      \
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE),       \
+               .info = axg_spdifin_iec958_info,                        \
+               .get = axg_spdifin_get_status,                          \
+       }
+
+static const char * const spdifin_chsts_src_texts[] = {
+       "A", "B",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0,
+                           SPDIFIN_CTRL0_STATUS_CH_SHIFT,
+                           spdifin_chsts_src_texts);
+
+static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 192000;
+
+       return 0;
+}
+
+static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+       struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+
+       ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv);
+
+       return 0;
+}
+
+#define AXG_SPDIFIN_LOCK_RATE(xname)                           \
+       {                                                       \
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,              \
+               .access = (SNDRV_CTL_ELEM_ACCESS_READ |         \
+                          SNDRV_CTL_ELEM_ACCESS_VOLATILE),     \
+               .get = axg_spdifin_rate_lock_get,               \
+               .info = axg_spdifin_rate_lock_info,             \
+               .name = xname,                                  \
+       }
+
+static const struct snd_kcontrol_new axg_spdifin_controls[] = {
+       AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"),
+       SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1),
+       SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src",
+                axg_spdifin_chsts_src_enum),
+       AXG_SPDIFIN_IEC958_MASK,
+       AXG_SPDIFIN_IEC958_STATUS,
+};
+
+static const struct snd_soc_component_driver axg_spdifin_component_drv = {
+       .controls               = axg_spdifin_controls,
+       .num_controls           = ARRAY_SIZE(axg_spdifin_controls),
+};
+
+static const struct regmap_config axg_spdifin_regmap_cfg = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = SPDIFIN_MUTE_VAL,
+};
+
+static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = {
+       32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+
+static const struct axg_spdifin_cfg axg_cfg = {
+       .mode_rates = axg_spdifin_mode_rates,
+       .ref_rate = 333333333,
+};
+
+static const struct of_device_id axg_spdifin_of_match[] = {
+       {
+               .compatible = "amlogic,axg-spdifin",
+               .data = &axg_cfg,
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_spdifin_of_match);
+
+static struct snd_soc_dai_driver *
+axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
+{
+       struct snd_soc_dai_driver *drv;
+       int i;
+
+       drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+       if (!drv)
+               return ERR_PTR(-ENOMEM);
+
+       drv->name = "SPDIF Input";
+       drv->ops = &axg_spdifin_ops;
+       drv->probe = axg_spdifin_dai_probe;
+       drv->remove = axg_spdifin_dai_remove;
+       drv->capture.stream_name = "Capture";
+       drv->capture.channels_min = 1;
+       drv->capture.channels_max = 2;
+       drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+
+       for (i = 0; i < SPDIFIN_MODE_NUM; i++) {
+               unsigned int rb =
+                       snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]);
+
+               if (rb == SNDRV_PCM_RATE_KNOT)
+                       return ERR_PTR(-EINVAL);
+
+               drv->capture.rates |= rb;
+       }
+
+       return drv;
+}
+
+static int axg_spdifin_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct axg_spdifin *priv;
+       struct snd_soc_dai_driver *dai_drv;
+       struct resource *res;
+       void __iomem *regs;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, priv);
+
+       priv->conf = of_device_get_match_data(dev);
+       if (!priv->conf) {
+               dev_err(dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg);
+       if (IS_ERR(priv->map)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(priv->map));
+               return PTR_ERR(priv->map);
+       }
+
+       priv->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(priv->pclk)) {
+               ret = PTR_ERR(priv->pclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get pclk: %d\n", ret);
+               return ret;
+       }
+
+       priv->refclk = devm_clk_get(dev, "refclk");
+       if (IS_ERR(priv->refclk)) {
+               ret = PTR_ERR(priv->refclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get mclk: %d\n", ret);
+               return ret;
+       }
+
+       dai_drv = axg_spdifin_get_dai_drv(dev, priv);
+       if (IS_ERR(dai_drv)) {
+               dev_err(dev, "failed to get dai driver: %ld\n",
+                       PTR_ERR(dai_drv));
+               return PTR_ERR(dai_drv);
+       }
+
+       return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv,
+                                              dai_drv, 1);
+}
+
+static struct platform_driver axg_spdifin_pdrv = {
+       .probe = axg_spdifin_probe,
+       .driver = {
+               .name = "axg-spdifin",
+               .of_match_table = axg_spdifin_of_match,
+       },
+};
+module_platform_driver(axg_spdifin_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index c2c9bb3125860fbc0d60cdeb97fa3a43ffdcf9ac..0e9ca3882ae5c1d544f52da08c1c12c422679e87 100644 (file)
@@ -25,6 +25,8 @@
 #define CTRL0_TODDR_LSB_POS_MASK       GENMASK(7, 3)
 #define CTRL0_TODDR_LSB_POS(x)         ((x) << 3)
 
+#define TODDR_MSB_POS  31
+
 static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
                             struct snd_soc_dai *dai)
 {
@@ -36,14 +38,7 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_soc_dai *dai)
 {
        struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
-       unsigned int type, width, msb = 31;
-
-       /*
-        * NOTE:
-        * Almost all backend will place the MSB at bit 31, except SPDIF Input
-        * which will put it at index 28. When adding support for the SPDIF
-        * Input, we'll need to find which type of backend we are connected to.
-        */
+       unsigned int type, width;
 
        switch (params_physical_width(params)) {
        case 8:
@@ -66,8 +61,8 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
                           CTRL0_TODDR_MSB_POS_MASK |
                           CTRL0_TODDR_LSB_POS_MASK,
                           CTRL0_TODDR_TYPE(type) |
-                          CTRL0_TODDR_MSB_POS(msb) |
-                          CTRL0_TODDR_LSB_POS(msb - (width - 1)));
+                          CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
+                          CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
 
        return 0;
 }
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
deleted file mode 100644 (file)
index 6dccea6..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-config SND_OMAP_SOC
-       tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)"
-       depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
-       select SND_SDMA_SOC
-
-config SND_SDMA_SOC
-       tristate "SoC Audio for Texas Instruments chips using sDMA"
-       depends on DMA_OMAP || COMPILE_TEST
-       select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_OMAP_SOC_DMIC
-       tristate
-
-config SND_OMAP_SOC_MCBSP
-       tristate
-
-config SND_OMAP_SOC_MCPDM
-       tristate
-
-config SND_OMAP_SOC_HDMI_AUDIO
-       tristate "HDMI audio support for OMAP4+ based SoCs"
-       depends on SND_SDMA_SOC
-       help
-         For HDMI audio to work OMAPDSS HDMI support should be
-         enabled.
-         The hdmi audio driver implements cpu-dai component using the
-         callbacks provided by OMAPDSS and registers the component
-         under DSS HDMI device. Omap-pcm is registered for platform
-         component also under DSS HDMI device. Dummy codec is used as
-         as codec component. The hdmi audio driver implements also
-         the card and registers it under its own platform device.
-         The device for the driver is registered by OMAPDSS hdmi
-         driver.
-
-config SND_OMAP_SOC_N810
-       tristate "SoC Audio support for Nokia N810"
-       depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC3X
-       help
-         Say Y if you want to add support for SoC audio on Nokia N810.
-
-config SND_OMAP_SOC_RX51
-       tristate "SoC Audio support for Nokia N900 (RX-51)"
-       depends on SND_SDMA_SOC && ARM && I2C
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC3X
-       select SND_SOC_TPA6130A2
-       depends on GPIOLIB
-       help
-         Say Y if you want to add support for SoC audio on Nokia N900
-         cellphone.
-
-config SND_OMAP_SOC_AMS_DELTA
-       tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
-       depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_CX20442
-       help
-         Say Y  if you want to add support  for SoC audio device  connected to
-         a handset and a speakerphone found on Amstrad E3 (Delta) videophone.
-
-         Note that in order to get those devices fully supported,  you have to
-         build  the kernel  with  standard  serial port  driver  included  and
-         configured for at least 4 ports.  Then, from userspace, you must load
-         a line discipline #19 on the modem (ttyS3) serial line.  The simplest
-         way to achieve this is to install util-linux-ng  and use the included
-         ldattach  utility.  This  can be  started  automatically  from  udev,
-         a simple rule like this one should do the trick (it does for me):
-               ACTION=="add", KERNEL=="controlC0", \
-                               RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
-
-config SND_OMAP_SOC_OSK5912
-       tristate "SoC Audio support for omap osk5912"
-       depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC23_I2C
-       help
-         Say Y if you want to add support for SoC audio on osk5912.
-
-config SND_OMAP_SOC_AM3517EVM
-       tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
-       depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC23_I2C
-       help
-         Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
-         EVM.
-
-config SND_OMAP_SOC_OMAP_TWL4030
-       tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
-       depends on TWL4030_CORE && SND_SDMA_SOC
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on TI SoC based boards
-         using twl4030 as c codec. This driver currently supports:
-         - Beagleboard or Devkit8000
-         - Gumstix Overo or CompuLab CM-T35/CM-T3730
-         - IGEP v2
-         - OMAP3EVM
-         - SDP3430
-         - Zoom2
-
-config SND_OMAP_SOC_OMAP_ABE_TWL6040
-       tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK
-       depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
-       select SND_OMAP_SOC_DMIC
-       select SND_OMAP_SOC_MCPDM
-       select SND_SOC_TWL6040
-       select SND_SOC_DMIC
-       select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
-       select CLK_TWL6040
-       help
-         Say Y if you want to add support for SoC audio on OMAP boards using
-         ABE and twl6040 codec. This driver currently supports:
-         - SDP4430/Blaze boards
-         - PandaBoard (4430)
-         - PandaBoardES (4460)
-         - omap5-uevm (5432)
-
-config SND_OMAP_SOC_OMAP3_PANDORA
-       tristate "SoC Audio support for OMAP3 Pandora"
-       depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
deleted file mode 100644 (file)
index 53eba34..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# OMAP Platform Support
-snd-soc-sdma-objs := sdma-pcm.o
-snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o
-snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
-
-obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o
-obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
-obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
-obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
-obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
-
-# OMAP Machine Support
-snd-soc-n810-objs := n810.o
-snd-soc-rx51-objs := rx51.o
-snd-soc-ams-delta-objs := ams-delta.o
-snd-soc-osk5912-objs := osk5912.o
-snd-soc-am3517evm-objs := am3517evm.o
-snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
-snd-soc-omap-twl4030-objs := omap-twl4030.o
-snd-soc-omap3pandora-objs := omap3pandora.o
-
-obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
-obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
-obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
-obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
deleted file mode 100644 (file)
index d565102..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * am3517evm.c  -- ALSA SoC support for OMAP3517 / AM3517 EVM
- *
- * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
- *
- * Based on sound/soc/omap/beagle.c by Steve Sakoman
- *
- * Copyright (C) 2009 Texas Instruments Incorporated
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-
-#include "../codecs/tlv320aic23.h"
-
-#define CODEC_CLOCK    12000000
-
-static int am3517evm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-                       CODEC_CLOCK, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               printk(KERN_ERR "can't set codec system clock\n");
-
-       return ret;
-}
-
-static const struct snd_soc_ops am3517evm_ops = {
-       .hw_params = am3517evm_hw_params,
-};
-
-/* am3517evm machine dapm widgets */
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Line Out", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-       SND_SOC_DAPM_MIC("Mic In", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* Line Out connected to LLOUT, RLOUT */
-       {"Line Out", NULL, "LOUT"},
-       {"Line Out", NULL, "ROUT"},
-
-       {"LLINEIN", NULL, "Line In"},
-       {"RLINEIN", NULL, "Line In"},
-
-       {"MICIN", NULL, "Mic In"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link am3517evm_dai = {
-       .name = "TLV320AIC23",
-       .stream_name = "AIC23",
-       .cpu_dai_name = "omap-mcbsp.1",
-       .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name = "omap-mcbsp.1",
-       .codec_name = "tlv320aic23-codec.2-001a",
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops = &am3517evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_am3517evm = {
-       .name = "am3517evm",
-       .owner = THIS_MODULE,
-       .dai_link = &am3517evm_dai,
-       .num_links = 1,
-
-       .dapm_widgets = tlv320aic23_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *am3517evm_snd_device;
-
-static int __init am3517evm_soc_init(void)
-{
-       int ret;
-
-       if (!machine_is_omap3517evm())
-               return -ENODEV;
-       pr_info("OMAP3517 / AM3517 EVM SoC init\n");
-
-       am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!am3517evm_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
-
-       ret = platform_device_add(am3517evm_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(am3517evm_snd_device);
-
-       return ret;
-}
-
-static void __exit am3517evm_soc_exit(void)
-{
-       platform_device_unregister(am3517evm_snd_device);
-}
-
-module_init(am3517evm_soc_init);
-module_exit(am3517evm_soc_exit);
-
-MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
deleted file mode 100644 (file)
index 4dce494..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * ams-delta.c  --  SoC audio for Amstrad E3 (Delta) videophone
- *
- * Copyright (C) 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
- *
- * Initially based on sound/soc/omap/osk5912.x
- * Copyright (C) 2008 Mistral Solutions
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/spinlock.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "../codecs/cx20442.h"
-
-/* Board specific DAPM widgets */
-static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
-       /* Handset */
-       SND_SOC_DAPM_MIC("Mouthpiece", NULL),
-       SND_SOC_DAPM_HP("Earpiece", NULL),
-       /* Handsfree/Speakerphone */
-       SND_SOC_DAPM_MIC("Microphone", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/* How they are connected to codec pins */
-static const struct snd_soc_dapm_route ams_delta_audio_map[] = {
-       {"TELIN", NULL, "Mouthpiece"},
-       {"Earpiece", NULL, "TELOUT"},
-
-       {"MIC", NULL, "Microphone"},
-       {"Speaker", NULL, "SPKOUT"},
-};
-
-/*
- * Controls, functional after the modem line discipline is activated.
- */
-
-/* Virtual switch: audio input/output constellations */
-static const char *ams_delta_audio_mode[] =
-       {"Mixed", "Handset", "Handsfree", "Speakerphone"};
-
-/* Selection <-> pin translation */
-#define AMS_DELTA_MOUTHPIECE   0
-#define AMS_DELTA_EARPIECE     1
-#define AMS_DELTA_MICROPHONE   2
-#define AMS_DELTA_SPEAKER      3
-#define AMS_DELTA_AGC          4
-
-#define AMS_DELTA_MIXED                ((1 << AMS_DELTA_EARPIECE) | \
-                                               (1 << AMS_DELTA_MICROPHONE))
-#define AMS_DELTA_HANDSET      ((1 << AMS_DELTA_MOUTHPIECE) | \
-                                               (1 << AMS_DELTA_EARPIECE))
-#define AMS_DELTA_HANDSFREE    ((1 << AMS_DELTA_MICROPHONE) | \
-                                               (1 << AMS_DELTA_SPEAKER))
-#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
-
-static const unsigned short ams_delta_audio_mode_pins[] = {
-       AMS_DELTA_MIXED,
-       AMS_DELTA_HANDSET,
-       AMS_DELTA_HANDSFREE,
-       AMS_DELTA_SPEAKERPHONE,
-};
-
-static unsigned short ams_delta_audio_agc;
-
-/*
- * Used for passing a codec structure pointer
- * from the board initialization code to the tty line discipline.
- */
-static struct snd_soc_component *cx20442_codec;
-
-static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-       struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
-       unsigned short pins;
-       int pin, changed = 0;
-
-       /* Refuse any mode changes if we are not able to control the codec. */
-       if (!cx20442_codec->card->pop_time)
-               return -EUNATCH;
-
-       if (ucontrol->value.enumerated.item[0] >= control->items)
-               return -EINVAL;
-
-       snd_soc_dapm_mutex_lock(dapm);
-
-       /* Translate selection to bitmap */
-       pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
-
-       /* Setup pins after corresponding bits if changed */
-       pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
-
-       if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
-               changed = 1;
-               if (pin)
-                       snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
-               else
-                       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
-       }
-       pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
-       if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
-               changed = 1;
-               if (pin)
-                       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
-               else
-                       snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece");
-       }
-       pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
-       if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
-               changed = 1;
-               if (pin)
-                       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
-               else
-                       snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone");
-       }
-       pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
-       if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
-               changed = 1;
-               if (pin)
-                       snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
-               else
-                       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
-       }
-       pin = !!(pins & (1 << AMS_DELTA_AGC));
-       if (pin != ams_delta_audio_agc) {
-               ams_delta_audio_agc = pin;
-               changed = 1;
-               if (pin)
-                       snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
-               else
-                       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
-       }
-
-       if (changed)
-               snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-
-       return changed;
-}
-
-static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-       unsigned short pins, mode;
-
-       pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
-                                                       AMS_DELTA_MOUTHPIECE) |
-                       (snd_soc_dapm_get_pin_status(dapm, "Earpiece") <<
-                                                       AMS_DELTA_EARPIECE));
-       if (pins)
-               pins |= (snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
-                                                       AMS_DELTA_MICROPHONE);
-       else
-               pins = ((snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
-                                                       AMS_DELTA_MICROPHONE) |
-                       (snd_soc_dapm_get_pin_status(dapm, "Speaker") <<
-                                                       AMS_DELTA_SPEAKER) |
-                       (ams_delta_audio_agc << AMS_DELTA_AGC));
-
-       for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++)
-               if (pins == ams_delta_audio_mode_pins[mode])
-                       break;
-
-       if (mode >= ARRAY_SIZE(ams_delta_audio_mode))
-               return -EINVAL;
-
-       ucontrol->value.enumerated.item[0] = mode;
-
-       return 0;
-}
-
-static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
-                                     ams_delta_audio_mode);
-
-static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
-       SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
-                       ams_delta_get_audio_mode, ams_delta_set_audio_mode),
-};
-
-/* Hook switch */
-static struct snd_soc_jack ams_delta_hook_switch;
-static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = {
-       {
-               .name = "hook_switch",
-               .report = SND_JACK_HEADSET,
-               .invert = 1,
-               .debounce_time = 150,
-       }
-};
-
-/* After we are able to control the codec over the modem,
- * the hook switch can be used for dynamic DAPM reconfiguration. */
-static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = {
-       /* Handset */
-       {
-               .pin = "Mouthpiece",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Earpiece",
-               .mask = SND_JACK_HEADPHONE,
-       },
-       /* Handsfree */
-       {
-               .pin = "Microphone",
-               .mask = SND_JACK_MICROPHONE,
-               .invert = 1,
-       },
-       {
-               .pin = "Speaker",
-               .mask = SND_JACK_HEADPHONE,
-               .invert = 1,
-       },
-};
-
-
-/*
- * Modem line discipline, required for making above controls functional.
- * Activated from userspace with ldattach, possibly invoked from udev rule.
- */
-
-/* To actually apply any modem controlled configuration changes to the codec,
- * we must connect codec DAI pins to the modem for a moment.  Be careful not
- * to interfere with our digital mute function that shares the same hardware. */
-static struct timer_list cx81801_timer;
-static bool cx81801_cmd_pending;
-static bool ams_delta_muted;
-static DEFINE_SPINLOCK(ams_delta_lock);
-static struct gpio_desc *gpiod_modem_codec;
-
-static void cx81801_timeout(struct timer_list *unused)
-{
-       int muted;
-
-       spin_lock(&ams_delta_lock);
-       cx81801_cmd_pending = 0;
-       muted = ams_delta_muted;
-       spin_unlock(&ams_delta_lock);
-
-       /* Reconnect the codec DAI back from the modem to the CPU DAI
-        * only if digital mute still off */
-       if (!muted)
-               gpiod_set_value(gpiod_modem_codec, 0);
-}
-
-/* Line discipline .open() */
-static int cx81801_open(struct tty_struct *tty)
-{
-       int ret;
-
-       if (!cx20442_codec)
-               return -ENODEV;
-
-       /*
-        * Pass the codec structure pointer for use by other ldisc callbacks,
-        * both the card and the codec specific parts.
-        */
-       tty->disc_data = cx20442_codec;
-
-       ret = v253_ops.open(tty);
-
-       if (ret < 0)
-               tty->disc_data = NULL;
-
-       return ret;
-}
-
-/* Line discipline .close() */
-static void cx81801_close(struct tty_struct *tty)
-{
-       struct snd_soc_component *component = tty->disc_data;
-       struct snd_soc_dapm_context *dapm = &component->card->dapm;
-
-       del_timer_sync(&cx81801_timer);
-
-       /* Prevent the hook switch from further changing the DAPM pins */
-       INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
-
-       if (!component)
-               return;
-
-       v253_ops.close(tty);
-
-       /* Revert back to default audio input/output constellation */
-       snd_soc_dapm_mutex_lock(dapm);
-
-       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
-       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
-       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
-
-       snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-}
-
-/* Line discipline .hangup() */
-static int cx81801_hangup(struct tty_struct *tty)
-{
-       cx81801_close(tty);
-       return 0;
-}
-
-/* Line discipline .receive_buf() */
-static void cx81801_receive(struct tty_struct *tty,
-                               const unsigned char *cp, char *fp, int count)
-{
-       struct snd_soc_component *component = tty->disc_data;
-       const unsigned char *c;
-       int apply, ret;
-
-       if (!component)
-               return;
-
-       if (!component->card->pop_time) {
-               /* First modem response, complete setup procedure */
-
-               /* Initialize timer used for config pulse generation */
-               timer_setup(&cx81801_timer, cx81801_timeout, 0);
-
-               v253_ops.receive_buf(tty, cp, fp, count);
-
-               /* Link hook switch to DAPM pins */
-               ret = snd_soc_jack_add_pins(&ams_delta_hook_switch,
-                                       ARRAY_SIZE(ams_delta_hook_switch_pins),
-                                       ams_delta_hook_switch_pins);
-               if (ret)
-                       dev_warn(component->dev,
-                               "Failed to link hook switch to DAPM pins, "
-                               "will continue with hook switch unlinked.\n");
-
-               return;
-       }
-
-       v253_ops.receive_buf(tty, cp, fp, count);
-
-       for (c = &cp[count - 1]; c >= cp; c--) {
-               if (*c != '\r')
-                       continue;
-               /* Complete modem response received, apply config to codec */
-
-               spin_lock_bh(&ams_delta_lock);
-               mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150));
-               apply = !ams_delta_muted && !cx81801_cmd_pending;
-               cx81801_cmd_pending = 1;
-               spin_unlock_bh(&ams_delta_lock);
-
-               /* Apply config pulse by connecting the codec to the modem
-                * if not already done */
-               if (apply)
-                       gpiod_set_value(gpiod_modem_codec, 1);
-               break;
-       }
-}
-
-/* Line discipline .write_wakeup() */
-static void cx81801_wakeup(struct tty_struct *tty)
-{
-       v253_ops.write_wakeup(tty);
-}
-
-static struct tty_ldisc_ops cx81801_ops = {
-       .magic = TTY_LDISC_MAGIC,
-       .name = "cx81801",
-       .owner = THIS_MODULE,
-       .open = cx81801_open,
-       .close = cx81801_close,
-       .hangup = cx81801_hangup,
-       .receive_buf = cx81801_receive,
-       .write_wakeup = cx81801_wakeup,
-};
-
-
-/*
- * Even if not very useful, the sound card can still work without any of the
- * above functonality activated.  You can still control its audio input/output
- * constellation and speakerphone gain from userspace by issuing AT commands
- * over the modem port.
- */
-
-static struct snd_soc_ops ams_delta_ops;
-
-
-/* Digital mute implemented using modem/CPU multiplexer.
- * Shares hardware with codec config pulse generation */
-static bool ams_delta_muted = 1;
-
-static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute)
-{
-       int apply;
-
-       if (ams_delta_muted == mute)
-               return 0;
-
-       spin_lock_bh(&ams_delta_lock);
-       ams_delta_muted = mute;
-       apply = !cx81801_cmd_pending;
-       spin_unlock_bh(&ams_delta_lock);
-
-       if (apply)
-               gpiod_set_value(gpiod_modem_codec, !!mute);
-       return 0;
-}
-
-/* Our codec DAI probably doesn't have its own .ops structure */
-static const struct snd_soc_dai_ops ams_delta_dai_ops = {
-       .digital_mute = ams_delta_digital_mute,
-};
-
-/* Will be used if the codec ever has its own digital_mute function */
-static int ams_delta_startup(struct snd_pcm_substream *substream)
-{
-       return ams_delta_digital_mute(NULL, 0);
-}
-
-static void ams_delta_shutdown(struct snd_pcm_substream *substream)
-{
-       ams_delta_digital_mute(NULL, 1);
-}
-
-
-/*
- * Card initialization
- */
-
-static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_card *card = rtd->card;
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-       int ret;
-       /* Codec is ready, now add/activate board specific controls */
-
-       /* Store a pointer to the codec structure for tty ldisc use */
-       cx20442_codec = rtd->codec_dai->component;
-
-       /* Add hook switch - can be used to control the codec from userspace
-        * even if line discipline fails */
-       ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET,
-                                   &ams_delta_hook_switch, NULL, 0);
-       if (ret)
-               dev_warn(card->dev,
-                               "Failed to allocate resources for hook switch, "
-                               "will continue without one.\n");
-       else {
-               ret = snd_soc_jack_add_gpiods(card->dev, &ams_delta_hook_switch,
-                                       ARRAY_SIZE(ams_delta_hook_switch_gpios),
-                                       ams_delta_hook_switch_gpios);
-               if (ret)
-                       dev_warn(card->dev,
-                               "Failed to set up hook switch GPIO line, "
-                               "will continue with hook switch inactive.\n");
-       }
-
-       gpiod_modem_codec = devm_gpiod_get(card->dev, "modem_codec",
-                                          GPIOD_OUT_HIGH);
-       if (IS_ERR(gpiod_modem_codec)) {
-               dev_warn(card->dev, "Failed to obtain modem_codec GPIO\n");
-               return 0;
-       }
-
-       /* Set up digital mute if not provided by the codec */
-       if (!codec_dai->driver->ops) {
-               codec_dai->driver->ops = &ams_delta_dai_ops;
-       } else {
-               ams_delta_ops.startup = ams_delta_startup;
-               ams_delta_ops.shutdown = ams_delta_shutdown;
-       }
-
-       /* Register optional line discipline for over the modem control */
-       ret = tty_register_ldisc(N_V253, &cx81801_ops);
-       if (ret) {
-               dev_warn(card->dev,
-                               "Failed to register line discipline, "
-                               "will continue without any controls.\n");
-               return 0;
-       }
-
-       /* Set up initial pin constellation */
-       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
-       snd_soc_dapm_disable_pin(dapm, "Speaker");
-       snd_soc_dapm_disable_pin(dapm, "AGCIN");
-       snd_soc_dapm_disable_pin(dapm, "AGCOUT");
-
-       return 0;
-}
-
-/* DAI glue - connects codec <--> CPU */
-static struct snd_soc_dai_link ams_delta_dai_link = {
-       .name = "CX20442",
-       .stream_name = "CX20442",
-       .cpu_dai_name = "omap-mcbsp.1",
-       .codec_dai_name = "cx20442-voice",
-       .init = ams_delta_cx20442_init,
-       .platform_name = "omap-mcbsp.1",
-       .codec_name = "cx20442-codec",
-       .ops = &ams_delta_ops,
-       .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-};
-
-/* Audio card driver */
-static struct snd_soc_card ams_delta_audio_card = {
-       .name = "AMS_DELTA",
-       .owner = THIS_MODULE,
-       .dai_link = &ams_delta_dai_link,
-       .num_links = 1,
-
-       .controls = ams_delta_audio_controls,
-       .num_controls = ARRAY_SIZE(ams_delta_audio_controls),
-       .dapm_widgets = ams_delta_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
-       .dapm_routes = ams_delta_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
-};
-
-/* Module init/exit */
-static int ams_delta_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &ams_delta_audio_card;
-       int ret;
-
-       card->dev = &pdev->dev;
-
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-               card->dev = NULL;
-               return ret;
-       }
-       return 0;
-}
-
-static int ams_delta_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       if (tty_unregister_ldisc(N_V253) != 0)
-               dev_warn(&pdev->dev,
-                       "failed to unregister V253 line discipline\n");
-
-       snd_soc_unregister_card(card);
-       card->dev = NULL;
-       return 0;
-}
-
-#define DRV_NAME "ams-delta-audio"
-
-static struct platform_driver ams_delta_driver = {
-       .driver = {
-               .name = DRV_NAME,
-       },
-       .probe = ams_delta_probe,
-       .remove = ams_delta_remove,
-};
-
-module_platform_driver(ams_delta_driver);
-
-MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
-MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
deleted file mode 100644 (file)
index 79d4dc7..0000000
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * sound/soc/omap/mcbsp.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Multichannel mode not supported.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "mcbsp.h"
-
-static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
-       void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
-       if (mcbsp->pdata->reg_size == 2) {
-               ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
-               writew_relaxed((u16)val, addr);
-       } else {
-               ((u32 *)mcbsp->reg_cache)[reg] = val;
-               writel_relaxed(val, addr);
-       }
-}
-
-static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
-{
-       void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
-       if (mcbsp->pdata->reg_size == 2) {
-               return !from_cache ? readw_relaxed(addr) :
-                                    ((u16 *)mcbsp->reg_cache)[reg];
-       } else {
-               return !from_cache ? readl_relaxed(addr) :
-                                    ((u32 *)mcbsp->reg_cache)[reg];
-       }
-}
-
-static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
-       writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
-}
-
-static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
-{
-       return readl_relaxed(mcbsp->st_data->io_base_st + reg);
-}
-
-#define MCBSP_READ(mcbsp, reg) \
-               omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
-#define MCBSP_WRITE(mcbsp, reg, val) \
-               omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
-#define MCBSP_READ_CACHE(mcbsp, reg) \
-               omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-
-#define MCBSP_ST_READ(mcbsp, reg) \
-                       omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
-#define MCBSP_ST_WRITE(mcbsp, reg, val) \
-                       omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
-
-static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
-{
-       dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
-       dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n",
-                       MCBSP_READ(mcbsp, DRR2));
-       dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n",
-                       MCBSP_READ(mcbsp, DRR1));
-       dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n",
-                       MCBSP_READ(mcbsp, DXR2));
-       dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n",
-                       MCBSP_READ(mcbsp, DXR1));
-       dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
-                       MCBSP_READ(mcbsp, SPCR2));
-       dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
-                       MCBSP_READ(mcbsp, SPCR1));
-       dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n",
-                       MCBSP_READ(mcbsp, RCR2));
-       dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n",
-                       MCBSP_READ(mcbsp, RCR1));
-       dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n",
-                       MCBSP_READ(mcbsp, XCR2));
-       dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n",
-                       MCBSP_READ(mcbsp, XCR1));
-       dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
-                       MCBSP_READ(mcbsp, SRGR2));
-       dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
-                       MCBSP_READ(mcbsp, SRGR1));
-       dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n",
-                       MCBSP_READ(mcbsp, PCR0));
-       dev_dbg(mcbsp->dev, "***********************\n");
-}
-
-static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id)
-{
-       struct omap_mcbsp *mcbsp = dev_id;
-       u16 irqst;
-
-       irqst = MCBSP_READ(mcbsp, IRQST);
-       dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
-
-       if (irqst & RSYNCERREN)
-               dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
-       if (irqst & RFSREN)
-               dev_dbg(mcbsp->dev, "RX Frame Sync\n");
-       if (irqst & REOFEN)
-               dev_dbg(mcbsp->dev, "RX End Of Frame\n");
-       if (irqst & RRDYEN)
-               dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
-       if (irqst & RUNDFLEN)
-               dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
-       if (irqst & ROVFLEN)
-               dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
-
-       if (irqst & XSYNCERREN)
-               dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
-       if (irqst & XFSXEN)
-               dev_dbg(mcbsp->dev, "TX Frame Sync\n");
-       if (irqst & XEOFEN)
-               dev_dbg(mcbsp->dev, "TX End Of Frame\n");
-       if (irqst & XRDYEN)
-               dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
-       if (irqst & XUNDFLEN)
-               dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
-       if (irqst & XOVFLEN)
-               dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
-       if (irqst & XEMPTYEOFEN)
-               dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
-
-       MCBSP_WRITE(mcbsp, IRQST, irqst);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
-{
-       struct omap_mcbsp *mcbsp_tx = dev_id;
-       u16 irqst_spcr2;
-
-       irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
-       dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
-
-       if (irqst_spcr2 & XSYNC_ERR) {
-               dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
-                       irqst_spcr2);
-               /* Writing zero to XSYNC_ERR clears the IRQ */
-               MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
-       }
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
-{
-       struct omap_mcbsp *mcbsp_rx = dev_id;
-       u16 irqst_spcr1;
-
-       irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
-       dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
-
-       if (irqst_spcr1 & RSYNC_ERR) {
-               dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
-                       irqst_spcr1);
-               /* Writing zero to RSYNC_ERR clears the IRQ */
-               MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*
- * omap_mcbsp_config simply write a config to the
- * appropriate McBSP.
- * You either call this function or set the McBSP registers
- * by yourself before calling omap_mcbsp_start().
- */
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
-                      const struct omap_mcbsp_reg_cfg *config)
-{
-       dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
-                       mcbsp->id, mcbsp->phys_base);
-
-       /* We write the given config */
-       MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
-       MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
-       MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
-       MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
-       MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
-       MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
-       MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
-       MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
-       MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
-       MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
-       MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
-       if (mcbsp->pdata->has_ccr) {
-               MCBSP_WRITE(mcbsp, XCCR, config->xccr);
-               MCBSP_WRITE(mcbsp, RCCR, config->rccr);
-       }
-       /* Enable wakeup behavior */
-       if (mcbsp->pdata->has_wakeup)
-               MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
-
-       /* Enable TX/RX sync error interrupts by default */
-       if (mcbsp->irq)
-               MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
-                           RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
-}
-
-/**
- * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
- * @id - mcbsp id
- * @stream - indicates the direction of data flow (rx or tx)
- *
- * Returns the address of mcbsp data transmit register or data receive register
- * to be used by DMA for transferring/receiving data based on the value of
- * @stream for the requested mcbsp given by @id
- */
-static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
-                                    unsigned int stream)
-{
-       int data_reg;
-
-       if (mcbsp->pdata->reg_size == 2) {
-               if (stream)
-                       data_reg = OMAP_MCBSP_REG_DRR1;
-               else
-                       data_reg = OMAP_MCBSP_REG_DXR1;
-       } else {
-               if (stream)
-                       data_reg = OMAP_MCBSP_REG_DRR;
-               else
-                       data_reg = OMAP_MCBSP_REG_DXR;
-       }
-
-       return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
-}
-
-static void omap_st_on(struct omap_mcbsp *mcbsp)
-{
-       unsigned int w;
-
-       if (mcbsp->pdata->force_ick_on)
-               mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
-
-       /* Disable Sidetone clock auto-gating for normal operation */
-       w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
-       MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
-
-       /* Enable McBSP Sidetone */
-       w = MCBSP_READ(mcbsp, SSELCR);
-       MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
-
-       /* Enable Sidetone from Sidetone Core */
-       w = MCBSP_ST_READ(mcbsp, SSELCR);
-       MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
-}
-
-static void omap_st_off(struct omap_mcbsp *mcbsp)
-{
-       unsigned int w;
-
-       w = MCBSP_ST_READ(mcbsp, SSELCR);
-       MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
-
-       w = MCBSP_READ(mcbsp, SSELCR);
-       MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
-
-       /* Enable Sidetone clock auto-gating to reduce power consumption */
-       w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
-       MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
-
-       if (mcbsp->pdata->force_ick_on)
-               mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
-}
-
-static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
-{
-       u16 val, i;
-
-       val = MCBSP_ST_READ(mcbsp, SSELCR);
-
-       if (val & ST_COEFFWREN)
-               MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
-       MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
-
-       for (i = 0; i < 128; i++)
-               MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
-
-       i = 0;
-
-       val = MCBSP_ST_READ(mcbsp, SSELCR);
-       while (!(val & ST_COEFFWRDONE) && (++i < 1000))
-               val = MCBSP_ST_READ(mcbsp, SSELCR);
-
-       MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
-       if (i == 1000)
-               dev_err(mcbsp->dev, "McBSP FIR load error!\n");
-}
-
-static void omap_st_chgain(struct omap_mcbsp *mcbsp)
-{
-       u16 w;
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-       w = MCBSP_ST_READ(mcbsp, SSELCR);
-
-       MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
-                     ST_CH1GAIN(st_data->ch1gain));
-}
-
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-       int ret = 0;
-
-       if (!st_data)
-               return -ENOENT;
-
-       spin_lock_irq(&mcbsp->lock);
-       if (channel == 0)
-               st_data->ch0gain = chgain;
-       else if (channel == 1)
-               st_data->ch1gain = chgain;
-       else
-               ret = -EINVAL;
-
-       if (st_data->enabled)
-               omap_st_chgain(mcbsp);
-       spin_unlock_irq(&mcbsp->lock);
-
-       return ret;
-}
-
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-       int ret = 0;
-
-       if (!st_data)
-               return -ENOENT;
-
-       spin_lock_irq(&mcbsp->lock);
-       if (channel == 0)
-               *chgain = st_data->ch0gain;
-       else if (channel == 1)
-               *chgain = st_data->ch1gain;
-       else
-               ret = -EINVAL;
-       spin_unlock_irq(&mcbsp->lock);
-
-       return ret;
-}
-
-static int omap_st_start(struct omap_mcbsp *mcbsp)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-       if (st_data->enabled && !st_data->running) {
-               omap_st_fir_write(mcbsp, st_data->taps);
-               omap_st_chgain(mcbsp);
-
-               if (!mcbsp->free) {
-                       omap_st_on(mcbsp);
-                       st_data->running = 1;
-               }
-       }
-
-       return 0;
-}
-
-int omap_st_enable(struct omap_mcbsp *mcbsp)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-       if (!st_data)
-               return -ENODEV;
-
-       spin_lock_irq(&mcbsp->lock);
-       st_data->enabled = 1;
-       omap_st_start(mcbsp);
-       spin_unlock_irq(&mcbsp->lock);
-
-       return 0;
-}
-
-static int omap_st_stop(struct omap_mcbsp *mcbsp)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-       if (st_data->running) {
-               if (!mcbsp->free) {
-                       omap_st_off(mcbsp);
-                       st_data->running = 0;
-               }
-       }
-
-       return 0;
-}
-
-int omap_st_disable(struct omap_mcbsp *mcbsp)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-       int ret = 0;
-
-       if (!st_data)
-               return -ENODEV;
-
-       spin_lock_irq(&mcbsp->lock);
-       omap_st_stop(mcbsp);
-       st_data->enabled = 0;
-       spin_unlock_irq(&mcbsp->lock);
-
-       return ret;
-}
-
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
-{
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-       if (!st_data)
-               return -ENODEV;
-
-       return st_data->enabled;
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH2 register.
- */
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
-       if (mcbsp->pdata->buffer_size == 0)
-               return;
-
-       if (threshold && threshold <= mcbsp->max_tx_thres)
-               MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH1 register.
- */
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
-       if (mcbsp->pdata->buffer_size == 0)
-               return;
-
-       if (threshold && threshold <= mcbsp->max_rx_thres)
-               MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
-}
-
-/*
- * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
- */
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
-{
-       u16 buffstat;
-
-       if (mcbsp->pdata->buffer_size == 0)
-               return 0;
-
-       /* Returns the number of free locations in the buffer */
-       buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
-
-       /* Number of slots are different in McBSP ports */
-       return mcbsp->pdata->buffer_size - buffstat;
-}
-
-/*
- * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
- * to reach the threshold value (when the DMA will be triggered to read it)
- */
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
-{
-       u16 buffstat, threshold;
-
-       if (mcbsp->pdata->buffer_size == 0)
-               return 0;
-
-       /* Returns the number of used locations in the buffer */
-       buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
-       /* RX threshold */
-       threshold = MCBSP_READ(mcbsp, THRSH1);
-
-       /* Return the number of location till we reach the threshold limit */
-       if (threshold <= buffstat)
-               return 0;
-       else
-               return threshold - buffstat;
-}
-
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
-{
-       void *reg_cache;
-       int err;
-
-       reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
-       if (!reg_cache) {
-               return -ENOMEM;
-       }
-
-       spin_lock(&mcbsp->lock);
-       if (!mcbsp->free) {
-               dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
-                       mcbsp->id);
-               err = -EBUSY;
-               goto err_kfree;
-       }
-
-       mcbsp->free = false;
-       mcbsp->reg_cache = reg_cache;
-       spin_unlock(&mcbsp->lock);
-
-       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
-               mcbsp->pdata->ops->request(mcbsp->id - 1);
-
-       /*
-        * Make sure that transmitter, receiver and sample-rate generator are
-        * not running before activating IRQs.
-        */
-       MCBSP_WRITE(mcbsp, SPCR1, 0);
-       MCBSP_WRITE(mcbsp, SPCR2, 0);
-
-       if (mcbsp->irq) {
-               err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
-                                 "McBSP", (void *)mcbsp);
-               if (err != 0) {
-                       dev_err(mcbsp->dev, "Unable to request IRQ\n");
-                       goto err_clk_disable;
-               }
-       } else {
-               err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
-                                 "McBSP TX", (void *)mcbsp);
-               if (err != 0) {
-                       dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
-                       goto err_clk_disable;
-               }
-
-               err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
-                                 "McBSP RX", (void *)mcbsp);
-               if (err != 0) {
-                       dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
-                       goto err_free_irq;
-               }
-       }
-
-       return 0;
-err_free_irq:
-       free_irq(mcbsp->tx_irq, (void *)mcbsp);
-err_clk_disable:
-       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
-               mcbsp->pdata->ops->free(mcbsp->id - 1);
-
-       /* Disable wakeup behavior */
-       if (mcbsp->pdata->has_wakeup)
-               MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
-       spin_lock(&mcbsp->lock);
-       mcbsp->free = true;
-       mcbsp->reg_cache = NULL;
-err_kfree:
-       spin_unlock(&mcbsp->lock);
-       kfree(reg_cache);
-
-       return err;
-}
-
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
-{
-       void *reg_cache;
-
-       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
-               mcbsp->pdata->ops->free(mcbsp->id - 1);
-
-       /* Disable wakeup behavior */
-       if (mcbsp->pdata->has_wakeup)
-               MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
-       /* Disable interrupt requests */
-       if (mcbsp->irq)
-               MCBSP_WRITE(mcbsp, IRQEN, 0);
-
-       if (mcbsp->irq) {
-               free_irq(mcbsp->irq, (void *)mcbsp);
-       } else {
-               free_irq(mcbsp->rx_irq, (void *)mcbsp);
-               free_irq(mcbsp->tx_irq, (void *)mcbsp);
-       }
-
-       reg_cache = mcbsp->reg_cache;
-
-       /*
-        * Select CLKS source from internal source unconditionally before
-        * marking the McBSP port as free.
-        * If the external clock source via MCBSP_CLKS pin has been selected the
-        * system will refuse to enter idle if the CLKS pin source is not reset
-        * back to internal source.
-        */
-       if (!mcbsp_omap1())
-               omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
-
-       spin_lock(&mcbsp->lock);
-       if (mcbsp->free)
-               dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
-       else
-               mcbsp->free = true;
-       mcbsp->reg_cache = NULL;
-       spin_unlock(&mcbsp->lock);
-
-       kfree(reg_cache);
-}
-
-/*
- * Here we start the McBSP, by enabling transmitter, receiver or both.
- * If no transmitter or receiver is active prior calling, then sample-rate
- * generator and frame sync are started.
- */
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
-       int enable_srg = 0;
-       u16 w;
-
-       if (mcbsp->st_data)
-               omap_st_start(mcbsp);
-
-       /* Only enable SRG, if McBSP is master */
-       w = MCBSP_READ_CACHE(mcbsp, PCR0);
-       if (w & (FSXM | FSRM | CLKXM | CLKRM))
-               enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-                               MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
-       if (enable_srg) {
-               /* Start the sample generator */
-               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-               MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
-       }
-
-       /* Enable transmitter and receiver */
-       tx &= 1;
-       w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-       MCBSP_WRITE(mcbsp, SPCR2, w | tx);
-
-       rx &= 1;
-       w = MCBSP_READ_CACHE(mcbsp, SPCR1);
-       MCBSP_WRITE(mcbsp, SPCR1, w | rx);
-
-       /*
-        * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
-        * REVISIT: 100us may give enough time for two CLKSRG, however
-        * due to some unknown PM related, clock gating etc. reason it
-        * is now at 500us.
-        */
-       udelay(500);
-
-       if (enable_srg) {
-               /* Start frame sync */
-               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-               MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
-       }
-
-       if (mcbsp->pdata->has_ccr) {
-               /* Release the transmitter and receiver */
-               w = MCBSP_READ_CACHE(mcbsp, XCCR);
-               w &= ~(tx ? XDISABLE : 0);
-               MCBSP_WRITE(mcbsp, XCCR, w);
-               w = MCBSP_READ_CACHE(mcbsp, RCCR);
-               w &= ~(rx ? RDISABLE : 0);
-               MCBSP_WRITE(mcbsp, RCCR, w);
-       }
-
-       /* Dump McBSP Regs */
-       omap_mcbsp_dump_reg(mcbsp);
-}
-
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
-       int idle;
-       u16 w;
-
-       /* Reset transmitter */
-       tx &= 1;
-       if (mcbsp->pdata->has_ccr) {
-               w = MCBSP_READ_CACHE(mcbsp, XCCR);
-               w |= (tx ? XDISABLE : 0);
-               MCBSP_WRITE(mcbsp, XCCR, w);
-       }
-       w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-       MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
-
-       /* Reset receiver */
-       rx &= 1;
-       if (mcbsp->pdata->has_ccr) {
-               w = MCBSP_READ_CACHE(mcbsp, RCCR);
-               w |= (rx ? RDISABLE : 0);
-               MCBSP_WRITE(mcbsp, RCCR, w);
-       }
-       w = MCBSP_READ_CACHE(mcbsp, SPCR1);
-       MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
-
-       idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-                       MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
-       if (idle) {
-               /* Reset the sample rate generator */
-               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-               MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
-       }
-
-       if (mcbsp->st_data)
-               omap_st_stop(mcbsp);
-}
-
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
-{
-       struct clk *fck_src;
-       const char *src;
-       int r;
-
-       if (fck_src_id == MCBSP_CLKS_PAD_SRC)
-               src = "pad_fck";
-       else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
-               src = "prcm_fck";
-       else
-               return -EINVAL;
-
-       fck_src = clk_get(mcbsp->dev, src);
-       if (IS_ERR(fck_src)) {
-               dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
-               return -EINVAL;
-       }
-
-       pm_runtime_put_sync(mcbsp->dev);
-
-       r = clk_set_parent(mcbsp->fclk, fck_src);
-       if (r) {
-               dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
-                       src);
-               clk_put(fck_src);
-               return r;
-       }
-
-       pm_runtime_get_sync(mcbsp->dev);
-
-       clk_put(fck_src);
-
-       return 0;
-
-}
-
-#define max_thres(m)                   (mcbsp->pdata->buffer_size)
-#define valid_threshold(m, val)                ((val) <= max_thres(m))
-#define THRESHOLD_PROP_BUILDER(prop)                                   \
-static ssize_t prop##_show(struct device *dev,                         \
-                       struct device_attribute *attr, char *buf)       \
-{                                                                      \
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);                \
-                                                                       \
-       return sprintf(buf, "%u\n", mcbsp->prop);                       \
-}                                                                      \
-                                                                       \
-static ssize_t prop##_store(struct device *dev,                                \
-                               struct device_attribute *attr,          \
-                               const char *buf, size_t size)           \
-{                                                                      \
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);                \
-       unsigned long val;                                              \
-       int status;                                                     \
-                                                                       \
-       status = kstrtoul(buf, 0, &val);                                \
-       if (status)                                                     \
-               return status;                                          \
-                                                                       \
-       if (!valid_threshold(mcbsp, val))                               \
-               return -EDOM;                                           \
-                                                                       \
-       mcbsp->prop = val;                                              \
-       return size;                                                    \
-}                                                                      \
-                                                                       \
-static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
-
-THRESHOLD_PROP_BUILDER(max_tx_thres);
-THRESHOLD_PROP_BUILDER(max_rx_thres);
-
-static const char *dma_op_modes[] = {
-       "element", "threshold",
-};
-
-static ssize_t dma_op_mode_show(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-       int dma_op_mode, i = 0;
-       ssize_t len = 0;
-       const char * const *s;
-
-       dma_op_mode = mcbsp->dma_op_mode;
-
-       for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
-               if (dma_op_mode == i)
-                       len += sprintf(buf + len, "[%s] ", *s);
-               else
-                       len += sprintf(buf + len, "%s ", *s);
-       }
-       len += sprintf(buf + len, "\n");
-
-       return len;
-}
-
-static ssize_t dma_op_mode_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t size)
-{
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-       int i;
-
-       i = sysfs_match_string(dma_op_modes, buf);
-       if (i < 0)
-               return i;
-
-       spin_lock_irq(&mcbsp->lock);
-       if (!mcbsp->free) {
-               size = -EBUSY;
-               goto unlock;
-       }
-       mcbsp->dma_op_mode = i;
-
-unlock:
-       spin_unlock_irq(&mcbsp->lock);
-
-       return size;
-}
-
-static DEVICE_ATTR_RW(dma_op_mode);
-
-static const struct attribute *additional_attrs[] = {
-       &dev_attr_max_tx_thres.attr,
-       &dev_attr_max_rx_thres.attr,
-       &dev_attr_dma_op_mode.attr,
-       NULL,
-};
-
-static const struct attribute_group additional_attr_group = {
-       .attrs = (struct attribute **)additional_attrs,
-};
-
-static ssize_t st_taps_show(struct device *dev,
-                           struct device_attribute *attr, char *buf)
-{
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-       ssize_t status = 0;
-       int i;
-
-       spin_lock_irq(&mcbsp->lock);
-       for (i = 0; i < st_data->nr_taps; i++)
-               status += sprintf(&buf[status], (i ? ", %d" : "%d"),
-                                 st_data->taps[i]);
-       if (i)
-               status += sprintf(&buf[status], "\n");
-       spin_unlock_irq(&mcbsp->lock);
-
-       return status;
-}
-
-static ssize_t st_taps_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t size)
-{
-       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-       int val, tmp, status, i = 0;
-
-       spin_lock_irq(&mcbsp->lock);
-       memset(st_data->taps, 0, sizeof(st_data->taps));
-       st_data->nr_taps = 0;
-
-       do {
-               status = sscanf(buf, "%d%n", &val, &tmp);
-               if (status < 0 || status == 0) {
-                       size = -EINVAL;
-                       goto out;
-               }
-               if (val < -32768 || val > 32767) {
-                       size = -EINVAL;
-                       goto out;
-               }
-               st_data->taps[i++] = val;
-               buf += tmp;
-               if (*buf != ',')
-                       break;
-               buf++;
-       } while (1);
-
-       st_data->nr_taps = i;
-
-out:
-       spin_unlock_irq(&mcbsp->lock);
-
-       return size;
-}
-
-static DEVICE_ATTR_RW(st_taps);
-
-static const struct attribute *sidetone_attrs[] = {
-       &dev_attr_st_taps.attr,
-       NULL,
-};
-
-static const struct attribute_group sidetone_attr_group = {
-       .attrs = (struct attribute **)sidetone_attrs,
-};
-
-static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
-{
-       struct omap_mcbsp_st_data *st_data;
-       int err;
-
-       st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
-       if (!st_data)
-               return -ENOMEM;
-
-       st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
-       if (IS_ERR(st_data->mcbsp_iclk)) {
-               dev_warn(mcbsp->dev,
-                        "Failed to get ick, sidetone might be broken\n");
-               st_data->mcbsp_iclk = NULL;
-       }
-
-       st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
-                                          resource_size(res));
-       if (!st_data->io_base_st)
-               return -ENOMEM;
-
-       err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-       if (err)
-               return err;
-
-       mcbsp->st_data = st_data;
-       return 0;
-}
-
-/*
- * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
- * 730 has only 2 McBSP, and both of them are MPU peripherals.
- */
-int omap_mcbsp_init(struct platform_device *pdev)
-{
-       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-       struct resource *res;
-       int ret = 0;
-
-       spin_lock_init(&mcbsp->lock);
-       mcbsp->free = true;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       if (!res)
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mcbsp->io_base))
-               return PTR_ERR(mcbsp->io_base);
-
-       mcbsp->phys_base = res->start;
-       mcbsp->reg_cache_size = resource_size(res);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
-       if (!res)
-               mcbsp->phys_dma_base = mcbsp->phys_base;
-       else
-               mcbsp->phys_dma_base = res->start;
-
-       /*
-        * OMAP1, 2 uses two interrupt lines: TX, RX
-        * OMAP2430, OMAP3 SoC have combined IRQ line as well.
-        * OMAP4 and newer SoC only have the combined IRQ line.
-        * Use the combined IRQ if available since it gives better debugging
-        * possibilities.
-        */
-       mcbsp->irq = platform_get_irq_byname(pdev, "common");
-       if (mcbsp->irq == -ENXIO) {
-               mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
-
-               if (mcbsp->tx_irq == -ENXIO) {
-                       mcbsp->irq = platform_get_irq(pdev, 0);
-                       mcbsp->tx_irq = 0;
-               } else {
-                       mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
-                       mcbsp->irq = 0;
-               }
-       }
-
-       if (!pdev->dev.of_node) {
-               res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
-               if (!res) {
-                       dev_err(&pdev->dev, "invalid tx DMA channel\n");
-                       return -ENODEV;
-               }
-               mcbsp->dma_req[0] = res->start;
-               mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
-
-               res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
-               if (!res) {
-                       dev_err(&pdev->dev, "invalid rx DMA channel\n");
-                       return -ENODEV;
-               }
-               mcbsp->dma_req[1] = res->start;
-               mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
-       } else {
-               mcbsp->dma_data[0].filter_data = "tx";
-               mcbsp->dma_data[1].filter_data = "rx";
-       }
-
-       mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
-       mcbsp->dma_data[0].maxburst = 4;
-
-       mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
-       mcbsp->dma_data[1].maxburst = 4;
-
-       mcbsp->fclk = clk_get(&pdev->dev, "fck");
-       if (IS_ERR(mcbsp->fclk)) {
-               ret = PTR_ERR(mcbsp->fclk);
-               dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
-               return ret;
-       }
-
-       mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
-       if (mcbsp->pdata->buffer_size) {
-               /*
-                * Initially configure the maximum thresholds to a safe value.
-                * The McBSP FIFO usage with these values should not go under
-                * 16 locations.
-                * If the whole FIFO without safety buffer is used, than there
-                * is a possibility that the DMA will be not able to push the
-                * new data on time, causing channel shifts in runtime.
-                */
-               mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
-               mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
-
-               ret = sysfs_create_group(&mcbsp->dev->kobj,
-                                        &additional_attr_group);
-               if (ret) {
-                       dev_err(mcbsp->dev,
-                               "Unable to create additional controls\n");
-                       goto err_thres;
-               }
-       } else {
-               mcbsp->max_tx_thres = -EINVAL;
-               mcbsp->max_rx_thres = -EINVAL;
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
-       if (res) {
-               ret = omap_st_add(mcbsp, res);
-               if (ret) {
-                       dev_err(mcbsp->dev,
-                               "Unable to create sidetone controls\n");
-                       goto err_st;
-               }
-       }
-
-       return 0;
-
-err_st:
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-err_thres:
-       clk_put(mcbsp->fclk);
-       return ret;
-}
-
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp)
-{
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
-       if (mcbsp->st_data) {
-               sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-               clk_put(mcbsp->st_data->mcbsp_iclk);
-       }
-}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
deleted file mode 100644 (file)
index 46ae126..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * sound/soc/omap/mcbsp.h
- *
- * OMAP Multi-Channel Buffered Serial Port
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#ifndef __ASOC_MCBSP_H
-#define __ASOC_MCBSP_H
-
-#ifdef CONFIG_ARCH_OMAP1
-#define mcbsp_omap1()  1
-#else
-#define mcbsp_omap1()  0
-#endif
-
-#include <sound/dmaengine_pcm.h>
-
-/* McBSP register numbers. Register address offset = num * reg_step */
-enum {
-       /* Common registers */
-       OMAP_MCBSP_REG_SPCR2 = 4,
-       OMAP_MCBSP_REG_SPCR1,
-       OMAP_MCBSP_REG_RCR2,
-       OMAP_MCBSP_REG_RCR1,
-       OMAP_MCBSP_REG_XCR2,
-       OMAP_MCBSP_REG_XCR1,
-       OMAP_MCBSP_REG_SRGR2,
-       OMAP_MCBSP_REG_SRGR1,
-       OMAP_MCBSP_REG_MCR2,
-       OMAP_MCBSP_REG_MCR1,
-       OMAP_MCBSP_REG_RCERA,
-       OMAP_MCBSP_REG_RCERB,
-       OMAP_MCBSP_REG_XCERA,
-       OMAP_MCBSP_REG_XCERB,
-       OMAP_MCBSP_REG_PCR0,
-       OMAP_MCBSP_REG_RCERC,
-       OMAP_MCBSP_REG_RCERD,
-       OMAP_MCBSP_REG_XCERC,
-       OMAP_MCBSP_REG_XCERD,
-       OMAP_MCBSP_REG_RCERE,
-       OMAP_MCBSP_REG_RCERF,
-       OMAP_MCBSP_REG_XCERE,
-       OMAP_MCBSP_REG_XCERF,
-       OMAP_MCBSP_REG_RCERG,
-       OMAP_MCBSP_REG_RCERH,
-       OMAP_MCBSP_REG_XCERG,
-       OMAP_MCBSP_REG_XCERH,
-
-       /* OMAP1-OMAP2420 registers */
-       OMAP_MCBSP_REG_DRR2 = 0,
-       OMAP_MCBSP_REG_DRR1,
-       OMAP_MCBSP_REG_DXR2,
-       OMAP_MCBSP_REG_DXR1,
-
-       /* OMAP2430 and onwards */
-       OMAP_MCBSP_REG_DRR = 0,
-       OMAP_MCBSP_REG_DXR = 2,
-       OMAP_MCBSP_REG_SYSCON = 35,
-       OMAP_MCBSP_REG_THRSH2,
-       OMAP_MCBSP_REG_THRSH1,
-       OMAP_MCBSP_REG_IRQST = 40,
-       OMAP_MCBSP_REG_IRQEN,
-       OMAP_MCBSP_REG_WAKEUPEN,
-       OMAP_MCBSP_REG_XCCR,
-       OMAP_MCBSP_REG_RCCR,
-       OMAP_MCBSP_REG_XBUFFSTAT,
-       OMAP_MCBSP_REG_RBUFFSTAT,
-       OMAP_MCBSP_REG_SSELCR,
-};
-
-/* OMAP3 sidetone control registers */
-#define OMAP_ST_REG_REV                0x00
-#define OMAP_ST_REG_SYSCONFIG  0x10
-#define OMAP_ST_REG_IRQSTATUS  0x18
-#define OMAP_ST_REG_IRQENABLE  0x1C
-#define OMAP_ST_REG_SGAINCR    0x24
-#define OMAP_ST_REG_SFIRCR     0x28
-#define OMAP_ST_REG_SSELCR     0x2C
-
-/************************** McBSP SPCR1 bit definitions ***********************/
-#define RRST                   BIT(0)
-#define RRDY                   BIT(1)
-#define RFULL                  BIT(2)
-#define RSYNC_ERR              BIT(3)
-#define RINTM(value)           (((value) & 0x3) << 4)  /* bits 4:5 */
-#define ABIS                   BIT(6)
-#define DXENA                  BIT(7)
-#define CLKSTP(value)          (((value) & 0x3) << 11) /* bits 11:12 */
-#define RJUST(value)           (((value) & 0x3) << 13) /* bits 13:14 */
-#define ALB                    BIT(15)
-#define DLB                    BIT(15)
-
-/************************** McBSP SPCR2 bit definitions ***********************/
-#define XRST                   BIT(0)
-#define XRDY                   BIT(1)
-#define XEMPTY                 BIT(2)
-#define XSYNC_ERR              BIT(3)
-#define XINTM(value)           (((value) & 0x3) << 4)  /* bits 4:5 */
-#define GRST                   BIT(6)
-#define FRST                   BIT(7)
-#define SOFT                   BIT(8)
-#define FREE                   BIT(9)
-
-/************************** McBSP PCR bit definitions *************************/
-#define CLKRP                  BIT(0)
-#define CLKXP                  BIT(1)
-#define FSRP                   BIT(2)
-#define FSXP                   BIT(3)
-#define DR_STAT                        BIT(4)
-#define DX_STAT                        BIT(5)
-#define CLKS_STAT              BIT(6)
-#define SCLKME                 BIT(7)
-#define CLKRM                  BIT(8)
-#define CLKXM                  BIT(9)
-#define FSRM                   BIT(10)
-#define FSXM                   BIT(11)
-#define RIOEN                  BIT(12)
-#define XIOEN                  BIT(13)
-#define IDLE_EN                        BIT(14)
-
-/************************** McBSP RCR1 bit definitions ************************/
-#define RWDLEN1(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
-#define RFRLEN1(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
-
-/************************** McBSP XCR1 bit definitions ************************/
-#define XWDLEN1(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
-#define XFRLEN1(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
-
-/*************************** McBSP RCR2 bit definitions ***********************/
-#define RDATDLY(value)         ((value) & 0x3)         /* Bits 0:1 */
-#define RFIG                   BIT(2)
-#define RCOMPAND(value)                (((value) & 0x3) << 3)  /* Bits 3:4 */
-#define RWDLEN2(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
-#define RFRLEN2(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
-#define RPHASE                 BIT(15)
-
-/*************************** McBSP XCR2 bit definitions ***********************/
-#define XDATDLY(value)         ((value) & 0x3)         /* Bits 0:1 */
-#define XFIG                   BIT(2)
-#define XCOMPAND(value)                (((value) & 0x3) << 3)  /* Bits 3:4 */
-#define XWDLEN2(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
-#define XFRLEN2(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
-#define XPHASE                 BIT(15)
-
-/************************* McBSP SRGR1 bit definitions ************************/
-#define CLKGDV(value)          ((value) & 0x7f)                /* Bits 0:7 */
-#define FWID(value)            (((value) & 0xff) << 8) /* Bits 8:15 */
-
-/************************* McBSP SRGR2 bit definitions ************************/
-#define FPER(value)            ((value) & 0x0fff)      /* Bits 0:11 */
-#define FSGM                   BIT(12)
-#define CLKSM                  BIT(13)
-#define CLKSP                  BIT(14)
-#define GSYNC                  BIT(15)
-
-/************************* McBSP MCR1 bit definitions *************************/
-#define RMCM                   BIT(0)
-#define RCBLK(value)           (((value) & 0x7) << 2)  /* Bits 2:4 */
-#define RPABLK(value)          (((value) & 0x3) << 5)  /* Bits 5:6 */
-#define RPBBLK(value)          (((value) & 0x3) << 7)  /* Bits 7:8 */
-
-/************************* McBSP MCR2 bit definitions *************************/
-#define XMCM(value)            ((value) & 0x3)         /* Bits 0:1 */
-#define XCBLK(value)           (((value) & 0x7) << 2)  /* Bits 2:4 */
-#define XPABLK(value)          (((value) & 0x3) << 5)  /* Bits 5:6 */
-#define XPBBLK(value)          (((value) & 0x3) << 7)  /* Bits 7:8 */
-
-/*********************** McBSP XCCR bit definitions *************************/
-#define XDISABLE               BIT(0)
-#define XDMAEN                 BIT(3)
-#define DILB                   BIT(5)
-#define XFULL_CYCLE            BIT(11)
-#define DXENDLY(value)         (((value) & 0x3) << 12) /* Bits 12:13 */
-#define PPCONNECT              BIT(14)
-#define EXTCLKGATE             BIT(15)
-
-/********************** McBSP RCCR bit definitions *************************/
-#define RDISABLE               BIT(0)
-#define RDMAEN                 BIT(3)
-#define RFULL_CYCLE            BIT(11)
-
-/********************** McBSP SYSCONFIG bit definitions ********************/
-#define SOFTRST                        BIT(1)
-#define ENAWAKEUP              BIT(2)
-#define SIDLEMODE(value)       (((value) & 0x3) << 3)
-#define CLOCKACTIVITY(value)   (((value) & 0x3) << 8)
-
-/********************** McBSP SSELCR bit definitions ***********************/
-#define SIDETONEEN             BIT(10)
-
-/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
-#define ST_AUTOIDLE            BIT(0)
-
-/********************** McBSP Sidetone SGAINCR bit definitions *************/
-#define ST_CH0GAIN(value)      ((value) & 0xffff)      /* Bits 0:15 */
-#define ST_CH1GAIN(value)      (((value) & 0xffff) << 16) /* Bits 16:31 */
-
-/********************** McBSP Sidetone SFIRCR bit definitions **************/
-#define ST_FIRCOEFF(value)     ((value) & 0xffff)      /* Bits 0:15 */
-
-/********************** McBSP Sidetone SSELCR bit definitions **************/
-#define ST_SIDETONEEN          BIT(0)
-#define ST_COEFFWREN           BIT(1)
-#define ST_COEFFWRDONE         BIT(2)
-
-/********************** McBSP DMA operating modes **************************/
-#define MCBSP_DMA_MODE_ELEMENT         0
-#define MCBSP_DMA_MODE_THRESHOLD       1
-
-/********************** McBSP WAKEUPEN/IRQST/IRQEN bit definitions *********/
-#define RSYNCERREN             BIT(0)
-#define RFSREN                 BIT(1)
-#define REOFEN                 BIT(2)
-#define RRDYEN                 BIT(3)
-#define RUNDFLEN               BIT(4)
-#define ROVFLEN                        BIT(5)
-#define XSYNCERREN             BIT(7)
-#define XFSXEN                 BIT(8)
-#define XEOFEN                 BIT(9)
-#define XRDYEN                 BIT(10)
-#define XUNDFLEN               BIT(11)
-#define XOVFLEN                        BIT(12)
-#define XEMPTYEOFEN            BIT(14)
-
-/* Clock signal muxing options */
-#define CLKR_SRC_CLKR          0 /* CLKR signal is from the CLKR pin */
-#define CLKR_SRC_CLKX          1 /* CLKR signal is from the CLKX pin */
-#define FSR_SRC_FSR            2 /* FSR signal is from the FSR pin */
-#define FSR_SRC_FSX            3 /* FSR signal is from the FSX pin */
-
-/* McBSP functional clock sources */
-#define MCBSP_CLKS_PRCM_SRC    0
-#define MCBSP_CLKS_PAD_SRC     1
-
-/* we don't do multichannel for now */
-struct omap_mcbsp_reg_cfg {
-       u16 spcr2;
-       u16 spcr1;
-       u16 rcr2;
-       u16 rcr1;
-       u16 xcr2;
-       u16 xcr1;
-       u16 srgr2;
-       u16 srgr1;
-       u16 mcr2;
-       u16 mcr1;
-       u16 pcr0;
-       u16 rcerc;
-       u16 rcerd;
-       u16 xcerc;
-       u16 xcerd;
-       u16 rcere;
-       u16 rcerf;
-       u16 xcere;
-       u16 xcerf;
-       u16 rcerg;
-       u16 rcerh;
-       u16 xcerg;
-       u16 xcerh;
-       u16 xccr;
-       u16 rccr;
-};
-
-struct omap_mcbsp_st_data {
-       void __iomem *io_base_st;
-       struct clk *mcbsp_iclk;
-       bool running;
-       bool enabled;
-       s16 taps[128];  /* Sidetone filter coefficients */
-       int nr_taps;    /* Number of filter coefficients in use */
-       s16 ch0gain;
-       s16 ch1gain;
-};
-
-struct omap_mcbsp {
-       struct device *dev;
-       struct clk *fclk;
-       spinlock_t lock;
-       unsigned long phys_base;
-       unsigned long phys_dma_base;
-       void __iomem *io_base;
-       u8 id;
-       /*
-        * Flags indicating is the bus already activated and configured by
-        * another substream
-        */
-       int active;
-       int configured;
-       u8 free;
-
-       int irq;
-       int rx_irq;
-       int tx_irq;
-
-       /* Protect the field .free, while checking if the mcbsp is in use */
-       struct omap_mcbsp_platform_data *pdata;
-       struct omap_mcbsp_st_data *st_data;
-       struct omap_mcbsp_reg_cfg cfg_regs;
-       struct snd_dmaengine_dai_dma_data dma_data[2];
-       unsigned int dma_req[2];
-       int dma_op_mode;
-       u16 max_tx_thres;
-       u16 max_rx_thres;
-       void *reg_cache;
-       int reg_cache_size;
-
-       unsigned int fmt;
-       unsigned int in_freq;
-       unsigned int latency[2];
-       int clk_div;
-       int wlen;
-
-       struct pm_qos_request pm_qos_req;
-};
-
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
-                      const struct omap_mcbsp_reg_cfg *config);
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
-
-/* McBSP functional clock source changing function */
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
-
-/* Sidetone specific API */
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
-int omap_st_enable(struct omap_mcbsp *mcbsp);
-int omap_st_disable(struct omap_mcbsp *mcbsp);
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
-
-int omap_mcbsp_init(struct platform_device *pdev);
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp);
-
-#endif /* __ASOC_MCBSP_H */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
deleted file mode 100644 (file)
index 9cfefe4..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * n810.c  --  SoC audio for Nokia N810
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-
-#define N810_HEADSET_AMP_GPIO  10
-#define N810_SPEAKER_AMP_GPIO  101
-
-enum {
-       N810_JACK_DISABLED,
-       N810_JACK_HP,
-       N810_JACK_HS,
-       N810_JACK_MIC,
-};
-
-static struct clk *sys_clkout2;
-static struct clk *sys_clkout2_src;
-static struct clk *func96m_clk;
-
-static int n810_spk_func;
-static int n810_jack_func;
-static int n810_dmic_func;
-
-static void n810_ext_control(struct snd_soc_dapm_context *dapm)
-{
-       int hp = 0, line1l = 0;
-
-       switch (n810_jack_func) {
-       case N810_JACK_HS:
-               line1l = 1;
-       case N810_JACK_HP:
-               hp = 1;
-               break;
-       case N810_JACK_MIC:
-               line1l = 1;
-               break;
-       }
-
-       snd_soc_dapm_mutex_lock(dapm);
-
-       if (n810_spk_func)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
-
-       if (hp)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
-       if (line1l)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
-
-       if (n810_dmic_func)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
-
-       snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-}
-
-static int n810_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-
-       n810_ext_control(&rtd->card->dapm);
-       return clk_prepare_enable(sys_clkout2);
-}
-
-static void n810_shutdown(struct snd_pcm_substream *substream)
-{
-       clk_disable_unprepare(sys_clkout2);
-}
-
-static int n810_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int err;
-
-       /* Set the codec system clock for DAC and ADC */
-       err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
-                                           SND_SOC_CLOCK_IN);
-
-       return err;
-}
-
-static const struct snd_soc_ops n810_ops = {
-       .startup = n810_startup,
-       .hw_params = n810_hw_params,
-       .shutdown = n810_shutdown,
-};
-
-static int n810_get_spk(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = n810_spk_func;
-
-       return 0;
-}
-
-static int n810_set_spk(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
-
-       if (n810_spk_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       n810_spk_func = ucontrol->value.enumerated.item[0];
-       n810_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static int n810_get_jack(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = n810_jack_func;
-
-       return 0;
-}
-
-static int n810_set_jack(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
-
-       if (n810_jack_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       n810_jack_func = ucontrol->value.enumerated.item[0];
-       n810_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static int n810_get_input(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = n810_dmic_func;
-
-       return 0;
-}
-
-static int n810_set_input(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
-
-       if (n810_dmic_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       n810_dmic_func = ucontrol->value.enumerated.item[0];
-       n810_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static int n810_spk_event(struct snd_soc_dapm_widget *w,
-                         struct snd_kcontrol *k, int event)
-{
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
-       else
-               gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
-
-       return 0;
-}
-
-static int n810_jack_event(struct snd_soc_dapm_widget *w,
-                          struct snd_kcontrol *k, int event)
-{
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
-       else
-               gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
-       SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
-       SND_SOC_DAPM_MIC("DMic", NULL),
-       SND_SOC_DAPM_MIC("HS Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"Headphone Jack", NULL, "HPLOUT"},
-       {"Headphone Jack", NULL, "HPROUT"},
-
-       {"Ext Spk", NULL, "LLOUT"},
-       {"Ext Spk", NULL, "RLOUT"},
-
-       {"DMic Rate 64", NULL, "DMic"},
-       {"DMic", NULL, "Mic Bias"},
-
-       /*
-        * Note that the mic bias is coming from Retu/Vilma and we don't have
-        * control over it atm. The analog HS mic is not working. <- TODO
-        */
-       {"LINE1L", NULL, "HS Mic"},
-};
-
-static const char *spk_function[] = {"Off", "On"};
-static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
-static const char *input_function[] = {"ADC", "Digital Mic"};
-static const struct soc_enum n810_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
-};
-
-static const struct snd_kcontrol_new aic33_n810_controls[] = {
-       SOC_ENUM_EXT("Speaker Function", n810_enum[0],
-                    n810_get_spk, n810_set_spk),
-       SOC_ENUM_EXT("Jack Function", n810_enum[1],
-                    n810_get_jack, n810_set_jack),
-       SOC_ENUM_EXT("Input Select",  n810_enum[2],
-                    n810_get_input, n810_set_input),
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link n810_dai = {
-       .name = "TLV320AIC33",
-       .stream_name = "AIC33",
-       .cpu_dai_name = "48076000.mcbsp",
-       .platform_name = "48076000.mcbsp",
-       .codec_name = "tlv320aic3x-codec.1-0018",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops = &n810_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_n810 = {
-       .name = "N810",
-       .owner = THIS_MODULE,
-       .dai_link = &n810_dai,
-       .num_links = 1,
-
-       .controls = aic33_n810_controls,
-       .num_controls = ARRAY_SIZE(aic33_n810_controls),
-       .dapm_widgets = aic33_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-       .fully_routed = true,
-};
-
-static struct platform_device *n810_snd_device;
-
-static int __init n810_soc_init(void)
-{
-       int err;
-       struct device *dev;
-
-       if (!of_have_populated_dt() ||
-           (!of_machine_is_compatible("nokia,n810") &&
-            !of_machine_is_compatible("nokia,n810-wimax")))
-               return -ENODEV;
-
-       n810_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!n810_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(n810_snd_device, &snd_soc_n810);
-       err = platform_device_add(n810_snd_device);
-       if (err)
-               goto err1;
-
-       dev = &n810_snd_device->dev;
-
-       sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
-       if (IS_ERR(sys_clkout2_src)) {
-               dev_err(dev, "Could not get sys_clkout2_src clock\n");
-               err = PTR_ERR(sys_clkout2_src);
-               goto err2;
-       }
-       sys_clkout2 = clk_get(dev, "sys_clkout2");
-       if (IS_ERR(sys_clkout2)) {
-               dev_err(dev, "Could not get sys_clkout2\n");
-               err = PTR_ERR(sys_clkout2);
-               goto err3;
-       }
-       /*
-        * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
-        * 96 MHz as its parent in order to get 12 MHz
-        */
-       func96m_clk = clk_get(dev, "func_96m_ck");
-       if (IS_ERR(func96m_clk)) {
-               dev_err(dev, "Could not get func 96M clock\n");
-               err = PTR_ERR(func96m_clk);
-               goto err4;
-       }
-       clk_set_parent(sys_clkout2_src, func96m_clk);
-       clk_set_rate(sys_clkout2, 12000000);
-
-       if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
-                   (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
-               err = -EINVAL;
-               goto err4;
-       }
-
-       gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
-       gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
-
-       return 0;
-err4:
-       clk_put(sys_clkout2);
-err3:
-       clk_put(sys_clkout2_src);
-err2:
-       platform_device_del(n810_snd_device);
-err1:
-       platform_device_put(n810_snd_device);
-
-       return err;
-}
-
-static void __exit n810_soc_exit(void)
-{
-       gpio_free(N810_SPEAKER_AMP_GPIO);
-       gpio_free(N810_HEADSET_AMP_GPIO);
-       clk_put(sys_clkout2_src);
-       clk_put(sys_clkout2);
-       clk_put(func96m_clk);
-
-       platform_device_unregister(n810_snd_device);
-}
-
-module_init(n810_soc_init);
-module_exit(n810_soc_exit);
-
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
-MODULE_DESCRIPTION("ALSA SoC Nokia N810");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
deleted file mode 100644 (file)
index fed45b4..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * omap-abe-twl6040.c  --  SoC audio for TI OMAP based boards with ABE and
- *                        twl6040 codec
- *
- * Author: Misael Lopez Cruz <misael.lopez@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/twl6040.h>
-#include <linux/module.h>
-#include <linux/of.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include "omap-dmic.h"
-#include "omap-mcpdm.h"
-#include "../codecs/twl6040.h"
-
-struct abe_twl6040 {
-       struct snd_soc_card card;
-       struct snd_soc_dai_link dai_links[2];
-       int     jack_detection; /* board can detect jack events */
-       int     mclk_freq;      /* MCLK frequency speed for twl6040 */
-};
-
-static struct platform_device *dmic_codec_dev;
-
-static int omap_abe_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_card *card = rtd->card;
-       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
-       int clk_id, freq;
-       int ret;
-
-       clk_id = twl6040_get_clk_id(codec_dai->component);
-       if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
-               freq = priv->mclk_freq;
-       else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
-               freq = 32768;
-       else
-               return -EINVAL;
-
-       /* set the codec mclk */
-       ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
-                               SND_SOC_CLOCK_IN);
-       if (ret) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-       return ret;
-}
-
-static const struct snd_soc_ops omap_abe_ops = {
-       .hw_params = omap_abe_hw_params,
-};
-
-static int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret = 0;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
-                                    19200000, SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set DMIC cpu system clock\n");
-               return ret;
-       }
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
-                                    SND_SOC_CLOCK_OUT);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set DMIC output clock\n");
-               return ret;
-       }
-       return 0;
-}
-
-static struct snd_soc_ops omap_abe_dmic_ops = {
-       .hw_params = omap_abe_dmic_hw_params,
-};
-
-/* Headset jack */
-static struct snd_soc_jack hs_jack;
-
-/*Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Headset Stereophone",
-               .mask = SND_JACK_HEADPHONE,
-       },
-};
-
-/* SDP4430 machine DAPM */
-static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
-       /* Outputs */
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_SPK("Earphone Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_LINE("Line Out", NULL),
-       SND_SOC_DAPM_SPK("Vibrator", NULL),
-
-       /* Inputs */
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
-       SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-
-       /* Digital microphones */
-       SND_SOC_DAPM_MIC("Digital Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* Routings for outputs */
-       {"Headset Stereophone", NULL, "HSOL"},
-       {"Headset Stereophone", NULL, "HSOR"},
-
-       {"Earphone Spk", NULL, "EP"},
-
-       {"Ext Spk", NULL, "HFL"},
-       {"Ext Spk", NULL, "HFR"},
-
-       {"Line Out", NULL, "AUXL"},
-       {"Line Out", NULL, "AUXR"},
-
-       {"Vibrator", NULL, "VIBRAL"},
-       {"Vibrator", NULL, "VIBRAR"},
-
-       /* Routings for inputs */
-       {"HSMIC", NULL, "Headset Mic"},
-       {"Headset Mic", NULL, "Headset Mic Bias"},
-
-       {"MAINMIC", NULL, "Main Handset Mic"},
-       {"Main Handset Mic", NULL, "Main Mic Bias"},
-
-       {"SUBMIC", NULL, "Sub Handset Mic"},
-       {"Sub Handset Mic", NULL, "Main Mic Bias"},
-
-       {"AFML", NULL, "Line In"},
-       {"AFMR", NULL, "Line In"},
-};
-
-static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_component *component = rtd->codec_dai->component;
-       struct snd_soc_card *card = rtd->card;
-       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
-       int hs_trim;
-       int ret = 0;
-
-       /*
-        * Configure McPDM offset cancellation based on the HSOTRIM value from
-        * twl6040.
-        */
-       hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
-       omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
-                                       TWL6040_HSF_TRIM_RIGHT(hs_trim));
-
-       /* Headset jack detection only if it is supported */
-       if (priv->jack_detection) {
-               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                           SND_JACK_HEADSET, &hs_jack,
-                                           hs_jack_pins,
-                                           ARRAY_SIZE(hs_jack_pins));
-               if (ret)
-                       return ret;
-
-               twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_route dmic_audio_map[] = {
-       {"DMic", NULL, "Digital Mic"},
-       {"Digital Mic", NULL, "Digital Mic1 Bias"},
-};
-
-static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
-
-       return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
-                               ARRAY_SIZE(dmic_audio_map));
-}
-
-static int omap_abe_probe(struct platform_device *pdev)
-{
-       struct device_node *node = pdev->dev.of_node;
-       struct snd_soc_card *card;
-       struct device_node *dai_node;
-       struct abe_twl6040 *priv;
-       int num_links = 0;
-       int ret = 0;
-
-       if (!node) {
-               dev_err(&pdev->dev, "of node is missing.\n");
-               return -ENODEV;
-       }
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
-       if (priv == NULL)
-               return -ENOMEM;
-
-       card = &priv->card;
-       card->dev = &pdev->dev;
-       card->owner = THIS_MODULE;
-       card->dapm_widgets = twl6040_dapm_widgets;
-       card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets);
-       card->dapm_routes = audio_map;
-       card->num_dapm_routes = ARRAY_SIZE(audio_map);
-
-       if (snd_soc_of_parse_card_name(card, "ti,model")) {
-               dev_err(&pdev->dev, "Card name is not provided\n");
-               return -ENODEV;
-       }
-
-       ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
-       if (ret) {
-               dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
-               return ret;
-       }
-
-       dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
-       if (!dai_node) {
-               dev_err(&pdev->dev, "McPDM node is not provided\n");
-               return -EINVAL;
-       }
-
-       priv->dai_links[0].name = "DMIC";
-       priv->dai_links[0].stream_name = "TWL6040";
-       priv->dai_links[0].cpu_of_node = dai_node;
-       priv->dai_links[0].platform_of_node = dai_node;
-       priv->dai_links[0].codec_dai_name = "twl6040-legacy";
-       priv->dai_links[0].codec_name = "twl6040-codec";
-       priv->dai_links[0].init = omap_abe_twl6040_init;
-       priv->dai_links[0].ops = &omap_abe_ops;
-
-       dai_node = of_parse_phandle(node, "ti,dmic", 0);
-       if (dai_node) {
-               num_links = 2;
-               priv->dai_links[1].name = "TWL6040";
-               priv->dai_links[1].stream_name = "DMIC Capture";
-               priv->dai_links[1].cpu_of_node = dai_node;
-               priv->dai_links[1].platform_of_node = dai_node;
-               priv->dai_links[1].codec_dai_name = "dmic-hifi";
-               priv->dai_links[1].codec_name = "dmic-codec";
-               priv->dai_links[1].init = omap_abe_dmic_init;
-               priv->dai_links[1].ops = &omap_abe_dmic_ops;
-       } else {
-               num_links = 1;
-       }
-
-       priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
-       of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
-       if (!priv->mclk_freq) {
-               dev_err(&pdev->dev, "MCLK frequency not provided\n");
-               return -EINVAL;
-       }
-
-       card->fully_routed = 1;
-
-       if (!priv->mclk_freq) {
-               dev_err(&pdev->dev, "MCLK frequency missing\n");
-               return -ENODEV;
-       }
-
-       card->dai_link = priv->dai_links;
-       card->num_links = num_links;
-
-       snd_soc_card_set_drvdata(card, priv);
-
-       ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret)
-               dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
-                       ret);
-
-       return ret;
-}
-
-static const struct of_device_id omap_abe_of_match[] = {
-       {.compatible = "ti,abe-twl6040", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, omap_abe_of_match);
-
-static struct platform_driver omap_abe_driver = {
-       .driver = {
-               .name = "omap-abe-twl6040",
-               .pm = &snd_soc_pm_ops,
-               .of_match_table = omap_abe_of_match,
-       },
-       .probe = omap_abe_probe,
-};
-
-static int __init omap_abe_init(void)
-{
-       int ret;
-
-       dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
-                                                        0);
-       if (IS_ERR(dmic_codec_dev)) {
-               pr_err("%s: dmic-codec device registration failed\n", __func__);
-               return PTR_ERR(dmic_codec_dev);
-       }
-
-       ret = platform_driver_register(&omap_abe_driver);
-       if (ret) {
-               pr_err("%s: platform driver registration failed\n", __func__);
-               platform_device_unregister(dmic_codec_dev);
-       }
-
-       return ret;
-}
-module_init(omap_abe_init);
-
-static void __exit omap_abe_exit(void)
-{
-       platform_driver_unregister(&omap_abe_driver);
-       platform_device_unregister(dmic_codec_dev);
-}
-module_exit(omap_abe_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:omap-abe-twl6040");
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
deleted file mode 100644 (file)
index cba9645..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * omap-dmic.c  --  OMAP ASoC DMIC DAI driver
- *
- * Copyright (C) 2010 - 2011 Texas Instruments
- *
- * Author: David Lambert <dlambert@ti.com>
- *        Misael Lopez Cruz <misael.lopez@ti.com>
- *        Liam Girdwood <lrg@ti.com>
- *        Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "omap-dmic.h"
-#include "sdma-pcm.h"
-
-struct omap_dmic {
-       struct device *dev;
-       void __iomem *io_base;
-       struct clk *fclk;
-       struct pm_qos_request pm_qos_req;
-       int latency;
-       int fclk_freq;
-       int out_freq;
-       int clk_div;
-       int sysclk;
-       int threshold;
-       u32 ch_enabled;
-       bool active;
-       struct mutex mutex;
-
-       struct snd_dmaengine_dai_dma_data dma_data;
-};
-
-static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
-{
-       writel_relaxed(val, dmic->io_base + reg);
-}
-
-static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
-{
-       return readl_relaxed(dmic->io_base + reg);
-}
-
-static inline void omap_dmic_start(struct omap_dmic *dmic)
-{
-       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
-
-       /* Configure DMA controller */
-       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG,
-                       OMAP_DMIC_DMA_ENABLE);
-
-       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled);
-}
-
-static inline void omap_dmic_stop(struct omap_dmic *dmic)
-{
-       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
-       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
-                       ctrl & ~OMAP_DMIC_UP_ENABLE_MASK);
-
-       /* Disable DMA request generation */
-       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG,
-                       OMAP_DMIC_DMA_ENABLE);
-
-}
-
-static inline int dmic_is_enabled(struct omap_dmic *dmic)
-{
-       return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) &
-                                               OMAP_DMIC_UP_ENABLE_MASK;
-}
-
-static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-       int ret = 0;
-
-       mutex_lock(&dmic->mutex);
-
-       if (!dai->active)
-               dmic->active = 1;
-       else
-               ret = -EBUSY;
-
-       mutex_unlock(&dmic->mutex);
-
-       return ret;
-}
-
-static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
-                                   struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-
-       mutex_lock(&dmic->mutex);
-
-       pm_qos_remove_request(&dmic->pm_qos_req);
-
-       if (!dai->active)
-               dmic->active = 0;
-
-       mutex_unlock(&dmic->mutex);
-}
-
-static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate)
-{
-       int divider = -EINVAL;
-
-       /*
-        * 192KHz rate is only supported with 19.2MHz/3.84MHz clock
-        * configuration.
-        */
-       if (sample_rate == 192000) {
-               if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000)
-                       divider = 0x6; /* Divider: 5 (192KHz sampling rate) */
-               else
-                       dev_err(dmic->dev,
-                               "invalid clock configuration for 192KHz\n");
-
-               return divider;
-       }
-
-       switch (dmic->out_freq) {
-       case 1536000:
-               if (dmic->fclk_freq != 24576000)
-                       goto div_err;
-               divider = 0x4; /* Divider: 16 */
-               break;
-       case 2400000:
-               switch (dmic->fclk_freq) {
-               case 12000000:
-                       divider = 0x5; /* Divider: 5 */
-                       break;
-               case 19200000:
-                       divider = 0x0; /* Divider: 8 */
-                       break;
-               case 24000000:
-                       divider = 0x2; /* Divider: 10 */
-                       break;
-               default:
-                       goto div_err;
-               }
-               break;
-       case 3072000:
-               if (dmic->fclk_freq != 24576000)
-                       goto div_err;
-               divider = 0x3; /* Divider: 8 */
-               break;
-       case 3840000:
-               if (dmic->fclk_freq != 19200000)
-                       goto div_err;
-               divider = 0x1; /* Divider: 5 (96KHz sampling rate) */
-               break;
-       default:
-               dev_err(dmic->dev, "invalid out frequency: %dHz\n",
-                       dmic->out_freq);
-               break;
-       }
-
-       return divider;
-
-div_err:
-       dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n",
-               dmic->out_freq, dmic->fclk_freq);
-       return -EINVAL;
-}
-
-static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       int channels;
-
-       dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
-       if (dmic->clk_div < 0) {
-               dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n",
-                       dmic->out_freq, dmic->fclk_freq);
-               return -EINVAL;
-       }
-
-       dmic->ch_enabled = 0;
-       channels = params_channels(params);
-       switch (channels) {
-       case 6:
-               dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
-               /* fall through */
-       case 4:
-               dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
-               /* fall through */
-       case 2:
-               dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
-               break;
-       default:
-               dev_err(dmic->dev, "invalid number of legacy channels\n");
-               return -EINVAL;
-       }
-
-       /* packet size is threshold * channels */
-       dma_data = snd_soc_dai_get_dma_data(dai, substream);
-       dma_data->maxburst = dmic->threshold * channels;
-       dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC /
-                       params_rate(params);
-
-       return 0;
-}
-
-static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-       u32 ctrl;
-
-       if (pm_qos_request_active(&dmic->pm_qos_req))
-               pm_qos_update_request(&dmic->pm_qos_req, dmic->latency);
-
-       /* Configure uplink threshold */
-       omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold);
-
-       ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
-
-       /* Set dmic out format */
-       ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK);
-       ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
-                OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
-
-       /* Configure dmic clock divider */
-       ctrl &= ~OMAP_DMIC_CLK_DIV_MASK;
-       ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div);
-
-       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl);
-
-       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
-                       ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
-                       OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
-
-       return 0;
-}
-
-static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream,
-                                 int cmd, struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               omap_dmic_start(dmic);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               omap_dmic_stop(dmic);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id,
-                                unsigned int freq)
-{
-       struct clk *parent_clk, *mux;
-       char *parent_clk_name;
-       int ret = 0;
-
-       switch (freq) {
-       case 12000000:
-       case 19200000:
-       case 24000000:
-       case 24576000:
-               break;
-       default:
-               dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq);
-               dmic->fclk_freq = 0;
-               return -EINVAL;
-       }
-
-       if (dmic->sysclk == clk_id) {
-               dmic->fclk_freq = freq;
-               return 0;
-       }
-
-       /* re-parent not allowed if a stream is ongoing */
-       if (dmic->active && dmic_is_enabled(dmic)) {
-               dev_err(dmic->dev, "can't re-parent when DMIC active\n");
-               return -EBUSY;
-       }
-
-       switch (clk_id) {
-       case OMAP_DMIC_SYSCLK_PAD_CLKS:
-               parent_clk_name = "pad_clks_ck";
-               break;
-       case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS:
-               parent_clk_name = "slimbus_clk";
-               break;
-       case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS:
-               parent_clk_name = "dmic_sync_mux_ck";
-               break;
-       default:
-               dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id);
-               return -EINVAL;
-       }
-
-       parent_clk = clk_get(dmic->dev, parent_clk_name);
-       if (IS_ERR(parent_clk)) {
-               dev_err(dmic->dev, "can't get %s\n", parent_clk_name);
-               return -ENODEV;
-       }
-
-       mux = clk_get_parent(dmic->fclk);
-       if (IS_ERR(mux)) {
-               dev_err(dmic->dev, "can't get fck mux parent\n");
-               clk_put(parent_clk);
-               return -ENODEV;
-       }
-
-       mutex_lock(&dmic->mutex);
-       if (dmic->active) {
-               /* disable clock while reparenting */
-               pm_runtime_put_sync(dmic->dev);
-               ret = clk_set_parent(mux, parent_clk);
-               pm_runtime_get_sync(dmic->dev);
-       } else {
-               ret = clk_set_parent(mux, parent_clk);
-       }
-       mutex_unlock(&dmic->mutex);
-
-       if (ret < 0) {
-               dev_err(dmic->dev, "re-parent failed\n");
-               goto err_busy;
-       }
-
-       dmic->sysclk = clk_id;
-       dmic->fclk_freq = freq;
-
-err_busy:
-       clk_put(mux);
-       clk_put(parent_clk);
-
-       return ret;
-}
-
-static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id,
-                                   unsigned int freq)
-{
-       int ret = 0;
-
-       if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) {
-               dev_err(dmic->dev, "output clk_id (%d) not supported\n",
-                       clk_id);
-               return -EINVAL;
-       }
-
-       switch (freq) {
-       case 1536000:
-       case 2400000:
-       case 3072000:
-       case 3840000:
-               dmic->out_freq = freq;
-               break;
-       default:
-               dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq);
-               dmic->out_freq = 0;
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
-                                   unsigned int freq, int dir)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-
-       if (dir == SND_SOC_CLOCK_IN)
-               return omap_dmic_select_fclk(dmic, clk_id, freq);
-       else if (dir == SND_SOC_CLOCK_OUT)
-               return omap_dmic_select_outclk(dmic, clk_id, freq);
-
-       dev_err(dmic->dev, "invalid clock direction (%d)\n", dir);
-       return -EINVAL;
-}
-
-static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
-       .startup        = omap_dmic_dai_startup,
-       .shutdown       = omap_dmic_dai_shutdown,
-       .hw_params      = omap_dmic_dai_hw_params,
-       .prepare        = omap_dmic_dai_prepare,
-       .trigger        = omap_dmic_dai_trigger,
-       .set_sysclk     = omap_dmic_set_dai_sysclk,
-};
-
-static int omap_dmic_probe(struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-
-       pm_runtime_enable(dmic->dev);
-
-       /* Disable lines while request is ongoing */
-       pm_runtime_get_sync(dmic->dev);
-       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00);
-       pm_runtime_put_sync(dmic->dev);
-
-       /* Configure DMIC threshold value */
-       dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
-
-       snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
-
-       return 0;
-}
-
-static int omap_dmic_remove(struct snd_soc_dai *dai)
-{
-       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-
-       pm_runtime_disable(dmic->dev);
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver omap_dmic_dai = {
-       .name = "omap-dmic",
-       .probe = omap_dmic_probe,
-       .remove = omap_dmic_remove,
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 6,
-               .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,
-               .sig_bits = 24,
-       },
-       .ops = &omap_dmic_dai_ops,
-};
-
-static const struct snd_soc_component_driver omap_dmic_component = {
-       .name           = "omap-dmic",
-};
-
-static int asoc_dmic_probe(struct platform_device *pdev)
-{
-       struct omap_dmic *dmic;
-       struct resource *res;
-       int ret;
-
-       dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL);
-       if (!dmic)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, dmic);
-       dmic->dev = &pdev->dev;
-       dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS;
-
-       mutex_init(&dmic->mutex);
-
-       dmic->fclk = devm_clk_get(dmic->dev, "fck");
-       if (IS_ERR(dmic->fclk)) {
-               dev_err(dmic->dev, "cant get fck\n");
-               return -ENODEV;
-       }
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
-       if (!res) {
-               dev_err(dmic->dev, "invalid dma memory resource\n");
-               return -ENODEV;
-       }
-       dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
-
-       dmic->dma_data.filter_data = "up_link";
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dmic->io_base))
-               return PTR_ERR(dmic->io_base);
-
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                             &omap_dmic_component,
-                                             &omap_dmic_dai, 1);
-       if (ret)
-               return ret;
-
-       ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link");
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static const struct of_device_id omap_dmic_of_match[] = {
-       { .compatible = "ti,omap4-dmic", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, omap_dmic_of_match);
-
-static struct platform_driver asoc_dmic_driver = {
-       .driver = {
-               .name = "omap-dmic",
-               .of_match_table = omap_dmic_of_match,
-       },
-       .probe = asoc_dmic_probe,
-};
-
-module_platform_driver(asoc_dmic_driver);
-
-MODULE_ALIAS("platform:omap-dmic");
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_DESCRIPTION("OMAP DMIC ASoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/omap/omap-dmic.h
deleted file mode 100644 (file)
index 231e728..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * omap-dmic.h  --  OMAP Digital Microphone Controller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _OMAP_DMIC_H
-#define _OMAP_DMIC_H
-
-#define OMAP_DMIC_REVISION_REG         0x00
-#define OMAP_DMIC_SYSCONFIG_REG                0x10
-#define OMAP_DMIC_IRQSTATUS_RAW_REG    0x24
-#define OMAP_DMIC_IRQSTATUS_REG                0x28
-#define OMAP_DMIC_IRQENABLE_SET_REG    0x2C
-#define OMAP_DMIC_IRQENABLE_CLR_REG    0x30
-#define OMAP_DMIC_IRQWAKE_EN_REG       0x34
-#define OMAP_DMIC_DMAENABLE_SET_REG    0x38
-#define OMAP_DMIC_DMAENABLE_CLR_REG    0x3C
-#define OMAP_DMIC_DMAWAKEEN_REG                0x40
-#define OMAP_DMIC_CTRL_REG             0x44
-#define OMAP_DMIC_DATA_REG             0x48
-#define OMAP_DMIC_FIFO_CTRL_REG                0x4C
-#define OMAP_DMIC_FIFO_DMIC1R_DATA_REG 0x50
-#define OMAP_DMIC_FIFO_DMIC1L_DATA_REG 0x54
-#define OMAP_DMIC_FIFO_DMIC2R_DATA_REG 0x58
-#define OMAP_DMIC_FIFO_DMIC2L_DATA_REG 0x5C
-#define OMAP_DMIC_FIFO_DMIC3R_DATA_REG 0x60
-#define OMAP_DMIC_FIFO_DMIC3L_DATA_REG 0x64
-
-/* IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR bit fields */
-#define OMAP_DMIC_IRQ                  (1 << 0)
-#define OMAP_DMIC_IRQ_FULL             (1 << 1)
-#define OMAP_DMIC_IRQ_ALMST_EMPTY      (1 << 2)
-#define OMAP_DMIC_IRQ_EMPTY            (1 << 3)
-#define OMAP_DMIC_IRQ_MASK             0x07
-
-/* DMIC_DMAENABLE bit fields */
-#define OMAP_DMIC_DMA_ENABLE           0x1
-
-/* DMIC_CTRL bit fields */
-#define OMAP_DMIC_UP1_ENABLE           (1 << 0)
-#define OMAP_DMIC_UP2_ENABLE           (1 << 1)
-#define OMAP_DMIC_UP3_ENABLE           (1 << 2)
-#define OMAP_DMIC_UP_ENABLE_MASK       0x7
-#define OMAP_DMIC_FORMAT               (1 << 3)
-#define OMAP_DMIC_POLAR1               (1 << 4)
-#define OMAP_DMIC_POLAR2               (1 << 5)
-#define OMAP_DMIC_POLAR3               (1 << 6)
-#define OMAP_DMIC_POLAR_MASK           (0x7 << 4)
-#define OMAP_DMIC_CLK_DIV(x)           (((x) & 0x7) << 7)
-#define OMAP_DMIC_CLK_DIV_MASK         (0x7 << 7)
-#define        OMAP_DMIC_RESET                 (1 << 10)
-
-#define OMAP_DMICOUTFORMAT_LJUST       (0 << 3)
-#define OMAP_DMICOUTFORMAT_RJUST       (1 << 3)
-
-/* DMIC_FIFO_CTRL bit fields */
-#define OMAP_DMIC_THRES_MAX            0xF
-
-enum omap_dmic_clk {
-       OMAP_DMIC_SYSCLK_PAD_CLKS,              /* PAD_CLKS */
-       OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS,         /* SLIMBUS_CLK */
-       OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS,         /* DMIC_SYNC_MUX_CLK */
-       OMAP_DMIC_ABE_DMIC_CLK,                 /* abe_dmic_clk */
-};
-
-#endif
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
deleted file mode 100644 (file)
index 673a9eb..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
- *
- * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
- *
- * Author: Jyri Sarha <jsarha@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#include <sound/dmaengine_pcm.h>
-#include <uapi/sound/asound.h>
-#include <sound/asoundef.h>
-#include <sound/omap-hdmi-audio.h>
-
-#include "sdma-pcm.h"
-
-#define DRV_NAME "omap-hdmi-audio"
-
-struct hdmi_audio_data {
-       struct snd_soc_card *card;
-
-       const struct omap_hdmi_audio_ops *ops;
-       struct device *dssdev;
-       struct snd_dmaengine_dai_dma_data dma_data;
-       struct omap_dss_audio dss_audio;
-       struct snd_aes_iec958 iec;
-       struct snd_cea_861_aud_if cea;
-
-       struct mutex current_stream_lock;
-       struct snd_pcm_substream *current_stream;
-};
-
-static
-struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
-{
-       struct snd_soc_pcm_runtime *rtd = ss->private_data;
-
-       return snd_soc_card_get_drvdata(rtd->card);
-}
-
-static void hdmi_dai_abort(struct device *dev)
-{
-       struct hdmi_audio_data *ad = dev_get_drvdata(dev);
-
-       mutex_lock(&ad->current_stream_lock);
-       if (ad->current_stream && ad->current_stream->runtime &&
-           snd_pcm_running(ad->current_stream)) {
-               dev_err(dev, "HDMI display disabled, aborting playback\n");
-               snd_pcm_stream_lock_irq(ad->current_stream);
-               snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
-               snd_pcm_stream_unlock_irq(ad->current_stream);
-       }
-       mutex_unlock(&ad->current_stream_lock);
-}
-
-static int hdmi_dai_startup(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
-       int ret;
-       /*
-        * Make sure that the period bytes are multiple of the DMA packet size.
-        * Largest packet size we use is 32 32-bit words = 128 bytes
-        */
-       ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
-       if (ret < 0) {
-               dev_err(dai->dev, "Could not apply period constraint: %d\n",
-                       ret);
-               return ret;
-       }
-       ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
-       if (ret < 0) {
-               dev_err(dai->dev, "Could not apply buffer constraint: %d\n",
-                       ret);
-               return ret;
-       }
-
-       snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
-
-       mutex_lock(&ad->current_stream_lock);
-       ad->current_stream = substream;
-       mutex_unlock(&ad->current_stream_lock);
-
-       ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
-
-       if (ret) {
-               mutex_lock(&ad->current_stream_lock);
-               ad->current_stream = NULL;
-               mutex_unlock(&ad->current_stream_lock);
-       }
-
-       return ret;
-}
-
-static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params,
-                             struct snd_soc_dai *dai)
-{
-       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
-       struct snd_aes_iec958 *iec = &ad->iec;
-       struct snd_cea_861_aud_if *cea = &ad->cea;
-
-       WARN_ON(ad->current_stream != substream);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               ad->dma_data.maxburst = 16;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               ad->dma_data.maxburst = 32;
-               break;
-       default:
-               dev_err(dai->dev, "format not supported!\n");
-               return -EINVAL;
-       }
-
-       ad->dss_audio.iec = iec;
-       ad->dss_audio.cea = cea;
-       /*
-        * fill the IEC-60958 channel status word
-        */
-       /* initialize the word bytes */
-       memset(iec->status, 0, sizeof(iec->status));
-
-       /* specify IEC-60958-3 (commercial use) */
-       iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
-
-       /* specify that the audio is LPCM*/
-       iec->status[0] &= ~IEC958_AES0_NONAUDIO;
-
-       iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
-
-       iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
-
-       iec->status[1] = IEC958_AES1_CON_GENERAL;
-
-       iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
-
-       iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
-
-       switch (params_rate(params)) {
-       case 32000:
-               iec->status[3] |= IEC958_AES3_CON_FS_32000;
-               break;
-       case 44100:
-               iec->status[3] |= IEC958_AES3_CON_FS_44100;
-               break;
-       case 48000:
-               iec->status[3] |= IEC958_AES3_CON_FS_48000;
-               break;
-       case 88200:
-               iec->status[3] |= IEC958_AES3_CON_FS_88200;
-               break;
-       case 96000:
-               iec->status[3] |= IEC958_AES3_CON_FS_96000;
-               break;
-       case 176400:
-               iec->status[3] |= IEC958_AES3_CON_FS_176400;
-               break;
-       case 192000:
-               iec->status[3] |= IEC958_AES3_CON_FS_192000;
-               break;
-       default:
-               dev_err(dai->dev, "rate not supported!\n");
-               return -EINVAL;
-       }
-
-       /* specify the clock accuracy */
-       iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
-
-       /*
-        * specify the word length. The same word length value can mean
-        * two different lengths. Hence, we need to specify the maximum
-        * word length as well.
-        */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
-               iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
-               iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
-               break;
-       default:
-               dev_err(dai->dev, "format not supported!\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Fill the CEA-861 audio infoframe (see spec for details)
-        */
-
-       cea->db1_ct_cc = (params_channels(params) - 1)
-               & CEA861_AUDIO_INFOFRAME_DB1CC;
-       cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
-
-       cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
-       cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
-
-       cea->db3 = 0; /* not used, all zeros */
-
-       if (params_channels(params) == 2)
-               cea->db4_ca = 0x0;
-       else if (params_channels(params) == 6)
-               cea->db4_ca = 0xb;
-       else
-               cea->db4_ca = 0x13;
-
-       if (cea->db4_ca == 0x00)
-               cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED;
-       else
-               cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
-
-       /* the expression is trivial but makes clear what we are doing */
-       cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
-
-       return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
-}
-
-static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                           struct snd_soc_dai *dai)
-{
-       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
-       int err = 0;
-
-       WARN_ON(ad->current_stream != substream);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               err = ad->ops->audio_start(ad->dssdev);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ad->ops->audio_stop(ad->dssdev);
-               break;
-       default:
-               err = -EINVAL;
-       }
-       return err;
-}
-
-static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
-                             struct snd_soc_dai *dai)
-{
-       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
-
-       WARN_ON(ad->current_stream != substream);
-
-       ad->ops->audio_shutdown(ad->dssdev);
-
-       mutex_lock(&ad->current_stream_lock);
-       ad->current_stream = NULL;
-       mutex_unlock(&ad->current_stream_lock);
-}
-
-static const struct snd_soc_dai_ops hdmi_dai_ops = {
-       .startup        = hdmi_dai_startup,
-       .hw_params      = hdmi_dai_hw_params,
-       .trigger        = hdmi_dai_trigger,
-       .shutdown       = hdmi_dai_shutdown,
-};
-
-static const struct snd_soc_component_driver omap_hdmi_component = {
-       .name = "omapdss_hdmi",
-};
-
-static struct snd_soc_dai_driver omap5_hdmi_dai = {
-       .name = "omap5-hdmi-dai",
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
-                         SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-                         SNDRV_PCM_RATE_192000),
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &hdmi_dai_ops,
-};
-
-static struct snd_soc_dai_driver omap4_hdmi_dai = {
-       .name = "omap4-hdmi-dai",
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
-                         SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-                         SNDRV_PCM_RATE_192000),
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
-       },
-       .ops = &hdmi_dai_ops,
-};
-
-static int omap_hdmi_audio_probe(struct platform_device *pdev)
-{
-       struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
-       struct device *dev = &pdev->dev;
-       struct hdmi_audio_data *ad;
-       struct snd_soc_dai_driver *dai_drv;
-       struct snd_soc_card *card;
-       int ret;
-
-       if (!ha) {
-               dev_err(dev, "No platform data\n");
-               return -EINVAL;
-       }
-
-       ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
-       if (!ad)
-               return -ENOMEM;
-       ad->dssdev = ha->dev;
-       ad->ops = ha->ops;
-       ad->dma_data.addr = ha->audio_dma_addr;
-       ad->dma_data.filter_data = "audio_tx";
-       ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       mutex_init(&ad->current_stream_lock);
-
-       switch (ha->version) {
-       case 4:
-               dai_drv = &omap4_hdmi_dai;
-               break;
-       case 5:
-               dai_drv = &omap5_hdmi_dai;
-               break;
-       default:
-               return -EINVAL;
-       }
-       ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
-                                        dai_drv, 1);
-       if (ret)
-               return ret;
-
-       ret = sdma_pcm_platform_register(ad->dssdev, "audio_tx", NULL);
-       if (ret)
-               return ret;
-
-       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
-       if (!card)
-               return -ENOMEM;
-
-       card->name = devm_kasprintf(dev, GFP_KERNEL,
-                                   "HDMI %s", dev_name(ad->dssdev));
-       if (!card->name)
-               return -ENOMEM;
-
-       card->owner = THIS_MODULE;
-       card->dai_link =
-               devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
-       if (!card->dai_link)
-               return -ENOMEM;
-       card->dai_link->name = card->name;
-       card->dai_link->stream_name = card->name;
-       card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
-       card->dai_link->platform_name = dev_name(ad->dssdev);
-       card->dai_link->codec_name = "snd-soc-dummy";
-       card->dai_link->codec_dai_name = "snd-soc-dummy-dai";
-       card->num_links = 1;
-       card->dev = dev;
-
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
-               return ret;
-       }
-
-       ad->card = card;
-       snd_soc_card_set_drvdata(card, ad);
-
-       dev_set_drvdata(dev, ad);
-
-       return 0;
-}
-
-static int omap_hdmi_audio_remove(struct platform_device *pdev)
-{
-       struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(ad->card);
-       return 0;
-}
-
-static struct platform_driver hdmi_audio_driver = {
-       .driver = {
-               .name = DRV_NAME,
-       },
-       .probe = omap_hdmi_audio_probe,
-       .remove = omap_hdmi_audio_remove,
-};
-
-module_platform_driver(hdmi_audio_driver);
-
-MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
-MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
deleted file mode 100644 (file)
index 2d6decb..0000000
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- * omap-mcbsp.c  --  OMAP ALSA SoC DAI driver using McBSP port
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include "mcbsp.h"
-#include "omap-mcbsp.h"
-#include "sdma-pcm.h"
-
-#define OMAP_MCBSP_RATES       (SNDRV_PCM_RATE_8000_96000)
-
-#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
-       xhandler_get, xhandler_put) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = omap_mcbsp_st_info_volsw, \
-       .get = xhandler_get, .put = xhandler_put, \
-       .private_value = (unsigned long) &(struct soc_mixer_control) \
-       {.min = xmin, .max = xmax} }
-
-enum {
-       OMAP_MCBSP_WORD_8 = 0,
-       OMAP_MCBSP_WORD_12,
-       OMAP_MCBSP_WORD_16,
-       OMAP_MCBSP_WORD_20,
-       OMAP_MCBSP_WORD_24,
-       OMAP_MCBSP_WORD_32,
-};
-
-/*
- * Stream DMA parameters. DMA request line and port address are set runtime
- * since they are different between OMAP1 and later OMAPs
- */
-static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
-               unsigned int packet_size)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       int words;
-
-       /*
-        * Configure McBSP threshold based on either:
-        * packet_size, when the sDMA is in packet mode, or based on the
-        * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
-        * for mono streams.
-        */
-       if (packet_size)
-               words = packet_size;
-       else
-               words = 1;
-
-       /* Configure McBSP internal buffer usage */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               omap_mcbsp_set_tx_threshold(mcbsp, words);
-       else
-               omap_mcbsp_set_rx_threshold(mcbsp, words);
-}
-
-static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
-                                   struct snd_pcm_hw_rule *rule)
-{
-       struct snd_interval *buffer_size = hw_param_interval(params,
-                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                       SNDRV_PCM_HW_PARAM_CHANNELS);
-       struct omap_mcbsp *mcbsp = rule->private;
-       struct snd_interval frames;
-       int size;
-
-       snd_interval_any(&frames);
-       size = mcbsp->pdata->buffer_size;
-
-       frames.min = size / channels->min;
-       frames.integer = 1;
-       return snd_interval_refine(buffer_size, &frames);
-}
-
-static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *cpu_dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       int err = 0;
-
-       if (!cpu_dai->active)
-               err = omap_mcbsp_request(mcbsp);
-
-       /*
-        * OMAP3 McBSP FIFO is word structured.
-        * McBSP2 has 1024 + 256 = 1280 word long buffer,
-        * McBSP1,3,4,5 has 128 word long buffer
-        * This means that the size of the FIFO depends on the sample format.
-        * For example on McBSP3:
-        * 16bit samples: size is 128 * 2 = 256 bytes
-        * 32bit samples: size is 128 * 4 = 512 bytes
-        * It is simpler to place constraint for buffer and period based on
-        * channels.
-        * McBSP3 as example again (16 or 32 bit samples):
-        * 1 channel (mono): size is 128 frames (128 words)
-        * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
-        * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
-        */
-       if (mcbsp->pdata->buffer_size) {
-               /*
-               * Rule for the buffer size. We should not allow
-               * smaller buffer than the FIFO size to avoid underruns.
-               * This applies only for the playback stream.
-               */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       snd_pcm_hw_rule_add(substream->runtime, 0,
-                                           SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-                                           omap_mcbsp_hwrule_min_buffersize,
-                                           mcbsp,
-                                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-
-               /* Make sure, that the period size is always even */
-               snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                          SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
-       }
-
-       return err;
-}
-
-static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
-                                   struct snd_soc_dai *cpu_dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
-       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-
-       if (mcbsp->latency[stream2])
-               pm_qos_update_request(&mcbsp->pm_qos_req,
-                                     mcbsp->latency[stream2]);
-       else if (mcbsp->latency[stream1])
-               pm_qos_remove_request(&mcbsp->pm_qos_req);
-
-       mcbsp->latency[stream1] = 0;
-
-       if (!cpu_dai->active) {
-               omap_mcbsp_free(mcbsp);
-               mcbsp->configured = 0;
-       }
-}
-
-static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *cpu_dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req;
-       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
-       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-       int latency = mcbsp->latency[stream2];
-
-       /* Prevent omap hardware from hitting off between FIFO fills */
-       if (!latency || mcbsp->latency[stream1] < latency)
-               latency = mcbsp->latency[stream1];
-
-       if (pm_qos_request_active(pm_qos_req))
-               pm_qos_update_request(pm_qos_req, latency);
-       else if (latency)
-               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
-
-       return 0;
-}
-
-static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                                 struct snd_soc_dai *cpu_dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               mcbsp->active++;
-               omap_mcbsp_start(mcbsp, play, !play);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               omap_mcbsp_stop(mcbsp, play, !play);
-               mcbsp->active--;
-               break;
-       default:
-               err = -EINVAL;
-       }
-
-       return err;
-}
-
-static snd_pcm_sframes_t omap_mcbsp_dai_delay(
-                       struct snd_pcm_substream *substream,
-                       struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       u16 fifo_use;
-       snd_pcm_sframes_t delay;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
-       else
-               fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
-
-       /*
-        * Divide the used locations with the channel count to get the
-        * FIFO usage in samples (don't care about partial samples in the
-        * buffer).
-        */
-       delay = fifo_use / substream->runtime->channels;
-
-       return delay;
-}
-
-static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *cpu_dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       int wlen, channels, wpf;
-       int pkt_size = 0;
-       unsigned int format, div, framesize, master;
-       unsigned int buffer_size = mcbsp->pdata->buffer_size;
-
-       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
-       channels = params_channels(params);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               wlen = 16;
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               wlen = 32;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (buffer_size) {
-               int latency;
-
-               if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
-                       int period_words, max_thrsh;
-                       int divider = 0;
-
-                       period_words = params_period_bytes(params) / (wlen / 8);
-                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                               max_thrsh = mcbsp->max_tx_thres;
-                       else
-                               max_thrsh = mcbsp->max_rx_thres;
-                       /*
-                        * Use sDMA packet mode if McBSP is in threshold mode:
-                        * If period words less than the FIFO size the packet
-                        * size is set to the number of period words, otherwise
-                        * Look for the biggest threshold value which divides
-                        * the period size evenly.
-                        */
-                       divider = period_words / max_thrsh;
-                       if (period_words % max_thrsh)
-                               divider++;
-                       while (period_words % divider &&
-                               divider < period_words)
-                               divider++;
-                       if (divider == period_words)
-                               return -EINVAL;
-
-                       pkt_size = period_words / divider;
-               } else if (channels > 1) {
-                       /* Use packet mode for non mono streams */
-                       pkt_size = channels;
-               }
-
-               latency = (buffer_size - pkt_size) / channels;
-               latency = latency * USEC_PER_SEC /
-                         (params->rate_num / params->rate_den);
-               mcbsp->latency[substream->stream] = latency;
-
-               omap_mcbsp_set_threshold(substream, pkt_size);
-       }
-
-       dma_data->maxburst = pkt_size;
-
-       if (mcbsp->configured) {
-               /* McBSP already configured by another stream */
-               return 0;
-       }
-
-       regs->rcr2      &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7));
-       regs->xcr2      &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
-       regs->rcr1      &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
-       regs->xcr1      &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
-       format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
-       wpf = channels;
-       if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
-                             format == SND_SOC_DAIFMT_LEFT_J)) {
-               /* Use dual-phase frames */
-               regs->rcr2      |= RPHASE;
-               regs->xcr2      |= XPHASE;
-               /* Set 1 word per (McBSP) frame for phase1 and phase2 */
-               wpf--;
-               regs->rcr2      |= RFRLEN2(wpf - 1);
-               regs->xcr2      |= XFRLEN2(wpf - 1);
-       }
-
-       regs->rcr1      |= RFRLEN1(wpf - 1);
-       regs->xcr1      |= XFRLEN1(wpf - 1);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               /* Set word lengths */
-               regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_16);
-               regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_16);
-               regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_16);
-               regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_16);
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               /* Set word lengths */
-               regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_32);
-               regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_32);
-               regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_32);
-               regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_32);
-               break;
-       default:
-               /* Unsupported PCM format */
-               return -EINVAL;
-       }
-
-       /* In McBSP master modes, FRAME (i.e. sample rate) is generated
-        * by _counting_ BCLKs. Calculate frame size in BCLKs */
-       master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
-       if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
-               div = mcbsp->clk_div ? mcbsp->clk_div : 1;
-               framesize = (mcbsp->in_freq / div) / params_rate(params);
-
-               if (framesize < wlen * channels) {
-                       printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
-                                       "channels\n", __func__);
-                       return -EINVAL;
-               }
-       } else
-               framesize = wlen * channels;
-
-       /* Set FS period and length in terms of bit clock periods */
-       regs->srgr2     &= ~FPER(0xfff);
-       regs->srgr1     &= ~FWID(0xff);
-       switch (format) {
-       case SND_SOC_DAIFMT_I2S:
-       case SND_SOC_DAIFMT_LEFT_J:
-               regs->srgr2     |= FPER(framesize - 1);
-               regs->srgr1     |= FWID((framesize >> 1) - 1);
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-       case SND_SOC_DAIFMT_DSP_B:
-               regs->srgr2     |= FPER(framesize - 1);
-               regs->srgr1     |= FWID(0);
-               break;
-       }
-
-       omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
-       mcbsp->wlen = wlen;
-       mcbsp->configured = 1;
-
-       return 0;
-}
-
-/*
- * This must be called before _set_clkdiv and _set_sysclk since McBSP register
- * cache is initialized here
- */
-static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-                                     unsigned int fmt)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-       bool inv_fs = false;
-
-       if (mcbsp->configured)
-               return 0;
-
-       mcbsp->fmt = fmt;
-       memset(regs, 0, sizeof(*regs));
-       /* Generic McBSP register settings */
-       regs->spcr2     |= XINTM(3) | FREE;
-       regs->spcr1     |= RINTM(3);
-       /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
-       if (!mcbsp->pdata->has_ccr) {
-               regs->rcr2      |= RFIG;
-               regs->xcr2      |= XFIG;
-       }
-
-       /* Configure XCCR/RCCR only for revisions which have ccr registers */
-       if (mcbsp->pdata->has_ccr) {
-               regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
-               regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               /* 1-bit data delay */
-               regs->rcr2      |= RDATDLY(1);
-               regs->xcr2      |= XDATDLY(1);
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               /* 0-bit data delay */
-               regs->rcr2      |= RDATDLY(0);
-               regs->xcr2      |= XDATDLY(0);
-               regs->spcr1     |= RJUST(2);
-               /* Invert FS polarity configuration */
-               inv_fs = true;
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-               /* 1-bit data delay */
-               regs->rcr2      |= RDATDLY(1);
-               regs->xcr2      |= XDATDLY(1);
-               /* Invert FS polarity configuration */
-               inv_fs = true;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               /* 0-bit data delay */
-               regs->rcr2      |= RDATDLY(0);
-               regs->xcr2      |= XDATDLY(0);
-               /* Invert FS polarity configuration */
-               inv_fs = true;
-               break;
-       default:
-               /* Unsupported data format */
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* McBSP master. Set FS and bit clocks as outputs */
-               regs->pcr0      |= FSXM | FSRM |
-                                  CLKXM | CLKRM;
-               /* Sample rate generator drives the FS */
-               regs->srgr2     |= FSGM;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               /* McBSP slave. FS clock as output */
-               regs->srgr2     |= FSGM;
-               regs->pcr0      |= FSXM | FSRM;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* McBSP slave */
-               break;
-       default:
-               /* Unsupported master/slave configuration */
-               return -EINVAL;
-       }
-
-       /* Set bit clock (CLKX/CLKR) and FS polarities */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               /*
-                * Normal BCLK + FS.
-                * FS active low. TX data driven on falling edge of bit clock
-                * and RX data sampled on rising edge of bit clock.
-                */
-               regs->pcr0      |= FSXP | FSRP |
-                                  CLKXP | CLKRP;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               regs->pcr0      |= CLKXP | CLKRP;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               regs->pcr0      |= FSXP | FSRP;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (inv_fs == true)
-               regs->pcr0 ^= FSXP | FSRP;
-
-       return 0;
-}
-
-static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
-                                    int div_id, int div)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-
-       if (div_id != OMAP_MCBSP_CLKGDV)
-               return -ENODEV;
-
-       mcbsp->clk_div = div;
-       regs->srgr1     &= ~CLKGDV(0xff);
-       regs->srgr1     |= CLKGDV(div - 1);
-
-       return 0;
-}
-
-static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-                                        int clk_id, unsigned int freq,
-                                        int dir)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-       int err = 0;
-
-       if (mcbsp->active) {
-               if (freq == mcbsp->in_freq)
-                       return 0;
-               else
-                       return -EBUSY;
-       }
-
-       mcbsp->in_freq = freq;
-       regs->srgr2 &= ~CLKSM;
-       regs->pcr0 &= ~SCLKME;
-
-       switch (clk_id) {
-       case OMAP_MCBSP_SYSCLK_CLK:
-               regs->srgr2     |= CLKSM;
-               break;
-       case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
-               if (mcbsp_omap1()) {
-                       err = -EINVAL;
-                       break;
-               }
-               err = omap2_mcbsp_set_clks_src(mcbsp,
-                                              MCBSP_CLKS_PRCM_SRC);
-               break;
-       case OMAP_MCBSP_SYSCLK_CLKS_EXT:
-               if (mcbsp_omap1()) {
-                       err = 0;
-                       break;
-               }
-               err = omap2_mcbsp_set_clks_src(mcbsp,
-                                              MCBSP_CLKS_PAD_SRC);
-               break;
-
-       case OMAP_MCBSP_SYSCLK_CLKX_EXT:
-               regs->srgr2     |= CLKSM;
-               regs->pcr0      |= SCLKME;
-               /*
-                * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
-                * disable output on those pins. This enables to inject the
-                * reference clock through CLKX/CLKR. For this to work
-                * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
-                */
-               regs->pcr0      &= ~CLKXM;
-               break;
-       case OMAP_MCBSP_SYSCLK_CLKR_EXT:
-               regs->pcr0      |= SCLKME;
-               /* Disable ouput on CLKR pin in master mode */
-               regs->pcr0      &= ~CLKRM;
-               break;
-       default:
-               err = -ENODEV;
-       }
-
-       return err;
-}
-
-static const struct snd_soc_dai_ops mcbsp_dai_ops = {
-       .startup        = omap_mcbsp_dai_startup,
-       .shutdown       = omap_mcbsp_dai_shutdown,
-       .prepare        = omap_mcbsp_dai_prepare,
-       .trigger        = omap_mcbsp_dai_trigger,
-       .delay          = omap_mcbsp_dai_delay,
-       .hw_params      = omap_mcbsp_dai_hw_params,
-       .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
-       .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
-       .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
-};
-
-static int omap_mcbsp_probe(struct snd_soc_dai *dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
-
-       pm_runtime_enable(mcbsp->dev);
-
-       snd_soc_dai_init_dma_data(dai,
-                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
-                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
-
-       return 0;
-}
-
-static int omap_mcbsp_remove(struct snd_soc_dai *dai)
-{
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
-
-       pm_runtime_disable(mcbsp->dev);
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver omap_mcbsp_dai = {
-       .probe = omap_mcbsp_probe,
-       .remove = omap_mcbsp_remove,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 16,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 16,
-               .rates = OMAP_MCBSP_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
-       },
-       .ops = &mcbsp_dai_ops,
-};
-
-static const struct snd_soc_component_driver omap_mcbsp_component = {
-       .name           = "omap-mcbsp",
-};
-
-static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int max = mc->max;
-       int min = mc->min;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = min;
-       uinfo->value.integer.max = max;
-       return 0;
-}
-
-#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel)                          \
-static int                                                             \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
-                                       struct snd_ctl_elem_value *uc)  \
-{                                                                      \
-       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
-       struct soc_mixer_control *mc =                                  \
-               (struct soc_mixer_control *)kc->private_value;          \
-       int max = mc->max;                                              \
-       int min = mc->min;                                              \
-       int val = uc->value.integer.value[0];                           \
-                                                                       \
-       if (val < min || val > max)                                     \
-               return -EINVAL;                                         \
-                                                                       \
-       /* OMAP McBSP implementation uses index values 0..4 */          \
-       return omap_st_set_chgain(mcbsp, channel, val);                 \
-}                                                                      \
-                                                                       \
-static int                                                             \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
-                                       struct snd_ctl_elem_value *uc)  \
-{                                                                      \
-       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
-       s16 chgain;                                                     \
-                                                                       \
-       if (omap_st_get_chgain(mcbsp, channel, &chgain))                \
-               return -EAGAIN;                                         \
-                                                                       \
-       uc->value.integer.value[0] = chgain;                            \
-       return 0;                                                       \
-}
-
-OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
-
-static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       u8 value = ucontrol->value.integer.value[0];
-
-       if (value == omap_st_is_enabled(mcbsp))
-               return 0;
-
-       if (value)
-               omap_st_enable(mcbsp);
-       else
-               omap_st_disable(mcbsp);
-
-       return 1;
-}
-
-static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
-       ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
-       return 0;
-}
-
-#define OMAP_MCBSP_ST_CONTROLS(port)                                     \
-static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
-SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0,             \
-              omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),           \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
-                             -32768, 32767,                              \
-                             omap_mcbsp_get_st_ch0_volume,               \
-                             omap_mcbsp_set_st_ch0_volume),              \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
-                             -32768, 32767,                              \
-                             omap_mcbsp_get_st_ch1_volume,               \
-                             omap_mcbsp_set_st_ch1_volume),              \
-}
-
-OMAP_MCBSP_ST_CONTROLS(2);
-OMAP_MCBSP_ST_CONTROLS(3);
-
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
-{
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
-       if (!mcbsp->st_data) {
-               dev_warn(mcbsp->dev, "No sidetone data for port\n");
-               return 0;
-       }
-
-       switch (port_id) {
-       case 2: /* McBSP 2 */
-               return snd_soc_add_dai_controls(cpu_dai,
-                                       omap_mcbsp2_st_controls,
-                                       ARRAY_SIZE(omap_mcbsp2_st_controls));
-       case 3: /* McBSP 3 */
-               return snd_soc_add_dai_controls(cpu_dai,
-                                       omap_mcbsp3_st_controls,
-                                       ARRAY_SIZE(omap_mcbsp3_st_controls));
-       default:
-               dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
-               break;
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
-
-static struct omap_mcbsp_platform_data omap2420_pdata = {
-       .reg_step = 4,
-       .reg_size = 2,
-};
-
-static struct omap_mcbsp_platform_data omap2430_pdata = {
-       .reg_step = 4,
-       .reg_size = 4,
-       .has_ccr = true,
-};
-
-static struct omap_mcbsp_platform_data omap3_pdata = {
-       .reg_step = 4,
-       .reg_size = 4,
-       .has_ccr = true,
-       .has_wakeup = true,
-};
-
-static struct omap_mcbsp_platform_data omap4_pdata = {
-       .reg_step = 4,
-       .reg_size = 4,
-       .has_ccr = true,
-       .has_wakeup = true,
-};
-
-static const struct of_device_id omap_mcbsp_of_match[] = {
-       {
-               .compatible = "ti,omap2420-mcbsp",
-               .data = &omap2420_pdata,
-       },
-       {
-               .compatible = "ti,omap2430-mcbsp",
-               .data = &omap2430_pdata,
-       },
-       {
-               .compatible = "ti,omap3-mcbsp",
-               .data = &omap3_pdata,
-       },
-       {
-               .compatible = "ti,omap4-mcbsp",
-               .data = &omap4_pdata,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match);
-
-static int asoc_mcbsp_probe(struct platform_device *pdev)
-{
-       struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct omap_mcbsp *mcbsp;
-       const struct of_device_id *match;
-       int ret;
-
-       match = of_match_device(omap_mcbsp_of_match, &pdev->dev);
-       if (match) {
-               struct device_node *node = pdev->dev.of_node;
-               struct omap_mcbsp_platform_data *pdata_quirk = pdata;
-               int buffer_size;
-
-               pdata = devm_kzalloc(&pdev->dev,
-                                    sizeof(struct omap_mcbsp_platform_data),
-                                    GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
-
-               memcpy(pdata, match->data, sizeof(*pdata));
-               if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size))
-                       pdata->buffer_size = buffer_size;
-               if (pdata_quirk)
-                       pdata->force_ick_on = pdata_quirk->force_ick_on;
-       } else if (!pdata) {
-               dev_err(&pdev->dev, "missing platform data.\n");
-               return -EINVAL;
-       }
-       mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
-       if (!mcbsp)
-               return -ENOMEM;
-
-       mcbsp->id = pdev->id;
-       mcbsp->pdata = pdata;
-       mcbsp->dev = &pdev->dev;
-       platform_set_drvdata(pdev, mcbsp);
-
-       ret = omap_mcbsp_init(pdev);
-       if (ret)
-               return ret;
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                             &omap_mcbsp_component,
-                                             &omap_mcbsp_dai, 1);
-       if (ret)
-               return ret;
-
-       return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
-}
-
-static int asoc_mcbsp_remove(struct platform_device *pdev)
-{
-       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-
-       if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
-               mcbsp->pdata->ops->free(mcbsp->id);
-
-       if (pm_qos_request_active(&mcbsp->pm_qos_req))
-               pm_qos_remove_request(&mcbsp->pm_qos_req);
-
-       omap_mcbsp_cleanup(mcbsp);
-
-       clk_put(mcbsp->fclk);
-
-       return 0;
-}
-
-static struct platform_driver asoc_mcbsp_driver = {
-       .driver = {
-                       .name = "omap-mcbsp",
-                       .of_match_table = omap_mcbsp_of_match,
-       },
-
-       .probe = asoc_mcbsp_probe,
-       .remove = asoc_mcbsp_remove,
-};
-
-module_platform_driver(asoc_mcbsp_driver);
-
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
-MODULE_DESCRIPTION("OMAP I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:omap-mcbsp");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
deleted file mode 100644 (file)
index 2e3369c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * omap-mcbsp.h
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_I2S_H__
-#define __OMAP_I2S_H__
-
-/* Source clocks for McBSP sample rate generator */
-enum omap_mcbsp_clksrg_clk {
-       OMAP_MCBSP_SYSCLK_CLKS_FCLK,    /* Internal FCLK */
-       OMAP_MCBSP_SYSCLK_CLKS_EXT,     /* External CLKS pin */
-       OMAP_MCBSP_SYSCLK_CLK,          /* Internal ICLK */
-       OMAP_MCBSP_SYSCLK_CLKX_EXT,     /* External CLKX pin */
-       OMAP_MCBSP_SYSCLK_CLKR_EXT,     /* External CLKR pin */
-};
-
-/* McBSP dividers */
-enum omap_mcbsp_div {
-       OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
-};
-
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
-
-#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
deleted file mode 100644 (file)
index 7d5bdc5..0000000
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
- *
- * Copyright (C) 2009 - 2011 Texas Instruments
- *
- * Author: Misael Lopez Cruz <misael.lopez@ti.com>
- * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
- *          Margarita Olaya <magi.olaya@ti.com>
- *          Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "omap-mcpdm.h"
-#include "sdma-pcm.h"
-
-struct mcpdm_link_config {
-       u32 link_mask; /* channel mask for the direction */
-       u32 threshold; /* FIFO threshold */
-};
-
-struct omap_mcpdm {
-       struct device *dev;
-       unsigned long phys_base;
-       void __iomem *io_base;
-       int irq;
-       struct pm_qos_request pm_qos_req;
-       int latency[2];
-
-       struct mutex mutex;
-
-       /* Playback/Capture configuration */
-       struct mcpdm_link_config config[2];
-
-       /* McPDM dn offsets for rx1, and 2 channels */
-       u32 dn_rx_offset;
-
-       /* McPDM needs to be restarted due to runtime reconfiguration */
-       bool restart;
-
-       /* pm state for suspend/resume handling */
-       int pm_active_count;
-
-       struct snd_dmaengine_dai_dma_data dma_data[2];
-};
-
-/*
- * Stream DMA parameters
- */
-
-static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
-{
-       writel_relaxed(val, mcpdm->io_base + reg);
-}
-
-static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
-{
-       return readl_relaxed(mcpdm->io_base + reg);
-}
-
-#ifdef DEBUG
-static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
-{
-       dev_dbg(mcpdm->dev, "***********************\n");
-       dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
-       dev_dbg(mcpdm->dev, "IRQSTATUS:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
-       dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
-       dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
-       dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
-       dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
-       dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
-       dev_dbg(mcpdm->dev, "DMAWAKEEN:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
-       dev_dbg(mcpdm->dev, "CTRL:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
-       dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
-       dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
-       dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
-       dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
-                       omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
-       dev_dbg(mcpdm->dev, "***********************\n");
-}
-#else
-static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
-#endif
-
-/*
- * Enables the transfer through the PDM interface to/from the Phoenix
- * codec by enabling the corresponding UP or DN channels.
- */
-static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
-{
-       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
-       u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
-
-       ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-
-       ctrl |= link_mask;
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-
-       ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-}
-
-/*
- * Disables the transfer through the PDM interface to/from the Phoenix
- * codec by disabling the corresponding UP or DN channels.
- */
-static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
-{
-       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
-       u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
-
-       ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-
-       ctrl &= ~(link_mask);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-
-       ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
-
-}
-
-/*
- * Is the physical McPDM interface active.
- */
-static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
-{
-       return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
-                                       (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
-}
-
-/*
- * Configures McPDM uplink, and downlink for audio.
- * This function should be called before omap_mcpdm_start.
- */
-static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
-{
-       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
-
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN);
-
-       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
-                       MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
-                       MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
-
-       /* Enable DN RX1/2 offset cancellation feature, if configured */
-       if (mcpdm->dn_rx_offset) {
-               u32 dn_offset = mcpdm->dn_rx_offset;
-
-               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
-               dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
-               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
-       }
-
-       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
-                        mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
-                        mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
-
-       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
-                       MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
-}
-
-/*
- * Cleans McPDM uplink, and downlink configuration.
- * This function should be called when the stream is closed.
- */
-static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
-{
-       /* Disable irq request generation for downlink */
-       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
-                       MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
-
-       /* Disable DMA request generation for downlink */
-       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
-
-       /* Disable irq request generation for uplink */
-       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
-                       MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
-
-       /* Disable DMA request generation for uplink */
-       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
-
-       /* Disable RX1/2 offset cancellation */
-       if (mcpdm->dn_rx_offset)
-               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
-}
-
-static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
-{
-       struct omap_mcpdm *mcpdm = dev_id;
-       int irq_status;
-
-       irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
-
-       /* Acknowledge irq event */
-       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
-
-       if (irq_status & MCPDM_DN_IRQ_FULL)
-               dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
-
-       if (irq_status & MCPDM_DN_IRQ_EMPTY)
-               dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
-
-       if (irq_status & MCPDM_DN_IRQ)
-               dev_dbg(mcpdm->dev, "DN (playback) write request\n");
-
-       if (irq_status & MCPDM_UP_IRQ_FULL)
-               dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
-
-       if (irq_status & MCPDM_UP_IRQ_EMPTY)
-               dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
-
-       if (irq_status & MCPDM_UP_IRQ)
-               dev_dbg(mcpdm->dev, "UP (capture) write request\n");
-
-       return IRQ_HANDLED;
-}
-
-static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-
-       mutex_lock(&mcpdm->mutex);
-
-       if (!dai->active)
-               omap_mcpdm_open_streams(mcpdm);
-
-       mutex_unlock(&mcpdm->mutex);
-
-       return 0;
-}
-
-static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
-       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-
-       mutex_lock(&mcpdm->mutex);
-
-       if (!dai->active) {
-               if (omap_mcpdm_active(mcpdm)) {
-                       omap_mcpdm_stop(mcpdm);
-                       omap_mcpdm_close_streams(mcpdm);
-                       mcpdm->config[0].link_mask = 0;
-                       mcpdm->config[1].link_mask = 0;
-               }
-       }
-
-       if (mcpdm->latency[stream2])
-               pm_qos_update_request(&mcpdm->pm_qos_req,
-                                     mcpdm->latency[stream2]);
-       else if (mcpdm->latency[stream1])
-               pm_qos_remove_request(&mcpdm->pm_qos_req);
-
-       mcpdm->latency[stream1] = 0;
-
-       mutex_unlock(&mcpdm->mutex);
-}
-
-static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-       int stream = substream->stream;
-       struct snd_dmaengine_dai_dma_data *dma_data;
-       u32 threshold;
-       int channels, latency;
-       int link_mask = 0;
-
-       channels = params_channels(params);
-       switch (channels) {
-       case 5:
-               if (stream == SNDRV_PCM_STREAM_CAPTURE)
-                       /* up to 3 channels for capture */
-                       return -EINVAL;
-               link_mask |= 1 << 4;
-               /* fall through */
-       case 4:
-               if (stream == SNDRV_PCM_STREAM_CAPTURE)
-                       /* up to 3 channels for capture */
-                       return -EINVAL;
-               link_mask |= 1 << 3;
-               /* fall through */
-       case 3:
-               link_mask |= 1 << 2;
-               /* fall through */
-       case 2:
-               link_mask |= 1 << 1;
-               /* fall through */
-       case 1:
-               link_mask |= 1 << 0;
-               break;
-       default:
-               /* unsupported number of channels */
-               return -EINVAL;
-       }
-
-       dma_data = snd_soc_dai_get_dma_data(dai, substream);
-
-       threshold = mcpdm->config[stream].threshold;
-       /* Configure McPDM channels, and DMA packet size */
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               link_mask <<= 3;
-
-               /* If capture is not running assume a stereo stream to come */
-               if (!mcpdm->config[!stream].link_mask)
-                       mcpdm->config[!stream].link_mask = 0x3;
-
-               dma_data->maxburst =
-                               (MCPDM_DN_THRES_MAX - threshold) * channels;
-               latency = threshold;
-       } else {
-               /* If playback is not running assume a stereo stream to come */
-               if (!mcpdm->config[!stream].link_mask)
-                       mcpdm->config[!stream].link_mask = (0x3 << 3);
-
-               dma_data->maxburst = threshold * channels;
-               latency = (MCPDM_DN_THRES_MAX - threshold);
-       }
-
-       /*
-        * The DMA must act to a DMA request within latency time (usec) to avoid
-        * under/overflow
-        */
-       mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params);
-
-       if (!mcpdm->latency[stream])
-               mcpdm->latency[stream] = 10;
-
-       /* Check if we need to restart McPDM with this stream */
-       if (mcpdm->config[stream].link_mask &&
-           mcpdm->config[stream].link_mask != link_mask)
-               mcpdm->restart = true;
-
-       mcpdm->config[stream].link_mask = link_mask;
-
-       return 0;
-}
-
-static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-       struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req;
-       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
-       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-       int latency = mcpdm->latency[stream2];
-
-       /* Prevent omap hardware from hitting off between FIFO fills */
-       if (!latency || mcpdm->latency[stream1] < latency)
-               latency = mcpdm->latency[stream1];
-
-       if (pm_qos_request_active(pm_qos_req))
-               pm_qos_update_request(pm_qos_req, latency);
-       else if (latency)
-               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
-
-       if (!omap_mcpdm_active(mcpdm)) {
-               omap_mcpdm_start(mcpdm);
-               omap_mcpdm_reg_dump(mcpdm);
-       } else if (mcpdm->restart) {
-               omap_mcpdm_stop(mcpdm);
-               omap_mcpdm_start(mcpdm);
-               mcpdm->restart = false;
-               omap_mcpdm_reg_dump(mcpdm);
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
-       .startup        = omap_mcpdm_dai_startup,
-       .shutdown       = omap_mcpdm_dai_shutdown,
-       .hw_params      = omap_mcpdm_dai_hw_params,
-       .prepare        = omap_mcpdm_prepare,
-};
-
-static int omap_mcpdm_probe(struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-       int ret;
-
-       pm_runtime_enable(mcpdm->dev);
-
-       /* Disable lines while request is ongoing */
-       pm_runtime_get_sync(mcpdm->dev);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
-
-       ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM",
-                         (void *)mcpdm);
-
-       pm_runtime_put_sync(mcpdm->dev);
-
-       if (ret) {
-               dev_err(mcpdm->dev, "Request for IRQ failed\n");
-               pm_runtime_disable(mcpdm->dev);
-       }
-
-       /* Configure McPDM threshold values */
-       mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
-       mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
-                                                       MCPDM_UP_THRES_MAX - 3;
-
-       snd_soc_dai_init_dma_data(dai,
-                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
-                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
-
-       return ret;
-}
-
-static int omap_mcpdm_remove(struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-
-       free_irq(mcpdm->irq, (void *)mcpdm);
-       pm_runtime_disable(mcpdm->dev);
-
-       if (pm_qos_request_active(&mcpdm->pm_qos_req))
-               pm_qos_remove_request(&mcpdm->pm_qos_req);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int omap_mcpdm_suspend(struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-
-       if (dai->active) {
-               omap_mcpdm_stop(mcpdm);
-               omap_mcpdm_close_streams(mcpdm);
-       }
-
-       mcpdm->pm_active_count = 0;
-       while (pm_runtime_active(mcpdm->dev)) {
-               pm_runtime_put_sync(mcpdm->dev);
-               mcpdm->pm_active_count++;
-       }
-
-       return 0;
-}
-
-static int omap_mcpdm_resume(struct snd_soc_dai *dai)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
-
-       if (mcpdm->pm_active_count) {
-               while (mcpdm->pm_active_count--)
-                       pm_runtime_get_sync(mcpdm->dev);
-
-               if (dai->active) {
-                       omap_mcpdm_open_streams(mcpdm);
-                       omap_mcpdm_start(mcpdm);
-               }
-       }
-
-
-       return 0;
-}
-#else
-#define omap_mcpdm_suspend NULL
-#define omap_mcpdm_resume NULL
-#endif
-
-#define OMAP_MCPDM_RATES       (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define OMAP_MCPDM_FORMATS     SNDRV_PCM_FMTBIT_S32_LE
-
-static struct snd_soc_dai_driver omap_mcpdm_dai = {
-       .probe = omap_mcpdm_probe,
-       .remove = omap_mcpdm_remove,
-       .suspend = omap_mcpdm_suspend,
-       .resume = omap_mcpdm_resume,
-       .probe_order = SND_SOC_COMP_ORDER_LATE,
-       .remove_order = SND_SOC_COMP_ORDER_EARLY,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 5,
-               .rates = OMAP_MCPDM_RATES,
-               .formats = OMAP_MCPDM_FORMATS,
-               .sig_bits = 24,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 3,
-               .rates = OMAP_MCPDM_RATES,
-               .formats = OMAP_MCPDM_FORMATS,
-               .sig_bits = 24,
-       },
-       .ops = &omap_mcpdm_dai_ops,
-};
-
-static const struct snd_soc_component_driver omap_mcpdm_component = {
-       .name           = "omap-mcpdm",
-};
-
-void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
-                                   u8 rx1, u8 rx2)
-{
-       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
-       mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
-}
-EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
-
-static int asoc_mcpdm_probe(struct platform_device *pdev)
-{
-       struct omap_mcpdm *mcpdm;
-       struct resource *res;
-       int ret;
-
-       mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
-       if (!mcpdm)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, mcpdm);
-
-       mutex_init(&mcpdm->mutex);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
-       if (res == NULL)
-               return -ENOMEM;
-
-       mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
-       mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
-
-       mcpdm->dma_data[0].filter_data = "dn_link";
-       mcpdm->dma_data[1].filter_data = "up_link";
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mcpdm->io_base))
-               return PTR_ERR(mcpdm->io_base);
-
-       mcpdm->irq = platform_get_irq(pdev, 0);
-       if (mcpdm->irq < 0)
-               return mcpdm->irq;
-
-       mcpdm->dev = &pdev->dev;
-
-       ret =  devm_snd_soc_register_component(&pdev->dev,
-                                              &omap_mcpdm_component,
-                                              &omap_mcpdm_dai, 1);
-       if (ret)
-               return ret;
-
-       return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link");
-}
-
-static const struct of_device_id omap_mcpdm_of_match[] = {
-       { .compatible = "ti,omap4-mcpdm", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
-
-static struct platform_driver asoc_mcpdm_driver = {
-       .driver = {
-               .name   = "omap-mcpdm",
-               .of_match_table = omap_mcpdm_of_match,
-       },
-
-       .probe  = asoc_mcpdm_probe,
-};
-
-module_platform_driver(asoc_mcpdm_driver);
-
-MODULE_ALIAS("platform:omap-mcpdm");
-MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
-MODULE_DESCRIPTION("OMAP PDM SoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
deleted file mode 100644 (file)
index de8cf26..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * omap-mcpdm.h
- *
- * Copyright (C) 2009 - 2011 Texas Instruments
- *
- * Contact: Misael Lopez Cruz <misael.lopez@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_MCPDM_H__
-#define __OMAP_MCPDM_H__
-
-#define MCPDM_REG_REVISION             0x00
-#define MCPDM_REG_SYSCONFIG            0x10
-#define MCPDM_REG_IRQSTATUS_RAW                0x24
-#define MCPDM_REG_IRQSTATUS            0x28
-#define MCPDM_REG_IRQENABLE_SET                0x2C
-#define MCPDM_REG_IRQENABLE_CLR                0x30
-#define MCPDM_REG_IRQWAKE_EN           0x34
-#define MCPDM_REG_DMAENABLE_SET                0x38
-#define MCPDM_REG_DMAENABLE_CLR                0x3C
-#define MCPDM_REG_DMAWAKEEN            0x40
-#define MCPDM_REG_CTRL                 0x44
-#define MCPDM_REG_DN_DATA              0x48
-#define MCPDM_REG_UP_DATA              0x4C
-#define MCPDM_REG_FIFO_CTRL_DN         0x50
-#define MCPDM_REG_FIFO_CTRL_UP         0x54
-#define MCPDM_REG_DN_OFFSET            0x58
-
-/*
- * MCPDM_IRQ bit fields
- * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
- */
-
-#define MCPDM_DN_IRQ                   (1 << 0)
-#define MCPDM_DN_IRQ_EMPTY             (1 << 1)
-#define MCPDM_DN_IRQ_ALMST_EMPTY       (1 << 2)
-#define MCPDM_DN_IRQ_FULL              (1 << 3)
-
-#define MCPDM_UP_IRQ                   (1 << 8)
-#define MCPDM_UP_IRQ_EMPTY             (1 << 9)
-#define MCPDM_UP_IRQ_ALMST_FULL                (1 << 10)
-#define MCPDM_UP_IRQ_FULL              (1 << 11)
-
-#define MCPDM_DOWNLINK_IRQ_MASK                0x00F
-#define MCPDM_UPLINK_IRQ_MASK          0xF00
-
-/*
- * MCPDM_DMAENABLE bit fields
- */
-
-#define MCPDM_DMA_DN_ENABLE            (1 << 0)
-#define MCPDM_DMA_UP_ENABLE            (1 << 1)
-
-/*
- * MCPDM_CTRL bit fields
- */
-
-#define MCPDM_PDM_UPLINK_EN(x)         (1 << (x - 1)) /* ch1 is at bit 0 */
-#define MCPDM_PDM_DOWNLINK_EN(x)       (1 << (x + 2)) /* ch1 is at bit 3 */
-#define MCPDM_PDMOUTFORMAT             (1 << 8)
-#define MCPDM_CMD_INT                  (1 << 9)
-#define MCPDM_STATUS_INT               (1 << 10)
-#define MCPDM_SW_UP_RST                        (1 << 11)
-#define MCPDM_SW_DN_RST                        (1 << 12)
-#define MCPDM_WD_EN                    (1 << 14)
-#define MCPDM_PDM_UP_MASK              0x7
-#define MCPDM_PDM_DN_MASK              (0x1f << 3)
-
-
-#define MCPDM_PDMOUTFORMAT_LJUST       (0 << 8)
-#define MCPDM_PDMOUTFORMAT_RJUST       (1 << 8)
-
-/*
- * MCPDM_FIFO_CTRL bit fields
- */
-
-#define MCPDM_UP_THRES_MAX             0xF
-#define MCPDM_DN_THRES_MAX             0xF
-
-/*
- * MCPDM_DN_OFFSET bit fields
- */
-
-#define MCPDM_DN_OFST_RX1_EN           (1 << 0)
-#define MCPDM_DNOFST_RX1(x)            ((x & 0x1f) << 1)
-#define MCPDM_DN_OFST_RX2_EN           (1 << 8)
-#define MCPDM_DNOFST_RX2(x)            ((x & 0x1f) << 9)
-
-void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
-                                   u8 rx1, u8 rx2);
-
-#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
deleted file mode 100644 (file)
index cccc316..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * omap-twl4030.c  --  SoC audio for TI SoC based boards with twl4030 codec
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This driver replaces the following machine drivers:
- * omap3beagle (Author: Steve Sakoman <steve@sakoman.com>)
- * omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>)
- * overo (Author: Steve Sakoman <steve@sakoman.com>)
- * igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>)
- * zoom2 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
- * sdp3430 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/platform_data/omap-twl4030.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include "omap-mcbsp.h"
-
-struct omap_twl4030 {
-       int jack_detect;        /* board can detect jack events */
-       struct snd_soc_jack hs_jack;
-};
-
-static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       unsigned int fmt;
-
-       switch (params_channels(params)) {
-       case 2: /* Stereo I2S mode */
-               fmt =   SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBM_CFM;
-               break;
-       case 4: /* Four channel TDM mode */
-               fmt =   SND_SOC_DAIFMT_DSP_A |
-                       SND_SOC_DAIFMT_IB_NF |
-                       SND_SOC_DAIFMT_CBM_CFM;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return snd_soc_runtime_set_dai_fmt(rtd, fmt);
-}
-
-static const struct snd_soc_ops omap_twl4030_ops = {
-       .hw_params = omap_twl4030_hw_params,
-};
-
-static const struct snd_soc_dapm_widget dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Earpiece Spk", NULL),
-       SND_SOC_DAPM_SPK("Handsfree Spk", NULL),
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_SPK("Carkit Spk", NULL),
-
-       SND_SOC_DAPM_MIC("Main Mic", NULL),
-       SND_SOC_DAPM_MIC("Sub Mic", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Carkit Mic", NULL),
-       SND_SOC_DAPM_MIC("Digital0 Mic", NULL),
-       SND_SOC_DAPM_MIC("Digital1 Mic", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* Headset Stereophone:  HSOL, HSOR */
-       {"Headset Stereophone", NULL, "HSOL"},
-       {"Headset Stereophone", NULL, "HSOR"},
-       /* External Speakers: HFL, HFR */
-       {"Handsfree Spk", NULL, "HFL"},
-       {"Handsfree Spk", NULL, "HFR"},
-       /* External Speakers: PredrivL, PredrivR */
-       {"Ext Spk", NULL, "PREDRIVEL"},
-       {"Ext Spk", NULL, "PREDRIVER"},
-       /* Carkit speakers:  CARKITL, CARKITR */
-       {"Carkit Spk", NULL, "CARKITL"},
-       {"Carkit Spk", NULL, "CARKITR"},
-       /* Earpiece */
-       {"Earpiece Spk", NULL, "EARPIECE"},
-
-       /* External Mics: MAINMIC, SUBMIC with bias */
-       {"MAINMIC", NULL, "Main Mic"},
-       {"Main Mic", NULL, "Mic Bias 1"},
-       {"SUBMIC", NULL, "Sub Mic"},
-       {"Sub Mic", NULL, "Mic Bias 2"},
-       /* Headset Mic: HSMIC with bias */
-       {"HSMIC", NULL, "Headset Mic"},
-       {"Headset Mic", NULL, "Headset Mic Bias"},
-       /* Digital Mics: DIGIMIC0, DIGIMIC1 with bias */
-       {"DIGIMIC0", NULL, "Digital0 Mic"},
-       {"Digital0 Mic", NULL, "Mic Bias 1"},
-       {"DIGIMIC1", NULL, "Digital1 Mic"},
-       {"Digital1 Mic", NULL, "Mic Bias 2"},
-       /* Carkit In: CARKITMIC */
-       {"CARKITMIC", NULL, "Carkit Mic"},
-       /* Aux In: AUXL, AUXR */
-       {"AUXL", NULL, "Line In"},
-       {"AUXR", NULL, "Line In"},
-};
-
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Headset Stereophone",
-               .mask = SND_JACK_HEADPHONE,
-       },
-};
-
-/* Headset jack detection gpios */
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
-       {
-               .name = "hsdet-gpio",
-               .report = SND_JACK_HEADSET,
-               .debounce_time = 200,
-       },
-};
-
-static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
-                                         int connected, char *pin)
-{
-       if (!connected)
-               snd_soc_dapm_disable_pin(dapm, pin);
-}
-
-static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_card *card = rtd->card;
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-       struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
-       struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
-       int ret = 0;
-
-       /* Headset jack detection only if it is supported */
-       if (priv->jack_detect > 0) {
-               hs_jack_gpios[0].gpio = priv->jack_detect;
-
-               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                           SND_JACK_HEADSET, &priv->hs_jack,
-                                           hs_jack_pins,
-                                           ARRAY_SIZE(hs_jack_pins));
-               if (ret)
-                       return ret;
-
-               ret = snd_soc_jack_add_gpios(&priv->hs_jack,
-                                            ARRAY_SIZE(hs_jack_gpios),
-                                            hs_jack_gpios);
-               if (ret)
-                       return ret;
-       }
-
-       /*
-        * NULL pdata means we booted with DT. In this case the routing is
-        * provided and the card is fully routed, no need to mark pins.
-        */
-       if (!pdata || !pdata->custom_routing)
-               return ret;
-
-       /* Disable not connected paths if not used */
-       twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk");
-       twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk");
-       twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-       twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk");
-       twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk");
-
-       twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic");
-       twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In");
-
-       return ret;
-}
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
-       {
-               .name = "TWL4030 HiFi",
-               .stream_name = "TWL4030 HiFi",
-               .cpu_dai_name = "omap-mcbsp.2",
-               .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-mcbsp.2",
-               .codec_name = "twl4030-codec",
-               .init = omap_twl4030_init,
-               .ops = &omap_twl4030_ops,
-       },
-       {
-               .name = "TWL4030 Voice",
-               .stream_name = "TWL4030 Voice",
-               .cpu_dai_name = "omap-mcbsp.3",
-               .codec_dai_name = "twl4030-voice",
-               .platform_name = "omap-mcbsp.3",
-               .codec_name = "twl4030-codec",
-               .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
-                          SND_SOC_DAIFMT_CBM_CFM,
-       },
-};
-
-/* Audio machine driver */
-static struct snd_soc_card omap_twl4030_card = {
-       .owner = THIS_MODULE,
-       .dai_link = omap_twl4030_dai_links,
-       .num_links = ARRAY_SIZE(omap_twl4030_dai_links),
-
-       .dapm_widgets = dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static int omap_twl4030_probe(struct platform_device *pdev)
-{
-       struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
-       struct device_node *node = pdev->dev.of_node;
-       struct snd_soc_card *card = &omap_twl4030_card;
-       struct omap_twl4030 *priv;
-       int ret = 0;
-
-       card->dev = &pdev->dev;
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_twl4030), GFP_KERNEL);
-       if (priv == NULL)
-               return -ENOMEM;
-
-       if (node) {
-               struct device_node *dai_node;
-               struct property *prop;
-
-               if (snd_soc_of_parse_card_name(card, "ti,model")) {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
-
-               dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "McBSP node is not provided\n");
-                       return -EINVAL;
-               }
-               omap_twl4030_dai_links[0].cpu_dai_name  = NULL;
-               omap_twl4030_dai_links[0].cpu_of_node = dai_node;
-
-               omap_twl4030_dai_links[0].platform_name  = NULL;
-               omap_twl4030_dai_links[0].platform_of_node = dai_node;
-
-               dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
-               if (!dai_node) {
-                       card->num_links = 1;
-               } else {
-                       omap_twl4030_dai_links[1].cpu_dai_name  = NULL;
-                       omap_twl4030_dai_links[1].cpu_of_node = dai_node;
-
-                       omap_twl4030_dai_links[1].platform_name  = NULL;
-                       omap_twl4030_dai_links[1].platform_of_node = dai_node;
-               }
-
-               priv->jack_detect = of_get_named_gpio(node,
-                                                     "ti,jack-det-gpio", 0);
-
-               /* Optional: audio routing can be provided */
-               prop = of_find_property(node, "ti,audio-routing", NULL);
-               if (prop) {
-                       ret = snd_soc_of_parse_audio_routing(card,
-                                                           "ti,audio-routing");
-                       if (ret)
-                               return ret;
-
-                       card->fully_routed = 1;
-               }
-       } else if (pdata) {
-               if (pdata->card_name) {
-                       card->name = pdata->card_name;
-               } else {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
-
-               if (!pdata->voice_connected)
-                       card->num_links = 1;
-
-               priv->jack_detect = pdata->jack_detect;
-       } else {
-               dev_err(&pdev->dev, "Missing pdata\n");
-               return -ENODEV;
-       }
-
-       snd_soc_card_set_drvdata(card, priv);
-       ret = devm_snd_soc_register_card(&pdev->dev, card);
-       if (ret) {
-               dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
-                       ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct of_device_id omap_twl4030_of_match[] = {
-       {.compatible = "ti,omap-twl4030", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, omap_twl4030_of_match);
-
-static struct platform_driver omap_twl4030_driver = {
-       .driver = {
-               .name = "omap-twl4030",
-               .pm = &snd_soc_pm_ops,
-               .of_match_table = omap_twl4030_of_match,
-       },
-       .probe = omap_twl4030_probe,
-};
-
-module_platform_driver(omap_twl4030_driver);
-
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:omap-twl4030");
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
deleted file mode 100644 (file)
index 4e3de71..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * omap3pandora.c  --  SoC audio for Pandora Handheld Console
- *
- * Author: Gražvydas Ignotas <notasas@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-
-#define OMAP3_PANDORA_DAC_POWER_GPIO   118
-#define OMAP3_PANDORA_AMP_POWER_GPIO   14
-
-#define PREFIX "ASoC omap3pandora: "
-
-static struct regulator *omap3pandora_dac_reg;
-
-static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                           SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               pr_err(PREFIX "can't set codec system clock\n");
-               return ret;
-       }
-
-       /* Set McBSP clock to external */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
-                                    256 * params_rate(params),
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               pr_err(PREFIX "can't set cpu system clock\n");
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
-       if (ret < 0) {
-               pr_err(PREFIX "can't set SRG clock divider\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *k, int event)
-{
-       int ret;
-
-       /*
-        * The PCM1773 DAC datasheet requires 1ms delay between switching
-        * VCC power on/off and /PD pin high/low
-        */
-       if (SND_SOC_DAPM_EVENT_ON(event)) {
-               ret = regulator_enable(omap3pandora_dac_reg);
-               if (ret) {
-                       dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
-                       return ret;
-               }
-               mdelay(1);
-               gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
-       } else {
-               gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
-               mdelay(1);
-               regulator_disable(omap3pandora_dac_reg);
-       }
-
-       return 0;
-}
-
-static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *k, int event)
-{
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
-       else
-               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
-
-       return 0;
-}
-
-/*
- * Audio paths on Pandora board:
- *
- *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
- *  |M|         A    +--------> Line Out
- *  |A| <~~clk~~+
- *  |P| <--- TWL4030 <--------- Line In and MICs
- */
-static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
-       SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
-                          0, 0, omap3pandora_dac_event,
-                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-       SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
-                          0, 0, NULL, 0, omap3pandora_hp_event,
-                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_LINE("Line Out", NULL),
-
-       SND_SOC_DAPM_MIC("Mic (internal)", NULL),
-       SND_SOC_DAPM_MIC("Mic (external)", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-};
-
-static const struct snd_soc_dapm_route omap3pandora_map[] = {
-       {"PCM DAC", NULL, "APLL Enable"},
-       {"Headphone Amplifier", NULL, "PCM DAC"},
-       {"Line Out", NULL, "PCM DAC"},
-       {"Headphone Jack", NULL, "Headphone Amplifier"},
-
-       {"AUXL", NULL, "Line In"},
-       {"AUXR", NULL, "Line In"},
-
-       {"MAINMIC", NULL, "Mic (internal)"},
-       {"Mic (internal)", NULL, "Mic Bias 1"},
-
-       {"SUBMIC", NULL, "Mic (external)"},
-       {"Mic (external)", NULL, "Mic Bias 2"},
-};
-
-static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
-
-       /* All TWL4030 output pins are floating */
-       snd_soc_dapm_nc_pin(dapm, "EARPIECE");
-       snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
-       snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
-       snd_soc_dapm_nc_pin(dapm, "HSOL");
-       snd_soc_dapm_nc_pin(dapm, "HSOR");
-       snd_soc_dapm_nc_pin(dapm, "CARKITL");
-       snd_soc_dapm_nc_pin(dapm, "CARKITR");
-       snd_soc_dapm_nc_pin(dapm, "HFL");
-       snd_soc_dapm_nc_pin(dapm, "HFR");
-       snd_soc_dapm_nc_pin(dapm, "VIBRA");
-
-       return 0;
-}
-
-static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
-
-       /* Not comnnected */
-       snd_soc_dapm_nc_pin(dapm, "HSMIC");
-       snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
-       snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
-       snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
-
-       return 0;
-}
-
-static const struct snd_soc_ops omap3pandora_ops = {
-       .hw_params = omap3pandora_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap3pandora_dai[] = {
-       {
-               .name = "PCM1773",
-               .stream_name = "HiFi Out",
-               .cpu_dai_name = "omap-mcbsp.2",
-               .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-mcbsp.2",
-               .codec_name = "twl4030-codec",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                          SND_SOC_DAIFMT_CBS_CFS,
-               .ops = &omap3pandora_ops,
-               .init = omap3pandora_out_init,
-       }, {
-               .name = "TWL4030",
-               .stream_name = "Line/Mic In",
-               .cpu_dai_name = "omap-mcbsp.4",
-               .codec_dai_name = "twl4030-hifi",
-               .platform_name = "omap-mcbsp.4",
-               .codec_name = "twl4030-codec",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                          SND_SOC_DAIFMT_CBS_CFS,
-               .ops = &omap3pandora_ops,
-               .init = omap3pandora_in_init,
-       }
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_omap3pandora = {
-       .name = "omap3pandora",
-       .owner = THIS_MODULE,
-       .dai_link = omap3pandora_dai,
-       .num_links = ARRAY_SIZE(omap3pandora_dai),
-
-       .dapm_widgets = omap3pandora_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
-       .dapm_routes = omap3pandora_map,
-       .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
-};
-
-static struct platform_device *omap3pandora_snd_device;
-
-static int __init omap3pandora_soc_init(void)
-{
-       int ret;
-
-       if (!machine_is_omap3_pandora())
-               return -ENODEV;
-
-       pr_info("OMAP3 Pandora SoC init\n");
-
-       ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
-       if (ret) {
-               pr_err(PREFIX "Failed to get DAC power GPIO\n");
-               return ret;
-       }
-
-       ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
-       if (ret) {
-               pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
-               goto fail0;
-       }
-
-       ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
-       if (ret) {
-               pr_err(PREFIX "Failed to get amp power GPIO\n");
-               goto fail0;
-       }
-
-       ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
-       if (ret) {
-               pr_err(PREFIX "Failed to set amp power GPIO direction\n");
-               goto fail1;
-       }
-
-       omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
-       if (omap3pandora_snd_device == NULL) {
-               pr_err(PREFIX "Platform device allocation failed\n");
-               ret = -ENOMEM;
-               goto fail1;
-       }
-
-       platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
-
-       ret = platform_device_add(omap3pandora_snd_device);
-       if (ret) {
-               pr_err(PREFIX "Unable to add platform device\n");
-               goto fail2;
-       }
-
-       omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
-       if (IS_ERR(omap3pandora_dac_reg)) {
-               pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
-                       dev_name(&omap3pandora_snd_device->dev),
-                       PTR_ERR(omap3pandora_dac_reg));
-               ret = PTR_ERR(omap3pandora_dac_reg);
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       platform_device_del(omap3pandora_snd_device);
-fail2:
-       platform_device_put(omap3pandora_snd_device);
-fail1:
-       gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
-fail0:
-       gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
-       return ret;
-}
-module_init(omap3pandora_soc_init);
-
-static void __exit omap3pandora_soc_exit(void)
-{
-       regulator_put(omap3pandora_dac_reg);
-       platform_device_unregister(omap3pandora_snd_device);
-       gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
-       gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
-}
-module_exit(omap3pandora_soc_exit);
-
-MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
deleted file mode 100644 (file)
index e409677..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * osk5912.c  --  SoC audio for OSK 5912
- *
- * Copyright (C) 2008 Mistral Solutions
- *
- * Contact: Arun KS  <arunks@mistralsolutions.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "../codecs/tlv320aic23.h"
-
-#define CODEC_CLOCK    12000000
-
-static struct clk *tlv320aic23_mclk;
-
-static int osk_startup(struct snd_pcm_substream *substream)
-{
-       return clk_enable(tlv320aic23_mclk);
-}
-
-static void osk_shutdown(struct snd_pcm_substream *substream)
-{
-       clk_disable(tlv320aic23_mclk);
-}
-
-static int osk_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int err;
-
-       /* Set the codec system clock for DAC and ADC */
-       err =
-           snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
-
-       if (err < 0) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return err;
-       }
-
-       return err;
-}
-
-static const struct snd_soc_ops osk_ops = {
-       .startup = osk_startup,
-       .hw_params = osk_hw_params,
-       .shutdown = osk_shutdown,
-};
-
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"Headphone Jack", NULL, "LHPOUT"},
-       {"Headphone Jack", NULL, "RHPOUT"},
-
-       {"LLINEIN", NULL, "Line In"},
-       {"RLINEIN", NULL, "Line In"},
-
-       {"MICIN", NULL, "Mic Jack"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link osk_dai = {
-       .name = "TLV320AIC23",
-       .stream_name = "AIC23",
-       .cpu_dai_name = "omap-mcbsp.1",
-       .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name = "omap-mcbsp.1",
-       .codec_name = "tlv320aic23-codec",
-       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops = &osk_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_card_osk = {
-       .name = "OSK5912",
-       .owner = THIS_MODULE,
-       .dai_link = &osk_dai,
-       .num_links = 1,
-
-       .dapm_widgets = tlv320aic23_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *osk_snd_device;
-
-static int __init osk_soc_init(void)
-{
-       int err;
-       u32 curRate;
-       struct device *dev;
-
-       if (!(machine_is_omap_osk()))
-               return -ENODEV;
-
-       osk_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!osk_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
-       err = platform_device_add(osk_snd_device);
-       if (err)
-               goto err1;
-
-       dev = &osk_snd_device->dev;
-
-       tlv320aic23_mclk = clk_get(dev, "mclk");
-       if (IS_ERR(tlv320aic23_mclk)) {
-               printk(KERN_ERR "Could not get mclk clock\n");
-               err = PTR_ERR(tlv320aic23_mclk);
-               goto err2;
-       }
-
-       /*
-        * Configure 12 MHz output on MCLK.
-        */
-       curRate = (uint) clk_get_rate(tlv320aic23_mclk);
-       if (curRate != CODEC_CLOCK) {
-               if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
-                       printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
-                       err = -ECANCELED;
-                       goto err3;
-               }
-       }
-
-       printk(KERN_INFO "MCLK = %d [%d]\n",
-              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
-
-       return 0;
-
-err3:
-       clk_put(tlv320aic23_mclk);
-err2:
-       platform_device_del(osk_snd_device);
-err1:
-       platform_device_put(osk_snd_device);
-
-       return err;
-
-}
-
-static void __exit osk_soc_exit(void)
-{
-       clk_put(tlv320aic23_mclk);
-       platform_device_unregister(osk_snd_device);
-}
-
-module_init(osk_soc_init);
-module_exit(osk_soc_exit);
-
-MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
-MODULE_DESCRIPTION("ALSA SoC OSK 5912");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
deleted file mode 100644 (file)
index 57448bd..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * rx51.c  --  SoC audio for Nokia RX-51
- *
- * Copyright (C) 2008 - 2009 Nokia Corporation
- *
- * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *          Eduardo Valentin <eduardo.valentin@nokia.com>
- *          Jarkko Nikula <jarkko.nikula@bitmer.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include <asm/mach-types.h>
-
-#include "omap-mcbsp.h"
-
-enum {
-       RX51_JACK_DISABLED,
-       RX51_JACK_TVOUT,                /* tv-out with stereo output */
-       RX51_JACK_HP,                   /* headphone: stereo output, no mic */
-       RX51_JACK_HS,                   /* headset: stereo output with mic */
-};
-
-struct rx51_audio_pdata {
-       struct gpio_desc *tvout_selection_gpio;
-       struct gpio_desc *jack_detection_gpio;
-       struct gpio_desc *eci_sw_gpio;
-       struct gpio_desc *speaker_amp_gpio;
-};
-
-static int rx51_spk_func;
-static int rx51_dmic_func;
-static int rx51_jack_func;
-
-static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
-{
-       struct snd_soc_card *card = dapm->card;
-       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
-       int hp = 0, hs = 0, tvout = 0;
-
-       switch (rx51_jack_func) {
-       case RX51_JACK_TVOUT:
-               tvout = 1;
-               hp = 1;
-               break;
-       case RX51_JACK_HS:
-               hs = 1;
-       case RX51_JACK_HP:
-               hp = 1;
-               break;
-       }
-
-       snd_soc_dapm_mutex_lock(dapm);
-
-       if (rx51_spk_func)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
-       if (rx51_dmic_func)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
-       if (hp)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
-       if (hs)
-               snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
-       else
-               snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
-
-       gpiod_set_value(pdata->tvout_selection_gpio, tvout);
-
-       snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-}
-
-static int rx51_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_card *card = rtd->card;
-
-       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-       rx51_ext_control(&card->dapm);
-
-       return 0;
-}
-
-static int rx51_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       /* Set the codec system clock for DAC and ADC */
-       return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
-                                     SND_SOC_CLOCK_IN);
-}
-
-static const struct snd_soc_ops rx51_ops = {
-       .startup = rx51_startup,
-       .hw_params = rx51_hw_params,
-};
-
-static int rx51_get_spk(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = rx51_spk_func;
-
-       return 0;
-}
-
-static int rx51_set_spk(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-
-       if (rx51_spk_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       rx51_spk_func = ucontrol->value.enumerated.item[0];
-       rx51_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static int rx51_spk_event(struct snd_soc_dapm_widget *w,
-                         struct snd_kcontrol *k, int event)
-{
-       struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_card *card = dapm->card;
-       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
-
-       gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio,
-                                    !!SND_SOC_DAPM_EVENT_ON(event));
-
-       return 0;
-}
-
-static int rx51_get_input(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = rx51_dmic_func;
-
-       return 0;
-}
-
-static int rx51_set_input(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-
-       if (rx51_dmic_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       rx51_dmic_func = ucontrol->value.enumerated.item[0];
-       rx51_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static int rx51_get_jack(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = rx51_jack_func;
-
-       return 0;
-}
-
-static int rx51_set_jack(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-
-       if (rx51_jack_func == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       rx51_jack_func = ucontrol->value.enumerated.item[0];
-       rx51_ext_control(&card->dapm);
-
-       return 1;
-}
-
-static struct snd_soc_jack rx51_av_jack;
-
-static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
-       {
-               .name = "avdet-gpio",
-               .report = SND_JACK_HEADSET,
-               .invert = 1,
-               .debounce_time = 200,
-       },
-};
-
-static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
-       SND_SOC_DAPM_MIC("DMic", NULL),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("HS Mic", NULL),
-       SND_SOC_DAPM_LINE("FM Transmitter", NULL),
-       SND_SOC_DAPM_SPK("Earphone", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"Ext Spk", NULL, "HPLOUT"},
-       {"Ext Spk", NULL, "HPROUT"},
-       {"Ext Spk", NULL, "HPLCOM"},
-       {"Ext Spk", NULL, "HPRCOM"},
-       {"FM Transmitter", NULL, "LLOUT"},
-       {"FM Transmitter", NULL, "RLOUT"},
-
-       {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"},
-       {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"},
-       {"TPA6130A2 LEFTIN", NULL, "LLOUT"},
-       {"TPA6130A2 RIGHTIN", NULL, "RLOUT"},
-
-       {"DMic Rate 64", NULL, "DMic"},
-       {"DMic", NULL, "Mic Bias"},
-
-       {"b LINE2R", NULL, "MONO_LOUT"},
-       {"Earphone", NULL, "b HPLOUT"},
-
-       {"LINE1L", NULL, "HS Mic"},
-       {"HS Mic", NULL, "b Mic Bias"},
-};
-
-static const char * const spk_function[] = {"Off", "On"};
-static const char * const input_function[] = {"ADC", "Digital Mic"};
-static const char * const jack_function[] = {
-       "Off", "TV-OUT", "Headphone", "Headset"
-};
-
-static const struct soc_enum rx51_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
-};
-
-static const struct snd_kcontrol_new aic34_rx51_controls[] = {
-       SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
-                    rx51_get_spk, rx51_set_spk),
-       SOC_ENUM_EXT("Input Select",  rx51_enum[1],
-                    rx51_get_input, rx51_set_input),
-       SOC_ENUM_EXT("Jack Function", rx51_enum[2],
-                    rx51_get_jack, rx51_set_jack),
-       SOC_DAPM_PIN_SWITCH("FM Transmitter"),
-       SOC_DAPM_PIN_SWITCH("Earphone"),
-};
-
-static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_card *card = rtd->card;
-       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
-       int err;
-
-       snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
-
-       err = omap_mcbsp_st_add_controls(rtd, 2);
-       if (err < 0) {
-               dev_err(card->dev, "Failed to add MCBSP controls\n");
-               return err;
-       }
-
-       /* AV jack detection */
-       err = snd_soc_card_jack_new(rtd->card, "AV Jack",
-                                   SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
-                                   &rx51_av_jack, NULL, 0);
-       if (err) {
-               dev_err(card->dev, "Failed to add AV Jack\n");
-               return err;
-       }
-
-       /* prepare gpio for snd_soc_jack_add_gpios */
-       rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio);
-       devm_gpiod_put(card->dev, pdata->jack_detection_gpio);
-
-       err = snd_soc_jack_add_gpios(&rx51_av_jack,
-                                    ARRAY_SIZE(rx51_av_jack_gpios),
-                                    rx51_av_jack_gpios);
-       if (err) {
-               dev_err(card->dev, "Failed to add GPIOs\n");
-               return err;
-       }
-
-       return err;
-}
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link rx51_dai[] = {
-       {
-               .name = "TLV320AIC34",
-               .stream_name = "AIC34",
-               .cpu_dai_name = "omap-mcbsp.2",
-               .codec_dai_name = "tlv320aic3x-hifi",
-               .platform_name = "omap-mcbsp.2",
-               .codec_name = "tlv320aic3x-codec.2-0018",
-               .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
-                          SND_SOC_DAIFMT_CBM_CFM,
-               .init = rx51_aic34_init,
-               .ops = &rx51_ops,
-       },
-};
-
-static struct snd_soc_aux_dev rx51_aux_dev[] = {
-       {
-               .name = "TLV320AIC34b",
-               .codec_name = "tlv320aic3x-codec.2-0019",
-       },
-       {
-               .name = "TPA61320A2",
-               .codec_name = "tpa6130a2.2-0060",
-       },
-};
-
-static struct snd_soc_codec_conf rx51_codec_conf[] = {
-       {
-               .dev_name = "tlv320aic3x-codec.2-0019",
-               .name_prefix = "b",
-       },
-       {
-               .dev_name = "tpa6130a2.2-0060",
-               .name_prefix = "TPA6130A2",
-       },
-};
-
-/* Audio card */
-static struct snd_soc_card rx51_sound_card = {
-       .name = "RX-51",
-       .owner = THIS_MODULE,
-       .dai_link = rx51_dai,
-       .num_links = ARRAY_SIZE(rx51_dai),
-       .aux_dev = rx51_aux_dev,
-       .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
-       .codec_conf = rx51_codec_conf,
-       .num_configs = ARRAY_SIZE(rx51_codec_conf),
-       .fully_routed = true,
-
-       .controls = aic34_rx51_controls,
-       .num_controls = ARRAY_SIZE(aic34_rx51_controls),
-       .dapm_widgets = aic34_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static int rx51_soc_probe(struct platform_device *pdev)
-{
-       struct rx51_audio_pdata *pdata;
-       struct device_node *np = pdev->dev.of_node;
-       struct snd_soc_card *card = &rx51_sound_card;
-       int err;
-
-       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
-               return -ENODEV;
-
-       card->dev = &pdev->dev;
-
-       if (np) {
-               struct device_node *dai_node;
-
-               dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "McBSP node is not provided\n");
-                       return -EINVAL;
-               }
-               rx51_dai[0].cpu_dai_name = NULL;
-               rx51_dai[0].platform_name = NULL;
-               rx51_dai[0].cpu_of_node = dai_node;
-               rx51_dai[0].platform_of_node = dai_node;
-
-               dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "Codec node is not provided\n");
-                       return -EINVAL;
-               }
-               rx51_dai[0].codec_name = NULL;
-               rx51_dai[0].codec_of_node = dai_node;
-
-               dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n");
-                       return -EINVAL;
-               }
-               rx51_aux_dev[0].codec_name = NULL;
-               rx51_aux_dev[0].codec_of_node = dai_node;
-               rx51_codec_conf[0].dev_name = NULL;
-               rx51_codec_conf[0].of_node = dai_node;
-
-               dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
-                       return -EINVAL;
-               }
-               rx51_aux_dev[1].codec_name = NULL;
-               rx51_aux_dev[1].codec_of_node = dai_node;
-               rx51_codec_conf[1].dev_name = NULL;
-               rx51_codec_conf[1].of_node = dai_node;
-       }
-
-       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-       if (pdata == NULL)
-               return -ENOMEM;
-
-       snd_soc_card_set_drvdata(card, pdata);
-
-       pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
-                                                    "tvout-selection",
-                                                    GPIOD_OUT_LOW);
-       if (IS_ERR(pdata->tvout_selection_gpio)) {
-               dev_err(card->dev, "could not get tvout selection gpio\n");
-               return PTR_ERR(pdata->tvout_selection_gpio);
-       }
-
-       pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
-                                                   "jack-detection",
-                                                   GPIOD_ASIS);
-       if (IS_ERR(pdata->jack_detection_gpio)) {
-               dev_err(card->dev, "could not get jack detection gpio\n");
-               return PTR_ERR(pdata->jack_detection_gpio);
-       }
-
-       pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
-                                           GPIOD_OUT_HIGH);
-       if (IS_ERR(pdata->eci_sw_gpio)) {
-               dev_err(card->dev, "could not get eci switch gpio\n");
-               return PTR_ERR(pdata->eci_sw_gpio);
-       }
-
-       pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
-                                                "speaker-amplifier",
-                                                GPIOD_OUT_LOW);
-       if (IS_ERR(pdata->speaker_amp_gpio)) {
-               dev_err(card->dev, "could not get speaker enable gpio\n");
-               return PTR_ERR(pdata->speaker_amp_gpio);
-       }
-
-       err = devm_snd_soc_register_card(card->dev, card);
-       if (err) {
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
-               return err;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_OF)
-static const struct of_device_id rx51_audio_of_match[] = {
-       { .compatible = "nokia,n900-audio", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
-#endif
-
-static struct platform_driver rx51_soc_driver = {
-       .driver = {
-               .name = "rx51-audio",
-               .of_match_table = of_match_ptr(rx51_audio_of_match),
-       },
-       .probe = rx51_soc_probe,
-};
-
-module_platform_driver(rx51_soc_driver);
-
-MODULE_AUTHOR("Nokia Corporation");
-MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:rx51-audio");
diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/omap/sdma-pcm.c
deleted file mode 100644 (file)
index 21a9c24..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
- *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
-#include <linux/omap-dmaengine.h>
-
-#include "sdma-pcm.h"
-
-static const struct snd_pcm_hardware sdma_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
-                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
-                                 SNDRV_PCM_INFO_INTERLEAVED,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 64 * 1024,
-       .buffer_bytes_max       = 128 * 1024,
-       .periods_min            = 2,
-       .periods_max            = 255,
-};
-
-static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = {
-       .pcm_hardware = &sdma_pcm_hardware,
-       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
-       .compat_filter_fn = omap_dma_filter_fn,
-       .prealloc_buffer_size = 128 * 1024,
-};
-
-int sdma_pcm_platform_register(struct device *dev,
-                              char *txdmachan, char *rxdmachan)
-{
-       struct snd_dmaengine_pcm_config *config;
-       unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT;
-
-       /* Standard names for the directions: 'tx' and 'rx' */
-       if (!txdmachan && !rxdmachan)
-               return devm_snd_dmaengine_pcm_register(dev,
-                                               &sdma_dmaengine_pcm_config,
-                                               flags);
-
-       config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
-       if (!config)
-               return -ENOMEM;
-
-       *config = sdma_dmaengine_pcm_config;
-
-       if (!txdmachan || !rxdmachan) {
-               /* One direction only PCM */
-               flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
-               if (!txdmachan) {
-                       txdmachan = rxdmachan;
-                       rxdmachan = NULL;
-               }
-       }
-
-       config->chan_names[0] = txdmachan;
-       config->chan_names[1] = rxdmachan;
-
-       return devm_snd_dmaengine_pcm_register(dev, config, flags);
-}
-EXPORT_SYMBOL_GPL(sdma_pcm_platform_register);
-
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_DESCRIPTION("sDMA PCM ASoC platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/omap/sdma-pcm.h
deleted file mode 100644 (file)
index 34a7f90..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
- *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- */
-
-#ifndef __SDMA_PCM_H__
-#define __SDMA_PCM_H__
-
-#if IS_ENABLED(CONFIG_SND_SDMA_SOC)
-int sdma_pcm_platform_register(struct device *dev,
-                              char *txdmachan, char *rxdmachan);
-#else
-static inline int sdma_pcm_platform_register(struct device *dev,
-                                            char *txdmachan, char *rxdmachan)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_SND_SDMA_SOC */
-
-#endif /* __SDMA_PCM_H__ */
index 943b44de14649539148d3d9323dce678861dab8f..67159a6b90a841be131317706aadd25bee4b3ef3 100644 (file)
@@ -79,7 +79,7 @@ config SND_PXA2XX_SOC_TOSA
        tristate "SoC AC97 Audio support for Tosa"
        depends on SND_PXA2XX_SOC && MACH_TOSA
        depends on MFD_TC6393XB
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
@@ -89,7 +89,7 @@ config SND_PXA2XX_SOC_TOSA
 config SND_PXA2XX_SOC_E740
        tristate "SoC AC97 Audio support for e740"
        depends on SND_PXA2XX_SOC && MACH_E740
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_SOC_WM9705
        select SND_PXA2XX_SOC_AC97
        help
@@ -99,7 +99,7 @@ config SND_PXA2XX_SOC_E740
 config SND_PXA2XX_SOC_E750
        tristate "SoC AC97 Audio support for e750"
        depends on SND_PXA2XX_SOC && MACH_E750
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_SOC_WM9705
        select SND_PXA2XX_SOC_AC97
        help
@@ -109,7 +109,7 @@ config SND_PXA2XX_SOC_E750
 config SND_PXA2XX_SOC_E800
        tristate "SoC AC97 Audio support for e800"
        depends on SND_PXA2XX_SOC && MACH_E800
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_SOC_WM9712
        select SND_PXA2XX_SOC_AC97
        help
@@ -120,7 +120,7 @@ config SND_PXA2XX_SOC_EM_X270
        tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
        depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
                        MACH_CM_X300)
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
@@ -131,7 +131,7 @@ config SND_PXA2XX_SOC_PALM27X
        bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
        depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
                        MACH_PALMT5 || MACH_PALMTE2)
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
@@ -161,7 +161,7 @@ config SND_SOC_TTC_DKB
 config SND_SOC_ZYLONITE
        tristate "SoC Audio support for Marvell Zylonite"
        depends on SND_PXA2XX_SOC && MACH_ZYLONITE
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
        select SND_PXA2XX_SOC_AC97
        select SND_PXA_SOC_SSP
        select SND_SOC_WM9713
@@ -169,16 +169,6 @@ config SND_SOC_ZYLONITE
          Say Y if you want to add support for SoC audio on the
          Marvell Zylonite reference platform.
 
-config SND_SOC_RAUMFELD
-       tristate "SoC Audio support Raumfeld audio adapter"
-       depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
-       depends on I2C && SPI_MASTER
-       select SND_PXA_SOC_SSP
-       select SND_SOC_CS4270
-       select SND_SOC_AK4104
-       help
-         Say Y if you want to add support for SoC audio on Raumfeld devices
-
 config SND_PXA2XX_SOC_HX4700
        tristate "SoC Audio support for HP iPAQ hx4700"
        depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
@@ -201,7 +191,7 @@ config SND_PXA2XX_SOC_MAGICIAN
 config SND_PXA2XX_SOC_MIOA701
         tristate "SoC Audio support for MIO A701"
         depends on SND_PXA2XX_SOC && MACH_MIOA701
-       depends on !AC97_BUS
+       depends on AC97_BUS=n
         select SND_PXA2XX_SOC_AC97
         select SND_SOC_WM9713
         help
index 5b265662f04fea8a2f1aae31669b3718e8956ee9..0ab2a9dcb7205a9d589c4c06edb2c5466046f6d4 100644 (file)
@@ -49,6 +49,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
-obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
 obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
 obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
deleted file mode 100644 (file)
index 111a907..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * raumfeld_audio.c  --  SoC audio for Raumfeld audio devices
- *
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- *
- * based on code from:
- *
- *    Wolfson Microelectronics PLC.
- *    Openedhand Ltd.
- *    Liam Girdwood <lrg@slimlogic.co.uk>
- *    Richard Purdie <richard@openedhand.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-
-#include "pxa-ssp.h"
-
-#define GPIO_SPDIF_RESET       (38)
-#define GPIO_MCLK_RESET                (111)
-#define GPIO_CODEC_RESET       (120)
-
-static struct i2c_client *max9486_client;
-static struct i2c_board_info max9486_hwmon_info = {
-       I2C_BOARD_INFO("max9485", 0x63),
-};
-
-#define MAX9485_MCLK_FREQ_112896 0x22
-#define MAX9485_MCLK_FREQ_122880 0x23
-#define MAX9485_MCLK_FREQ_225792 0x32
-#define MAX9485_MCLK_FREQ_245760 0x33
-
-static void set_max9485_clk(char clk)
-{
-       i2c_master_send(max9486_client, &clk, 1);
-}
-
-static void raumfeld_enable_audio(bool en)
-{
-       if (en) {
-               gpio_set_value(GPIO_MCLK_RESET, 1);
-
-               /* wait some time to let the clocks become stable */
-               msleep(100);
-
-               gpio_set_value(GPIO_SPDIF_RESET, 1);
-               gpio_set_value(GPIO_CODEC_RESET, 1);
-       } else {
-               gpio_set_value(GPIO_MCLK_RESET, 0);
-               gpio_set_value(GPIO_SPDIF_RESET, 0);
-               gpio_set_value(GPIO_CODEC_RESET, 0);
-       }
-}
-
-/* CS4270 */
-static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       /* set freq to 0 to enable all possible codec sample rates */
-       return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       /* set freq to 0 to enable all possible codec sample rates */
-       snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
-                                    struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int clk = 0;
-       int ret = 0;
-
-       switch (params_rate(params)) {
-       case 44100:
-               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
-               clk = 11289600;
-               break;
-       case 48000:
-               set_max9485_clk(MAX9485_MCLK_FREQ_122880);
-               clk = 12288000;
-               break;
-       case 88200:
-               set_max9485_clk(MAX9485_MCLK_FREQ_225792);
-               clk = 22579200;
-               break;
-       case 96000:
-               set_max9485_clk(MAX9485_MCLK_FREQ_245760);
-               clk = 24576000;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
-       if (ret < 0)
-               return ret;
-
-       /* setup the CPU DAI */
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static const struct snd_soc_ops raumfeld_cs4270_ops = {
-       .startup = raumfeld_cs4270_startup,
-       .shutdown = raumfeld_cs4270_shutdown,
-       .hw_params = raumfeld_cs4270_hw_params,
-};
-
-static int raumfeld_analog_suspend(struct snd_soc_card *card)
-{
-       raumfeld_enable_audio(false);
-       return 0;
-}
-
-static int raumfeld_analog_resume(struct snd_soc_card *card)
-{
-       raumfeld_enable_audio(true);
-       return 0;
-}
-
-/* AK4104 */
-
-static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
-                                    struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret = 0, clk = 0;
-
-       switch (params_rate(params)) {
-       case 44100:
-               set_max9485_clk(MAX9485_MCLK_FREQ_112896);
-               clk = 11289600;
-               break;
-       case 48000:
-               set_max9485_clk(MAX9485_MCLK_FREQ_122880);
-               clk = 12288000;
-               break;
-       case 88200:
-               set_max9485_clk(MAX9485_MCLK_FREQ_225792);
-               clk = 22579200;
-               break;
-       case 96000:
-               set_max9485_clk(MAX9485_MCLK_FREQ_245760);
-               clk = 24576000;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* setup the CPU DAI */
-       ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops raumfeld_ak4104_ops = {
-       .hw_params = raumfeld_ak4104_hw_params,
-};
-
-#define DAI_LINK_CS4270                \
-{                                                      \
-       .name           = "CS4270",                     \
-       .stream_name    = "CS4270",                     \
-       .cpu_dai_name   = "pxa-ssp-dai.0",              \
-       .platform_name  = "pxa-pcm-audio",              \
-       .codec_dai_name = "cs4270-hifi",                \
-       .codec_name     = "cs4270.0-0048",      \
-       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
-                         SND_SOC_DAIFMT_NB_NF |        \
-                         SND_SOC_DAIFMT_CBS_CFS,       \
-       .ops            = &raumfeld_cs4270_ops,         \
-}
-
-#define DAI_LINK_AK4104                \
-{                                                      \
-       .name           = "ak4104",                     \
-       .stream_name    = "Playback",                   \
-       .cpu_dai_name   = "pxa-ssp-dai.1",              \
-       .codec_dai_name = "ak4104-hifi",                \
-       .platform_name  = "pxa-pcm-audio",              \
-       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
-                         SND_SOC_DAIFMT_NB_NF |        \
-                         SND_SOC_DAIFMT_CBS_CFS,       \
-       .ops            = &raumfeld_ak4104_ops,         \
-       .codec_name     = "spi0.0",                     \
-}
-
-static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = {
-       DAI_LINK_CS4270,
-       DAI_LINK_AK4104,
-};
-
-static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = {
-       DAI_LINK_CS4270,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_connector = {
-       .name           = "Raumfeld Connector",
-       .owner          = THIS_MODULE,
-       .dai_link       = snd_soc_raumfeld_connector_dai,
-       .num_links      = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
-       .suspend_post   = raumfeld_analog_suspend,
-       .resume_pre     = raumfeld_analog_resume,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_speaker = {
-       .name           = "Raumfeld Speaker",
-       .owner          = THIS_MODULE,
-       .dai_link       = snd_soc_raumfeld_speaker_dai,
-       .num_links      = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
-       .suspend_post   = raumfeld_analog_suspend,
-       .resume_pre     = raumfeld_analog_resume,
-};
-
-static struct platform_device *raumfeld_audio_device;
-
-static int __init raumfeld_audio_init(void)
-{
-       int ret;
-
-       if (!machine_is_raumfeld_speaker() &&
-           !machine_is_raumfeld_connector())
-               return 0;
-
-       max9486_client = i2c_new_device(i2c_get_adapter(0),
-                                       &max9486_hwmon_info);
-
-       if (!max9486_client)
-               return -ENOMEM;
-
-       set_max9485_clk(MAX9485_MCLK_FREQ_122880);
-
-       /* Register analog device */
-       raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
-       if (!raumfeld_audio_device)
-               return -ENOMEM;
-
-       if (machine_is_raumfeld_speaker())
-               platform_set_drvdata(raumfeld_audio_device,
-                                    &snd_soc_raumfeld_speaker);
-
-       if (machine_is_raumfeld_connector())
-               platform_set_drvdata(raumfeld_audio_device,
-                                    &snd_soc_raumfeld_connector);
-
-       ret = platform_device_add(raumfeld_audio_device);
-       if (ret < 0) {
-               platform_device_put(raumfeld_audio_device);
-               return ret;
-       }
-
-       raumfeld_enable_audio(true);
-       return 0;
-}
-
-static void __exit raumfeld_audio_exit(void)
-{
-       raumfeld_enable_audio(false);
-
-       platform_device_unregister(raumfeld_audio_device);
-
-       i2c_unregister_device(max9486_client);
-
-       gpio_free(GPIO_MCLK_RESET);
-       gpio_free(GPIO_CODEC_RESET);
-       gpio_free(GPIO_SPDIF_RESET);
-}
-
-module_init(raumfeld_audio_init);
-module_exit(raumfeld_audio_exit);
-
-/* Module information */
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("Raumfeld audio SoC");
-MODULE_LICENSE("GPL");
index 2a4c912d1e484df0c605af91371fa6ee3460bf63..804ae0d930589e80448d0c3ec57a64a348a24230 100644 (file)
@@ -66,6 +66,7 @@ config SND_SOC_QDSP6_ASM
        tristate
 
 config SND_SOC_QDSP6_ASM_DAI
+       select SND_SOC_COMPRESS
        tristate
 
 config SND_SOC_QDSP6
@@ -100,6 +101,7 @@ config SND_SOC_SDM845
        depends on QCOM_APR
        select SND_SOC_QDSP6
        select SND_SOC_QCOM_COMMON
+       select SND_SOC_RT5663
        help
          To add support for audio on Qualcomm Technologies Inc.
          SDM845 SoC-based systems.
index d07271ea4c45165b694a51777af7957b36d454ad..028bce671cbcfee3492a2b8cad9d66ea23f0ab77 100644 (file)
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
        if (ret) {
                dev_err(soc_runtime->dev,
                        "error writing to rdmactl reg: %d\n", ret);
-                       return ret;
+               return ret;
        }
 
        data->dma_ch = dma_ch;
index 8f6c8fc073a93048cb2e33d8439105ac2dc7d025..dc645ba4d8d0879c7e12aaa3353a64fa78590f8a 100644 (file)
@@ -341,6 +341,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
 
        switch (dai->id) {
        case HDMI_RX:
+       case DISPLAY_PORT_RX:
                q6afe_hdmi_port_prepare(dai_data->port[dai->id],
                                        &dai_data->port_config[dai->id].hdmi);
                break;
@@ -445,6 +446,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
 
 static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
        {"HDMI Playback", NULL, "HDMI_RX"},
+       {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
        {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
        {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
        {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
@@ -561,13 +563,13 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
        {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
 };
 
-static struct snd_soc_dai_ops q6hdmi_ops = {
+static const struct snd_soc_dai_ops q6hdmi_ops = {
        .prepare        = q6afe_dai_prepare,
        .hw_params      = q6hdmi_hw_params,
        .shutdown       = q6afe_dai_shutdown,
 };
 
-static struct snd_soc_dai_ops q6i2s_ops = {
+static const struct snd_soc_dai_ops q6i2s_ops = {
        .prepare        = q6afe_dai_prepare,
        .hw_params      = q6i2s_hw_params,
        .set_fmt        = q6i2s_set_fmt,
@@ -575,14 +577,14 @@ static struct snd_soc_dai_ops q6i2s_ops = {
        .set_sysclk     = q6afe_mi2s_set_sysclk,
 };
 
-static struct snd_soc_dai_ops q6slim_ops = {
+static const struct snd_soc_dai_ops q6slim_ops = {
        .prepare        = q6afe_dai_prepare,
        .hw_params      = q6slim_hw_params,
        .shutdown       = q6afe_dai_shutdown,
        .set_channel_map = q6slim_set_channel_map,
 };
 
-static struct snd_soc_dai_ops q6tdm_ops = {
+static const struct snd_soc_dai_ops q6tdm_ops = {
        .prepare        = q6afe_dai_prepare,
        .shutdown       = q6afe_dai_shutdown,
        .set_sysclk     = q6afe_mi2s_set_sysclk,
@@ -1090,6 +1092,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
        Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
        Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
        Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
+       {
+               .playback = {
+                       .stream_name = "Display Port Playback",
+                       .rates = SNDRV_PCM_RATE_48000 |
+                                SNDRV_PCM_RATE_96000 |
+                                SNDRV_PCM_RATE_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_LE,
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rate_max =     192000,
+                       .rate_min =     48000,
+               },
+               .ops = &q6hdmi_ops,
+               .id = DISPLAY_PORT_RX,
+               .name = "DISPLAY_PORT",
+               .probe = msm_dai_q6_dai_probe,
+               .remove = msm_dai_q6_dai_remove,
+       },
 };
 
 static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -1311,6 +1332,7 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
                                                0, 0, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
                                                0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0),
 };
 
 static const struct snd_soc_component_driver q6afe_dai_component = {
index 829b5e987b2aaf03d234fc79f276bb5e324ba715..e0945f7a58c816e5c6b7dda7cc7073aeb8aa3bb6 100644 (file)
@@ -71,6 +71,7 @@
 /* Port IDs */
 #define AFE_API_VERSION_HDMI_CONFIG    0x1
 #define AFE_PORT_ID_MULTICHAN_HDMI_RX  0x100E
+#define AFE_PORT_ID_HDMI_OVER_DP_RX    0x6020
 
 #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
 /* Clock set API version */
@@ -704,6 +705,8 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
                                QUINARY_TDM_RX_7, 1, 1},
        [QUINARY_TDM_TX_7] =  { AFE_PORT_ID_QUINARY_TDM_TX_7,
                                QUINARY_TDM_TX_7, 0, 1},
+       [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX,
+                               DISPLAY_PORT_RX, 1, 1},
 };
 
 static void q6afe_port_free(struct kref *ref)
@@ -1384,6 +1387,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
 
        switch (port_id) {
        case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+       case AFE_PORT_ID_HDMI_OVER_DP_RX:
                cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
                break;
        case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
index 86115de5c1b2a1bd16a42a13305b4c62d6feee27..5b986b74dd36f96d0a4a37bc8714f0b741c39486 100644 (file)
@@ -10,6 +10,8 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <sound/compress_driver.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/of_device.h>
 #define CAPTURE_MIN_PERIOD_SIZE     320
 #define SID_MASK_DEFAULT       0xF
 
+/* Default values used if user space does not set */
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
+#define Q6ASM_DAI_TX_RX        0
+#define Q6ASM_DAI_TX   1
+#define Q6ASM_DAI_RX   2
+
 enum stream_state {
        Q6ASM_STREAM_IDLE = 0,
        Q6ASM_STREAM_STOPPED,
@@ -38,11 +49,18 @@ enum stream_state {
 
 struct q6asm_dai_rtd {
        struct snd_pcm_substream *substream;
+       struct snd_compr_stream *cstream;
+       struct snd_compr_params codec_param;
+       struct snd_dma_buffer dma_buffer;
+       spinlock_t lock;
        phys_addr_t phys;
        unsigned int pcm_size;
        unsigned int pcm_count;
        unsigned int pcm_irq_pos;       /* IRQ position */
        unsigned int periods;
+       unsigned int bytes_sent;
+       unsigned int bytes_received;
+       unsigned int copied_total;
        uint16_t bits_per_sample;
        uint16_t source; /* Encoding source bit mask */
        struct audio_client *audio_client;
@@ -137,6 +155,21 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
        .mask = 0,
 };
 
+static const struct snd_compr_codec_caps q6asm_compr_caps = {
+       .num_descriptors = 1,
+       .descriptor[0].max_ch = 2,
+       .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
+                                       24000, 32000, 44100, 48000, 88200,
+                                       96000, 176400, 192000 },
+       .descriptor[0].num_sample_rates = 13,
+       .descriptor[0].bit_rate[0] = 320,
+       .descriptor[0].bit_rate[1] = 128,
+       .descriptor[0].num_bitrates = 2,
+       .descriptor[0].profiles = 0,
+       .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+       .descriptor[0].formats = 0,
+};
+
 static void event_handler(uint32_t opcode, uint32_t token,
                          uint32_t *payload, void *priv)
 {
@@ -460,6 +493,306 @@ static struct snd_pcm_ops q6asm_dai_ops = {
        .mmap           = q6asm_dai_mmap,
 };
 
+static void compress_event_handler(uint32_t opcode, uint32_t token,
+                                  uint32_t *payload, void *priv)
+{
+       struct q6asm_dai_rtd *prtd = priv;
+       struct snd_compr_stream *substream = prtd->cstream;
+       unsigned long flags;
+       uint64_t avail;
+
+       switch (opcode) {
+       case ASM_CLIENT_EVENT_CMD_RUN_DONE:
+               spin_lock_irqsave(&prtd->lock, flags);
+               if (!prtd->bytes_sent) {
+                       q6asm_write_async(prtd->audio_client, prtd->pcm_count,
+                                         0, 0, NO_TIMESTAMP);
+                       prtd->bytes_sent += prtd->pcm_count;
+               }
+
+               spin_unlock_irqrestore(&prtd->lock, flags);
+               break;
+
+       case ASM_CLIENT_EVENT_CMD_EOS_DONE:
+               prtd->state = Q6ASM_STREAM_STOPPED;
+               break;
+
+       case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
+               spin_lock_irqsave(&prtd->lock, flags);
+
+               prtd->copied_total += prtd->pcm_count;
+               snd_compr_fragment_elapsed(substream);
+
+               if (prtd->state != Q6ASM_STREAM_RUNNING) {
+                       spin_unlock_irqrestore(&prtd->lock, flags);
+                       break;
+               }
+
+               avail = prtd->bytes_received - prtd->bytes_sent;
+
+               if (avail >= prtd->pcm_count) {
+                       q6asm_write_async(prtd->audio_client,
+                                          prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+                       prtd->bytes_sent += prtd->pcm_count;
+               }
+
+               spin_unlock_irqrestore(&prtd->lock, flags);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
+{
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
+       struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct q6asm_dai_data *pdata;
+       struct device *dev = c->dev;
+       struct q6asm_dai_rtd *prtd;
+       int stream_id, size, ret;
+
+       stream_id = cpu_dai->driver->id;
+       pdata = snd_soc_component_get_drvdata(c);
+       if (!pdata) {
+               dev_err(dev, "Drv data not found ..\n");
+               return -EINVAL;
+       }
+
+       prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+       if (!prtd)
+               return -ENOMEM;
+
+       prtd->cstream = stream;
+       prtd->audio_client = q6asm_audio_client_alloc(dev,
+                                       (q6asm_cb)compress_event_handler,
+                                       prtd, stream_id, LEGACY_PCM_MODE);
+       if (!prtd->audio_client) {
+               dev_err(dev, "Could not allocate memory\n");
+               kfree(prtd);
+               return -ENOMEM;
+       }
+
+       size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
+                       COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+                                 &prtd->dma_buffer);
+       if (ret) {
+               dev_err(dev, "Cannot allocate buffer(s)\n");
+               return ret;
+       }
+
+       if (pdata->sid < 0)
+               prtd->phys = prtd->dma_buffer.addr;
+       else
+               prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
+
+       snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
+       spin_lock_init(&prtd->lock);
+       runtime->private_data = prtd;
+
+       return 0;
+}
+
+static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
+
+       if (prtd->audio_client) {
+               if (prtd->state)
+                       q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+
+               snd_dma_free_pages(&prtd->dma_buffer);
+               q6asm_unmap_memory_regions(stream->direction,
+                                          prtd->audio_client);
+               q6asm_audio_client_free(prtd->audio_client);
+               prtd->audio_client = NULL;
+       }
+       q6routing_stream_close(rtd->dai_link->id, stream->direction);
+       kfree(prtd);
+
+       return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
+                                     struct snd_compr_params *params)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
+       struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+       int dir = stream->direction;
+       struct q6asm_dai_data *pdata;
+       struct device *dev = c->dev;
+       int ret;
+
+       memcpy(&prtd->codec_param, params, sizeof(*params));
+
+       pdata = snd_soc_component_get_drvdata(c);
+       if (!pdata)
+               return -EINVAL;
+
+       if (!prtd || !prtd->audio_client) {
+               dev_err(dev, "private data null or audio client freed\n");
+               return -EINVAL;
+       }
+
+       prtd->periods = runtime->fragments;
+       prtd->pcm_count = runtime->fragment_size;
+       prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+       prtd->bits_per_sample = 16;
+       if (dir == SND_COMPRESS_PLAYBACK) {
+               ret = q6asm_open_write(prtd->audio_client, params->codec.id,
+                                       prtd->bits_per_sample);
+
+               if (ret < 0) {
+                       dev_err(dev, "q6asm_open_write failed\n");
+                       q6asm_audio_client_free(prtd->audio_client);
+                       prtd->audio_client = NULL;
+                       return ret;
+               }
+       }
+
+       prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+       ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+                             prtd->session_id, dir);
+       if (ret) {
+               dev_err(dev, "Stream reg failed ret:%d\n", ret);
+               return ret;
+       }
+
+       ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
+                                      (prtd->pcm_size / prtd->periods),
+                                      prtd->periods);
+
+       if (ret < 0) {
+               dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
+               return -ENOMEM;
+       }
+
+       prtd->state = Q6ASM_STREAM_RUNNING;
+
+       return 0;
+}
+
+static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               prtd->state = Q6ASM_STREAM_STOPPED;
+               ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
+               struct snd_compr_tstamp *tstamp)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&prtd->lock, flags);
+
+       tstamp->copied_total = prtd->copied_total;
+       tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
+
+       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       return 0;
+}
+
+static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
+                               size_t count)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&prtd->lock, flags);
+       prtd->bytes_received += count;
+       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       return count;
+}
+
+static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
+               struct vm_area_struct *vma)
+{
+       struct snd_compr_runtime *runtime = stream->runtime;
+       struct q6asm_dai_rtd *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = stream->private_data;
+       struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+       struct device *dev = c->dev;
+
+       return dma_mmap_coherent(dev, vma,
+                       prtd->dma_buffer.area, prtd->dma_buffer.addr,
+                       prtd->dma_buffer.bytes);
+}
+
+static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
+                                   struct snd_compr_caps *caps)
+{
+       caps->direction = SND_COMPRESS_PLAYBACK;
+       caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
+       caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
+       caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
+       caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+       caps->num_codecs = 1;
+       caps->codecs[0] = SND_AUDIOCODEC_MP3;
+
+       return 0;
+}
+
+static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
+                                         struct snd_compr_codec_caps *codec)
+{
+       switch (codec->codec) {
+       case SND_AUDIOCODEC_MP3:
+               *codec = q6asm_compr_caps;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct snd_compr_ops q6asm_dai_compr_ops = {
+       .open           = q6asm_dai_compr_open,
+       .free           = q6asm_dai_compr_free,
+       .set_params     = q6asm_dai_compr_set_params,
+       .pointer        = q6asm_dai_compr_pointer,
+       .trigger        = q6asm_dai_compr_trigger,
+       .get_caps       = q6asm_dai_compr_get_caps,
+       .get_codec_caps = q6asm_dai_compr_get_codec_caps,
+       .mmap           = q6asm_dai_compr_mmap,
+       .ack            = q6asm_dai_compr_ack,
+};
+
 static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm_substream *psubstream, *csubstream;
@@ -515,7 +848,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
        .ops            = &q6asm_dai_ops,
        .pcm_new        = q6asm_dai_pcm_new,
        .pcm_free       = q6asm_dai_pcm_free,
-
+       .compr_ops      = &q6asm_dai_compr_ops,
 };
 
 static struct snd_soc_dai_driver q6asm_fe_dais[] = {
@@ -529,6 +862,41 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = {
        Q6ASM_FEDAI_DRIVER(8),
 };
 
+static int of_q6asm_parse_dai_data(struct device *dev,
+                                   struct q6asm_dai_data *pdata)
+{
+       static struct snd_soc_dai_driver *dai_drv;
+       struct snd_soc_pcm_stream empty_stream;
+       struct device_node *node;
+       int ret, id, dir;
+
+       memset(&empty_stream, 0, sizeof(empty_stream));
+
+       for_each_child_of_node(dev->of_node, node) {
+               ret = of_property_read_u32(node, "reg", &id);
+               if (ret || id > MAX_SESSIONS || id < 0) {
+                       dev_err(dev, "valid dai id not found:%d\n", ret);
+                       continue;
+               }
+
+               dai_drv = &q6asm_fe_dais[id];
+
+               ret = of_property_read_u32(node, "direction", &dir);
+               if (ret)
+                       continue;
+
+               if (dir == Q6ASM_DAI_RX)
+                       dai_drv->capture = empty_stream;
+               else if (dir == Q6ASM_DAI_TX)
+                       dai_drv->playback = empty_stream;
+
+               if (of_property_read_bool(node, "is-compress-dai"))
+                       dai_drv->compress_new = snd_soc_new_compress;
+       }
+
+       return 0;
+}
+
 static int q6asm_dai_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -549,6 +917,8 @@ static int q6asm_dai_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, pdata);
 
+       of_q6asm_parse_dai_data(dev, pdata);
+
        return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
                                        q6asm_fe_dais,
                                        ARRAY_SIZE(q6asm_fe_dais));
index e1cfa846a1dcf40664892fc713966033ac1bf43b..4f85cb19a3091df9b0c3abf4379a04a515758553 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kref.h>
 #include <linux/of.h>
 #include <uapi/sound/asound.h>
+#include <uapi/sound/compress_params.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -36,6 +37,7 @@
 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2     0x00010DA3
 #define ASM_SESSION_CMD_RUN_V2                 0x00010DAA
 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2     0x00010DA5
+#define ASM_MEDIA_FMT_MP3                      0x00010BE9
 #define ASM_DATA_CMD_WRITE_V2                  0x00010DAB
 #define ASM_DATA_CMD_READ_V2                   0x00010DAC
 #define ASM_SESSION_CMD_SUSPEND                        0x00010DEC
@@ -868,6 +870,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
        open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
 
        switch (format) {
+       case SND_AUDIOCODEC_MP3:
+               open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
+               break;
        case FORMAT_LINEAR_PCM:
                open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
                break;
index d61b8404f7da999c2326e2aa6ee26522a044257e..ddcd9978cf57b8c6310b9c114f1f58c75efd51db 100644 (file)
@@ -453,6 +453,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
 static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
        Q6ROUTING_RX_MIXERS(HDMI_RX) };
 
+static const struct snd_kcontrol_new display_port_mixer_controls[] = {
+       Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) };
+
 static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
        Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
 
@@ -655,6 +658,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
                           hdmi_mixer_controls,
                           ARRAY_SIZE(hdmi_mixer_controls)),
 
+       SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+                          display_port_mixer_controls,
+                          ARRAY_SIZE(display_port_mixer_controls)),
+
        SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
                           slimbus_rx_mixer_controls,
                           ARRAY_SIZE(slimbus_rx_mixer_controls)),
@@ -833,6 +840,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 
 static const struct snd_soc_dapm_route intercon[] = {
        Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+       Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer",
+                               "DISPLAY_PORT_RX"),
        Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
        Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
        Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
index 9effbecc571f6b319812a301aba7777f34c17fa0..1db8ef6682233feaf38145efb07af877c28a1ef2 100644 (file)
@@ -6,18 +6,31 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
 #include "common.h"
 #include "qdsp6/q6afe.h"
+#include "../codecs/rt5663.h"
 
 #define DEFAULT_SAMPLE_RATE_48K                48000
 #define DEFAULT_MCLK_RATE              24576000
-#define DEFAULT_BCLK_RATE              12288000
+#define TDM_BCLK_RATE          6144000
+#define MI2S_BCLK_RATE         1536000
+#define LEFT_SPK_TDM_TX_MASK    0x30
+#define RIGHT_SPK_TDM_TX_MASK   0xC0
+#define SPK_TDM_RX_MASK         0x03
+#define NUM_TDM_SLOTS           8
 
 struct sdm845_snd_data {
+       struct snd_soc_jack jack;
+       bool jack_setup;
        struct snd_soc_card *card;
        uint32_t pri_mi2s_clk_count;
+       uint32_t sec_mi2s_clk_count;
        uint32_t quat_tdm_clk_count;
 };
 
@@ -28,12 +41,12 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret = 0;
+       int ret = 0, j;
        int channels, slot_width;
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               slot_width = 32;
+               slot_width = 16;
                break;
        default:
                dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
@@ -75,6 +88,35 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
                        goto end;
                }
        }
+
+       for (j = 0; j < rtd->num_codecs; j++) {
+               struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+               if (!strcmp(codec_dai->component->name_prefix, "Left")) {
+                       ret = snd_soc_dai_set_tdm_slot(
+                                       codec_dai, LEFT_SPK_TDM_TX_MASK,
+                                       SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+                                       slot_width);
+                       if (ret < 0) {
+                               dev_err(rtd->dev,
+                                       "DEV0 TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+
+               if (!strcmp(codec_dai->component->name_prefix, "Right")) {
+                       ret = snd_soc_dai_set_tdm_slot(
+                                       codec_dai, RIGHT_SPK_TDM_TX_MASK,
+                                       SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+                                       slot_width);
+                       if (ret < 0) {
+                               dev_err(rtd->dev,
+                                       "DEV1 TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+
 end:
        return ret;
 }
@@ -84,9 +126,27 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        switch (cpu_dai->id) {
+       case PRIMARY_MI2S_RX:
+       case PRIMARY_MI2S_TX:
+               /*
+                * Use ASRC for internal clocks, as PLL rate isn't multiple
+                * of BCLK.
+                */
+               rt5663_sel_asrc_clk_src(
+                       codec_dai->component,
+                       RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+                       RT5663_CLK_SEL_I2S1_ASRC);
+               ret = snd_soc_dai_set_sysclk(
+                       codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
+                       SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       dev_err(rtd->dev,
+                               "snd_soc_dai_set_sysclk err = %d\n", ret);
+               break;
        case QUATERNARY_TDM_RX_0:
        case QUATERNARY_TDM_TX_0:
                ret = sdm845_tdm_snd_hw_params(substream, params);
@@ -98,24 +158,87 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *component;
+       struct snd_soc_dai_link *dai_link = rtd->dai_link;
+       struct snd_soc_card *card = rtd->card;
+       struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
+       int i, rval;
+
+       if (!pdata->jack_setup) {
+               struct snd_jack *jack;
+
+               rval = snd_soc_card_jack_new(card, "Headset Jack",
+                               SND_JACK_HEADSET |
+                               SND_JACK_HEADPHONE |
+                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                               SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                               &pdata->jack, NULL, 0);
+
+               if (rval < 0) {
+                       dev_err(card->dev, "Unable to add Headphone Jack\n");
+                       return rval;
+               }
+
+               jack = pdata->jack.jack;
+
+               snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+               snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+               snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+               snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+               pdata->jack_setup = true;
+       }
+
+       for (i = 0 ; i < dai_link->num_codecs; i++) {
+               struct snd_soc_dai *dai = rtd->codec_dais[i];
+
+               component = dai->component;
+               rval = snd_soc_component_set_jack(
+                               component, &pdata->jack, NULL);
+               if (rval != 0 && rval != -ENOTSUPP) {
+                       dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+                       return rval;
+               }
+       }
+
+       return 0;
+}
+
+
 static int sdm845_snd_startup(struct snd_pcm_substream *substream)
 {
        unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_card *card = rtd->card;
        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int j;
+       int ret;
 
        switch (cpu_dai->id) {
        case PRIMARY_MI2S_RX:
        case PRIMARY_MI2S_TX:
+               codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
                if (++(data->pri_mi2s_clk_count) == 1) {
                        snd_soc_dai_set_sysclk(cpu_dai,
                                Q6AFE_LPASS_CLK_ID_MCLK_1,
                                DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
                        snd_soc_dai_set_sysclk(cpu_dai,
                                Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
-                               DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+                               MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+               snd_soc_dai_set_fmt(cpu_dai, fmt);
+               snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+               break;
+
+       case SECONDARY_MI2S_TX:
+               if (++(data->sec_mi2s_clk_count) == 1) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+                               MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
                }
                snd_soc_dai_set_fmt(cpu_dai, fmt);
                break;
@@ -125,7 +248,35 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
                if (++(data->quat_tdm_clk_count) == 1) {
                        snd_soc_dai_set_sysclk(cpu_dai,
                                Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
-                               DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+                               TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+
+               codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
+
+               for (j = 0; j < rtd->num_codecs; j++) {
+                       codec_dai = rtd->codec_dais[j];
+
+                       if (!strcmp(codec_dai->component->name_prefix,
+                                   "Left")) {
+                               ret = snd_soc_dai_set_fmt(
+                                               codec_dai, codec_dai_fmt);
+                               if (ret < 0) {
+                                       dev_err(rtd->dev,
+                                               "Left TDM fmt err:%d\n", ret);
+                                       return ret;
+                               }
+                       }
+
+                       if (!strcmp(codec_dai->component->name_prefix,
+                                   "Right")) {
+                               ret = snd_soc_dai_set_fmt(
+                                               codec_dai, codec_dai_fmt);
+                               if (ret < 0) {
+                                       dev_err(rtd->dev,
+                                               "Right TDM slot err:%d\n", ret);
+                                       return ret;
+                               }
+                       }
                }
                break;
 
@@ -156,6 +307,14 @@ static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
                };
                break;
 
+       case SECONDARY_MI2S_TX:
+               if (--(data->sec_mi2s_clk_count) == 0) {
+                       snd_soc_dai_set_sysclk(cpu_dai,
+                               Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+                               0, SNDRV_PCM_STREAM_CAPTURE);
+               }
+               break;
+
        case QUATERNARY_TDM_RX_0:
        case QUATERNARY_TDM_TX_0:
                if (--(data->quat_tdm_clk_count) == 0) {
@@ -171,7 +330,7 @@ static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
        }
 }
 
-static struct snd_soc_ops sdm845_be_ops = {
+static const struct snd_soc_ops sdm845_be_ops = {
        .hw_params = sdm845_snd_hw_params,
        .startup = sdm845_snd_startup,
        .shutdown = sdm845_snd_shutdown,
@@ -193,7 +352,15 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static void sdm845_add_be_ops(struct snd_soc_card *card)
+static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static void sdm845_add_ops(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *link;
        int i;
@@ -203,6 +370,7 @@ static void sdm845_add_be_ops(struct snd_soc_card *card)
                        link->ops = &sdm845_be_ops;
                        link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
                }
+               link->init = sdm845_dai_init;
        }
 }
 
@@ -224,6 +392,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
                goto data_alloc_fail;
        }
 
+       card->dapm_widgets = sdm845_snd_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
        card->dev = dev;
        dev_set_drvdata(dev, card);
        ret = qcom_snd_parse_of(card);
@@ -235,7 +405,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
        data->card = card;
        snd_soc_card_set_drvdata(card, data);
 
-       sdm845_add_be_ops(card);
+       sdm845_add_ops(card);
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(dev, "Sound card registration failed\n");
index 28327dd2c6cb4e0e4110dc4787ecaa7e8884646f..e821ccc70f478eeb2ef9fae75bcb3c5156f96b38 100644 (file)
@@ -249,28 +249,8 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
        out  = out      << shift;
        mask = 0x0f1f   << shift;
 
-       switch (id / 2) {
-       case 0:
-               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0,  mask, in);
-               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
-               break;
-       case 1:
-               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1,  mask, in);
-               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
-               break;
-       case 2:
-               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2,  mask, in);
-               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
-               break;
-       case 3:
-               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3,  mask, in);
-               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
-               break;
-       case 4:
-               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4,  mask, in);
-               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
-               break;
-       }
+       rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2),  mask, in);
+       rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
 
        if (en)
                rsnd_mod_bset(adg_mod, DIV_EN, en, en);
@@ -299,17 +279,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
        if (id == 8)
                return;
 
-       switch (id / 4) {
-       case 0:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
-               break;
-       case 1:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
-               break;
-       case 2:
-               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
-               break;
-       }
+       rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
 
        dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
 }
@@ -613,7 +583,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
                return -ENOMEM;
 
        ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
-                     NULL, NULL, 0, 0);
+                     NULL, 0, 0);
        if (ret)
                return ret;
 
index cc191cd5fb82dcb768f04ed5e1d0b69f7ce952c4..e6bb6a9a068493fe6de083806e45f538ccff28cd 100644 (file)
@@ -116,10 +116,11 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod,
 }
 
 static struct rsnd_mod_ops rsnd_cmd_ops = {
-       .name   = CMD_NAME,
-       .init   = rsnd_cmd_init,
-       .start  = rsnd_cmd_start,
-       .stop   = rsnd_cmd_stop,
+       .name           = CMD_NAME,
+       .init           = rsnd_cmd_init,
+       .start          = rsnd_cmd_start,
+       .stop           = rsnd_cmd_stop,
+       .get_status     = rsnd_mod_get_status,
 };
 
 static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
@@ -162,7 +163,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
        for_each_rsnd_cmd(cmd, priv, i) {
                ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
                                    &rsnd_cmd_ops, NULL,
-                                   rsnd_mod_get_status, RSND_MOD_CMD, i);
+                                   RSND_MOD_CMD, i);
                if (ret)
                        return ret;
        }
index f930f51b686fc95fd78c973576548582b67bb5aa..59e250cc2e9df285d778d7939a4812a3c90219df 100644 (file)
@@ -123,8 +123,8 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
                struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
                struct device *dev = rsnd_priv_to_dev(priv);
 
-               dev_warn(dev, "%s[%d] is not your expected module\n",
-                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+               dev_warn(dev, "%s is not your expected module\n",
+                        rsnd_mod_name(mod));
        }
 }
 
@@ -137,20 +137,69 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
        return mod->ops->dma_req(io, mod);
 }
 
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
-                        struct rsnd_mod *mod,
+#define MOD_NAME_NUM   5
+#define MOD_NAME_SIZE 16
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+       static char names[MOD_NAME_NUM][MOD_NAME_SIZE];
+       static int num;
+       char *name = names[num];
+
+       num++;
+       if (num >= MOD_NAME_NUM)
+               num = 0;
+
+       /*
+        * Let's use same char to avoid pointlessness memory
+        * Thus, rsnd_mod_name() should be used immediately
+        * Don't keep pointer
+        */
+       if ((mod)->ops->id_sub) {
+               snprintf(name, MOD_NAME_SIZE, "%s[%d%d]",
+                        mod->ops->name,
+                        rsnd_mod_id(mod),
+                        rsnd_mod_id_sub(mod));
+       } else {
+               snprintf(name, MOD_NAME_SIZE, "%s[%d]",
+                        mod->ops->name,
+                        rsnd_mod_id(mod));
+       }
+
+       return name;
+}
+
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         enum rsnd_mod_type type)
 {
        return &mod->status;
 }
 
+int rsnd_mod_id_raw(struct rsnd_mod *mod)
+{
+       return mod->id;
+}
+
+int rsnd_mod_id(struct rsnd_mod *mod)
+{
+       if ((mod)->ops->id)
+               return (mod)->ops->id(mod);
+
+       return rsnd_mod_id_raw(mod);
+}
+
+int rsnd_mod_id_sub(struct rsnd_mod *mod)
+{
+       if ((mod)->ops->id_sub)
+               return (mod)->ops->id_sub(mod);
+
+       return 0;
+}
+
 int rsnd_mod_init(struct rsnd_priv *priv,
                  struct rsnd_mod *mod,
                  struct rsnd_mod_ops *ops,
                  struct clk *clk,
-                 u32* (*get_status)(struct rsnd_dai_stream *io,
-                                    struct rsnd_mod *mod,
-                                    enum rsnd_mod_type type),
                  enum rsnd_mod_type type,
                  int id)
 {
@@ -164,7 +213,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
        mod->type       = type;
        mod->clk        = clk;
        mod->priv       = priv;
-       mod->get_status = get_status;
 
        return ret;
 }
@@ -228,7 +276,20 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
        struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
 
        if (ctu_mod) {
-               u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod);
+               u32 converted_chan = rsnd_io_converted_chan(io);
+
+               /*
+                * !! Note !!
+                *
+                * converted_chan will be used for CTU,
+                * or TDM Split mode.
+                * User shouldn't use CTU with TDM Split mode.
+                */
+               if (rsnd_runtime_is_tdm_split(io)) {
+                       struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+                       dev_err(dev, "CTU and TDM Split should be used\n");
+               }
 
                if (converted_chan)
                        return converted_chan;
@@ -246,7 +307,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
                rsnd_runtime_channel_original_with_params(io, params);
 
        /* Use Multi SSI */
-       if (rsnd_runtime_is_ssi_multi(io))
+       if (rsnd_runtime_is_multi_ssi(io))
                chan /= rsnd_rdai_ssi_lane_get(rdai);
 
        /* TDM Extend Mode needs 8ch */
@@ -256,7 +317,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
        return chan;
 }
 
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        int lane = rsnd_rdai_ssi_lane_get(rdai);
@@ -267,11 +328,16 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
        return (chan > 2) && (lane > 1);
 }
 
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
 {
        return rsnd_runtime_channel_for_ssi(io) >= 6;
 }
 
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
+{
+       return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
+}
+
 /*
  *     ADINR function
  */
@@ -472,20 +538,19 @@ static int rsnd_status_update(u32 *status,
        enum rsnd_mod_type *types = rsnd_mod_sequence[is_play];         \
        for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) {     \
                int tmp = 0;                                            \
-               u32 *status = mod->get_status(io, mod, types[i]);       \
+               u32 *status = mod->ops->get_status(mod, io, types[i]);  \
                int func_call = rsnd_status_update(status,              \
                                                __rsnd_mod_shift_##fn,  \
                                                __rsnd_mod_add_##fn,    \
                                                __rsnd_mod_call_##fn);  \
-               rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n",           \
-                       rsnd_mod_name(mod), rsnd_mod_id(mod), *status,  \
+               rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n",               \
+                       rsnd_mod_name(mod), *status,    \
                        (func_call && (mod)->ops->fn) ? #fn : "");      \
                if (func_call && (mod)->ops->fn)                        \
                        tmp = (mod)->ops->fn(mod, io, param);           \
                if (tmp && (tmp != -EPROBE_DEFER))                      \
-                       dev_err(dev, "%s[%d] : %s error %d\n",          \
-                               rsnd_mod_name(mod), rsnd_mod_id(mod),   \
-                                                    #fn, tmp);         \
+                       dev_err(dev, "%s : %s error %d\n",              \
+                               rsnd_mod_name(mod), #fn, tmp);          \
                ret |= tmp;                                             \
        }                                                               \
        ret;                                                            \
@@ -512,8 +577,8 @@ int rsnd_dai_connect(struct rsnd_mod *mod,
 
        io->mod[type] = mod;
 
-       dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+       dev_dbg(dev, "%s is connected to io (%s)\n",
+               rsnd_mod_name(mod),
                rsnd_io_is_play(io) ? "Playback" : "Capture");
 
        return 0;
@@ -750,6 +815,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
 
        switch (slots) {
        case 2:
+               /* TDM Split Mode */
        case 6:
        case 8:
                /* TDM Extend Mode */
@@ -965,6 +1031,82 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        .prepare        = rsnd_soc_dai_prepare,
 };
 
+static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
+                                     struct device_node *dai_np,
+                                     int dai_i, int is_play)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+       struct rsnd_dai_stream *io = is_play ?
+               &rdai->playback :
+               &rdai->capture;
+       struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
+       struct device_node *np;
+       int i, j;
+
+       if (!ssiu_np)
+               return;
+
+       if (!rsnd_io_to_mod_ssi(io))
+               return;
+
+       /*
+        * This driver assumes that it is TDM Split mode
+        * if it includes ssiu node
+        */
+       for (i = 0;; i++) {
+               struct device_node *node = is_play ?
+                       of_parse_phandle(dai_np, "playback", i) :
+                       of_parse_phandle(dai_np, "capture",  i);
+
+               if (!node)
+                       break;
+
+               j = 0;
+               for_each_child_of_node(ssiu_np, np) {
+                       if (np == node) {
+                               rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+                               dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+                       }
+                       j++;
+               }
+
+       }
+}
+
+static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
+                                    struct rsnd_dai_stream *io,
+                                    struct device_node *endpoint)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *remote_port = of_graph_get_remote_port(endpoint);
+       struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint);
+
+       if (!rsnd_io_to_mod_ssi(io))
+               return;
+
+       /* HDMI0 */
+       if (strstr(remote_node->full_name, "hdmi@fead0000")) {
+               rsnd_flags_set(io, RSND_STREAM_HDMI0);
+               dev_dbg(dev, "%s connected to HDMI0\n", io->name);
+       }
+
+       /* HDMI1 */
+       if (strstr(remote_node->full_name, "hdmi@feae0000")) {
+               rsnd_flags_set(io, RSND_STREAM_HDMI1);
+               dev_dbg(dev, "%s connected to HDMI1\n", io->name);
+       }
+
+       /*
+        * This driver assumes that it is TDM Split mode
+        * if remote node has multi endpoint
+        */
+       if (of_get_child_count(remote_port) > 1) {
+               rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+               dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+       }
+}
+
 void rsnd_parse_connect_common(struct rsnd_dai *rdai,
                struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
                struct device_node *node,
@@ -1051,24 +1193,24 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        drv->name       = rdai->name;
        drv->ops        = &rsnd_soc_dai_ops;
 
-       snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+       snprintf(io_playback->name, RSND_DAI_NAME_SIZE,
                 "DAI%d Playback", dai_i);
        drv->playback.rates             = RSND_RATES;
        drv->playback.formats           = RSND_FMTS;
        drv->playback.channels_min      = 2;
        drv->playback.channels_max      = 8;
-       drv->playback.stream_name       = rdai->playback.name;
+       drv->playback.stream_name       = io_playback->name;
 
-       snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+       snprintf(io_capture->name, RSND_DAI_NAME_SIZE,
                 "DAI%d Capture", dai_i);
        drv->capture.rates              = RSND_RATES;
        drv->capture.formats            = RSND_FMTS;
        drv->capture.channels_min       = 2;
        drv->capture.channels_max       = 8;
-       drv->capture.stream_name        = rdai->capture.name;
+       drv->capture.stream_name        = io_capture->name;
 
-       rdai->playback.rdai             = rdai;
-       rdai->capture.rdai              = rdai;
+       io_playback->rdai               = rdai;
+       io_capture->rdai                = rdai;
        rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
        rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
        rsnd_rdai_width_set(rdai, 32);   /* default 32bit width */
@@ -1081,6 +1223,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
                        break;
 
                rsnd_parse_connect_ssi(rdai, playback, capture);
+               rsnd_parse_connect_ssiu(rdai, playback, capture);
                rsnd_parse_connect_src(rdai, playback, capture);
                rsnd_parse_connect_ctu(rdai, playback, capture);
                rsnd_parse_connect_mix(rdai, playback, capture);
@@ -1137,12 +1280,23 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
        if (is_graph) {
                for_each_endpoint_of_node(dai_node, dai_np) {
                        __rsnd_dai_probe(priv, dai_np, dai_i);
-                       rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
+                       if (rsnd_is_gen3(priv)) {
+                               struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+
+                               rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+                               rsnd_parse_connect_graph(priv, &rdai->capture,  dai_np);
+                       }
                        dai_i++;
                }
        } else {
-               for_each_child_of_node(dai_node, dai_np)
-                       __rsnd_dai_probe(priv, dai_np, dai_i++);
+               for_each_child_of_node(dai_node, dai_np) {
+                       __rsnd_dai_probe(priv, dai_np, dai_i);
+                       if (rsnd_is_gen3(priv)) {
+                               rsnd_parse_connect_simple(priv, dai_np, dai_i, 1);
+                               rsnd_parse_connect_simple(priv, dai_np, dai_i, 0);
+                       }
+                       dai_i++;
+               }
        }
 
        return 0;
@@ -1157,8 +1311,40 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
        int ret;
 
+       /*
+        * rsnd assumes that it might be used under DPCM if user want to use
+        * channel / rate convert. Then, rsnd should be FE.
+        * And then, this function will be called *after* BE settings.
+        * this means, each BE already has fixuped hw_params.
+        * see
+        *      dpcm_fe_dai_hw_params()
+        *      dpcm_be_dai_hw_params()
+        */
+       io->converted_rate = 0;
+       io->converted_chan = 0;
+       if (fe->dai_link->dynamic) {
+               struct rsnd_priv *priv = rsnd_io_to_priv(io);
+               struct device *dev = rsnd_priv_to_dev(priv);
+               struct snd_soc_dpcm *dpcm;
+               struct snd_pcm_hw_params *be_params;
+               int stream = substream->stream;
+
+               for_each_dpcm_be(fe, stream, dpcm) {
+                       be_params = &dpcm->hw_params;
+                       if (params_channels(hw_params) != params_channels(be_params))
+                               io->converted_chan = params_channels(be_params);
+                       if (params_rate(hw_params) != params_rate(be_params))
+                               io->converted_rate = params_rate(be_params);
+               }
+               if (io->converted_chan)
+                       dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
+               if (io->converted_rate)
+                       dev_dbg(dev, "convert rate     = %d\n", io->converted_rate);
+       }
+
        ret = rsnd_dai_call(hw_params, io, substream, hw_params);
        if (ret)
                return ret;
@@ -1339,6 +1525,18 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
        };
        int ret;
 
+       /*
+        * 1) Avoid duplicate register (ex. MIXer case)
+        * 2) re-register if card was rebinded
+        */
+       list_for_each_entry(kctrl, &card->controls, list) {
+               struct rsnd_kctrl_cfg *c = kctrl->private_data;
+
+               if (strcmp(kctrl->id.name, name) == 0 &&
+                   c->mod == mod)
+                       return 0;
+       }
+
        if (size > RSND_MAX_CHANNELS)
                return -EINVAL;
 
index ad702377a6c33c814afbedffe901865b22994672..8cb06dab234ef9941732f6bfa340f42d3eba715c 100644 (file)
 struct rsnd_ctu {
        struct rsnd_mod mod;
        struct rsnd_kctrl_cfg_m pass;
-       struct rsnd_kctrl_cfg_m sv0;
-       struct rsnd_kctrl_cfg_m sv1;
-       struct rsnd_kctrl_cfg_m sv2;
-       struct rsnd_kctrl_cfg_m sv3;
+       struct rsnd_kctrl_cfg_m sv[4];
        struct rsnd_kctrl_cfg_s reset;
        int channels;
        u32 flags;
@@ -107,13 +104,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod)
        rsnd_mod_write(mod, CTU_SWRSR, 0);
 }
 
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
-{
-       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-
-       return ctu->channels;
-}
-
 static int rsnd_ctu_probe_(struct rsnd_mod *mod,
                           struct rsnd_dai_stream *io,
                           struct rsnd_priv *priv)
@@ -127,7 +117,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
        struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
        u32 cpmdr = 0;
        u32 scmdr = 0;
-       int i;
+       int i, j;
 
        for (i = 0; i < RSND_MAX_CHANNELS; i++) {
                u32 val = rsnd_kctrl_valm(ctu->pass, i);
@@ -146,45 +136,13 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
 
        rsnd_mod_write(mod, CTU_SCMDR, scmdr);
 
-       if (scmdr > 0) {
-               rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0));
-               rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1));
-               rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2));
-               rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3));
-               rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4));
-               rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5));
-               rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6));
-               rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7));
-       }
-       if (scmdr > 1) {
-               rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0));
-               rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1));
-               rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2));
-               rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3));
-               rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4));
-               rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5));
-               rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6));
-               rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7));
-       }
-       if (scmdr > 2) {
-               rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0));
-               rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1));
-               rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2));
-               rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3));
-               rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4));
-               rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5));
-               rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6));
-               rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7));
-       }
-       if (scmdr > 3) {
-               rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0));
-               rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1));
-               rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2));
-               rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3));
-               rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4));
-               rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5));
-               rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6));
-               rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7));
+       for (i = 0; i < 4; i++) {
+
+               if (i >= scmdr)
+                       break;
+
+               for (j = 0; j < RSND_MAX_CHANNELS; j++)
+                       rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
        }
 
        rsnd_mod_write(mod, CTU_CTUIR, 0);
@@ -201,10 +159,10 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
 
        for (i = 0; i < RSND_MAX_CHANNELS; i++) {
                rsnd_kctrl_valm(ctu->pass, i) = 0;
-               rsnd_kctrl_valm(ctu->sv0,  i) = 0;
-               rsnd_kctrl_valm(ctu->sv1,  i) = 0;
-               rsnd_kctrl_valm(ctu->sv2,  i) = 0;
-               rsnd_kctrl_valm(ctu->sv3,  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[0],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[1],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[2],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[3],  i) = 0;
        }
        rsnd_kctrl_vals(ctu->reset) = 0;
 }
@@ -233,43 +191,6 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *fe_params)
-{
-       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-       struct snd_soc_pcm_runtime *fe = substream->private_data;
-
-       /*
-        * CTU assumes that it is used under DPCM if user want to use
-        * channel transfer. Then, CTU should be FE.
-        * And then, this function will be called *after* BE settings.
-        * this means, each BE already has fixuped hw_params.
-        * see
-        *      dpcm_fe_dai_hw_params()
-        *      dpcm_be_dai_hw_params()
-        */
-       ctu->channels = 0;
-       if (fe->dai_link->dynamic) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-               struct device *dev = rsnd_priv_to_dev(priv);
-               struct snd_soc_dpcm *dpcm;
-               struct snd_pcm_hw_params *be_params;
-               int stream = substream->stream;
-
-               for_each_dpcm_be(fe, stream, dpcm) {
-                       be_params = &dpcm->hw_params;
-                       if (params_channels(fe_params) != params_channels(be_params))
-                               ctu->channels = params_channels(be_params);
-               }
-
-               dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
-       }
-
-       return 0;
-}
-
 static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
@@ -291,7 +212,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
                               rsnd_kctrl_accept_anytime,
                               NULL,
-                              &ctu->sv0, RSND_MAX_CHANNELS,
+                              &ctu->sv[0], RSND_MAX_CHANNELS,
                               0x00FFFFFF);
        if (ret < 0)
                return ret;
@@ -300,7 +221,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
                               rsnd_kctrl_accept_anytime,
                               NULL,
-                              &ctu->sv1, RSND_MAX_CHANNELS,
+                              &ctu->sv[1], RSND_MAX_CHANNELS,
                               0x00FFFFFF);
        if (ret < 0)
                return ret;
@@ -309,7 +230,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
                               rsnd_kctrl_accept_anytime,
                               NULL,
-                              &ctu->sv2, RSND_MAX_CHANNELS,
+                              &ctu->sv[2], RSND_MAX_CHANNELS,
                               0x00FFFFFF);
        if (ret < 0)
                return ret;
@@ -318,7 +239,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
                               rsnd_kctrl_accept_anytime,
                               NULL,
-                              &ctu->sv3, RSND_MAX_CHANNELS,
+                              &ctu->sv[3], RSND_MAX_CHANNELS,
                               0x00FFFFFF);
        if (ret < 0)
                return ret;
@@ -334,13 +255,34 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        return ret;
 }
 
+static int rsnd_ctu_id(struct rsnd_mod *mod)
+{
+       /*
+        * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
+        * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
+        */
+       return mod->id / 4;
+}
+
+static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
+{
+       /*
+        * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
+        * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
+        */
+       return mod->id % 4;
+}
+
 static struct rsnd_mod_ops rsnd_ctu_ops = {
        .name           = CTU_NAME,
        .probe          = rsnd_ctu_probe_,
        .init           = rsnd_ctu_init,
        .quit           = rsnd_ctu_quit,
-       .hw_params      = rsnd_ctu_hw_params,
        .pcm_new        = rsnd_ctu_pcm_new,
+       .get_status     = rsnd_mod_get_status,
+       .id             = rsnd_ctu_id,
+       .id_sub         = rsnd_ctu_id_sub,
+       .id_cmd         = rsnd_mod_id_raw,
 };
 
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
@@ -404,7 +346,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
-                                   clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
+                                   clk, RSND_MOD_CTU, i);
                if (ret) {
                        of_node_put(np);
                        goto rsnd_ctu_probe_done;
index 6d1947515dc8fce87a95eb21a2f2f8bf635ea7a1..0324a5c3961963b1d9315d1618161c8113891808 100644 (file)
@@ -174,8 +174,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
        cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-       dev_dbg(dev, "%s[%d] %pad -> %pad\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+       dev_dbg(dev, "%s %pad -> %pad\n",
+               rsnd_mod_name(mod),
                &cfg.src_addr, &cfg.dst_addr);
 
        ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -218,7 +218,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
        int i = 0;
 
        for_each_child_of_node(of_node, np) {
-               if (i == rsnd_mod_id(mod) && (!chan))
+               if (i == rsnd_mod_id_raw(mod) && (!chan))
                        chan = of_dma_request_slave_channel(np, name);
                i++;
        }
@@ -289,12 +289,13 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
 }
 
 static struct rsnd_mod_ops rsnd_dmaen_ops = {
-       .name   = "audmac",
-       .prepare = rsnd_dmaen_prepare,
-       .cleanup = rsnd_dmaen_cleanup,
-       .start  = rsnd_dmaen_start,
-       .stop   = rsnd_dmaen_stop,
-       .pointer= rsnd_dmaen_pointer,
+       .name           = "audmac",
+       .prepare        = rsnd_dmaen_prepare,
+       .cleanup        = rsnd_dmaen_cleanup,
+       .start          = rsnd_dmaen_start,
+       .stop           = rsnd_dmaen_stop,
+       .pointer        = rsnd_dmaen_pointer,
+       .get_status     = rsnd_mod_get_status,
 };
 
 /*
@@ -343,14 +344,16 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
                             struct rsnd_mod *mod)
 {
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
        const u8 *entry = NULL;
        int id = 255;
        int size = 0;
 
-       if (mod == ssi) {
-               int busif = rsnd_ssi_get_busif(io);
+       if ((mod == ssi) ||
+           (mod == ssiu)) {
+               int busif = rsnd_mod_id_sub(ssiu);
 
                entry = gen2_id_table_ssiu;
                size = ARRAY_SIZE(gen2_id_table_ssiu);
@@ -368,8 +371,7 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
        if ((!entry) || (size <= id)) {
                struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
 
-               dev_err(dev, "unknown connection (%s[%d])\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+               dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
 
                /* use non-prohibited SRS number as error */
                return 0x00; /* SSI00 */
@@ -477,10 +479,11 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
 }
 
 static struct rsnd_mod_ops rsnd_dmapp_ops = {
-       .name   = "audmac-pp",
-       .start  = rsnd_dmapp_start,
-       .stop   = rsnd_dmapp_stop,
-       .quit   = rsnd_dmapp_stop,
+       .name           = "audmac-pp",
+       .start          = rsnd_dmapp_start,
+       .stop           = rsnd_dmapp_stop,
+       .quit           = rsnd_dmapp_stop,
+       .get_status     = rsnd_mod_get_status,
 };
 
 /*
@@ -529,13 +532,14 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
        struct device *dev = rsnd_priv_to_dev(priv);
        phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
        phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
-       int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
+       int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
+                    !!(rsnd_io_to_mod_ssiu(io) == mod);
        int use_src = !!rsnd_io_to_mod_src(io);
        int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
                      !!rsnd_io_to_mod_mix(io) ||
                      !!rsnd_io_to_mod_ctu(io);
        int id = rsnd_mod_id(mod);
-       int busif = rsnd_ssi_get_busif(io);
+       int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
        struct dma_addr {
                dma_addr_t out_addr;
                dma_addr_t in_addr;
@@ -619,7 +623,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
                             struct rsnd_mod **mod_from,
                             struct rsnd_mod **mod_to)
 {
-       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *ssi;
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
        struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
        struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
@@ -630,6 +634,28 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
        struct device *dev = rsnd_priv_to_dev(priv);
        int nr, i, idx;
 
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssiu_dma_req()
+        *      rsnd_ssi_dma_req()
+        */
+       if (rsnd_ssiu_of_node(priv)) {
+               struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+
+               /* use SSIU */
+               ssi = ssiu;
+               if (this == rsnd_io_to_mod_ssi(io))
+                       this = ssiu;
+       } else {
+               /* keep compatible, use SSI */
+               ssi = rsnd_io_to_mod_ssi(io);
+       }
+
        if (!ssi)
                return;
 
@@ -690,12 +716,10 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
                *mod_to         = mod[1];
        }
 
-       dev_dbg(dev, "module connection (this is %s[%d])\n",
-               rsnd_mod_name(this), rsnd_mod_id(this));
+       dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
        for (i = 0; i <= idx; i++) {
-               dev_dbg(dev, "  %s[%d]%s\n",
+               dev_dbg(dev, "  %s%s\n",
                        rsnd_mod_name(mod[i] ? mod[i] : &mem),
-                       rsnd_mod_id  (mod[i] ? mod[i] : &mem),
                        (mod[i] == *mod_from) ? " from" :
                        (mod[i] == *mod_to)   ? " to" : "");
        }
@@ -756,16 +780,14 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
        *dma_mod = rsnd_mod_get(dma);
 
        ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
-                           rsnd_mod_get_status, type, dma_id);
+                           type, dma_id);
        if (ret < 0)
                return ret;
 
-       dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
-               rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
+       dev_dbg(dev, "%s %s -> %s\n",
+               rsnd_mod_name(*dma_mod),
                rsnd_mod_name(mod_from ? mod_from : &mem),
-               rsnd_mod_id  (mod_from ? mod_from : &mem),
-               rsnd_mod_name(mod_to   ? mod_to   : &mem),
-               rsnd_mod_id  (mod_to   ? mod_to   : &mem));
+               rsnd_mod_name(mod_to   ? mod_to   : &mem));
 
        ret = attach(io, dma, mod_from, mod_to);
        if (ret < 0)
@@ -823,5 +845,5 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
        priv->dma = dmac;
 
        /* dummy mem mod for debug */
-       return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
+       return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
 }
index 2b16e0ce6bc5374aff6e3bc0ade4a3faed6a3087..8d91c0eb0880f17eb627bb946934b158fa3fd033 100644 (file)
@@ -40,11 +40,8 @@ struct rsnd_dvc {
        struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
        struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
        struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
-       u32 flags;
 };
 
-#define KCTRL_INITIALIZED      (1 << 0)
-
 #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 
@@ -89,14 +86,8 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
                        val[i] = rsnd_kctrl_valm(dvc->volume, i);
 
        /* Enable Digital Volume */
-       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
-       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
-       rsnd_mod_write(mod, DVC_VOL2R, val[2]);
-       rsnd_mod_write(mod, DVC_VOL3R, val[3]);
-       rsnd_mod_write(mod, DVC_VOL4R, val[4]);
-       rsnd_mod_write(mod, DVC_VOL5R, val[5]);
-       rsnd_mod_write(mod, DVC_VOL6R, val[6]);
-       rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+       for (i = 0; i < RSND_MAX_CHANNELS; i++)
+               rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
 }
 
 static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
@@ -227,9 +218,6 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        int channels = rsnd_rdai_channels_get(rdai);
        int ret;
 
-       if (rsnd_flags_has(dvc, KCTRL_INITIALIZED))
-               return 0;
-
        /* Volume */
        ret = rsnd_kctrl_new_m(mod, io, rtd,
                        is_play ?
@@ -285,8 +273,6 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       rsnd_flags_set(dvc, KCTRL_INITIALIZED);
-
        return 0;
 }
 
@@ -306,6 +292,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = {
        .init           = rsnd_dvc_init,
        .quit           = rsnd_dvc_quit,
        .pcm_new        = rsnd_dvc_pcm_new,
+       .get_status     = rsnd_mod_get_status,
 };
 
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
@@ -365,7 +352,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
-                                   clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
+                                   clk, RSND_MOD_DVC, i);
                if (ret) {
                        of_node_put(np);
                        goto rsnd_dvc_probe_done;
index 1f7881cc16b26ea85ce957e81bc693f2b8fa5fe4..7cda60188f41a227197352931ef49248de1a127f 100644 (file)
@@ -26,8 +26,8 @@ struct rsnd_gen {
        struct regmap *regmap[RSND_BASE_MAX];
 
        /* RSND_REG_MAX base */
-       struct regmap_field *regs[RSND_REG_MAX];
-       const char *reg_name[RSND_REG_MAX];
+       struct regmap_field *regs[REG_MAX];
+       const char *reg_name[REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
@@ -49,11 +49,11 @@ struct rsnd_regmap_field_conf {
 }
 /* single address mapping */
 #define RSND_GEN_S_REG(id, offset)     \
-       RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
+       RSND_REG_SET(id, offset, 0, #id)
 
 /* multi address mapping */
 #define RSND_GEN_M_REG(id, offset, _id_offset) \
-       RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
+       RSND_REG_SET(id, offset, _id_offset, #id)
 
 /*
  *             basic function
@@ -71,9 +71,17 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
        return 1;
 }
 
-u32 rsnd_read(struct rsnd_priv *priv,
-             struct rsnd_mod *mod, enum rsnd_reg reg)
+static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
 {
+       if (mod->ops->id_cmd)
+               return mod->ops->id_cmd(mod);
+
+       return rsnd_mod_id(mod);
+}
+
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
        u32 val;
@@ -81,35 +89,36 @@ u32 rsnd_read(struct rsnd_priv *priv,
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return 0;
 
-       regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+       regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
 
-       dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+       dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod),
                rsnd_reg_name(gen, reg), reg, val);
 
        return val;
 }
 
-void rsnd_write(struct rsnd_priv *priv,
-               struct rsnd_mod *mod,
-               enum rsnd_reg reg, u32 data)
+void rsnd_mod_write(struct rsnd_mod *mod,
+                   enum rsnd_reg reg, u32 data)
 {
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return;
 
-       regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+       regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
 
-       dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+       dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod),
                rsnd_reg_name(gen, reg), reg, data);
 }
 
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
-              enum rsnd_reg reg, u32 mask, u32 data)
+void rsnd_mod_bset(struct rsnd_mod *mod,
+                  enum rsnd_reg reg, u32 mask, u32 data)
 {
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
@@ -117,10 +126,10 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
                return;
 
        regmap_fields_force_update_bits(gen->regs[reg],
-                                       rsnd_mod_id(mod), mask, data);
+                                       rsnd_mod_id_cmd(mod), mask, data);
 
-       dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
+       dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
+               rsnd_mod_name(mod),
                rsnd_reg_name(gen, reg), reg, data, mask);
 
 }
index 8e3b57eaa708da568e0688d5310f5150eba2eaa4..a3e0370f5704a7a3318da26061eb24307e45612e 100644 (file)
@@ -256,6 +256,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = {
        .init           = rsnd_mix_init,
        .quit           = rsnd_mix_quit,
        .pcm_new        = rsnd_mix_pcm_new,
+       .get_status     = rsnd_mod_get_status,
 };
 
 struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
@@ -315,7 +316,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
-                                   clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
+                                   clk, RSND_MOD_MIX, i);
                if (ret) {
                        of_node_put(np);
                        goto rsnd_mix_probe_done;
index 4464d1d0a042c55449615b32f7c174b041a9242b..605e4b934982156c1752df6b9748a8042355c068 100644 (file)
  */
 enum rsnd_reg {
        /* SCU (MIX/CTU/DVC) */
-       RSND_REG_SRC_I_BUSIF_MODE,
-       RSND_REG_SRC_O_BUSIF_MODE,
-       RSND_REG_SRC_ROUTE_MODE0,
-       RSND_REG_SRC_SWRSR,
-       RSND_REG_SRC_SRCIR,
-       RSND_REG_SRC_ADINR,
-       RSND_REG_SRC_IFSCR,
-       RSND_REG_SRC_IFSVR,
-       RSND_REG_SRC_SRCCR,
-       RSND_REG_SRC_CTRL,
-       RSND_REG_SRC_BSDSR,
-       RSND_REG_SRC_BSISR,
-       RSND_REG_SRC_INT_ENABLE0,
-       RSND_REG_SRC_BUSIF_DALIGN,
-       RSND_REG_SRCIN_TIMSEL0,
-       RSND_REG_SRCIN_TIMSEL1,
-       RSND_REG_SRCIN_TIMSEL2,
-       RSND_REG_SRCIN_TIMSEL3,
-       RSND_REG_SRCIN_TIMSEL4,
-       RSND_REG_SRCOUT_TIMSEL0,
-       RSND_REG_SRCOUT_TIMSEL1,
-       RSND_REG_SRCOUT_TIMSEL2,
-       RSND_REG_SRCOUT_TIMSEL3,
-       RSND_REG_SRCOUT_TIMSEL4,
-       RSND_REG_SCU_SYS_STATUS0,
-       RSND_REG_SCU_SYS_STATUS1,
-       RSND_REG_SCU_SYS_INT_EN0,
-       RSND_REG_SCU_SYS_INT_EN1,
-       RSND_REG_CMD_CTRL,
-       RSND_REG_CMD_BUSIF_MODE,
-       RSND_REG_CMD_BUSIF_DALIGN,
-       RSND_REG_CMD_ROUTE_SLCT,
-       RSND_REG_CMDOUT_TIMSEL,
-       RSND_REG_CTU_SWRSR,
-       RSND_REG_CTU_CTUIR,
-       RSND_REG_CTU_ADINR,
-       RSND_REG_CTU_CPMDR,
-       RSND_REG_CTU_SCMDR,
-       RSND_REG_CTU_SV00R,
-       RSND_REG_CTU_SV01R,
-       RSND_REG_CTU_SV02R,
-       RSND_REG_CTU_SV03R,
-       RSND_REG_CTU_SV04R,
-       RSND_REG_CTU_SV05R,
-       RSND_REG_CTU_SV06R,
-       RSND_REG_CTU_SV07R,
-       RSND_REG_CTU_SV10R,
-       RSND_REG_CTU_SV11R,
-       RSND_REG_CTU_SV12R,
-       RSND_REG_CTU_SV13R,
-       RSND_REG_CTU_SV14R,
-       RSND_REG_CTU_SV15R,
-       RSND_REG_CTU_SV16R,
-       RSND_REG_CTU_SV17R,
-       RSND_REG_CTU_SV20R,
-       RSND_REG_CTU_SV21R,
-       RSND_REG_CTU_SV22R,
-       RSND_REG_CTU_SV23R,
-       RSND_REG_CTU_SV24R,
-       RSND_REG_CTU_SV25R,
-       RSND_REG_CTU_SV26R,
-       RSND_REG_CTU_SV27R,
-       RSND_REG_CTU_SV30R,
-       RSND_REG_CTU_SV31R,
-       RSND_REG_CTU_SV32R,
-       RSND_REG_CTU_SV33R,
-       RSND_REG_CTU_SV34R,
-       RSND_REG_CTU_SV35R,
-       RSND_REG_CTU_SV36R,
-       RSND_REG_CTU_SV37R,
-       RSND_REG_MIX_SWRSR,
-       RSND_REG_MIX_MIXIR,
-       RSND_REG_MIX_ADINR,
-       RSND_REG_MIX_MIXMR,
-       RSND_REG_MIX_MVPDR,
-       RSND_REG_MIX_MDBAR,
-       RSND_REG_MIX_MDBBR,
-       RSND_REG_MIX_MDBCR,
-       RSND_REG_MIX_MDBDR,
-       RSND_REG_MIX_MDBER,
-       RSND_REG_DVC_SWRSR,
-       RSND_REG_DVC_DVUIR,
-       RSND_REG_DVC_ADINR,
-       RSND_REG_DVC_DVUCR,
-       RSND_REG_DVC_ZCMCR,
-       RSND_REG_DVC_VOL0R,
-       RSND_REG_DVC_VOL1R,
-       RSND_REG_DVC_VOL2R,
-       RSND_REG_DVC_VOL3R,
-       RSND_REG_DVC_VOL4R,
-       RSND_REG_DVC_VOL5R,
-       RSND_REG_DVC_VOL6R,
-       RSND_REG_DVC_VOL7R,
-       RSND_REG_DVC_DVUER,
-       RSND_REG_DVC_VRCTR,
-       RSND_REG_DVC_VRPDR,
-       RSND_REG_DVC_VRDBR,
+       SRC_I_BUSIF_MODE,
+       SRC_O_BUSIF_MODE,
+       SRC_ROUTE_MODE0,
+       SRC_SWRSR,
+       SRC_SRCIR,
+       SRC_ADINR,
+       SRC_IFSCR,
+       SRC_IFSVR,
+       SRC_SRCCR,
+       SRC_CTRL,
+       SRC_BSDSR,
+       SRC_BSISR,
+       SRC_INT_ENABLE0,
+       SRC_BUSIF_DALIGN,
+       SRCIN_TIMSEL0,
+       SRCIN_TIMSEL1,
+       SRCIN_TIMSEL2,
+       SRCIN_TIMSEL3,
+       SRCIN_TIMSEL4,
+       SRCOUT_TIMSEL0,
+       SRCOUT_TIMSEL1,
+       SRCOUT_TIMSEL2,
+       SRCOUT_TIMSEL3,
+       SRCOUT_TIMSEL4,
+       SCU_SYS_STATUS0,
+       SCU_SYS_STATUS1,
+       SCU_SYS_INT_EN0,
+       SCU_SYS_INT_EN1,
+       CMD_CTRL,
+       CMD_BUSIF_MODE,
+       CMD_BUSIF_DALIGN,
+       CMD_ROUTE_SLCT,
+       CMDOUT_TIMSEL,
+       CTU_SWRSR,
+       CTU_CTUIR,
+       CTU_ADINR,
+       CTU_CPMDR,
+       CTU_SCMDR,
+       CTU_SV00R,
+       CTU_SV01R,
+       CTU_SV02R,
+       CTU_SV03R,
+       CTU_SV04R,
+       CTU_SV05R,
+       CTU_SV06R,
+       CTU_SV07R,
+       CTU_SV10R,
+       CTU_SV11R,
+       CTU_SV12R,
+       CTU_SV13R,
+       CTU_SV14R,
+       CTU_SV15R,
+       CTU_SV16R,
+       CTU_SV17R,
+       CTU_SV20R,
+       CTU_SV21R,
+       CTU_SV22R,
+       CTU_SV23R,
+       CTU_SV24R,
+       CTU_SV25R,
+       CTU_SV26R,
+       CTU_SV27R,
+       CTU_SV30R,
+       CTU_SV31R,
+       CTU_SV32R,
+       CTU_SV33R,
+       CTU_SV34R,
+       CTU_SV35R,
+       CTU_SV36R,
+       CTU_SV37R,
+       MIX_SWRSR,
+       MIX_MIXIR,
+       MIX_ADINR,
+       MIX_MIXMR,
+       MIX_MVPDR,
+       MIX_MDBAR,
+       MIX_MDBBR,
+       MIX_MDBCR,
+       MIX_MDBDR,
+       MIX_MDBER,
+       DVC_SWRSR,
+       DVC_DVUIR,
+       DVC_ADINR,
+       DVC_DVUCR,
+       DVC_ZCMCR,
+       DVC_VOL0R,
+       DVC_VOL1R,
+       DVC_VOL2R,
+       DVC_VOL3R,
+       DVC_VOL4R,
+       DVC_VOL5R,
+       DVC_VOL6R,
+       DVC_VOL7R,
+       DVC_DVUER,
+       DVC_VRCTR,
+       DVC_VRPDR,
+       DVC_VRDBR,
 
        /* ADG */
-       RSND_REG_BRRA,
-       RSND_REG_BRRB,
-       RSND_REG_BRGCKR,
-       RSND_REG_DIV_EN,
-       RSND_REG_AUDIO_CLK_SEL0,
-       RSND_REG_AUDIO_CLK_SEL1,
-       RSND_REG_AUDIO_CLK_SEL2,
+       BRRA,
+       BRRB,
+       BRGCKR,
+       DIV_EN,
+       AUDIO_CLK_SEL0,
+       AUDIO_CLK_SEL1,
+       AUDIO_CLK_SEL2,
 
        /* SSIU */
-       RSND_REG_SSI_MODE,
-       RSND_REG_SSI_MODE0,
-       RSND_REG_SSI_MODE1,
-       RSND_REG_SSI_MODE2,
-       RSND_REG_SSI_CONTROL,
-       RSND_REG_SSI_CTRL,
-       RSND_REG_SSI_BUSIF0_MODE,
-       RSND_REG_SSI_BUSIF0_ADINR,
-       RSND_REG_SSI_BUSIF0_DALIGN,
-       RSND_REG_SSI_BUSIF1_MODE,
-       RSND_REG_SSI_BUSIF1_ADINR,
-       RSND_REG_SSI_BUSIF1_DALIGN,
-       RSND_REG_SSI_BUSIF2_MODE,
-       RSND_REG_SSI_BUSIF2_ADINR,
-       RSND_REG_SSI_BUSIF2_DALIGN,
-       RSND_REG_SSI_BUSIF3_MODE,
-       RSND_REG_SSI_BUSIF3_ADINR,
-       RSND_REG_SSI_BUSIF3_DALIGN,
-       RSND_REG_SSI_BUSIF4_MODE,
-       RSND_REG_SSI_BUSIF4_ADINR,
-       RSND_REG_SSI_BUSIF4_DALIGN,
-       RSND_REG_SSI_BUSIF5_MODE,
-       RSND_REG_SSI_BUSIF5_ADINR,
-       RSND_REG_SSI_BUSIF5_DALIGN,
-       RSND_REG_SSI_BUSIF6_MODE,
-       RSND_REG_SSI_BUSIF6_ADINR,
-       RSND_REG_SSI_BUSIF6_DALIGN,
-       RSND_REG_SSI_BUSIF7_MODE,
-       RSND_REG_SSI_BUSIF7_ADINR,
-       RSND_REG_SSI_BUSIF7_DALIGN,
-       RSND_REG_SSI_INT_ENABLE,
-       RSND_REG_SSI_SYS_STATUS0,
-       RSND_REG_SSI_SYS_STATUS1,
-       RSND_REG_SSI_SYS_STATUS2,
-       RSND_REG_SSI_SYS_STATUS3,
-       RSND_REG_SSI_SYS_STATUS4,
-       RSND_REG_SSI_SYS_STATUS5,
-       RSND_REG_SSI_SYS_STATUS6,
-       RSND_REG_SSI_SYS_STATUS7,
-       RSND_REG_HDMI0_SEL,
-       RSND_REG_HDMI1_SEL,
+       SSI_MODE,
+       SSI_MODE0,
+       SSI_MODE1,
+       SSI_MODE2,
+       SSI_CONTROL,
+       SSI_CTRL,
+       SSI_BUSIF0_MODE,
+       SSI_BUSIF1_MODE,
+       SSI_BUSIF2_MODE,
+       SSI_BUSIF3_MODE,
+       SSI_BUSIF4_MODE,
+       SSI_BUSIF5_MODE,
+       SSI_BUSIF6_MODE,
+       SSI_BUSIF7_MODE,
+       SSI_BUSIF0_ADINR,
+       SSI_BUSIF1_ADINR,
+       SSI_BUSIF2_ADINR,
+       SSI_BUSIF3_ADINR,
+       SSI_BUSIF4_ADINR,
+       SSI_BUSIF5_ADINR,
+       SSI_BUSIF6_ADINR,
+       SSI_BUSIF7_ADINR,
+       SSI_BUSIF0_DALIGN,
+       SSI_BUSIF1_DALIGN,
+       SSI_BUSIF2_DALIGN,
+       SSI_BUSIF3_DALIGN,
+       SSI_BUSIF4_DALIGN,
+       SSI_BUSIF5_DALIGN,
+       SSI_BUSIF6_DALIGN,
+       SSI_BUSIF7_DALIGN,
+       SSI_INT_ENABLE,
+       SSI_SYS_STATUS0,
+       SSI_SYS_STATUS1,
+       SSI_SYS_STATUS2,
+       SSI_SYS_STATUS3,
+       SSI_SYS_STATUS4,
+       SSI_SYS_STATUS5,
+       SSI_SYS_STATUS6,
+       SSI_SYS_STATUS7,
+       HDMI0_SEL,
+       HDMI1_SEL,
 
        /* SSI */
-       RSND_REG_SSICR,
-       RSND_REG_SSISR,
-       RSND_REG_SSITDR,
-       RSND_REG_SSIRDR,
-       RSND_REG_SSIWSR,
+       SSICR,
+       SSISR,
+       SSITDR,
+       SSIRDR,
+       SSIWSR,
 
-       RSND_REG_MAX,
+       REG_MAX,
 };
+#define SRCIN_TIMSEL(i)                (SRCIN_TIMSEL0 + (i))
+#define SRCOUT_TIMSEL(i)       (SRCOUT_TIMSEL0 + (i))
+#define CTU_SVxxR(i, j)                (CTU_SV00R + (i * 8) + (j))
+#define DVC_VOLxR(i)           (DVC_VOL0R + (i))
+#define AUDIO_CLK_SEL(i)       (AUDIO_CLK_SEL0 + (i))
+#define SSI_BUSIF_MODE(i)      (SSI_BUSIF0_MODE + (i))
+#define SSI_BUSIF_ADINR(i)     (SSI_BUSIF0_ADINR + (i))
+#define SSI_BUSIF_DALIGN(i)    (SSI_BUSIF0_DALIGN + (i))
+#define SSI_SYS_STATUS(i)      (SSI_SYS_STATUS0 + (i))
+
 
 struct rsnd_priv;
 struct rsnd_mod;
@@ -210,20 +220,9 @@ struct rsnd_dai_stream;
 /*
  *     R-Car basic functions
  */
-#define rsnd_mod_read(m, r) \
-       rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
-#define rsnd_mod_write(m, r, d) \
-       rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
-#define rsnd_mod_bset(m, r, s, d) \
-       rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
-
-u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
-void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
-               enum rsnd_reg reg, u32 data);
-void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
-               enum rsnd_reg reg, u32 data);
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
-                   u32 mask, u32 data);
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data);
+void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data);
 u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
@@ -301,6 +300,12 @@ struct rsnd_mod_ops {
        int (*cleanup)(struct rsnd_mod *mod,
                       struct rsnd_dai_stream *io,
                       struct rsnd_priv *priv);
+       u32 *(*get_status)(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          enum rsnd_mod_type type);
+       int (*id)(struct rsnd_mod *mod);
+       int (*id_sub)(struct rsnd_mod *mod);
+       int (*id_cmd)(struct rsnd_mod *mod);
 };
 
 struct rsnd_dai_stream;
@@ -310,9 +315,6 @@ struct rsnd_mod {
        struct rsnd_mod_ops *ops;
        struct rsnd_priv *priv;
        struct clk *clk;
-       u32 *(*get_status)(struct rsnd_dai_stream *io,
-                          struct rsnd_mod *mod,
-                          enum rsnd_mod_type type);
        u32 status;
 };
 /*
@@ -375,8 +377,6 @@ struct rsnd_mod {
 #define __rsnd_mod_call_pointer                0
 
 #define rsnd_mod_to_priv(mod)  ((mod)->priv)
-#define rsnd_mod_name(mod)     ((mod)->ops->name)
-#define rsnd_mod_id(mod)       ((mod)->id)
 #define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
 #define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
 #define rsnd_mod_get(ip)       (&(ip)->mod)
@@ -385,9 +385,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
                  struct rsnd_mod *mod,
                  struct rsnd_mod_ops *ops,
                  struct clk *clk,
-                 u32* (*get_status)(struct rsnd_dai_stream *io,
-                                    struct rsnd_mod *mod,
-                                    enum rsnd_mod_type type),
                  enum rsnd_mod_type type,
                  int id);
 void rsnd_mod_quit(struct rsnd_mod *mod);
@@ -396,9 +393,13 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
                        void (*callback)(struct rsnd_mod *mod,
                                         struct rsnd_dai_stream *io));
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
-                        struct rsnd_mod *mod,
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
                         enum rsnd_mod_type type);
+int rsnd_mod_id(struct rsnd_mod *mod);
+int rsnd_mod_id_raw(struct rsnd_mod *mod);
+int rsnd_mod_id_sub(struct rsnd_mod *mod);
+char *rsnd_mod_name(struct rsnd_mod *mod);
 struct rsnd_mod *rsnd_mod_next(int *iterator,
                               struct rsnd_dai_stream *io,
                               enum rsnd_mod_type *array,
@@ -430,8 +431,9 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
        rsnd_runtime_channel_for_ssi_with_params(io, NULL)
 int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
                                 struct snd_pcm_hw_params *params);
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
 
 /*
  * DT
@@ -440,6 +442,7 @@ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
 #define RSND_NODE_DAI  "rcar_sound,dai"
 #define RSND_NODE_SSI  "rcar_sound,ssi"
+#define RSND_NODE_SSIU "rcar_sound,ssiu"
 #define RSND_NODE_SRC  "rcar_sound,src"
 #define RSND_NODE_CTU  "rcar_sound,ctu"
 #define RSND_NODE_MIX  "rcar_sound,mix"
@@ -456,8 +459,17 @@ struct rsnd_dai_stream {
        struct rsnd_mod *dma;
        struct rsnd_dai *rdai;
        struct device *dmac_dev; /* for IPMMU */
+       u32 converted_rate;      /* converted sampling rate */
+       int converted_chan;      /* converted channels */
        u32 parent_ssi_status;
+       u32 flags;
 };
+
+/* flags */
+#define RSND_STREAM_HDMI0      (1 << 0) /* for HDMI0 */
+#define RSND_STREAM_HDMI1      (1 << 1) /* for HDMI1 */
+#define RSND_STREAM_TDM_SPLIT  (1 << 2) /* for TDM split mode */
+
 #define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
 #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
 #define rsnd_io_to_mod_ssiu(io)        rsnd_io_to_mod((io), RSND_MOD_SSIU)
@@ -472,6 +484,8 @@ struct rsnd_dai_stream {
 #define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
 #define rsnd_io_to_runtime(io) ((io)->substream ? \
                                (io)->substream->runtime : NULL)
+#define rsnd_io_converted_rate(io)     ((io)->converted_rate)
+#define rsnd_io_converted_chan(io)     ((io)->converted_chan)
 int rsnd_io_is_working(struct rsnd_dai_stream *io);
 
 struct rsnd_dai {
@@ -712,18 +726,9 @@ extern const char * const volume_ramp_rate[];
 int rsnd_ssi_probe(struct rsnd_priv *priv);
 void rsnd_ssi_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io);
 u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
 
-#define RSND_SSI_HDMI_PORT0    0xf0
-#define RSND_SSI_HDMI_PORT1    0xf1
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
-                                   struct device_node *endpoint,
-                                   int dai_i);
-
 #define rsnd_ssi_is_pin_sharing(io)    \
        __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
 int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
@@ -742,6 +747,10 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
                     struct rsnd_mod *mod);
 int rsnd_ssiu_probe(struct rsnd_priv *priv);
 void rsnd_ssiu_remove(struct rsnd_priv *priv);
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+                            struct device_node *playback,
+                            struct device_node *capture);
+#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
 
 /*
  *     R-Car SRC
@@ -767,7 +776,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
  */
 int rsnd_ctu_probe(struct rsnd_priv *priv);
 void rsnd_ctu_remove(struct rsnd_priv *priv);
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
 #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
 #define rsnd_parse_connect_ctu(rdai, playback, capture)                        \
index cd38a43b976fae6739605ae381e3813e6b4d6736..50348a2c920317f7cac07b2c2e453e41765d37da 100644 (file)
@@ -25,7 +25,6 @@ struct rsnd_src {
        struct rsnd_mod *dma;
        struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
        struct rsnd_kctrl_cfg_s sync; /* sync convert */
-       u32 convert_rate; /* sampling rate convert */
        int irq;
 };
 
@@ -89,12 +88,12 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
                return 0;
 
        if (!rsnd_src_sync_is_enabled(mod))
-               return src->convert_rate;
+               return rsnd_io_converted_rate(io);
 
        convert_rate = src->sync.val;
 
        if (!convert_rate)
-               convert_rate = src->convert_rate;
+               convert_rate = rsnd_io_converted_rate(io);
 
        if (!convert_rate)
                convert_rate = runtime->rate;
@@ -135,40 +134,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
        return rate;
 }
 
-static int rsnd_src_hw_params(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *fe_params)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       struct snd_soc_pcm_runtime *fe = substream->private_data;
-
-       /*
-        * SRC assumes that it is used under DPCM if user want to use
-        * sampling rate convert. Then, SRC should be FE.
-        * And then, this function will be called *after* BE settings.
-        * this means, each BE already has fixuped hw_params.
-        * see
-        *      dpcm_fe_dai_hw_params()
-        *      dpcm_be_dai_hw_params()
-        */
-       src->convert_rate = 0;
-       if (fe->dai_link->dynamic) {
-               int stream = substream->stream;
-               struct snd_soc_dpcm *dpcm;
-               struct snd_pcm_hw_params *be_params;
-
-               for_each_dpcm_be(fe, stream, dpcm) {
-                       be_params = &dpcm->hw_params;
-
-                       if (params_rate(fe_params) != params_rate(be_params))
-                               src->convert_rate = params_rate(be_params);
-               }
-       }
-
-       return 0;
-}
-
 static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
                                      struct rsnd_mod *mod)
 {
@@ -349,9 +314,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
        status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
        status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
        if ((status0 & val0) || (status1 & val1)) {
-               rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod),
-                       status0, status1);
+               rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
+                       rsnd_mod_name(mod), status0, status1);
 
                ret = true;
        }
@@ -527,16 +491,16 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
 }
 
 static struct rsnd_mod_ops rsnd_src_ops = {
-       .name   = SRC_NAME,
-       .dma_req = rsnd_src_dma_req,
-       .probe  = rsnd_src_probe_,
-       .init   = rsnd_src_init,
-       .quit   = rsnd_src_quit,
-       .start  = rsnd_src_start,
-       .stop   = rsnd_src_stop,
-       .irq    = rsnd_src_irq,
-       .hw_params = rsnd_src_hw_params,
-       .pcm_new = rsnd_src_pcm_new,
+       .name           = SRC_NAME,
+       .dma_req        = rsnd_src_dma_req,
+       .probe          = rsnd_src_probe_,
+       .init           = rsnd_src_init,
+       .quit           = rsnd_src_quit,
+       .start          = rsnd_src_start,
+       .stop           = rsnd_src_stop,
+       .irq            = rsnd_src_irq,
+       .pcm_new        = rsnd_src_pcm_new,
+       .get_status     = rsnd_mod_get_status,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -605,8 +569,7 @@ int rsnd_src_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(src),
-                                   &rsnd_src_ops, clk, rsnd_mod_get_status,
-                                   RSND_MOD_SRC, i);
+                                   &rsnd_src_ops, clk, RSND_MOD_SRC, i);
                if (ret) {
                        of_node_put(np);
                        goto rsnd_src_probe_done;
index 6ec78f3096dd3e8158561535569e1f2502674d49..45ef295743ecdc2f6042e36b2c2f31edd619a3f9 100644 (file)
@@ -99,9 +99,7 @@ struct rsnd_ssi {
 /* flags */
 #define RSND_SSI_CLK_PIN_SHARE         (1 << 0)
 #define RSND_SSI_NO_BUSIF              (1 << 1) /* SSI+DMA without BUSIF */
-#define RSND_SSI_HDMI0                 (1 << 2) /* for HDMI0 */
-#define RSND_SSI_HDMI1                 (1 << 3) /* for HDMI1 */
-#define RSND_SSI_PROBED                        (1 << 4)
+#define RSND_SSI_PROBED                        (1 << 2)
 
 #define for_each_rsnd_ssi(pos, priv, i)                                        \
        for (i = 0;                                                     \
@@ -119,19 +117,7 @@ struct rsnd_ssi {
        (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
 #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
 
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
-               return RSND_SSI_HDMI_PORT0;
-
-       if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
-               return RSND_SSI_HDMI_PORT1;
-
-       return 0;
-}
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
 
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 {
@@ -150,11 +136,6 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
        return use_busif;
 }
 
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
-{
-       return 0; /* BUSIF0 only for now */
-}
-
 static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, SSISR, 0);
@@ -181,8 +162,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
                udelay(5);
        }
 
-       dev_warn(dev, "%s[%d] status check failed\n",
-                rsnd_mod_name(mod), rsnd_mod_id(mod));
+       dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
 }
 
 static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
@@ -224,7 +204,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
 
 u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
 {
-       if (rsnd_runtime_is_ssi_multi(io))
+       if (rsnd_runtime_is_multi_ssi(io))
                return rsnd_ssi_multi_slaves(io);
 
        return 0;
@@ -320,6 +300,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
                return 0;
        }
 
+       if (rsnd_runtime_is_tdm_split(io))
+               chan = rsnd_io_converted_chan(io);
+
        main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
        if (!main_rate) {
                dev_err(dev, "unsupported clock rate\n");
@@ -346,9 +329,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
        ssi->rate = rate;
        ssi->chan = chan;
 
-       dev_dbg(dev, "%s[%d] outputs %u Hz\n",
-               rsnd_mod_name(mod),
-               rsnd_mod_id(mod), rate);
+       dev_dbg(dev, "%s outputs %d chan %u Hz\n",
+               rsnd_mod_name(mod), chan, rate);
 
        return 0;
 }
@@ -379,14 +361,23 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
                                struct rsnd_dai_stream *io)
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        u32 cr_own      = ssi->cr_own;
        u32 cr_mode     = ssi->cr_mode;
        u32 wsr         = ssi->wsr;
-       int is_tdm;
+       int width;
+       int is_tdm, is_tdm_split;
+
+       is_tdm          = rsnd_runtime_is_tdm(io);
+       is_tdm_split    = rsnd_runtime_is_tdm_split(io);
 
-       is_tdm = rsnd_runtime_is_ssi_tdm(io);
+       if (is_tdm)
+               dev_dbg(dev, "TDM mode\n");
+       if (is_tdm_split)
+               dev_dbg(dev, "TDM Split mode\n");
 
        cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
 
@@ -405,7 +396,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
         *      rsnd_ssiu_init_gen2()
         */
        wsr = ssi->wsr;
-       if (is_tdm) {
+       if (is_tdm || is_tdm_split) {
                wsr     |= WS_MODE;
                cr_own  |= CHNL_8;
        }
@@ -421,7 +412,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
                cr_own |= TRMD;
 
        cr_own &= ~DWL_MASK;
-       switch (snd_pcm_format_width(runtime->format)) {
+       width = snd_pcm_format_width(runtime->format);
+       if (is_tdm_split) {
+               /*
+                * The SWL and DWL bits in SSICR should be fixed at 32-bit
+                * setting when TDM split mode.
+                * see datasheet
+                *      Operation :: TDM Format Split Function (TDM Split Mode)
+                */
+               width = 32;
+       }
+
+       switch (width) {
        case 8:
                cr_own |= DWL_8;
                break;
@@ -431,6 +433,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
        case 24:
                cr_own |= DWL_24;
                break;
+       case 32:
+               cr_own |= DWL_32;
+               break;
        }
 
        if (rsnd_ssi_is_dma_mode(mod)) {
@@ -494,8 +499,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
                return 0;
 
        if (!ssi->usrcnt) {
-               dev_err(dev, "%s[%d] usrcnt error\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+               dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
                return -EIO;
        }
 
@@ -654,8 +658,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 
        /* DMA only */
        if (is_dma && (status & (UIRQ | OIRQ))) {
-               rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod), status);
+               rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n",
+                       rsnd_mod_name(mod), status);
 
                stop = true;
        }
@@ -681,6 +685,41 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
+                               enum rsnd_mod_type type)
+{
+       /*
+        * SSIP (= SSI parent) needs to be special, otherwise,
+        * 2nd SSI might doesn't start. see also rsnd_mod_call()
+        *
+        * We can't include parent SSI status on SSI, because we don't know
+        * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+        * ex) trouble case
+        *      Playback: SSI0
+        *      Capture : SSI1 (needs SSI0)
+        *
+        * 1) start Capture  -> SSI0/SSI1 are started.
+        * 2) start Playback -> SSI0 doesn't work, because it is already
+        *                      marked as "started" on 1)
+        *
+        * OTOH, using each mod's status is good for MUX case.
+        * It doesn't need to start in 2nd start
+        * ex)
+        *      IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+        *                          |
+        *      IO-1: SRC1 -> CTU2 -+
+        *
+        * 1) start IO-0 ->     start SSI0
+        * 2) start IO-1 ->     SSI0 doesn't need to start, because it is
+        *                      already started on 1)
+        */
+       if (type == RSND_MOD_SSIP)
+               return &io->parent_ssi_status;
+
+       return rsnd_mod_get_status(mod, io, type);
+}
+
 /*
  *             SSI PIO
  */
@@ -730,7 +769,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int ret;
+       int ret = 0;
 
        /*
         * SSIP/SSIU/IRQ are not needed on
@@ -744,10 +783,6 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
         * see rsnd_ssi_pcm_new()
         */
 
-       ret = rsnd_ssiu_attach(io, mod);
-       if (ret < 0)
-               return ret;
-
        /*
         * SSI might be called again as PIO fallback
         * It is easy to manual handling for IRQ request/free
@@ -876,18 +911,19 @@ static int rsnd_ssi_prepare(struct rsnd_mod *mod,
 }
 
 static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
-       .name   = SSI_NAME,
-       .probe  = rsnd_ssi_common_probe,
-       .remove = rsnd_ssi_common_remove,
-       .init   = rsnd_ssi_pio_init,
-       .quit   = rsnd_ssi_quit,
-       .start  = rsnd_ssi_start,
-       .stop   = rsnd_ssi_stop,
-       .irq    = rsnd_ssi_irq,
-       .pointer = rsnd_ssi_pio_pointer,
-       .pcm_new = rsnd_ssi_pcm_new,
-       .hw_params = rsnd_ssi_hw_params,
-       .prepare = rsnd_ssi_prepare,
+       .name           = SSI_NAME,
+       .probe          = rsnd_ssi_common_probe,
+       .remove         = rsnd_ssi_common_remove,
+       .init           = rsnd_ssi_pio_init,
+       .quit           = rsnd_ssi_quit,
+       .start          = rsnd_ssi_start,
+       .stop           = rsnd_ssi_stop,
+       .irq            = rsnd_ssi_irq,
+       .pointer        = rsnd_ssi_pio_pointer,
+       .pcm_new        = rsnd_ssi_pcm_new,
+       .hw_params      = rsnd_ssi_hw_params,
+       .prepare        = rsnd_ssi_prepare,
+       .get_status     = rsnd_ssi_get_status,
 };
 
 static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -928,8 +964,7 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
         */
        mod->ops = &rsnd_ssi_pio_ops;
 
-       dev_info(dev, "%s[%d] fallback to PIO mode\n",
-                rsnd_mod_name(mod), rsnd_mod_id(mod));
+       dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
 
        return 0;
 }
@@ -941,6 +976,17 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
        int is_play = rsnd_io_is_play(io);
        char *name;
 
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssiu_dma_req()
+        *      rsnd_dma_of_path()
+        */
+
        if (rsnd_ssi_use_busif(io))
                name = is_play ? "rxu" : "txu";
        else
@@ -951,27 +997,27 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
 }
 
 static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
-       .name   = SSI_NAME,
-       .dma_req = rsnd_ssi_dma_req,
-       .probe  = rsnd_ssi_dma_probe,
-       .remove = rsnd_ssi_common_remove,
-       .init   = rsnd_ssi_init,
-       .quit   = rsnd_ssi_quit,
-       .start  = rsnd_ssi_start,
-       .stop   = rsnd_ssi_stop,
-       .irq    = rsnd_ssi_irq,
-       .pcm_new = rsnd_ssi_pcm_new,
-       .fallback = rsnd_ssi_fallback,
-       .hw_params = rsnd_ssi_hw_params,
-       .prepare = rsnd_ssi_prepare,
+       .name           = SSI_NAME,
+       .dma_req        = rsnd_ssi_dma_req,
+       .probe          = rsnd_ssi_dma_probe,
+       .remove         = rsnd_ssi_common_remove,
+       .init           = rsnd_ssi_init,
+       .quit           = rsnd_ssi_quit,
+       .start          = rsnd_ssi_start,
+       .stop           = rsnd_ssi_stop,
+       .irq            = rsnd_ssi_irq,
+       .pcm_new        = rsnd_ssi_pcm_new,
+       .fallback       = rsnd_ssi_fallback,
+       .hw_params      = rsnd_ssi_hw_params,
+       .prepare        = rsnd_ssi_prepare,
+       .get_status     = rsnd_ssi_get_status,
 };
 
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
 {
        return mod->ops == &rsnd_ssi_dma_ops;
 }
 
-
 /*
  *             ssi mod function
  */
@@ -1027,54 +1073,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
        of_node_put(node);
 }
 
-static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
-                                            struct rsnd_dai_stream *io,
-                                            struct device_node *remote_ep)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_ssi *ssi;
-       struct device_node *remote_node = of_graph_get_port_parent(remote_ep);
-
-       /* support Gen3 only */
-       if (!rsnd_is_gen3(priv))
-               return;
-
-       if (!mod)
-               return;
-
-       ssi  = rsnd_mod_to_ssi(mod);
-
-       /* HDMI0 */
-       if (strstr(remote_node->full_name, "hdmi@fead0000")) {
-               rsnd_flags_set(ssi, RSND_SSI_HDMI0);
-               dev_dbg(dev, "%s[%d] connected to HDMI0\n",
-                        rsnd_mod_name(mod), rsnd_mod_id(mod));
-       }
-
-       /* HDMI1 */
-       if (strstr(remote_node->full_name, "hdmi@feae0000")) {
-               rsnd_flags_set(ssi, RSND_SSI_HDMI1);
-               dev_dbg(dev, "%s[%d] connected to HDMI1\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
-       }
-}
-
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
-                                   struct device_node *endpoint,
-                                   int dai_i)
-{
-       struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
-       struct device_node *remote_ep;
-
-       remote_ep = of_graph_get_remote_endpoint(endpoint);
-       if (!remote_ep)
-               return;
-
-       __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
-       __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture,  remote_ep);
-}
-
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
 {
        if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@ -1091,41 +1089,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
        return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
 }
 
-static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod,
-                               enum rsnd_mod_type type)
-{
-       /*
-        * SSIP (= SSI parent) needs to be special, otherwise,
-        * 2nd SSI might doesn't start. see also rsnd_mod_call()
-        *
-        * We can't include parent SSI status on SSI, because we don't know
-        * how many SSI requests parent SSI. Thus, it is localed on "io" now.
-        * ex) trouble case
-        *      Playback: SSI0
-        *      Capture : SSI1 (needs SSI0)
-        *
-        * 1) start Capture  -> SSI0/SSI1 are started.
-        * 2) start Playback -> SSI0 doesn't work, because it is already
-        *                      marked as "started" on 1)
-        *
-        * OTOH, using each mod's status is good for MUX case.
-        * It doesn't need to start in 2nd start
-        * ex)
-        *      IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
-        *                          |
-        *      IO-1: SRC1 -> CTU2 -+
-        *
-        * 1) start IO-0 ->     start SSI0
-        * 2) start IO-1 ->     SSI0 doesn't need to start, because it is
-        *                      already started on 1)
-        */
-       if (type == RSND_MOD_SSIP)
-               return &io->parent_ssi_status;
-
-       return rsnd_mod_get_status(io, mod, type);
-}
-
 int rsnd_ssi_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
@@ -1192,7 +1155,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
                        ops = &rsnd_ssi_dma_ops;
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
-                                   rsnd_ssi_get_status, RSND_MOD_SSI, i);
+                                   RSND_MOD_SSI, i);
                if (ret) {
                        of_node_put(np);
                        goto rsnd_ssi_probe_done;
index 39b67643b5dc2fe25680338a7e5da1a57c779ee5..c5934adcfd0155e5a410ecc1d5ea171268f16e8d 100644 (file)
@@ -12,8 +12,14 @@ struct rsnd_ssiu {
        struct rsnd_mod mod;
        u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
        unsigned int usrcnt;
+       int id;
+       int id_sub;
 };
 
+/* SSI_MODE */
+#define TDM_EXT                (1 << 0)
+#define TDM_SPLIT      (1 << 8)
+
 #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
 #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
 #define for_each_rsnd_ssiu(pos, priv, i)                               \
@@ -22,6 +28,33 @@ struct rsnd_ssiu {
                     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));  \
             i++)
 
+/*
+ *     SSI     Gen2            Gen3
+ *     0       BUSIF0-3        BUSIF0-7
+ *     1       BUSIF0-3        BUSIF0-7
+ *     2       BUSIF0-3        BUSIF0-7
+ *     3       BUSIF0          BUSIF0-7
+ *     4       BUSIF0          BUSIF0-7
+ *     5       BUSIF0          BUSIF0
+ *     6       BUSIF0          BUSIF0
+ *     7       BUSIF0          BUSIF0
+ *     8       BUSIF0          BUSIF0
+ *     9       BUSIF0-3        BUSIF0-7
+ *     total   22              52
+ */
+static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
+static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
+
+static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io,
+                                enum rsnd_mod_type type)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+       int busif = rsnd_mod_id_sub(mod);
+
+       return &ssiu->busif_status[busif];
+}
+
 static int rsnd_ssiu_init(struct rsnd_mod *mod,
                          struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
@@ -32,6 +65,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
        int id = rsnd_mod_id(mod);
        u32 mask1, val1;
        u32 mask2, val2;
+       int i;
 
        /* clear status */
        switch (id) {
@@ -40,16 +74,12 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
        case 2:
        case 3:
        case 4:
-               rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
-               rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
-               rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
-               rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
+               for (i = 0; i < 4; i++)
+                       rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
                break;
        case 9:
-               rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
-               rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
-               rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
-               rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
+               for (i = 0; i < 4; i++)
+                       rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << (id * 4));
                break;
        }
 
@@ -115,8 +145,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
 }
 
 static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
-       .name   = SSIU_NAME,
-       .init   = rsnd_ssiu_init,
+       .name           = SSIU_NAME,
+       .init           = rsnd_ssiu_init,
+       .get_status     = rsnd_ssiu_get_status,
 };
 
 static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
@@ -124,7 +155,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
                               struct rsnd_priv *priv)
 {
        struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       int hdmi = rsnd_ssi_hdmi_port(io);
+       u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
+       u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
        int ret;
        u32 mode = 0;
 
@@ -134,20 +166,21 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
 
        ssiu->usrcnt++;
 
-       if (rsnd_runtime_is_ssi_tdm(io)) {
-               /*
-                * TDM Extend Mode
-                * see
-                *      rsnd_ssi_config_init()
-                */
-               mode = 0x1;
-       }
+       /*
+        * TDM Extend/Split Mode
+        * see
+        *      rsnd_ssi_config_init()
+        */
+       if (rsnd_runtime_is_tdm(io))
+               mode = TDM_EXT;
+       else if (rsnd_runtime_is_tdm_split(io))
+               mode = TDM_SPLIT;
 
        rsnd_mod_write(mod, SSI_MODE, mode);
 
        if (rsnd_ssi_use_busif(io)) {
                int id = rsnd_mod_id(mod);
-               int busif = rsnd_ssi_get_busif(io);
+               int busif = rsnd_mod_id_sub(mod);
 
                /*
                 * FIXME
@@ -162,46 +195,18 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
                                id, busif);
                }
 
-#define RSND_WRITE_BUSIF(i)                                            \
-               rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR,               \
-                              rsnd_get_adinr_bit(mod, io) |            \
-                              (rsnd_io_is_play(io) ?                   \
-                               rsnd_runtime_channel_after_ctu(io) :    \
-                               rsnd_runtime_channel_original(io)));    \
-               rsnd_mod_write(mod, SSI_BUSIF##i##_MODE,                \
-                              rsnd_get_busif_shift(io, mod) | 1);      \
-               rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN,              \
-                              rsnd_get_dalign(mod, io))
-
-               switch (busif) {
-               case 0:
-                       RSND_WRITE_BUSIF(0);
-                       break;
-               case 1:
-                       RSND_WRITE_BUSIF(1);
-                       break;
-               case 2:
-                       RSND_WRITE_BUSIF(2);
-                       break;
-               case 3:
-                       RSND_WRITE_BUSIF(3);
-                       break;
-               case 4:
-                       RSND_WRITE_BUSIF(4);
-                       break;
-               case 5:
-                       RSND_WRITE_BUSIF(5);
-                       break;
-               case 6:
-                       RSND_WRITE_BUSIF(6);
-                       break;
-               case 7:
-                       RSND_WRITE_BUSIF(7);
-                       break;
-               }
+               rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif),
+                              rsnd_get_adinr_bit(mod, io) |
+                              (rsnd_io_is_play(io) ?
+                               rsnd_runtime_channel_after_ctu(io) :
+                               rsnd_runtime_channel_original(io)));
+               rsnd_mod_write(mod, SSI_BUSIF_MODE(busif),
+                              rsnd_get_busif_shift(io, mod) | 1);
+               rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif),
+                              rsnd_get_dalign(mod, io));
        }
 
-       if (hdmi) {
+       if (has_hdmi0 || has_hdmi1) {
                enum rsnd_mod_type rsnd_ssi_array[] = {
                        RSND_MOD_SSIM1,
                        RSND_MOD_SSIM2,
@@ -227,14 +232,10 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
                                rsnd_mod_id(pos) << shift;
                }
 
-               switch (hdmi) {
-               case RSND_SSI_HDMI_PORT0:
+               if (has_hdmi0)
                        rsnd_mod_write(mod, HDMI0_SEL, val);
-                       break;
-               case RSND_SSI_HDMI_PORT1:
+               if (has_hdmi1)
                        rsnd_mod_write(mod, HDMI1_SEL, val);
-                       break;
-               }
        }
 
        return 0;
@@ -244,7 +245,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
                                struct rsnd_dai_stream *io,
                                struct rsnd_priv *priv)
 {
-       int busif = rsnd_ssi_get_busif(io);
+       int busif = rsnd_mod_id_sub(mod);
 
        if (!rsnd_ssi_use_busif(io))
                return 0;
@@ -262,7 +263,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
                               struct rsnd_priv *priv)
 {
        struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       int busif = rsnd_ssi_get_busif(io);
+       int busif = rsnd_mod_id_sub(mod);
 
        if (!rsnd_ssi_use_busif(io))
                return 0;
@@ -278,11 +279,53 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_ssiu_id(struct rsnd_mod *mod)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+       /* see rsnd_ssiu_probe() */
+       return ssiu->id;
+}
+
+static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+       /* see rsnd_ssiu_probe() */
+       return ssiu->id_sub;
+}
+
+static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
+                                         struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int is_play = rsnd_io_is_play(io);
+       char *name;
+
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssi_dma_req()
+        *      rsnd_dma_of_path()
+        */
+
+       name = is_play ? "rx" : "tx";
+
+       return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
+                                       mod, name);
+}
+
 static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
-       .name   = SSIU_NAME,
-       .init   = rsnd_ssiu_init_gen2,
-       .start  = rsnd_ssiu_start_gen2,
-       .stop   = rsnd_ssiu_stop_gen2,
+       .name           = SSIU_NAME,
+       .dma_req        = rsnd_ssiu_dma_req,
+       .init           = rsnd_ssiu_init_gen2,
+       .start          = rsnd_ssiu_start_gen2,
+       .stop           = rsnd_ssiu_stop_gen2,
+       .get_status     = rsnd_ssiu_get_status,
 };
 
 static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
@@ -293,36 +336,85 @@ static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
        return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
 }
 
-int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
-                    struct rsnd_mod *ssi_mod)
+static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
+                                              struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *mod;
+       struct rsnd_ssiu *ssiu;
+       int i;
 
-       rsnd_mod_confirm_ssi(ssi_mod);
+       if (!ssi_mod)
+               return;
 
-       return rsnd_dai_connect(mod, io, mod->type);
+       /* select BUSIF0 */
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               mod = rsnd_mod_get(ssiu);
+
+               if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
+                   (rsnd_mod_id_sub(mod) == 0)) {
+                       rsnd_dai_connect(mod, io, mod->type);
+                       return;
+               }
+       }
 }
 
-static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io,
-                                struct rsnd_mod *mod,
-                                enum rsnd_mod_type type)
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+                            struct device_node *playback,
+                            struct device_node *capture)
 {
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       int busif = rsnd_ssi_get_busif(io);
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device_node *node = rsnd_ssiu_of_node(priv);
+       struct device_node *np;
+       struct rsnd_mod *mod;
+       struct rsnd_dai_stream *io_p = &rdai->playback;
+       struct rsnd_dai_stream *io_c = &rdai->capture;
+       int i;
 
-       return &ssiu->busif_status[busif];
+       /* use rcar_sound,ssiu if exist */
+       if (node) {
+               i = 0;
+               for_each_child_of_node(node, np) {
+                       mod = rsnd_ssiu_mod_get(priv, i);
+                       if (np == playback)
+                               rsnd_dai_connect(mod, io_p, mod->type);
+                       if (np == capture)
+                               rsnd_dai_connect(mod, io_c, mod->type);
+                       i++;
+               }
+
+               of_node_put(node);
+       }
+
+       /* Keep DT compatibility */
+       if (!rsnd_io_to_mod_ssiu(io_p))
+               rsnd_parse_connect_ssiu_compatible(priv, io_p);
+       if (!rsnd_io_to_mod_ssiu(io_c))
+               rsnd_parse_connect_ssiu_compatible(priv, io_c);
 }
 
 int rsnd_ssiu_probe(struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *node;
        struct rsnd_ssiu *ssiu;
        struct rsnd_mod_ops *ops;
+       const int *list = NULL;
        int i, nr, ret;
 
-       /* same number to SSI */
-       nr      = priv->ssi_nr;
+       /*
+        * Keep DT compatibility.
+        * if it has "rcar_sound,ssiu", use it.
+        * if not, use "rcar_sound,ssi"
+        * see
+        *      rsnd_ssiu_bufsif_to_id()
+        */
+       node = rsnd_ssiu_of_node(priv);
+       if (node)
+               nr = of_get_child_count(node);
+       else
+               nr = priv->ssi_nr;
+
        ssiu    = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
        if (!ssiu)
                return -ENOMEM;
@@ -335,10 +427,46 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
        else
                ops = &rsnd_ssiu_ops_gen2;
 
+       /* Keep compatibility */
+       nr = 0;
+       if ((node) &&
+           (ops == &rsnd_ssiu_ops_gen2)) {
+               ops->id         = rsnd_ssiu_id;
+               ops->id_sub     = rsnd_ssiu_id_sub;
+
+               if (rsnd_is_gen2(priv)) {
+                       list    = gen2_id;
+                       nr      = ARRAY_SIZE(gen2_id);
+               } else if (rsnd_is_gen3(priv)) {
+                       list    = gen3_id;
+                       nr      = ARRAY_SIZE(gen3_id);
+               } else {
+                       dev_err(dev, "unknown SSIU\n");
+                       return -ENODEV;
+               }
+       }
+
        for_each_rsnd_ssiu(ssiu, priv, i) {
+               if (node) {
+                       int j;
+
+                       /*
+                        * see
+                        *      rsnd_ssiu_get_id()
+                        *      rsnd_ssiu_get_id_sub()
+                        */
+                       for (j = 0; j < nr; j++) {
+                               if (list[j] > i)
+                                       break;
+                               ssiu->id        = j;
+                               ssiu->id_sub    = i - list[ssiu->id];
+                       }
+               } else {
+                       ssiu->id = i;
+               }
+
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
-                                   ops, NULL, rsnd_ssiu_get_status,
-                                   RSND_MOD_SSIU, i);
+                                   ops, NULL, RSND_MOD_SSIU, i);
                if (ret)
                        return ret;
        }
index b29d0f65611eb536ded7aaa3e41416ca600c2bde..0462b3ec977a221a5d7869d3e7afb02e36cd7e5a 100644 (file)
@@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
        for (i = 0; i < num_dais; ++i) {
                struct snd_soc_dai_driver *drv = dais[i]->driver;
 
-               if (!rtd->dai_link->no_pcm && drv->pcm_new)
+               if (drv->pcm_new)
                        ret = drv->pcm_new(rtd, dais[i]);
                if (ret < 0) {
                        dev_err(dais[i]->dev,
@@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
 
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
-                                  struct snd_soc_codec_conf *codec_conf,
-                                  struct device_node *of_node,
-                                  const char *propname)
+void snd_soc_of_parse_node_prefix(struct device_node *np,
+                                 struct snd_soc_codec_conf *codec_conf,
+                                 struct device_node *of_node,
+                                 const char *propname)
 {
-       struct device_node *np = card->dev->of_node;
        const char *str;
        int ret;
 
@@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
        codec_conf->of_node     = of_node;
        codec_conf->name_prefix = str;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
 
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname)
index d597eba61992ce6decf9651843a82c72763c109b..bcb35cae2a2c3b8992885d66d6336d2f69e5ba4b 100644 (file)
@@ -74,14 +74,14 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
                return ret;
        }
 
-       dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
-               sai->pdev->dev.of_node->name,
+       dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
+               sai->pdev->dev.of_node,
                synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
 
        prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
        if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
-               dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
-                       sai->pdev->dev.of_node->name,
+               dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
+                       sai->pdev->dev.of_node,
                        prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
                clk_disable_unprepare(sai->pclk);
                return -EINVAL;
index 211589b0b2ef5400276d689599134bd02919691d..d4825700b63f66464938a7a8547414517cb8722e 100644 (file)
@@ -336,8 +336,7 @@ static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
        struct stm32_sai_sub_data *sai = mclk->sai_data;
-       unsigned int div;
-       int ret;
+       int div, ret;
 
        div = stm32_sai_get_clk_div(sai, parent_rate, rate);
        if (div < 0)
index 8f5f999df6311948da6bb9a13a222cf2de3e4ca1..df1fed0aa0019d90e787cdd18ddffaf7416991f3 100644 (file)
@@ -274,6 +274,7 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
         * stream widgets at the card level.
         */
 
+       SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0),
        SND_SOC_DAPM_MUX("Headphone Source Playback Route",
                         SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
        SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
@@ -361,6 +362,7 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
        { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
        { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
        { "Headphone Amp", NULL, "Headphone Source Playback Route" },
+       { "Headphone Amp", NULL, "hpvcc" },
        { "HP", NULL, "Headphone Amp" },
 
        /* Microphone Routes */
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
new file mode 100644 (file)
index 0000000..4bf3c15
--- /dev/null
@@ -0,0 +1,209 @@
+menu "Audio support for Texas Instruments SoCs"
+depends on DMA_OMAP || TI_EDMA || COMPILE_TEST
+
+config SND_SOC_TI_EDMA_PCM
+       tristate
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_TI_SDMA_PCM
+       tristate
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+
+comment "Texas Instruments DAI support for:"
+config SND_SOC_DAVINCI_ASP
+       tristate "daVinci Audio Serial Port (ASP) or McBSP suport"
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       select SND_SOC_TI_EDMA_PCM
+       help
+         Say Y or M here if you want audio support via daVinci ASP or McBSP.
+         The driver only implements the ASP support which is a subset of
+         daVinci McBSP (w/o the multichannel support).
+
+config SND_SOC_DAVINCI_MCASP
+       tristate "Multichannel Audio Serial Port (McASP) support"
+       select SND_SOC_TI_EDMA_PCM if TI_EDMA
+       select SND_SOC_TI_SDMA_PCM if DMA_OMAP
+       help
+         Say Y or M here if you want to have support for McASP IP found in
+         various Texas Instruments SoCs like:
+         - daVinci devices
+         - Sitara line of SoCs (AM335x, AM438x, etc)
+         - DRA7x devices
+         - Keystone devices
+
+config SND_SOC_DAVINCI_VCIF
+       tristate "daVinci Voice Interface (VCIF) suport"
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       select SND_SOC_TI_EDMA_PCM
+       help
+         Say Y or M here if you want audio support via daVinci VCIF.
+
+config SND_SOC_OMAP_DMIC
+       tristate "Digital Microphone Module (DMIC) support"
+       depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+       select SND_SOC_TI_SDMA_PCM
+       help
+         Say Y or M here if you want to have support for DMIC IP found in
+         OMAP4 and OMAP5.
+
+config SND_SOC_OMAP_MCBSP
+       tristate "Multichannel Buffered Serial Port (McBSP) support"
+       depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST
+       select SND_SOC_TI_SDMA_PCM
+       help
+         Say Y or M here if you want to have support for McBSP IP found in
+         Texas Instruments OMAP1/2/3/4/5 SoCs.
+
+config SND_SOC_OMAP_MCPDM
+       tristate "Multichannel PDM Controller (McPDM) support"
+       depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+       select SND_SOC_TI_SDMA_PCM
+       help
+         Say Y or M here if you want to have support for McPDM IP found in
+         OMAP4 and OMAP5.
+
+comment "Audio support for boards with Texas Instruments SoCs"
+config SND_SOC_NOKIA_N810
+       tristate "SoC Audio support for Nokia N810"
+       depends on MACH_NOKIA_N810 && I2C
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_TLV320AIC3X
+       help
+         Say Y or M if you want to add support for SoC audio on Nokia N810.
+
+config SND_SOC_NOKIA_RX51
+       tristate "SoC Audio support for Nokia RX-51"
+       depends on ARCH_OMAP3 && I2C && GPIOLIB
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_TLV320AIC3X
+       select SND_SOC_TPA6130A2
+       help
+         Say Y or M if you want to add support for SoC audio on Nokia RX-51
+         hardware. This is also known as Nokia N900 product.
+
+config SND_SOC_OMAP3_PANDORA
+       tristate "SoC Audio support for OMAP3 Pandora"
+       depends on ARCH_OMAP3
+       depends on TWL4030_CORE
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y or M if you want to add support for SoC audio on the OMAP3 Pandora.
+
+config SND_SOC_OMAP3_TWL4030
+       tristate "SoC Audio support for OMAP3 based boards with twl4030 codec"
+       depends on ARCH_OMAP3 || COMPILE_TEST
+       depends on TWL4030_CORE
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y or M if you want to add support for SoC audio on OMAP3 based
+         boards using twl4030 as codec. This driver currently supports:
+         - Beagleboard or Devkit8000
+         - Gumstix Overo or CompuLab CM-T35/CM-T3730
+         - IGEP v2
+         - OMAP3EVM
+         - SDP3430
+         - Zoom2
+
+config SND_SOC_OMAP_ABE_TWL6040
+       tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
+       depends on TWL6040_CORE && COMMON_CLK
+       depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
+       select SND_SOC_OMAP_DMIC
+       select SND_SOC_OMAP_MCPDM
+       select SND_SOC_TWL6040
+       help
+         Say Y or M if you want to add support for SoC audio on OMAP boards
+         using ABE and twl6040 codec. This driver currently supports:
+         - SDP4430/Blaze boards
+         - PandaBoard (4430)
+         - PandaBoardES (4460)
+         - OMAP5 uEVM
+
+config SND_SOC_OMAP_AMS_DELTA
+       tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
+       depends on MACH_AMS_DELTA && TTY
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_CX20442
+       help
+         Say Y  or M if you want to add support  for SoC audio device
+         connected to a handset and a speakerphone found on Amstrad E3 (Delta)
+         videophone.
+
+         Note that in order to get those devices fully supported,  you have to
+         build  the kernel  with  standard  serial port  driver  included  and
+         configured for at least 4 ports.  Then, from userspace, you must load
+         a line discipline #19 on the modem (ttyS3) serial line.  The simplest
+         way to achieve this is to install util-linux-ng  and use the included
+         ldattach  utility.  This  can be  started  automatically  from  udev,
+         a simple rule like this one should do the trick (it does for me):
+               ACTION=="add", KERNEL=="controlC0", \
+                               RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
+
+config SND_SOC_OMAP_HDMI
+       tristate "OMAP4/5 HDMI audio support"
+       depends on OMAP4_DSS_HDMI || OMAP5_DSS_HDMI || COMPILE_TEST
+       select SND_SOC_TI_SDMA_PCM
+       help
+         For HDMI audio to work OMAPDSS HDMI support should be
+         enabled.
+         The hdmi audio driver implements cpu-dai component using the
+         callbacks provided by OMAPDSS and registers the component
+         under DSS HDMI device. Omap-pcm is registered for platform
+         component also under DSS HDMI device. Dummy codec is used as
+         as codec component. The hdmi audio driver implements also
+         the card and registers it under its own platform device.
+         The device for the driver is registered by OMAPDSS hdmi
+         driver.
+
+config SND_SOC_OMAP_OSK5912
+       tristate "SoC Audio support for omap osk5912"
+       depends on MACH_OMAP_OSK && I2C
+       select SND_SOC_OMAP_MCBSP
+       select SND_SOC_TLV320AIC23_I2C
+       help
+         Say Y or M if you want to add support for SoC audio on osk5912.
+
+config SND_SOC_DAVINCI_EVM
+       tristate "SoC Audio support for DaVinci EVMs"
+       depends on ARCH_DAVINCI && I2C
+       select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_DM355_EVM
+       select SND_SOC_DAVINCI_ASP if SND_SOC_DM365_AIC3X_CODEC
+       select SND_SOC_DAVINCI_VCIF if SND_SOC_DM365_VOICE_CODEC
+       select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_EVM # DM6446
+       select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DM6467_EVM
+       select SND_SOC_SPDIF if MACH_DAVINCI_DM6467_EVM
+       select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA830_EVM
+       select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA850_EVM
+       select SND_SOC_TLV320AIC3X
+       help
+         Say Y if you want to add support for SoC audio on the following TI
+         DaVinci EVM platforms:
+         - DM355
+         - DM365
+         - DM6446
+         - DM6447
+         - DM830
+         - DM850
+
+choice
+       prompt "DM365 codec select"
+       depends on SND_SOC_DAVINCI_EVM
+       depends on MACH_DAVINCI_DM365_EVM
+
+config SND_SOC_DM365_AIC3X_CODEC
+       bool "Audio Codec - AIC3101"
+       help
+         Say Y if you want to add support for AIC3101 audio codec
+
+config SND_SOC_DM365_VOICE_CODEC
+       bool "Voice Codec - CQ93VC"
+       select MFD_DAVINCI_VOICECODEC
+       select SND_SOC_CQ0093VC
+       help
+         Say Y if you want to add support for SoC On-chip voice codec
+endchoice
+
+endmenu
+
diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile
new file mode 100644 (file)
index 0000000..08c44d5
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Platform drivers
+snd-soc-ti-edma-objs := edma-pcm.o
+snd-soc-ti-sdma-objs := sdma-pcm.o
+
+obj-$(CONFIG_SND_SOC_TI_EDMA_PCM) += snd-soc-ti-edma.o
+obj-$(CONFIG_SND_SOC_TI_SDMA_PCM) += snd-soc-ti-sdma.o
+
+# CPU DAI drivers
+snd-soc-davinci-asp-objs := davinci-i2s.o
+snd-soc-davinci-mcasp-objs := davinci-mcasp.o
+snd-soc-davinci-vcif-objs := davinci-vcif.o
+snd-soc-omap-dmic-objs := omap-dmic.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_ASP) += snd-soc-davinci-asp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_MCASP) += snd-soc-davinci-mcasp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_VCIF) += snd-soc-davinci-vcif.o
+obj-$(CONFIG_SND_SOC_OMAP_DMIC) += snd-soc-omap-dmic.o
+obj-$(CONFIG_SND_SOC_OMAP_MCBSP) += snd-soc-omap-mcbsp.o
+obj-$(CONFIG_SND_SOC_OMAP_MCPDM) += snd-soc-omap-mcpdm.o
+
+# Machine drivers
+snd-soc-davinci-evm-objs := davinci-evm.o
+snd-soc-n810-objs := n810.o
+snd-soc-rx51-objs := rx51.o
+snd-soc-omap3pandora-objs := omap3pandora.o
+snd-soc-omap-twl4030-objs := omap-twl4030.o
+snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
+snd-soc-ams-delta-objs := ams-delta.o
+snd-soc-omap-hdmi-objs := omap-hdmi.o
+snd-soc-osk5912-objs := osk5912.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o
+obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_SOC_NOKIA_RX51) += snd-soc-rx51.o
+obj-$(CONFIG_SND_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
+obj-$(CONFIG_SND_SOC_OMAP3_TWL4030) += snd-soc-omap-twl4030.o
+obj-$(CONFIG_SND_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
+obj-$(CONFIG_SND_SOC_OMAP_AMS_DELTA) += snd-soc-ams-delta.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI) += snd-soc-omap-hdmi.o
+obj-$(CONFIG_SND_SOC_OMAP_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
new file mode 100644 (file)
index 0000000..4dce494
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * ams-delta.c  --  SoC audio for Amstrad E3 (Delta) videophone
+ *
+ * Copyright (C) 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Initially based on sound/soc/omap/osk5912.x
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "../codecs/cx20442.h"
+
+/* Board specific DAPM widgets */
+static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
+       /* Handset */
+       SND_SOC_DAPM_MIC("Mouthpiece", NULL),
+       SND_SOC_DAPM_HP("Earpiece", NULL),
+       /* Handsfree/Speakerphone */
+       SND_SOC_DAPM_MIC("Microphone", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/* How they are connected to codec pins */
+static const struct snd_soc_dapm_route ams_delta_audio_map[] = {
+       {"TELIN", NULL, "Mouthpiece"},
+       {"Earpiece", NULL, "TELOUT"},
+
+       {"MIC", NULL, "Microphone"},
+       {"Speaker", NULL, "SPKOUT"},
+};
+
+/*
+ * Controls, functional after the modem line discipline is activated.
+ */
+
+/* Virtual switch: audio input/output constellations */
+static const char *ams_delta_audio_mode[] =
+       {"Mixed", "Handset", "Handsfree", "Speakerphone"};
+
+/* Selection <-> pin translation */
+#define AMS_DELTA_MOUTHPIECE   0
+#define AMS_DELTA_EARPIECE     1
+#define AMS_DELTA_MICROPHONE   2
+#define AMS_DELTA_SPEAKER      3
+#define AMS_DELTA_AGC          4
+
+#define AMS_DELTA_MIXED                ((1 << AMS_DELTA_EARPIECE) | \
+                                               (1 << AMS_DELTA_MICROPHONE))
+#define AMS_DELTA_HANDSET      ((1 << AMS_DELTA_MOUTHPIECE) | \
+                                               (1 << AMS_DELTA_EARPIECE))
+#define AMS_DELTA_HANDSFREE    ((1 << AMS_DELTA_MICROPHONE) | \
+                                               (1 << AMS_DELTA_SPEAKER))
+#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
+
+static const unsigned short ams_delta_audio_mode_pins[] = {
+       AMS_DELTA_MIXED,
+       AMS_DELTA_HANDSET,
+       AMS_DELTA_HANDSFREE,
+       AMS_DELTA_SPEAKERPHONE,
+};
+
+static unsigned short ams_delta_audio_agc;
+
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_component *cx20442_codec;
+
+static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+       struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
+       unsigned short pins;
+       int pin, changed = 0;
+
+       /* Refuse any mode changes if we are not able to control the codec. */
+       if (!cx20442_codec->card->pop_time)
+               return -EUNATCH;
+
+       if (ucontrol->value.enumerated.item[0] >= control->items)
+               return -EINVAL;
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       /* Translate selection to bitmap */
+       pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
+
+       /* Setup pins after corresponding bits if changed */
+       pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
+
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
+               changed = 1;
+               if (pin)
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
+               else
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
+       }
+       pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
+               changed = 1;
+               if (pin)
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
+               else
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece");
+       }
+       pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
+               changed = 1;
+               if (pin)
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
+               else
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone");
+       }
+       pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
+               changed = 1;
+               if (pin)
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
+               else
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+       }
+       pin = !!(pins & (1 << AMS_DELTA_AGC));
+       if (pin != ams_delta_audio_agc) {
+               ams_delta_audio_agc = pin;
+               changed = 1;
+               if (pin)
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
+               else
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
+       }
+
+       if (changed)
+               snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       return changed;
+}
+
+static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+       unsigned short pins, mode;
+
+       pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
+                                                       AMS_DELTA_MOUTHPIECE) |
+                       (snd_soc_dapm_get_pin_status(dapm, "Earpiece") <<
+                                                       AMS_DELTA_EARPIECE));
+       if (pins)
+               pins |= (snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
+                                                       AMS_DELTA_MICROPHONE);
+       else
+               pins = ((snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
+                                                       AMS_DELTA_MICROPHONE) |
+                       (snd_soc_dapm_get_pin_status(dapm, "Speaker") <<
+                                                       AMS_DELTA_SPEAKER) |
+                       (ams_delta_audio_agc << AMS_DELTA_AGC));
+
+       for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++)
+               if (pins == ams_delta_audio_mode_pins[mode])
+                       break;
+
+       if (mode >= ARRAY_SIZE(ams_delta_audio_mode))
+               return -EINVAL;
+
+       ucontrol->value.enumerated.item[0] = mode;
+
+       return 0;
+}
+
+static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
+                                     ams_delta_audio_mode);
+
+static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
+       SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
+                       ams_delta_get_audio_mode, ams_delta_set_audio_mode),
+};
+
+/* Hook switch */
+static struct snd_soc_jack ams_delta_hook_switch;
+static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = {
+       {
+               .name = "hook_switch",
+               .report = SND_JACK_HEADSET,
+               .invert = 1,
+               .debounce_time = 150,
+       }
+};
+
+/* After we are able to control the codec over the modem,
+ * the hook switch can be used for dynamic DAPM reconfiguration. */
+static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = {
+       /* Handset */
+       {
+               .pin = "Mouthpiece",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Earpiece",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       /* Handsfree */
+       {
+               .pin = "Microphone",
+               .mask = SND_JACK_MICROPHONE,
+               .invert = 1,
+       },
+       {
+               .pin = "Speaker",
+               .mask = SND_JACK_HEADPHONE,
+               .invert = 1,
+       },
+};
+
+
+/*
+ * Modem line discipline, required for making above controls functional.
+ * Activated from userspace with ldattach, possibly invoked from udev rule.
+ */
+
+/* To actually apply any modem controlled configuration changes to the codec,
+ * we must connect codec DAI pins to the modem for a moment.  Be careful not
+ * to interfere with our digital mute function that shares the same hardware. */
+static struct timer_list cx81801_timer;
+static bool cx81801_cmd_pending;
+static bool ams_delta_muted;
+static DEFINE_SPINLOCK(ams_delta_lock);
+static struct gpio_desc *gpiod_modem_codec;
+
+static void cx81801_timeout(struct timer_list *unused)
+{
+       int muted;
+
+       spin_lock(&ams_delta_lock);
+       cx81801_cmd_pending = 0;
+       muted = ams_delta_muted;
+       spin_unlock(&ams_delta_lock);
+
+       /* Reconnect the codec DAI back from the modem to the CPU DAI
+        * only if digital mute still off */
+       if (!muted)
+               gpiod_set_value(gpiod_modem_codec, 0);
+}
+
+/* Line discipline .open() */
+static int cx81801_open(struct tty_struct *tty)
+{
+       int ret;
+
+       if (!cx20442_codec)
+               return -ENODEV;
+
+       /*
+        * Pass the codec structure pointer for use by other ldisc callbacks,
+        * both the card and the codec specific parts.
+        */
+       tty->disc_data = cx20442_codec;
+
+       ret = v253_ops.open(tty);
+
+       if (ret < 0)
+               tty->disc_data = NULL;
+
+       return ret;
+}
+
+/* Line discipline .close() */
+static void cx81801_close(struct tty_struct *tty)
+{
+       struct snd_soc_component *component = tty->disc_data;
+       struct snd_soc_dapm_context *dapm = &component->card->dapm;
+
+       del_timer_sync(&cx81801_timer);
+
+       /* Prevent the hook switch from further changing the DAPM pins */
+       INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
+
+       if (!component)
+               return;
+
+       v253_ops.close(tty);
+
+       /* Revert back to default audio input/output constellation */
+       snd_soc_dapm_mutex_lock(dapm);
+
+       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
+       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+}
+
+/* Line discipline .hangup() */
+static int cx81801_hangup(struct tty_struct *tty)
+{
+       cx81801_close(tty);
+       return 0;
+}
+
+/* Line discipline .receive_buf() */
+static void cx81801_receive(struct tty_struct *tty,
+                               const unsigned char *cp, char *fp, int count)
+{
+       struct snd_soc_component *component = tty->disc_data;
+       const unsigned char *c;
+       int apply, ret;
+
+       if (!component)
+               return;
+
+       if (!component->card->pop_time) {
+               /* First modem response, complete setup procedure */
+
+               /* Initialize timer used for config pulse generation */
+               timer_setup(&cx81801_timer, cx81801_timeout, 0);
+
+               v253_ops.receive_buf(tty, cp, fp, count);
+
+               /* Link hook switch to DAPM pins */
+               ret = snd_soc_jack_add_pins(&ams_delta_hook_switch,
+                                       ARRAY_SIZE(ams_delta_hook_switch_pins),
+                                       ams_delta_hook_switch_pins);
+               if (ret)
+                       dev_warn(component->dev,
+                               "Failed to link hook switch to DAPM pins, "
+                               "will continue with hook switch unlinked.\n");
+
+               return;
+       }
+
+       v253_ops.receive_buf(tty, cp, fp, count);
+
+       for (c = &cp[count - 1]; c >= cp; c--) {
+               if (*c != '\r')
+                       continue;
+               /* Complete modem response received, apply config to codec */
+
+               spin_lock_bh(&ams_delta_lock);
+               mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150));
+               apply = !ams_delta_muted && !cx81801_cmd_pending;
+               cx81801_cmd_pending = 1;
+               spin_unlock_bh(&ams_delta_lock);
+
+               /* Apply config pulse by connecting the codec to the modem
+                * if not already done */
+               if (apply)
+                       gpiod_set_value(gpiod_modem_codec, 1);
+               break;
+       }
+}
+
+/* Line discipline .write_wakeup() */
+static void cx81801_wakeup(struct tty_struct *tty)
+{
+       v253_ops.write_wakeup(tty);
+}
+
+static struct tty_ldisc_ops cx81801_ops = {
+       .magic = TTY_LDISC_MAGIC,
+       .name = "cx81801",
+       .owner = THIS_MODULE,
+       .open = cx81801_open,
+       .close = cx81801_close,
+       .hangup = cx81801_hangup,
+       .receive_buf = cx81801_receive,
+       .write_wakeup = cx81801_wakeup,
+};
+
+
+/*
+ * Even if not very useful, the sound card can still work without any of the
+ * above functonality activated.  You can still control its audio input/output
+ * constellation and speakerphone gain from userspace by issuing AT commands
+ * over the modem port.
+ */
+
+static struct snd_soc_ops ams_delta_ops;
+
+
+/* Digital mute implemented using modem/CPU multiplexer.
+ * Shares hardware with codec config pulse generation */
+static bool ams_delta_muted = 1;
+
+static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       int apply;
+
+       if (ams_delta_muted == mute)
+               return 0;
+
+       spin_lock_bh(&ams_delta_lock);
+       ams_delta_muted = mute;
+       apply = !cx81801_cmd_pending;
+       spin_unlock_bh(&ams_delta_lock);
+
+       if (apply)
+               gpiod_set_value(gpiod_modem_codec, !!mute);
+       return 0;
+}
+
+/* Our codec DAI probably doesn't have its own .ops structure */
+static const struct snd_soc_dai_ops ams_delta_dai_ops = {
+       .digital_mute = ams_delta_digital_mute,
+};
+
+/* Will be used if the codec ever has its own digital_mute function */
+static int ams_delta_startup(struct snd_pcm_substream *substream)
+{
+       return ams_delta_digital_mute(NULL, 0);
+}
+
+static void ams_delta_shutdown(struct snd_pcm_substream *substream)
+{
+       ams_delta_digital_mute(NULL, 1);
+}
+
+
+/*
+ * Card initialization
+ */
+
+static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+       int ret;
+       /* Codec is ready, now add/activate board specific controls */
+
+       /* Store a pointer to the codec structure for tty ldisc use */
+       cx20442_codec = rtd->codec_dai->component;
+
+       /* Add hook switch - can be used to control the codec from userspace
+        * even if line discipline fails */
+       ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET,
+                                   &ams_delta_hook_switch, NULL, 0);
+       if (ret)
+               dev_warn(card->dev,
+                               "Failed to allocate resources for hook switch, "
+                               "will continue without one.\n");
+       else {
+               ret = snd_soc_jack_add_gpiods(card->dev, &ams_delta_hook_switch,
+                                       ARRAY_SIZE(ams_delta_hook_switch_gpios),
+                                       ams_delta_hook_switch_gpios);
+               if (ret)
+                       dev_warn(card->dev,
+                               "Failed to set up hook switch GPIO line, "
+                               "will continue with hook switch inactive.\n");
+       }
+
+       gpiod_modem_codec = devm_gpiod_get(card->dev, "modem_codec",
+                                          GPIOD_OUT_HIGH);
+       if (IS_ERR(gpiod_modem_codec)) {
+               dev_warn(card->dev, "Failed to obtain modem_codec GPIO\n");
+               return 0;
+       }
+
+       /* Set up digital mute if not provided by the codec */
+       if (!codec_dai->driver->ops) {
+               codec_dai->driver->ops = &ams_delta_dai_ops;
+       } else {
+               ams_delta_ops.startup = ams_delta_startup;
+               ams_delta_ops.shutdown = ams_delta_shutdown;
+       }
+
+       /* Register optional line discipline for over the modem control */
+       ret = tty_register_ldisc(N_V253, &cx81801_ops);
+       if (ret) {
+               dev_warn(card->dev,
+                               "Failed to register line discipline, "
+                               "will continue without any controls.\n");
+               return 0;
+       }
+
+       /* Set up initial pin constellation */
+       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+       snd_soc_dapm_disable_pin(dapm, "Speaker");
+       snd_soc_dapm_disable_pin(dapm, "AGCIN");
+       snd_soc_dapm_disable_pin(dapm, "AGCOUT");
+
+       return 0;
+}
+
+/* DAI glue - connects codec <--> CPU */
+static struct snd_soc_dai_link ams_delta_dai_link = {
+       .name = "CX20442",
+       .stream_name = "CX20442",
+       .cpu_dai_name = "omap-mcbsp.1",
+       .codec_dai_name = "cx20442-voice",
+       .init = ams_delta_cx20442_init,
+       .platform_name = "omap-mcbsp.1",
+       .codec_name = "cx20442-codec",
+       .ops = &ams_delta_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
+};
+
+/* Audio card driver */
+static struct snd_soc_card ams_delta_audio_card = {
+       .name = "AMS_DELTA",
+       .owner = THIS_MODULE,
+       .dai_link = &ams_delta_dai_link,
+       .num_links = 1,
+
+       .controls = ams_delta_audio_controls,
+       .num_controls = ARRAY_SIZE(ams_delta_audio_controls),
+       .dapm_widgets = ams_delta_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
+       .dapm_routes = ams_delta_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
+};
+
+/* Module init/exit */
+static int ams_delta_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &ams_delta_audio_card;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               card->dev = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+static int ams_delta_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       if (tty_unregister_ldisc(N_V253) != 0)
+               dev_warn(&pdev->dev,
+                       "failed to unregister V253 line discipline\n");
+
+       snd_soc_unregister_card(card);
+       card->dev = NULL;
+       return 0;
+}
+
+#define DRV_NAME "ams-delta-audio"
+
+static struct platform_driver ams_delta_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = ams_delta_probe,
+       .remove = ams_delta_remove,
+};
+
+module_platform_driver(ams_delta_driver);
+
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
new file mode 100644 (file)
index 0000000..4869d63
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * ASoC driver for TI DAVINCI EVM platform
+ *
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <asm/mach-types.h>
+
+struct snd_soc_card_drvdata_davinci {
+       struct clk *mclk;
+       unsigned sysclk;
+};
+
+static int evm_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *soc_card = rtd->card;
+       struct snd_soc_card_drvdata_davinci *drvdata =
+               snd_soc_card_get_drvdata(soc_card);
+
+       if (drvdata->mclk)
+               return clk_prepare_enable(drvdata->mclk);
+
+       return 0;
+}
+
+static void evm_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *soc_card = rtd->card;
+       struct snd_soc_card_drvdata_davinci *drvdata =
+               snd_soc_card_get_drvdata(soc_card);
+
+       if (drvdata->mclk)
+               clk_disable_unprepare(drvdata->mclk);
+}
+
+static int evm_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_card *soc_card = rtd->card;
+       int ret = 0;
+       unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
+                          snd_soc_card_get_drvdata(soc_card))->sysclk;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       /* set the CPU system clock */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops evm_ops = {
+       .startup = evm_startup,
+       .shutdown = evm_shutdown,
+       .hw_params = evm_hw_params,
+};
+
+/* davinci-evm machine dapm widgets */
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+/* davinci-evm machine audio_mapnections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Headphone connected to HPLOUT, HPROUT */
+       {"Headphone Jack", NULL, "HPLOUT"},
+       {"Headphone Jack", NULL, "HPROUT"},
+
+       /* Line Out connected to LLOUT, RLOUT */
+       {"Line Out", NULL, "LLOUT"},
+       {"Line Out", NULL, "RLOUT"},
+
+       /* Mic connected to (MIC3L | MIC3R) */
+       {"MIC3L", NULL, "Mic Bias"},
+       {"MIC3R", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Mic Jack"},
+
+       /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
+       {"LINE1L", NULL, "Line In"},
+       {"LINE2L", NULL, "Line In"},
+       {"LINE1R", NULL, "Line In"},
+       {"LINE2R", NULL, "Line In"},
+};
+
+/* Logic for a aic3x as connected on a davinci-evm */
+static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct device_node *np = card->dev->of_node;
+       int ret;
+
+       /* Add davinci-evm specific widgets */
+       snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
+                                 ARRAY_SIZE(aic3x_dapm_widgets));
+
+       if (np) {
+               ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+               if (ret)
+                       return ret;
+       } else {
+               /* Set up davinci-evm specific audio path audio_map */
+               snd_soc_dapm_add_routes(&card->dapm, audio_map,
+                                       ARRAY_SIZE(audio_map));
+       }
+
+       /* not connected */
+       snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
+       snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
+
+       return 0;
+}
+
+/* davinci-evm digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link dm6446_evm_dai = {
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name = "davinci-mcbsp",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-001b",
+       .platform_name = "davinci-mcbsp",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+};
+
+static struct snd_soc_dai_link dm355_evm_dai = {
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name = "davinci-mcbsp.1",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-001b",
+       .platform_name = "davinci-mcbsp.1",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+};
+
+static struct snd_soc_dai_link dm365_evm_dai = {
+#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name = "davinci-mcbsp",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-0018",
+       .platform_name = "davinci-mcbsp",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
+       .name = "Voice Codec - CQ93VC",
+       .stream_name = "CQ93",
+       .cpu_dai_name = "davinci-vcif",
+       .codec_dai_name = "cq93vc-hifi",
+       .codec_name = "cq93vc-codec",
+       .platform_name = "davinci-vcif",
+#endif
+};
+
+static struct snd_soc_dai_link dm6467_evm_dai[] = {
+       {
+               .name = "TLV320AIC3X",
+               .stream_name = "AIC3X",
+               .cpu_dai_name= "davinci-mcasp.0",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name = "davinci-mcasp.0",
+               .codec_name = "tlv320aic3x-codec.0-001a",
+               .init = evm_aic3x_init,
+               .ops = &evm_ops,
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                          SND_SOC_DAIFMT_IB_NF,
+       },
+       {
+               .name = "McASP",
+               .stream_name = "spdif",
+               .cpu_dai_name= "davinci-mcasp.1",
+               .codec_dai_name = "dit-hifi",
+               .codec_name = "spdif_dit",
+               .platform_name = "davinci-mcasp.1",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                          SND_SOC_DAIFMT_IB_NF,
+       },
+};
+
+static struct snd_soc_dai_link da830_evm_dai = {
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name = "davinci-mcasp.1",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-0018",
+       .platform_name = "davinci-mcasp.1",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+};
+
+static struct snd_soc_dai_link da850_evm_dai = {
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name= "davinci-mcasp.0",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-0018",
+       .platform_name = "davinci-mcasp.0",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+};
+
+/* davinci dm6446 evm audio machine driver */
+/*
+ * ASP0 in DM6446 EVM is clocked by U55, as configured by
+ * board-dm644x-evm.c using GPIOs from U18.  There are six
+ * options; here we "know" we use a 48 KHz sample rate.
+ */
+static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
+       .sysclk = 12288000,
+};
+
+static struct snd_soc_card dm6446_snd_soc_card_evm = {
+       .name = "DaVinci DM6446 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = &dm6446_evm_dai,
+       .num_links = 1,
+       .drvdata = &dm6446_snd_soc_card_drvdata,
+};
+
+/* davinci dm355 evm audio machine driver */
+/* ASP1 on DM355 EVM is clocked by an external oscillator */
+static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
+static struct snd_soc_card dm355_snd_soc_card_evm = {
+       .name = "DaVinci DM355 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = &dm355_evm_dai,
+       .num_links = 1,
+       .drvdata = &dm355_snd_soc_card_drvdata,
+};
+
+/* davinci dm365 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
+static struct snd_soc_card dm365_snd_soc_card_evm = {
+       .name = "DaVinci DM365 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = &dm365_evm_dai,
+       .num_links = 1,
+       .drvdata = &dm365_snd_soc_card_drvdata,
+};
+
+/* davinci dm6467 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
+static struct snd_soc_card dm6467_snd_soc_card_evm = {
+       .name = "DaVinci DM6467 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = dm6467_evm_dai,
+       .num_links = ARRAY_SIZE(dm6467_evm_dai),
+       .drvdata = &dm6467_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
+       .sysclk = 24576000,
+};
+
+static struct snd_soc_card da830_snd_soc_card = {
+       .name = "DA830/OMAP-L137 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = &da830_evm_dai,
+       .num_links = 1,
+       .drvdata = &da830_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
+       .sysclk = 24576000,
+};
+
+static struct snd_soc_card da850_snd_soc_card = {
+       .name = "DA850/OMAP-L138 EVM",
+       .owner = THIS_MODULE,
+       .dai_link = &da850_evm_dai,
+       .num_links = 1,
+       .drvdata = &da850_snd_soc_card_drvdata,
+};
+
+#if defined(CONFIG_OF)
+
+/*
+ * The struct is used as place holder. It will be completely
+ * filled with data from dt node.
+ */
+static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
+       .name           = "TLV320AIC3X",
+       .stream_name    = "AIC3X",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .ops            = &evm_ops,
+       .init           = evm_aic3x_init,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+                  SND_SOC_DAIFMT_IB_NF,
+};
+
+static const struct of_device_id davinci_evm_dt_ids[] = {
+       {
+               .compatible = "ti,da830-evm-audio",
+               .data = (void *) &evm_dai_tlv320aic3x,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
+
+/* davinci evm audio machine driver */
+static struct snd_soc_card evm_soc_card = {
+       .owner = THIS_MODULE,
+       .num_links = 1,
+};
+
+static int davinci_evm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *match;
+       struct snd_soc_dai_link *dai;
+       struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+       struct clk *mclk;
+       int ret = 0;
+
+       match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
+       }
+
+       dai = (struct snd_soc_dai_link *) match->data;
+
+       evm_soc_card.dai_link = dai;
+
+       dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
+       if (!dai->codec_of_node)
+               return -EINVAL;
+
+       dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
+       if (!dai->cpu_of_node)
+               return -EINVAL;
+
+       dai->platform_of_node = dai->cpu_of_node;
+
+       evm_soc_card.dev = &pdev->dev;
+       ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
+       if (ret)
+               return ret;
+
+       mclk = devm_clk_get(&pdev->dev, "mclk");
+       if (PTR_ERR(mclk) == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (IS_ERR(mclk)) {
+               dev_dbg(&pdev->dev, "mclk not found.\n");
+               mclk = NULL;
+       }
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       drvdata->mclk = mclk;
+
+       ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
+
+       if (ret < 0) {
+               if (!drvdata->mclk) {
+                       dev_err(&pdev->dev,
+                               "No clock or clock rate defined.\n");
+                       return -EINVAL;
+               }
+               drvdata->sysclk = clk_get_rate(drvdata->mclk);
+       } else if (drvdata->mclk) {
+               unsigned int requestd_rate = drvdata->sysclk;
+               clk_set_rate(drvdata->mclk, drvdata->sysclk);
+               drvdata->sysclk = clk_get_rate(drvdata->mclk);
+               if (drvdata->sysclk != requestd_rate)
+                       dev_warn(&pdev->dev,
+                                "Could not get requested rate %u using %u.\n",
+                                requestd_rate, drvdata->sysclk);
+       }
+
+       snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
+       ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
+
+       if (ret)
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+       return ret;
+}
+
+static struct platform_driver davinci_evm_driver = {
+       .probe          = davinci_evm_probe,
+       .driver         = {
+               .name   = "davinci_evm",
+               .pm     = &snd_soc_pm_ops,
+               .of_match_table = of_match_ptr(davinci_evm_dt_ids),
+       },
+};
+#endif
+
+static struct platform_device *evm_snd_device;
+
+static int __init evm_init(void)
+{
+       struct snd_soc_card *evm_snd_dev_data;
+       int index;
+       int ret;
+
+       /*
+        * If dtb is there, the devices will be created dynamically.
+        * Only register platfrom driver structure.
+        */
+#if defined(CONFIG_OF)
+       if (of_have_populated_dt())
+               return platform_driver_register(&davinci_evm_driver);
+#endif
+
+       if (machine_is_davinci_evm()) {
+               evm_snd_dev_data = &dm6446_snd_soc_card_evm;
+               index = 0;
+       } else if (machine_is_davinci_dm355_evm()) {
+               evm_snd_dev_data = &dm355_snd_soc_card_evm;
+               index = 1;
+       } else if (machine_is_davinci_dm365_evm()) {
+               evm_snd_dev_data = &dm365_snd_soc_card_evm;
+               index = 0;
+       } else if (machine_is_davinci_dm6467_evm()) {
+               evm_snd_dev_data = &dm6467_snd_soc_card_evm;
+               index = 0;
+       } else if (machine_is_davinci_da830_evm()) {
+               evm_snd_dev_data = &da830_snd_soc_card;
+               index = 1;
+       } else if (machine_is_davinci_da850_evm()) {
+               evm_snd_dev_data = &da850_snd_soc_card;
+               index = 0;
+       } else
+               return -EINVAL;
+
+       evm_snd_device = platform_device_alloc("soc-audio", index);
+       if (!evm_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
+       ret = platform_device_add(evm_snd_device);
+       if (ret)
+               platform_device_put(evm_snd_device);
+
+       return ret;
+}
+
+static void __exit evm_exit(void)
+{
+#if defined(CONFIG_OF)
+       if (of_have_populated_dt()) {
+               platform_driver_unregister(&davinci_evm_driver);
+               return;
+       }
+#endif
+
+       platform_device_unregister(evm_snd_device);
+}
+
+module_init(evm_init);
+module_exit(evm_exit);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
new file mode 100644 (file)
index 0000000..a3206e6
--- /dev/null
@@ -0,0 +1,782 @@
+/*
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * DT support  (c) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
+ *             based on davinci-mcasp.c DT support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO:
+ * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/platform_data/davinci_asp.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "edma-pcm.h"
+#include "davinci-i2s.h"
+
+#define DRV_NAME "davinci-i2s"
+
+/*
+ * NOTE:  terminology here is confusing.
+ *
+ *  - This driver supports the "Audio Serial Port" (ASP),
+ *    found on dm6446, dm355, and other DaVinci chips.
+ *
+ *  - But it labels it a "Multi-channel Buffered Serial Port"
+ *    (McBSP) as on older chips like the dm642 ... which was
+ *    backward-compatible, possibly explaining that confusion.
+ *
+ *  - OMAP chips have a controller called McBSP, which is
+ *    incompatible with the DaVinci flavor of McBSP.
+ *
+ *  - Newer DaVinci chips have a controller called McASP,
+ *    incompatible with ASP and with either McBSP.
+ *
+ * In short:  this uses ASP to implement I2S, not McBSP.
+ * And it won't be the only DaVinci implemention of I2S.
+ */
+#define DAVINCI_MCBSP_DRR_REG  0x00
+#define DAVINCI_MCBSP_DXR_REG  0x04
+#define DAVINCI_MCBSP_SPCR_REG 0x08
+#define DAVINCI_MCBSP_RCR_REG  0x0c
+#define DAVINCI_MCBSP_XCR_REG  0x10
+#define DAVINCI_MCBSP_SRGR_REG 0x14
+#define DAVINCI_MCBSP_PCR_REG  0x24
+
+#define DAVINCI_MCBSP_SPCR_RRST                (1 << 0)
+#define DAVINCI_MCBSP_SPCR_RINTM(v)    ((v) << 4)
+#define DAVINCI_MCBSP_SPCR_XRST                (1 << 16)
+#define DAVINCI_MCBSP_SPCR_XINTM(v)    ((v) << 20)
+#define DAVINCI_MCBSP_SPCR_GRST                (1 << 22)
+#define DAVINCI_MCBSP_SPCR_FRST                (1 << 23)
+#define DAVINCI_MCBSP_SPCR_FREE                (1 << 25)
+
+#define DAVINCI_MCBSP_RCR_RWDLEN1(v)   ((v) << 5)
+#define DAVINCI_MCBSP_RCR_RFRLEN1(v)   ((v) << 8)
+#define DAVINCI_MCBSP_RCR_RDATDLY(v)   ((v) << 16)
+#define DAVINCI_MCBSP_RCR_RFIG         (1 << 18)
+#define DAVINCI_MCBSP_RCR_RWDLEN2(v)   ((v) << 21)
+#define DAVINCI_MCBSP_RCR_RFRLEN2(v)   ((v) << 24)
+#define DAVINCI_MCBSP_RCR_RPHASE       BIT(31)
+
+#define DAVINCI_MCBSP_XCR_XWDLEN1(v)   ((v) << 5)
+#define DAVINCI_MCBSP_XCR_XFRLEN1(v)   ((v) << 8)
+#define DAVINCI_MCBSP_XCR_XDATDLY(v)   ((v) << 16)
+#define DAVINCI_MCBSP_XCR_XFIG         (1 << 18)
+#define DAVINCI_MCBSP_XCR_XWDLEN2(v)   ((v) << 21)
+#define DAVINCI_MCBSP_XCR_XFRLEN2(v)   ((v) << 24)
+#define DAVINCI_MCBSP_XCR_XPHASE       BIT(31)
+
+#define DAVINCI_MCBSP_SRGR_FWID(v)     ((v) << 8)
+#define DAVINCI_MCBSP_SRGR_FPER(v)     ((v) << 16)
+#define DAVINCI_MCBSP_SRGR_FSGM                (1 << 28)
+#define DAVINCI_MCBSP_SRGR_CLKSM       BIT(29)
+
+#define DAVINCI_MCBSP_PCR_CLKRP                (1 << 0)
+#define DAVINCI_MCBSP_PCR_CLKXP                (1 << 1)
+#define DAVINCI_MCBSP_PCR_FSRP         (1 << 2)
+#define DAVINCI_MCBSP_PCR_FSXP         (1 << 3)
+#define DAVINCI_MCBSP_PCR_SCLKME       (1 << 7)
+#define DAVINCI_MCBSP_PCR_CLKRM                (1 << 8)
+#define DAVINCI_MCBSP_PCR_CLKXM                (1 << 9)
+#define DAVINCI_MCBSP_PCR_FSRM         (1 << 10)
+#define DAVINCI_MCBSP_PCR_FSXM         (1 << 11)
+
+enum {
+       DAVINCI_MCBSP_WORD_8 = 0,
+       DAVINCI_MCBSP_WORD_12,
+       DAVINCI_MCBSP_WORD_16,
+       DAVINCI_MCBSP_WORD_20,
+       DAVINCI_MCBSP_WORD_24,
+       DAVINCI_MCBSP_WORD_32,
+};
+
+static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = 1,
+       [SNDRV_PCM_FORMAT_S16_LE]       = 2,
+       [SNDRV_PCM_FORMAT_S32_LE]       = 4,
+};
+
+static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = DAVINCI_MCBSP_WORD_8,
+       [SNDRV_PCM_FORMAT_S16_LE]       = DAVINCI_MCBSP_WORD_16,
+       [SNDRV_PCM_FORMAT_S32_LE]       = DAVINCI_MCBSP_WORD_32,
+};
+
+static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+       [SNDRV_PCM_FORMAT_S8]           = SNDRV_PCM_FORMAT_S16_LE,
+       [SNDRV_PCM_FORMAT_S16_LE]       = SNDRV_PCM_FORMAT_S32_LE,
+};
+
+struct davinci_mcbsp_dev {
+       struct device *dev;
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
+       void __iomem                    *base;
+#define MOD_DSP_A      0
+#define MOD_DSP_B      1
+       int                             mode;
+       u32                             pcr;
+       struct clk                      *clk;
+       /*
+        * Combining both channels into 1 element will at least double the
+        * amount of time between servicing the dma channel, increase
+        * effiency, and reduce the chance of overrun/underrun. But,
+        * it will result in the left & right channels being swapped.
+        *
+        * If relabeling the left and right channels is not possible,
+        * you may want to let the codec know to swap them back.
+        *
+        * It may allow x10 the amount of time to service dma requests,
+        * if the codec is master and is using an unnecessarily fast bit clock
+        * (ie. tlvaic23b), independent of the sample rate. So, having an
+        * entire frame at once means it can be serviced at the sample rate
+        * instead of the bit clock rate.
+        *
+        * In the now unlikely case that an underrun still
+        * occurs, both the left and right samples will be repeated
+        * so that no pops are heard, and the left and right channels
+        * won't end up being swapped because of the underrun.
+        */
+       unsigned enable_channel_combine:1;
+
+       unsigned int fmt;
+       int clk_div;
+       int clk_input_pin;
+       bool i2s_accurate_sck;
+};
+
+static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
+                                          int reg, u32 val)
+{
+       __raw_writel(val, dev->base + reg);
+}
+
+static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
+{
+       return __raw_readl(dev->base + reg);
+}
+
+static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
+{
+       u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
+       /* The clock needs to toggle to complete reset.
+        * So, fake it by toggling the clk polarity.
+        */
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
+}
+
+static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
+               struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       u32 spcr;
+       u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
+       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+       if (spcr & mask) {
+               /* start off disabled */
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
+                               spcr & ~mask);
+               toggle_clock(dev, playback);
+       }
+       if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM |
+                       DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) {
+               /* Start the sample generator */
+               spcr |= DAVINCI_MCBSP_SPCR_GRST;
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+       }
+
+       if (playback) {
+               /* Stop the DMA to avoid data loss */
+               /* while the transmitter is out of reset to handle XSYNCERR */
+               if (component->driver->ops->trigger) {
+                       int ret = component->driver->ops->trigger(substream,
+                               SNDRV_PCM_TRIGGER_STOP);
+                       if (ret < 0)
+                               printk(KERN_DEBUG "Playback DMA stop failed\n");
+               }
+
+               /* Enable the transmitter */
+               spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+               spcr |= DAVINCI_MCBSP_SPCR_XRST;
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+
+               /* wait for any unexpected frame sync error to occur */
+               udelay(100);
+
+               /* Disable the transmitter to clear any outstanding XSYNCERR */
+               spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+               spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+               toggle_clock(dev, playback);
+
+               /* Restart the DMA */
+               if (component->driver->ops->trigger) {
+                       int ret = component->driver->ops->trigger(substream,
+                               SNDRV_PCM_TRIGGER_START);
+                       if (ret < 0)
+                               printk(KERN_DEBUG "Playback DMA start failed\n");
+               }
+       }
+
+       /* Enable transmitter or receiver */
+       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+       spcr |= mask;
+
+       if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) {
+               /* Start frame sync */
+               spcr |= DAVINCI_MCBSP_SPCR_FRST;
+       }
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+}
+
+static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
+{
+       u32 spcr;
+
+       /* Reset transmitter/receiver and sample rate/frame sync generators */
+       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+       spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
+       spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+       toggle_clock(dev, playback);
+}
+
+#define DEFAULT_BITPERSAMPLE   16
+
+static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+                                  unsigned int fmt)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned int pcr;
+       unsigned int srgr;
+       bool inv_fs = false;
+       /* Attention srgr is updated by hw_params! */
+       srgr = DAVINCI_MCBSP_SRGR_FSGM |
+               DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
+               DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
+
+       dev->fmt = fmt;
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* cpu is master */
+               pcr = DAVINCI_MCBSP_PCR_FSXM |
+                       DAVINCI_MCBSP_PCR_FSRM |
+                       DAVINCI_MCBSP_PCR_CLKXM |
+                       DAVINCI_MCBSP_PCR_CLKRM;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
+               /*
+                * Selection of the clock input pin that is the
+                * input for the Sample Rate Generator.
+                * McBSP FSR and FSX are driven by the Sample Rate
+                * Generator.
+                */
+               switch (dev->clk_input_pin) {
+               case MCBSP_CLKS:
+                       pcr |= DAVINCI_MCBSP_PCR_CLKXM |
+                               DAVINCI_MCBSP_PCR_CLKRM;
+                       break;
+               case MCBSP_CLKR:
+                       pcr |= DAVINCI_MCBSP_PCR_SCLKME;
+                       break;
+               default:
+                       dev_err(dev->dev, "bad clk_input_pin\n");
+                       return -EINVAL;
+               }
+
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* codec is master */
+               pcr = 0;
+               break;
+       default:
+               printk(KERN_ERR "%s:bad master\n", __func__);
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               /* Davinci doesn't support TRUE I2S, but some codecs will have
+                * the left and right channels contiguous. This allows
+                * dsp_a mode to be used with an inverted normal frame clk.
+                * If your codec is master and does not have contiguous
+                * channels, then you will have sound on only one channel.
+                * Try using a different mode, or codec as slave.
+                *
+                * The TLV320AIC33 is an example of a codec where this works.
+                * It has a variable bit clock frequency allowing it to have
+                * valid data on every bit clock.
+                *
+                * The TLV320AIC23 is an example of a codec where this does not
+                * work. It has a fixed bit clock frequency with progressively
+                * more empty bit clock slots between channels as the sample
+                * rate is lowered.
+                */
+               inv_fs = true;
+               /* fall through */
+       case SND_SOC_DAIFMT_DSP_A:
+               dev->mode = MOD_DSP_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               dev->mode = MOD_DSP_B;
+               break;
+       default:
+               printk(KERN_ERR "%s:bad format\n", __func__);
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /* CLKRP Receive clock polarity,
+                *      1 - sampled on rising edge of CLKR
+                *      valid on rising edge
+                * CLKXP Transmit clock polarity,
+                *      1 - clocked on falling edge of CLKX
+                *      valid on rising edge
+                * FSRP  Receive frame sync pol, 0 - active high
+                * FSXP  Transmit frame sync pol, 0 - active high
+                */
+               pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP);
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               /* CLKRP Receive clock polarity,
+                *      0 - sampled on falling edge of CLKR
+                *      valid on falling edge
+                * CLKXP Transmit clock polarity,
+                *      0 - clocked on rising edge of CLKX
+                *      valid on falling edge
+                * FSRP  Receive frame sync pol, 1 - active low
+                * FSXP  Transmit frame sync pol, 1 - active low
+                */
+               pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               /* CLKRP Receive clock polarity,
+                *      1 - sampled on rising edge of CLKR
+                *      valid on rising edge
+                * CLKXP Transmit clock polarity,
+                *      1 - clocked on falling edge of CLKX
+                *      valid on rising edge
+                * FSRP  Receive frame sync pol, 1 - active low
+                * FSXP  Transmit frame sync pol, 1 - active low
+                */
+               pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP |
+                       DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               /* CLKRP Receive clock polarity,
+                *      0 - sampled on falling edge of CLKR
+                *      valid on falling edge
+                * CLKXP Transmit clock polarity,
+                *      0 - clocked on rising edge of CLKX
+                *      valid on falling edge
+                * FSRP  Receive frame sync pol, 0 - active high
+                * FSXP  Transmit frame sync pol, 0 - active high
+                */
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (inv_fs == true)
+               pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+       dev->pcr = pcr;
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
+       return 0;
+}
+
+static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                               int div_id, int div)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (div_id != DAVINCI_MCBSP_CLKGDV)
+               return -ENODEV;
+
+       dev->clk_div = div;
+       return 0;
+}
+
+static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct snd_interval *i = NULL;
+       int mcbsp_word_length, master;
+       unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
+       u32 spcr;
+       snd_pcm_format_t fmt;
+       unsigned element_cnt = 1;
+
+       /* general line settings */
+       spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+       } else {
+               spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+       }
+
+       master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       fmt = params_format(params);
+       mcbsp_word_length = asp_word_length[fmt];
+
+       switch (master) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               freq = clk_get_rate(dev->clk);
+               srgr = DAVINCI_MCBSP_SRGR_FSGM |
+                      DAVINCI_MCBSP_SRGR_CLKSM;
+               srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
+                                               8 - 1);
+               if (dev->i2s_accurate_sck) {
+                       clk_div = 256;
+                       do {
+                               framesize = (freq / (--clk_div)) /
+                               params->rate_num *
+                                       params->rate_den;
+                       } while (((framesize < 33) || (framesize > 4095)) &&
+                                (clk_div));
+                       clk_div--;
+                       srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
+               } else {
+                       /* symmetric waveforms */
+                       clk_div = freq / (mcbsp_word_length * 16) /
+                                 params->rate_num * params->rate_den;
+                       srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
+                                                       16 - 1);
+               }
+               clk_div &= 0xFF;
+               srgr |= clk_div;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               srgr = DAVINCI_MCBSP_SRGR_FSGM;
+               clk_div = dev->clk_div - 1;
+               srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
+               srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
+               clk_div &= 0xFF;
+               srgr |= clk_div;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* Clock and frame sync given from external sources */
+               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+               srgr = DAVINCI_MCBSP_SRGR_FSGM;
+               srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
+               pr_debug("%s - %d  FWID set: re-read srgr = %X\n",
+                       __func__, __LINE__, snd_interval_value(i) - 1);
+
+               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
+               srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
+               break;
+       default:
+               return -EINVAL;
+       }
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+
+       rcr = DAVINCI_MCBSP_RCR_RFIG;
+       xcr = DAVINCI_MCBSP_XCR_XFIG;
+       if (dev->mode == MOD_DSP_B) {
+               rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
+               xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
+       } else {
+               rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
+               xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+       }
+       /* Determine xfer data type */
+       fmt = params_format(params);
+       if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
+               printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
+               return -EINVAL;
+       }
+
+       if (params_channels(params) == 2) {
+               element_cnt = 2;
+               if (double_fmt[fmt] && dev->enable_channel_combine) {
+                       element_cnt = 1;
+                       fmt = double_fmt[fmt];
+               }
+               switch (master) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+               case SND_SOC_DAIFMT_CBS_CFM:
+                       rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
+                       xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
+                       rcr |= DAVINCI_MCBSP_RCR_RPHASE;
+                       xcr |= DAVINCI_MCBSP_XCR_XPHASE;
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+                       rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
+                       xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       mcbsp_word_length = asp_word_length[fmt];
+
+       switch (master) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBS_CFM:
+               rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
+               xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
+               xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
+               DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
+       xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
+               DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
+       else
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+
+       pr_debug("%s - %d  srgr=%X\n", __func__, __LINE__, srgr);
+       pr_debug("%s - %d  xcr=%X\n", __func__, __LINE__, xcr);
+       pr_debug("%s - %d  rcr=%X\n", __func__, __LINE__, rcr);
+       return 0;
+}
+
+static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       davinci_mcbsp_stop(dev, playback);
+       return 0;
+}
+
+static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+       int ret = 0;
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               davinci_mcbsp_start(dev, substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               davinci_mcbsp_stop(dev, playback);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       davinci_mcbsp_stop(dev, playback);
+}
+
+#define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
+
+static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+       .shutdown       = davinci_i2s_shutdown,
+       .prepare        = davinci_i2s_prepare,
+       .trigger        = davinci_i2s_trigger,
+       .hw_params      = davinci_i2s_hw_params,
+       .set_fmt        = davinci_i2s_set_dai_fmt,
+       .set_clkdiv     = davinci_i2s_dai_set_clkdiv,
+
+};
+
+static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver davinci_i2s_dai = {
+       .probe = davinci_i2s_dai_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = DAVINCI_I2S_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = DAVINCI_I2S_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = &davinci_i2s_dai_ops,
+
+};
+
+static const struct snd_soc_component_driver davinci_i2s_component = {
+       .name           = DRV_NAME,
+};
+
+static int davinci_i2s_probe(struct platform_device *pdev)
+{
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       struct davinci_mcbsp_dev *dev;
+       struct resource *mem, *res;
+       void __iomem *io_base;
+       int *dma;
+       int ret;
+
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       if (!mem) {
+               dev_warn(&pdev->dev,
+                        "\"mpu\" mem resource not found, using index 0\n");
+               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!mem) {
+                       dev_err(&pdev->dev, "no mem resource?\n");
+                       return -ENODEV;
+               }
+       }
+
+       io_base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(io_base))
+               return PTR_ERR(io_base);
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
+                          GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->base = io_base;
+
+       /* setup DMA, first TX, then RX */
+       dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (res) {
+               dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
+               *dma = res->start;
+               dma_data->filter_data = dma;
+       } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               dma_data->filter_data = "tx";
+       } else {
+               dev_err(&pdev->dev, "Missing DMA tx resource\n");
+               return -ENODEV;
+       }
+
+       dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+       dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (res) {
+               dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
+               *dma = res->start;
+               dma_data->filter_data = dma;
+       } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               dma_data->filter_data = "rx";
+       } else {
+               dev_err(&pdev->dev, "Missing DMA rx resource\n");
+               return -ENODEV;
+       }
+
+       dev->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dev->clk))
+               return -ENODEV;
+       clk_enable(dev->clk);
+
+       dev->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, dev);
+
+       ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
+                                        &davinci_i2s_dai, 1);
+       if (ret != 0)
+               goto err_release_clk;
+
+       ret = edma_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto err_unregister_component;
+       }
+
+       return 0;
+
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
+err_release_clk:
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       return ret;
+}
+
+static int davinci_i2s_remove(struct platform_device *pdev)
+{
+       struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_component(&pdev->dev);
+
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+       dev->clk = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id davinci_i2s_match[] = {
+       { .compatible = "ti,da850-mcbsp" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, davinci_i2s_match);
+
+static struct platform_driver davinci_mcbsp_driver = {
+       .probe          = davinci_i2s_probe,
+       .remove         = davinci_i2s_remove,
+       .driver         = {
+               .name   = "davinci-mcbsp",
+               .of_match_table = of_match_ptr(davinci_i2s_match),
+       },
+};
+
+module_platform_driver(davinci_mcbsp_driver);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/davinci-i2s.h b/sound/soc/ti/davinci-i2s.h
new file mode 100644 (file)
index 0000000..48dac3e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DAVINCI_I2S_H
+#define _DAVINCI_I2S_H
+
+/* McBSP dividers */
+enum davinci_mcbsp_div {
+       DAVINCI_MCBSP_CLKGDV,              /* Sample rate generator divider */
+};
+
+#endif
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
new file mode 100644 (file)
index 0000000..eeda6d5
--- /dev/null
@@ -0,0 +1,2212 @@
+/*
+ * ALSA SoC McASP Audio Layer for TI DAVINCI processor
+ *
+ * Multi-channel Audio Serial Port Driver
+ *
+ * Author: Nirmal Pandey <n-pandey@ti.com>,
+ *         Suresh Rajashekara <suresh.r@ti.com>
+ *         Steve Chen <schen@.mvista.com>
+ *
+ * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright:   (C) 2009  Texas Instruments, India
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/davinci_asp.h>
+#include <linux/math64.h>
+#include <linux/bitmap.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "edma-pcm.h"
+#include "sdma-pcm.h"
+#include "davinci-mcasp.h"
+
+#define MCASP_MAX_AFIFO_DEPTH  64
+
+static u32 context_regs[] = {
+       DAVINCI_MCASP_TXFMCTL_REG,
+       DAVINCI_MCASP_RXFMCTL_REG,
+       DAVINCI_MCASP_TXFMT_REG,
+       DAVINCI_MCASP_RXFMT_REG,
+       DAVINCI_MCASP_ACLKXCTL_REG,
+       DAVINCI_MCASP_ACLKRCTL_REG,
+       DAVINCI_MCASP_AHCLKXCTL_REG,
+       DAVINCI_MCASP_AHCLKRCTL_REG,
+       DAVINCI_MCASP_PDIR_REG,
+       DAVINCI_MCASP_RXMASK_REG,
+       DAVINCI_MCASP_TXMASK_REG,
+       DAVINCI_MCASP_RXTDM_REG,
+       DAVINCI_MCASP_TXTDM_REG,
+};
+
+struct davinci_mcasp_context {
+       u32     config_regs[ARRAY_SIZE(context_regs)];
+       u32     afifo_regs[2]; /* for read/write fifo control registers */
+       u32     *xrsr_regs; /* for serializer configuration */
+       bool    pm_state;
+};
+
+struct davinci_mcasp_ruledata {
+       struct davinci_mcasp *mcasp;
+       int serializers;
+};
+
+struct davinci_mcasp {
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       void __iomem *base;
+       u32 fifo_base;
+       struct device *dev;
+       struct snd_pcm_substream *substreams[2];
+       unsigned int dai_fmt;
+
+       /* McASP specific data */
+       int     tdm_slots;
+       u32     tdm_mask[2];
+       int     slot_width;
+       u8      op_mode;
+       u8      dismod;
+       u8      num_serializer;
+       u8      *serial_dir;
+       u8      version;
+       u8      bclk_div;
+       int     streams;
+       u32     irq_request[2];
+       int     dma_request[2];
+
+       int     sysclk_freq;
+       bool    bclk_master;
+
+       unsigned long pdir; /* Pin direction bitfield */
+
+       /* McASP FIFO related */
+       u8      txnumevt;
+       u8      rxnumevt;
+
+       bool    dat_port;
+
+       /* Used for comstraint setting on the second stream */
+       u32     channels;
+
+#ifdef CONFIG_PM_SLEEP
+       struct davinci_mcasp_context context;
+#endif
+
+       struct davinci_mcasp_ruledata ruledata[2];
+       struct snd_pcm_hw_constraint_list chconstr[2];
+};
+
+static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val)
+{
+       void __iomem *reg = mcasp->base + offset;
+       __raw_writel(__raw_readl(reg) | val, reg);
+}
+
+static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val)
+{
+       void __iomem *reg = mcasp->base + offset;
+       __raw_writel((__raw_readl(reg) & ~(val)), reg);
+}
+
+static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
+                                 u32 val, u32 mask)
+{
+       void __iomem *reg = mcasp->base + offset;
+       __raw_writel((__raw_readl(reg) & ~mask) | val, reg);
+}
+
+static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
+                                u32 val)
+{
+       __raw_writel(val, mcasp->base + offset);
+}
+
+static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
+{
+       return (u32)__raw_readl(mcasp->base + offset);
+}
+
+static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
+{
+       int i = 0;
+
+       mcasp_set_bits(mcasp, ctl_reg, val);
+
+       /* programming GBLCTL needs to read back from GBLCTL and verfiy */
+       /* loop count is to avoid the lock-up */
+       for (i = 0; i < 1000; i++) {
+               if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
+                       break;
+       }
+
+       if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
+               printk(KERN_ERR "GBLCTL write error\n");
+}
+
+static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
+{
+       u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+       u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+
+       return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
+}
+
+static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+       u32 bit = PIN_BIT_AMUTE;
+
+       for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
+               if (enable)
+                       mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+               else
+                       mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+       }
+}
+
+static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+       u32 bit;
+
+       for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) {
+               if (enable)
+                       mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+               else
+                       mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+       }
+}
+
+static void mcasp_start_rx(struct davinci_mcasp *mcasp)
+{
+       if (mcasp->rxnumevt) {  /* enable FIFO */
+               u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+
+               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+               mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
+       }
+
+       /* Start clocks */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
+       /*
+        * When ASYNC == 0 the transmit and receive sections operate
+        * synchronously from the transmit clock and frame sync. We need to make
+        * sure that the TX signlas are enabled when starting reception.
+        */
+       if (mcasp_is_synchronous(mcasp)) {
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+       }
+
+       /* Activate serializer(s) */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
+       /* Release RX state machine */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+       /* Release Frame Sync generator */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+       if (mcasp_is_synchronous(mcasp))
+               mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+
+       /* enable receive IRQs */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
+                      mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+static void mcasp_start_tx(struct davinci_mcasp *mcasp)
+{
+       u32 cnt;
+
+       if (mcasp->txnumevt) {  /* enable FIFO */
+               u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+
+               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+               mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
+       }
+
+       /* Start clocks */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+       mcasp_set_clk_pdir(mcasp, true);
+
+       /* Activate serializer(s) */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
+
+       /* wait for XDATA to be cleared */
+       cnt = 0;
+       while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
+              (cnt < 100000))
+               cnt++;
+
+       mcasp_set_axr_pdir(mcasp, true);
+
+       /* Release TX state machine */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+       /* Release Frame Sync generator */
+       mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+
+       /* enable transmit IRQs */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
+                      mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
+}
+
+static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
+{
+       mcasp->streams++;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               mcasp_start_tx(mcasp);
+       else
+               mcasp_start_rx(mcasp);
+}
+
+static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
+{
+       /* disable IRQ sources */
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
+                      mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
+
+       /*
+        * In synchronous mode stop the TX clocks if no other stream is
+        * running
+        */
+       if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
+               mcasp_set_clk_pdir(mcasp, false);
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
+       }
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+
+       if (mcasp->rxnumevt) {  /* disable FIFO */
+               u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+
+               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+       }
+}
+
+static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
+{
+       u32 val = 0;
+
+       /* disable IRQ sources */
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
+                      mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
+
+       /*
+        * In synchronous mode keep TX clocks running if the capture stream is
+        * still running.
+        */
+       if (mcasp_is_synchronous(mcasp) && mcasp->streams)
+               val =  TXHCLKRST | TXCLKRST | TXFSRST;
+       else
+               mcasp_set_clk_pdir(mcasp, false);
+
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+
+       if (mcasp->txnumevt) {  /* disable FIFO */
+               u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+
+               mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+       }
+
+       mcasp_set_axr_pdir(mcasp, false);
+}
+
+static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
+{
+       mcasp->streams--;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               mcasp_stop_tx(mcasp);
+       else
+               mcasp_stop_rx(mcasp);
+}
+
+static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
+{
+       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+       struct snd_pcm_substream *substream;
+       u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
+       u32 handled_mask = 0;
+       u32 stat;
+
+       stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
+       if (stat & XUNDRN & irq_mask) {
+               dev_warn(mcasp->dev, "Transmit buffer underflow\n");
+               handled_mask |= XUNDRN;
+
+               substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
+               if (substream)
+                       snd_pcm_stop_xrun(substream);
+       }
+
+       if (!handled_mask)
+               dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
+                        stat);
+
+       if (stat & XRERR)
+               handled_mask |= XRERR;
+
+       /* Ack the handled event only */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
+
+       return IRQ_RETVAL(handled_mask);
+}
+
+static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
+{
+       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+       struct snd_pcm_substream *substream;
+       u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
+       u32 handled_mask = 0;
+       u32 stat;
+
+       stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
+       if (stat & ROVRN & irq_mask) {
+               dev_warn(mcasp->dev, "Receive buffer overflow\n");
+               handled_mask |= ROVRN;
+
+               substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
+               if (substream)
+                       snd_pcm_stop_xrun(substream);
+       }
+
+       if (!handled_mask)
+               dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
+                        stat);
+
+       if (stat & XRERR)
+               handled_mask |= XRERR;
+
+       /* Ack the handled event only */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
+
+       return IRQ_RETVAL(handled_mask);
+}
+
+static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
+{
+       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
+               ret = davinci_mcasp_tx_irq_handler(irq, data);
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
+               ret |= davinci_mcasp_rx_irq_handler(irq, data);
+
+       return ret;
+}
+
+static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+                                        unsigned int fmt)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
+       u32 data_delay;
+       bool fs_pol_rising;
+       bool inv_fs = false;
+
+       if (!fmt)
+               return 0;
+
+       pm_runtime_get_sync(mcasp->dev);
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* 1st data bit occur one ACLK cycle after the frame sync */
+               data_delay = 1;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+       case SND_SOC_DAIFMT_AC97:
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* No delay after FS */
+               data_delay = 0;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               /* configure a full-word SYNC pulse (LRCLK) */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* 1st data bit occur one ACLK cycle after the frame sync */
+               data_delay = 1;
+               /* FS need to be inverted */
+               inv_fs = true;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* configure a full-word SYNC pulse (LRCLK) */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+               /* No delay after FS */
+               data_delay = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
+                      FSXDLY(3));
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
+                      FSRDLY(3));
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* codec is clock and frame slave */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               /* BCLK */
+               set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+               set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+               /* Frame Sync */
+               set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+               set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
+               mcasp->bclk_master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /* codec is clock slave and frame master */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               /* BCLK */
+               set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+               set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+               /* Frame Sync */
+               clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+               clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
+               mcasp->bclk_master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               /* codec is clock master and frame slave */
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               /* BCLK */
+               clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+               clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+               /* Frame Sync */
+               set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+               set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
+               mcasp->bclk_master = 0;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* codec is clock and frame master */
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               /* BCLK */
+               clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+               clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+               /* Frame Sync */
+               clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+               clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
+               mcasp->bclk_master = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_NF:
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               fs_pol_rising = true;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               fs_pol_rising = false;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               fs_pol_rising = false;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               fs_pol_rising = true;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (inv_fs)
+               fs_pol_rising = !fs_pol_rising;
+
+       if (fs_pol_rising) {
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+       } else {
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+       }
+
+       mcasp->dai_fmt = fmt;
+out:
+       pm_runtime_put(mcasp->dev);
+       return ret;
+}
+
+static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
+                                     int div, bool explicit)
+{
+       pm_runtime_get_sync(mcasp->dev);
+       switch (div_id) {
+       case MCASP_CLKDIV_AUXCLK:                       /* MCLK divider */
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
+                              AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
+                              AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
+               break;
+
+       case MCASP_CLKDIV_BCLK:                 /* BCLK divider */
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
+                              ACLKXDIV(div - 1), ACLKXDIV_MASK);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
+                              ACLKRDIV(div - 1), ACLKRDIV_MASK);
+               if (explicit)
+                       mcasp->bclk_div = div;
+               break;
+
+       case MCASP_CLKDIV_BCLK_FS_RATIO:
+               /*
+                * BCLK/LRCLK ratio descries how many bit-clock cycles
+                * fit into one frame. The clock ratio is given for a
+                * full period of data (for I2S format both left and
+                * right channels), so it has to be divided by number
+                * of tdm-slots (for I2S - divided by 2).
+                * Instead of storing this ratio, we calculate a new
+                * tdm_slot width by dividing the the ratio by the
+                * number of configured tdm slots.
+                */
+               mcasp->slot_width = div / mcasp->tdm_slots;
+               if (div % mcasp->tdm_slots)
+                       dev_warn(mcasp->dev,
+                                "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
+                                __func__, div, mcasp->tdm_slots);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       pm_runtime_put(mcasp->dev);
+       return 0;
+}
+
+static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+                                   int div)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
+}
+
+static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                   unsigned int freq, int dir)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_get_sync(mcasp->dev);
+       if (dir == SND_SOC_CLOCK_OUT) {
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+               set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
+       } else {
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+               clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
+       }
+
+       mcasp->sysclk_freq = freq;
+
+       pm_runtime_put(mcasp->dev);
+       return 0;
+}
+
+/* All serializers must have equal number of channels */
+static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
+                                      int serializers)
+{
+       struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
+       unsigned int *list = (unsigned int *) cl->list;
+       int slots = mcasp->tdm_slots;
+       int i, count = 0;
+
+       if (mcasp->tdm_mask[stream])
+               slots = hweight32(mcasp->tdm_mask[stream]);
+
+       for (i = 1; i <= slots; i++)
+               list[count++] = i;
+
+       for (i = 2; i <= serializers; i++)
+               list[count++] = i*slots;
+
+       cl->count = count;
+
+       return 0;
+}
+
+static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
+{
+       int rx_serializers = 0, tx_serializers = 0, ret, i;
+
+       for (i = 0; i < mcasp->num_serializer; i++)
+               if (mcasp->serial_dir[i] == TX_MODE)
+                       tx_serializers++;
+               else if (mcasp->serial_dir[i] == RX_MODE)
+                       rx_serializers++;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
+                                         tx_serializers);
+       if (ret)
+               return ret;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
+                                         rx_serializers);
+
+       return ret;
+}
+
+
+static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
+                                     unsigned int tx_mask,
+                                     unsigned int rx_mask,
+                                     int slots, int slot_width)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       dev_dbg(mcasp->dev,
+                "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
+                __func__, tx_mask, rx_mask, slots, slot_width);
+
+       if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
+               dev_err(mcasp->dev,
+                       "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
+                       tx_mask, rx_mask, slots);
+               return -EINVAL;
+       }
+
+       if (slot_width &&
+           (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
+               dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
+                       __func__, slot_width);
+               return -EINVAL;
+       }
+
+       mcasp->tdm_slots = slots;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
+       mcasp->slot_width = slot_width;
+
+       return davinci_mcasp_set_ch_constraints(mcasp);
+}
+
+static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
+                                      int sample_width)
+{
+       u32 fmt;
+       u32 tx_rotate = (sample_width / 4) & 0x7;
+       u32 mask = (1ULL << sample_width) - 1;
+       u32 slot_width = sample_width;
+
+       /*
+        * For captured data we should not rotate, inversion and masking is
+        * enoguh to get the data to the right position:
+        * Format         data from bus         after reverse (XRBUF)
+        * S16_LE:      |LSB|MSB|xxx|xxx|       |xxx|xxx|MSB|LSB|
+        * S24_3LE:     |LSB|DAT|MSB|xxx|       |xxx|MSB|DAT|LSB|
+        * S24_LE:      |LSB|DAT|MSB|xxx|       |xxx|MSB|DAT|LSB|
+        * S32_LE:      |LSB|DAT|DAT|MSB|       |MSB|DAT|DAT|LSB|
+        */
+       u32 rx_rotate = 0;
+
+       /*
+        * Setting the tdm slot width either with set_clkdiv() or
+        * set_tdm_slot() allows us to for example send 32 bits per
+        * channel to the codec, while only 16 of them carry audio
+        * payload.
+        */
+       if (mcasp->slot_width) {
+               /*
+                * When we have more bclk then it is needed for the
+                * data, we need to use the rotation to move the
+                * received samples to have correct alignment.
+                */
+               slot_width = mcasp->slot_width;
+               rx_rotate = (slot_width - sample_width) / 4;
+       }
+
+       /* mapping of the XSSZ bit-field as described in the datasheet */
+       fmt = (slot_width >> 1) - 1;
+
+       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
+                              RXSSZ(0x0F));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
+                              TXSSZ(0x0F));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+                              TXROT(7));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
+                              RXROT(7));
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
+       }
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
+
+       return 0;
+}
+
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
+                                int period_words, int channels)
+{
+       struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
+       int i;
+       u8 tx_ser = 0;
+       u8 rx_ser = 0;
+       u8 slots = mcasp->tdm_slots;
+       u8 max_active_serializers = (channels + slots - 1) / slots;
+       int active_serializers, numevt;
+       u32 reg;
+       /* Default configuration */
+       if (mcasp->version < MCASP_VERSION_3)
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
+
+       /* All PINS as McASP */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+       } else {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
+       }
+
+       for (i = 0; i < mcasp->num_serializer; i++) {
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                              mcasp->serial_dir[i]);
+               if (mcasp->serial_dir[i] == TX_MODE &&
+                                       tx_ser < max_active_serializers) {
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                                      mcasp->dismod, DISMOD_MASK);
+                       set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+                       tx_ser++;
+               } else if (mcasp->serial_dir[i] == RX_MODE &&
+                                       rx_ser < max_active_serializers) {
+                       clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+                       rx_ser++;
+               } else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                                      SRMOD_INACTIVE, SRMOD_MASK);
+                       clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+               } else if (mcasp->serial_dir[i] == TX_MODE) {
+                       /* Unused TX pins, clear PDIR  */
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                                      mcasp->dismod, DISMOD_MASK);
+                       clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+               }
+       }
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               active_serializers = tx_ser;
+               numevt = mcasp->txnumevt;
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+       } else {
+               active_serializers = rx_ser;
+               numevt = mcasp->rxnumevt;
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+       }
+
+       if (active_serializers < max_active_serializers) {
+               dev_warn(mcasp->dev, "stream has more channels (%d) than are "
+                        "enabled in mcasp (%d)\n", channels,
+                        active_serializers * slots);
+               return -EINVAL;
+       }
+
+       /* AFIFO is not in use */
+       if (!numevt) {
+               /* Configure the burst size for platform drivers */
+               if (active_serializers > 1) {
+                       /*
+                        * If more than one serializers are in use we have one
+                        * DMA request to provide data for all serializers.
+                        * For example if three serializers are enabled the DMA
+                        * need to transfer three words per DMA request.
+                        */
+                       dma_data->maxburst = active_serializers;
+               } else {
+                       dma_data->maxburst = 0;
+               }
+               return 0;
+       }
+
+       if (period_words % active_serializers) {
+               dev_err(mcasp->dev, "Invalid combination of period words and "
+                       "active serializers: %d, %d\n", period_words,
+                       active_serializers);
+               return -EINVAL;
+       }
+
+       /*
+        * Calculate the optimal AFIFO depth for platform side:
+        * The number of words for numevt need to be in steps of active
+        * serializers.
+        */
+       numevt = (numevt / active_serializers) * active_serializers;
+
+       while (period_words % numevt && numevt > 0)
+               numevt -= active_serializers;
+       if (numevt <= 0)
+               numevt = active_serializers;
+
+       mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
+       mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
+
+       /* Configure the burst size for platform drivers */
+       if (numevt == 1)
+               numevt = 0;
+       dma_data->maxburst = numevt;
+
+       return 0;
+}
+
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
+                             int channels)
+{
+       int i, active_slots;
+       int total_slots;
+       int active_serializers;
+       u32 mask = 0;
+       u32 busel = 0;
+
+       total_slots = mcasp->tdm_slots;
+
+       /*
+        * If more than one serializer is needed, then use them with
+        * all the specified tdm_slots. Otherwise, one serializer can
+        * cope with the transaction using just as many slots as there
+        * are channels in the stream.
+        */
+       if (mcasp->tdm_mask[stream]) {
+               active_slots = hweight32(mcasp->tdm_mask[stream]);
+               active_serializers = (channels + active_slots - 1) /
+                       active_slots;
+               if (active_serializers == 1) {
+                       active_slots = channels;
+                       for (i = 0; i < total_slots; i++) {
+                               if ((1 << i) & mcasp->tdm_mask[stream]) {
+                                       mask |= (1 << i);
+                                       if (--active_slots <= 0)
+                                               break;
+                               }
+                       }
+               }
+       } else {
+               active_serializers = (channels + total_slots - 1) / total_slots;
+               if (active_serializers == 1)
+                       active_slots = channels;
+               else
+                       active_slots = total_slots;
+
+               for (i = 0; i < active_slots; i++)
+                       mask |= (1 << i);
+       }
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+
+       if (!mcasp->dat_port)
+               busel = TXSEL;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                              FSXMOD(total_slots), FSXMOD(0x1FF));
+       } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+                              FSRMOD(total_slots), FSRMOD(0x1FF));
+               /*
+                * If McASP is set to be TX/RX synchronous and the playback is
+                * not running already we need to configure the TX slots in
+                * order to have correct FSX on the bus
+                */
+               if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
+                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                                      FSXMOD(total_slots), FSXMOD(0x1FF));
+       }
+
+       return 0;
+}
+
+/* S/PDIF */
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
+                             unsigned int rate)
+{
+       u32 cs_value = 0;
+       u8 *cs_bytes = (u8*) &cs_value;
+
+       /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
+          and LSB first */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
+
+       /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
+
+       /* Set the TX tdm : for all the slots */
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
+
+       /* Set the TX clock controls : div = 1 and internal */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
+
+       mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+
+       /* Only 44100 and 48000 are valid, both have the same setting */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
+
+       /* Enable the DIT */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+       /* Set S/PDIF channel status bits */
+       cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
+       cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
+
+       switch (rate) {
+       case 22050:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
+               break;
+       case 24000:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
+               break;
+       case 32000:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
+               break;
+       case 44100:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
+               break;
+       case 88200:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
+               break;
+       case 96000:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
+               break;
+       case 176400:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
+               break;
+       case 192000:
+               cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
+               break;
+       default:
+               printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
+               return -EINVAL;
+       }
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
+
+       return 0;
+}
+
+static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
+                                     unsigned int bclk_freq, bool set)
+{
+       int error_ppm;
+       unsigned int sysclk_freq = mcasp->sysclk_freq;
+       u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
+       int div = sysclk_freq / bclk_freq;
+       int rem = sysclk_freq % bclk_freq;
+       int aux_div = 1;
+
+       if (div > (ACLKXDIV_MASK + 1)) {
+               if (reg & AHCLKXE) {
+                       aux_div = div / (ACLKXDIV_MASK + 1);
+                       if (div % (ACLKXDIV_MASK + 1))
+                               aux_div++;
+
+                       sysclk_freq /= aux_div;
+                       div = sysclk_freq / bclk_freq;
+                       rem = sysclk_freq % bclk_freq;
+               } else if (set) {
+                       dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
+                                sysclk_freq);
+               }
+       }
+
+       if (rem != 0) {
+               if (div == 0 ||
+                   ((sysclk_freq / div) - bclk_freq) >
+                   (bclk_freq - (sysclk_freq / (div+1)))) {
+                       div++;
+                       rem = rem - bclk_freq;
+               }
+       }
+       error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
+                    (int)bclk_freq)) / div - 1000000;
+
+       if (set) {
+               if (error_ppm)
+                       dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
+                                error_ppm);
+
+               __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
+               if (reg & AHCLKXE)
+                       __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
+                                                  aux_div, 0);
+       }
+
+       return error_ppm;
+}
+
+static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
+{
+       if (!mcasp->txnumevt)
+               return 0;
+
+       return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
+}
+
+static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
+{
+       if (!mcasp->rxnumevt)
+               return 0;
+
+       return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
+}
+
+static snd_pcm_sframes_t davinci_mcasp_delay(
+                       struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *cpu_dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 fifo_use;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               fifo_use = davinci_mcasp_tx_delay(mcasp);
+       else
+               fifo_use = davinci_mcasp_rx_delay(mcasp);
+
+       /*
+        * Divide the used locations with the channel count to get the
+        * FIFO usage in samples (don't care about partial samples in the
+        * buffer).
+        */
+       return fifo_use / substream->runtime->channels;
+}
+
+static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       int word_length;
+       int channels = params_channels(params);
+       int period_size = params_period_size(params);
+       int ret;
+
+       ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt);
+       if (ret)
+               return ret;
+
+       /*
+        * If mcasp is BCLK master, and a BCLK divider was not provided by
+        * the machine driver, we need to calculate the ratio.
+        */
+       if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
+               int slots = mcasp->tdm_slots;
+               int rate = params_rate(params);
+               int sbits = params_width(params);
+
+               if (mcasp->slot_width)
+                       sbits = mcasp->slot_width;
+
+               davinci_mcasp_calc_clk_div(mcasp, rate * sbits * slots, true);
+       }
+
+       ret = mcasp_common_hw_param(mcasp, substream->stream,
+                                   period_size * channels, channels);
+       if (ret)
+               return ret;
+
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               ret = mcasp_dit_hw_param(mcasp, params_rate(params));
+       else
+               ret = mcasp_i2s_hw_param(mcasp, substream->stream,
+                                        channels);
+
+       if (ret)
+               return ret;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_U8:
+       case SNDRV_PCM_FORMAT_S8:
+               word_length = 8;
+               break;
+
+       case SNDRV_PCM_FORMAT_U16_LE:
+       case SNDRV_PCM_FORMAT_S16_LE:
+               word_length = 16;
+               break;
+
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               word_length = 24;
+               break;
+
+       case SNDRV_PCM_FORMAT_U24_LE:
+       case SNDRV_PCM_FORMAT_S24_LE:
+               word_length = 24;
+               break;
+
+       case SNDRV_PCM_FORMAT_U32_LE:
+       case SNDRV_PCM_FORMAT_S32_LE:
+               word_length = 32;
+               break;
+
+       default:
+               printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
+               return -EINVAL;
+       }
+
+       davinci_config_channel_size(mcasp, word_length);
+
+       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+               mcasp->channels = channels;
+
+       return 0;
+}
+
+static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
+                                    int cmd, struct snd_soc_dai *cpu_dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               davinci_mcasp_start(mcasp, substream->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               davinci_mcasp_stop(mcasp, substream->stream);
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const unsigned int davinci_mcasp_dai_rates[] = {
+       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+       88200, 96000, 176400, 192000,
+};
+
+#define DAVINCI_MAX_RATE_ERROR_PPM 1000
+
+static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                     struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_interval *ri =
+               hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       int sbits = params_width(params);
+       int slots = rd->mcasp->tdm_slots;
+       struct snd_interval range;
+       int i;
+
+       if (rd->mcasp->slot_width)
+               sbits = rd->mcasp->slot_width;
+
+       snd_interval_any(&range);
+       range.empty = 1;
+
+       for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
+               if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
+                       uint bclk_freq = sbits*slots*
+                               davinci_mcasp_dai_rates[i];
+                       int ppm;
+
+                       ppm = davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq,
+                                                        false);
+                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
+                               if (range.empty) {
+                                       range.min = davinci_mcasp_dai_rates[i];
+                                       range.empty = 0;
+                               }
+                               range.max = davinci_mcasp_dai_rates[i];
+                       }
+               }
+       }
+
+       dev_dbg(rd->mcasp->dev,
+               "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
+               ri->min, ri->max, range.min, range.max, sbits, slots);
+
+       return snd_interval_refine(hw_param_interval(params, rule->var),
+                                  &range);
+}
+
+static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
+                                       struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask nfmt;
+       int rate = params_rate(params);
+       int slots = rd->mcasp->tdm_slots;
+       int i, count = 0;
+
+       snd_mask_none(&nfmt);
+
+       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+               if (snd_mask_test(fmt, i)) {
+                       uint sbits = snd_pcm_format_width(i);
+                       int ppm;
+
+                       if (rd->mcasp->slot_width)
+                               sbits = rd->mcasp->slot_width;
+
+                       ppm = davinci_mcasp_calc_clk_div(rd->mcasp,
+                                                        sbits * slots * rate,
+                                                        false);
+                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
+                               snd_mask_set(&nfmt, i);
+                               count++;
+                       }
+               }
+       }
+       dev_dbg(rd->mcasp->dev,
+               "%d possible sample format for %d Hz and %d tdm slots\n",
+               count, rate, slots);
+
+       return snd_mask_refine(fmt, &nfmt);
+}
+
+static int davinci_mcasp_hw_rule_min_periodsize(
+               struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *period_size = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+       struct snd_interval frames;
+
+       snd_interval_any(&frames);
+       frames.min = 64;
+       frames.integer = 1;
+
+       return snd_interval_refine(period_size, &frames);
+}
+
+static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct davinci_mcasp_ruledata *ruledata =
+                                       &mcasp->ruledata[substream->stream];
+       u32 max_channels = 0;
+       int i, dir;
+       int tdm_slots = mcasp->tdm_slots;
+
+       /* Do not allow more then one stream per direction */
+       if (mcasp->substreams[substream->stream])
+               return -EBUSY;
+
+       mcasp->substreams[substream->stream] = substream;
+
+       if (mcasp->tdm_mask[substream->stream])
+               tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
+
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               return 0;
+
+       /*
+        * Limit the maximum allowed channels for the first stream:
+        * number of serializers for the direction * tdm slots per serializer
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir = TX_MODE;
+       else
+               dir = RX_MODE;
+
+       for (i = 0; i < mcasp->num_serializer; i++) {
+               if (mcasp->serial_dir[i] == dir)
+                       max_channels++;
+       }
+       ruledata->serializers = max_channels;
+       max_channels *= tdm_slots;
+       /*
+        * If the already active stream has less channels than the calculated
+        * limnit based on the seirializers * tdm_slots, we need to use that as
+        * a constraint for the second stream.
+        * Otherwise (first stream or less allowed channels) we use the
+        * calculated constraint.
+        */
+       if (mcasp->channels && mcasp->channels < max_channels)
+               max_channels = mcasp->channels;
+       /*
+        * But we can always allow channels upto the amount of
+        * the available tdm_slots.
+        */
+       if (max_channels < tdm_slots)
+               max_channels = tdm_slots;
+
+       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                    SNDRV_PCM_HW_PARAM_CHANNELS,
+                                    0, max_channels);
+
+       snd_pcm_hw_constraint_list(substream->runtime,
+                                  0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &mcasp->chconstr[substream->stream]);
+
+       if (mcasp->slot_width)
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                            8, mcasp->slot_width);
+
+       /*
+        * If we rely on implicit BCLK divider setting we should
+        * set constraints based on what we can provide.
+        */
+       if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
+               int ret;
+
+               ruledata->mcasp = mcasp;
+
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         davinci_mcasp_hw_rule_rate,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
+               if (ret)
+                       return ret;
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         davinci_mcasp_hw_rule_format,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_RATE, -1);
+               if (ret)
+                       return ret;
+       }
+
+       snd_pcm_hw_rule_add(substream->runtime, 0,
+                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                           davinci_mcasp_hw_rule_min_periodsize, NULL,
+                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+
+       return 0;
+}
+
+static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *cpu_dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       mcasp->substreams[substream->stream] = NULL;
+
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               return;
+
+       if (!cpu_dai->active)
+               mcasp->channels = 0;
+}
+
+static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+       .startup        = davinci_mcasp_startup,
+       .shutdown       = davinci_mcasp_shutdown,
+       .trigger        = davinci_mcasp_trigger,
+       .delay          = davinci_mcasp_delay,
+       .hw_params      = davinci_mcasp_hw_params,
+       .set_fmt        = davinci_mcasp_set_dai_fmt,
+       .set_clkdiv     = davinci_mcasp_set_clkdiv,
+       .set_sysclk     = davinci_mcasp_set_sysclk,
+       .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
+};
+
+static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+       u32 reg;
+       int i;
+
+       context->pm_state = pm_runtime_active(mcasp->dev);
+       if (!context->pm_state)
+               pm_runtime_get_sync(mcasp->dev);
+
+       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+               context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+       if (mcasp->txnumevt) {
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+               context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+       }
+       if (mcasp->rxnumevt) {
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+               context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+       }
+
+       for (i = 0; i < mcasp->num_serializer; i++)
+               context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+                                               DAVINCI_MCASP_XRSRCTL_REG(i));
+
+       pm_runtime_put_sync(mcasp->dev);
+
+       return 0;
+}
+
+static int davinci_mcasp_resume(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+       u32 reg;
+       int i;
+
+       pm_runtime_get_sync(mcasp->dev);
+
+       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+               mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+       if (mcasp->txnumevt) {
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+               mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+       }
+       if (mcasp->rxnumevt) {
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+               mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+       }
+
+       for (i = 0; i < mcasp->num_serializer; i++)
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                             context->xrsr_regs[i]);
+
+       if (!context->pm_state)
+               pm_runtime_put_sync(mcasp->dev);
+
+       return 0;
+}
+#else
+#define davinci_mcasp_suspend NULL
+#define davinci_mcasp_resume NULL
+#endif
+
+#define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
+
+#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
+                               SNDRV_PCM_FMTBIT_U8 | \
+                               SNDRV_PCM_FMTBIT_S16_LE | \
+                               SNDRV_PCM_FMTBIT_U16_LE | \
+                               SNDRV_PCM_FMTBIT_S24_LE | \
+                               SNDRV_PCM_FMTBIT_U24_LE | \
+                               SNDRV_PCM_FMTBIT_S24_3LE | \
+                               SNDRV_PCM_FMTBIT_U24_3LE | \
+                               SNDRV_PCM_FMTBIT_S32_LE | \
+                               SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
+       {
+               .name           = "davinci-mcasp.0",
+               .probe          = davinci_mcasp_dai_probe,
+               .suspend        = davinci_mcasp_suspend,
+               .resume         = davinci_mcasp_resume,
+               .playback       = {
+                       .channels_min   = 1,
+                       .channels_max   = 32 * 16,
+                       .rates          = DAVINCI_MCASP_RATES,
+                       .formats        = DAVINCI_MCASP_PCM_FMTS,
+               },
+               .capture        = {
+                       .channels_min   = 1,
+                       .channels_max   = 32 * 16,
+                       .rates          = DAVINCI_MCASP_RATES,
+                       .formats        = DAVINCI_MCASP_PCM_FMTS,
+               },
+               .ops            = &davinci_mcasp_dai_ops,
+
+               .symmetric_samplebits   = 1,
+               .symmetric_rates        = 1,
+       },
+       {
+               .name           = "davinci-mcasp.1",
+               .probe          = davinci_mcasp_dai_probe,
+               .playback       = {
+                       .channels_min   = 1,
+                       .channels_max   = 384,
+                       .rates          = DAVINCI_MCASP_RATES,
+                       .formats        = DAVINCI_MCASP_PCM_FMTS,
+               },
+               .ops            = &davinci_mcasp_dai_ops,
+       },
+
+};
+
+static const struct snd_soc_component_driver davinci_mcasp_component = {
+       .name           = "davinci-mcasp",
+};
+
+/* Some HW specific values and defaults. The rest is filled in from DT. */
+static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
+       .tx_dma_offset = 0x400,
+       .rx_dma_offset = 0x400,
+       .version = MCASP_VERSION_1,
+};
+
+static struct davinci_mcasp_pdata da830_mcasp_pdata = {
+       .tx_dma_offset = 0x2000,
+       .rx_dma_offset = 0x2000,
+       .version = MCASP_VERSION_2,
+};
+
+static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
+       .tx_dma_offset = 0,
+       .rx_dma_offset = 0,
+       .version = MCASP_VERSION_3,
+};
+
+static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
+       /* The CFG port offset will be calculated if it is needed */
+       .tx_dma_offset = 0,
+       .rx_dma_offset = 0,
+       .version = MCASP_VERSION_4,
+};
+
+static const struct of_device_id mcasp_dt_ids[] = {
+       {
+               .compatible = "ti,dm646x-mcasp-audio",
+               .data = &dm646x_mcasp_pdata,
+       },
+       {
+               .compatible = "ti,da830-mcasp-audio",
+               .data = &da830_mcasp_pdata,
+       },
+       {
+               .compatible = "ti,am33xx-mcasp-audio",
+               .data = &am33xx_mcasp_pdata,
+       },
+       {
+               .compatible = "ti,dra7-mcasp-audio",
+               .data = &dra7_mcasp_pdata,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
+
+static int mcasp_reparent_fck(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct clk *gfclk, *parent_clk;
+       const char *parent_name;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       parent_name = of_get_property(node, "fck_parent", NULL);
+       if (!parent_name)
+               return 0;
+
+       dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
+
+       gfclk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(gfclk)) {
+               dev_err(&pdev->dev, "failed to get fck\n");
+               return PTR_ERR(gfclk);
+       }
+
+       parent_clk = clk_get(NULL, parent_name);
+       if (IS_ERR(parent_clk)) {
+               dev_err(&pdev->dev, "failed to get parent clock\n");
+               ret = PTR_ERR(parent_clk);
+               goto err1;
+       }
+
+       ret = clk_set_parent(gfclk, parent_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to reparent fck\n");
+               goto err2;
+       }
+
+err2:
+       clk_put(parent_clk);
+err1:
+       clk_put(gfclk);
+       return ret;
+}
+
+static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
+                                               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct davinci_mcasp_pdata *pdata = NULL;
+       const struct of_device_id *match =
+                       of_match_device(mcasp_dt_ids, &pdev->dev);
+       struct of_phandle_args dma_spec;
+
+       const u32 *of_serial_dir32;
+       u32 val;
+       int i, ret = 0;
+
+       if (pdev->dev.platform_data) {
+               pdata = pdev->dev.platform_data;
+               pdata->dismod = DISMOD_LOW;
+               return pdata;
+       } else if (match) {
+               pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
+                                    GFP_KERNEL);
+               if (!pdata) {
+                       ret = -ENOMEM;
+                       return pdata;
+               }
+       } else {
+               /* control shouldn't reach here. something is wrong */
+               ret = -EINVAL;
+               goto nodata;
+       }
+
+       ret = of_property_read_u32(np, "op-mode", &val);
+       if (ret >= 0)
+               pdata->op_mode = val;
+
+       ret = of_property_read_u32(np, "tdm-slots", &val);
+       if (ret >= 0) {
+               if (val < 2 || val > 32) {
+                       dev_err(&pdev->dev,
+                               "tdm-slots must be in rage [2-32]\n");
+                       ret = -EINVAL;
+                       goto nodata;
+               }
+
+               pdata->tdm_slots = val;
+       }
+
+       of_serial_dir32 = of_get_property(np, "serial-dir", &val);
+       val /= sizeof(u32);
+       if (of_serial_dir32) {
+               u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
+                                                (sizeof(*of_serial_dir) * val),
+                                                GFP_KERNEL);
+               if (!of_serial_dir) {
+                       ret = -ENOMEM;
+                       goto nodata;
+               }
+
+               for (i = 0; i < val; i++)
+                       of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
+
+               pdata->num_serializer = val;
+               pdata->serial_dir = of_serial_dir;
+       }
+
+       ret = of_property_match_string(np, "dma-names", "tx");
+       if (ret < 0)
+               goto nodata;
+
+       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                        &dma_spec);
+       if (ret < 0)
+               goto nodata;
+
+       pdata->tx_dma_channel = dma_spec.args[0];
+
+       /* RX is not valid in DIT mode */
+       if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               ret = of_property_match_string(np, "dma-names", "rx");
+               if (ret < 0)
+                       goto nodata;
+
+               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                                &dma_spec);
+               if (ret < 0)
+                       goto nodata;
+
+               pdata->rx_dma_channel = dma_spec.args[0];
+       }
+
+       ret = of_property_read_u32(np, "tx-num-evt", &val);
+       if (ret >= 0)
+               pdata->txnumevt = val;
+
+       ret = of_property_read_u32(np, "rx-num-evt", &val);
+       if (ret >= 0)
+               pdata->rxnumevt = val;
+
+       ret = of_property_read_u32(np, "sram-size-playback", &val);
+       if (ret >= 0)
+               pdata->sram_size_playback = val;
+
+       ret = of_property_read_u32(np, "sram-size-capture", &val);
+       if (ret >= 0)
+               pdata->sram_size_capture = val;
+
+       ret = of_property_read_u32(np, "dismod", &val);
+       if (ret >= 0) {
+               if (val == 0 || val == 2 || val == 3) {
+                       pdata->dismod = DISMOD_VAL(val);
+               } else {
+                       dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
+                       pdata->dismod = DISMOD_LOW;
+               }
+       } else {
+               pdata->dismod = DISMOD_LOW;
+       }
+
+       return  pdata;
+
+nodata:
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error populating platform data, err %d\n",
+                       ret);
+               pdata = NULL;
+       }
+       return  pdata;
+}
+
+enum {
+       PCM_EDMA,
+       PCM_SDMA,
+};
+static const char *sdma_prefix = "ti,omap";
+
+static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
+{
+       struct dma_chan *chan;
+       const char *tmp;
+       int ret = PCM_EDMA;
+
+       if (!mcasp->dev->of_node)
+               return PCM_EDMA;
+
+       tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
+       chan = dma_request_slave_channel_reason(mcasp->dev, tmp);
+       if (IS_ERR(chan)) {
+               if (PTR_ERR(chan) != -EPROBE_DEFER)
+                       dev_err(mcasp->dev,
+                               "Can't verify DMA configuration (%ld)\n",
+                               PTR_ERR(chan));
+               return PTR_ERR(chan);
+       }
+       if (WARN_ON(!chan->device || !chan->device->dev))
+               return -EINVAL;
+
+       if (chan->device->dev->of_node)
+               ret = of_property_read_string(chan->device->dev->of_node,
+                                             "compatible", &tmp);
+       else
+               dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
+
+       dma_release_channel(chan);
+       if (ret)
+               return ret;
+
+       dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
+       if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
+               return PCM_SDMA;
+
+       return PCM_EDMA;
+}
+
+static u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata)
+{
+       int i;
+       u32 offset = 0;
+
+       if (pdata->version != MCASP_VERSION_4)
+               return pdata->tx_dma_offset;
+
+       for (i = 0; i < pdata->num_serializer; i++) {
+               if (pdata->serial_dir[i] == TX_MODE) {
+                       if (!offset) {
+                               offset = DAVINCI_MCASP_TXBUF_REG(i);
+                       } else {
+                               pr_err("%s: Only one serializer allowed!\n",
+                                      __func__);
+                               break;
+                       }
+               }
+       }
+
+       return offset;
+}
+
+static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
+{
+       int i;
+       u32 offset = 0;
+
+       if (pdata->version != MCASP_VERSION_4)
+               return pdata->rx_dma_offset;
+
+       for (i = 0; i < pdata->num_serializer; i++) {
+               if (pdata->serial_dir[i] == RX_MODE) {
+                       if (!offset) {
+                               offset = DAVINCI_MCASP_RXBUF_REG(i);
+                       } else {
+                               pr_err("%s: Only one serializer allowed!\n",
+                                      __func__);
+                               break;
+                       }
+               }
+       }
+
+       return offset;
+}
+
+static int davinci_mcasp_probe(struct platform_device *pdev)
+{
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       struct resource *mem, *res, *dat;
+       struct davinci_mcasp_pdata *pdata;
+       struct davinci_mcasp *mcasp;
+       char *irq_name;
+       int *dma;
+       int irq;
+       int ret;
+
+       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
+       mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
+                          GFP_KERNEL);
+       if (!mcasp)
+               return  -ENOMEM;
+
+       pdata = davinci_mcasp_set_pdata_from_of(pdev);
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       if (!mem) {
+               dev_warn(mcasp->dev,
+                        "\"mpu\" mem resource not found, using index 0\n");
+               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!mem) {
+                       dev_err(&pdev->dev, "no mem resource?\n");
+                       return -ENODEV;
+               }
+       }
+
+       mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(mcasp->base))
+               return PTR_ERR(mcasp->base);
+
+       pm_runtime_enable(&pdev->dev);
+
+       mcasp->op_mode = pdata->op_mode;
+       /* sanity check for tdm slots parameter */
+       if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
+               if (pdata->tdm_slots < 2) {
+                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
+                               pdata->tdm_slots);
+                       mcasp->tdm_slots = 2;
+               } else if (pdata->tdm_slots > 32) {
+                       dev_err(&pdev->dev, "invalid tdm slots: %d\n",
+                               pdata->tdm_slots);
+                       mcasp->tdm_slots = 32;
+               } else {
+                       mcasp->tdm_slots = pdata->tdm_slots;
+               }
+       }
+
+       mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM_SLEEP
+       mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
+                                       mcasp->num_serializer, sizeof(u32),
+                                       GFP_KERNEL);
+       if (!mcasp->context.xrsr_regs) {
+               ret = -ENOMEM;
+               goto err;
+       }
+#endif
+       mcasp->serial_dir = pdata->serial_dir;
+       mcasp->version = pdata->version;
+       mcasp->txnumevt = pdata->txnumevt;
+       mcasp->rxnumevt = pdata->rxnumevt;
+       mcasp->dismod = pdata->dismod;
+
+       mcasp->dev = &pdev->dev;
+
+       irq = platform_get_irq_byname(pdev, "common");
+       if (irq >= 0) {
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
+                                         dev_name(&pdev->dev));
+               if (!irq_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               davinci_mcasp_common_irq_handler,
+                                               IRQF_ONESHOT | IRQF_SHARED,
+                                               irq_name, mcasp);
+               if (ret) {
+                       dev_err(&pdev->dev, "common IRQ request failed\n");
+                       goto err;
+               }
+
+               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
+               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
+       }
+
+       irq = platform_get_irq_byname(pdev, "rx");
+       if (irq >= 0) {
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
+                                         dev_name(&pdev->dev));
+               if (!irq_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               davinci_mcasp_rx_irq_handler,
+                                               IRQF_ONESHOT, irq_name, mcasp);
+               if (ret) {
+                       dev_err(&pdev->dev, "RX IRQ request failed\n");
+                       goto err;
+               }
+
+               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
+       }
+
+       irq = platform_get_irq_byname(pdev, "tx");
+       if (irq >= 0) {
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
+                                         dev_name(&pdev->dev));
+               if (!irq_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               davinci_mcasp_tx_irq_handler,
+                                               IRQF_ONESHOT, irq_name, mcasp);
+               if (ret) {
+                       dev_err(&pdev->dev, "TX IRQ request failed\n");
+                       goto err;
+               }
+
+               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
+       }
+
+       dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+       if (dat)
+               mcasp->dat_port = true;
+
+       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       if (dat)
+               dma_data->addr = dat->start;
+       else
+               dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata);
+
+       dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (res)
+               *dma = res->start;
+       else
+               *dma = pdata->tx_dma_channel;
+
+       /* dmaengine filter data for DT and non-DT boot */
+       if (pdev->dev.of_node)
+               dma_data->filter_data = "tx";
+       else
+               dma_data->filter_data = dma;
+
+       /* RX is not valid in DIT mode */
+       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+               if (dat)
+                       dma_data->addr = dat->start;
+               else
+                       dma_data->addr =
+                               mem->start + davinci_mcasp_rxdma_offset(pdata);
+
+               dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res)
+                       *dma = res->start;
+               else
+                       *dma = pdata->rx_dma_channel;
+
+               /* dmaengine filter data for DT and non-DT boot */
+               if (pdev->dev.of_node)
+                       dma_data->filter_data = "rx";
+               else
+                       dma_data->filter_data = dma;
+       }
+
+       if (mcasp->version < MCASP_VERSION_3) {
+               mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
+               /* dma_params->dma_addr is pointing to the data port address */
+               mcasp->dat_port = true;
+       } else {
+               mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
+       }
+
+       /* Allocate memory for long enough list for all possible
+        * scenarios. Maximum number tdm slots is 32 and there cannot
+        * be more serializers than given in the configuration.  The
+        * serializer directions could be taken into account, but it
+        * would make code much more complex and save only couple of
+        * bytes.
+        */
+       mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
+               devm_kcalloc(mcasp->dev,
+                            32 + mcasp->num_serializer - 1,
+                            sizeof(unsigned int),
+                            GFP_KERNEL);
+
+       mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
+               devm_kcalloc(mcasp->dev,
+                            32 + mcasp->num_serializer - 1,
+                            sizeof(unsigned int),
+                            GFP_KERNEL);
+
+       if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
+           !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = davinci_mcasp_set_ch_constraints(mcasp);
+       if (ret)
+               goto err;
+
+       dev_set_drvdata(&pdev->dev, mcasp);
+
+       mcasp_reparent_fck(pdev);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                       &davinci_mcasp_component,
+                                       &davinci_mcasp_dai[pdata->op_mode], 1);
+
+       if (ret != 0)
+               goto err;
+
+       ret = davinci_mcasp_get_dma_type(mcasp);
+       switch (ret) {
+       case PCM_EDMA:
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \
+       (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+        IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM))
+               ret = edma_pcm_platform_register(&pdev->dev);
+#else
+               dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
+               ret = -EINVAL;
+               goto err;
+#endif
+               break;
+       case PCM_SDMA:
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \
+       (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+        IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM))
+               ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+#else
+               dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
+               ret = -EINVAL;
+               goto err;
+#endif
+               break;
+       default:
+               dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
+       case -EPROBE_DEFER:
+               goto err;
+               break;
+       }
+
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       pm_runtime_disable(&pdev->dev);
+       return ret;
+}
+
+static int davinci_mcasp_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver davinci_mcasp_driver = {
+       .probe          = davinci_mcasp_probe,
+       .remove         = davinci_mcasp_remove,
+       .driver         = {
+               .name   = "davinci-mcasp",
+               .of_match_table = mcasp_dt_ids,
+       },
+};
+
+module_platform_driver(davinci_mcasp_driver);
+
+MODULE_AUTHOR("Steve Chen");
+MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/davinci-mcasp.h b/sound/soc/ti/davinci-mcasp.h
new file mode 100644 (file)
index 0000000..5e4060d
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * ALSA SoC McASP Audio Layer for TI DAVINCI processor
+ *
+ * MCASP related definitions
+ *
+ * Author: Nirmal Pandey <n-pandey@ti.com>,
+ *         Suresh Rajashekara <suresh.r@ti.com>
+ *         Steve Chen <schen@.mvista.com>
+ *
+ * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright:   (C) 2009  Texas Instruments, India
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DAVINCI_MCASP_H
+#define DAVINCI_MCASP_H
+
+/*
+ * McASP register definitions
+ */
+#define DAVINCI_MCASP_PID_REG          0x00
+#define DAVINCI_MCASP_PWREMUMGT_REG    0x04
+
+#define DAVINCI_MCASP_PFUNC_REG                0x10
+#define DAVINCI_MCASP_PDIR_REG         0x14
+#define DAVINCI_MCASP_PDOUT_REG                0x18
+#define DAVINCI_MCASP_PDSET_REG                0x1c
+
+#define DAVINCI_MCASP_PDCLR_REG                0x20
+
+#define DAVINCI_MCASP_TLGC_REG         0x30
+#define DAVINCI_MCASP_TLMR_REG         0x34
+
+#define DAVINCI_MCASP_GBLCTL_REG       0x44
+#define DAVINCI_MCASP_AMUTE_REG                0x48
+#define DAVINCI_MCASP_LBCTL_REG                0x4c
+
+#define DAVINCI_MCASP_TXDITCTL_REG     0x50
+
+#define DAVINCI_MCASP_GBLCTLR_REG      0x60
+#define DAVINCI_MCASP_RXMASK_REG       0x64
+#define DAVINCI_MCASP_RXFMT_REG                0x68
+#define DAVINCI_MCASP_RXFMCTL_REG      0x6c
+
+#define DAVINCI_MCASP_ACLKRCTL_REG     0x70
+#define DAVINCI_MCASP_AHCLKRCTL_REG    0x74
+#define DAVINCI_MCASP_RXTDM_REG                0x78
+#define DAVINCI_MCASP_EVTCTLR_REG      0x7c
+
+#define DAVINCI_MCASP_RXSTAT_REG       0x80
+#define DAVINCI_MCASP_RXTDMSLOT_REG    0x84
+#define DAVINCI_MCASP_RXCLKCHK_REG     0x88
+#define DAVINCI_MCASP_REVTCTL_REG      0x8c
+
+#define DAVINCI_MCASP_GBLCTLX_REG      0xa0
+#define DAVINCI_MCASP_TXMASK_REG       0xa4
+#define DAVINCI_MCASP_TXFMT_REG                0xa8
+#define DAVINCI_MCASP_TXFMCTL_REG      0xac
+
+#define DAVINCI_MCASP_ACLKXCTL_REG     0xb0
+#define DAVINCI_MCASP_AHCLKXCTL_REG    0xb4
+#define DAVINCI_MCASP_TXTDM_REG                0xb8
+#define DAVINCI_MCASP_EVTCTLX_REG      0xbc
+
+#define DAVINCI_MCASP_TXSTAT_REG       0xc0
+#define DAVINCI_MCASP_TXTDMSLOT_REG    0xc4
+#define DAVINCI_MCASP_TXCLKCHK_REG     0xc8
+#define DAVINCI_MCASP_XEVTCTL_REG      0xcc
+
+/* Left(even TDM Slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRA_REG      0x100
+/* Right(odd TDM slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRB_REG      0x118
+/* Left(even TDM slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRA_REG      0x130
+/* Right(odd TDM Slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRB_REG      0x148
+
+/* Serializer n Control Register */
+#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
+#define DAVINCI_MCASP_XRSRCTL_REG(n)   (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
+                                               (n << 2))
+
+/* Transmit Buffer for Serializer n */
+#define DAVINCI_MCASP_TXBUF_REG(n)     (0x200 + (n << 2))
+/* Receive Buffer for Serializer n */
+#define DAVINCI_MCASP_RXBUF_REG(n)     (0x280 + (n << 2))
+
+/* McASP FIFO Registers */
+#define DAVINCI_MCASP_V2_AFIFO_BASE    (0x1010)
+#define DAVINCI_MCASP_V3_AFIFO_BASE    (0x1000)
+
+/* FIFO register offsets from AFIFO base */
+#define MCASP_WFIFOCTL_OFFSET          (0x0)
+#define MCASP_WFIFOSTS_OFFSET          (0x4)
+#define MCASP_RFIFOCTL_OFFSET          (0x8)
+#define MCASP_RFIFOSTS_OFFSET          (0xc)
+
+/*
+ * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
+ *     Register Bits
+ */
+#define MCASP_FREE     BIT(0)
+#define MCASP_SOFT     BIT(1)
+
+/*
+ * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
+ * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ * DAVINCI_MCASP_PDOUT_REG - Pin output in GPIO mode
+ * DAVINCI_MCASP_PDSET_REG - Pin input in GPIO mode
+ */
+#define PIN_BIT_AXR(n) (n)
+#define PIN_BIT_AMUTE  25
+#define PIN_BIT_ACLKX  26
+#define PIN_BIT_AHCLKX 27
+#define PIN_BIT_AFSX   28
+#define PIN_BIT_ACLKR  29
+#define PIN_BIT_AHCLKR 30
+#define PIN_BIT_AFSR   31
+
+/*
+ * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
+ */
+#define DITEN  BIT(0)  /* Transmit DIT mode enable/disable */
+#define VA     BIT(2)
+#define VB     BIT(3)
+
+/*
+ * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
+ */
+#define TXROT(val)     (val)
+#define TXSEL          BIT(3)
+#define TXSSZ(val)     (val<<4)
+#define TXPBIT(val)    (val<<8)
+#define TXPAD(val)     (val<<13)
+#define TXORD          BIT(15)
+#define FSXDLY(val)    (val<<16)
+
+/*
+ * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
+ */
+#define RXROT(val)     (val)
+#define RXSEL          BIT(3)
+#define RXSSZ(val)     (val<<4)
+#define RXPBIT(val)    (val<<8)
+#define RXPAD(val)     (val<<13)
+#define RXORD          BIT(15)
+#define FSRDLY(val)    (val<<16)
+
+/*
+ * DAVINCI_MCASP_TXFMCTL_REG -  Transmit Frame Control Register Bits
+ */
+#define FSXPOL         BIT(0)
+#define AFSXE          BIT(1)
+#define FSXDUR         BIT(4)
+#define FSXMOD(val)    (val<<7)
+
+/*
+ * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
+ */
+#define FSRPOL         BIT(0)
+#define AFSRE          BIT(1)
+#define FSRDUR         BIT(4)
+#define FSRMOD(val)    (val<<7)
+
+/*
+ * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
+ */
+#define ACLKXDIV(val)  (val)
+#define ACLKXE         BIT(5)
+#define TX_ASYNC       BIT(6)
+#define ACLKXPOL       BIT(7)
+#define ACLKXDIV_MASK  0x1f
+
+/*
+ * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
+ */
+#define ACLKRDIV(val)  (val)
+#define ACLKRE         BIT(5)
+#define RX_ASYNC       BIT(6)
+#define ACLKRPOL       BIT(7)
+#define ACLKRDIV_MASK  0x1f
+
+/*
+ * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
+ *     Register Bits
+ */
+#define AHCLKXDIV(val) (val)
+#define AHCLKXPOL      BIT(14)
+#define AHCLKXE                BIT(15)
+#define AHCLKXDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
+ *     Register Bits
+ */
+#define AHCLKRDIV(val) (val)
+#define AHCLKRPOL      BIT(14)
+#define AHCLKRE                BIT(15)
+#define AHCLKRDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_XRSRCTL_BASE_REG -  Serializer Control Register Bits
+ */
+#define MODE(val)      (val)
+#define DISMOD_3STATE  (0x0)
+#define DISMOD_LOW     (0x2 << 2)
+#define DISMOD_HIGH    (0x3 << 2)
+#define DISMOD_VAL(x)  ((x) << 2)
+#define DISMOD_MASK    DISMOD_HIGH
+#define TXSTATE                BIT(4)
+#define RXSTATE                BIT(5)
+#define SRMOD_MASK     3
+#define SRMOD_INACTIVE 0
+
+/*
+ * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
+ */
+#define LBEN           BIT(0)
+#define LBORD          BIT(1)
+#define LBGENMODE(val) (val<<2)
+
+/*
+ * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
+ */
+#define TXTDMS(n)      (1<<n)
+
+/*
+ * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
+ */
+#define RXTDMS(n)      (1<<n)
+
+/*
+ * DAVINCI_MCASP_GBLCTL_REG -  Global Control Register Bits
+ */
+#define RXCLKRST       BIT(0)  /* Receiver Clock Divider Reset */
+#define RXHCLKRST      BIT(1)  /* Receiver High Frequency Clock Divider */
+#define RXSERCLR       BIT(2)  /* Receiver Serializer Clear */
+#define RXSMRST                BIT(3)  /* Receiver State Machine Reset */
+#define RXFSRST                BIT(4)  /* Frame Sync Generator Reset */
+#define TXCLKRST       BIT(8)  /* Transmitter Clock Divider Reset */
+#define TXHCLKRST      BIT(9)  /* Transmitter High Frequency Clock Divider*/
+#define TXSERCLR       BIT(10) /* Transmit Serializer Clear */
+#define TXSMRST                BIT(11) /* Transmitter State Machine Reset */
+#define TXFSRST                BIT(12) /* Frame Sync Generator Reset */
+
+/*
+ * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits
+ * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits
+ */
+#define XRERR          BIT(8) /* Transmit/Receive error */
+#define XRDATA         BIT(5) /* Transmit/Receive data ready */
+
+/*
+ * DAVINCI_MCASP_AMUTE_REG -  Mute Control Register Bits
+ */
+#define MUTENA(val)    (val)
+#define MUTEINPOL      BIT(2)
+#define MUTEINENA      BIT(3)
+#define MUTEIN         BIT(4)
+#define MUTER          BIT(5)
+#define MUTEX          BIT(6)
+#define MUTEFSR                BIT(7)
+#define MUTEFSX                BIT(8)
+#define MUTEBADCLKR    BIT(9)
+#define MUTEBADCLKX    BIT(10)
+#define MUTERXDMAERR   BIT(11)
+#define MUTETXDMAERR   BIT(12)
+
+/*
+ * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
+ */
+#define RXDATADMADIS   BIT(0)
+
+/*
+ * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
+ */
+#define TXDATADMADIS   BIT(0)
+
+/*
+ * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits
+ */
+#define ROVRN          BIT(0)
+
+/*
+ * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits
+ */
+#define XUNDRN         BIT(0)
+
+/*
+ * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
+ */
+#define FIFO_ENABLE    BIT(16)
+#define NUMEVT_MASK    (0xFF << 8)
+#define NUMEVT(x)      (((x) & 0xFF) << 8)
+#define NUMDMA_MASK    (0xFF)
+
+/* clock divider IDs */
+#define MCASP_CLKDIV_AUXCLK            0 /* HCLK divider from AUXCLK */
+#define MCASP_CLKDIV_BCLK              1 /* BCLK divider from HCLK */
+#define MCASP_CLKDIV_BCLK_FS_RATIO     2 /* to set BCLK FS ration */
+
+#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/ti/davinci-vcif.c b/sound/soc/ti/davinci-vcif.c
new file mode 100644 (file)
index 0000000..5415b72
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * ALSA SoC Voice Codec Interface for TI DAVINCI processor
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mfd/davinci_voicecodec.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "edma-pcm.h"
+#include "davinci-i2s.h"
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) { \
+               val |= mask; \
+       } else { \
+               val &= ~mask; \
+       } \
+} while (0)
+
+struct davinci_vcif_dev {
+       struct davinci_vc *davinci_vc;
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
+};
+
+static void davinci_vcif_start(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct davinci_vcif_dev *davinci_vcif_dev =
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
+       u32 w;
+
+       /* Start the sample generator and enable transmitter/receiver */
+       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
+       else
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
+
+       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
+}
+
+static void davinci_vcif_stop(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct davinci_vcif_dev *davinci_vcif_dev =
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
+       u32 w;
+
+       /* Reset transmitter/receiver and sample rate/frame sync generators */
+       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
+       else
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
+
+       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
+}
+
+static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
+       struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
+       u32 w;
+
+       /* Restart the codec before setup */
+       davinci_vcif_stop(substream);
+       davinci_vcif_start(substream);
+
+       /* General line settings */
+       writel(DAVINCI_VC_CTRL_MASK, davinci_vc->base + DAVINCI_VC_CTRL);
+
+       writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTCLR);
+
+       writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTEN);
+
+       w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
+
+       /* Determine xfer data type */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_U8:
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
+                           DAVINCI_VC_CTRL_RD_UNSIGNED |
+                           DAVINCI_VC_CTRL_WD_BITS_8 |
+                           DAVINCI_VC_CTRL_WD_UNSIGNED, 1);
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
+                           DAVINCI_VC_CTRL_WD_BITS_8, 1);
+
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_UNSIGNED |
+                           DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
+                           DAVINCI_VC_CTRL_RD_UNSIGNED |
+                           DAVINCI_VC_CTRL_WD_BITS_8 |
+                           DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
+               break;
+       default:
+               printk(KERN_WARNING "davinci-vcif: unsupported PCM format");
+               return -EINVAL;
+       }
+
+       writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
+
+       return 0;
+}
+
+static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               davinci_vcif_start(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               davinci_vcif_stop(substream);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+#define DAVINCI_VCIF_RATES     SNDRV_PCM_RATE_8000_48000
+
+static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
+       .trigger        = davinci_vcif_trigger,
+       .hw_params      = davinci_vcif_hw_params,
+};
+
+static int davinci_vcif_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver davinci_vcif_dai = {
+       .probe = davinci_vcif_dai_probe,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = DAVINCI_VCIF_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = DAVINCI_VCIF_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = &davinci_vcif_dai_ops,
+
+};
+
+static const struct snd_soc_component_driver davinci_vcif_component = {
+       .name           = "davinci-vcif",
+};
+
+static int davinci_vcif_probe(struct platform_device *pdev)
+{
+       struct davinci_vc *davinci_vc = pdev->dev.platform_data;
+       struct davinci_vcif_dev *davinci_vcif_dev;
+       int ret;
+
+       davinci_vcif_dev = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct davinci_vcif_dev),
+                                       GFP_KERNEL);
+       if (!davinci_vcif_dev)
+               return -ENOMEM;
+
+       /* DMA tx params */
+       davinci_vcif_dev->davinci_vc = davinci_vc;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data =
+                               &davinci_vc->davinci_vcif.dma_tx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+                               davinci_vc->davinci_vcif.dma_tx_addr;
+
+       /* DMA rx params */
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data =
+                               &davinci_vc->davinci_vcif.dma_rx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+                               davinci_vc->davinci_vcif.dma_rx_addr;
+
+       dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &davinci_vcif_component,
+                                             &davinci_vcif_dai, 1);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "could not register dai\n");
+               return ret;
+       }
+
+       ret = edma_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver davinci_vcif_driver = {
+       .probe          = davinci_vcif_probe,
+       .driver         = {
+               .name   = "davinci-vcif",
+       },
+};
+
+module_platform_driver(davinci_vcif_driver);
+
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/edma-pcm.c b/sound/soc/ti/edma-pcm.c
new file mode 100644 (file)
index 0000000..59e588a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/edma.h>
+
+#include "edma-pcm.h"
+
+static const struct snd_pcm_hardware edma_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+                                 SNDRV_PCM_INFO_INTERLEAVED,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 64 * 1024,
+       .periods_min            = 2,
+       .periods_max            = 19, /* Limit by edma dmaengine driver */
+};
+
+static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
+       .pcm_hardware = &edma_pcm_hardware,
+       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+       .compat_filter_fn = edma_filter_fn,
+       .prealloc_buffer_size = 128 * 1024,
+};
+
+int edma_pcm_platform_register(struct device *dev)
+{
+       return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
+                                       SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/edma-pcm.h b/sound/soc/ti/edma-pcm.h
new file mode 100644 (file)
index 0000000..8058bdb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __EDMA_PCM_H__
+#define __EDMA_PCM_H__
+
+#if IS_ENABLED(CONFIG_SND_SOC_TI_EDMA_PCM)
+int edma_pcm_platform_register(struct device *dev);
+#else
+static inline int edma_pcm_platform_register(struct device *dev)
+{
+       return 0;
+}
+#endif /* CONFIG_SND_SOC_TI_EDMA_PCM */
+
+#endif /* __EDMA_PCM_H__ */
diff --git a/sound/soc/ti/n810.c b/sound/soc/ti/n810.c
new file mode 100644 (file)
index 0000000..9cfefe4
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * n810.c  --  SoC audio for Nokia N810
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "omap-mcbsp.h"
+
+#define N810_HEADSET_AMP_GPIO  10
+#define N810_SPEAKER_AMP_GPIO  101
+
+enum {
+       N810_JACK_DISABLED,
+       N810_JACK_HP,
+       N810_JACK_HS,
+       N810_JACK_MIC,
+};
+
+static struct clk *sys_clkout2;
+static struct clk *sys_clkout2_src;
+static struct clk *func96m_clk;
+
+static int n810_spk_func;
+static int n810_jack_func;
+static int n810_dmic_func;
+
+static void n810_ext_control(struct snd_soc_dapm_context *dapm)
+{
+       int hp = 0, line1l = 0;
+
+       switch (n810_jack_func) {
+       case N810_JACK_HS:
+               line1l = 1;
+       case N810_JACK_HP:
+               hp = 1;
+               break;
+       case N810_JACK_MIC:
+               line1l = 1;
+               break;
+       }
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       if (n810_spk_func)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
+
+       if (hp)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+       if (line1l)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
+
+       if (n810_dmic_func)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int n810_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
+       n810_ext_control(&rtd->card->dapm);
+       return clk_prepare_enable(sys_clkout2);
+}
+
+static void n810_shutdown(struct snd_pcm_substream *substream)
+{
+       clk_disable_unprepare(sys_clkout2);
+}
+
+static int n810_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int err;
+
+       /* Set the codec system clock for DAC and ADC */
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
+                                           SND_SOC_CLOCK_IN);
+
+       return err;
+}
+
+static const struct snd_soc_ops n810_ops = {
+       .startup = n810_startup,
+       .hw_params = n810_hw_params,
+       .shutdown = n810_shutdown,
+};
+
+static int n810_get_spk(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = n810_spk_func;
+
+       return 0;
+}
+
+static int n810_set_spk(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+       if (n810_spk_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       n810_spk_func = ucontrol->value.enumerated.item[0];
+       n810_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static int n810_get_jack(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = n810_jack_func;
+
+       return 0;
+}
+
+static int n810_set_jack(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+       if (n810_jack_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       n810_jack_func = ucontrol->value.enumerated.item[0];
+       n810_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static int n810_get_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = n810_dmic_func;
+
+       return 0;
+}
+
+static int n810_set_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+       if (n810_dmic_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       n810_dmic_func = ucontrol->value.enumerated.item[0];
+       n810_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static int n810_spk_event(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *k, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
+       else
+               gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
+
+       return 0;
+}
+
+static int n810_jack_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *k, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
+       else
+               gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
+       SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
+       SND_SOC_DAPM_MIC("DMic", NULL),
+       SND_SOC_DAPM_MIC("HS Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "HPLOUT"},
+       {"Headphone Jack", NULL, "HPROUT"},
+
+       {"Ext Spk", NULL, "LLOUT"},
+       {"Ext Spk", NULL, "RLOUT"},
+
+       {"DMic Rate 64", NULL, "DMic"},
+       {"DMic", NULL, "Mic Bias"},
+
+       /*
+        * Note that the mic bias is coming from Retu/Vilma and we don't have
+        * control over it atm. The analog HS mic is not working. <- TODO
+        */
+       {"LINE1L", NULL, "HS Mic"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
+static const char *input_function[] = {"ADC", "Digital Mic"};
+static const struct soc_enum n810_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
+};
+
+static const struct snd_kcontrol_new aic33_n810_controls[] = {
+       SOC_ENUM_EXT("Speaker Function", n810_enum[0],
+                    n810_get_spk, n810_set_spk),
+       SOC_ENUM_EXT("Jack Function", n810_enum[1],
+                    n810_get_jack, n810_set_jack),
+       SOC_ENUM_EXT("Input Select",  n810_enum[2],
+                    n810_get_input, n810_set_input),
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link n810_dai = {
+       .name = "TLV320AIC33",
+       .stream_name = "AIC33",
+       .cpu_dai_name = "48076000.mcbsp",
+       .platform_name = "48076000.mcbsp",
+       .codec_name = "tlv320aic3x-codec.1-0018",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
+       .ops = &n810_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_n810 = {
+       .name = "N810",
+       .owner = THIS_MODULE,
+       .dai_link = &n810_dai,
+       .num_links = 1,
+
+       .controls = aic33_n810_controls,
+       .num_controls = ARRAY_SIZE(aic33_n810_controls),
+       .dapm_widgets = aic33_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
+};
+
+static struct platform_device *n810_snd_device;
+
+static int __init n810_soc_init(void)
+{
+       int err;
+       struct device *dev;
+
+       if (!of_have_populated_dt() ||
+           (!of_machine_is_compatible("nokia,n810") &&
+            !of_machine_is_compatible("nokia,n810-wimax")))
+               return -ENODEV;
+
+       n810_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!n810_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(n810_snd_device, &snd_soc_n810);
+       err = platform_device_add(n810_snd_device);
+       if (err)
+               goto err1;
+
+       dev = &n810_snd_device->dev;
+
+       sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
+       if (IS_ERR(sys_clkout2_src)) {
+               dev_err(dev, "Could not get sys_clkout2_src clock\n");
+               err = PTR_ERR(sys_clkout2_src);
+               goto err2;
+       }
+       sys_clkout2 = clk_get(dev, "sys_clkout2");
+       if (IS_ERR(sys_clkout2)) {
+               dev_err(dev, "Could not get sys_clkout2\n");
+               err = PTR_ERR(sys_clkout2);
+               goto err3;
+       }
+       /*
+        * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
+        * 96 MHz as its parent in order to get 12 MHz
+        */
+       func96m_clk = clk_get(dev, "func_96m_ck");
+       if (IS_ERR(func96m_clk)) {
+               dev_err(dev, "Could not get func 96M clock\n");
+               err = PTR_ERR(func96m_clk);
+               goto err4;
+       }
+       clk_set_parent(sys_clkout2_src, func96m_clk);
+       clk_set_rate(sys_clkout2, 12000000);
+
+       if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
+                   (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
+               err = -EINVAL;
+               goto err4;
+       }
+
+       gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
+       gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
+
+       return 0;
+err4:
+       clk_put(sys_clkout2);
+err3:
+       clk_put(sys_clkout2_src);
+err2:
+       platform_device_del(n810_snd_device);
+err1:
+       platform_device_put(n810_snd_device);
+
+       return err;
+}
+
+static void __exit n810_soc_exit(void)
+{
+       gpio_free(N810_SPEAKER_AMP_GPIO);
+       gpio_free(N810_HEADSET_AMP_GPIO);
+       clk_put(sys_clkout2_src);
+       clk_put(sys_clkout2);
+       clk_put(func96m_clk);
+
+       platform_device_unregister(n810_snd_device);
+}
+
+module_init(n810_soc_init);
+module_exit(n810_soc_exit);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
+MODULE_DESCRIPTION("ALSA SoC Nokia N810");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c
new file mode 100644 (file)
index 0000000..fed45b4
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * omap-abe-twl6040.c  --  SoC audio for TI OMAP based boards with ABE and
+ *                        twl6040 codec
+ *
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "omap-dmic.h"
+#include "omap-mcpdm.h"
+#include "../codecs/twl6040.h"
+
+struct abe_twl6040 {
+       struct snd_soc_card card;
+       struct snd_soc_dai_link dai_links[2];
+       int     jack_detection; /* board can detect jack events */
+       int     mclk_freq;      /* MCLK frequency speed for twl6040 */
+};
+
+static struct platform_device *dmic_codec_dev;
+
+static int omap_abe_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
+       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
+       int clk_id, freq;
+       int ret;
+
+       clk_id = twl6040_get_clk_id(codec_dai->component);
+       if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
+               freq = priv->mclk_freq;
+       else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
+               freq = 32768;
+       else
+               return -EINVAL;
+
+       /* set the codec mclk */
+       ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
+                               SND_SOC_CLOCK_IN);
+       if (ret) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return ret;
+       }
+       return ret;
+}
+
+static const struct snd_soc_ops omap_abe_ops = {
+       .hw_params = omap_abe_hw_params,
+};
+
+static int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret = 0;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
+                                    19200000, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set DMIC cpu system clock\n");
+               return ret;
+       }
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
+                                    SND_SOC_CLOCK_OUT);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set DMIC output clock\n");
+               return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_ops omap_abe_dmic_ops = {
+       .hw_params = omap_abe_dmic_hw_params,
+};
+
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+/* SDP4430 machine DAPM */
+static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
+       /* Outputs */
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_SPK("Earphone Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_SPK("Vibrator", NULL),
+
+       /* Inputs */
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
+       SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+
+       /* Digital microphones */
+       SND_SOC_DAPM_MIC("Digital Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Routings for outputs */
+       {"Headset Stereophone", NULL, "HSOL"},
+       {"Headset Stereophone", NULL, "HSOR"},
+
+       {"Earphone Spk", NULL, "EP"},
+
+       {"Ext Spk", NULL, "HFL"},
+       {"Ext Spk", NULL, "HFR"},
+
+       {"Line Out", NULL, "AUXL"},
+       {"Line Out", NULL, "AUXR"},
+
+       {"Vibrator", NULL, "VIBRAL"},
+       {"Vibrator", NULL, "VIBRAR"},
+
+       /* Routings for inputs */
+       {"HSMIC", NULL, "Headset Mic"},
+       {"Headset Mic", NULL, "Headset Mic Bias"},
+
+       {"MAINMIC", NULL, "Main Handset Mic"},
+       {"Main Handset Mic", NULL, "Main Mic Bias"},
+
+       {"SUBMIC", NULL, "Sub Handset Mic"},
+       {"Sub Handset Mic", NULL, "Main Mic Bias"},
+
+       {"AFML", NULL, "Line In"},
+       {"AFMR", NULL, "Line In"},
+};
+
+static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *component = rtd->codec_dai->component;
+       struct snd_soc_card *card = rtd->card;
+       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
+       int hs_trim;
+       int ret = 0;
+
+       /*
+        * Configure McPDM offset cancellation based on the HSOTRIM value from
+        * twl6040.
+        */
+       hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
+       omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
+                                       TWL6040_HSF_TRIM_RIGHT(hs_trim));
+
+       /* Headset jack detection only if it is supported */
+       if (priv->jack_detection) {
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
+               if (ret)
+                       return ret;
+
+               twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_route dmic_audio_map[] = {
+       {"DMic", NULL, "Digital Mic"},
+       {"Digital Mic", NULL, "Digital Mic1 Bias"},
+};
+
+static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+
+       return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
+                               ARRAY_SIZE(dmic_audio_map));
+}
+
+static int omap_abe_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct snd_soc_card *card;
+       struct device_node *dai_node;
+       struct abe_twl6040 *priv;
+       int num_links = 0;
+       int ret = 0;
+
+       if (!node) {
+               dev_err(&pdev->dev, "of node is missing.\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       card = &priv->card;
+       card->dev = &pdev->dev;
+       card->owner = THIS_MODULE;
+       card->dapm_widgets = twl6040_dapm_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets);
+       card->dapm_routes = audio_map;
+       card->num_dapm_routes = ARRAY_SIZE(audio_map);
+
+       if (snd_soc_of_parse_card_name(card, "ti,model")) {
+               dev_err(&pdev->dev, "Card name is not provided\n");
+               return -ENODEV;
+       }
+
+       ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+               return ret;
+       }
+
+       dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+       if (!dai_node) {
+               dev_err(&pdev->dev, "McPDM node is not provided\n");
+               return -EINVAL;
+       }
+
+       priv->dai_links[0].name = "DMIC";
+       priv->dai_links[0].stream_name = "TWL6040";
+       priv->dai_links[0].cpu_of_node = dai_node;
+       priv->dai_links[0].platform_of_node = dai_node;
+       priv->dai_links[0].codec_dai_name = "twl6040-legacy";
+       priv->dai_links[0].codec_name = "twl6040-codec";
+       priv->dai_links[0].init = omap_abe_twl6040_init;
+       priv->dai_links[0].ops = &omap_abe_ops;
+
+       dai_node = of_parse_phandle(node, "ti,dmic", 0);
+       if (dai_node) {
+               num_links = 2;
+               priv->dai_links[1].name = "TWL6040";
+               priv->dai_links[1].stream_name = "DMIC Capture";
+               priv->dai_links[1].cpu_of_node = dai_node;
+               priv->dai_links[1].platform_of_node = dai_node;
+               priv->dai_links[1].codec_dai_name = "dmic-hifi";
+               priv->dai_links[1].codec_name = "dmic-codec";
+               priv->dai_links[1].init = omap_abe_dmic_init;
+               priv->dai_links[1].ops = &omap_abe_dmic_ops;
+       } else {
+               num_links = 1;
+       }
+
+       priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
+       of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
+       if (!priv->mclk_freq) {
+               dev_err(&pdev->dev, "MCLK frequency not provided\n");
+               return -EINVAL;
+       }
+
+       card->fully_routed = 1;
+
+       if (!priv->mclk_freq) {
+               dev_err(&pdev->dev, "MCLK frequency missing\n");
+               return -ENODEV;
+       }
+
+       card->dai_link = priv->dai_links;
+       card->num_links = num_links;
+
+       snd_soc_card_set_drvdata(card, priv);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
+                       ret);
+
+       return ret;
+}
+
+static const struct of_device_id omap_abe_of_match[] = {
+       {.compatible = "ti,abe-twl6040", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_abe_of_match);
+
+static struct platform_driver omap_abe_driver = {
+       .driver = {
+               .name = "omap-abe-twl6040",
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = omap_abe_of_match,
+       },
+       .probe = omap_abe_probe,
+};
+
+static int __init omap_abe_init(void)
+{
+       int ret;
+
+       dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
+                                                        0);
+       if (IS_ERR(dmic_codec_dev)) {
+               pr_err("%s: dmic-codec device registration failed\n", __func__);
+               return PTR_ERR(dmic_codec_dev);
+       }
+
+       ret = platform_driver_register(&omap_abe_driver);
+       if (ret) {
+               pr_err("%s: platform driver registration failed\n", __func__);
+               platform_device_unregister(dmic_codec_dev);
+       }
+
+       return ret;
+}
+module_init(omap_abe_init);
+
+static void __exit omap_abe_exit(void)
+{
+       platform_driver_unregister(&omap_abe_driver);
+       platform_device_unregister(dmic_codec_dev);
+}
+module_exit(omap_abe_exit);
+
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-abe-twl6040");
diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c
new file mode 100644 (file)
index 0000000..cba9645
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * omap-dmic.c  --  OMAP ASoC DMIC DAI driver
+ *
+ * Copyright (C) 2010 - 2011 Texas Instruments
+ *
+ * Author: David Lambert <dlambert@ti.com>
+ *        Misael Lopez Cruz <misael.lopez@ti.com>
+ *        Liam Girdwood <lrg@ti.com>
+ *        Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "omap-dmic.h"
+#include "sdma-pcm.h"
+
+struct omap_dmic {
+       struct device *dev;
+       void __iomem *io_base;
+       struct clk *fclk;
+       struct pm_qos_request pm_qos_req;
+       int latency;
+       int fclk_freq;
+       int out_freq;
+       int clk_div;
+       int sysclk;
+       int threshold;
+       u32 ch_enabled;
+       bool active;
+       struct mutex mutex;
+
+       struct snd_dmaengine_dai_dma_data dma_data;
+};
+
+static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
+{
+       writel_relaxed(val, dmic->io_base + reg);
+}
+
+static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
+{
+       return readl_relaxed(dmic->io_base + reg);
+}
+
+static inline void omap_dmic_start(struct omap_dmic *dmic)
+{
+       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+
+       /* Configure DMA controller */
+       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG,
+                       OMAP_DMIC_DMA_ENABLE);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled);
+}
+
+static inline void omap_dmic_stop(struct omap_dmic *dmic)
+{
+       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
+                       ctrl & ~OMAP_DMIC_UP_ENABLE_MASK);
+
+       /* Disable DMA request generation */
+       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG,
+                       OMAP_DMIC_DMA_ENABLE);
+
+}
+
+static inline int dmic_is_enabled(struct omap_dmic *dmic)
+{
+       return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) &
+                                               OMAP_DMIC_UP_ENABLE_MASK;
+}
+
+static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       int ret = 0;
+
+       mutex_lock(&dmic->mutex);
+
+       if (!dai->active)
+               dmic->active = 1;
+       else
+               ret = -EBUSY;
+
+       mutex_unlock(&dmic->mutex);
+
+       return ret;
+}
+
+static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       mutex_lock(&dmic->mutex);
+
+       pm_qos_remove_request(&dmic->pm_qos_req);
+
+       if (!dai->active)
+               dmic->active = 0;
+
+       mutex_unlock(&dmic->mutex);
+}
+
+static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate)
+{
+       int divider = -EINVAL;
+
+       /*
+        * 192KHz rate is only supported with 19.2MHz/3.84MHz clock
+        * configuration.
+        */
+       if (sample_rate == 192000) {
+               if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000)
+                       divider = 0x6; /* Divider: 5 (192KHz sampling rate) */
+               else
+                       dev_err(dmic->dev,
+                               "invalid clock configuration for 192KHz\n");
+
+               return divider;
+       }
+
+       switch (dmic->out_freq) {
+       case 1536000:
+               if (dmic->fclk_freq != 24576000)
+                       goto div_err;
+               divider = 0x4; /* Divider: 16 */
+               break;
+       case 2400000:
+               switch (dmic->fclk_freq) {
+               case 12000000:
+                       divider = 0x5; /* Divider: 5 */
+                       break;
+               case 19200000:
+                       divider = 0x0; /* Divider: 8 */
+                       break;
+               case 24000000:
+                       divider = 0x2; /* Divider: 10 */
+                       break;
+               default:
+                       goto div_err;
+               }
+               break;
+       case 3072000:
+               if (dmic->fclk_freq != 24576000)
+                       goto div_err;
+               divider = 0x3; /* Divider: 8 */
+               break;
+       case 3840000:
+               if (dmic->fclk_freq != 19200000)
+                       goto div_err;
+               divider = 0x1; /* Divider: 5 (96KHz sampling rate) */
+               break;
+       default:
+               dev_err(dmic->dev, "invalid out frequency: %dHz\n",
+                       dmic->out_freq);
+               break;
+       }
+
+       return divider;
+
+div_err:
+       dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n",
+               dmic->out_freq, dmic->fclk_freq);
+       return -EINVAL;
+}
+
+static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       int channels;
+
+       dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
+       if (dmic->clk_div < 0) {
+               dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n",
+                       dmic->out_freq, dmic->fclk_freq);
+               return -EINVAL;
+       }
+
+       dmic->ch_enabled = 0;
+       channels = params_channels(params);
+       switch (channels) {
+       case 6:
+               dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
+               /* fall through */
+       case 4:
+               dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
+               /* fall through */
+       case 2:
+               dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
+               break;
+       default:
+               dev_err(dmic->dev, "invalid number of legacy channels\n");
+               return -EINVAL;
+       }
+
+       /* packet size is threshold * channels */
+       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+       dma_data->maxburst = dmic->threshold * channels;
+       dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC /
+                       params_rate(params);
+
+       return 0;
+}
+
+static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       u32 ctrl;
+
+       if (pm_qos_request_active(&dmic->pm_qos_req))
+               pm_qos_update_request(&dmic->pm_qos_req, dmic->latency);
+
+       /* Configure uplink threshold */
+       omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold);
+
+       ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+
+       /* Set dmic out format */
+       ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK);
+       ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
+                OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
+
+       /* Configure dmic clock divider */
+       ctrl &= ~OMAP_DMIC_CLK_DIV_MASK;
+       ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
+                       ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
+                       OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
+
+       return 0;
+}
+
+static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream,
+                                 int cmd, struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               omap_dmic_start(dmic);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               omap_dmic_stop(dmic);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id,
+                                unsigned int freq)
+{
+       struct clk *parent_clk, *mux;
+       char *parent_clk_name;
+       int ret = 0;
+
+       switch (freq) {
+       case 12000000:
+       case 19200000:
+       case 24000000:
+       case 24576000:
+               break;
+       default:
+               dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq);
+               dmic->fclk_freq = 0;
+               return -EINVAL;
+       }
+
+       if (dmic->sysclk == clk_id) {
+               dmic->fclk_freq = freq;
+               return 0;
+       }
+
+       /* re-parent not allowed if a stream is ongoing */
+       if (dmic->active && dmic_is_enabled(dmic)) {
+               dev_err(dmic->dev, "can't re-parent when DMIC active\n");
+               return -EBUSY;
+       }
+
+       switch (clk_id) {
+       case OMAP_DMIC_SYSCLK_PAD_CLKS:
+               parent_clk_name = "pad_clks_ck";
+               break;
+       case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS:
+               parent_clk_name = "slimbus_clk";
+               break;
+       case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS:
+               parent_clk_name = "dmic_sync_mux_ck";
+               break;
+       default:
+               dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id);
+               return -EINVAL;
+       }
+
+       parent_clk = clk_get(dmic->dev, parent_clk_name);
+       if (IS_ERR(parent_clk)) {
+               dev_err(dmic->dev, "can't get %s\n", parent_clk_name);
+               return -ENODEV;
+       }
+
+       mux = clk_get_parent(dmic->fclk);
+       if (IS_ERR(mux)) {
+               dev_err(dmic->dev, "can't get fck mux parent\n");
+               clk_put(parent_clk);
+               return -ENODEV;
+       }
+
+       mutex_lock(&dmic->mutex);
+       if (dmic->active) {
+               /* disable clock while reparenting */
+               pm_runtime_put_sync(dmic->dev);
+               ret = clk_set_parent(mux, parent_clk);
+               pm_runtime_get_sync(dmic->dev);
+       } else {
+               ret = clk_set_parent(mux, parent_clk);
+       }
+       mutex_unlock(&dmic->mutex);
+
+       if (ret < 0) {
+               dev_err(dmic->dev, "re-parent failed\n");
+               goto err_busy;
+       }
+
+       dmic->sysclk = clk_id;
+       dmic->fclk_freq = freq;
+
+err_busy:
+       clk_put(mux);
+       clk_put(parent_clk);
+
+       return ret;
+}
+
+static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id,
+                                   unsigned int freq)
+{
+       int ret = 0;
+
+       if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) {
+               dev_err(dmic->dev, "output clk_id (%d) not supported\n",
+                       clk_id);
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case 1536000:
+       case 2400000:
+       case 3072000:
+       case 3840000:
+               dmic->out_freq = freq;
+               break;
+       default:
+               dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq);
+               dmic->out_freq = 0;
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                   unsigned int freq, int dir)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       if (dir == SND_SOC_CLOCK_IN)
+               return omap_dmic_select_fclk(dmic, clk_id, freq);
+       else if (dir == SND_SOC_CLOCK_OUT)
+               return omap_dmic_select_outclk(dmic, clk_id, freq);
+
+       dev_err(dmic->dev, "invalid clock direction (%d)\n", dir);
+       return -EINVAL;
+}
+
+static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
+       .startup        = omap_dmic_dai_startup,
+       .shutdown       = omap_dmic_dai_shutdown,
+       .hw_params      = omap_dmic_dai_hw_params,
+       .prepare        = omap_dmic_dai_prepare,
+       .trigger        = omap_dmic_dai_trigger,
+       .set_sysclk     = omap_dmic_set_dai_sysclk,
+};
+
+static int omap_dmic_probe(struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_enable(dmic->dev);
+
+       /* Disable lines while request is ongoing */
+       pm_runtime_get_sync(dmic->dev);
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00);
+       pm_runtime_put_sync(dmic->dev);
+
+       /* Configure DMIC threshold value */
+       dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
+
+       snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
+
+       return 0;
+}
+
+static int omap_dmic_remove(struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_disable(dmic->dev);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver omap_dmic_dai = {
+       .name = "omap-dmic",
+       .probe = omap_dmic_probe,
+       .remove = omap_dmic_remove,
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 6,
+               .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,
+               .sig_bits = 24,
+       },
+       .ops = &omap_dmic_dai_ops,
+};
+
+static const struct snd_soc_component_driver omap_dmic_component = {
+       .name           = "omap-dmic",
+};
+
+static int asoc_dmic_probe(struct platform_device *pdev)
+{
+       struct omap_dmic *dmic;
+       struct resource *res;
+       int ret;
+
+       dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL);
+       if (!dmic)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dmic);
+       dmic->dev = &pdev->dev;
+       dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS;
+
+       mutex_init(&dmic->mutex);
+
+       dmic->fclk = devm_clk_get(dmic->dev, "fck");
+       if (IS_ERR(dmic->fclk)) {
+               dev_err(dmic->dev, "cant get fck\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+       if (!res) {
+               dev_err(dmic->dev, "invalid dma memory resource\n");
+               return -ENODEV;
+       }
+       dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
+
+       dmic->dma_data.filter_data = "up_link";
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dmic->io_base))
+               return PTR_ERR(dmic->io_base);
+
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &omap_dmic_component,
+                                             &omap_dmic_dai, 1);
+       if (ret)
+               return ret;
+
+       ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link");
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const struct of_device_id omap_dmic_of_match[] = {
+       { .compatible = "ti,omap4-dmic", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, omap_dmic_of_match);
+
+static struct platform_driver asoc_dmic_driver = {
+       .driver = {
+               .name = "omap-dmic",
+               .of_match_table = omap_dmic_of_match,
+       },
+       .probe = asoc_dmic_probe,
+};
+
+module_platform_driver(asoc_dmic_driver);
+
+MODULE_ALIAS("platform:omap-dmic");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("OMAP DMIC ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/omap-dmic.h b/sound/soc/ti/omap-dmic.h
new file mode 100644 (file)
index 0000000..231e728
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * omap-dmic.h  --  OMAP Digital Microphone Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _OMAP_DMIC_H
+#define _OMAP_DMIC_H
+
+#define OMAP_DMIC_REVISION_REG         0x00
+#define OMAP_DMIC_SYSCONFIG_REG                0x10
+#define OMAP_DMIC_IRQSTATUS_RAW_REG    0x24
+#define OMAP_DMIC_IRQSTATUS_REG                0x28
+#define OMAP_DMIC_IRQENABLE_SET_REG    0x2C
+#define OMAP_DMIC_IRQENABLE_CLR_REG    0x30
+#define OMAP_DMIC_IRQWAKE_EN_REG       0x34
+#define OMAP_DMIC_DMAENABLE_SET_REG    0x38
+#define OMAP_DMIC_DMAENABLE_CLR_REG    0x3C
+#define OMAP_DMIC_DMAWAKEEN_REG                0x40
+#define OMAP_DMIC_CTRL_REG             0x44
+#define OMAP_DMIC_DATA_REG             0x48
+#define OMAP_DMIC_FIFO_CTRL_REG                0x4C
+#define OMAP_DMIC_FIFO_DMIC1R_DATA_REG 0x50
+#define OMAP_DMIC_FIFO_DMIC1L_DATA_REG 0x54
+#define OMAP_DMIC_FIFO_DMIC2R_DATA_REG 0x58
+#define OMAP_DMIC_FIFO_DMIC2L_DATA_REG 0x5C
+#define OMAP_DMIC_FIFO_DMIC3R_DATA_REG 0x60
+#define OMAP_DMIC_FIFO_DMIC3L_DATA_REG 0x64
+
+/* IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR bit fields */
+#define OMAP_DMIC_IRQ                  (1 << 0)
+#define OMAP_DMIC_IRQ_FULL             (1 << 1)
+#define OMAP_DMIC_IRQ_ALMST_EMPTY      (1 << 2)
+#define OMAP_DMIC_IRQ_EMPTY            (1 << 3)
+#define OMAP_DMIC_IRQ_MASK             0x07
+
+/* DMIC_DMAENABLE bit fields */
+#define OMAP_DMIC_DMA_ENABLE           0x1
+
+/* DMIC_CTRL bit fields */
+#define OMAP_DMIC_UP1_ENABLE           (1 << 0)
+#define OMAP_DMIC_UP2_ENABLE           (1 << 1)
+#define OMAP_DMIC_UP3_ENABLE           (1 << 2)
+#define OMAP_DMIC_UP_ENABLE_MASK       0x7
+#define OMAP_DMIC_FORMAT               (1 << 3)
+#define OMAP_DMIC_POLAR1               (1 << 4)
+#define OMAP_DMIC_POLAR2               (1 << 5)
+#define OMAP_DMIC_POLAR3               (1 << 6)
+#define OMAP_DMIC_POLAR_MASK           (0x7 << 4)
+#define OMAP_DMIC_CLK_DIV(x)           (((x) & 0x7) << 7)
+#define OMAP_DMIC_CLK_DIV_MASK         (0x7 << 7)
+#define        OMAP_DMIC_RESET                 (1 << 10)
+
+#define OMAP_DMICOUTFORMAT_LJUST       (0 << 3)
+#define OMAP_DMICOUTFORMAT_RJUST       (1 << 3)
+
+/* DMIC_FIFO_CTRL bit fields */
+#define OMAP_DMIC_THRES_MAX            0xF
+
+enum omap_dmic_clk {
+       OMAP_DMIC_SYSCLK_PAD_CLKS,              /* PAD_CLKS */
+       OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS,         /* SLIMBUS_CLK */
+       OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS,         /* DMIC_SYNC_MUX_CLK */
+       OMAP_DMIC_ABE_DMIC_CLK,                 /* abe_dmic_clk */
+};
+
+#endif
diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c
new file mode 100644 (file)
index 0000000..673a9eb
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <uapi/sound/asound.h>
+#include <sound/asoundef.h>
+#include <sound/omap-hdmi-audio.h>
+
+#include "sdma-pcm.h"
+
+#define DRV_NAME "omap-hdmi-audio"
+
+struct hdmi_audio_data {
+       struct snd_soc_card *card;
+
+       const struct omap_hdmi_audio_ops *ops;
+       struct device *dssdev;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct omap_dss_audio dss_audio;
+       struct snd_aes_iec958 iec;
+       struct snd_cea_861_aud_if cea;
+
+       struct mutex current_stream_lock;
+       struct snd_pcm_substream *current_stream;
+};
+
+static
+struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+
+       return snd_soc_card_get_drvdata(rtd->card);
+}
+
+static void hdmi_dai_abort(struct device *dev)
+{
+       struct hdmi_audio_data *ad = dev_get_drvdata(dev);
+
+       mutex_lock(&ad->current_stream_lock);
+       if (ad->current_stream && ad->current_stream->runtime &&
+           snd_pcm_running(ad->current_stream)) {
+               dev_err(dev, "HDMI display disabled, aborting playback\n");
+               snd_pcm_stream_lock_irq(ad->current_stream);
+               snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
+               snd_pcm_stream_unlock_irq(ad->current_stream);
+       }
+       mutex_unlock(&ad->current_stream_lock);
+}
+
+static int hdmi_dai_startup(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+       int ret;
+       /*
+        * Make sure that the period bytes are multiple of the DMA packet size.
+        * Largest packet size we use is 32 32-bit words = 128 bytes
+        */
+       ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+       if (ret < 0) {
+               dev_err(dai->dev, "Could not apply period constraint: %d\n",
+                       ret);
+               return ret;
+       }
+       ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
+       if (ret < 0) {
+               dev_err(dai->dev, "Could not apply buffer constraint: %d\n",
+                       ret);
+               return ret;
+       }
+
+       snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
+
+       mutex_lock(&ad->current_stream_lock);
+       ad->current_stream = substream;
+       mutex_unlock(&ad->current_stream_lock);
+
+       ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
+
+       if (ret) {
+               mutex_lock(&ad->current_stream_lock);
+               ad->current_stream = NULL;
+               mutex_unlock(&ad->current_stream_lock);
+       }
+
+       return ret;
+}
+
+static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+       struct snd_aes_iec958 *iec = &ad->iec;
+       struct snd_cea_861_aud_if *cea = &ad->cea;
+
+       WARN_ON(ad->current_stream != substream);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               ad->dma_data.maxburst = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               ad->dma_data.maxburst = 32;
+               break;
+       default:
+               dev_err(dai->dev, "format not supported!\n");
+               return -EINVAL;
+       }
+
+       ad->dss_audio.iec = iec;
+       ad->dss_audio.cea = cea;
+       /*
+        * fill the IEC-60958 channel status word
+        */
+       /* initialize the word bytes */
+       memset(iec->status, 0, sizeof(iec->status));
+
+       /* specify IEC-60958-3 (commercial use) */
+       iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
+
+       /* specify that the audio is LPCM*/
+       iec->status[0] &= ~IEC958_AES0_NONAUDIO;
+
+       iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
+
+       iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
+
+       iec->status[1] = IEC958_AES1_CON_GENERAL;
+
+       iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
+
+       iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
+
+       switch (params_rate(params)) {
+       case 32000:
+               iec->status[3] |= IEC958_AES3_CON_FS_32000;
+               break;
+       case 44100:
+               iec->status[3] |= IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               iec->status[3] |= IEC958_AES3_CON_FS_48000;
+               break;
+       case 88200:
+               iec->status[3] |= IEC958_AES3_CON_FS_88200;
+               break;
+       case 96000:
+               iec->status[3] |= IEC958_AES3_CON_FS_96000;
+               break;
+       case 176400:
+               iec->status[3] |= IEC958_AES3_CON_FS_176400;
+               break;
+       case 192000:
+               iec->status[3] |= IEC958_AES3_CON_FS_192000;
+               break;
+       default:
+               dev_err(dai->dev, "rate not supported!\n");
+               return -EINVAL;
+       }
+
+       /* specify the clock accuracy */
+       iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
+
+       /*
+        * specify the word length. The same word length value can mean
+        * two different lengths. Hence, we need to specify the maximum
+        * word length as well.
+        */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
+               iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
+               iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
+               break;
+       default:
+               dev_err(dai->dev, "format not supported!\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Fill the CEA-861 audio infoframe (see spec for details)
+        */
+
+       cea->db1_ct_cc = (params_channels(params) - 1)
+               & CEA861_AUDIO_INFOFRAME_DB1CC;
+       cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
+
+       cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
+       cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
+
+       cea->db3 = 0; /* not used, all zeros */
+
+       if (params_channels(params) == 2)
+               cea->db4_ca = 0x0;
+       else if (params_channels(params) == 6)
+               cea->db4_ca = 0xb;
+       else
+               cea->db4_ca = 0x13;
+
+       if (cea->db4_ca == 0x00)
+               cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED;
+       else
+               cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
+
+       /* the expression is trivial but makes clear what we are doing */
+       cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
+
+       return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
+}
+
+static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+       int err = 0;
+
+       WARN_ON(ad->current_stream != substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               err = ad->ops->audio_start(ad->dssdev);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ad->ops->audio_stop(ad->dssdev);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+
+       WARN_ON(ad->current_stream != substream);
+
+       ad->ops->audio_shutdown(ad->dssdev);
+
+       mutex_lock(&ad->current_stream_lock);
+       ad->current_stream = NULL;
+       mutex_unlock(&ad->current_stream_lock);
+}
+
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
+       .startup        = hdmi_dai_startup,
+       .hw_params      = hdmi_dai_hw_params,
+       .trigger        = hdmi_dai_trigger,
+       .shutdown       = hdmi_dai_shutdown,
+};
+
+static const struct snd_soc_component_driver omap_hdmi_component = {
+       .name = "omapdss_hdmi",
+};
+
+static struct snd_soc_dai_driver omap5_hdmi_dai = {
+       .name = "omap5-hdmi-dai",
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+                         SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                         SNDRV_PCM_RATE_192000),
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &hdmi_dai_ops,
+};
+
+static struct snd_soc_dai_driver omap4_hdmi_dai = {
+       .name = "omap4-hdmi-dai",
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+                         SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                         SNDRV_PCM_RATE_192000),
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+       },
+       .ops = &hdmi_dai_ops,
+};
+
+static int omap_hdmi_audio_probe(struct platform_device *pdev)
+{
+       struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct hdmi_audio_data *ad;
+       struct snd_soc_dai_driver *dai_drv;
+       struct snd_soc_card *card;
+       int ret;
+
+       if (!ha) {
+               dev_err(dev, "No platform data\n");
+               return -EINVAL;
+       }
+
+       ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
+       if (!ad)
+               return -ENOMEM;
+       ad->dssdev = ha->dev;
+       ad->ops = ha->ops;
+       ad->dma_data.addr = ha->audio_dma_addr;
+       ad->dma_data.filter_data = "audio_tx";
+       ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       mutex_init(&ad->current_stream_lock);
+
+       switch (ha->version) {
+       case 4:
+               dai_drv = &omap4_hdmi_dai;
+               break;
+       case 5:
+               dai_drv = &omap5_hdmi_dai;
+               break;
+       default:
+               return -EINVAL;
+       }
+       ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
+                                        dai_drv, 1);
+       if (ret)
+               return ret;
+
+       ret = sdma_pcm_platform_register(ad->dssdev, "audio_tx", NULL);
+       if (ret)
+               return ret;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = devm_kasprintf(dev, GFP_KERNEL,
+                                   "HDMI %s", dev_name(ad->dssdev));
+       if (!card->name)
+               return -ENOMEM;
+
+       card->owner = THIS_MODULE;
+       card->dai_link =
+               devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
+       if (!card->dai_link)
+               return -ENOMEM;
+       card->dai_link->name = card->name;
+       card->dai_link->stream_name = card->name;
+       card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
+       card->dai_link->platform_name = dev_name(ad->dssdev);
+       card->dai_link->codec_name = "snd-soc-dummy";
+       card->dai_link->codec_dai_name = "snd-soc-dummy-dai";
+       card->num_links = 1;
+       card->dev = dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
+               return ret;
+       }
+
+       ad->card = card;
+       snd_soc_card_set_drvdata(card, ad);
+
+       dev_set_drvdata(dev, ad);
+
+       return 0;
+}
+
+static int omap_hdmi_audio_remove(struct platform_device *pdev)
+{
+       struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(ad->card);
+       return 0;
+}
+
+static struct platform_driver hdmi_audio_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = omap_hdmi_audio_probe,
+       .remove = omap_hdmi_audio_remove,
+};
+
+module_platform_driver(hdmi_audio_driver);
+
+MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/ti/omap-mcbsp-priv.h b/sound/soc/ti/omap-mcbsp-priv.h
new file mode 100644 (file)
index 0000000..7865cda
--- /dev/null
@@ -0,0 +1,324 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * OMAP Multi-Channel Buffered Serial Port
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#ifndef __OMAP_MCBSP_PRIV_H__
+#define __OMAP_MCBSP_PRIV_H__
+
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#ifdef CONFIG_ARCH_OMAP1
+#define mcbsp_omap1()  1
+#else
+#define mcbsp_omap1()  0
+#endif
+
+/* McBSP register numbers. Register address offset = num * reg_step */
+enum {
+       /* Common registers */
+       OMAP_MCBSP_REG_SPCR2 = 4,
+       OMAP_MCBSP_REG_SPCR1,
+       OMAP_MCBSP_REG_RCR2,
+       OMAP_MCBSP_REG_RCR1,
+       OMAP_MCBSP_REG_XCR2,
+       OMAP_MCBSP_REG_XCR1,
+       OMAP_MCBSP_REG_SRGR2,
+       OMAP_MCBSP_REG_SRGR1,
+       OMAP_MCBSP_REG_MCR2,
+       OMAP_MCBSP_REG_MCR1,
+       OMAP_MCBSP_REG_RCERA,
+       OMAP_MCBSP_REG_RCERB,
+       OMAP_MCBSP_REG_XCERA,
+       OMAP_MCBSP_REG_XCERB,
+       OMAP_MCBSP_REG_PCR0,
+       OMAP_MCBSP_REG_RCERC,
+       OMAP_MCBSP_REG_RCERD,
+       OMAP_MCBSP_REG_XCERC,
+       OMAP_MCBSP_REG_XCERD,
+       OMAP_MCBSP_REG_RCERE,
+       OMAP_MCBSP_REG_RCERF,
+       OMAP_MCBSP_REG_XCERE,
+       OMAP_MCBSP_REG_XCERF,
+       OMAP_MCBSP_REG_RCERG,
+       OMAP_MCBSP_REG_RCERH,
+       OMAP_MCBSP_REG_XCERG,
+       OMAP_MCBSP_REG_XCERH,
+
+       /* OMAP1-OMAP2420 registers */
+       OMAP_MCBSP_REG_DRR2 = 0,
+       OMAP_MCBSP_REG_DRR1,
+       OMAP_MCBSP_REG_DXR2,
+       OMAP_MCBSP_REG_DXR1,
+
+       /* OMAP2430 and onwards */
+       OMAP_MCBSP_REG_DRR = 0,
+       OMAP_MCBSP_REG_DXR = 2,
+       OMAP_MCBSP_REG_SYSCON = 35,
+       OMAP_MCBSP_REG_THRSH2,
+       OMAP_MCBSP_REG_THRSH1,
+       OMAP_MCBSP_REG_IRQST = 40,
+       OMAP_MCBSP_REG_IRQEN,
+       OMAP_MCBSP_REG_WAKEUPEN,
+       OMAP_MCBSP_REG_XCCR,
+       OMAP_MCBSP_REG_RCCR,
+       OMAP_MCBSP_REG_XBUFFSTAT,
+       OMAP_MCBSP_REG_RBUFFSTAT,
+       OMAP_MCBSP_REG_SSELCR,
+};
+
+/************************** McBSP SPCR1 bit definitions ***********************/
+#define RRST                   BIT(0)
+#define RRDY                   BIT(1)
+#define RFULL                  BIT(2)
+#define RSYNC_ERR              BIT(3)
+#define RINTM(value)           (((value) & 0x3) << 4)  /* bits 4:5 */
+#define ABIS                   BIT(6)
+#define DXENA                  BIT(7)
+#define CLKSTP(value)          (((value) & 0x3) << 11) /* bits 11:12 */
+#define RJUST(value)           (((value) & 0x3) << 13) /* bits 13:14 */
+#define ALB                    BIT(15)
+#define DLB                    BIT(15)
+
+/************************** McBSP SPCR2 bit definitions ***********************/
+#define XRST                   BIT(0)
+#define XRDY                   BIT(1)
+#define XEMPTY                 BIT(2)
+#define XSYNC_ERR              BIT(3)
+#define XINTM(value)           (((value) & 0x3) << 4)  /* bits 4:5 */
+#define GRST                   BIT(6)
+#define FRST                   BIT(7)
+#define SOFT                   BIT(8)
+#define FREE                   BIT(9)
+
+/************************** McBSP PCR bit definitions *************************/
+#define CLKRP                  BIT(0)
+#define CLKXP                  BIT(1)
+#define FSRP                   BIT(2)
+#define FSXP                   BIT(3)
+#define DR_STAT                        BIT(4)
+#define DX_STAT                        BIT(5)
+#define CLKS_STAT              BIT(6)
+#define SCLKME                 BIT(7)
+#define CLKRM                  BIT(8)
+#define CLKXM                  BIT(9)
+#define FSRM                   BIT(10)
+#define FSXM                   BIT(11)
+#define RIOEN                  BIT(12)
+#define XIOEN                  BIT(13)
+#define IDLE_EN                        BIT(14)
+
+/************************** McBSP RCR1 bit definitions ************************/
+#define RWDLEN1(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
+#define RFRLEN1(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
+
+/************************** McBSP XCR1 bit definitions ************************/
+#define XWDLEN1(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
+#define XFRLEN1(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
+
+/*************************** McBSP RCR2 bit definitions ***********************/
+#define RDATDLY(value)         ((value) & 0x3)         /* Bits 0:1 */
+#define RFIG                   BIT(2)
+#define RCOMPAND(value)                (((value) & 0x3) << 3)  /* Bits 3:4 */
+#define RWDLEN2(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
+#define RFRLEN2(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
+#define RPHASE                 BIT(15)
+
+/*************************** McBSP XCR2 bit definitions ***********************/
+#define XDATDLY(value)         ((value) & 0x3)         /* Bits 0:1 */
+#define XFIG                   BIT(2)
+#define XCOMPAND(value)                (((value) & 0x3) << 3)  /* Bits 3:4 */
+#define XWDLEN2(value)         (((value) & 0x7) << 5)  /* Bits 5:7 */
+#define XFRLEN2(value)         (((value) & 0x7f) << 8) /* Bits 8:14 */
+#define XPHASE                 BIT(15)
+
+/************************* McBSP SRGR1 bit definitions ************************/
+#define CLKGDV(value)          ((value) & 0x7f)                /* Bits 0:7 */
+#define FWID(value)            (((value) & 0xff) << 8) /* Bits 8:15 */
+
+/************************* McBSP SRGR2 bit definitions ************************/
+#define FPER(value)            ((value) & 0x0fff)      /* Bits 0:11 */
+#define FSGM                   BIT(12)
+#define CLKSM                  BIT(13)
+#define CLKSP                  BIT(14)
+#define GSYNC                  BIT(15)
+
+/************************* McBSP MCR1 bit definitions *************************/
+#define RMCM                   BIT(0)
+#define RCBLK(value)           (((value) & 0x7) << 2)  /* Bits 2:4 */
+#define RPABLK(value)          (((value) & 0x3) << 5)  /* Bits 5:6 */
+#define RPBBLK(value)          (((value) & 0x3) << 7)  /* Bits 7:8 */
+
+/************************* McBSP MCR2 bit definitions *************************/
+#define XMCM(value)            ((value) & 0x3)         /* Bits 0:1 */
+#define XCBLK(value)           (((value) & 0x7) << 2)  /* Bits 2:4 */
+#define XPABLK(value)          (((value) & 0x3) << 5)  /* Bits 5:6 */
+#define XPBBLK(value)          (((value) & 0x3) << 7)  /* Bits 7:8 */
+
+/*********************** McBSP XCCR bit definitions *************************/
+#define XDISABLE               BIT(0)
+#define XDMAEN                 BIT(3)
+#define DILB                   BIT(5)
+#define XFULL_CYCLE            BIT(11)
+#define DXENDLY(value)         (((value) & 0x3) << 12) /* Bits 12:13 */
+#define PPCONNECT              BIT(14)
+#define EXTCLKGATE             BIT(15)
+
+/********************** McBSP RCCR bit definitions *************************/
+#define RDISABLE               BIT(0)
+#define RDMAEN                 BIT(3)
+#define RFULL_CYCLE            BIT(11)
+
+/********************** McBSP SYSCONFIG bit definitions ********************/
+#define SOFTRST                        BIT(1)
+#define ENAWAKEUP              BIT(2)
+#define SIDLEMODE(value)       (((value) & 0x3) << 3)
+#define CLOCKACTIVITY(value)   (((value) & 0x3) << 8)
+
+/********************** McBSP DMA operating modes **************************/
+#define MCBSP_DMA_MODE_ELEMENT         0
+#define MCBSP_DMA_MODE_THRESHOLD       1
+
+/********************** McBSP WAKEUPEN/IRQST/IRQEN bit definitions *********/
+#define RSYNCERREN             BIT(0)
+#define RFSREN                 BIT(1)
+#define REOFEN                 BIT(2)
+#define RRDYEN                 BIT(3)
+#define RUNDFLEN               BIT(4)
+#define ROVFLEN                        BIT(5)
+#define XSYNCERREN             BIT(7)
+#define XFSXEN                 BIT(8)
+#define XEOFEN                 BIT(9)
+#define XRDYEN                 BIT(10)
+#define XUNDFLEN               BIT(11)
+#define XOVFLEN                        BIT(12)
+#define XEMPTYEOFEN            BIT(14)
+
+/* Clock signal muxing options */
+#define CLKR_SRC_CLKR          0 /* CLKR signal is from the CLKR pin */
+#define CLKR_SRC_CLKX          1 /* CLKR signal is from the CLKX pin */
+#define FSR_SRC_FSR            2 /* FSR signal is from the FSR pin */
+#define FSR_SRC_FSX            3 /* FSR signal is from the FSX pin */
+
+/* McBSP functional clock sources */
+#define MCBSP_CLKS_PRCM_SRC    0
+#define MCBSP_CLKS_PAD_SRC     1
+
+/* we don't do multichannel for now */
+struct omap_mcbsp_reg_cfg {
+       u16 spcr2;
+       u16 spcr1;
+       u16 rcr2;
+       u16 rcr1;
+       u16 xcr2;
+       u16 xcr1;
+       u16 srgr2;
+       u16 srgr1;
+       u16 mcr2;
+       u16 mcr1;
+       u16 pcr0;
+       u16 rcerc;
+       u16 rcerd;
+       u16 xcerc;
+       u16 xcerd;
+       u16 rcere;
+       u16 rcerf;
+       u16 xcere;
+       u16 xcerf;
+       u16 rcerg;
+       u16 rcerh;
+       u16 xcerg;
+       u16 xcerh;
+       u16 xccr;
+       u16 rccr;
+};
+
+struct omap_mcbsp_st_data;
+
+struct omap_mcbsp {
+       struct device *dev;
+       struct clk *fclk;
+       spinlock_t lock;
+       unsigned long phys_base;
+       unsigned long phys_dma_base;
+       void __iomem *io_base;
+       u8 id;
+       /*
+        * Flags indicating is the bus already activated and configured by
+        * another substream
+        */
+       int active;
+       int configured;
+       u8 free;
+
+       int irq;
+       int rx_irq;
+       int tx_irq;
+
+       /* Protect the field .free, while checking if the mcbsp is in use */
+       struct omap_mcbsp_platform_data *pdata;
+       struct omap_mcbsp_st_data *st_data;
+       struct omap_mcbsp_reg_cfg cfg_regs;
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       unsigned int dma_req[2];
+       int dma_op_mode;
+       u16 max_tx_thres;
+       u16 max_rx_thres;
+       void *reg_cache;
+       int reg_cache_size;
+
+       unsigned int fmt;
+       unsigned int in_freq;
+       unsigned int latency[2];
+       int clk_div;
+       int wlen;
+
+       struct pm_qos_request pm_qos_req;
+};
+
+static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+       void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+       if (mcbsp->pdata->reg_size == 2) {
+               ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
+               writew_relaxed((u16)val, addr);
+       } else {
+               ((u32 *)mcbsp->reg_cache)[reg] = val;
+               writel_relaxed(val, addr);
+       }
+}
+
+static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
+                                 bool from_cache)
+{
+       void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+       if (mcbsp->pdata->reg_size == 2) {
+               return !from_cache ? readw_relaxed(addr) :
+                                    ((u16 *)mcbsp->reg_cache)[reg];
+       } else {
+               return !from_cache ? readl_relaxed(addr) :
+                                    ((u32 *)mcbsp->reg_cache)[reg];
+       }
+}
+
+#define MCBSP_READ(mcbsp, reg) \
+               omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
+#define MCBSP_WRITE(mcbsp, reg, val) \
+               omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
+#define MCBSP_READ_CACHE(mcbsp, reg) \
+               omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
+
+
+/* Sidetone specific API */
+int omap_mcbsp_st_init(struct platform_device *pdev);
+void omap_mcbsp_st_cleanup(struct platform_device *pdev);
+
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
+
+#endif /* __OMAP_MCBSP_PRIV_H__ */
diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c
new file mode 100644 (file)
index 0000000..1a3fe85
--- /dev/null
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * McBSP Sidetone support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include "omap-mcbsp.h"
+#include "omap-mcbsp-priv.h"
+
+/* OMAP3 sidetone control registers */
+#define OMAP_ST_REG_REV                0x00
+#define OMAP_ST_REG_SYSCONFIG  0x10
+#define OMAP_ST_REG_IRQSTATUS  0x18
+#define OMAP_ST_REG_IRQENABLE  0x1C
+#define OMAP_ST_REG_SGAINCR    0x24
+#define OMAP_ST_REG_SFIRCR     0x28
+#define OMAP_ST_REG_SSELCR     0x2C
+
+/********************** McBSP SSELCR bit definitions ***********************/
+#define SIDETONEEN             BIT(10)
+
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
+#define ST_AUTOIDLE            BIT(0)
+
+/********************** McBSP Sidetone SGAINCR bit definitions *************/
+#define ST_CH0GAIN(value)      ((value) & 0xffff)      /* Bits 0:15 */
+#define ST_CH1GAIN(value)      (((value) & 0xffff) << 16) /* Bits 16:31 */
+
+/********************** McBSP Sidetone SFIRCR bit definitions **************/
+#define ST_FIRCOEFF(value)     ((value) & 0xffff)      /* Bits 0:15 */
+
+/********************** McBSP Sidetone SSELCR bit definitions **************/
+#define ST_SIDETONEEN          BIT(0)
+#define ST_COEFFWREN           BIT(1)
+#define ST_COEFFWRDONE         BIT(2)
+
+struct omap_mcbsp_st_data {
+       void __iomem *io_base_st;
+       struct clk *mcbsp_iclk;
+       bool running;
+       bool enabled;
+       s16 taps[128];  /* Sidetone filter coefficients */
+       int nr_taps;    /* Number of filter coefficients in use */
+       s16 ch0gain;
+       s16 ch1gain;
+};
+
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+       writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
+}
+
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+{
+       return readl_relaxed(mcbsp->st_data->io_base_st + reg);
+}
+
+#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
+                       omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
+
+static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
+{
+       unsigned int w;
+
+       if (mcbsp->pdata->force_ick_on)
+               mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
+
+       /* Disable Sidetone clock auto-gating for normal operation */
+       w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+       MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
+
+       /* Enable McBSP Sidetone */
+       w = MCBSP_READ(mcbsp, SSELCR);
+       MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
+
+       /* Enable Sidetone from Sidetone Core */
+       w = MCBSP_ST_READ(mcbsp, SSELCR);
+       MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+
+static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
+{
+       unsigned int w;
+
+       w = MCBSP_ST_READ(mcbsp, SSELCR);
+       MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
+
+       w = MCBSP_READ(mcbsp, SSELCR);
+       MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
+
+       /* Enable Sidetone clock auto-gating to reduce power consumption */
+       w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+       MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
+
+       if (mcbsp->pdata->force_ick_on)
+               mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
+}
+
+static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
+{
+       u16 val, i;
+
+       val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+       if (val & ST_COEFFWREN)
+               MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+       MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
+
+       for (i = 0; i < 128; i++)
+               MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
+
+       i = 0;
+
+       val = MCBSP_ST_READ(mcbsp, SSELCR);
+       while (!(val & ST_COEFFWRDONE) && (++i < 1000))
+               val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+       MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+       if (i == 1000)
+               dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+
+static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
+{
+       u16 w;
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+       w = MCBSP_ST_READ(mcbsp, SSELCR);
+
+       MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
+                      ST_CH1GAIN(st_data->ch1gain));
+}
+
+static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
+                                   s16 chgain)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+       int ret = 0;
+
+       if (!st_data)
+               return -ENOENT;
+
+       spin_lock_irq(&mcbsp->lock);
+       if (channel == 0)
+               st_data->ch0gain = chgain;
+       else if (channel == 1)
+               st_data->ch1gain = chgain;
+       else
+               ret = -EINVAL;
+
+       if (st_data->enabled)
+               omap_mcbsp_st_chgain(mcbsp);
+       spin_unlock_irq(&mcbsp->lock);
+
+       return ret;
+}
+
+static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
+                                   s16 *chgain)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+       int ret = 0;
+
+       if (!st_data)
+               return -ENOENT;
+
+       spin_lock_irq(&mcbsp->lock);
+       if (channel == 0)
+               *chgain = st_data->ch0gain;
+       else if (channel == 1)
+               *chgain = st_data->ch1gain;
+       else
+               ret = -EINVAL;
+       spin_unlock_irq(&mcbsp->lock);
+
+       return ret;
+}
+
+static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+       if (!st_data)
+               return -ENODEV;
+
+       spin_lock_irq(&mcbsp->lock);
+       st_data->enabled = 1;
+       omap_mcbsp_st_start(mcbsp);
+       spin_unlock_irq(&mcbsp->lock);
+
+       return 0;
+}
+
+static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+       int ret = 0;
+
+       if (!st_data)
+               return -ENODEV;
+
+       spin_lock_irq(&mcbsp->lock);
+       omap_mcbsp_st_stop(mcbsp);
+       st_data->enabled = 0;
+       spin_unlock_irq(&mcbsp->lock);
+
+       return ret;
+}
+
+static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+       if (!st_data)
+               return -ENODEV;
+
+       return st_data->enabled;
+}
+
+static ssize_t st_taps_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+       ssize_t status = 0;
+       int i;
+
+       spin_lock_irq(&mcbsp->lock);
+       for (i = 0; i < st_data->nr_taps; i++)
+               status += sprintf(&buf[status], (i ? ", %d" : "%d"),
+                                 st_data->taps[i]);
+       if (i)
+               status += sprintf(&buf[status], "\n");
+       spin_unlock_irq(&mcbsp->lock);
+
+       return status;
+}
+
+static ssize_t st_taps_store(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t size)
+{
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+       int val, tmp, status, i = 0;
+
+       spin_lock_irq(&mcbsp->lock);
+       memset(st_data->taps, 0, sizeof(st_data->taps));
+       st_data->nr_taps = 0;
+
+       do {
+               status = sscanf(buf, "%d%n", &val, &tmp);
+               if (status < 0 || status == 0) {
+                       size = -EINVAL;
+                       goto out;
+               }
+               if (val < -32768 || val > 32767) {
+                       size = -EINVAL;
+                       goto out;
+               }
+               st_data->taps[i++] = val;
+               buf += tmp;
+               if (*buf != ',')
+                       break;
+               buf++;
+       } while (1);
+
+       st_data->nr_taps = i;
+
+out:
+       spin_unlock_irq(&mcbsp->lock);
+
+       return size;
+}
+
+static DEVICE_ATTR_RW(st_taps);
+
+static const struct attribute *sidetone_attrs[] = {
+       &dev_attr_st_taps.attr,
+       NULL,
+};
+
+static const struct attribute_group sidetone_attr_group = {
+       .attrs = (struct attribute **)sidetone_attrs,
+};
+
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+       if (st_data->enabled && !st_data->running) {
+               omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
+               omap_mcbsp_st_chgain(mcbsp);
+
+               if (!mcbsp->free) {
+                       omap_mcbsp_st_on(mcbsp);
+                       st_data->running = 1;
+               }
+       }
+
+       return 0;
+}
+
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
+{
+       struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+       if (st_data->running) {
+               if (!mcbsp->free) {
+                       omap_mcbsp_st_off(mcbsp);
+                       st_data->running = 0;
+               }
+       }
+
+       return 0;
+}
+
+int omap_mcbsp_st_init(struct platform_device *pdev)
+{
+       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+       struct omap_mcbsp_st_data *st_data;
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+       if (!res)
+               return 0;
+
+       st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+       if (!st_data)
+               return -ENOMEM;
+
+       st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+       if (IS_ERR(st_data->mcbsp_iclk)) {
+               dev_warn(mcbsp->dev,
+                        "Failed to get ick, sidetone might be broken\n");
+               st_data->mcbsp_iclk = NULL;
+       }
+
+       st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+                                          resource_size(res));
+       if (!st_data->io_base_st)
+               return -ENOMEM;
+
+       ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+       if (ret)
+               return ret;
+
+       mcbsp->st_data = st_data;
+
+       return 0;
+}
+
+void omap_mcbsp_st_cleanup(struct platform_device *pdev)
+{
+       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+       if (mcbsp->st_data) {
+               sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+               clk_put(mcbsp->st_data->mcbsp_iclk);
+       }
+}
+
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int max = mc->max;
+       int min = mc->min;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = min;
+       uinfo->value.integer.max = max;
+       return 0;
+}
+
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel)                          \
+static int                                                             \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
+                                      struct snd_ctl_elem_value *uc)   \
+{                                                                      \
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
+       struct soc_mixer_control *mc =                                  \
+               (struct soc_mixer_control *)kc->private_value;          \
+       int max = mc->max;                                              \
+       int min = mc->min;                                              \
+       int val = uc->value.integer.value[0];                           \
+                                                                       \
+       if (val < min || val > max)                                     \
+               return -EINVAL;                                         \
+                                                                       \
+       /* OMAP McBSP implementation uses index values 0..4 */          \
+       return omap_mcbsp_st_set_chgain(mcbsp, channel, val);           \
+}                                                                      \
+                                                                       \
+static int                                                             \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
+                                      struct snd_ctl_elem_value *uc)   \
+{                                                                      \
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
+       s16 chgain;                                                     \
+                                                                       \
+       if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain))          \
+               return -EAGAIN;                                         \
+                                                                       \
+       uc->value.integer.value[0] = chgain;                            \
+       return 0;                                                       \
+}
+
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
+
+static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       u8 value = ucontrol->value.integer.value[0];
+
+       if (value == omap_mcbsp_st_is_enabled(mcbsp))
+               return 0;
+
+       if (value)
+               omap_mcbsp_st_enable(mcbsp);
+       else
+               omap_mcbsp_st_disable(mcbsp);
+
+       return 1;
+}
+
+static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
+       return 0;
+}
+
+#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax,               \
+                                     xhandler_get, xhandler_put)       \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,             \
+       .info = omap_mcbsp_st_info_volsw,                               \
+       .get = xhandler_get, .put = xhandler_put,                       \
+       .private_value = (unsigned long)&(struct soc_mixer_control)     \
+       {.min = xmin, .max = xmax} }
+
+#define OMAP_MCBSP_ST_CONTROLS(port)                                     \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0,             \
+              omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),           \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch0_volume,               \
+                             omap_mcbsp_set_st_ch0_volume),              \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch1_volume,               \
+                             omap_mcbsp_set_st_ch1_volume),              \
+}
+
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
+
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
+{
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (!mcbsp->st_data) {
+               dev_warn(mcbsp->dev, "No sidetone data for port\n");
+               return 0;
+       }
+
+       switch (port_id) {
+       case 2: /* McBSP 2 */
+               return snd_soc_add_dai_controls(cpu_dai,
+                                       omap_mcbsp2_st_controls,
+                                       ARRAY_SIZE(omap_mcbsp2_st_controls));
+       case 3: /* McBSP 3 */
+               return snd_soc_add_dai_controls(cpu_dai,
+                                       omap_mcbsp3_st_controls,
+                                       ARRAY_SIZE(omap_mcbsp3_st_controls));
+       default:
+               dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
new file mode 100644 (file)
index 0000000..a395598
--- /dev/null
@@ -0,0 +1,1479 @@
+/*
+ * omap-mcbsp.c  --  OMAP ALSA SoC DAI driver using McBSP port
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "omap-mcbsp-priv.h"
+#include "omap-mcbsp.h"
+#include "sdma-pcm.h"
+
+#define OMAP_MCBSP_RATES       (SNDRV_PCM_RATE_8000_96000)
+
+enum {
+       OMAP_MCBSP_WORD_8 = 0,
+       OMAP_MCBSP_WORD_12,
+       OMAP_MCBSP_WORD_16,
+       OMAP_MCBSP_WORD_20,
+       OMAP_MCBSP_WORD_24,
+       OMAP_MCBSP_WORD_32,
+};
+
+static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
+{
+       dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+       dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n", MCBSP_READ(mcbsp, DRR2));
+       dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n", MCBSP_READ(mcbsp, DRR1));
+       dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n", MCBSP_READ(mcbsp, DXR2));
+       dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n", MCBSP_READ(mcbsp, DXR1));
+       dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2));
+       dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1));
+       dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n", MCBSP_READ(mcbsp, RCR2));
+       dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n", MCBSP_READ(mcbsp, RCR1));
+       dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n", MCBSP_READ(mcbsp, XCR2));
+       dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n", MCBSP_READ(mcbsp, XCR1));
+       dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2));
+       dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1));
+       dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n", MCBSP_READ(mcbsp, PCR0));
+       dev_dbg(mcbsp->dev, "***********************\n");
+}
+
+static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
+{
+       struct clk *fck_src;
+       const char *src;
+       int r;
+
+       if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+               src = "pad_fck";
+       else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+               src = "prcm_fck";
+       else
+               return -EINVAL;
+
+       fck_src = clk_get(mcbsp->dev, src);
+       if (IS_ERR(fck_src)) {
+               dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
+               return -EINVAL;
+       }
+
+       pm_runtime_put_sync(mcbsp->dev);
+
+       r = clk_set_parent(mcbsp->fclk, fck_src);
+       if (r) {
+               dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
+                       src);
+               clk_put(fck_src);
+               return r;
+       }
+
+       pm_runtime_get_sync(mcbsp->dev);
+
+       clk_put(fck_src);
+
+       return 0;
+}
+
+static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
+{
+       struct omap_mcbsp *mcbsp = data;
+       u16 irqst;
+
+       irqst = MCBSP_READ(mcbsp, IRQST);
+       dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
+
+       if (irqst & RSYNCERREN)
+               dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
+       if (irqst & RFSREN)
+               dev_dbg(mcbsp->dev, "RX Frame Sync\n");
+       if (irqst & REOFEN)
+               dev_dbg(mcbsp->dev, "RX End Of Frame\n");
+       if (irqst & RRDYEN)
+               dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
+       if (irqst & RUNDFLEN)
+               dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
+       if (irqst & ROVFLEN)
+               dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
+
+       if (irqst & XSYNCERREN)
+               dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
+       if (irqst & XFSXEN)
+               dev_dbg(mcbsp->dev, "TX Frame Sync\n");
+       if (irqst & XEOFEN)
+               dev_dbg(mcbsp->dev, "TX End Of Frame\n");
+       if (irqst & XRDYEN)
+               dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
+       if (irqst & XUNDFLEN)
+               dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
+       if (irqst & XOVFLEN)
+               dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
+       if (irqst & XEMPTYEOFEN)
+               dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
+
+       MCBSP_WRITE(mcbsp, IRQST, irqst);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
+{
+       struct omap_mcbsp *mcbsp = data;
+       u16 irqst_spcr2;
+
+       irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
+       dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+       if (irqst_spcr2 & XSYNC_ERR) {
+               dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
+                       irqst_spcr2);
+               /* Writing zero to XSYNC_ERR clears the IRQ */
+               MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
+{
+       struct omap_mcbsp *mcbsp = data;
+       u16 irqst_spcr1;
+
+       irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
+       dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+       if (irqst_spcr1 & RSYNC_ERR) {
+               dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
+                       irqst_spcr1);
+               /* Writing zero to RSYNC_ERR clears the IRQ */
+               MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+static void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+                             const struct omap_mcbsp_reg_cfg *config)
+{
+       dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
+               mcbsp->id, mcbsp->phys_base);
+
+       /* We write the given config */
+       MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
+       MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
+       MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
+       MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
+       MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
+       MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
+       MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
+       MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
+       MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
+       MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
+       MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
+       if (mcbsp->pdata->has_ccr) {
+               MCBSP_WRITE(mcbsp, XCCR, config->xccr);
+               MCBSP_WRITE(mcbsp, RCCR, config->rccr);
+       }
+       /* Enable wakeup behavior */
+       if (mcbsp->pdata->has_wakeup)
+               MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
+
+       /* Enable TX/RX sync error interrupts by default */
+       if (mcbsp->irq)
+               MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
+                           RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @mcbsp: omap_mcbsp struct for the McBSP instance
+ * @stream: Stream direction (playback/capture)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+                                    unsigned int stream)
+{
+       int data_reg;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (mcbsp->pdata->reg_size == 2)
+                       data_reg = OMAP_MCBSP_REG_DXR1;
+               else
+                       data_reg = OMAP_MCBSP_REG_DXR;
+       } else {
+               if (mcbsp->pdata->reg_size == 2)
+                       data_reg = OMAP_MCBSP_REG_DRR1;
+               else
+                       data_reg = OMAP_MCBSP_REG_DRR;
+       }
+
+       return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
+ */
+static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+       if (threshold && threshold <= mcbsp->max_tx_thres)
+               MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
+ */
+static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+       if (threshold && threshold <= mcbsp->max_rx_thres)
+               MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+       u16 buffstat;
+
+       /* Returns the number of free locations in the buffer */
+       buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+       /* Number of slots are different in McBSP ports */
+       return mcbsp->pdata->buffer_size - buffstat;
+}
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+       u16 buffstat, threshold;
+
+       /* Returns the number of used locations in the buffer */
+       buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+       /* RX threshold */
+       threshold = MCBSP_READ(mcbsp, THRSH1);
+
+       /* Return the number of location till we reach the threshold limit */
+       if (threshold <= buffstat)
+               return 0;
+       else
+               return threshold - buffstat;
+}
+
+static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+       void *reg_cache;
+       int err;
+
+       reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
+       if (!reg_cache)
+               return -ENOMEM;
+
+       spin_lock(&mcbsp->lock);
+       if (!mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
+               err = -EBUSY;
+               goto err_kfree;
+       }
+
+       mcbsp->free = false;
+       mcbsp->reg_cache = reg_cache;
+       spin_unlock(&mcbsp->lock);
+
+       if(mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+               mcbsp->pdata->ops->request(mcbsp->id - 1);
+
+       /*
+        * Make sure that transmitter, receiver and sample-rate generator are
+        * not running before activating IRQs.
+        */
+       MCBSP_WRITE(mcbsp, SPCR1, 0);
+       MCBSP_WRITE(mcbsp, SPCR2, 0);
+
+       if (mcbsp->irq) {
+               err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
+                                 "McBSP", (void *)mcbsp);
+               if (err != 0) {
+                       dev_err(mcbsp->dev, "Unable to request IRQ\n");
+                       goto err_clk_disable;
+               }
+       } else {
+               err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
+                                 "McBSP TX", (void *)mcbsp);
+               if (err != 0) {
+                       dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
+                       goto err_clk_disable;
+               }
+
+               err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
+                                 "McBSP RX", (void *)mcbsp);
+               if (err != 0) {
+                       dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
+                       goto err_free_irq;
+               }
+       }
+
+       return 0;
+err_free_irq:
+       free_irq(mcbsp->tx_irq, (void *)mcbsp);
+err_clk_disable:
+       if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+       /* Disable wakeup behavior */
+       if (mcbsp->pdata->has_wakeup)
+               MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+       spin_lock(&mcbsp->lock);
+       mcbsp->free = true;
+       mcbsp->reg_cache = NULL;
+err_kfree:
+       spin_unlock(&mcbsp->lock);
+       kfree(reg_cache);
+
+       return err;
+}
+
+static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+       void *reg_cache;
+
+       if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+       /* Disable wakeup behavior */
+       if (mcbsp->pdata->has_wakeup)
+               MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+       /* Disable interrupt requests */
+       if (mcbsp->irq)
+               MCBSP_WRITE(mcbsp, IRQEN, 0);
+
+       if (mcbsp->irq) {
+               free_irq(mcbsp->irq, (void *)mcbsp);
+       } else {
+               free_irq(mcbsp->rx_irq, (void *)mcbsp);
+               free_irq(mcbsp->tx_irq, (void *)mcbsp);
+       }
+
+       reg_cache = mcbsp->reg_cache;
+
+       /*
+        * Select CLKS source from internal source unconditionally before
+        * marking the McBSP port as free.
+        * If the external clock source via MCBSP_CLKS pin has been selected the
+        * system will refuse to enter idle if the CLKS pin source is not reset
+        * back to internal source.
+        */
+       if (!mcbsp_omap1())
+               omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
+
+       spin_lock(&mcbsp->lock);
+       if (mcbsp->free)
+               dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
+       else
+               mcbsp->free = true;
+       mcbsp->reg_cache = NULL;
+       spin_unlock(&mcbsp->lock);
+
+       kfree(reg_cache);
+}
+
+/*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
+{
+       int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int rx = !tx;
+       int enable_srg = 0;
+       u16 w;
+
+       if (mcbsp->st_data)
+               omap_mcbsp_st_start(mcbsp);
+
+       /* Only enable SRG, if McBSP is master */
+       w = MCBSP_READ_CACHE(mcbsp, PCR0);
+       if (w & (FSXM | FSRM | CLKXM | CLKRM))
+               enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+                               MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+       if (enable_srg) {
+               /* Start the sample generator */
+               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+               MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
+       }
+
+       /* Enable transmitter and receiver */
+       tx &= 1;
+       w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+       MCBSP_WRITE(mcbsp, SPCR2, w | tx);
+
+       rx &= 1;
+       w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+       MCBSP_WRITE(mcbsp, SPCR1, w | rx);
+
+       /*
+        * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+        * REVISIT: 100us may give enough time for two CLKSRG, however
+        * due to some unknown PM related, clock gating etc. reason it
+        * is now at 500us.
+        */
+       udelay(500);
+
+       if (enable_srg) {
+               /* Start frame sync */
+               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+               MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
+       }
+
+       if (mcbsp->pdata->has_ccr) {
+               /* Release the transmitter and receiver */
+               w = MCBSP_READ_CACHE(mcbsp, XCCR);
+               w &= ~(tx ? XDISABLE : 0);
+               MCBSP_WRITE(mcbsp, XCCR, w);
+               w = MCBSP_READ_CACHE(mcbsp, RCCR);
+               w &= ~(rx ? RDISABLE : 0);
+               MCBSP_WRITE(mcbsp, RCCR, w);
+       }
+
+       /* Dump McBSP Regs */
+       omap_mcbsp_dump_reg(mcbsp);
+}
+
+static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
+{
+       int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int rx = !tx;
+       int idle;
+       u16 w;
+
+       /* Reset transmitter */
+       tx &= 1;
+       if (mcbsp->pdata->has_ccr) {
+               w = MCBSP_READ_CACHE(mcbsp, XCCR);
+               w |= (tx ? XDISABLE : 0);
+               MCBSP_WRITE(mcbsp, XCCR, w);
+       }
+       w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+       MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
+
+       /* Reset receiver */
+       rx &= 1;
+       if (mcbsp->pdata->has_ccr) {
+               w = MCBSP_READ_CACHE(mcbsp, RCCR);
+               w |= (rx ? RDISABLE : 0);
+               MCBSP_WRITE(mcbsp, RCCR, w);
+       }
+       w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+       MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
+
+       idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+                       MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+       if (idle) {
+               /* Reset the sample rate generator */
+               w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+               MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
+       }
+
+       if (mcbsp->st_data)
+               omap_mcbsp_st_stop(mcbsp);
+}
+
+#define max_thres(m)                   (mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val)                ((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop)                                   \
+static ssize_t prop##_show(struct device *dev,                         \
+                       struct device_attribute *attr, char *buf)       \
+{                                                                      \
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);                \
+                                                                       \
+       return sprintf(buf, "%u\n", mcbsp->prop);                       \
+}                                                                      \
+                                                                       \
+static ssize_t prop##_store(struct device *dev,                                \
+                               struct device_attribute *attr,          \
+                               const char *buf, size_t size)           \
+{                                                                      \
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);                \
+       unsigned long val;                                              \
+       int status;                                                     \
+                                                                       \
+       status = kstrtoul(buf, 0, &val);                                \
+       if (status)                                                     \
+               return status;                                          \
+                                                                       \
+       if (!valid_threshold(mcbsp, val))                               \
+               return -EDOM;                                           \
+                                                                       \
+       mcbsp->prop = val;                                              \
+       return size;                                                    \
+}                                                                      \
+                                                                       \
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store)
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char * const dma_op_modes[] = {
+       "element", "threshold",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+       int dma_op_mode, i = 0;
+       ssize_t len = 0;
+       const char * const *s;
+
+       dma_op_mode = mcbsp->dma_op_mode;
+
+       for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+               if (dma_op_mode == i)
+                       len += sprintf(buf + len, "[%s] ", *s);
+               else
+                       len += sprintf(buf + len, "%s ", *s);
+       }
+       len += sprintf(buf + len, "\n");
+
+       return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+                                struct device_attribute *attr, const char *buf,
+                                size_t size)
+{
+       struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+       int i;
+
+       i = sysfs_match_string(dma_op_modes, buf);
+       if (i < 0)
+               return i;
+
+       spin_lock_irq(&mcbsp->lock);
+       if (!mcbsp->free) {
+               size = -EBUSY;
+               goto unlock;
+       }
+       mcbsp->dma_op_mode = i;
+
+unlock:
+       spin_unlock_irq(&mcbsp->lock);
+
+       return size;
+}
+
+static DEVICE_ATTR_RW(dma_op_mode);
+
+static const struct attribute *additional_attrs[] = {
+       &dev_attr_max_tx_thres.attr,
+       &dev_attr_max_rx_thres.attr,
+       &dev_attr_dma_op_mode.attr,
+       NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+       .attrs = (struct attribute **)additional_attrs,
+};
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+static int omap_mcbsp_init(struct platform_device *pdev)
+{
+       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+       struct resource *res;
+       int ret = 0;
+
+       spin_lock_init(&mcbsp->lock);
+       mcbsp->free = true;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       if (!res)
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mcbsp->io_base))
+               return PTR_ERR(mcbsp->io_base);
+
+       mcbsp->phys_base = res->start;
+       mcbsp->reg_cache_size = resource_size(res);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+       if (!res)
+               mcbsp->phys_dma_base = mcbsp->phys_base;
+       else
+               mcbsp->phys_dma_base = res->start;
+
+       /*
+        * OMAP1, 2 uses two interrupt lines: TX, RX
+        * OMAP2430, OMAP3 SoC have combined IRQ line as well.
+        * OMAP4 and newer SoC only have the combined IRQ line.
+        * Use the combined IRQ if available since it gives better debugging
+        * possibilities.
+        */
+       mcbsp->irq = platform_get_irq_byname(pdev, "common");
+       if (mcbsp->irq == -ENXIO) {
+               mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+
+               if (mcbsp->tx_irq == -ENXIO) {
+                       mcbsp->irq = platform_get_irq(pdev, 0);
+                       mcbsp->tx_irq = 0;
+               } else {
+                       mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+                       mcbsp->irq = 0;
+               }
+       }
+
+       if (!pdev->dev.of_node) {
+               res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+               if (!res) {
+                       dev_err(&pdev->dev, "invalid tx DMA channel\n");
+                       return -ENODEV;
+               }
+               mcbsp->dma_req[0] = res->start;
+               mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+
+               res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+               if (!res) {
+                       dev_err(&pdev->dev, "invalid rx DMA channel\n");
+                       return -ENODEV;
+               }
+               mcbsp->dma_req[1] = res->start;
+               mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+       } else {
+               mcbsp->dma_data[0].filter_data = "tx";
+               mcbsp->dma_data[1].filter_data = "rx";
+       }
+
+       mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
+                                               SNDRV_PCM_STREAM_PLAYBACK);
+       mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
+                                               SNDRV_PCM_STREAM_CAPTURE);
+
+       mcbsp->fclk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(mcbsp->fclk)) {
+               ret = PTR_ERR(mcbsp->fclk);
+               dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
+               return ret;
+       }
+
+       mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+       if (mcbsp->pdata->buffer_size) {
+               /*
+                * Initially configure the maximum thresholds to a safe value.
+                * The McBSP FIFO usage with these values should not go under
+                * 16 locations.
+                * If the whole FIFO without safety buffer is used, than there
+                * is a possibility that the DMA will be not able to push the
+                * new data on time, causing channel shifts in runtime.
+                */
+               mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+               mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
+
+               ret = sysfs_create_group(&mcbsp->dev->kobj,
+                                        &additional_attr_group);
+               if (ret) {
+                       dev_err(mcbsp->dev,
+                               "Unable to create additional controls\n");
+                       goto err_thres;
+               }
+       }
+
+       ret = omap_mcbsp_st_init(pdev);
+       if (ret)
+               goto err_st;
+
+       return 0;
+
+err_st:
+       if (mcbsp->pdata->buffer_size)
+               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+err_thres:
+       clk_put(mcbsp->fclk);
+       return ret;
+}
+
+/*
+ * Stream DMA parameters. DMA request line and port address are set runtime
+ * since they are different between OMAP1 and later OMAPs
+ */
+static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
+               unsigned int packet_size)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       int words;
+
+       /* No need to proceed further if McBSP does not have FIFO */
+       if (mcbsp->pdata->buffer_size == 0)
+               return;
+
+       /*
+        * Configure McBSP threshold based on either:
+        * packet_size, when the sDMA is in packet mode, or based on the
+        * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
+        * for mono streams.
+        */
+       if (packet_size)
+               words = packet_size;
+       else
+               words = 1;
+
+       /* Configure McBSP internal buffer usage */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               omap_mcbsp_set_tx_threshold(mcbsp, words);
+       else
+               omap_mcbsp_set_rx_threshold(mcbsp, words);
+}
+
+static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
+                                   struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *buffer_size = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct omap_mcbsp *mcbsp = rule->private;
+       struct snd_interval frames;
+       int size;
+
+       snd_interval_any(&frames);
+       size = mcbsp->pdata->buffer_size;
+
+       frames.min = size / channels->min;
+       frames.integer = 1;
+       return snd_interval_refine(buffer_size, &frames);
+}
+
+static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *cpu_dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       int err = 0;
+
+       if (!cpu_dai->active)
+               err = omap_mcbsp_request(mcbsp);
+
+       /*
+        * OMAP3 McBSP FIFO is word structured.
+        * McBSP2 has 1024 + 256 = 1280 word long buffer,
+        * McBSP1,3,4,5 has 128 word long buffer
+        * This means that the size of the FIFO depends on the sample format.
+        * For example on McBSP3:
+        * 16bit samples: size is 128 * 2 = 256 bytes
+        * 32bit samples: size is 128 * 4 = 512 bytes
+        * It is simpler to place constraint for buffer and period based on
+        * channels.
+        * McBSP3 as example again (16 or 32 bit samples):
+        * 1 channel (mono): size is 128 frames (128 words)
+        * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
+        * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
+        */
+       if (mcbsp->pdata->buffer_size) {
+               /*
+               * Rule for the buffer size. We should not allow
+               * smaller buffer than the FIFO size to avoid underruns.
+               * This applies only for the playback stream.
+               */
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       snd_pcm_hw_rule_add(substream->runtime, 0,
+                                           SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                           omap_mcbsp_hwrule_min_buffersize,
+                                           mcbsp,
+                                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+               /* Make sure, that the period size is always even */
+               snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+       }
+
+       return err;
+}
+
+static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *cpu_dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
+       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+
+       if (mcbsp->latency[stream2])
+               pm_qos_update_request(&mcbsp->pm_qos_req,
+                                     mcbsp->latency[stream2]);
+       else if (mcbsp->latency[stream1])
+               pm_qos_remove_request(&mcbsp->pm_qos_req);
+
+       mcbsp->latency[stream1] = 0;
+
+       if (!cpu_dai->active) {
+               omap_mcbsp_free(mcbsp);
+               mcbsp->configured = 0;
+       }
+}
+
+static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *cpu_dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req;
+       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
+       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+       int latency = mcbsp->latency[stream2];
+
+       /* Prevent omap hardware from hitting off between FIFO fills */
+       if (!latency || mcbsp->latency[stream1] < latency)
+               latency = mcbsp->latency[stream1];
+
+       if (pm_qos_request_active(pm_qos_req))
+               pm_qos_update_request(pm_qos_req, latency);
+       else if (latency)
+               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
+
+       return 0;
+}
+
+static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                                 struct snd_soc_dai *cpu_dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               mcbsp->active++;
+               omap_mcbsp_start(mcbsp, substream->stream);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               omap_mcbsp_stop(mcbsp, substream->stream);
+               mcbsp->active--;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_sframes_t omap_mcbsp_dai_delay(
+                       struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       u16 fifo_use;
+       snd_pcm_sframes_t delay;
+
+       /* No need to proceed further if McBSP does not have FIFO */
+       if (mcbsp->pdata->buffer_size == 0)
+               return 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
+       else
+               fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
+
+       /*
+        * Divide the used locations with the channel count to get the
+        * FIFO usage in samples (don't care about partial samples in the
+        * buffer).
+        */
+       delay = fifo_use / substream->runtime->channels;
+
+       return delay;
+}
+
+static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *cpu_dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       int wlen, channels, wpf;
+       int pkt_size = 0;
+       unsigned int format, div, framesize, master;
+       unsigned int buffer_size = mcbsp->pdata->buffer_size;
+
+       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       channels = params_channels(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               wlen = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               wlen = 32;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (buffer_size) {
+               int latency;
+
+               if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
+                       int period_words, max_thrsh;
+                       int divider = 0;
+
+                       period_words = params_period_bytes(params) / (wlen / 8);
+                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               max_thrsh = mcbsp->max_tx_thres;
+                       else
+                               max_thrsh = mcbsp->max_rx_thres;
+                       /*
+                        * Use sDMA packet mode if McBSP is in threshold mode:
+                        * If period words less than the FIFO size the packet
+                        * size is set to the number of period words, otherwise
+                        * Look for the biggest threshold value which divides
+                        * the period size evenly.
+                        */
+                       divider = period_words / max_thrsh;
+                       if (period_words % max_thrsh)
+                               divider++;
+                       while (period_words % divider &&
+                               divider < period_words)
+                               divider++;
+                       if (divider == period_words)
+                               return -EINVAL;
+
+                       pkt_size = period_words / divider;
+               } else if (channels > 1) {
+                       /* Use packet mode for non mono streams */
+                       pkt_size = channels;
+               }
+
+               latency = (buffer_size - pkt_size) / channels;
+               latency = latency * USEC_PER_SEC /
+                         (params->rate_num / params->rate_den);
+               mcbsp->latency[substream->stream] = latency;
+
+               omap_mcbsp_set_threshold(substream, pkt_size);
+       }
+
+       dma_data->maxburst = pkt_size;
+
+       if (mcbsp->configured) {
+               /* McBSP already configured by another stream */
+               return 0;
+       }
+
+       regs->rcr2      &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7));
+       regs->xcr2      &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
+       regs->rcr1      &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
+       regs->xcr1      &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
+       format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+       wpf = channels;
+       if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
+                             format == SND_SOC_DAIFMT_LEFT_J)) {
+               /* Use dual-phase frames */
+               regs->rcr2      |= RPHASE;
+               regs->xcr2      |= XPHASE;
+               /* Set 1 word per (McBSP) frame for phase1 and phase2 */
+               wpf--;
+               regs->rcr2      |= RFRLEN2(wpf - 1);
+               regs->xcr2      |= XFRLEN2(wpf - 1);
+       }
+
+       regs->rcr1      |= RFRLEN1(wpf - 1);
+       regs->xcr1      |= XFRLEN1(wpf - 1);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               /* Set word lengths */
+               regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_16);
+               regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_16);
+               regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_16);
+               regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_16);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               /* Set word lengths */
+               regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_32);
+               regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_32);
+               regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_32);
+               regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_32);
+               break;
+       default:
+               /* Unsupported PCM format */
+               return -EINVAL;
+       }
+
+       /* In McBSP master modes, FRAME (i.e. sample rate) is generated
+        * by _counting_ BCLKs. Calculate frame size in BCLKs */
+       master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
+               div = mcbsp->clk_div ? mcbsp->clk_div : 1;
+               framesize = (mcbsp->in_freq / div) / params_rate(params);
+
+               if (framesize < wlen * channels) {
+                       printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
+                                       "channels\n", __func__);
+                       return -EINVAL;
+               }
+       } else
+               framesize = wlen * channels;
+
+       /* Set FS period and length in terms of bit clock periods */
+       regs->srgr2     &= ~FPER(0xfff);
+       regs->srgr1     &= ~FWID(0xff);
+       switch (format) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+               regs->srgr2     |= FPER(framesize - 1);
+               regs->srgr1     |= FWID((framesize >> 1) - 1);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               regs->srgr2     |= FPER(framesize - 1);
+               regs->srgr1     |= FWID(0);
+               break;
+       }
+
+       omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
+       mcbsp->wlen = wlen;
+       mcbsp->configured = 1;
+
+       return 0;
+}
+
+/*
+ * This must be called before _set_clkdiv and _set_sysclk since McBSP register
+ * cache is initialized here
+ */
+static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+                                     unsigned int fmt)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
+       bool inv_fs = false;
+
+       if (mcbsp->configured)
+               return 0;
+
+       mcbsp->fmt = fmt;
+       memset(regs, 0, sizeof(*regs));
+       /* Generic McBSP register settings */
+       regs->spcr2     |= XINTM(3) | FREE;
+       regs->spcr1     |= RINTM(3);
+       /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
+       if (!mcbsp->pdata->has_ccr) {
+               regs->rcr2      |= RFIG;
+               regs->xcr2      |= XFIG;
+       }
+
+       /* Configure XCCR/RCCR only for revisions which have ccr registers */
+       if (mcbsp->pdata->has_ccr) {
+               regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
+               regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               /* 1-bit data delay */
+               regs->rcr2      |= RDATDLY(1);
+               regs->xcr2      |= XDATDLY(1);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /* 0-bit data delay */
+               regs->rcr2      |= RDATDLY(0);
+               regs->xcr2      |= XDATDLY(0);
+               regs->spcr1     |= RJUST(2);
+               /* Invert FS polarity configuration */
+               inv_fs = true;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* 1-bit data delay */
+               regs->rcr2      |= RDATDLY(1);
+               regs->xcr2      |= XDATDLY(1);
+               /* Invert FS polarity configuration */
+               inv_fs = true;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               /* 0-bit data delay */
+               regs->rcr2      |= RDATDLY(0);
+               regs->xcr2      |= XDATDLY(0);
+               /* Invert FS polarity configuration */
+               inv_fs = true;
+               break;
+       default:
+               /* Unsupported data format */
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* McBSP master. Set FS and bit clocks as outputs */
+               regs->pcr0      |= FSXM | FSRM |
+                                  CLKXM | CLKRM;
+               /* Sample rate generator drives the FS */
+               regs->srgr2     |= FSGM;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               /* McBSP slave. FS clock as output */
+               regs->srgr2     |= FSGM;
+               regs->pcr0      |= FSXM | FSRM;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* McBSP slave */
+               break;
+       default:
+               /* Unsupported master/slave configuration */
+               return -EINVAL;
+       }
+
+       /* Set bit clock (CLKX/CLKR) and FS polarities */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /*
+                * Normal BCLK + FS.
+                * FS active low. TX data driven on falling edge of bit clock
+                * and RX data sampled on rising edge of bit clock.
+                */
+               regs->pcr0      |= FSXP | FSRP |
+                                  CLKXP | CLKRP;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               regs->pcr0      |= CLKXP | CLKRP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               regs->pcr0      |= FSXP | FSRP;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (inv_fs == true)
+               regs->pcr0 ^= FSXP | FSRP;
+
+       return 0;
+}
+
+static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                    int div_id, int div)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
+
+       if (div_id != OMAP_MCBSP_CLKGDV)
+               return -ENODEV;
+
+       mcbsp->clk_div = div;
+       regs->srgr1     &= ~CLKGDV(0xff);
+       regs->srgr1     |= CLKGDV(div - 1);
+
+       return 0;
+}
+
+static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+                                        int clk_id, unsigned int freq,
+                                        int dir)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
+       int err = 0;
+
+       if (mcbsp->active) {
+               if (freq == mcbsp->in_freq)
+                       return 0;
+               else
+                       return -EBUSY;
+       }
+
+       mcbsp->in_freq = freq;
+       regs->srgr2 &= ~CLKSM;
+       regs->pcr0 &= ~SCLKME;
+
+       switch (clk_id) {
+       case OMAP_MCBSP_SYSCLK_CLK:
+               regs->srgr2     |= CLKSM;
+               break;
+       case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
+               if (mcbsp_omap1()) {
+                       err = -EINVAL;
+                       break;
+               }
+               err = omap2_mcbsp_set_clks_src(mcbsp,
+                                              MCBSP_CLKS_PRCM_SRC);
+               break;
+       case OMAP_MCBSP_SYSCLK_CLKS_EXT:
+               if (mcbsp_omap1()) {
+                       err = 0;
+                       break;
+               }
+               err = omap2_mcbsp_set_clks_src(mcbsp,
+                                              MCBSP_CLKS_PAD_SRC);
+               break;
+
+       case OMAP_MCBSP_SYSCLK_CLKX_EXT:
+               regs->srgr2     |= CLKSM;
+               regs->pcr0      |= SCLKME;
+               /*
+                * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
+                * disable output on those pins. This enables to inject the
+                * reference clock through CLKX/CLKR. For this to work
+                * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
+                */
+               regs->pcr0      &= ~CLKXM;
+               break;
+       case OMAP_MCBSP_SYSCLK_CLKR_EXT:
+               regs->pcr0      |= SCLKME;
+               /* Disable ouput on CLKR pin in master mode */
+               regs->pcr0      &= ~CLKRM;
+               break;
+       default:
+               err = -ENODEV;
+       }
+
+       return err;
+}
+
+static const struct snd_soc_dai_ops mcbsp_dai_ops = {
+       .startup        = omap_mcbsp_dai_startup,
+       .shutdown       = omap_mcbsp_dai_shutdown,
+       .prepare        = omap_mcbsp_dai_prepare,
+       .trigger        = omap_mcbsp_dai_trigger,
+       .delay          = omap_mcbsp_dai_delay,
+       .hw_params      = omap_mcbsp_dai_hw_params,
+       .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
+       .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
+       .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
+};
+
+static int omap_mcbsp_probe(struct snd_soc_dai *dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_enable(mcbsp->dev);
+
+       snd_soc_dai_init_dma_data(dai,
+                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+                                 &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+       return 0;
+}
+
+static int omap_mcbsp_remove(struct snd_soc_dai *dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_disable(mcbsp->dev);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver omap_mcbsp_dai = {
+       .probe = omap_mcbsp_probe,
+       .remove = omap_mcbsp_remove,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .ops = &mcbsp_dai_ops,
+};
+
+static const struct snd_soc_component_driver omap_mcbsp_component = {
+       .name           = "omap-mcbsp",
+};
+
+static struct omap_mcbsp_platform_data omap2420_pdata = {
+       .reg_step = 4,
+       .reg_size = 2,
+};
+
+static struct omap_mcbsp_platform_data omap2430_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+};
+
+static struct omap_mcbsp_platform_data omap3_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static struct omap_mcbsp_platform_data omap4_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static const struct of_device_id omap_mcbsp_of_match[] = {
+       {
+               .compatible = "ti,omap2420-mcbsp",
+               .data = &omap2420_pdata,
+       },
+       {
+               .compatible = "ti,omap2430-mcbsp",
+               .data = &omap2430_pdata,
+       },
+       {
+               .compatible = "ti,omap3-mcbsp",
+               .data = &omap3_pdata,
+       },
+       {
+               .compatible = "ti,omap4-mcbsp",
+               .data = &omap4_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match);
+
+static int asoc_mcbsp_probe(struct platform_device *pdev)
+{
+       struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct omap_mcbsp *mcbsp;
+       const struct of_device_id *match;
+       int ret;
+
+       match = of_match_device(omap_mcbsp_of_match, &pdev->dev);
+       if (match) {
+               struct device_node *node = pdev->dev.of_node;
+               struct omap_mcbsp_platform_data *pdata_quirk = pdata;
+               int buffer_size;
+
+               pdata = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct omap_mcbsp_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               memcpy(pdata, match->data, sizeof(*pdata));
+               if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size))
+                       pdata->buffer_size = buffer_size;
+               if (pdata_quirk)
+                       pdata->force_ick_on = pdata_quirk->force_ick_on;
+       } else if (!pdata) {
+               dev_err(&pdev->dev, "missing platform data.\n");
+               return -EINVAL;
+       }
+       mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
+       if (!mcbsp)
+               return -ENOMEM;
+
+       mcbsp->id = pdev->id;
+       mcbsp->pdata = pdata;
+       mcbsp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mcbsp);
+
+       ret = omap_mcbsp_init(pdev);
+       if (ret)
+               return ret;
+
+       if (mcbsp->pdata->reg_size == 2) {
+               omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
+               omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &omap_mcbsp_component,
+                                             &omap_mcbsp_dai, 1);
+       if (ret)
+               return ret;
+
+       return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+}
+
+static int asoc_mcbsp_remove(struct platform_device *pdev)
+{
+       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+       if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(mcbsp->id);
+
+       if (pm_qos_request_active(&mcbsp->pm_qos_req))
+               pm_qos_remove_request(&mcbsp->pm_qos_req);
+
+       if (mcbsp->pdata->buffer_size)
+               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+       omap_mcbsp_st_cleanup(pdev);
+
+       clk_put(mcbsp->fclk);
+
+       return 0;
+}
+
+static struct platform_driver asoc_mcbsp_driver = {
+       .driver = {
+                       .name = "omap-mcbsp",
+                       .of_match_table = omap_mcbsp_of_match,
+       },
+
+       .probe = asoc_mcbsp_probe,
+       .remove = asoc_mcbsp_remove,
+};
+
+module_platform_driver(asoc_mcbsp_driver);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
+MODULE_DESCRIPTION("OMAP I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-mcbsp");
diff --git a/sound/soc/ti/omap-mcbsp.h b/sound/soc/ti/omap-mcbsp.h
new file mode 100644 (file)
index 0000000..7911d24
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * omap-mcbsp.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_MCBSP_H__
+#define __OMAP_MCBSP_H__
+
+#include <sound/dmaengine_pcm.h>
+
+/* Source clocks for McBSP sample rate generator */
+enum omap_mcbsp_clksrg_clk {
+       OMAP_MCBSP_SYSCLK_CLKS_FCLK,    /* Internal FCLK */
+       OMAP_MCBSP_SYSCLK_CLKS_EXT,     /* External CLKS pin */
+       OMAP_MCBSP_SYSCLK_CLK,          /* Internal ICLK */
+       OMAP_MCBSP_SYSCLK_CLKX_EXT,     /* External CLKX pin */
+       OMAP_MCBSP_SYSCLK_CLKR_EXT,     /* External CLKR pin */
+};
+
+/* McBSP dividers */
+enum omap_mcbsp_div {
+       OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
+};
+
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
+
+#endif /* __OMAP_MCBSP_H__ */
diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c
new file mode 100644 (file)
index 0000000..7d5bdc5
--- /dev/null
@@ -0,0 +1,619 @@
+/*
+ * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
+ *
+ * Copyright (C) 2009 - 2011 Texas Instruments
+ *
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
+ * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
+ *          Margarita Olaya <magi.olaya@ti.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "omap-mcpdm.h"
+#include "sdma-pcm.h"
+
+struct mcpdm_link_config {
+       u32 link_mask; /* channel mask for the direction */
+       u32 threshold; /* FIFO threshold */
+};
+
+struct omap_mcpdm {
+       struct device *dev;
+       unsigned long phys_base;
+       void __iomem *io_base;
+       int irq;
+       struct pm_qos_request pm_qos_req;
+       int latency[2];
+
+       struct mutex mutex;
+
+       /* Playback/Capture configuration */
+       struct mcpdm_link_config config[2];
+
+       /* McPDM dn offsets for rx1, and 2 channels */
+       u32 dn_rx_offset;
+
+       /* McPDM needs to be restarted due to runtime reconfiguration */
+       bool restart;
+
+       /* pm state for suspend/resume handling */
+       int pm_active_count;
+
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+};
+
+/*
+ * Stream DMA parameters
+ */
+
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
+{
+       writel_relaxed(val, mcpdm->io_base + reg);
+}
+
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+       return readl_relaxed(mcpdm->io_base + reg);
+}
+
+#ifdef DEBUG
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
+{
+       dev_dbg(mcpdm->dev, "***********************\n");
+       dev_dbg(mcpdm->dev, "IRQSTATUS_RAW:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
+       dev_dbg(mcpdm->dev, "IRQSTATUS:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
+       dev_dbg(mcpdm->dev, "IRQENABLE_SET:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
+       dev_dbg(mcpdm->dev, "IRQENABLE_CLR:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
+       dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
+       dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
+       dev_dbg(mcpdm->dev, "DMAENABLE_CLR:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
+       dev_dbg(mcpdm->dev, "DMAWAKEEN:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
+       dev_dbg(mcpdm->dev, "CTRL:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
+       dev_dbg(mcpdm->dev, "DN_DATA:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
+       dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
+       dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
+       dev_dbg(mcpdm->dev, "FIFO_CTRL_UP:  0x%04x\n",
+                       omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
+       dev_dbg(mcpdm->dev, "***********************\n");
+}
+#else
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
+#endif
+
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
+{
+       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+       u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
+
+       ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+       ctrl |= link_mask;
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+       ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
+{
+       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+       u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
+
+       ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+       ctrl &= ~(link_mask);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+       ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+}
+
+/*
+ * Is the physical McPDM interface active.
+ */
+static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
+{
+       return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
+                                       (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
+}
+
+/*
+ * Configures McPDM uplink, and downlink for audio.
+ * This function should be called before omap_mcpdm_start.
+ */
+static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
+{
+       u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN);
+
+       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
+                       MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
+                       MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+       /* Enable DN RX1/2 offset cancellation feature, if configured */
+       if (mcpdm->dn_rx_offset) {
+               u32 dn_offset = mcpdm->dn_rx_offset;
+
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+               dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+       }
+
+       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
+                        mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
+                        mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
+
+       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
+                       MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
+}
+
+/*
+ * Cleans McPDM uplink, and downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
+{
+       /* Disable irq request generation for downlink */
+       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+                       MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
+
+       /* Disable DMA request generation for downlink */
+       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
+
+       /* Disable irq request generation for uplink */
+       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+                       MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+       /* Disable DMA request generation for uplink */
+       omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
+
+       /* Disable RX1/2 offset cancellation */
+       if (mcpdm->dn_rx_offset)
+               omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+       struct omap_mcpdm *mcpdm = dev_id;
+       int irq_status;
+
+       irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
+
+       /* Acknowledge irq event */
+       omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
+
+       if (irq_status & MCPDM_DN_IRQ_FULL)
+               dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
+
+       if (irq_status & MCPDM_DN_IRQ_EMPTY)
+               dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
+
+       if (irq_status & MCPDM_DN_IRQ)
+               dev_dbg(mcpdm->dev, "DN (playback) write request\n");
+
+       if (irq_status & MCPDM_UP_IRQ_FULL)
+               dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
+
+       if (irq_status & MCPDM_UP_IRQ_EMPTY)
+               dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
+
+       if (irq_status & MCPDM_UP_IRQ)
+               dev_dbg(mcpdm->dev, "UP (capture) write request\n");
+
+       return IRQ_HANDLED;
+}
+
+static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+       mutex_lock(&mcpdm->mutex);
+
+       if (!dai->active)
+               omap_mcpdm_open_streams(mcpdm);
+
+       mutex_unlock(&mcpdm->mutex);
+
+       return 0;
+}
+
+static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
+       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+
+       mutex_lock(&mcpdm->mutex);
+
+       if (!dai->active) {
+               if (omap_mcpdm_active(mcpdm)) {
+                       omap_mcpdm_stop(mcpdm);
+                       omap_mcpdm_close_streams(mcpdm);
+                       mcpdm->config[0].link_mask = 0;
+                       mcpdm->config[1].link_mask = 0;
+               }
+       }
+
+       if (mcpdm->latency[stream2])
+               pm_qos_update_request(&mcpdm->pm_qos_req,
+                                     mcpdm->latency[stream2]);
+       else if (mcpdm->latency[stream1])
+               pm_qos_remove_request(&mcpdm->pm_qos_req);
+
+       mcpdm->latency[stream1] = 0;
+
+       mutex_unlock(&mcpdm->mutex);
+}
+
+static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+       int stream = substream->stream;
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       u32 threshold;
+       int channels, latency;
+       int link_mask = 0;
+
+       channels = params_channels(params);
+       switch (channels) {
+       case 5:
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       /* up to 3 channels for capture */
+                       return -EINVAL;
+               link_mask |= 1 << 4;
+               /* fall through */
+       case 4:
+               if (stream == SNDRV_PCM_STREAM_CAPTURE)
+                       /* up to 3 channels for capture */
+                       return -EINVAL;
+               link_mask |= 1 << 3;
+               /* fall through */
+       case 3:
+               link_mask |= 1 << 2;
+               /* fall through */
+       case 2:
+               link_mask |= 1 << 1;
+               /* fall through */
+       case 1:
+               link_mask |= 1 << 0;
+               break;
+       default:
+               /* unsupported number of channels */
+               return -EINVAL;
+       }
+
+       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+
+       threshold = mcpdm->config[stream].threshold;
+       /* Configure McPDM channels, and DMA packet size */
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               link_mask <<= 3;
+
+               /* If capture is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = 0x3;
+
+               dma_data->maxburst =
+                               (MCPDM_DN_THRES_MAX - threshold) * channels;
+               latency = threshold;
+       } else {
+               /* If playback is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = (0x3 << 3);
+
+               dma_data->maxburst = threshold * channels;
+               latency = (MCPDM_DN_THRES_MAX - threshold);
+       }
+
+       /*
+        * The DMA must act to a DMA request within latency time (usec) to avoid
+        * under/overflow
+        */
+       mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params);
+
+       if (!mcpdm->latency[stream])
+               mcpdm->latency[stream] = 10;
+
+       /* Check if we need to restart McPDM with this stream */
+       if (mcpdm->config[stream].link_mask &&
+           mcpdm->config[stream].link_mask != link_mask)
+               mcpdm->restart = true;
+
+       mcpdm->config[stream].link_mask = link_mask;
+
+       return 0;
+}
+
+static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+       struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req;
+       int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
+       int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+       int latency = mcpdm->latency[stream2];
+
+       /* Prevent omap hardware from hitting off between FIFO fills */
+       if (!latency || mcpdm->latency[stream1] < latency)
+               latency = mcpdm->latency[stream1];
+
+       if (pm_qos_request_active(pm_qos_req))
+               pm_qos_update_request(pm_qos_req, latency);
+       else if (latency)
+               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
+
+       if (!omap_mcpdm_active(mcpdm)) {
+               omap_mcpdm_start(mcpdm);
+               omap_mcpdm_reg_dump(mcpdm);
+       } else if (mcpdm->restart) {
+               omap_mcpdm_stop(mcpdm);
+               omap_mcpdm_start(mcpdm);
+               mcpdm->restart = false;
+               omap_mcpdm_reg_dump(mcpdm);
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+       .startup        = omap_mcpdm_dai_startup,
+       .shutdown       = omap_mcpdm_dai_shutdown,
+       .hw_params      = omap_mcpdm_dai_hw_params,
+       .prepare        = omap_mcpdm_prepare,
+};
+
+static int omap_mcpdm_probe(struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       pm_runtime_enable(mcpdm->dev);
+
+       /* Disable lines while request is ongoing */
+       pm_runtime_get_sync(mcpdm->dev);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
+
+       ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM",
+                         (void *)mcpdm);
+
+       pm_runtime_put_sync(mcpdm->dev);
+
+       if (ret) {
+               dev_err(mcpdm->dev, "Request for IRQ failed\n");
+               pm_runtime_disable(mcpdm->dev);
+       }
+
+       /* Configure McPDM threshold values */
+       mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
+       mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
+                                                       MCPDM_UP_THRES_MAX - 3;
+
+       snd_soc_dai_init_dma_data(dai,
+                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+                                 &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+       return ret;
+}
+
+static int omap_mcpdm_remove(struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+       free_irq(mcpdm->irq, (void *)mcpdm);
+       pm_runtime_disable(mcpdm->dev);
+
+       if (pm_qos_request_active(&mcpdm->pm_qos_req))
+               pm_qos_remove_request(&mcpdm->pm_qos_req);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int omap_mcpdm_suspend(struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+       if (dai->active) {
+               omap_mcpdm_stop(mcpdm);
+               omap_mcpdm_close_streams(mcpdm);
+       }
+
+       mcpdm->pm_active_count = 0;
+       while (pm_runtime_active(mcpdm->dev)) {
+               pm_runtime_put_sync(mcpdm->dev);
+               mcpdm->pm_active_count++;
+       }
+
+       return 0;
+}
+
+static int omap_mcpdm_resume(struct snd_soc_dai *dai)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+       if (mcpdm->pm_active_count) {
+               while (mcpdm->pm_active_count--)
+                       pm_runtime_get_sync(mcpdm->dev);
+
+               if (dai->active) {
+                       omap_mcpdm_open_streams(mcpdm);
+                       omap_mcpdm_start(mcpdm);
+               }
+       }
+
+
+       return 0;
+}
+#else
+#define omap_mcpdm_suspend NULL
+#define omap_mcpdm_resume NULL
+#endif
+
+#define OMAP_MCPDM_RATES       (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define OMAP_MCPDM_FORMATS     SNDRV_PCM_FMTBIT_S32_LE
+
+static struct snd_soc_dai_driver omap_mcpdm_dai = {
+       .probe = omap_mcpdm_probe,
+       .remove = omap_mcpdm_remove,
+       .suspend = omap_mcpdm_suspend,
+       .resume = omap_mcpdm_resume,
+       .probe_order = SND_SOC_COMP_ORDER_LATE,
+       .remove_order = SND_SOC_COMP_ORDER_EARLY,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 5,
+               .rates = OMAP_MCPDM_RATES,
+               .formats = OMAP_MCPDM_FORMATS,
+               .sig_bits = 24,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 3,
+               .rates = OMAP_MCPDM_RATES,
+               .formats = OMAP_MCPDM_FORMATS,
+               .sig_bits = 24,
+       },
+       .ops = &omap_mcpdm_dai_ops,
+};
+
+static const struct snd_soc_component_driver omap_mcpdm_component = {
+       .name           = "omap-mcpdm",
+};
+
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+                                   u8 rx1, u8 rx2)
+{
+       struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+       mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
+}
+EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
+
+static int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+       struct omap_mcpdm *mcpdm;
+       struct resource *res;
+       int ret;
+
+       mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
+       if (!mcpdm)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mcpdm);
+
+       mutex_init(&mcpdm->mutex);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+       if (res == NULL)
+               return -ENOMEM;
+
+       mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
+       mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
+
+       mcpdm->dma_data[0].filter_data = "dn_link";
+       mcpdm->dma_data[1].filter_data = "up_link";
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mcpdm->io_base))
+               return PTR_ERR(mcpdm->io_base);
+
+       mcpdm->irq = platform_get_irq(pdev, 0);
+       if (mcpdm->irq < 0)
+               return mcpdm->irq;
+
+       mcpdm->dev = &pdev->dev;
+
+       ret =  devm_snd_soc_register_component(&pdev->dev,
+                                              &omap_mcpdm_component,
+                                              &omap_mcpdm_dai, 1);
+       if (ret)
+               return ret;
+
+       return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link");
+}
+
+static const struct of_device_id omap_mcpdm_of_match[] = {
+       { .compatible = "ti,omap4-mcpdm", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match);
+
+static struct platform_driver asoc_mcpdm_driver = {
+       .driver = {
+               .name   = "omap-mcpdm",
+               .of_match_table = omap_mcpdm_of_match,
+       },
+
+       .probe  = asoc_mcpdm_probe,
+};
+
+module_platform_driver(asoc_mcpdm_driver);
+
+MODULE_ALIAS("platform:omap-mcpdm");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_DESCRIPTION("OMAP PDM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/omap-mcpdm.h b/sound/soc/ti/omap-mcpdm.h
new file mode 100644 (file)
index 0000000..de8cf26
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * omap-mcpdm.h
+ *
+ * Copyright (C) 2009 - 2011 Texas Instruments
+ *
+ * Contact: Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_MCPDM_H__
+#define __OMAP_MCPDM_H__
+
+#define MCPDM_REG_REVISION             0x00
+#define MCPDM_REG_SYSCONFIG            0x10
+#define MCPDM_REG_IRQSTATUS_RAW                0x24
+#define MCPDM_REG_IRQSTATUS            0x28
+#define MCPDM_REG_IRQENABLE_SET                0x2C
+#define MCPDM_REG_IRQENABLE_CLR                0x30
+#define MCPDM_REG_IRQWAKE_EN           0x34
+#define MCPDM_REG_DMAENABLE_SET                0x38
+#define MCPDM_REG_DMAENABLE_CLR                0x3C
+#define MCPDM_REG_DMAWAKEEN            0x40
+#define MCPDM_REG_CTRL                 0x44
+#define MCPDM_REG_DN_DATA              0x48
+#define MCPDM_REG_UP_DATA              0x4C
+#define MCPDM_REG_FIFO_CTRL_DN         0x50
+#define MCPDM_REG_FIFO_CTRL_UP         0x54
+#define MCPDM_REG_DN_OFFSET            0x58
+
+/*
+ * MCPDM_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define MCPDM_DN_IRQ                   (1 << 0)
+#define MCPDM_DN_IRQ_EMPTY             (1 << 1)
+#define MCPDM_DN_IRQ_ALMST_EMPTY       (1 << 2)
+#define MCPDM_DN_IRQ_FULL              (1 << 3)
+
+#define MCPDM_UP_IRQ                   (1 << 8)
+#define MCPDM_UP_IRQ_EMPTY             (1 << 9)
+#define MCPDM_UP_IRQ_ALMST_FULL                (1 << 10)
+#define MCPDM_UP_IRQ_FULL              (1 << 11)
+
+#define MCPDM_DOWNLINK_IRQ_MASK                0x00F
+#define MCPDM_UPLINK_IRQ_MASK          0xF00
+
+/*
+ * MCPDM_DMAENABLE bit fields
+ */
+
+#define MCPDM_DMA_DN_ENABLE            (1 << 0)
+#define MCPDM_DMA_UP_ENABLE            (1 << 1)
+
+/*
+ * MCPDM_CTRL bit fields
+ */
+
+#define MCPDM_PDM_UPLINK_EN(x)         (1 << (x - 1)) /* ch1 is at bit 0 */
+#define MCPDM_PDM_DOWNLINK_EN(x)       (1 << (x + 2)) /* ch1 is at bit 3 */
+#define MCPDM_PDMOUTFORMAT             (1 << 8)
+#define MCPDM_CMD_INT                  (1 << 9)
+#define MCPDM_STATUS_INT               (1 << 10)
+#define MCPDM_SW_UP_RST                        (1 << 11)
+#define MCPDM_SW_DN_RST                        (1 << 12)
+#define MCPDM_WD_EN                    (1 << 14)
+#define MCPDM_PDM_UP_MASK              0x7
+#define MCPDM_PDM_DN_MASK              (0x1f << 3)
+
+
+#define MCPDM_PDMOUTFORMAT_LJUST       (0 << 8)
+#define MCPDM_PDMOUTFORMAT_RJUST       (1 << 8)
+
+/*
+ * MCPDM_FIFO_CTRL bit fields
+ */
+
+#define MCPDM_UP_THRES_MAX             0xF
+#define MCPDM_DN_THRES_MAX             0xF
+
+/*
+ * MCPDM_DN_OFFSET bit fields
+ */
+
+#define MCPDM_DN_OFST_RX1_EN           (1 << 0)
+#define MCPDM_DNOFST_RX1(x)            ((x & 0x1f) << 1)
+#define MCPDM_DN_OFST_RX2_EN           (1 << 8)
+#define MCPDM_DNOFST_RX2(x)            ((x & 0x1f) << 9)
+
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+                                   u8 rx1, u8 rx2);
+
+#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
new file mode 100644 (file)
index 0000000..cccc316
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * omap-twl4030.c  --  SoC audio for TI SoC based boards with twl4030 codec
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This driver replaces the following machine drivers:
+ * omap3beagle (Author: Steve Sakoman <steve@sakoman.com>)
+ * omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>)
+ * overo (Author: Steve Sakoman <steve@sakoman.com>)
+ * igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>)
+ * zoom2 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
+ * sdp3430 (Author: Misael Lopez Cruz <misael.lopez@ti.com>)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/platform_data/omap-twl4030.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "omap-mcbsp.h"
+
+struct omap_twl4030 {
+       int jack_detect;        /* board can detect jack events */
+       struct snd_soc_jack hs_jack;
+};
+
+static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int fmt;
+
+       switch (params_channels(params)) {
+       case 2: /* Stereo I2S mode */
+               fmt =   SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       case 4: /* Four channel TDM mode */
+               fmt =   SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_runtime_set_dai_fmt(rtd, fmt);
+}
+
+static const struct snd_soc_ops omap_twl4030_ops = {
+       .hw_params = omap_twl4030_hw_params,
+};
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Earpiece Spk", NULL),
+       SND_SOC_DAPM_SPK("Handsfree Spk", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_SPK("Carkit Spk", NULL),
+
+       SND_SOC_DAPM_MIC("Main Mic", NULL),
+       SND_SOC_DAPM_MIC("Sub Mic", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Carkit Mic", NULL),
+       SND_SOC_DAPM_MIC("Digital0 Mic", NULL),
+       SND_SOC_DAPM_MIC("Digital1 Mic", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Headset Stereophone:  HSOL, HSOR */
+       {"Headset Stereophone", NULL, "HSOL"},
+       {"Headset Stereophone", NULL, "HSOR"},
+       /* External Speakers: HFL, HFR */
+       {"Handsfree Spk", NULL, "HFL"},
+       {"Handsfree Spk", NULL, "HFR"},
+       /* External Speakers: PredrivL, PredrivR */
+       {"Ext Spk", NULL, "PREDRIVEL"},
+       {"Ext Spk", NULL, "PREDRIVER"},
+       /* Carkit speakers:  CARKITL, CARKITR */
+       {"Carkit Spk", NULL, "CARKITL"},
+       {"Carkit Spk", NULL, "CARKITR"},
+       /* Earpiece */
+       {"Earpiece Spk", NULL, "EARPIECE"},
+
+       /* External Mics: MAINMIC, SUBMIC with bias */
+       {"MAINMIC", NULL, "Main Mic"},
+       {"Main Mic", NULL, "Mic Bias 1"},
+       {"SUBMIC", NULL, "Sub Mic"},
+       {"Sub Mic", NULL, "Mic Bias 2"},
+       /* Headset Mic: HSMIC with bias */
+       {"HSMIC", NULL, "Headset Mic"},
+       {"Headset Mic", NULL, "Headset Mic Bias"},
+       /* Digital Mics: DIGIMIC0, DIGIMIC1 with bias */
+       {"DIGIMIC0", NULL, "Digital0 Mic"},
+       {"Digital0 Mic", NULL, "Mic Bias 1"},
+       {"DIGIMIC1", NULL, "Digital1 Mic"},
+       {"Digital1 Mic", NULL, "Mic Bias 2"},
+       /* Carkit In: CARKITMIC */
+       {"CARKITMIC", NULL, "Carkit Mic"},
+       /* Aux In: AUXL, AUXR */
+       {"AUXL", NULL, "Line In"},
+       {"AUXR", NULL, "Line In"},
+};
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+       {
+               .name = "hsdet-gpio",
+               .report = SND_JACK_HEADSET,
+               .debounce_time = 200,
+       },
+};
+
+static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
+                                         int connected, char *pin)
+{
+       if (!connected)
+               snd_soc_dapm_disable_pin(dapm, pin);
+}
+
+static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+       struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
+       struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
+       int ret = 0;
+
+       /* Headset jack detection only if it is supported */
+       if (priv->jack_detect > 0) {
+               hs_jack_gpios[0].gpio = priv->jack_detect;
+
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &priv->hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
+               if (ret)
+                       return ret;
+
+               ret = snd_soc_jack_add_gpios(&priv->hs_jack,
+                                            ARRAY_SIZE(hs_jack_gpios),
+                                            hs_jack_gpios);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * NULL pdata means we booted with DT. In this case the routing is
+        * provided and the card is fully routed, no need to mark pins.
+        */
+       if (!pdata || !pdata->custom_routing)
+               return ret;
+
+       /* Disable not connected paths if not used */
+       twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk");
+       twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk");
+       twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
+       twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk");
+       twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk");
+
+       twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic");
+       twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In");
+
+       return ret;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
+       {
+               .name = "TWL4030 HiFi",
+               .stream_name = "TWL4030 HiFi",
+               .cpu_dai_name = "omap-mcbsp.2",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-mcbsp.2",
+               .codec_name = "twl4030-codec",
+               .init = omap_twl4030_init,
+               .ops = &omap_twl4030_ops,
+       },
+       {
+               .name = "TWL4030 Voice",
+               .stream_name = "TWL4030 Voice",
+               .cpu_dai_name = "omap-mcbsp.3",
+               .codec_dai_name = "twl4030-voice",
+               .platform_name = "omap-mcbsp.3",
+               .codec_name = "twl4030-codec",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+                          SND_SOC_DAIFMT_CBM_CFM,
+       },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card omap_twl4030_card = {
+       .owner = THIS_MODULE,
+       .dai_link = omap_twl4030_dai_links,
+       .num_links = ARRAY_SIZE(omap_twl4030_dai_links),
+
+       .dapm_widgets = dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int omap_twl4030_probe(struct platform_device *pdev)
+{
+       struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *node = pdev->dev.of_node;
+       struct snd_soc_card *card = &omap_twl4030_card;
+       struct omap_twl4030 *priv;
+       int ret = 0;
+
+       card->dev = &pdev->dev;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_twl4030), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       if (node) {
+               struct device_node *dai_node;
+               struct property *prop;
+
+               if (snd_soc_of_parse_card_name(card, "ti,model")) {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McBSP node is not provided\n");
+                       return -EINVAL;
+               }
+               omap_twl4030_dai_links[0].cpu_dai_name  = NULL;
+               omap_twl4030_dai_links[0].cpu_of_node = dai_node;
+
+               omap_twl4030_dai_links[0].platform_name  = NULL;
+               omap_twl4030_dai_links[0].platform_of_node = dai_node;
+
+               dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
+               if (!dai_node) {
+                       card->num_links = 1;
+               } else {
+                       omap_twl4030_dai_links[1].cpu_dai_name  = NULL;
+                       omap_twl4030_dai_links[1].cpu_of_node = dai_node;
+
+                       omap_twl4030_dai_links[1].platform_name  = NULL;
+                       omap_twl4030_dai_links[1].platform_of_node = dai_node;
+               }
+
+               priv->jack_detect = of_get_named_gpio(node,
+                                                     "ti,jack-det-gpio", 0);
+
+               /* Optional: audio routing can be provided */
+               prop = of_find_property(node, "ti,audio-routing", NULL);
+               if (prop) {
+                       ret = snd_soc_of_parse_audio_routing(card,
+                                                           "ti,audio-routing");
+                       if (ret)
+                               return ret;
+
+                       card->fully_routed = 1;
+               }
+       } else if (pdata) {
+               if (pdata->card_name) {
+                       card->name = pdata->card_name;
+               } else {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               if (!pdata->voice_connected)
+                       card->num_links = 1;
+
+               priv->jack_detect = pdata->jack_detect;
+       } else {
+               dev_err(&pdev->dev, "Missing pdata\n");
+               return -ENODEV;
+       }
+
+       snd_soc_card_set_drvdata(card, priv);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret) {
+               dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id omap_twl4030_of_match[] = {
+       {.compatible = "ti,omap-twl4030", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_twl4030_of_match);
+
+static struct platform_driver omap_twl4030_driver = {
+       .driver = {
+               .name = "omap-twl4030",
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = omap_twl4030_of_match,
+       },
+       .probe = omap_twl4030_probe,
+};
+
+module_platform_driver(omap_twl4030_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-twl4030");
diff --git a/sound/soc/ti/omap3pandora.c b/sound/soc/ti/omap3pandora.c
new file mode 100644 (file)
index 0000000..4e3de71
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * omap3pandora.c  --  SoC audio for Pandora Handheld Console
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "omap-mcbsp.h"
+
+#define OMAP3_PANDORA_DAC_POWER_GPIO   118
+#define OMAP3_PANDORA_AMP_POWER_GPIO   14
+
+#define PREFIX "ASoC omap3pandora: "
+
+static struct regulator *omap3pandora_dac_reg;
+
+static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret;
+
+       /* Set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+                                           SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err(PREFIX "can't set codec system clock\n");
+               return ret;
+       }
+
+       /* Set McBSP clock to external */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
+                                    256 * params_rate(params),
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err(PREFIX "can't set cpu system clock\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
+       if (ret < 0) {
+               pr_err(PREFIX "can't set SRG clock divider\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *k, int event)
+{
+       int ret;
+
+       /*
+        * The PCM1773 DAC datasheet requires 1ms delay between switching
+        * VCC power on/off and /PD pin high/low
+        */
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = regulator_enable(omap3pandora_dac_reg);
+               if (ret) {
+                       dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
+                       return ret;
+               }
+               mdelay(1);
+               gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
+       } else {
+               gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
+               mdelay(1);
+               regulator_disable(omap3pandora_dac_reg);
+       }
+
+       return 0;
+}
+
+static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *k, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
+       else
+               gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
+
+       return 0;
+}
+
+/*
+ * Audio paths on Pandora board:
+ *
+ *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
+ *  |M|         A    +--------> Line Out
+ *  |A| <~~clk~~+
+ *  |P| <--- TWL4030 <--------- Line In and MICs
+ */
+static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
+                          0, 0, omap3pandora_dac_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
+                          0, 0, NULL, 0, omap3pandora_hp_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+
+       SND_SOC_DAPM_MIC("Mic (internal)", NULL),
+       SND_SOC_DAPM_MIC("Mic (external)", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route omap3pandora_map[] = {
+       {"PCM DAC", NULL, "APLL Enable"},
+       {"Headphone Amplifier", NULL, "PCM DAC"},
+       {"Line Out", NULL, "PCM DAC"},
+       {"Headphone Jack", NULL, "Headphone Amplifier"},
+
+       {"AUXL", NULL, "Line In"},
+       {"AUXR", NULL, "Line In"},
+
+       {"MAINMIC", NULL, "Mic (internal)"},
+       {"Mic (internal)", NULL, "Mic Bias 1"},
+
+       {"SUBMIC", NULL, "Mic (external)"},
+       {"Mic (external)", NULL, "Mic Bias 2"},
+};
+
+static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+
+       /* All TWL4030 output pins are floating */
+       snd_soc_dapm_nc_pin(dapm, "EARPIECE");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
+       snd_soc_dapm_nc_pin(dapm, "HSOL");
+       snd_soc_dapm_nc_pin(dapm, "HSOR");
+       snd_soc_dapm_nc_pin(dapm, "CARKITL");
+       snd_soc_dapm_nc_pin(dapm, "CARKITR");
+       snd_soc_dapm_nc_pin(dapm, "HFL");
+       snd_soc_dapm_nc_pin(dapm, "HFR");
+       snd_soc_dapm_nc_pin(dapm, "VIBRA");
+
+       return 0;
+}
+
+static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+
+       /* Not comnnected */
+       snd_soc_dapm_nc_pin(dapm, "HSMIC");
+       snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
+
+       return 0;
+}
+
+static const struct snd_soc_ops omap3pandora_ops = {
+       .hw_params = omap3pandora_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap3pandora_dai[] = {
+       {
+               .name = "PCM1773",
+               .stream_name = "HiFi Out",
+               .cpu_dai_name = "omap-mcbsp.2",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-mcbsp.2",
+               .codec_name = "twl4030-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .ops = &omap3pandora_ops,
+               .init = omap3pandora_out_init,
+       }, {
+               .name = "TWL4030",
+               .stream_name = "Line/Mic In",
+               .cpu_dai_name = "omap-mcbsp.4",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-mcbsp.4",
+               .codec_name = "twl4030-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .ops = &omap3pandora_ops,
+               .init = omap3pandora_in_init,
+       }
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_omap3pandora = {
+       .name = "omap3pandora",
+       .owner = THIS_MODULE,
+       .dai_link = omap3pandora_dai,
+       .num_links = ARRAY_SIZE(omap3pandora_dai),
+
+       .dapm_widgets = omap3pandora_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
+       .dapm_routes = omap3pandora_map,
+       .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
+};
+
+static struct platform_device *omap3pandora_snd_device;
+
+static int __init omap3pandora_soc_init(void)
+{
+       int ret;
+
+       if (!machine_is_omap3_pandora())
+               return -ENODEV;
+
+       pr_info("OMAP3 Pandora SoC init\n");
+
+       ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
+       if (ret) {
+               pr_err(PREFIX "Failed to get DAC power GPIO\n");
+               return ret;
+       }
+
+       ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
+       if (ret) {
+               pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
+               goto fail0;
+       }
+
+       ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
+       if (ret) {
+               pr_err(PREFIX "Failed to get amp power GPIO\n");
+               goto fail0;
+       }
+
+       ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
+       if (ret) {
+               pr_err(PREFIX "Failed to set amp power GPIO direction\n");
+               goto fail1;
+       }
+
+       omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
+       if (omap3pandora_snd_device == NULL) {
+               pr_err(PREFIX "Platform device allocation failed\n");
+               ret = -ENOMEM;
+               goto fail1;
+       }
+
+       platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
+
+       ret = platform_device_add(omap3pandora_snd_device);
+       if (ret) {
+               pr_err(PREFIX "Unable to add platform device\n");
+               goto fail2;
+       }
+
+       omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
+       if (IS_ERR(omap3pandora_dac_reg)) {
+               pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
+                       dev_name(&omap3pandora_snd_device->dev),
+                       PTR_ERR(omap3pandora_dac_reg));
+               ret = PTR_ERR(omap3pandora_dac_reg);
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       platform_device_del(omap3pandora_snd_device);
+fail2:
+       platform_device_put(omap3pandora_snd_device);
+fail1:
+       gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
+fail0:
+       gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
+       return ret;
+}
+module_init(omap3pandora_soc_init);
+
+static void __exit omap3pandora_soc_exit(void)
+{
+       regulator_put(omap3pandora_dac_reg);
+       platform_device_unregister(omap3pandora_snd_device);
+       gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
+       gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
+}
+module_exit(omap3pandora_soc_exit);
+
+MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/osk5912.c b/sound/soc/ti/osk5912.c
new file mode 100644 (file)
index 0000000..e409677
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * osk5912.c  --  SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS  <arunks@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK    12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+       return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+       clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int err;
+
+       /* Set the codec system clock for DAC and ADC */
+       err =
+           snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return err;
+       }
+
+       return err;
+}
+
+static const struct snd_soc_ops osk_ops = {
+       .startup = osk_startup,
+       .hw_params = osk_hw_params,
+       .shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "LHPOUT"},
+       {"Headphone Jack", NULL, "RHPOUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+
+       {"MICIN", NULL, "Mic Jack"},
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .cpu_dai_name = "omap-mcbsp.1",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "omap-mcbsp.1",
+       .codec_name = "tlv320aic23-codec",
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
+       .ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_card_osk = {
+       .name = "OSK5912",
+       .owner = THIS_MODULE,
+       .dai_link = &osk_dai,
+       .num_links = 1,
+
+       .dapm_widgets = tlv320aic23_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+       int err;
+       u32 curRate;
+       struct device *dev;
+
+       if (!(machine_is_omap_osk()))
+               return -ENODEV;
+
+       osk_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!osk_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
+       err = platform_device_add(osk_snd_device);
+       if (err)
+               goto err1;
+
+       dev = &osk_snd_device->dev;
+
+       tlv320aic23_mclk = clk_get(dev, "mclk");
+       if (IS_ERR(tlv320aic23_mclk)) {
+               printk(KERN_ERR "Could not get mclk clock\n");
+               err = PTR_ERR(tlv320aic23_mclk);
+               goto err2;
+       }
+
+       /*
+        * Configure 12 MHz output on MCLK.
+        */
+       curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+                       err = -ECANCELED;
+                       goto err3;
+               }
+       }
+
+       printk(KERN_INFO "MCLK = %d [%d]\n",
+              (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+
+       return 0;
+
+err3:
+       clk_put(tlv320aic23_mclk);
+err2:
+       platform_device_del(osk_snd_device);
+err1:
+       platform_device_put(osk_snd_device);
+
+       return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+       clk_put(tlv320aic23_mclk);
+       platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c
new file mode 100644 (file)
index 0000000..57448bd
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * rx51.c  --  SoC audio for Nokia RX-51
+ *
+ * Copyright (C) 2008 - 2009 Nokia Corporation
+ *
+ * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *          Eduardo Valentin <eduardo.valentin@nokia.com>
+ *          Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include <asm/mach-types.h>
+
+#include "omap-mcbsp.h"
+
+enum {
+       RX51_JACK_DISABLED,
+       RX51_JACK_TVOUT,                /* tv-out with stereo output */
+       RX51_JACK_HP,                   /* headphone: stereo output, no mic */
+       RX51_JACK_HS,                   /* headset: stereo output with mic */
+};
+
+struct rx51_audio_pdata {
+       struct gpio_desc *tvout_selection_gpio;
+       struct gpio_desc *jack_detection_gpio;
+       struct gpio_desc *eci_sw_gpio;
+       struct gpio_desc *speaker_amp_gpio;
+};
+
+static int rx51_spk_func;
+static int rx51_dmic_func;
+static int rx51_jack_func;
+
+static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
+{
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+       int hp = 0, hs = 0, tvout = 0;
+
+       switch (rx51_jack_func) {
+       case RX51_JACK_TVOUT:
+               tvout = 1;
+               hp = 1;
+               break;
+       case RX51_JACK_HS:
+               hs = 1;
+       case RX51_JACK_HP:
+               hp = 1;
+               break;
+       }
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       if (rx51_spk_func)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
+       if (rx51_dmic_func)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
+       if (hp)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+       if (hs)
+               snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
+       else
+               snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
+
+       gpiod_set_value(pdata->tvout_selection_gpio, tvout);
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int rx51_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+       rx51_ext_control(&card->dapm);
+
+       return 0;
+}
+
+static int rx51_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       /* Set the codec system clock for DAC and ADC */
+       return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
+                                     SND_SOC_CLOCK_IN);
+}
+
+static const struct snd_soc_ops rx51_ops = {
+       .startup = rx51_startup,
+       .hw_params = rx51_hw_params,
+};
+
+static int rx51_get_spk(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = rx51_spk_func;
+
+       return 0;
+}
+
+static int rx51_set_spk(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+       if (rx51_spk_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       rx51_spk_func = ucontrol->value.enumerated.item[0];
+       rx51_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static int rx51_spk_event(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
+       gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio,
+                                    !!SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static int rx51_get_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = rx51_dmic_func;
+
+       return 0;
+}
+
+static int rx51_set_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+       if (rx51_dmic_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       rx51_dmic_func = ucontrol->value.enumerated.item[0];
+       rx51_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static int rx51_get_jack(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = rx51_jack_func;
+
+       return 0;
+}
+
+static int rx51_set_jack(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+       if (rx51_jack_func == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       rx51_jack_func = ucontrol->value.enumerated.item[0];
+       rx51_ext_control(&card->dapm);
+
+       return 1;
+}
+
+static struct snd_soc_jack rx51_av_jack;
+
+static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
+       {
+               .name = "avdet-gpio",
+               .report = SND_JACK_HEADSET,
+               .invert = 1,
+               .debounce_time = 200,
+       },
+};
+
+static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
+       SND_SOC_DAPM_MIC("DMic", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("HS Mic", NULL),
+       SND_SOC_DAPM_LINE("FM Transmitter", NULL),
+       SND_SOC_DAPM_SPK("Earphone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Ext Spk", NULL, "HPLOUT"},
+       {"Ext Spk", NULL, "HPROUT"},
+       {"Ext Spk", NULL, "HPLCOM"},
+       {"Ext Spk", NULL, "HPRCOM"},
+       {"FM Transmitter", NULL, "LLOUT"},
+       {"FM Transmitter", NULL, "RLOUT"},
+
+       {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"},
+       {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"},
+       {"TPA6130A2 LEFTIN", NULL, "LLOUT"},
+       {"TPA6130A2 RIGHTIN", NULL, "RLOUT"},
+
+       {"DMic Rate 64", NULL, "DMic"},
+       {"DMic", NULL, "Mic Bias"},
+
+       {"b LINE2R", NULL, "MONO_LOUT"},
+       {"Earphone", NULL, "b HPLOUT"},
+
+       {"LINE1L", NULL, "HS Mic"},
+       {"HS Mic", NULL, "b Mic Bias"},
+};
+
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const input_function[] = {"ADC", "Digital Mic"};
+static const char * const jack_function[] = {
+       "Off", "TV-OUT", "Headphone", "Headset"
+};
+
+static const struct soc_enum rx51_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
+};
+
+static const struct snd_kcontrol_new aic34_rx51_controls[] = {
+       SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
+                    rx51_get_spk, rx51_set_spk),
+       SOC_ENUM_EXT("Input Select",  rx51_enum[1],
+                    rx51_get_input, rx51_set_input),
+       SOC_ENUM_EXT("Jack Function", rx51_enum[2],
+                    rx51_get_jack, rx51_set_jack),
+       SOC_DAPM_PIN_SWITCH("FM Transmitter"),
+       SOC_DAPM_PIN_SWITCH("Earphone"),
+};
+
+static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+       int err;
+
+       snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
+
+       err = omap_mcbsp_st_add_controls(rtd, 2);
+       if (err < 0) {
+               dev_err(card->dev, "Failed to add MCBSP controls\n");
+               return err;
+       }
+
+       /* AV jack detection */
+       err = snd_soc_card_jack_new(rtd->card, "AV Jack",
+                                   SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
+                                   &rx51_av_jack, NULL, 0);
+       if (err) {
+               dev_err(card->dev, "Failed to add AV Jack\n");
+               return err;
+       }
+
+       /* prepare gpio for snd_soc_jack_add_gpios */
+       rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio);
+       devm_gpiod_put(card->dev, pdata->jack_detection_gpio);
+
+       err = snd_soc_jack_add_gpios(&rx51_av_jack,
+                                    ARRAY_SIZE(rx51_av_jack_gpios),
+                                    rx51_av_jack_gpios);
+       if (err) {
+               dev_err(card->dev, "Failed to add GPIOs\n");
+               return err;
+       }
+
+       return err;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx51_dai[] = {
+       {
+               .name = "TLV320AIC34",
+               .stream_name = "AIC34",
+               .cpu_dai_name = "omap-mcbsp.2",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name = "omap-mcbsp.2",
+               .codec_name = "tlv320aic3x-codec.2-0018",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+                          SND_SOC_DAIFMT_CBM_CFM,
+               .init = rx51_aic34_init,
+               .ops = &rx51_ops,
+       },
+};
+
+static struct snd_soc_aux_dev rx51_aux_dev[] = {
+       {
+               .name = "TLV320AIC34b",
+               .codec_name = "tlv320aic3x-codec.2-0019",
+       },
+       {
+               .name = "TPA61320A2",
+               .codec_name = "tpa6130a2.2-0060",
+       },
+};
+
+static struct snd_soc_codec_conf rx51_codec_conf[] = {
+       {
+               .dev_name = "tlv320aic3x-codec.2-0019",
+               .name_prefix = "b",
+       },
+       {
+               .dev_name = "tpa6130a2.2-0060",
+               .name_prefix = "TPA6130A2",
+       },
+};
+
+/* Audio card */
+static struct snd_soc_card rx51_sound_card = {
+       .name = "RX-51",
+       .owner = THIS_MODULE,
+       .dai_link = rx51_dai,
+       .num_links = ARRAY_SIZE(rx51_dai),
+       .aux_dev = rx51_aux_dev,
+       .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
+       .codec_conf = rx51_codec_conf,
+       .num_configs = ARRAY_SIZE(rx51_codec_conf),
+       .fully_routed = true,
+
+       .controls = aic34_rx51_controls,
+       .num_controls = ARRAY_SIZE(aic34_rx51_controls),
+       .dapm_widgets = aic34_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int rx51_soc_probe(struct platform_device *pdev)
+{
+       struct rx51_audio_pdata *pdata;
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &rx51_sound_card;
+       int err;
+
+       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
+               return -ENODEV;
+
+       card->dev = &pdev->dev;
+
+       if (np) {
+               struct device_node *dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McBSP node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].cpu_dai_name = NULL;
+               rx51_dai[0].platform_name = NULL;
+               rx51_dai[0].cpu_of_node = dai_node;
+               rx51_dai[0].platform_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Codec node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_dai[0].codec_name = NULL;
+               rx51_dai[0].codec_of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_aux_dev[0].codec_name = NULL;
+               rx51_aux_dev[0].codec_of_node = dai_node;
+               rx51_codec_conf[0].dev_name = NULL;
+               rx51_codec_conf[0].of_node = dai_node;
+
+               dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
+                       return -EINVAL;
+               }
+               rx51_aux_dev[1].codec_name = NULL;
+               rx51_aux_dev[1].codec_of_node = dai_node;
+               rx51_codec_conf[1].dev_name = NULL;
+               rx51_codec_conf[1].of_node = dai_node;
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (pdata == NULL)
+               return -ENOMEM;
+
+       snd_soc_card_set_drvdata(card, pdata);
+
+       pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+                                                    "tvout-selection",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(pdata->tvout_selection_gpio)) {
+               dev_err(card->dev, "could not get tvout selection gpio\n");
+               return PTR_ERR(pdata->tvout_selection_gpio);
+       }
+
+       pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
+                                                   "jack-detection",
+                                                   GPIOD_ASIS);
+       if (IS_ERR(pdata->jack_detection_gpio)) {
+               dev_err(card->dev, "could not get jack detection gpio\n");
+               return PTR_ERR(pdata->jack_detection_gpio);
+       }
+
+       pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
+                                           GPIOD_OUT_HIGH);
+       if (IS_ERR(pdata->eci_sw_gpio)) {
+               dev_err(card->dev, "could not get eci switch gpio\n");
+               return PTR_ERR(pdata->eci_sw_gpio);
+       }
+
+       pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+                                                "speaker-amplifier",
+                                                GPIOD_OUT_LOW);
+       if (IS_ERR(pdata->speaker_amp_gpio)) {
+               dev_err(card->dev, "could not get speaker enable gpio\n");
+               return PTR_ERR(pdata->speaker_amp_gpio);
+       }
+
+       err = devm_snd_soc_register_card(card->dev, card);
+       if (err) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rx51_audio_of_match[] = {
+       { .compatible = "nokia,n900-audio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
+#endif
+
+static struct platform_driver rx51_soc_driver = {
+       .driver = {
+               .name = "rx51-audio",
+               .of_match_table = of_match_ptr(rx51_audio_of_match),
+       },
+       .probe = rx51_soc_probe,
+};
+
+module_platform_driver(rx51_soc_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rx51-audio");
diff --git a/sound/soc/ti/sdma-pcm.c b/sound/soc/ti/sdma-pcm.c
new file mode 100644 (file)
index 0000000..21a9c24
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/omap-dmaengine.h>
+
+#include "sdma-pcm.h"
+
+static const struct snd_pcm_hardware sdma_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+                                 SNDRV_PCM_INFO_INTERLEAVED,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 64 * 1024,
+       .buffer_bytes_max       = 128 * 1024,
+       .periods_min            = 2,
+       .periods_max            = 255,
+};
+
+static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = {
+       .pcm_hardware = &sdma_pcm_hardware,
+       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+       .compat_filter_fn = omap_dma_filter_fn,
+       .prealloc_buffer_size = 128 * 1024,
+};
+
+int sdma_pcm_platform_register(struct device *dev,
+                              char *txdmachan, char *rxdmachan)
+{
+       struct snd_dmaengine_pcm_config *config;
+       unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT;
+
+       /* Standard names for the directions: 'tx' and 'rx' */
+       if (!txdmachan && !rxdmachan)
+               return devm_snd_dmaengine_pcm_register(dev,
+                                               &sdma_dmaengine_pcm_config,
+                                               flags);
+
+       config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
+       if (!config)
+               return -ENOMEM;
+
+       *config = sdma_dmaengine_pcm_config;
+
+       if (!txdmachan || !rxdmachan) {
+               /* One direction only PCM */
+               flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
+               if (!txdmachan) {
+                       txdmachan = rxdmachan;
+                       rxdmachan = NULL;
+               }
+       }
+
+       config->chan_names[0] = txdmachan;
+       config->chan_names[1] = rxdmachan;
+
+       return devm_snd_dmaengine_pcm_register(dev, config, flags);
+}
+EXPORT_SYMBOL_GPL(sdma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("sDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ti/sdma-pcm.h b/sound/soc/ti/sdma-pcm.h
new file mode 100644 (file)
index 0000000..cb0627c
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#ifndef __SDMA_PCM_H__
+#define __SDMA_PCM_H__
+
+#if IS_ENABLED(CONFIG_SND_SOC_TI_SDMA_PCM)
+int sdma_pcm_platform_register(struct device *dev,
+                              char *txdmachan, char *rxdmachan);
+#else
+static inline int sdma_pcm_platform_register(struct device *dev,
+                                            char *txdmachan, char *rxdmachan)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_SND_SOC_TI_SDMA_PCM */
+
+#endif /* __SDMA_PCM_H__ */
diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
new file mode 100644 (file)
index 0000000..25e287f
--- /dev/null
@@ -0,0 +1,8 @@
+config SND_SOC_XILINX_I2S
+       tristate "Audio support for the the Xilinx I2S"
+       help
+         Select this option to enable Xilinx I2S Audio. This enables
+         I2S playback and capture using xilinx soft IP. In transmitter
+         mode, IP receives audio in AES format, extracts PCM and sends
+         PCM data. In receiver mode, IP receives PCM audio and
+         encapsulates PCM in AES format and sends AES data.
diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile
new file mode 100644 (file)
index 0000000..6c1209b
--- /dev/null
@@ -0,0 +1,2 @@
+snd-soc-xlnx-i2s-objs      := xlnx_i2s.o
+obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c
new file mode 100644 (file)
index 0000000..d4ae9ef
--- /dev/null
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx ASoC I2S audio support
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Praveen Vuppala <praveenv@xilinx.com>
+ * Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "xlnx_i2s"
+
+#define I2S_CORE_CTRL_OFFSET           0x08
+#define I2S_I2STIM_OFFSET              0x20
+#define I2S_CH0_OFFSET                 0x30
+#define I2S_I2STIM_VALID_MASK          GENMASK(7, 0)
+
+static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai,
+                                   int div_id, int div)
+{
+       void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (!div || (div & ~I2S_I2STIM_VALID_MASK))
+               return -EINVAL;
+
+       writel(div, base + I2S_I2STIM_OFFSET);
+
+       return 0;
+}
+
+static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params,
+                             struct snd_soc_dai *i2s_dai)
+{
+       u32 reg_off, chan_id;
+       void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+       chan_id = params_channels(params) / 2;
+
+       while (chan_id > 0) {
+               reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4);
+               writel(chan_id, base + reg_off);
+               chan_id--;
+       }
+
+       return 0;
+}
+
+static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *i2s_dai)
+{
+       void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               writel(1, base + I2S_CORE_CTRL_OFFSET);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               writel(0, base + I2S_CORE_CTRL_OFFSET);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = {
+       .trigger = xlnx_i2s_trigger,
+       .set_clkdiv = xlnx_i2s_set_sclkout_div,
+       .hw_params = xlnx_i2s_hw_params
+};
+
+static const struct snd_soc_component_driver xlnx_i2s_component = {
+       .name = DRV_NAME,
+};
+
+static const struct of_device_id xlnx_i2s_of_match[] = {
+       { .compatible = "xlnx,i2s-transmitter-1.0", },
+       { .compatible = "xlnx,i2s-receiver-1.0", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match);
+
+static int xlnx_i2s_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *base;
+       struct snd_soc_dai_driver *dai_drv;
+       int ret;
+       u32 ch, format, data_width;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+
+       dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
+       if (!dai_drv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       ret = of_property_read_u32(node, "xlnx,num-channels", &ch);
+       if (ret < 0) {
+               dev_err(dev, "cannot get supported channels\n");
+               return ret;
+       }
+       ch = ch * 2;
+
+       ret = of_property_read_u32(node, "xlnx,dwidth", &data_width);
+       if (ret < 0) {
+               dev_err(dev, "cannot get data width\n");
+               return ret;
+       }
+       switch (data_width) {
+       case 16:
+               format = SNDRV_PCM_FMTBIT_S16_LE;
+               break;
+       case 24:
+               format = SNDRV_PCM_FMTBIT_S24_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) {
+               dai_drv->name = "xlnx_i2s_playback";
+               dai_drv->playback.stream_name = "Playback";
+               dai_drv->playback.formats = format;
+               dai_drv->playback.channels_min = ch;
+               dai_drv->playback.channels_max = ch;
+               dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000;
+               dai_drv->ops = &xlnx_i2s_dai_ops;
+       } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) {
+               dai_drv->name = "xlnx_i2s_capture";
+               dai_drv->capture.stream_name = "Capture";
+               dai_drv->capture.formats = format;
+               dai_drv->capture.channels_min = ch;
+               dai_drv->capture.channels_max = ch;
+               dai_drv->capture.rates = SNDRV_PCM_RATE_8000_192000;
+               dai_drv->ops = &xlnx_i2s_dai_ops;
+       } else {
+               return -ENODEV;
+       }
+
+       dev_set_drvdata(&pdev->dev, base);
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component,
+                                             dai_drv, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "i2s component registration failed\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "%s DAI registered\n", dai_drv->name);
+
+       return ret;
+}
+
+static struct platform_driver xlnx_i2s_aud_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = xlnx_i2s_of_match,
+       },
+       .probe = xlnx_i2s_probe,
+};
+
+module_platform_driver(xlnx_i2s_aud_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Praveen Vuppala  <praveenv@xilinx.com>");
+MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
index e557946718a9ed7006c17901060b927b43e0f31c..d9fcae071b477dc1afc110d1f8fb42055d736344 100644 (file)
@@ -22,9 +22,9 @@
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <linux/uaccess.h>
+#include <linux/nospec.h>
 #include "emux_voice.h"
 
-
 #define TMP_CLIENT_ID  0x1001
 
 /*
@@ -66,13 +66,16 @@ snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg)
                return -EFAULT;
        if (info.mode < 0 || info.mode >= EMUX_MD_END)
                return -EINVAL;
+       info.mode = array_index_nospec(info.mode, EMUX_MD_END);
 
        if (info.port < 0) {
                for (i = 0; i < emu->num_ports; i++)
                        emu->portptrs[i]->ctrls[info.mode] = info.value;
        } else {
-               if (info.port < emu->num_ports)
+               if (info.port < emu->num_ports) {
+                       info.port = array_index_nospec(info.port, emu->num_ports);
                        emu->portptrs[info.port]->ctrls[info.mode] = info.value;
+               }
        }
        return 0;
 }
index 6623cafc94f2c639bcceefe877c57927ac31042b..96340f23f86d8ea0bddac16c4ab631686daf03af 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
+#include <linux/bits.h>
 
 #include <sound/control.h>
 #include <sound/core.h>
@@ -668,15 +669,133 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
 }
 
 /*
- * C-Media CM6206 is based on CM106 with two additional
- * registers that are not documented in the data sheet.
- * Values here are chosen based on sniffing USB traffic
- * under Windows.
+ * CM6206 registers from the CM6206 datasheet rev 2.1
  */
+#define CM6206_REG0_DMA_MASTER BIT(15)
+#define CM6206_REG0_SPDIFO_RATE_48K (2 << 12)
+#define CM6206_REG0_SPDIFO_RATE_96K (7 << 12)
+/* Bit 4 thru 11 is the S/PDIF category code */
+#define CM6206_REG0_SPDIFO_CAT_CODE_GENERAL (0 << 4)
+#define CM6206_REG0_SPDIFO_EMPHASIS_CD BIT(3)
+#define CM6206_REG0_SPDIFO_COPYRIGHT_NA BIT(2)
+#define CM6206_REG0_SPDIFO_NON_AUDIO BIT(1)
+#define CM6206_REG0_SPDIFO_PRO_FORMAT BIT(0)
+
+#define CM6206_REG1_TEST_SEL_CLK BIT(14)
+#define CM6206_REG1_PLLBIN_EN BIT(13)
+#define CM6206_REG1_SOFT_MUTE_EN BIT(12)
+#define CM6206_REG1_GPIO4_OUT BIT(11)
+#define CM6206_REG1_GPIO4_OE BIT(10)
+#define CM6206_REG1_GPIO3_OUT BIT(9)
+#define CM6206_REG1_GPIO3_OE BIT(8)
+#define CM6206_REG1_GPIO2_OUT BIT(7)
+#define CM6206_REG1_GPIO2_OE BIT(6)
+#define CM6206_REG1_GPIO1_OUT BIT(5)
+#define CM6206_REG1_GPIO1_OE BIT(4)
+#define CM6206_REG1_SPDIFO_INVALID BIT(3)
+#define CM6206_REG1_SPDIF_LOOP_EN BIT(2)
+#define CM6206_REG1_SPDIFO_DIS BIT(1)
+#define CM6206_REG1_SPDIFI_MIX BIT(0)
+
+#define CM6206_REG2_DRIVER_ON BIT(15)
+#define CM6206_REG2_HEADP_SEL_SIDE_CHANNELS (0 << 13)
+#define CM6206_REG2_HEADP_SEL_SURROUND_CHANNELS (1 << 13)
+#define CM6206_REG2_HEADP_SEL_CENTER_SUBW (2 << 13)
+#define CM6206_REG2_HEADP_SEL_FRONT_CHANNELS (3 << 13)
+#define CM6206_REG2_MUTE_HEADPHONE_RIGHT BIT(12)
+#define CM6206_REG2_MUTE_HEADPHONE_LEFT BIT(11)
+#define CM6206_REG2_MUTE_REAR_SURROUND_RIGHT BIT(10)
+#define CM6206_REG2_MUTE_REAR_SURROUND_LEFT BIT(9)
+#define CM6206_REG2_MUTE_SIDE_SURROUND_RIGHT BIT(8)
+#define CM6206_REG2_MUTE_SIDE_SURROUND_LEFT BIT(7)
+#define CM6206_REG2_MUTE_SUBWOOFER BIT(6)
+#define CM6206_REG2_MUTE_CENTER BIT(5)
+#define CM6206_REG2_MUTE_RIGHT_FRONT BIT(3)
+#define CM6206_REG2_MUTE_LEFT_FRONT BIT(3)
+#define CM6206_REG2_EN_BTL BIT(2)
+#define CM6206_REG2_MCUCLKSEL_1_5_MHZ (0)
+#define CM6206_REG2_MCUCLKSEL_3_MHZ (1)
+#define CM6206_REG2_MCUCLKSEL_6_MHZ (2)
+#define CM6206_REG2_MCUCLKSEL_12_MHZ (3)
+
+/* Bit 11..13 sets the sensitivity to FLY tuner volume control VP/VD signal */
+#define CM6206_REG3_FLYSPEED_DEFAULT (2 << 11)
+#define CM6206_REG3_VRAP25EN BIT(10)
+#define CM6206_REG3_MSEL1 BIT(9)
+#define CM6206_REG3_SPDIFI_RATE_44_1K BIT(0 << 7)
+#define CM6206_REG3_SPDIFI_RATE_48K BIT(2 << 7)
+#define CM6206_REG3_SPDIFI_RATE_32K BIT(3 << 7)
+#define CM6206_REG3_PINSEL BIT(6)
+#define CM6206_REG3_FOE BIT(5)
+#define CM6206_REG3_ROE BIT(4)
+#define CM6206_REG3_CBOE BIT(3)
+#define CM6206_REG3_LOSE BIT(2)
+#define CM6206_REG3_HPOE BIT(1)
+#define CM6206_REG3_SPDIFI_CANREC BIT(0)
+
+#define CM6206_REG5_DA_RSTN BIT(13)
+#define CM6206_REG5_AD_RSTN BIT(12)
+#define CM6206_REG5_SPDIFO_AD2SPDO BIT(12)
+#define CM6206_REG5_SPDIFO_SEL_FRONT (0 << 9)
+#define CM6206_REG5_SPDIFO_SEL_SIDE_SUR (1 << 9)
+#define CM6206_REG5_SPDIFO_SEL_CEN_LFE (2 << 9)
+#define CM6206_REG5_SPDIFO_SEL_REAR_SUR (3 << 9)
+#define CM6206_REG5_CODECM BIT(8)
+#define CM6206_REG5_EN_HPF BIT(7)
+#define CM6206_REG5_T_SEL_DSDA4 BIT(6)
+#define CM6206_REG5_T_SEL_DSDA3 BIT(5)
+#define CM6206_REG5_T_SEL_DSDA2 BIT(4)
+#define CM6206_REG5_T_SEL_DSDA1 BIT(3)
+#define CM6206_REG5_T_SEL_DSDAD_NORMAL 0
+#define CM6206_REG5_T_SEL_DSDAD_FRONT 4
+#define CM6206_REG5_T_SEL_DSDAD_S_SURROUND 5
+#define CM6206_REG5_T_SEL_DSDAD_CEN_LFE 6
+#define CM6206_REG5_T_SEL_DSDAD_R_SURROUND 7
+
 static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 {
        int err  = 0, reg;
-       int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
+       int val[] = {
+               /*
+                * Values here are chosen based on sniffing USB traffic
+                * under Windows.
+                *
+                * REG0: DAC is master, sample rate 48kHz, no copyright
+                */
+               CM6206_REG0_SPDIFO_RATE_48K |
+               CM6206_REG0_SPDIFO_COPYRIGHT_NA,
+               /*
+                * REG1: PLL binary search enable, soft mute enable.
+                */
+               CM6206_REG1_PLLBIN_EN |
+               CM6206_REG1_SOFT_MUTE_EN |
+               /*
+                * REG2: enable output drivers,
+                * select front channels to the headphone output,
+                * then mute the headphone channels, run the MCU
+                * at 1.5 MHz.
+                */
+               CM6206_REG2_DRIVER_ON |
+               CM6206_REG2_HEADP_SEL_FRONT_CHANNELS |
+               CM6206_REG2_MUTE_HEADPHONE_RIGHT |
+               CM6206_REG2_MUTE_HEADPHONE_LEFT,
+               /*
+                * REG3: default flyspeed, set 2.5V mic bias
+                * enable all line out ports and enable SPDIF
+                */
+               CM6206_REG3_FLYSPEED_DEFAULT |
+               CM6206_REG3_VRAP25EN |
+               CM6206_REG3_FOE |
+               CM6206_REG3_ROE |
+               CM6206_REG3_CBOE |
+               CM6206_REG3_LOSE |
+               CM6206_REG3_HPOE |
+               CM6206_REG3_SPDIFI_CANREC,
+               /* REG4 is just a bunch of GPIO lines */
+               0x0000,
+               /* REG5: de-assert AD/DA reset signals */
+               CM6206_REG5_DA_RSTN |
+               CM6206_REG5_AD_RSTN };
 
        for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
                err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
index 83d76c345940557f25a6e2b08150bacbd3dc404f..00c92eb854ce7b65daedc7c3fa98f69f9b891d86 100644 (file)
@@ -1648,7 +1648,7 @@ static int had_create_jack(struct snd_intelhad *ctx,
  * PM callbacks
  */
 
-static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
+static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
 {
        struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
        int port;
@@ -1664,23 +1664,8 @@ static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
                }
        }
 
-       return 0;
-}
-
-static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
-{
-       struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
-       int err;
+       snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot);
 
-       err = hdmi_lpe_audio_runtime_suspend(dev);
-       if (!err)
-               snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot);
-       return err;
-}
-
-static int hdmi_lpe_audio_runtime_resume(struct device *dev)
-{
-       pm_runtime_mark_last_busy(dev);
        return 0;
 }
 
@@ -1688,8 +1673,10 @@ static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev)
 {
        struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
 
-       hdmi_lpe_audio_runtime_resume(dev);
+       pm_runtime_mark_last_busy(dev);
+
        snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D0);
+
        return 0;
 }
 
@@ -1877,7 +1864,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_mark_last_busy(&pdev->dev);
-       pm_runtime_set_active(&pdev->dev);
 
        dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
        for_each_port(card_ctx, port) {
@@ -1908,8 +1894,6 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev)
 
 static const struct dev_pm_ops hdmi_lpe_audio_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
-       SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend,
-                          hdmi_lpe_audio_runtime_resume, NULL)
 };
 
 static struct platform_driver hdmi_lpe_audio_driver = {
index 486ed1f0c0bc17f48dca895ebf9581aa7d69278d..0a4d73317759c9ee523d7d5482548b3171c821e6 100644 (file)
@@ -155,7 +155,7 @@ enum nlmsgerr_attrs {
 #define NETLINK_LIST_MEMBERSHIPS       9
 #define NETLINK_CAP_ACK                        10
 #define NETLINK_EXT_ACK                        11
-#define NETLINK_DUMP_STRICT_CHK                12
+#define NETLINK_GET_STRICT_CHK         12
 
 struct nl_pktinfo {
        __u32   group;
index db213171f8d99e0e0b114c2620fb0eda59c0152c..2d9b94b631cb9f301e08198e5416a47ca866ffd8 100644 (file)
@@ -106,7 +106,7 @@ static int ap_insert_action(char *argument, u32 to_be_done)
 
        current_action++;
        if (current_action > AP_MAX_ACTIONS) {
-               fprintf(stderr, "Too many table options (max %u)\n",
+               fprintf(stderr, "Too many table options (max %d)\n",
                        AP_MAX_ACTIONS);
                return (-1);
        }
index db66a952c173958395f9134c1fa029fbbd6d3950..fd8765af19bba631d8a05cb12c04f38c0de875ee 100644 (file)
@@ -89,6 +89,7 @@ endif
 localedir ?=   /usr/share/locale
 docdir ?=       /usr/share/doc/packages/cpupower
 confdir ?=      /etc/
+bash_completion_dir ?= /usr/share/bash-completion/completions
 
 # Toolchain: what tools do we use, and what options do they need:
 
@@ -96,7 +97,8 @@ CP = cp -fpR
 INSTALL = /usr/bin/install -c
 INSTALL_PROGRAM = ${INSTALL}
 INSTALL_DATA  = ${INSTALL} -m 644
-INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+#bash completion scripts get sourced and so they should be rw only.
+INSTALL_SCRIPT = ${INSTALL} -m 644
 
 # If you are running a cross compiler, you may want to set this
 # to something more interesting, like "arm-linux-".  If you want
@@ -288,6 +290,8 @@ install-lib:
 install-tools:
        $(INSTALL) -d $(DESTDIR)${bindir}
        $(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir}
+       $(INSTALL) -d $(DESTDIR)${bash_completion_dir}
+       $(INSTALL_SCRIPT) cpupower-completion.sh '$(DESTDIR)${bash_completion_dir}/cpupower'
 
 install-man:
        $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
diff --git a/tools/power/cpupower/cpupower-completion.sh b/tools/power/cpupower/cpupower-completion.sh
new file mode 100644 (file)
index 0000000..e10839c
--- /dev/null
@@ -0,0 +1,128 @@
+# -*- shell-script -*-
+# bash completion script for cpupower
+# Taken from git.git's completion script.
+
+_cpupower_commands="frequency-info frequency-set idle-info idle-set set info monitor"
+
+_frequency_info ()
+{
+       local flags="-f -w -l -d -p -g -a -s -y -o -m -n --freq --hwfreq --hwlimits --driver --policy --governors --related-cpus --affected-cpus --stats --latency --proc --human --no-rounding"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               frequency-info) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_frequency_set ()
+{
+       local flags="-f -g --freq --governor -d --min -u --max -r --related"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               -f| --freq | -d | --min | -u | --max)
+               if [ -d /sys/devices/system/cpu/cpufreq/ ] ; then
+                       COMPREPLY=($(compgen -W '$(cat $(ls -d /sys/devices/system/cpu/cpufreq/policy* | head -1)/scaling_available_frequencies)' -- "$cur"))
+               fi ;;
+               -g| --governor)
+               if [ -d /sys/devices/system/cpu/cpufreq/ ] ; then
+                       COMPREPLY=($(compgen -W '$(cat $(ls -d /sys/devices/system/cpu/cpufreq/policy* | head -1)/scaling_available_governors)' -- "$cur"))
+               fi;;
+               frequency-set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_idle_info()
+{
+       local flags="-f --silent"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               idle-info) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_idle_set()
+{
+       local flags="-d --disable -e --enable -D --disable-by-latency -E --enable-all"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               idle-set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_set()
+{
+       local flags="--perf-bias, -b"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_monitor()
+{
+       local flags="-l -m -i -c -v"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev" in
+               monitor) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+       esac
+}
+
+_taskset()
+{
+       local prev_to_prev="${COMP_WORDS[COMP_CWORD-2]}"
+       local prev="${COMP_WORDS[COMP_CWORD-1]}"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$prev_to_prev" in
+               -c|--cpu) COMPREPLY=($(compgen -W "$_cpupower_commands" -- "$cur")) ;;
+       esac
+       case "$prev" in
+               frequency-info) _frequency_info ;;
+               frequency-set) _frequency_set ;;
+               idle-info) _idle_info ;;
+               idle-set) _idle_set ;;
+               set) _set ;;
+               monitor) _monitor ;;
+       esac
+
+}
+
+_cpupower ()
+{
+       local i
+       local c=1
+       local command
+
+       while test $c -lt $COMP_CWORD; do
+               if test $c == 1; then
+                       command="${COMP_WORDS[c]}"
+               fi
+               c=$((++c))
+       done
+
+       # Complete name of subcommand if the user has not finished typing it yet.
+       if test $c -eq $COMP_CWORD -a -z "$command"; then
+               COMPREPLY=($(compgen -W "help -v --version -c --cpu $_cpupower_commands" -- "${COMP_WORDS[COMP_CWORD]}"))
+               return
+       fi
+
+       # Complete arguments to subcommands.
+       case "$command" in
+               -v|--version) return ;;
+               -c|--cpu) _taskset ;;
+               help) COMPREPLY=($(compgen -W "$_cpupower_commands" -- "${COMP_WORDS[COMP_CWORD]}")) ;;
+               frequency-info) _frequency_info ;;
+               frequency-set) _frequency_set ;;
+               idle-info) _idle_info ;;
+               idle-set) _idle_set ;;
+               set) _set ;;
+               monitor) _monitor ;;
+       esac
+}
+
+complete -o bashdefault -o default -F _cpupower cpupower 2>/dev/null \
+    || complete -o default -F _cpupower cpupower
index 84e2b648e622ffcbdcc0a50805b72b8a89c9a5d1..2fa3c5757bcb5b4f72cf85a6bf8a6cbad8efbf6f 100755 (executable)
@@ -585,9 +585,9 @@ current_max_cpu = 0
 
 read_trace_data(filename)
 
-clear_trace_file()
-# Free the memory
 if interval:
+    clear_trace_file()
+    # Free the memory
     free_trace_buffer()
 
 if graph_data_present == False:
index 328f62e6ea02f9ee4dd5a05b35a2857814b6b80e..9327c0ddc3a59c6424d33b6278b9cf7e51155ce7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * turbostat -- show CPU frequency and C-state residency
- * on modern Intel turbo-capable processors.
+ * on modern Intel and AMD processors.
  *
  * Copyright (c) 2013 Intel Corporation.
  * Len Brown <len.brown@intel.com>
@@ -71,6 +71,8 @@ unsigned int do_irtl_snb;
 unsigned int do_irtl_hsw;
 unsigned int units = 1000000;  /* MHz etc */
 unsigned int genuine_intel;
+unsigned int authentic_amd;
+unsigned int max_level, max_extended_level;
 unsigned int has_invariant_tsc;
 unsigned int do_nhm_platform_info;
 unsigned int no_MSR_MISC_PWR_MGMT;
@@ -1667,30 +1669,51 @@ int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp)
 
 void get_apic_id(struct thread_data *t)
 {
-       unsigned int eax, ebx, ecx, edx, max_level;
+       unsigned int eax, ebx, ecx, edx;
 
-       eax = ebx = ecx = edx = 0;
+       if (DO_BIC(BIC_APIC)) {
+               eax = ebx = ecx = edx = 0;
+               __cpuid(1, eax, ebx, ecx, edx);
 
-       if (!genuine_intel)
+               t->apic_id = (ebx >> 24) & 0xff;
+       }
+
+       if (!DO_BIC(BIC_X2APIC))
                return;
 
-       __cpuid(0, max_level, ebx, ecx, edx);
+       if (authentic_amd) {
+               unsigned int topology_extensions;
 
-       __cpuid(1, eax, ebx, ecx, edx);
-       t->apic_id = (ebx >> 24) & 0xf;
+               if (max_extended_level < 0x8000001e)
+                       return;
 
-       if (max_level < 0xb)
+               eax = ebx = ecx = edx = 0;
+               __cpuid(0x80000001, eax, ebx, ecx, edx);
+                       topology_extensions = ecx & (1 << 22);
+
+               if (topology_extensions == 0)
+                       return;
+
+               eax = ebx = ecx = edx = 0;
+               __cpuid(0x8000001e, eax, ebx, ecx, edx);
+
+               t->x2apic_id = eax;
                return;
+       }
 
-       if (!DO_BIC(BIC_X2APIC))
+       if (!genuine_intel)
+               return;
+
+       if (max_level < 0xb)
                return;
 
        ecx = 0;
        __cpuid(0xb, eax, ebx, ecx, edx);
        t->x2apic_id = edx;
 
-       if (debug && (t->apic_id != t->x2apic_id))
-               fprintf(outf, "cpu%d: apic 0x%x x2apic 0x%x\n", t->cpu_id, t->apic_id, t->x2apic_id);
+       if (debug && (t->apic_id != (t->x2apic_id & 0xff)))
+               fprintf(outf, "cpu%d: BIOS BUG: apic 0x%x x2apic 0x%x\n",
+                               t->cpu_id, t->apic_id, t->x2apic_id);
 }
 
 /*
@@ -1953,11 +1976,12 @@ done:
 #define PCL_7S 11 /* PC7 Shrink */
 #define PCL__8 12 /* PC8 */
 #define PCL__9 13 /* PC9 */
-#define PCLUNL 14 /* Unlimited */
+#define PCL_10 14 /* PC10 */
+#define PCLUNL 15 /* Unlimited */
 
 int pkg_cstate_limit = PCLUKN;
 char *pkg_cstate_limit_strings[] = { "reserved", "unknown", "pc0", "pc1", "pc2",
-       "pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "unlimited"};
+       "pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "pc10", "unlimited"};
 
 int nhm_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCL__3, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int snb_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCL__7, PCL_7S, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
@@ -1965,7 +1989,7 @@ int hsw_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL__3, PCL__6, PCL__7, PCL_7S,
 int slv_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCLRSV, PCLRSV, PCL__4, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7};
 int amt_pkg_cstate_limits[16] = {PCLUNL, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
-int bxt_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
+int glm_pkg_cstate_limits[16] = {PCLUNL, PCL__1, PCL__3, PCL__6, PCL__7, PCL_7S, PCL__8, PCL__9, PCL_10, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int skx_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 
 
@@ -3113,13 +3137,8 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
        bclk = discover_bclk(family, model);
 
        switch (model) {
-       case INTEL_FAM6_NEHALEM_EP:     /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
        case INTEL_FAM6_NEHALEM:        /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
-       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
-       case INTEL_FAM6_WESTMERE:       /* Westmere Client - Clarkdale, Arrandale */
-       case INTEL_FAM6_WESTMERE_EP:    /* Westmere EP - Gulftown */
        case INTEL_FAM6_NEHALEM_EX:     /* Nehalem-EX Xeon - Beckton */
-       case INTEL_FAM6_WESTMERE_EX:    /* Westmere-EX Xeon - Eagleton */
                pkg_cstate_limits = nhm_pkg_cstate_limits;
                break;
        case INTEL_FAM6_SANDYBRIDGE:    /* SNB */
@@ -3131,16 +3150,11 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
                break;
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSX */
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
-       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
                pkg_cstate_limits = hsw_pkg_cstate_limits;
                has_misc_feature_control = 1;
@@ -3159,13 +3173,12 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
                no_MSR_MISC_PWR_MGMT = 1;
                break;
        case INTEL_FAM6_XEON_PHI_KNL:   /* PHI */
-       case INTEL_FAM6_XEON_PHI_KNM:
                pkg_cstate_limits = phi_pkg_cstate_limits;
                break;
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
        case INTEL_FAM6_ATOM_GOLDMONT_X:        /* DNV */
-               pkg_cstate_limits = bxt_pkg_cstate_limits;
+               pkg_cstate_limits = glm_pkg_cstate_limits;
                break;
        default:
                return 0;
@@ -3220,7 +3233,6 @@ int is_bdx(unsigned int family, unsigned int model)
 
        switch (model) {
        case INTEL_FAM6_BROADWELL_X:
-       case INTEL_FAM6_BROADWELL_XEON_D:
                return 1;
        }
        return 0;
@@ -3246,9 +3258,7 @@ int has_turbo_ratio_limit(unsigned int family, unsigned int model)
        switch (model) {
        /* Nehalem compatible, but do not include turbo-ratio limit support */
        case INTEL_FAM6_NEHALEM_EX:     /* Nehalem-EX Xeon - Beckton */
-       case INTEL_FAM6_WESTMERE_EX:    /* Westmere-EX Xeon - Eagleton */
        case INTEL_FAM6_XEON_PHI_KNL:   /* PHI - Knights Landing (different MSR definition) */
-       case INTEL_FAM6_XEON_PHI_KNM:
                return 0;
        default:
                return 1;
@@ -3303,7 +3313,6 @@ int has_knl_turbo_ratio_limit(unsigned int family, unsigned int model)
 
        switch (model) {
        case INTEL_FAM6_XEON_PHI_KNL:   /* Knights Landing */
-       case INTEL_FAM6_XEON_PHI_KNM:
                return 1;
        default:
                return 0;
@@ -3337,21 +3346,15 @@ int has_config_tdp(unsigned int family, unsigned int model)
        case INTEL_FAM6_IVYBRIDGE:      /* IVB */
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSX */
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
-       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
 
        case INTEL_FAM6_XEON_PHI_KNL:   /* Knights Landing */
-       case INTEL_FAM6_XEON_PHI_KNM:
                return 1;
        default:
                return 0;
@@ -3744,9 +3747,7 @@ rapl_dram_energy_units_probe(int  model, double rapl_energy_units)
        switch (model) {
        case INTEL_FAM6_HASWELL_X:      /* HSX */
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
-       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
        case INTEL_FAM6_XEON_PHI_KNL:   /* KNL */
-       case INTEL_FAM6_XEON_PHI_KNM:
                return (rapl_dram_energy_units = 15.3 / 1000000);
        default:
                return (rapl_energy_units);
@@ -3775,7 +3776,6 @@ void rapl_probe(unsigned int family, unsigned int model)
        case INTEL_FAM6_SANDYBRIDGE:
        case INTEL_FAM6_IVYBRIDGE:
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
@@ -3799,9 +3799,6 @@ void rapl_probe(unsigned int family, unsigned int model)
                        BIC_PRESENT(BIC_PkgWatt);
                break;
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
                do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
                BIC_PRESENT(BIC_PKG__);
@@ -3820,10 +3817,8 @@ void rapl_probe(unsigned int family, unsigned int model)
                break;
        case INTEL_FAM6_HASWELL_X:      /* HSX */
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
-       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_XEON_PHI_KNL:   /* KNL */
-       case INTEL_FAM6_XEON_PHI_KNM:
                do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
                BIC_PRESENT(BIC_PKG__);
                BIC_PRESENT(BIC_RAM__);
@@ -3916,7 +3911,6 @@ void perf_limit_reasons_probe(unsigned int family, unsigned int model)
 
        switch (model) {
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
                do_gfx_perf_limit_reasons = 1;
        case INTEL_FAM6_HASWELL_X:      /* HSX */
@@ -4128,16 +4122,11 @@ int has_snb_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_IVYBRIDGE_X:    /* IVB Xeon */
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSW */
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
-       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
@@ -4166,12 +4155,9 @@ int has_hsw_msrs(unsigned int family, unsigned int model)
                return 0;
 
        switch (model) {
-       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
+       case INTEL_FAM6_HASWELL_CORE:
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
@@ -4195,9 +4181,6 @@ int has_skl_msrs(unsigned int family, unsigned int model)
 
        switch (model) {
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-       case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-       case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-       case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
                return 1;
        }
@@ -4222,7 +4205,6 @@ int is_knl(unsigned int family, unsigned int model)
                return 0;
        switch (model) {
        case INTEL_FAM6_XEON_PHI_KNL:   /* KNL */
-       case INTEL_FAM6_XEON_PHI_KNM:
                return 1;
        }
        return 0;
@@ -4436,18 +4418,56 @@ void decode_c6_demotion_policy_msr(void)
                        base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS");
 }
 
+/*
+ * When models are the same, for the purpose of turbostat, reuse
+ */
+unsigned int intel_model_duplicates(unsigned int model)
+{
+
+       switch(model) {
+       case INTEL_FAM6_NEHALEM_EP:     /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
+       case INTEL_FAM6_NEHALEM:        /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
+       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+       case INTEL_FAM6_WESTMERE:       /* Westmere Client - Clarkdale, Arrandale */
+       case INTEL_FAM6_WESTMERE_EP:    /* Westmere EP - Gulftown */
+               return INTEL_FAM6_NEHALEM;
+
+       case INTEL_FAM6_NEHALEM_EX:     /* Nehalem-EX Xeon - Beckton */
+       case INTEL_FAM6_WESTMERE_EX:    /* Westmere-EX Xeon - Eagleton */
+               return INTEL_FAM6_NEHALEM_EX;
+
+       case INTEL_FAM6_XEON_PHI_KNM:
+               return INTEL_FAM6_XEON_PHI_KNL;
+
+       case INTEL_FAM6_HASWELL_ULT:
+               return INTEL_FAM6_HASWELL_CORE;
+
+       case INTEL_FAM6_BROADWELL_X:
+       case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
+               return INTEL_FAM6_BROADWELL_X;
+
+       case INTEL_FAM6_SKYLAKE_MOBILE:
+       case INTEL_FAM6_SKYLAKE_DESKTOP:
+       case INTEL_FAM6_KABYLAKE_MOBILE:
+       case INTEL_FAM6_KABYLAKE_DESKTOP:
+               return INTEL_FAM6_SKYLAKE_MOBILE;
+       }
+       return model;
+}
 void process_cpuid()
 {
-       unsigned int eax, ebx, ecx, edx, max_level, max_extended_level;
-       unsigned int fms, family, model, stepping;
+       unsigned int eax, ebx, ecx, edx;
+       unsigned int fms, family, model, stepping, ecx_flags, edx_flags;
        unsigned int has_turbo;
 
        eax = ebx = ecx = edx = 0;
 
        __cpuid(0, max_level, ebx, ecx, edx);
 
-       if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
+       if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)
                genuine_intel = 1;
+       else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
+               authentic_amd = 1;
 
        if (!quiet)
                fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
@@ -4461,25 +4481,8 @@ void process_cpuid()
                family += (fms >> 20) & 0xff;
        if (family >= 6)
                model += ((fms >> 16) & 0xf) << 4;
-
-       if (!quiet) {
-               fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
-                       max_level, family, model, stepping, family, model, stepping);
-               fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n",
-                       ecx & (1 << 0) ? "SSE3" : "-",
-                       ecx & (1 << 3) ? "MONITOR" : "-",
-                       ecx & (1 << 6) ? "SMX" : "-",
-                       ecx & (1 << 7) ? "EIST" : "-",
-                       ecx & (1 << 8) ? "TM2" : "-",
-                       edx & (1 << 4) ? "TSC" : "-",
-                       edx & (1 << 5) ? "MSR" : "-",
-                       edx & (1 << 22) ? "ACPI-TM" : "-",
-                       edx & (1 << 28) ? "HT" : "-",
-                       edx & (1 << 29) ? "TM" : "-");
-       }
-
-       if (!(edx & (1 << 5)))
-               errx(1, "CPUID: no MSR");
+       ecx_flags = ecx;
+       edx_flags = edx;
 
        /*
         * check max extended function levels of CPUID.
@@ -4489,6 +4492,27 @@ void process_cpuid()
        ebx = ecx = edx = 0;
        __cpuid(0x80000000, max_extended_level, ebx, ecx, edx);
 
+       if (!quiet) {
+               fprintf(outf, "0x%x CPUID levels; 0x%x xlevels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
+                       max_level, max_extended_level, family, model, stepping, family, model, stepping);
+               fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n",
+                       ecx_flags & (1 << 0) ? "SSE3" : "-",
+                       ecx_flags & (1 << 3) ? "MONITOR" : "-",
+                       ecx_flags & (1 << 6) ? "SMX" : "-",
+                       ecx_flags & (1 << 7) ? "EIST" : "-",
+                       ecx_flags & (1 << 8) ? "TM2" : "-",
+                       edx_flags & (1 << 4) ? "TSC" : "-",
+                       edx_flags & (1 << 5) ? "MSR" : "-",
+                       edx_flags & (1 << 22) ? "ACPI-TM" : "-",
+                       edx_flags & (1 << 28) ? "HT" : "-",
+                       edx_flags & (1 << 29) ? "TM" : "-");
+       }
+       if (genuine_intel)
+               model = intel_model_duplicates(model);
+
+       if (!(edx_flags & (1 << 5)))
+               errx(1, "CPUID: no MSR");
+
        if (max_extended_level >= 0x80000007) {
 
                /*
@@ -4576,9 +4600,6 @@ void process_cpuid()
                        if (crystal_hz == 0)
                                switch(model) {
                                case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
-                               case INTEL_FAM6_SKYLAKE_DESKTOP:        /* SKL */
-                               case INTEL_FAM6_KABYLAKE_MOBILE:        /* KBL */
-                               case INTEL_FAM6_KABYLAKE_DESKTOP:       /* KBL */
                                        crystal_hz = 24000000;  /* 24.0 MHz */
                                        break;
                                case INTEL_FAM6_ATOM_GOLDMONT_X:        /* DNV */
@@ -4860,6 +4881,8 @@ void topology_probe()
                return;
 
        for (i = 0; i <= topo.max_cpu_num; ++i) {
+               if (cpu_is_not_present(i))
+                       continue;
                fprintf(outf,
                        "cpu %d pkg %d node %d lnode %d core %d thread %d\n",
                        i, cpus[i].physical_package_id,
index 107350a7821d09afe1e78721ae2aef06479b5fad..df9d32fd205538429180f05ef7828dca589875a5 100644 (file)
@@ -70,18 +70,18 @@ static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
 {
        void *data_end = (void *)(long)skb->data_end;
        void *data = (void *)(long)skb->data;
-       __u16 nhoff = skb->flow_keys->nhoff;
+       __u16 thoff = skb->flow_keys->thoff;
        __u8 *hdr;
 
        /* Verifies this variable offset does not overflow */
-       if (nhoff > (USHRT_MAX - hdr_size))
+       if (thoff > (USHRT_MAX - hdr_size))
                return NULL;
 
-       hdr = data + nhoff;
+       hdr = data + thoff;
        if (hdr + hdr_size <= data_end)
                return hdr;
 
-       if (bpf_skb_load_bytes(skb, nhoff, buffer, hdr_size))
+       if (bpf_skb_load_bytes(skb, thoff, buffer, hdr_size))
                return NULL;
 
        return buffer;
@@ -158,13 +158,13 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
                        /* Only inspect standard GRE packets with version 0 */
                        return BPF_OK;
 
-               keys->nhoff += sizeof(*gre); /* Step over GRE Flags and Proto */
+               keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */
                if (GRE_IS_CSUM(gre->flags))
-                       keys->nhoff += 4; /* Step over chksum and Padding */
+                       keys->thoff += 4; /* Step over chksum and Padding */
                if (GRE_IS_KEY(gre->flags))
-                       keys->nhoff += 4; /* Step over key */
+                       keys->thoff += 4; /* Step over key */
                if (GRE_IS_SEQ(gre->flags))
-                       keys->nhoff += 4; /* Step over sequence number */
+                       keys->thoff += 4; /* Step over sequence number */
 
                keys->is_encap = true;
 
@@ -174,7 +174,7 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
                        if (!eth)
                                return BPF_DROP;
 
-                       keys->nhoff += sizeof(*eth);
+                       keys->thoff += sizeof(*eth);
 
                        return parse_eth_proto(skb, eth->h_proto);
                } else {
@@ -191,7 +191,6 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
                if ((__u8 *)tcp + (tcp->doff << 2) > data_end)
                        return BPF_DROP;
 
-               keys->thoff = keys->nhoff;
                keys->sport = tcp->source;
                keys->dport = tcp->dest;
                return BPF_OK;
@@ -201,7 +200,6 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
                if (!udp)
                        return BPF_DROP;
 
-               keys->thoff = keys->nhoff;
                keys->sport = udp->source;
                keys->dport = udp->dest;
                return BPF_OK;
@@ -252,8 +250,8 @@ PROG(IP)(struct __sk_buff *skb)
        keys->ipv4_src = iph->saddr;
        keys->ipv4_dst = iph->daddr;
 
-       keys->nhoff += iph->ihl << 2;
-       if (data + keys->nhoff > data_end)
+       keys->thoff += iph->ihl << 2;
+       if (data + keys->thoff > data_end)
                return BPF_DROP;
 
        if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
@@ -285,7 +283,7 @@ PROG(IPV6)(struct __sk_buff *skb)
        keys->addr_proto = ETH_P_IPV6;
        memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
 
-       keys->nhoff += sizeof(struct ipv6hdr);
+       keys->thoff += sizeof(struct ipv6hdr);
 
        return parse_ipv6_proto(skb, ip6h->nexthdr);
 }
@@ -301,7 +299,7 @@ PROG(IPV6OP)(struct __sk_buff *skb)
        /* hlen is in 8-octets and does not include the first 8 bytes
         * of the header
         */
-       skb->flow_keys->nhoff += (1 + ip6h->hdrlen) << 3;
+       skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3;
 
        return parse_ipv6_proto(skb, ip6h->nexthdr);
 }
@@ -315,7 +313,7 @@ PROG(IPV6FR)(struct __sk_buff *skb)
        if (!fragh)
                return BPF_DROP;
 
-       keys->nhoff += sizeof(*fragh);
+       keys->thoff += sizeof(*fragh);
        keys->is_frag = true;
        if (!(fragh->frag_off & bpf_htons(IP6_OFFSET)))
                keys->is_first_frag = true;
@@ -341,7 +339,7 @@ PROG(VLAN)(struct __sk_buff *skb)
        __be16 proto;
 
        /* Peek back to see if single or double-tagging */
-       if (bpf_skb_load_bytes(skb, keys->nhoff - sizeof(proto), &proto,
+       if (bpf_skb_load_bytes(skb, keys->thoff - sizeof(proto), &proto,
                               sizeof(proto)))
                return BPF_DROP;
 
@@ -354,14 +352,14 @@ PROG(VLAN)(struct __sk_buff *skb)
                if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q))
                        return BPF_DROP;
 
-               keys->nhoff += sizeof(*vlan);
+               keys->thoff += sizeof(*vlan);
        }
 
        vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
        if (!vlan)
                return BPF_DROP;
 
-       keys->nhoff += sizeof(*vlan);
+       keys->thoff += sizeof(*vlan);
        /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/
        if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) ||
            vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q))
index df6f751cc1e81c0bcc1f68e86a5bc57e530a2452..f8eac4a544f450b4ae8acbfa7d57ab1b55675f97 100644 (file)
@@ -13915,6 +13915,34 @@ static struct bpf_test tests[] = {
                .result_unpriv = REJECT,
                .result = ACCEPT,
        },
+       {
+               "calls: cross frame pruning",
+               .insns = {
+                       /* r8 = !!random();
+                        * call pruner()
+                        * if (r8)
+                        *     do something bad;
+                        */
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_get_prandom_u32),
+                       BPF_MOV64_IMM(BPF_REG_8, 0),
+                       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+                       BPF_MOV64_IMM(BPF_REG_8, 1),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1),
+                       BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_1, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
+               .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
+               .result_unpriv = REJECT,
+               .errstr = "!read_ok",
+               .result = REJECT,
+       },
 };
 
 static int probe_filter_length(const struct bpf_insn *fp)
@@ -13940,7 +13968,7 @@ static int create_map(uint32_t type, uint32_t size_key,
        return fd;
 }
 
-static int create_prog_dummy1(enum bpf_map_type prog_type)
+static int create_prog_dummy1(enum bpf_prog_type prog_type)
 {
        struct bpf_insn prog[] = {
                BPF_MOV64_IMM(BPF_REG_0, 42),
@@ -13951,7 +13979,7 @@ static int create_prog_dummy1(enum bpf_map_type prog_type)
                                ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
 }
 
-static int create_prog_dummy2(enum bpf_map_type prog_type, int mfd, int idx)
+static int create_prog_dummy2(enum bpf_prog_type prog_type, int mfd, int idx)
 {
        struct bpf_insn prog[] = {
                BPF_MOV64_IMM(BPF_REG_3, idx),
@@ -13966,7 +13994,7 @@ static int create_prog_dummy2(enum bpf_map_type prog_type, int mfd, int idx)
                                ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
 }
 
-static int create_prog_array(enum bpf_map_type prog_type, uint32_t max_elem,
+static int create_prog_array(enum bpf_prog_type prog_type, uint32_t max_elem,
                             int p1key)
 {
        int p2key = 1;
@@ -14037,7 +14065,7 @@ static int create_cgroup_storage(bool percpu)
 
 static char bpf_vlog[UINT_MAX >> 8];
 
-static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type,
+static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
                          struct bpf_insn *prog, int *map_fds)
 {
        int *fixup_map_hash_8b = test->fixup_map_hash_8b;
@@ -14166,7 +14194,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type,
                do {
                        prog[*fixup_map_stacktrace].imm = map_fds[12];
                        fixup_map_stacktrace++;
-               } while (fixup_map_stacktrace);
+               } while (*fixup_map_stacktrace);
        }
 }
 
index 256d82d5fa8751aa400a1eef4f22e5c60b0f4dea..923570a9708ae730909920e321ee2880af0f8a8f 100644 (file)
@@ -7,6 +7,7 @@ CFLAGS += -I../../../../usr/include/
 TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh
 TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh ip_defrag.sh
 TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
+TEST_PROGS += test_vxlan_fdb_changelink.sh
 TEST_PROGS_EXTENDED := in_netns.sh
 TEST_GEN_FILES =  socket
 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy
diff --git a/tools/testing/selftests/net/test_vxlan_fdb_changelink.sh b/tools/testing/selftests/net/test_vxlan_fdb_changelink.sh
new file mode 100755 (executable)
index 0000000..2d442cd
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Check FDB default-remote handling across "ip link set".
+
+check_remotes()
+{
+       local what=$1; shift
+       local N=$(bridge fdb sh dev vx | grep 00:00:00:00:00:00 | wc -l)
+
+       echo -ne "expected two remotes after $what\t"
+       if [[ $N != 2 ]]; then
+               echo "[FAIL]"
+               EXIT_STATUS=1
+       else
+               echo "[ OK ]"
+       fi
+}
+
+ip link add name vx up type vxlan id 2000 dstport 4789
+bridge fdb ap dev vx 00:00:00:00:00:00 dst 192.0.2.20 self permanent
+bridge fdb ap dev vx 00:00:00:00:00:00 dst 192.0.2.30 self permanent
+check_remotes "fdb append"
+
+ip link set dev vx type vxlan remote 192.0.2.30
+check_remotes "link set"
+
+ip link del dev vx
+exit $EXIT_STATUS
index fb22bccfbc8a7f2df651474211b48aa67efdf8f9..7ef45a4a3cba72dea65d6c9ff9b7779710d20de5 100644 (file)
 #define PAGE_MASK (~(PAGE_SIZE-1))
 #define PAGE_ALIGN(x) ((x + PAGE_SIZE - 1) & PAGE_MASK)
 
+/* generic data direction definitions */
+#define READ                    0
+#define WRITE                   1
+
 typedef unsigned long long phys_addr_t;
 typedef unsigned long long dma_addr_t;
 typedef size_t __kernel_size_t;
index 3710342cf6ad01f7c495ff27ddc2c83feb643dbb..6855cce3e528793fd47b90f5f9811ea5617c693a 100644 (file)
@@ -175,10 +175,14 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
 {
        struct kvm_coalesced_mmio_dev *dev, *tmp;
 
+       if (zone->pio != 1 && zone->pio != 0)
+               return -EINVAL;
+
        mutex_lock(&kvm->slots_lock);
 
        list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list)
-               if (coalesced_mmio_in_range(dev, zone->addr, zone->size)) {
+               if (zone->pio == dev->zone.pio &&
+                   coalesced_mmio_in_range(dev, zone->addr, zone->size)) {
                        kvm_io_bus_unregister_dev(kvm,
                                zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, &dev->dev);
                        kvm_iodevice_destructor(&dev->dev);